123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- define([
- 'jquery',
- 'base/js/namespace',
- 'base/js/utils',
- 'base/js/i18n',
- 'base/js/dialog',
- 'base/js/events',
- 'base/js/keyboard',
- 'moment',
- 'bidi/bidi'
- ], function($, IPython, utils, i18n, dialog, events, keyboard, moment, bidi) {
- "use strict";
- var extension = function(path){
- /**
- * return the last pat after the dot in a filepath
- * or the filepath itself if no dots present.
- * Empty string if the filepath ends with a dot.
- **/
- var parts = path.split('.');
- return parts[parts.length-1];
- };
- var item_in = function(item, list) {
- // Normalize list and item to lowercase
- var normalized_list = list.map(function(_item) {
- return _item.toLowerCase();
- });
- return normalized_list.indexOf(item.toLowerCase()) !== -1;
- };
- var includes_extension = function(filepath, extensionslist) {
- return item_in(extension(filepath), extensionslist);
- };
- function name_sorter(ascending) {
- return (function(a, b) {
- if (type_order[a['type']] < type_order[b['type']]) {
- return -1;
- }
- if (type_order[a['type']] > type_order[b['type']]) {
- return 1;
- }
- if (a['name'].toLowerCase() < b['name'].toLowerCase()) {
- return (ascending) ? -1 : 1;
- }
- if (a['name'].toLowerCase() > b['name'].toLowerCase()) {
- return (ascending) ? 1 : -1;
- }
- return 0;
- });
- }
- function modified_sorter(ascending) {
- var order = ascending ? 1 : 0;
- return (function(a, b) {
- return utils.datetime_sort_helper(a.last_modified, b.last_modified,
- order)
- });
- }
- function size_sorter(ascending) {
- var order = ascending ? 1 : 0;
- // directories have file size of undefined
- return (function(a, b) {
- if (a.size === undefined) {
- return (ascending) ? -1 : 1;
- }
- if (b.size === undefined) {
- return (ascending) ? 1 : -1;
- }
- if (a.size > b.size) {
- return (ascending) ? -1 : 1;
- }
- if (b.size > a.size) {
- return (ascending) ? 1 : -1;
- }
- return 0;
- });
- }
- var sort_functions = {
- 'sort-name': name_sorter,
- 'last-modified': modified_sorter,
- 'file-size': size_sorter
- };
- var NotebookList = function (selector, options) {
- /**
- * Constructor
- *
- * Parameters:
- * selector: string
- * options: dictionary
- * Dictionary of keyword arguments.
- * session_list: SessionList instance
- * element_name: string
- * base_url: string
- * notebook_path: string
- * contents: Contents instance
- */
- var that = this;
- this.session_list = options.session_list;
- this.events = this.session_list.events;
- // allow code re-use by just changing element_name in kernellist.js
- this.element_name = options.element_name || 'notebook';
- this.selector = selector;
- if (this.selector !== undefined) {
- this.element = $(selector);
- this.style();
- this.bind_events();
- }
- this.notebooks_list = [];
- this.sessions = {};
- this.base_url = options.base_url || utils.get_body_data("baseUrl");
- this.notebook_path = options.notebook_path || utils.get_body_data("notebookPath");
- this.initial_notebook_path = this.notebook_path;
- this.contents = options.contents;
- if (this.session_list && this.session_list.events) {
- this.session_list.events.on('sessions_loaded.Dashboard',
- function(e, d) { that.sessions_loaded(d); });
- }
- this.selected = [];
- this.sort_function = name_sorter(1);
- // 0 => descending, 1 => ascending
- this.sort_id = 'sort-name';
- this.sort_direction = 1;
- this._max_upload_size_mb = 25;
- this.EDIT_MIMETYPES = [
- 'application/javascript',
- 'application/x-sh',
- 'application/vnd.groove-tool-template'
- ];
- };
- NotebookList.prototype.style = function () {
- var prefix = '#' + this.element_name;
- $(prefix + '_toolbar').addClass('list_toolbar');
- $(prefix + '_list_info').addClass('toolbar_info');
- $(prefix + '_buttons').addClass('toolbar_buttons');
- $(prefix + '_list_header').addClass('list_header');
- this.element.addClass("list_container");
- };
- NotebookList.prototype.bind_events = function () {
- var that = this;
- $('#refresh_' + this.element_name + '_list').click(function () {
- that.load_sessions();
- });
- this.element.bind('dragover', function () {
- return false;
- });
- this.element.bind('drop', function(event){
- that.handleFilesUpload(event,'drop');
- return false;
- });
- // Bind events for singleton controls.
- if (!NotebookList._bound_singletons) {
- NotebookList._bound_singletons = true;
- $('#new-file').click(function(e) {
- var w = window.open('', IPython._target);
- that.contents.new_untitled(that.notebook_path || '', {type: 'file', ext: '.txt'}).then(function(data) {
- w.location = utils.url_path_join(
- that.base_url, 'edit',
- utils.encode_uri_components(data.path)
- );
- }).catch(function (e) {
- w.close();
- dialog.modal({
- title: i18n.msg._('Creating File Failed'),
- body: $('<div/>')
- .text(i18n.msg._("An error occurred while creating a new file."))
- .append($('<div/>')
- .addClass('alert alert-danger')
- .text(e.message || e)),
- buttons: {
- OK: {'class': 'btn-primary'}
- }
- });
- console.warn('Error during New file creation', e);
- });
- that.load_sessions();
- e.preventDefault();
- });
- $('#new-folder').click(function(e) {
- that.contents.new_untitled(that.notebook_path || '', {type: 'directory'})
- .then(function(){
- that.load_list();
- }).catch(function (e) {
- dialog.modal({
- title: i18n.msg._('Creating Folder Failed'),
- body: $('<div/>')
- .text(i18n.msg._("An error occurred while creating a new folder."))
- .append($('<div/>')
- .addClass('alert alert-danger')
- .text(e.message || e)),
- buttons: {
- OK: {'class': 'btn-primary'}
- }
- });
- console.warn('Error during New directory creation', e);
- });
- that.load_sessions();
- e.preventDefault();
- });
- // Bind events for action buttons.
- $('.rename-button').click($.proxy(this.rename_selected, this));
- $('.move-button').click($.proxy(this.move_selected, this));
- $('.download-button').click($.proxy(this.download_selected, this));
- $('.shutdown-button').click($.proxy(this.shutdown_selected, this));
- $('.duplicate-button').click($.proxy(this.duplicate_selected, this));
- $('.view-button').click($.proxy(this.view_selected, this));
- $('.edit-button').click($.proxy(this.edit_selected, this));
- $('.delete-button').click($.proxy(this.delete_selected, this));
- // Bind events for selection menu buttons.
- $('#selector-menu').click(function (event) {
- that.select($(event.target).attr('id'));
- });
- var select_all = $('#select-all');
- select_all.change(function () {
- if (!select_all.prop('checked') || select_all.data('indeterminate')) {
- that.select('select-none');
- } else {
- that.select('select-all');
- }
- });
- $('#button-select-all').click(function (e) {
- // toggle checkbox if the click doesn't come from the checkbox already
- if (!$(e.target).is('input[type=checkbox]')) {
- if (select_all.prop('checked') || select_all.data('indeterminate')) {
- that.select('select-none');
- } else {
- that.select('select-all');
- }
- }
- });
- $('.sort-action').click(function(e) {
- var sort_on = e.target.id;
- // Clear sort indications in UI
- $(".sort-action i").removeClass("fa-arrow-up").removeClass("fa-arrow-down");
- if ((that.sort_id === sort_on) && (that.sort_direction === 1)) {
- that.sort_list(sort_on, 0);
- $("#" + sort_on + " i").addClass("fa-arrow-up");
- that.sort_direction = 0;
- } else {
- that.sort_list(sort_on, 1);
- $("#" + sort_on + " i").addClass("fa-arrow-down");
- that.sort_direction = 1;
- }
- that.sort_id = sort_on;
- });
- }
- };
- NotebookList.prototype.sort_list = function(id, order) {
- if (sort_functions.hasOwnProperty(id)) {
- this.sort_function = sort_functions[id](order);
- this.draw_notebook_list(this.model_list, this.error_msg);
- } else {
- console.error("No such sort id: '" + id + "'")
- }
- };
- NotebookList.prototype.handleFilesUpload = function(event, dropOrForm) {
- var that = this;
- var files;
- if(dropOrForm === 'drop'){
- files = event.originalEvent.dataTransfer.files;
- } else {
- files = event.originalEvent.target.files;
- }
- var reader_onload = function (event) {
- var item = $(event.target).data('item');
- that.add_file_data(event.target.result, item);
- that.add_upload_button(item);
- };
- var reader_onerror = function (event) {
- var item = $(event.target).data('item');
- var name = item.data('name');
- item.remove();
- dialog.modal({
- title : i18n.msg._('Failed to read file'),
- body : i18n.msg.sprintf(i18n.msg._("Failed to read file %s"),name),
- buttons : {'OK' : { 'class' : 'btn-primary' }}
- });
- };
- Array.from(files).forEach(function(f) {
- var name_and_ext = utils.splitext(f.name);
- var file_ext = name_and_ext[1];
- if (f.size > that._max_upload_size_mb * 1024 * 1024) {
- var body_msg = i18n.msg.sprintf(i18n.msg._("The file size is %d MB. Do you still want to upload it?"),
- Math.round(f.size / (1024 * 1024)));
- dialog.modal({
- title : i18n.msg._('Large file size warning'),
- body : body_msg,
- buttons : {
- Cancel: {},
- Ok: {
- class: "btn-primary",
- click: function() {
- that.add_large_file_upload_button(f);
- }
- }
- }
- });
- }
- else{
- var reader = new FileReader();
- if (file_ext === '.ipynb') {
- reader.readAsText(f);
- } else {
- // read non-notebook files as binary
- reader.readAsArrayBuffer(f);
- }
- var item = that.new_item(0, true);
- item.addClass('new-file');
- that.add_name_input(f.name, item, file_ext === '.ipynb' ? 'notebook' : 'file');
- // Store the list item in the reader so we can use it later
- // to know which item it belongs to.
- $(reader).data('item', item);
- reader.onload = reader_onload;
- reader.onerror = reader_onerror;
- }
- });
- // Clear fileinput value. This is required to
- // reset the form. Otherwise, if you upload a file, delete it and try to
- // upload it again, the changed event won't fire.
- var form = $('input.fileinput');
- form.val('');
- return false;
- };
- NotebookList.prototype.clear_list = function (remove_uploads) {
- /**
- * Clears the navigation tree.
- *
- * Parameters
- * remove_uploads: bool=False
- * Should upload prompts also be removed from the tree.
- */
- if (remove_uploads) {
- this.element.children('.list_item').remove();
- } else {
- this.element.children('.list_item:not(.new-file)').remove();
- }
- };
- NotebookList.prototype.load_sessions = function(){
- this.session_list.load_sessions();
- };
- NotebookList.prototype.sessions_loaded = function(data){
- this.sessions = data;
- this.load_list();
- };
- NotebookList.prototype.load_list = function () {
- var that = this;
- // Add an event handler browser back and forward events
- window.onpopstate = function(e) {
- var path = (window.history.state && window.history.state.path) ?
- window.history.state.path : that.initial_notebook_path;
- that.update_location(path);
- };
- var breadcrumb = $('.breadcrumb');
- breadcrumb.empty();
- var list_item = $('<li/>');
- var root_url = utils.url_path_join(that.base_url, '/tree');
- var root = $('<li/>').append(
- $("<a/>")
- .attr('href', root_url)
- .append(
- $("<i/>")
- .addClass('fa fa-folder')
- )
- .click(function(e) {
- // Allow the default browser action when the user holds a modifier (e.g., Ctrl-Click)
- if(e.altKey || e.metaKey || e.shiftKey) {
- return true;
- }
- var path = '';
- window.history.pushState(
- {path: path},
- 'Home',
- utils.url_path_join(that.base_url, 'tree')
- );
- that.update_location(path);
- return false;
- })
- );
- breadcrumb.append(root);
- var path_parts = [];
- this.notebook_path.split('/').forEach(function(path_part) {
- path_parts.push(path_part);
- var path = path_parts.join('/');
- var url = utils.url_path_join(
- that.base_url,
- '/tree',
- utils.encode_uri_components(path)
- );
- var crumb = $('<li/>').append(
- $('<a/>')
- .attr('href', url)
- .text(path_part)
- .click(function(e) {
- // Allow the default browser action when the user holds a modifier (e.g., Ctrl-Click)
- if(e.altKey || e.metaKey || e.shiftKey) {
- return true;
- }
- window.history.pushState(
- {path: path},
- path,
- url
- );
- that.update_location(path);
- return false;
- })
- );
- breadcrumb.append(crumb);
- });
- this.contents.list_contents(that.notebook_path).then(
- $.proxy(this.draw_notebook_list, this),
- function(error) {
- that.draw_notebook_list({content: []}, i18n.msg._("Server error: ") + error.message);
- }
- );
- };
-
- NotebookList.prototype.update_location = function (path) {
- this.notebook_path = path;
- $('body').attr('data-notebook-path', path);
- // Update the file tree list without reloading the page
- this.load_list();
- // Update the page title so the browser tab reflects it
- // Match how the title appears with a trailing slash or
- // "Home" if the page loads from the server.
- $('title').text(path ? path+'/' : i18n.msg._("Home"));
- };
- /**
- * Draw the list of notebooks
- * @method draw_notebook_list
- * @param {Array} list An array of dictionaries representing files or
- * directories.
- * @param {String} error_msg An error message
- */
- var type_order = {'directory':0,'notebook':1,'file':2};
- NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
- // Remember what was selected before the refresh.
- var selected_before = this.selected;
- // Store the data to be redrawn by sorting
- this.model_list = list;
- this.error_msg = error_msg;
- list.content.sort(this.sort_function);
- var message = error_msg || i18n.msg._('The notebook list is empty.');
- var item = null;
- var model = null;
- var len = list.content.length;
- this.clear_list();
- var n_uploads = this.element.children('.list_item').length;
- if (len === 0) {
- item = this.new_item(0);
- var span12 = item.children().first();
- span12.empty();
- span12.append($('<div style="margin:auto;text-align:center;color:grey"/>').text(message));
- }
- var path = this.notebook_path;
- var offset = n_uploads;
- if (path !== '') {
- item = this.new_item(offset, false);
- model = {
- type: 'directory',
- name: '..',
- path: utils.url_path_split(path)[0]
- };
- this.add_link(model, item);
- offset += 1;
- }
- for (var i=0; i<len; i++) {
- model = list.content[i];
- item = this.new_item(i+offset, true);
- try {
- this.add_link(model, item);
- } catch(err) {
- console.log('Error adding link: ' + err);
- }
- }
- // Trigger an event when we've finished drawing the notebook list.
- events.trigger('draw_notebook_list.NotebookList');
- // Reselect the items that were selected before. Notify listeners
- // that the selected items may have changed. O(n^2) operation.
- selected_before.forEach(function(item) {
- var list_items = $('.list_item');
- for (var i=0; i<list_items.length; i++) {
- var $list_item = $(list_items[i]);
- if ($list_item.data('path') === item.path) {
- $list_item.find('input[type=checkbox]').prop('checked', true);
- break;
- }
- }
- });
- this._selection_changed();
- };
- /**
- * Creates a new item.
- * @param {integer} index
- * @param {boolean} [selectable] - tristate, undefined: don't draw checkbox,
- * false: don't draw checkbox but pad
- * where it should be, true: draw checkbox.
- * @return {JQuery} row
- */
- NotebookList.prototype.new_item = function (index, selectable) {
- var row = $('<div/>')
- .addClass("list_item")
- .addClass("row");
- var item = $("<div/>")
- .addClass("col-md-12")
- .appendTo(row);
-
- var checkbox;
- if (selectable !== undefined) {
- checkbox = $('<input/>')
- .attr('type', 'checkbox')
- .attr('title', i18n.msg._('Click here to rename, delete, etc.'))
- .appendTo(item);
- }
- $('<i/>')
- .addClass('item_icon')
- .appendTo(item);
- var link = $("<a/>")
- .addClass("item_link")
- .appendTo(item);
- $("<span/>")
- .addClass("item_name")
- .appendTo(link);
- $("<span/>")
- .addClass("file_size")
- .addClass("pull-right")
- .appendTo(item);
- $("<span/>")
- .addClass("item_modified")
- .addClass("pull-right")
- .appendTo(item);
- if (selectable === false) {
- checkbox.css('visibility', 'hidden');
- } else if (selectable === true) {
- var that = this;
- row.click(function(e) {
- // toggle checkbox only if the click doesn't come from the checkbox or the link
- if (!$(e.target).is('span[class=item_name]') && !$(e.target).is('input[type=checkbox]')) {
- checkbox.prop('checked', !checkbox.prop('checked'));
- }
- that._selection_changed();
- });
- }
- var buttons = $('<div/>')
- .addClass("item_buttons pull-right")
- .appendTo(item);
- $('<div/>')
- .addClass('running-indicator')
- .text(i18n.msg._('Running'))
- .css('visibility', 'hidden')
- .appendTo(buttons);
- if (index === -1) {
- this.element.append(row);
- } else {
- this.element.children().eq(index).after(row);
- }
- return row;
- };
- NotebookList.icons = {
- directory: 'folder_icon',
- notebook: 'notebook_icon',
- file: 'file_icon'
- };
- NotebookList.uri_prefixes = {
- directory: 'tree',
- notebook: 'notebooks',
- file: 'edit'
- };
- /**
- * Select all items in the tree of specified type.
- * selection_type : string among "select-all", "select-folders", "select-notebooks", "select-running-notebooks", "select-files"
- * any other string (like "select-none") deselects all items
- */
- NotebookList.prototype.select = function(selection_type) {
- var that = this;
- $('.list_item').each(function(index, item) {
- var item_type = $(item).data('type');
- var state = false;
- state = state || (selection_type === "select-all");
- state = state || (selection_type === "select-folders" && item_type === 'directory');
- state = state || (selection_type === "select-notebooks" && item_type === 'notebook');
- state = state || (selection_type === "select-running-notebooks" && item_type === 'notebook' && that.sessions[$(item).data('path')] !== undefined);
- state = state || (selection_type === "select-files" && item_type === 'file');
- $(item).find('input[type=checkbox]').prop('checked', state);
- });
- this._selection_changed();
- };
- NotebookList.prototype._is_notebook = function(model) {
- var ipynb_extensions = ['ipynb'];
- return includes_extension(model.path, ipynb_extensions);
- };
-
- NotebookList.prototype._is_editable = function(model) {
- // Allow any file to be "edited"
- // Non-text files will display the following error:
- // Error: [FILE] is not UTF-8 encoded
- // Saving is disabled.
- // See Console for more details.
- return true;
- };
-
- NotebookList.prototype._is_viewable = function(model) {
- var html_types = ['htm', 'html', 'xhtml', 'xml', 'mht', 'mhtml'];
- var media_extension = ['3gp', 'avi', 'mov', 'mp4', 'm4v', 'm4a', 'mp3', 'mkv', 'ogv', 'ogm', 'ogg', 'oga', 'webm', 'wav'];
- var image_type = ['bmp', 'gif', 'jpg', 'jpeg', 'png', 'webp'];
- var other_type = ['ico'];
- var viewable_extensions = [].concat(html_types, media_extension, image_type, other_type);
- return model.mimetype === 'text/html'
- || includes_extension(model.path, viewable_extensions);
- };
-
- // Files like PDF that should be opened using `/files` prefix
- NotebookList.prototype._is_pdflike = function(model) {
- var pdflike_extensions = ['pdf'];
- return includes_extension(model.path, pdflike_extensions);
- };
- /**
- * Handles when any row selector checkbox is toggled.
- */
- NotebookList.prototype._selection_changed = function() {
- // Use a JQuery selector to find each row with a checked checkbox. If
- // we decide to add more checkboxes in the future, this code will need
- // to be changed to distinguish which checkbox is the row selector.
- var that = this;
- var selected = [];
- var has_running_notebook = false;
- var has_directory = false;
- var has_file = false;
- var checked = 0;
- $('.list_item :checked').each(function(index, item) {
- var parent = $(item).parent().parent();
- // If the item doesn't have an upload button, isn't the
- // breadcrumbs and isn't the parent folder '..', then it can be selected.
- // Breadcrumbs path == ''.
- if (parent.find('.upload_button').length === 0 && parent.data('path') !== '' && parent.data('path') !== utils.url_path_split(that.notebook_path)[0]) {
- checked++;
- selected.push({
- name: parent.data('name'),
- path: parent.data('path'),
- type: parent.data('type')
- });
- // Set flags according to what is selected. Flags are later
- // used to decide which action buttons are visible.
- has_running_notebook = has_running_notebook ||
- (parent.data('type') === 'notebook' && that.sessions[parent.data('path')] !== undefined);
- has_file = has_file || (parent.data('type') === 'file');
- has_directory = has_directory || (parent.data('type') === 'directory');
- }
- });
- this.selected = selected;
- // Rename is only visible when one item is selected, and it is not a running notebook
- if (selected.length === 1 && !has_running_notebook) {
- $('.rename-button').css('display', 'inline-block');
- } else {
- $('.rename-button').css('display', 'none');
- }
- // Move is visible if at least one item is selected, and none of them
- // are a running notebook.
- if (selected.length > 0 && !has_running_notebook) {
- $('.move-button').css('display', 'inline-block');
- } else {
- $('.move-button').css('display', 'none');
- }
- // Download is only visible when one item is selected, and it is not a
- // running notebook or a directory
- // TODO(nhdaly): Add support for download multiple items at once.
- if (selected.length === 1 && !has_running_notebook && !has_directory) {
- $('.download-button').css('display', 'inline-block');
- } else {
- $('.download-button').css('display', 'none');
- }
- // Shutdown is only visible when one or more notebooks running notebooks
- // are selected and no non-notebook items are selected.
- if (has_running_notebook && !(has_file || has_directory)) {
- $('.shutdown-button').css('display', 'inline-block');
- } else {
- $('.shutdown-button').css('display', 'none');
- }
- // Duplicate isn't visible when a directory is selected.
- if (selected.length > 0 && !has_directory) {
- $('.duplicate-button').css('display', 'inline-block');
- } else {
- $('.duplicate-button').css('display', 'none');
- }
- // Delete is visible if one or more items are selected.
- if (selected.length > 0) {
- $('.delete-button').css('display', 'inline-block');
- } else {
- $('.delete-button').css('display', 'none');
- }
- // View is visible in the following case:
- //
- // - the item is editable
- // - it is not a notebook
- //
- // If it's not editable or unknown, the default action should be view
- // already so no need to show the button.
- // That should include things like, html, py, txt, json....
- if (selected.length >= 1 && !has_directory) {
- $('.view-button').css('display', 'inline-block');
- } else {
- $('.view-button').css('display', 'none');
- }
- // Edit is visible when an item is unknown, that is to say:
- // - not in the editable list
- // - not in the known non-editable list.
- // - not a notebook.
- // Indeed if it's editable the default action is already to edit.
- // And non editable files should not show edit button.
- // for unknown we'll assume users know what they are doing.
- if (selected.length >= 1 && !has_directory && selected.every(function(el) {
- return that._is_editable(el);
- })) {
- $('.edit-button').css('display', 'inline-block');
- } else {
- $('.edit-button').css('display', 'none');
- }
- // If all of the items are selected, show the selector as checked. If
- // some of the items are selected, show it as checked. Otherwise,
- // uncheck it.
- var total = 0;
- $('.list_item input[type=checkbox]').each(function(index, item) {
- var parent = $(item).parent().parent();
- // If the item doesn't have an upload button and it's not the
- // breadcrumbs, it can be selected. Breadcrumbs path == ''.
- if (parent.find('.upload_button').length === 0 && parent.data('path') !== '' && parent.data('path') !== utils.url_path_split(that.notebook_path)[0]) {
- total++;
- }
- });
- var select_all = $("#select-all");
- if (checked === 0) {
- select_all.prop('checked', false);
- select_all.prop('indeterminate', false);
- select_all.data('indeterminate', false);
- } else if (checked === total) {
- select_all.prop('checked', true);
- select_all.prop('indeterminate', false);
- select_all.data('indeterminate', false);
- } else {
- select_all.prop('checked', false);
- select_all.prop('indeterminate', true);
- select_all.data('indeterminate', true);
- }
- // Update total counter
- checked = bidi.applyBidi(checked);
- $('#counter-select-all').html(checked===0 ? ' ' : checked);
- // If at aleast on item is selected, hide the selection instructions.
- if (checked > 0) {
- $('.dynamic-instructions').hide();
- } else {
- $('.dynamic-instructions').show();
- }
- };
- NotebookList.prototype.add_link = function (model, item) {
- var that = this;
- var running = (model.type === 'notebook' && this.sessions[model.path] !== undefined);
- item.data('name',model.name);
- item.data('path', model.path);
- item.data('modified', model.last_modified);
- item.data('type', model.type);
- item.find(".item_name").text(bidi.applyBidi(model.name));
- var icon = NotebookList.icons[model.type];
- if (running) {
- icon = 'running_' + icon;
- }
- var uri_prefix = NotebookList.uri_prefixes[model.type];
- if (model.type === 'file' && this._is_viewable(model))
- {
- uri_prefix = 'view';
- }
- if (model.type === 'file' && this._is_pdflike(model))
- {
- uri_prefix = 'files';
- }
- if (model.type === 'file' && this._is_notebook(model))
- {
- uri_prefix = 'notebooks';
- }
- item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
- var link = item.find("a.item_link")
- .attr('href',
- utils.url_path_join(
- this.base_url,
- uri_prefix,
- utils.encode_uri_components(model.path)
- )
- );
- item.find(".item_buttons .running-indicator").css('visibility', running ? '' : 'hidden');
- // directory nav doesn't open new tabs
- // files, notebooks do
- if (model.type !== "directory") {
- link.attr('target', IPython._target);
- } else {
- // Replace with a click handler that will use the History API to
- // push a new route without reloading the page if the click is
- // not modified (e.g., Ctrl-Click)
- link.click(function (e) {
- if(e.altKey || e.metaKey || e.shiftKey) {
- return true;
- }
- window.history.pushState({
- path: model.path
- }, model.path, utils.url_path_join(
- that.base_url,
- 'tree',
- utils.encode_uri_components(model.path)
- ));
- that.update_location(model.path);
- return false;
- });
- }
-
- // Add in the date that the file was last modified
- item.find(".item_modified").text(utils.format_datetime(model.last_modified));
- item.find(".item_modified").attr("title", moment(model.last_modified).format("YYYY-MM-DD HH:mm"));
- var filesize = utils.format_filesize(model.size);
- item.find(".file_size").text(filesize || '\xA0');
- };
- NotebookList.prototype.add_name_input = function (name, item, icon_type) {
- item.data('name', name);
- item.find(".item_icon").addClass(NotebookList.icons[icon_type]).addClass('icon-fixed-width');
- item.find(".item_name").empty().append(
- $('<input/>')
- .addClass("filename_input")
- .attr('value', name)
- .attr('size', '30')
- .attr('type', 'text')
- .keyup(function(event){
- if(event.keyCode === 13){item.find('.upload_button').click();}
- else if(event.keyCode === 27){item.remove();}
- })
- );
- };
- NotebookList.prototype.add_file_data = function (data, item) {
- item.data('filedata', data);
- };
- NotebookList.prototype.shutdown_selected = function() {
- var that = this;
- this.selected.forEach(function(item) {
- if (item.type === 'notebook') {
- that.shutdown_notebook(item.path);
- }
- });
- // Deselect items after successful shutdown.
- that.select('select-none');
- };
- NotebookList.prototype.shutdown_notebook = function(path) {
- var that = this;
- var settings = {
- processData : false,
- cache : false,
- type : "DELETE",
- dataType : "json",
- success : function () {
- that.load_sessions();
- },
- error : utils.log_ajax_error
- };
- var session = this.sessions[path];
- if (session) {
- var url = utils.url_path_join(
- this.base_url,
- 'api/sessions',
- encodeURIComponent(session.id)
- );
- utils.ajax(url, settings);
- }
- };
- NotebookList.prototype.rename_selected = function() {
- if (this.selected.length !== 1){
- return;
- }
- var that = this;
- var item_path = this.selected[0].path;
- var item_name = this.selected[0].name;
- var item_type = this.selected[0].type;
- var input = $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
- .val(item_name);
- var rename_msg = function (type) {
- switch(type) {
- case 'file': return i18n.msg._("Enter a new file name:");
- case 'directory': return i18n.msg._("Enter a new directory name:");
- case 'notebook': return i18n.msg._("Enter a new notebook name:");
- default: return i18n.msg._("Enter a new name:");
- }
- };
- var rename_title = function (type) {
- switch(type) {
- case 'file': return i18n.msg._("Rename file");
- case 'directory': return i18n.msg._("Rename directory");
- case 'notebook': return i18n.msg._("Rename notebook");
- default: return i18n.msg._("Rename");
- }
- };
- var dialog_body = $('<div/>').append(
- $("<p/>").addClass("rename-message")
- .text(rename_msg(item_type))
- ).append(
- $("<br/>")
- ).append(input);
-
- // This statement is used simply so that message extraction
- // will pick up the strings. The actual setting of the text
- // for the button is in dialog.js.
- var button_labels = [ i18n.msg._("Cancel"), i18n.msg._("Rename"), i18n.msg._("OK"), i18n.msg._("Move")];
- var d = dialog.modal({
- title : rename_title(item_type),
- body : dialog_body,
- default_button: "Cancel",
- buttons : {
- Cancel: {},
- Rename : {
- class: "btn-primary",
- click: function() {
- that.contents.rename(item_path, utils.url_path_join(that.notebook_path, input.val())).then(function() {
- that.load_list();
- // Deselect items after successful rename.
- that.select('select-none');
- }).catch(function(e) {
- var template = i18n.msg._("An error occurred while renaming \"%1$s\" to \"%2$s\".");
- var failmsg = i18n.msg.sprintf(template,item_name,input.val());
- dialog.modal({
- title: i18n.msg._("Rename Failed"),
- body: $('<div/>')
- .text(failmsg)
- .append($('<div/>')
- .addClass('alert alert-danger')
- .text(e.message || e)),
- buttons: {
- OK: {'class': 'btn-primary'}
- }
- });
- console.warn('Error during renaming :', e);
- });
- }
- }
- },
- open : function () {
- // Upon ENTER, click the OK button.
- input.keydown(function (event) {
- if (event.which === keyboard.keycodes.enter) {
- d.find('.btn-primary').first().click();
- return false;
- }
- });
- input.focus();
- // Highlight the filename (up to the filetype suffix) in the input field.
- if (input.val().indexOf(".") > 0) {
- input[0].setSelectionRange(0,input.val().indexOf("."));
- } else {
- input.select();
- }
- }
- });
- };
- NotebookList.prototype.move_selected = function() {
- var that = this;
- var selected = that.selected.slice(); // Don't let that.selected change out from under us
- var num_items = selected.length;
- // Can move one or more selected items.
- if (!(num_items >= 1)) {
- return;
- }
- // Open a dialog to enter the new path, with current path as default.
- var input = $('<input/>').attr('type','text').attr('size','25').addClass('form-control')
- .val(utils.url_path_join('/', that.notebook_path));
- var dialog_body = $('<div/>').append(
- $("<p/>").addClass("rename-message")
- .text(i18n.msg.sprintf(i18n.msg.ngettext("Enter a new destination directory path for this item:",
- "Enter a new destination directory path for these %d items:", num_items),num_items))
- ).append(
- $("<br/>")
- ).append(
- $("<div/>").append(
- // $("<i/>").addClass("fa fa-folder").addClass("server-root")
- $("<span/>").text(utils.get_body_data("serverRoot")).addClass("server-root")
- ).append(
- input.addClass("path-input")
- ).addClass("move-path")
- );
- var d = dialog.modal({
- title : i18n.msg.sprintf(i18n.msg.ngettext("Move an Item","Move %d Items",num_items),num_items),
- body : dialog_body,
- default_button: "Cancel",
- buttons : {
- Cancel : {},
- Move : {
- class: "btn-primary",
- click: function() {
- // Move all the items.
- selected.forEach(function(item) {
- var item_path = item.path;
- var item_name = item.name;
- // Construct the new path using the user input and the item's name.
- var new_path = utils.url_path_join(input.val(), item_name);
- that.contents.rename(item_path, new_path).then(function() {
- // After each move finishes, reload the list.
- that.load_list();
- }).catch(function(e) {
- // If any of the moves fails, show this dialog for that move.
- var failmsg = i18n.msg._("An error occurred while moving \"%1$s\" from \"%2$s\" to \"%3$s\".");
- dialog.modal({
- title: i18n.msg._("Move Failed"),
- body: $('<div/>')
- .text(i18n.msg.sprintf(failmsg,item_name,item_path,new_path))
- .append($('<div/>')
- .addClass('alert alert-danger')
- .text(e.message || e)),
- buttons: {
- OK: {'class': 'btn-primary'}
- }
- });
- console.warn('Error during moving :', e);
- });
- }); // End of forEach.
- }
- }
- },
- // TODO: Consider adding fancier UI per Issue #941.
- open : function () {
- // Upon ENTER, click the OK button.
- input.keydown(function (event) {
- if (event.which === keyboard.keycodes.enter) {
- d.find('.btn-primary').first().click();
- return false;
- }
- });
- // Put the cursor at the end of the input.
- input.focus();
- }
- });
- };
- NotebookList.prototype.download_selected = function() {
- var that = this;
- // TODO(nhdaly): Support download multiple items at once.
- if (that.selected.length !== 1){
- return;
- }
- var item_path = that.selected[0].path;
- window.open(utils.url_path_join(that.base_url, 'files', utils.encode_uri_components(item_path)) + '?download=1', IPython._target);
- };
- NotebookList.prototype.delete_selected = function() {
- var selected = this.selected.slice(); // Don't let that.selected change out from under us
- var template = i18n.msg.ngettext("Are you sure you want to permanently delete: \"%s\"?",
- "Are you sure you want to permanently delete the %d files or folders selected?",
- selected.length);
- var delete_msg;
- if (selected.length === 1) {
- delete_msg = i18n.msg.sprintf(template, selected[0].name);
- } else {
- delete_msg = i18n.msg.sprintf(template, selected.length);
- }
- var that = this;
- dialog.modal({
- title : i18n.msg._("Delete"),
- body : delete_msg,
- default_button: "Cancel",
- buttons : {
- Cancel: {},
- Delete : {
- class: "btn-danger",
- click: function() {
- // Shutdown any/all selected notebooks before deleting
- // the files.
- that.shutdown_selected();
- // Delete selected.
- selected.forEach(function(item) {
- that.contents.delete(item.path).then(function() {
- that.notebook_deleted(item.path);
- }).catch(function(e) {
- var failmsg = i18n.msg._("An error occurred while deleting \"%s\".");
- dialog.modal({
- title: i18n.msg._("Delete Failed"),
- body: $('<div/>')
- .text(i18n.msg.sprintf(failmsg, item.path))
- .append($('<div/>')
- .addClass('alert alert-danger')
- .text(e.message || e)),
- buttons: {
- OK: {'class': 'btn-primary'}
- }
- });
- console.warn('Error during content deletion:', e);
- });
- });
- }
- }
- }
- });
- };
- NotebookList.prototype.view_selected = function() {
- var that = this;
- that.selected.forEach(function(item) {
- var item_path = utils.encode_uri_components(item.path);
- var item_type = that._is_notebook(item) ? 'notebooks' : that._is_viewable(item) ? 'view' : 'files';
- window.open(utils.url_path_join(that.base_url, item_type, item_path), IPython._target);
- });
- };
- NotebookList.prototype.edit_selected = function() {
- var that = this;
- that.selected.forEach(function(item) {
- var item_path = utils.encode_uri_components(item.path);
- window.open(utils.url_path_join(that.base_url, 'edit', item_path), IPython._target);
- });
- };
- NotebookList.prototype.duplicate_selected = function() {
- var selected = this.selected.slice(); // Don't let that.selected change out from under us
- var template = i18n.msg.ngettext("Are you sure you want to duplicate: \"%s\"?",
- "Are you sure you want to duplicate the %d files selected?",selected.length);
- var dup_msg;
- if (selected.length === 1) {
- dup_msg = i18n.msg.sprintf(template,selected[0].name);
- } else {
- dup_msg = i18n.msg.sprintf(template,selected.length);
- }
- var that = this;
- dialog.modal({
- title : i18n.msg._("Duplicate"),
- body : dup_msg,
- default_button: "Cancel",
- buttons : {
- Cancel: {},
- Duplicate : {
- class: "btn-primary",
- click: function() {
- selected.forEach(function(item) {
- that.contents.copy(item.path, that.notebook_path).then(function () {
- that.load_list();
- // Deselect items after successful duplication.
- that.select('select-none');
- }).catch(function(e) {
- var failmsg = i18n.msg._("An error occurred while duplicating \"%s\".");
- dialog.modal({
- title: i18n.msg._("Duplicate Failed"),
- body: $('<div/>')
- .text(i18n.msg.sprintf(failmsg,item.path))
- .append($('<div/>')
- .addClass('alert alert-danger')
- .text(e.message || e)),
- buttons: {
- OK: {'class': 'btn-primary'}
- }
- });
- console.warn('Error during content duplication', e);
- });
- });
- }
- }
- }
- });
- };
- NotebookList.prototype.notebook_deleted = function(path) {
- /**
- * Remove the deleted notebook.
- */
- var that = this;
- $(".list_item").each(function() {
- var element = $(this);
- if (element.data("path") === path) {
- element.remove();
- events.trigger('notebook_deleted.NotebookList');
- that._selection_changed();
- }
- });
- };
- // Add a new class for large file upload
- NotebookList.prototype.add_large_file_upload_button = function (file) {
- var that = this;
- var item = that.new_item(0, true);
- var stop_signal = false;
- item.addClass('new-file');
- that.add_name_input(file.name, item, 'file');
- var cancel_button = $('<button/>').text("Cancel")
- .addClass("btn btn-default btn-xs")
- .click(function (e) {
- item.remove();
- stop_signal = true;
- return false;
- });
- var upload_button = $('<button/>').text("Upload")
- .addClass('btn btn-primary btn-xs upload_button')
- .click(function (e) {
- var filename = item.find('.item_name > input').val();
- var path = utils.url_path_join(that.notebook_path, filename);
- var format = 'text';
- if (filename.length === 0 || filename[0] === '.') {
- dialog.modal({
- title : 'Invalid file name',
- body : "File names must be at least one character and not start with a dot",
- buttons : {'OK' : { 'class' : 'btn-primary' }}
- });
- return false;
- }
-
- var check_exist = function () {
- var exists = false;
- $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
- if ($(v).data('name') === filename) { exists = true; return false; }
- });
- return exists
- };
- var exists = check_exist();
-
- var add_uploading_button = function (f, item) {
- // change buttons, add a progress bar
- var uploading_button = item.find('.upload_button').text("Uploading");
- uploading_button.off('click'); // Prevent double upload
- var progress_bar = $('<span/>')
- .addClass('progress-bar')
- .css('top', '0')
- .css('left', '0')
- .css('width', '0')
- .css('height', '3px')
- .css('border-radius', '0 0 0 0')
- .css('display', 'inline-block')
- .css('position', 'absolute');
- var parse_large_file = function (f, item) {
- // codes inspired by https://stackoverflow.com/a/28318964
- var chunk_size = 1024 * 1024;
- var offset = 0;
- var chunk = 0;
- var chunk_reader = null;
-
- var large_reader_onload = function (event) {
- if (stop_signal === true) {
- return;
- }
- if (event.target.error == null) {
- offset += chunk_size;
- if (offset >= f.size) {
- chunk = -1;
- } else {
- chunk += 1;
- }
- // callback for handling reading: reader_onload in add_upload_button
- var item = $(event.target).data('item');
- that.add_file_data(event.target.result, item);
- upload_file(item, chunk); // Do the upload
- } else {
- console.log("Read error: " + event.target.error);
- }
- };
- var on_error = function (event) {
- var item = $(event.target).data('item');
- var name = item.data('name');
- item.remove();
- var _exists = check_exist();
- if (_exists) {
- that.contents.delete(path);
- }
- dialog.modal({
- title : 'Failed to read file',
- body : "Failed to read file '" + name + "'",
- buttons : {'OK' : { 'class' : 'btn-primary' }}
- });
- };
- chunk_reader = function (_offset, _f) {
- var reader = new FileReader();
- var blob = _f.slice(_offset, chunk_size + _offset);
- // Load everything as ArrayBuffer
- reader.readAsArrayBuffer(blob);
- // Store the list item in the reader so we can use it later
- // to know which item it belongs to.
- $(reader).data('item', item);
- reader.onload = large_reader_onload;
- reader.onerror = on_error;
- };
- // These codes to upload file in original class
- var upload_file = function(item, chunk) {
- var filedata = item.data('filedata');
- if (filedata instanceof ArrayBuffer) {
- // base64-encode binary file data
- var bytes = '';
- var buf = new Uint8Array(filedata);
- var nbytes = buf.byteLength;
- for (var i=0; i<nbytes; i++) {
- bytes += String.fromCharCode(buf[i]);
- }
- filedata = btoa(bytes);
- format = 'base64';
- }
- var model = { name: filename, path: path };
- var name_and_ext = utils.splitext(filename);
- var file_ext = name_and_ext[1];
- var content_type;
- // Treat everything as generic file
- model.type = 'file';
- model.format = format;
- content_type = 'application/octet-stream';
- model.chunk = chunk;
- model.content = filedata;
-
- var on_success = function () {
- if (offset < f.size) {
- // of to the next chunk
- chunk_reader(offset, f);
- // change progress bar and progress button
- var progress = offset / f.size * 100;
- progress = progress > 100 ? 100 : progress;
- uploading_button.text(progress.toFixed(0)+'%');
- progress_bar.css('width', progress+'%')
- .attr('aria-valuenow', progress.toString());
- } else {
- item.removeClass('new-file');
- that.add_link(model, item);
- that.session_list.load_sessions();
- }
- };
- that.contents.save(path, model).then(on_success, on_error);
- };
- // now let's start the read with the first block
- chunk_reader(offset, f);
- };
- item.find('.item_buttons')
- .append(progress_bar);
- parse_large_file(f, item);
- };
- if (exists) {
- dialog.modal({
- title : "Replace file",
- body : 'There is already a file named ' + filename + ', do you want to replace it?',
- default_button: "Cancel",
- buttons : {
- Overwrite : {
- class: "btn-danger",
- click: function () {
- add_uploading_button(file, item);
- }
- },
- Cancel : {
- click: function() { item.remove(); }
- }
- }
- });
- } else {
- add_uploading_button(file, item);
- }
- return false;
- });
- item.find(".item_buttons").empty()
- .append(upload_button)
- .append(cancel_button);
- };
- NotebookList.prototype.add_upload_button = function (item) {
- var that = this;
- var upload_button = $('<button/>').text(i18n.msg._("Upload"))
- .addClass('btn btn-primary btn-xs upload_button')
- .click(function (e) {
- var filename = item.find('.item_name > input').val();
- var path = utils.url_path_join(that.notebook_path, filename);
- var filedata = item.data('filedata');
- var format = 'text';
- if (filename.length === 0 || filename[0] === '.') {
- dialog.modal({
- title : i18n.msg._('Invalid file name'),
- body : i18n.msg._("File names must be at least one character and not start with a period"),
- buttons : {'OK' : { 'class' : 'btn-primary' }}
- });
- return false;
- }
- if (filedata instanceof ArrayBuffer) {
- // base64-encode binary file data
- var bytes = '';
- var buf = new Uint8Array(filedata);
- var nbytes = buf.byteLength;
- for (var i=0; i<nbytes; i++) {
- bytes += String.fromCharCode(buf[i]);
- }
- filedata = btoa(bytes);
- format = 'base64';
- }
- var model = { name: filename, path: path };
- var name_and_ext = utils.splitext(filename);
- var file_ext = name_and_ext[1];
- var content_type;
- if (file_ext === '.ipynb') {
- model.type = 'notebook';
- model.format = 'json';
- try {
- model.content = JSON.parse(filedata);
- } catch (e) {
- var failbody = i18n.msg._("The error was: %s");
- dialog.modal({
- title : i18n.msg._('Cannot upload invalid Notebook'),
- body : i18n.msg.sprintf(failbody,e),
- buttons : {'OK' : {
- 'class' : 'btn-primary',
- click: function () {
- item.remove();
- }
- }}
- });
- console.warn('Error during notebook uploading', e);
- return false;
- }
- content_type = 'application/json';
- } else {
- model.type = 'file';
- model.format = format;
- model.content = filedata;
- content_type = 'application/octet-stream';
- }
- var on_success = function () {
- item.removeClass('new-file');
- that.add_link(model, item);
- that.session_list.load_sessions();
- };
- var exists = false;
- $.each(that.element.find('.list_item:not(.new-file)'), function(k,v){
- if ($(v).data('name') === filename) { exists = true; return false; }
- });
- if (exists) {
- var body = i18n.msg._("There is already a file named \"%s\". Do you want to replace it?");
- dialog.modal({
- title : i18n.msg._("Replace file"),
- body : i18n.msg.sprintf(body,filename),
- default_button: "Cancel",
- buttons : {
- Cancel : {
- click: function() { item.remove(); }
- },
- Overwrite : {
- class: "btn-danger",
- click: function () {
- that.contents.save(path, model).then(on_success);
- }
- }
- }
- });
- } else {
- that.contents.save(path, model).then(on_success);
- }
- return false;
- });
- var cancel_button = $('<button/>').text(i18n.msg._("Cancel"))
- .addClass("btn btn-default btn-xs")
- .click(function (e) {
- item.remove();
- return false;
- });
- item.find(".item_buttons").empty()
- .append(upload_button)
- .append(cancel_button);
- };
- return {'NotebookList': NotebookList};
- });
|