<commit_before>/*global App */
'use strict';

App.module('Base.Helpers', function (Helpers, App) {

  Helpers.LayoutChanger = function(){};

  _.extend(Helpers.LayoutChanger.prototype, {

    initialize: function() {
      this.initializeLayouts();
      this.initializeViews();

      App.vent.on('layout_showed', this.showViews, this);
    },

    initializeLayouts: function() {
      this.layouts = {};
      this.layouts.counter = 0;
      this.layouts.list = [];
    },

    addLayout: function(layout) {
      this.layouts.list.push(layout);
    },

    initializeViews: function() {
      this.views = {};
      this.views.list = [];

      this.leftView = null;
      this.views.leftCounter = 0;

      this.rightView = null;
      this.views.rightCounter = 0;
    },

    addView: function(view) {
      this.views.list.push(view);
    },

    getNextLayout : function() {
      this.layouts.counter += 1;
      var layout = this.getCurrentLayout();

      App.vent.trigger('new_layout', layout);

      return layout;
    },

    countVisibleViews: function() {
      var visibleViews = 0;
      if(!_.isNull(this.leftView)){
        visibleViews++;
      }
      if(!_.isNull(this.rightView)){
        visibleViews++;
      }

      return visibleViews;
    },

    showViews: function() {
      var rmArray = this.regionManagerArray();
      var visibleViews = this.countVisibleViews();

      // need another layout
      if(rmArray.length === 1 && visibleViews === 2){
        this.getNextLayout();
        this.showViews();
        return;
      }
      if(rmArray.length === 2 && visibleViews === 1){
        this.getNextLayout();
        this.showViews();
        return;
      }

      // ok, lets show the views
      if(rmArray.length === 1){
        var onlyRightViewVisible = _.isNull(this.leftView)  && !_.isNull(this.rightView);
        var onlyLeftViewVisible  = _.isNull(this.rightView) && !_.isNull(this.leftView);
        if( onlyRightViewVisible ) {
          rmArray[0].show(this.rightView);
        }
        else if ( onlyLeftViewVisible ) {
          rmArray[0].show(this.leftView);
        }
        else{
          rmArray[0].close();
        }
      }
      else if(rmArray.length === 2){
        if(!_.isNull(this.leftView)){
          rmArray[0].show(this.leftView);
        }
        if(!_.isNull(this.rightView)){
          rmArray[1].show(this.rightView);
        }
      }

    },

    getCurrentLayout : function() {
      var index = this.layouts.counter % this.layouts.list.length;
      return this.layouts.list[index];
    },

    regionManagerArray: function() {
      return this.getCurrentLayout().regionManager.toArray();
    },

    getNextLeftView : function() {
      var total = this.views.list.length;
      var index = this.views.leftCounter % total;
      this.views.leftCounter += 1;

      if(!_.isNull(this.views.list[index])){
        this.leftView = new this.views.list[index]();
      }
      else{
        this.leftView = null;
      }

      this.showViews();

      return this.leftView;
    },

    getNextRightView : function() {
      var total = this.views.list.length;
      var index = this.views.rightCounter % total;
      this.views.rightCounter += 1;

      if(!_.isNull(this.views.list[index])){
        this.rightView = new this.views.list[index]();
      }
      else{
        this.rightView = null;
      }

      this.showViews();

      return this.rightView;
    },

  });

});<commit_msg>rename refactoring<commit_after>/*global App */
'use strict';

App.module('Base.Helpers', function (Helpers, App) {

  Helpers.LayoutChanger = function(){};

  _.extend(Helpers.LayoutChanger.prototype, {

    initialize: function() {
      this.initializeLayouts();
      this.initializeViews();

      App.vent.on('layout_showed', this.showViews, this);
    },

    initializeLayouts: function() {
      this.layouts = {};
      this.layouts.counter = 0;
      this.layouts.list = [];
    },

    addLayout: function(layout) {
      this.layouts.list.push(layout);
    },

    initializeViews: function() {
      this.views = {};
      this.views.list = [];

      this.leftView = null;
      this.views.leftCounter = 0;

      this.rightView = null;
      this.views.rightCounter = 0;
    },

    addView: function(view) {
      this.views.list.push(view);
    },

    getNextLayout : function() {
      this.layouts.counter += 1;
      var layout = this.getCurrentLayout();

      App.vent.trigger('new_layout', layout);

      return layout;
    },

    countVisibleViews: function() {
      var visibleViews = 0;
      if(!_.isNull(this.leftView)){
        visibleViews++;
      }
      if(!_.isNull(this.rightView)){
        visibleViews++;
      }

      return visibleViews;
    },

    showViews: function() {
      var rmArray = this.regionManagerArray();
      var hasOneRegion = rmArray.length === 1;
      var hasTwoRegions = rmArray.length === 2;
      var visibleViews = this.countVisibleViews();
      var isLeftNull = _.isNull(this.leftView);
      var isRightNull = _.isNull(this.rightView);

      var needToChangeLayout =  (rmArray.length === 1 && visibleViews === 2) ||
                                (rmArray.length === 2 && visibleViews === 1);
      if(needToChangeLayout){
        this.getNextLayout();
        this.showViews();
        return;
      }

      // full screen
      if( hasOneRegion ){

        var onlyRightViewVisible = isLeftNull  && !isRightNull;
        var onlyLeftViewVisible  = isRightNull && !isLeftNull;

        if( onlyRightViewVisible ) {
          rmArray[0].show(this.rightView);
        }
        else if ( onlyLeftViewVisible ) {
          rmArray[0].show(this.leftView);
        }
        else{
          rmArray[0].close();
        }
      }

      // left and right
      if( hasTwoRegions ){
        if(!isLeftNull){
          rmArray[0].show(this.leftView);
        }
        if(!isRightNull){
          rmArray[1].show(this.rightView);
        }
      }

    },

    getCurrentLayout : function() {
      var index = this.layouts.counter % this.layouts.list.length;
      return this.layouts.list[index];
    },

    regionManagerArray: function() {
      return this.getCurrentLayout().regionManager.toArray();
    },

    getNextLeftView : function() {
      var total = this.views.list.length;
      var index = this.views.leftCounter % total;
      this.views.leftCounter += 1;

      if(!_.isNull(this.views.list[index])){
        this.leftView = new this.views.list[index]();
      }
      else{
        this.leftView = null;
      }

      this.showViews();

      return this.leftView;
    },

    getNextRightView : function() {
      var total = this.views.list.length;
      var index = this.views.rightCounter % total;
      this.views.rightCounter += 1;

      if(!_.isNull(this.views.list[index])){
        this.rightView = new this.views.list[index]();
      }
      else{
        this.rightView = null;
      }

      this.showViews();

      return this.rightView;
    },

  });

});<|endoftext|>


<commit_before>// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.

define([
    'base/js/namespace',
    'jquery',
    'base/js/utils',
    'base/js/dialog',
], function(IPython, $, utils, dialog) {
    "use strict";

    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;
        // 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.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); });
        }
    };

    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;
        });
    };

    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;
        }
        for (var i = 0; i < files.length; i++) {
            var f = files[i];
            var name_and_ext = utils.splitext(f.name);
            var file_ext = name_and_ext[1];

            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);
            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 = function (event) {
                var item = $(event.target).data('item');
                that.add_file_data(event.target.result, item);
                that.add_upload_button(item);
            };
            reader.onerror = function (event) {
                var item = $(event.target).data('item');
                var name = item.data('name');
                item.remove();
                dialog.modal({
                    title : 'Failed to read file',
                    body : "Failed to read file '" + name + "'",
                    buttons : {'OK' : { 'class' : 'btn-primary' }}
                });
            };
        }
        // Replace the file input form wth a clone of itself. 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.replaceWith(form.clone(true));
        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;
        this.contents.list_contents(that.notebook_path).then(
            $.proxy(this.draw_notebook_list, this),
            function(error) {
                that.draw_notebook_list({content: []}, "Server error: " + error.message);
            }
        );
    };

    /**
     * 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
     */
    NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
        var message = error_msg || 'Notebook list 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);
            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);
            this.add_link(model, item);
        }
    };

    NotebookList.prototype.new_item = function (index) {
        var item = $('<div/>').addClass("list_item").addClass("row");
        // item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
        // item.css('border-top-style','none');
        item.append($("<div/>").addClass("col-md-12").append(
            $('<i/>').addClass('item_icon')
        ).append(
            $("<a/>").addClass("item_link").append(
                $("<span/>").addClass("item_name")
            )
        ).append(
            $('<div/>').addClass("item_buttons btn-group pull-right")
        ));

        if (index === -1) {
            this.element.append(item);
        } else {
            this.element.children().eq(index).after(item);
        }
        return item;
    };

    NotebookList.icons = {
        directory: 'folder_icon',
        notebook: 'notebook_icon',
        file: 'file_icon',
    };

    NotebookList.uri_prefixes = {
        directory: 'tree',
        notebook: 'notebooks',
        file: 'files',
    };

    NotebookList.prototype.add_link = function (model, item) {
        var path = model.path,
            name = model.name;
        item.data('name', name);
        item.data('path', path);
        item.find(".item_name").text(name);
        var icon = NotebookList.icons[model.type];
        var uri_prefix = NotebookList.uri_prefixes[model.type];
        item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
        var link = item.find("a.item_link")
            .attr('href',
                utils.url_join_encode(
                    this.base_url,
                    uri_prefix,
                    path
                )
            );
        // directory nav doesn't open new tabs
        // files, notebooks do
        if (model.type !== "directory") {
            link.attr('target','_blank');
        }
        var path_name = utils.url_path_join(path, name);
        if (model.type == 'file') {
            this.add_delete_button(item);
        } else if (model.type == 'notebook') {
            if(this.sessions[path_name] === undefined){
                this.add_delete_button(item);
            } else {
                this.add_shutdown_button(item, this.sessions[path_name]);
            }
        }
    };

    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.add_shutdown_button = function (item, session) {
        var that = this;
        var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-xs btn-danger").
            click(function (e) {
                var settings = {
                    processData : false,
                    cache : false,
                    type : "DELETE",
                    dataType : "json",
                    success : function () {
                        that.load_sessions();
                    },
                    error : utils.log_ajax_error,
                };
                var url = utils.url_join_encode(
                    that.base_url,
                    'api/sessions',
                    session
                );
                $.ajax(url, settings);
                return false;
            });
        // var new_buttons = item.find('a'); // shutdown_button;
        item.find(".item_buttons").text("").append(shutdown_button);
    };

    NotebookList.prototype.add_delete_button = function (item) {
        var notebooklist = this;
        var delete_button = $("<button/>").text("Delete").addClass("btn btn-default btn-xs").
            click(function (e) {
                // $(this) is the button that was clicked.
                var that = $(this);
                // We use the filename from the parent list_item element's
                // data because the outer scope's values change as we iterate through the loop.
                var parent_item = that.parents('div.list_item');
                var name = parent_item.data('name');
                var path = parent_item.data('path');
                var message = 'Are you sure you want to permanently delete the file: ' + name + '?';
                dialog.modal({
                    title : "Delete file",
                    body : message,
                    buttons : {
                        Delete : {
                            class: "btn-danger",
                            click: function() {
                                notebooklist.contents.delete(path).then(
                                    function() {
                                        notebooklist.notebook_deleted(path);
                                    }
                                );
                            }
                        },
                        Cancel : {}
                    }
                });
                return false;
            });
        item.find(".item_buttons").text("").append(delete_button);
    };

    NotebookList.prototype.notebook_deleted = function(path) {
        // Remove the deleted notebook.
        $( ":data(path)" ).each(function() {
            var element = $(this);
            if (element.data("path") == path) {
                element.remove();
            }
        });
    };

    NotebookList.prototype.add_upload_button = function (item) {
        var that = this;
        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 filedata = item.data('filedata');
                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;
                }
                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 = {};

                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) {
                        dialog.modal({
                            title : 'Cannot upload invalid Notebook',
                            body : "The error was: " + e,
                            buttons : {'OK' : {
                                'class' : 'btn-primary',
                                click: function () {
                                    item.remove();
                                }
                            }}
                        });
                        return false;
                    }
                    content_type = 'application/json';
                } else {
                    model.type = 'file';
                    model.format = format;
                    model.content = filedata;
                    content_type = 'application/octet-stream';
                }
                filedata = item.data('filedata');

                var on_success = function () {
                    item.removeClass('new-file');
                    that.add_link(model, item);
                    that.add_delete_button(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) {
                    dialog.modal({
                        title : "Replace file",
                        body : 'There is already a file named ' + filename + ', do you want to replace it?',
                        buttons : {
                            Overwrite : {
                                class: "btn-danger",
                                click: function () {
                                    that.contents.save(path, model).then(on_success);
                                }
                            },
                            Cancel : {
                                click: function() { item.remove(); }
                            }
                        }
                    });
                } else {
                    that.contents.save(path, model).then(on_success);
                }

                return false;
            });
        var cancel_button = $('<button/>').text("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);
    };

    // Backwards compatability.
    IPython.NotebookList = NotebookList;

    return {'NotebookList': NotebookList};
});
<commit_msg>Add the "Duplicate" button in the main dashboard<commit_after>// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.

define([
    'base/js/namespace',
    'jquery',
    'base/js/utils',
    'base/js/dialog',
], function(IPython, $, utils, dialog) {
    "use strict";

    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;
        // 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.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); });
        }
    };

    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;
        });
    };

    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;
        }
        for (var i = 0; i < files.length; i++) {
            var f = files[i];
            var name_and_ext = utils.splitext(f.name);
            var file_ext = name_and_ext[1];

            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);
            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 = function (event) {
                var item = $(event.target).data('item');
                that.add_file_data(event.target.result, item);
                that.add_upload_button(item);
            };
            reader.onerror = function (event) {
                var item = $(event.target).data('item');
                var name = item.data('name');
                item.remove();
                dialog.modal({
                    title : 'Failed to read file',
                    body : "Failed to read file '" + name + "'",
                    buttons : {'OK' : { 'class' : 'btn-primary' }}
                });
            };
        }
        // Replace the file input form wth a clone of itself. 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.replaceWith(form.clone(true));
        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;
        this.contents.list_contents(that.notebook_path).then(
            $.proxy(this.draw_notebook_list, this),
            function(error) {
                that.draw_notebook_list({content: []}, "Server error: " + error.message);
            }
        );
    };

    /**
     * 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
     */
    NotebookList.prototype.draw_notebook_list = function (list, error_msg) {
        var message = error_msg || 'Notebook list 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);
            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);
            this.add_link(model, item);
        }
    };

    NotebookList.prototype.new_item = function (index) {
        var item = $('<div/>').addClass("list_item").addClass("row");
        // item.addClass('list_item ui-widget ui-widget-content ui-helper-clearfix');
        // item.css('border-top-style','none');
        item.append($("<div/>").addClass("col-md-12").append(
            $('<i/>').addClass('item_icon')
        ).append(
            $("<a/>").addClass("item_link").append(
                $("<span/>").addClass("item_name")
            )
        ).append(
            $('<div/>').addClass("item_buttons btn-group pull-right")
        ));

        if (index === -1) {
            this.element.append(item);
        } else {
            this.element.children().eq(index).after(item);
        }
        return item;
    };

    NotebookList.icons = {
        directory: 'folder_icon',
        notebook: 'notebook_icon',
        file: 'file_icon',
    };

    NotebookList.uri_prefixes = {
        directory: 'tree',
        notebook: 'notebooks',
        file: 'files',
    };

    NotebookList.prototype.add_link = function (model, item) {
        var path = model.path,
            name = model.name;
        item.data('name', name);
        item.data('path', path);
        item.find(".item_name").text(name);
        var icon = NotebookList.icons[model.type];
        var uri_prefix = NotebookList.uri_prefixes[model.type];
        item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
        var link = item.find("a.item_link")
            .attr('href',
                utils.url_join_encode(
                    this.base_url,
                    uri_prefix,
                    path
                )
            );
        // directory nav doesn't open new tabs
        // files, notebooks do
        if (model.type !== "directory") {
            link.attr('target','_blank');
        }
        var path_name = utils.url_path_join(path, name);
        if (model.type == 'file') {
            this.add_delete_button(item);
        } else if (model.type == 'notebook') {
            if(this.sessions[path_name] === undefined){
                this.add_delete_button(item);
                this.add_duplicate_button(item);
            } else {
                this.add_shutdown_button(item, this.sessions[path_name]);
            }
        }
    };

    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.add_shutdown_button = function (item, session) {
        var that = this;
        var shutdown_button = $("<button/>").text("Shutdown").addClass("btn btn-xs btn-danger").
            click(function (e) {
                var settings = {
                    processData : false,
                    cache : false,
                    type : "DELETE",
                    dataType : "json",
                    success : function () {
                        that.load_sessions();
                    },
                    error : utils.log_ajax_error,
                };
                var url = utils.url_join_encode(
                    that.base_url,
                    'api/sessions',
                    session
                );
                $.ajax(url, settings);
                return false;
            });
        // var new_buttons = item.find('a'); // shutdown_button;
        item.find(".item_buttons").append(shutdown_button);
    };

    NotebookList.prototype.add_duplicate_button = function (item) {
        var new_buttons = $('<span/>').addClass("btn-group pull-right");
        var notebooklist = this;
        var duplicate_button = $("<button/>").text("Duplicate").addClass("btn btn-defaultbtn-xs").
            click(function (e) {
                // $(this) is the button that was clicked.
                var that = $(this);
                // We use the nbname and notebook_id from the parent notebook_item element's
                // data because the outer scopes values change as we iterate through the loop.
                var parent_item = that.parents('div.list_item');
                var nbname = parent_item.data('nbname');
                var message = 'Are you sure you want to duplicate the notebook: ' + nbname + '?';
                var copy_from = {'copy_from' : nbname}
                IPython.dialog.modal({
                    title : "Duplicate notebook",
                    body : message,
                    buttons : {
                        Duplicate : {
                            class: "btn-primary",
                            click: function() {
                                var settings = {
                                    processData : false,
                                    cache : false,
                                    type : "POST",
                                    dataType : "json",
                                    data : JSON.stringify(copy_from),
                                    success : function (data, status, xhr) {
                                        notebooklist.load_list();
                                    }
                                };
                                var url = utils.url_join_encode(
                                    notebooklist.base_url,
                                    'api/notebooks',
                                    notebooklist.notebook_path
                                );
                                $.ajax(url, settings);
                            }
                        },
                        Cancel : {}
                    }
                });
                return false;
            });
        item.find(".item_buttons").append(duplicate_button);
    };

    NotebookList.prototype.add_delete_button = function (item) {
        var notebooklist = this;
        var delete_button = $("<button/>").text("Delete").addClass("btn btn-default btn-xs").
            click(function (e) {
                // $(this) is the button that was clicked.
                var that = $(this);
                // We use the filename from the parent list_item element's
                // data because the outer scope's values change as we iterate through the loop.
                var parent_item = that.parents('div.list_item');
                var name = parent_item.data('name');
                var path = parent_item.data('path');
                var message = 'Are you sure you want to permanently delete the file: ' + name + '?';
                dialog.modal({
                    title : "Delete file",
                    body : message,
                    buttons : {
                        Delete : {
                            class: "btn-danger",
                            click: function() {
                                notebooklist.contents.delete(path).then(
                                    function() {
                                        notebooklist.notebook_deleted(path);
                                    }
                                );
                            }
                        },
                        Cancel : {}
                    }
                });
                return false;
            });
        item.find(".item_buttons").append(delete_button);
    };

    NotebookList.prototype.notebook_deleted = function(path) {
        // Remove the deleted notebook.
        $( ":data(path)" ).each(function() {
            var element = $(this);
            if (element.data("path") == path) {
                element.remove();
            }
        });
    };

    NotebookList.prototype.add_upload_button = function (item) {
        var that = this;
        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 filedata = item.data('filedata');
                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;
                }
                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 = {};

                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) {
                        dialog.modal({
                            title : 'Cannot upload invalid Notebook',
                            body : "The error was: " + e,
                            buttons : {'OK' : {
                                'class' : 'btn-primary',
                                click: function () {
                                    item.remove();
                                }
                            }}
                        });
                        return false;
                    }
                    content_type = 'application/json';
                } else {
                    model.type = 'file';
                    model.format = format;
                    model.content = filedata;
                    content_type = 'application/octet-stream';
                }
                filedata = item.data('filedata');

                var on_success = function () {
                    item.removeClass('new-file');
                    that.add_link(model, item);
                    that.add_delete_button(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) {
                    dialog.modal({
                        title : "Replace file",
                        body : 'There is already a file named ' + filename + ', do you want to replace it?',
                        buttons : {
                            Overwrite : {
                                class: "btn-danger",
                                click: function () {
                                    that.contents.save(path, model).then(on_success);
                                }
                            },
                            Cancel : {
                                click: function() { item.remove(); }
                            }
                        }
                    });
                } else {
                    that.contents.save(path, model).then(on_success);
                }

                return false;
            });
        var cancel_button = $('<button/>').text("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);
    };

    // Backwards compatability.
    IPython.NotebookList = NotebookList;

    return {'NotebookList': NotebookList};
});
<|endoftext|>


<commit_before>/*
* jQuery Mobile Framework : "listview" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
(function($, undefined ) {

$.widget( "mobile.listview", $.mobile.widget, {
	options: {
		theme: "c",
		countTheme: "c",
		headerTheme: "b",
		dividerTheme: "b",
		splitIcon: "arrow-r",
		splitTheme: "b",
		inset: false
	},

	_create: function() {
		var $list = this.element,
			o = this.options;

		// create listview markup
		$list
			.addClass( "ui-listview" )
			.attr( "role", "listbox" )

		if ( o.inset ) {
			$list.addClass( "ui-listview-inset ui-corner-all ui-shadow" );
		}

		$list.delegate( ".ui-li", "focusin", function() {
			$( this ).attr( "tabindex", "0" );
		});

		this._itemApply( $list, $list );

		this.refresh( true );

		//keyboard events for menu items
		$list.keydown(function( e ) {
			var target = $( e.target ),
				li = target.closest( "li" );

			// switch logic based on which key was pressed
			switch ( e.keyCode ) {
				// up or left arrow keys
				case 38:
					var prev = li.prev();

					// if there's a previous option, focus it
					if ( prev.length ) {
						target
							.blur()
							.attr( "tabindex", "-1" );

						prev.find( "a" ).first().focus();
					}

					return false;
				break;

				// down or right arrow keys
				case 40:
					var next = li.next();

					// if there's a next option, focus it
					if ( next.length ) {
						target
							.blur()
							.attr( "tabindex", "-1" );

						next.find( "a" ).first().focus();
					}

					return false;
				break;

				case 39:
					var a = li.find( "a.ui-li-link-alt" );

					if ( a.length ) {
						target.blur();
						a.first().focus();
					}

					return false;
				break;

				case 37:
					var a = li.find( "a.ui-link-inherit" );

					if ( a.length ) {
						target.blur();
						a.first().focus();
					}

					return false;
				break;

				// if enter or space is pressed, trigger click
				case 13:
				case 32:
					 target.trigger( "click" );

					 return false;
				break;
			}
		});

		// tapping the whole LI triggers click on the first link
		$list.delegate( "li", "click", function(event) {
			if ( !$( event.target ).closest( "a" ).length ) {
				$( this ).find( "a" ).first().trigger( "click" );
				return false;
			}
		});

	},

	_itemApply: function( $list, item ) {
		// TODO class has to be defined in markup
		item.find( ".ui-li-count" )
			.addClass( "ui-btn-up-" + ($list.data( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );

		item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" );

		item.find( "p, dl" ).addClass( "ui-li-desc" );

		$list.find( "li" ).find( "img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
			$( this ).closest( "li" )
				.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
		});

		var aside = item.find( ".ui-li-aside" );

		if ( aside.length ) {
            aside.each(function(i, el) {
			    $(el).prependTo( $(el).parent() ); //shift aside to front for css float
            });
		}

		if ( $.support.cssPseudoElement || !$.nodeName( item[0], "ol" ) ) {
			return;
		}
	},

	_removeCorners: function(li){
		li
			.add( li.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb") )
			.removeClass( "ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl" );
	},

	refresh: function( create ) {
		this._createSubPages();

		var o = this.options,
			$list = this.element,
			self = this,
			dividertheme = $list.data( "dividertheme" ) || o.dividerTheme,
			li = $list.children( "li" ),
			counter = $.support.cssPseudoElement || !$.nodeName( $list[0], "ol" ) ? 0 : 1;

		if ( counter ) {
			$list.find( ".ui-li-dec" ).remove();
		}

		li.attr({ "role": "option", "tabindex": "-1" });

		li.first().attr( "tabindex", "0" );

		//workaround for Windows Phone 7 focus/active tap color
		//without this, delegated events will highlight the whole list, rather than the LI
		if( $.mobile.browser.ie && $.mobile.browser.ie <= 8 ){
			li
				.unbind( "mousedown.iefocus" )
				.bind( "mousedown.iefocus", function(e){
					e.preventDefault();
				});
		}

		li.each(function( pos ) {
			var item = $( this ),
				itemClass = "ui-li";

			// If we're creating the element, we update it regardless
			if ( !create && item.hasClass( "ui-li" ) ) {
				return;
			}

			var itemTheme = item.data("theme") || o.theme;

			var a = item.find( "a" );

			if ( a.length ) {
				var icon = item.data("icon");

				item
					.buttonMarkup({
						wrapperEls: "div",
						shadow: false,
						corners: false,
						iconpos: "right",
						icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
						theme: itemTheme
					});

				a.first().addClass( "ui-link-inherit" );

				if ( a.length > 1 ) {
					itemClass += " ui-li-has-alt";

					var last = a.last(),
						splittheme = $list.data( "splittheme" ) || last.data( "theme" ) || o.splitTheme;

					last
						.appendTo(item)
						.attr( "title", last.text() )
						.addClass( "ui-li-link-alt" )
						.empty()
						.buttonMarkup({
							shadow: false,
							corners: false,
							theme: itemTheme,
							icon: false,
							iconpos: false
						})
						.find( ".ui-btn-inner" )
							.append( $( "" ).buttonMarkup({
								shadow: true,
								corners: true,
								theme: splittheme,
								iconpos: "notext",
								icon: $list.data( "spliticon" ) || last.data( "icon" ) ||  o.splitIcon
							} ) );
				}

			} else if ( item.data( "role" ) === "list-divider" ) {
				itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
				item.attr( "role", "heading" );

				//reset counter when a divider heading is encountered
				if ( counter ) {
					counter = 1;
				}

			} else {
				itemClass += " ui-li-static ui-btn-up-" + itemTheme;
			}

			if( o.inset ){
				if ( pos === 0 ) {
						itemClass += " ui-corner-top";

						item
							.add( item.find( ".ui-btn-inner" ) )
							.find( ".ui-li-link-alt" )
								.addClass( "ui-corner-tr" )
							.end()
							.find( ".ui-li-thumb" )
								.addClass( "ui-corner-tl" );
						if(item.next().next().length){
							self._removeCorners( item.next() );
						}

				}
				if ( pos === li.length - 1 ) {
						itemClass += " ui-corner-bottom";

						item
							.add( item.find( ".ui-btn-inner" ) )
							.find( ".ui-li-link-alt" )
								.addClass( "ui-corner-br" )
							.end()
							.find( ".ui-li-thumb" )
								.addClass( "ui-corner-bl" );

						if(item.prev().prev().length){
							self._removeCorners( item.prev() );
						}
				}
			}

			if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
				item
					.find( ".ui-link-inherit" ).first()
					.addClass( "ui-li-jsnumbering" )
					.prepend( "" + (counter++) + ". " );
			}

			item.addClass( itemClass );

			if ( !create ) {
				self._itemApply( $list, item );
			}
		});
	},

	//create a string for ID/subpage url creation
	_idStringEscape: function( str ){
		return str.replace(/[^a-zA-Z0-9]/g, '-');
	},

	_createSubPages: function() {
		var parentList = this.element,
			parentPage = parentList.closest( ".ui-page" ),
			parentId = parentPage.data( "url" ),
			o = this.options,
			self = this,
			persistentFooterID = parentPage.find( "[data-role='footer']" ).data( "id" );

		$( parentList.find( "ul, ol" ).toArray().reverse() ).each(function( i ) {
			var list = $( this ),
				parent = list.parent(),
				title = $.trim(parent.contents()[ 0 ].nodeValue) || parent.find('a:first').text(),
				id = parentId + "&" + $.mobile.subPageUrlKey + "=" + self._idStringEscape(title + " " + i),
				theme = list.data( "theme" ) || o.theme,
				countTheme = list.data( "counttheme" ) || parentList.data( "counttheme" ) || o.countTheme,
				newPage = list.wrap( "

" )
							.parent()
								.before( "

" + title + "

" )
								.after( persistentFooterID ? $( "
", { "data-role": "footer", "data-id": persistentFooterID, "class": "ui-footer-duplicate" } ) : "" )
								.parent()
									.attr({
										"data-url": id,
										"data-theme": theme,
										"data-count-theme": countTheme
									})
									.appendTo( $.mobile.pageContainer );

				newPage.page();
			var anchor = parent.find('a:first');
			if (!anchor.length) {
				anchor = $("").html(title).prependTo(parent.empty());
			}
			anchor.attr('href','#' + id);
		}).listview();
	}
});

})( jQuery );
<commit_msg>Bug fix: only apply thumb style if img tag is on the first level. This fixes the problem when you want multiple images on each li element, like a 5 star rating for each element for example. Now to add multiple images you just have to put them in a div.<commit_after>/*
* jQuery Mobile Framework : "listview" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
(function($, undefined ) {

$.widget( "mobile.listview", $.mobile.widget, {
	options: {
		theme: "c",
		countTheme: "c",
		headerTheme: "b",
		dividerTheme: "b",
		splitIcon: "arrow-r",
		splitTheme: "b",
		inset: false
	},

	_create: function() {
		var $list = this.element,
			o = this.options;

		// create listview markup
		$list
			.addClass( "ui-listview" )
			.attr( "role", "listbox" )

		if ( o.inset ) {
			$list.addClass( "ui-listview-inset ui-corner-all ui-shadow" );
		}

		$list.delegate( ".ui-li", "focusin", function() {
			$( this ).attr( "tabindex", "0" );
		});

		this._itemApply( $list, $list );

		this.refresh( true );

		//keyboard events for menu items
		$list.keydown(function( e ) {
			var target = $( e.target ),
				li = target.closest( "li" );

			// switch logic based on which key was pressed
			switch ( e.keyCode ) {
				// up or left arrow keys
				case 38:
					var prev = li.prev();

					// if there's a previous option, focus it
					if ( prev.length ) {
						target
							.blur()
							.attr( "tabindex", "-1" );

						prev.find( "a" ).first().focus();
					}

					return false;
				break;

				// down or right arrow keys
				case 40:
					var next = li.next();

					// if there's a next option, focus it
					if ( next.length ) {
						target
							.blur()
							.attr( "tabindex", "-1" );

						next.find( "a" ).first().focus();
					}

					return false;
				break;

				case 39:
					var a = li.find( "a.ui-li-link-alt" );

					if ( a.length ) {
						target.blur();
						a.first().focus();
					}

					return false;
				break;

				case 37:
					var a = li.find( "a.ui-link-inherit" );

					if ( a.length ) {
						target.blur();
						a.first().focus();
					}

					return false;
				break;

				// if enter or space is pressed, trigger click
				case 13:
				case 32:
					 target.trigger( "click" );

					 return false;
				break;
			}
		});

		// tapping the whole LI triggers click on the first link
		$list.delegate( "li", "click", function(event) {
			if ( !$( event.target ).closest( "a" ).length ) {
				$( this ).find( "a" ).first().trigger( "click" );
				return false;
			}
		});

	},

	_itemApply: function( $list, item ) {
		// TODO class has to be defined in markup
		item.find( ".ui-li-count" )
			.addClass( "ui-btn-up-" + ($list.data( "counttheme" ) || this.options.countTheme) + " ui-btn-corner-all" );

		item.find( "h1, h2, h3, h4, h5, h6" ).addClass( "ui-li-heading" );

		item.find( "p, dl" ).addClass( "ui-li-desc" );

		$list.find( "li" ).children( "img:eq(0)" ).addClass( "ui-li-thumb" ).each(function() {
			$( this ).closest( "li" )
				.addClass( $(this).is( ".ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
		});

		var aside = item.find( ".ui-li-aside" );

		if ( aside.length ) {
            aside.each(function(i, el) {
			    $(el).prependTo( $(el).parent() ); //shift aside to front for css float
            });
		}

		if ( $.support.cssPseudoElement || !$.nodeName( item[0], "ol" ) ) {
			return;
		}
	},

	_removeCorners: function(li){
		li
			.add( li.find(".ui-btn-inner, .ui-li-link-alt, .ui-li-thumb") )
			.removeClass( "ui-corner-top ui-corner-bottom ui-corner-br ui-corner-bl ui-corner-tr ui-corner-tl" );
	},

	refresh: function( create ) {
		this._createSubPages();

		var o = this.options,
			$list = this.element,
			self = this,
			dividertheme = $list.data( "dividertheme" ) || o.dividerTheme,
			li = $list.children( "li" ),
			counter = $.support.cssPseudoElement || !$.nodeName( $list[0], "ol" ) ? 0 : 1;

		if ( counter ) {
			$list.find( ".ui-li-dec" ).remove();
		}

		li.attr({ "role": "option", "tabindex": "-1" });

		li.first().attr( "tabindex", "0" );

		//workaround for Windows Phone 7 focus/active tap color
		//without this, delegated events will highlight the whole list, rather than the LI
		if( $.mobile.browser.ie && $.mobile.browser.ie <= 8 ){
			li
				.unbind( "mousedown.iefocus" )
				.bind( "mousedown.iefocus", function(e){
					e.preventDefault();
				});
		}

		li.each(function( pos ) {
			var item = $( this ),
				itemClass = "ui-li";

			// If we're creating the element, we update it regardless
			if ( !create && item.hasClass( "ui-li" ) ) {
				return;
			}

			var itemTheme = item.data("theme") || o.theme;

			var a = item.find( "a" );

			if ( a.length ) {
				var icon = item.data("icon");

				item
					.buttonMarkup({
						wrapperEls: "div",
						shadow: false,
						corners: false,
						iconpos: "right",
						icon: a.length > 1 || icon === false ? false : icon || "arrow-r",
						theme: itemTheme
					});

				a.first().addClass( "ui-link-inherit" );

				if ( a.length > 1 ) {
					itemClass += " ui-li-has-alt";

					var last = a.last(),
						splittheme = $list.data( "splittheme" ) || last.data( "theme" ) || o.splitTheme;

					last
						.appendTo(item)
						.attr( "title", last.text() )
						.addClass( "ui-li-link-alt" )
						.empty()
						.buttonMarkup({
							shadow: false,
							corners: false,
							theme: itemTheme,
							icon: false,
							iconpos: false
						})
						.find( ".ui-btn-inner" )
							.append( $( "" ).buttonMarkup({
								shadow: true,
								corners: true,
								theme: splittheme,
								iconpos: "notext",
								icon: $list.data( "spliticon" ) || last.data( "icon" ) ||  o.splitIcon
							} ) );
				}

			} else if ( item.data( "role" ) === "list-divider" ) {
				itemClass += " ui-li-divider ui-btn ui-bar-" + dividertheme;
				item.attr( "role", "heading" );

				//reset counter when a divider heading is encountered
				if ( counter ) {
					counter = 1;
				}

			} else {
				itemClass += " ui-li-static ui-btn-up-" + itemTheme;
			}

			if( o.inset ){
				if ( pos === 0 ) {
						itemClass += " ui-corner-top";

						item
							.add( item.find( ".ui-btn-inner" ) )
							.find( ".ui-li-link-alt" )
								.addClass( "ui-corner-tr" )
							.end()
							.find( ".ui-li-thumb" )
								.addClass( "ui-corner-tl" );
						if(item.next().next().length){
							self._removeCorners( item.next() );
						}

				}
				if ( pos === li.length - 1 ) {
						itemClass += " ui-corner-bottom";

						item
							.add( item.find( ".ui-btn-inner" ) )
							.find( ".ui-li-link-alt" )
								.addClass( "ui-corner-br" )
							.end()
							.find( ".ui-li-thumb" )
								.addClass( "ui-corner-bl" );

						if(item.prev().prev().length){
							self._removeCorners( item.prev() );
						}
				}
			}

			if ( counter && itemClass.indexOf( "ui-li-divider" ) < 0 ) {
				item
					.find( ".ui-link-inherit" ).first()
					.addClass( "ui-li-jsnumbering" )
					.prepend( "" + (counter++) + ". " );
			}

			item.addClass( itemClass );

			if ( !create ) {
				self._itemApply( $list, item );
			}
		});
	},

	//create a string for ID/subpage url creation
	_idStringEscape: function( str ){
		return str.replace(/[^a-zA-Z0-9]/g, '-');
	},

	_createSubPages: function() {
		var parentList = this.element,
			parentPage = parentList.closest( ".ui-page" ),
			parentId = parentPage.data( "url" ),
			o = this.options,
			self = this,
			persistentFooterID = parentPage.find( "[data-role='footer']" ).data( "id" );

		$( parentList.find( "ul, ol" ).toArray().reverse() ).each(function( i ) {
			var list = $( this ),
				parent = list.parent(),
				title = $.trim(parent.contents()[ 0 ].nodeValue) || parent.find('a:first').text(),
				id = parentId + "&" + $.mobile.subPageUrlKey + "=" + self._idStringEscape(title + " " + i),
				theme = list.data( "theme" ) || o.theme,
				countTheme = list.data( "counttheme" ) || parentList.data( "counttheme" ) || o.countTheme,
				newPage = list.wrap( "

" )
							.parent()
								.before( "

" + title + "

" )
								.after( persistentFooterID ? $( "
", { "data-role": "footer", "data-id": persistentFooterID, "class": "ui-footer-duplicate" } ) : "" )
								.parent()
									.attr({
										"data-url": id,
										"data-theme": theme,
										"data-count-theme": countTheme
									})
									.appendTo( $.mobile.pageContainer );

				newPage.page();
			var anchor = parent.find('a:first');
			if (!anchor.length) {
				anchor = $("").html(title).prependTo(parent.empty());
			}
			anchor.attr('href','#' + id);
		}).listview();
	}
});

})( jQuery );
<|endoftext|>


<commit_before>function KeyboardInputManager() {
  this.events = {};

  if (window.navigator.msPointerEnabled) {
    //Internet Explorer 10 style
    this.eventTouchstart    = "MSPointerDown";
    this.eventTouchmove     = "MSPointerMove";
    this.eventTouchend      = "MSPointerUp";
  } else {
    this.eventTouchstart    = "touchstart";
    this.eventTouchmove     = "touchmove";
    this.eventTouchend      = "touchend";
  }

  this.listen();
}

KeyboardInputManager.prototype.on = function (event, callback) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(callback);
};

KeyboardInputManager.prototype.emit = function (event, data) {
  var callbacks = this.events[event];
  if (callbacks) {
    callbacks.forEach(function (callback) {
      callback(data);
    });
  }
};

KeyboardInputManager.prototype.listen = function () {
  var self = this;

  var map = {
    38: 0, // Up
    39: 1, // Right
    40: 2, // Down
    37: 3, // Left
    75: 0, // Vim up
    76: 1, // Vim right
    74: 2, // Vim down
    72: 3, // Vim left
    87: 0, // W
    68: 1, // D
    83: 2, // S
    65: 3  // A
  };

  // Respond to direction keys
  document.addEventListener("keydown", function (event) {
    var modifiers = event.altKey || event.ctrlKey || event.metaKey ||
                    event.shiftKey;
    var mapped    = map[event.which];

    if (!modifiers) {
      if (mapped !== undefined) {
        event.preventDefault();
        self.emit("move", mapped);
      }
    }

    // R key restarts the game
    if (!modifiers && event.which === 82) {
      self.restart.call(self, event);
    }
  });

  // Respond to button presses
  this.bindButtonPress(".retry-button", this.restart);
  this.bindButtonPress(".restart-button", this.restart);
  this.bindButtonPress(".keep-playing-button", this.keepPlaying);

  // Respond to swipe events
  var touchStartClientX, touchStartClientY;
  var gameContainer = document.getElementsByClassName("game-container")[0];

  gameContainer.addEventListener(this.eventTouchstart, function (event) {
    if ((!window.navigator.msPointerEnabled && event.touches.length > 1) ||
        event.targetTouches > 1) {
      return; // Ignore if touching with more than 1 finger
    }

    if (window.navigator.msPointerEnabled) {
      touchStartClientX = event.pageX;
      touchStartClientY = event.pageY;
    } else {
      touchStartClientX = event.touches[0].clientX;
      touchStartClientY = event.touches[0].clientY;
    }

    event.preventDefault();
  });

  gameContainer.addEventListener(this.eventTouchmove, function (event) {
    event.preventDefault();
  });

  gameContainer.addEventListener(this.eventTouchend, function (event) {
    if ((!window.navigator.msPointerEnabled && event.touches.length > 0) ||
        event.targetTouches > 0) {
      return; // Ignore if still touching with one or more fingers
    }

    var touchEndClientX, touchEndClientY;

    if (window.navigator.msPointerEnabled) {
      touchEndClientX = event.pageX;
      touchEndClientY = event.pageY;
    } else {
      touchEndClientX = event.changedTouches[0].clientX;
      touchEndClientY = event.changedTouches[0].clientY;
    }

    var dx = touchEndClientX - touchStartClientX;
    var absDx = Math.abs(dx);

    var dy = touchEndClientY - touchStartClientY;
    var absDy = Math.abs(dy);

    if (Math.max(absDx, absDy) > 10) {
      // (right : left) : (down : up)
      self.emit("move", absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 2 : 0));
    }
  });
};

KeyboardInputManager.prototype.restart = function (event) {
  event.preventDefault();
  this.emit("restart");
};

KeyboardInputManager.prototype.keepPlaying = function (event) {
  event.preventDefault();
  this.emit("keepPlaying");
};

KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
  var button = document.querySelector(selector);
  button.addEventListener("click", fn.bind(this));
  button.addEventListener(this.eventTouchend, fn.bind(this));
};
<commit_msg>Change Keyboard keys<commit_after>function KeyboardInputManager() {
  this.events = {};

  if (window.navigator.msPointerEnabled) {
    //Internet Explorer 10 style
    this.eventTouchstart    = "MSPointerDown";
    this.eventTouchmove     = "MSPointerMove";
    this.eventTouchend      = "MSPointerUp";
  } else {
    this.eventTouchstart    = "touchstart";
    this.eventTouchmove     = "touchmove";
    this.eventTouchend      = "touchend";
  }

  this.listen();
}

KeyboardInputManager.prototype.on = function (event, callback) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(callback);
};

KeyboardInputManager.prototype.emit = function (event, data) {
  var callbacks = this.events[event];
  if (callbacks) {
    callbacks.forEach(function (callback) {
      callback(data);
    });
  }
};

KeyboardInputManager.prototype.listen = function () {
  var self = this;

  var map = {
    38: 3, // Up
    39: 2, // Right
    40: 1, // Down
    37: 0, // Left
    75: 3, // Vim up
    76: 2, // Vim right
    74: 1, // Vim down
    72: 0, // Vim left
    87: 3, // W
    68: 2, // D
    83: 1, // S
    65: 0  // A
  };

  // Respond to direction keys
  document.addEventListener("keydown", function (event) {
    var modifiers = event.altKey || event.ctrlKey || event.metaKey ||
                    event.shiftKey;
    var mapped    = map[event.which];

    if (!modifiers) {
      if (mapped !== undefined) {
        event.preventDefault();
        self.emit("move", mapped);
      }
    }

    // R key restarts the game
    if (!modifiers && event.which === 82) {
      self.restart.call(self, event);
    }
  });

  // Respond to button presses
  this.bindButtonPress(".retry-button", this.restart);
  this.bindButtonPress(".restart-button", this.restart);
  this.bindButtonPress(".keep-playing-button", this.keepPlaying);

  // Respond to swipe events
  var touchStartClientX, touchStartClientY;
  var gameContainer = document.getElementsByClassName("game-container")[0];

  gameContainer.addEventListener(this.eventTouchstart, function (event) {
    if ((!window.navigator.msPointerEnabled && event.touches.length > 1) ||
        event.targetTouches > 1) {
      return; // Ignore if touching with more than 1 finger
    }

    if (window.navigator.msPointerEnabled) {
      touchStartClientX = event.pageX;
      touchStartClientY = event.pageY;
    } else {
      touchStartClientX = event.touches[0].clientX;
      touchStartClientY = event.touches[0].clientY;
    }

    event.preventDefault();
  });

  gameContainer.addEventListener(this.eventTouchmove, function (event) {
    event.preventDefault();
  });

  gameContainer.addEventListener(this.eventTouchend, function (event) {
    if ((!window.navigator.msPointerEnabled && event.touches.length > 0) ||
        event.targetTouches > 0) {
      return; // Ignore if still touching with one or more fingers
    }

    var touchEndClientX, touchEndClientY;

    if (window.navigator.msPointerEnabled) {
      touchEndClientX = event.pageX;
      touchEndClientY = event.pageY;
    } else {
      touchEndClientX = event.changedTouches[0].clientX;
      touchEndClientY = event.changedTouches[0].clientY;
    }

    var dx = touchEndClientX - touchStartClientX;
    var absDx = Math.abs(dx);

    var dy = touchEndClientY - touchStartClientY;
    var absDy = Math.abs(dy);

    if (Math.max(absDx, absDy) > 10) {
      // (right : left) : (down : up)
      self.emit("move", absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 2 : 0));
    }
  });
};

KeyboardInputManager.prototype.restart = function (event) {
  event.preventDefault();
  this.emit("restart");
};

KeyboardInputManager.prototype.keepPlaying = function (event) {
  event.preventDefault();
  this.emit("keepPlaying");
};

KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
  var button = document.querySelector(selector);
  button.addEventListener("click", fn.bind(this));
  button.addEventListener(this.eventTouchend, fn.bind(this));
};
<|endoftext|>


<commit_before>$(function() {

  // Storage of note model/properties.
  var notes = {};
  var resizeTimer; //set resizeTimer to empty so it resets on page load

  //entry point
  //caches note & image width, sets up resize handler
  var init = function() {
    findNotes();
    //on resize, run the function and reset the timeout
    //250 is the delay in milliseconds. Can be adjust as you see fit.
    $(window).resize(function() {
      clearTimeout(resizeTimer);
      resizeTimer = setTimeout(checkSize, 250);
    });
  }

  var findNotes = function() {
    $(".DC-note-container").each(function() { getCoordinates($(this)); /*swapURL(this);*/ });
  }

  //link notes to wapo embedder pages instead of document cloud
  //var swapURL = function(note) {
  //    var note = $(note);
  //    if (note.data('wapo')) {
  //        var newLink = note.data('wapo');
  //        note.find('a').attr('href', newLink);
  //        note.find('a').attr('target', '_blank');
  //    }
  //}

  // gets default/canonical positioning data from the DOM for note & stores it.
  var getCoordinates = function(noteEl) {
    var noteID = $(noteEl).attr('id');

    var wrapWidth     = noteEl.find(".DC-note-excerpt").width();
    var docWidth      = noteEl.find(".DC-note-image").width();
    var docTop        = noteEl.find(".DC-note-image").position().top;
    var lCoverWidth   = noteEl.find(".DC-left-cover").width();
    var rCoverWidth   = noteEl.find(".DC-right-cover").width();
    var excerptHeight = noteEl.find(".DC-note-excerpt").height();
    var excerptLeft   = noteEl.find(".DC-note-excerpt").position().left;
    var excerptWidth  = noteEl.find(".DC-note-excerpt").width();

    if (docWidth != 0 && !(notes[noteID])) { //don't store notes that are set to display none
      var note = {
        x1: lCoverWidth,
        x2: 750 - rCoverWidth,
        y1: -1* docTop,
        y2: -1* docTop + excerptHeight,

        noteID: noteID,
        wrapWidth: wrapWidth,
        docWidth: docWidth,
        docTop: docTop,
        lCoverWidth: lCoverWidth,
        rCoverWidth: rCoverWidth,
        excerptHeight: excerptHeight,
        excerptLeft: excerptLeft,
        excerptWidth: excerptWidth,

        noteWidth: 750 - (lCoverWidth + rCoverWidth)
      }

      notes[noteID] = note;
    }
    checkSize();
  }

  //diffs the note's natural width with its current width and decides what to do
  var checkSize = function() {
    $.each(notes, function() {
      var noteElem = $("#" + this.noteID); // the notes lookup should just cache the element.
      var newWrapWidth = noteElem.find('.DC-note-excerpt-wrap').width(); // Get viewable width

      //if viewable width < left cover width + note width, kill left cover & scale!
      ( newWrapWidth < this.lCoverWidth+this.noteWidth ) ? resizeDoc(this.noteID) : restoreDoc(this.noteID);
    });
  }

  //calculates scaling factor based on the new note width & updates the note element's attributes
  var resizeDoc = function(noteID) {
    //original values
    var natNoteWidth = notes[noteID].noteWidth;
    var natWrapWidth = notes[noteID].wrapWidth;
    var natDocWidth  = notes[noteID].docWidth;

    //new values after resize of browser
    var newWrapWidth = $("#" + noteID + " .DC-note-excerpt-wrap").width();

    //calculate new width of document image
    var newDocWidth = natDocWidth - natNoteWidth + newWrapWidth;

    var scaling_factor   = newDocWidth / natDocWidth;
    var newExcerptWidth  = (notes[noteID].excerptWidth)  * scaling_factor;
    var newExcerptHeight = (notes[noteID].excerptHeight) * scaling_factor;

    //new x1,x2,y1,y2
    var newX1 = (notes[noteID].x1) * scaling_factor;
    var newX2 = (notes[noteID].x2) * scaling_factor;

    //apply calculations to elements
    scaleNoteImage(noteID, {
      imageHeight:     newExcerptHeight,
      imageWidth:      newDocWidth,
      leftCoverWidth:  newX1,
      excerptWidth:    newExcerptWidth,
      rightCoverWidth: newExcerptWidth - newX2,
      imageTop:        (notes[noteID].docTop) * scaling_factor,
      excerptLeft:     -1 * newX1
    });
  }

  //sets note element's attributes back to default
  var restoreDoc = function(noteID) {
    scaleNoteImage(noteID, {
      imageHeight:     notes[noteID].excerptHeight,
      imageWidth:      notes[noteID].docWidth,
      leftCoverWidth:  notes[noteID].lCoverWidth,
      excerptWidth:    notes[noteID].excerptWidth,
      rightCoverWidth: notes[noteID].rCoverWidth,
      imageTop:        notes[noteID].docTop,
      excerptLeft:     notes[noteID].excerptLeft
    });
  }

  var scaleNoteImage = function(noteID,dimensions){
    // set heights for note images.
    var noteEl = $("#"+noteID);
    noteEl.find(".DC-note-excerpt").height(dimensions.imageHeight);
    noteEl.find(".DC-left-cover"  ).height(dimensions.imageHeight);
    noteEl.find(".DC-right-cover" ).height(dimensions.imageHeight);

    // Set widths of viewable area, left cover, note excerpt, and right cover.
    noteEl.find(".DC-note-image"  ).width(dimensions.imageWidth);
    noteEl.find(".DC-left-cover"  ).width(dimensions.leftCoverWidth);
    noteEl.find(".DC-note-excerpt").width(dimensions.excerptWidth);
    noteEl.find(".DC-right-cover" ).width(dimensions.rightCoverWidth);

    // position left cover & note excerpt
    noteEl.find(".DC-note-image"  ).css('top', dimensions.imageTop);
    noteEl.find(".DC-note-excerpt").css('left', dimensions.excerptLeft);
  }

  //footnote click
  $(document).on('click', '.link-fn', function() {
    var fnLink = $(this);
    var fnLinkIcon = $(this).find('.fa');
    var fnID = $(this).data('fn');
    var footnote = $('#footnote' + fnID);
    if (footnote.hasClass('show')) {
      footnote.removeClass('show');
      footnote.slideUp({
        duration: 800,
        easing: 'swing'
      });
      fnLink.removeClass('reverse');
    } else {
      footnote.addClass('show');
      footnote.slideDown({
        duration: 800,
        easing: 'swing'
      });
      fnLink.addClass('reverse');
      //add note to notes and run subsequent functions
      var note = $(footnote).find('.DC-note-container');
      getCoords(note);
    }
    if (fnLinkIcon.hasClass('fa-caret-down')) {
      fnLinkIcon.removeClass('fa-caret-down').addClass('fa-caret-up');
    } else {
      fnLinkIcon.removeClass('fa-caret-up').addClass('fa-caret-down');
    }
  });

  $(window).load(function() {
    init();
  });

});
<commit_msg>Proposed description of when to resize.<commit_after>$(function() {

  // Storage of note model/properties.
  var notes = {};
  var resizeTimer; //set resizeTimer to empty so it resets on page load

  //entry point
  //caches note & image width, sets up resize handler
  var init = function() {
    findNotes();
    //on resize, run the function and reset the timeout
    //250 is the delay in milliseconds. Can be adjust as you see fit.
    $(window).resize(function() {
      clearTimeout(resizeTimer);
      resizeTimer = setTimeout(checkSize, 250);
    });
  }

  var findNotes = function() {
    $(".DC-note-container").each(function() { getCoordinates($(this)); /*swapURL(this);*/ });
  }

  //link notes to wapo embedder pages instead of document cloud
  //var swapURL = function(note) {
  //    var note = $(note);
  //    if (note.data('wapo')) {
  //        var newLink = note.data('wapo');
  //        note.find('a').attr('href', newLink);
  //        note.find('a').attr('target', '_blank');
  //    }
  //}

  // gets default/canonical positioning data from the DOM for note & stores it.
  var getCoordinates = function(noteEl) {
    var noteID = $(noteEl).attr('id');

    var wrapWidth     = noteEl.find(".DC-note-excerpt").width();
    var docWidth      = noteEl.find(".DC-note-image").width();
    var docTop        = noteEl.find(".DC-note-image").position().top;
    var lCoverWidth   = noteEl.find(".DC-left-cover").width();
    var rCoverWidth   = noteEl.find(".DC-right-cover").width();
    var excerptHeight = noteEl.find(".DC-note-excerpt").height();
    var excerptLeft   = noteEl.find(".DC-note-excerpt").position().left;
    var excerptWidth  = noteEl.find(".DC-note-excerpt").width();

    if (docWidth != 0 && !(notes[noteID])) { //don't store notes that are set to display none
      var note = {
        x1: lCoverWidth,
        x2: 750 - rCoverWidth,
        y1: -1* docTop,
        y2: -1* docTop + excerptHeight,

        noteID: noteID,
        wrapWidth: wrapWidth,
        docWidth: docWidth,
        docTop: docTop,
        lCoverWidth: lCoverWidth,
        rCoverWidth: rCoverWidth,
        excerptHeight: excerptHeight,
        excerptLeft: excerptLeft,
        excerptWidth: excerptWidth,

        noteWidth: 750 - (lCoverWidth + rCoverWidth)
      }

      notes[noteID] = note;
    }
    checkSize();
  }

  //diffs the note's natural width with its current width and decides what to do
  var checkSize = function() {
    $.each(notes, function() {
      var noteElem = $("#" + this.noteID); // the notes lookup should just cache the element.
      var newWrapWidth = noteElem.find('.DC-note-excerpt-wrap').width(); // Get viewable width

      //if viewable width < left cover width + note width, kill left cover
      //if viewable width <                    note width, scale!
      //else, restoreDoc
      ( newWrapWidth < this.lCoverWidth+this.noteWidth ) ? resizeDoc(this.noteID) : restoreDoc(this.noteID);
    });
  }

  //calculates scaling factor based on the new note width & updates the note element's attributes
  var resizeDoc = function(noteID) {
    //original values
    var natNoteWidth = notes[noteID].noteWidth;
    var natWrapWidth = notes[noteID].wrapWidth;
    var natDocWidth  = notes[noteID].docWidth;

    //new values after resize of browser
    var newWrapWidth = $("#" + noteID + " .DC-note-excerpt-wrap").width();

    //calculate new width of document image
    var newDocWidth = natDocWidth - natNoteWidth + newWrapWidth;

    var scaling_factor   = newDocWidth / natDocWidth;
    var newExcerptWidth  = (notes[noteID].excerptWidth)  * scaling_factor;
    var newExcerptHeight = (notes[noteID].excerptHeight) * scaling_factor;

    //new x1,x2,y1,y2
    var newX1 = (notes[noteID].x1) * scaling_factor;
    var newX2 = (notes[noteID].x2) * scaling_factor;

    //apply calculations to elements
    scaleNoteImage(noteID, {
      imageHeight:     newExcerptHeight,
      imageWidth:      newDocWidth,
      leftCoverWidth:  newX1,
      excerptWidth:    newExcerptWidth,
      rightCoverWidth: newExcerptWidth - newX2,
      imageTop:        (notes[noteID].docTop) * scaling_factor,
      excerptLeft:     -1 * newX1
    });
  }

  //sets note element's attributes back to default
  var restoreDoc = function(noteID) {
    scaleNoteImage(noteID, {
      imageHeight:     notes[noteID].excerptHeight,
      imageWidth:      notes[noteID].docWidth,
      leftCoverWidth:  notes[noteID].lCoverWidth,
      excerptWidth:    notes[noteID].excerptWidth,
      rightCoverWidth: notes[noteID].rCoverWidth,
      imageTop:        notes[noteID].docTop,
      excerptLeft:     notes[noteID].excerptLeft
    });
  }

  var scaleNoteImage = function(noteID,dimensions){
    // set heights for note images.
    var noteEl = $("#"+noteID);
    noteEl.find(".DC-note-excerpt").height(dimensions.imageHeight);
    noteEl.find(".DC-left-cover"  ).height(dimensions.imageHeight);
    noteEl.find(".DC-right-cover" ).height(dimensions.imageHeight);

    // Set widths of viewable area, left cover, note excerpt, and right cover.
    noteEl.find(".DC-note-image"  ).width(dimensions.imageWidth);
    noteEl.find(".DC-left-cover"  ).width(dimensions.leftCoverWidth);
    noteEl.find(".DC-note-excerpt").width(dimensions.excerptWidth);
    noteEl.find(".DC-right-cover" ).width(dimensions.rightCoverWidth);

    // position left cover & note excerpt
    noteEl.find(".DC-note-image"  ).css('top', dimensions.imageTop);
    noteEl.find(".DC-note-excerpt").css('left', dimensions.excerptLeft);
  }

  //footnote click
  $(document).on('click', '.link-fn', function() {
    var fnLink = $(this);
    var fnLinkIcon = $(this).find('.fa');
    var fnID = $(this).data('fn');
    var footnote = $('#footnote' + fnID);
    if (footnote.hasClass('show')) {
      footnote.removeClass('show');
      footnote.slideUp({
        duration: 800,
        easing: 'swing'
      });
      fnLink.removeClass('reverse');
    } else {
      footnote.addClass('show');
      footnote.slideDown({
        duration: 800,
        easing: 'swing'
      });
      fnLink.addClass('reverse');
      //add note to notes and run subsequent functions
      var note = $(footnote).find('.DC-note-container');
      getCoords(note);
    }
    if (fnLinkIcon.hasClass('fa-caret-down')) {
      fnLinkIcon.removeClass('fa-caret-down').addClass('fa-caret-up');
    } else {
      fnLinkIcon.removeClass('fa-caret-up').addClass('fa-caret-down');
    }
  });

  $(window).load(function() {
    init();
  });

});
<|endoftext|>


<commit_before>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * The "about us" dialog
 */
var AboutModal = Modal.extend({
    initialize: function() {
        _.extend(this.options, {
            title: "About " + Settings.VERSION
        });
    },

    events: {
    	'click a' : 'dummy'
    },

    dummy: function() { return true;},

    type: "info",

    message: Settings.VERSION + "
" +
        "http://www.analytical-labs.com/

"
        + "Powered by  http://meteorite.bi/ "
});
<commit_msg>close about modal on clicking ok<commit_after>/*
 *   Copyright 2012 OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

/**
 * The "about us" dialog
 */
var AboutModal = Modal.extend({
    initialize: function() {
        _.extend(this.options, {
            title: "About " + Settings.VERSION
        });
    },

    events: {
    	'click a' : 'close'
    },

    dummy: function() { return true;},

    type: "info",

    message: Settings.VERSION + "
" +
        "http://www.analytical-labs.com/

"
        + "Powered by  http://meteorite.bi/ "
});
<|endoftext|>


<commit_before>import { extend, override } from 'flarum/extend';
import IndexPage from 'flarum/components/IndexPage';
import DiscussionListState from 'flarum/states/DiscussionListState';
import GlobalSearchState from 'flarum/states/GlobalSearchState';
import classList from 'flarum/utils/classList';

import TagHero from './components/TagHero';

export default function() {
  IndexPage.prototype.currentTag = function() {
    if (this.currentActiveTag) {
      return this.currentActiveTag;
    }

    const slug = app.search.params().tags;
    let tag = null;

    if (slug) {
      tag = app.store.getBy('tags', 'slug', slug);
    }

    if (slug && !tag || (tag && !tag.isChild() && !tag.children())) {
      // Unlike the backend, no need to fetch parent.children because if we're on
      // a child tag page, then either:
      //    - We loaded in that child tag (and its siblings) in the API document
      //    - We first navigated to the current tag's parent, which would have loaded in the current tag's siblings.
      app.store.find('tags', slug, { include: 'children,children.parent,parent,state'}).then(() => {
        this.currentActiveTag = app.store.getBy('tags', 'slug', slug);

        m.redraw();
      });
    }

    if (tag) {
      this.currentActiveTag = tag;
      return this.currentActiveTag;
    }
  };

  // If currently viewing a tag, insert a tag hero at the top of the view.
  override(IndexPage.prototype, 'hero', function(original) {
    const tag = this.currentTag();

    if (tag) return <TagHero model={tag} />;

    return original();
  });

  extend(IndexPage.prototype, 'view', function(vdom) {
    const tag = this.currentTag();

    if (tag) vdom.attrs.className += ' IndexPage--tag'+tag.id();
  });

  extend(IndexPage.prototype, 'setTitle', function() {
    const tag = this.currentTag();

    if (tag) {
      app.setTitle(tag.name());
    }
  });

  // If currently viewing a tag, restyle the 'new discussion' button to use
  // the tag's color, and disable if the user isn't allowed to edit.
  extend(IndexPage.prototype, 'sidebarItems', function(items) {
    const tag = this.currentTag();

    if (tag) {
      const color = tag.color();
      const canStartDiscussion = tag.canStartDiscussion() || !app.session.user;
      const newDiscussion = items.get('newDiscussion');

      if (color) {
        newDiscussion.attrs.className = classList([newDiscussion.attrs.className, 'Button--tagColored']);
        newDiscussion.attrs.style = { '--color': color };
      }

      newDiscussion.attrs.disabled = !canStartDiscussion;
      newDiscussion.children = app.translator.trans(canStartDiscussion ? 'core.forum.index.start_discussion_button' : 'core.forum.index.cannot_start_discussion_button');
    }
  });

  // Add a parameter for the global search state to pass on to the
  // DiscussionListState that will let us filter discussions by tag.
  extend(GlobalSearchState.prototype, 'params', function(params) {
    params.tags = m.route.param('tags');
  });

  // Translate that parameter into a gambit appended to the search query.
  extend(DiscussionListState.prototype, 'requestParams', function(params) {
    params.include.push('tags', 'tags.parent');

    if (this.params.tags) {
      params.filter.tag = this.params.tags;
      // TODO: replace this with a more robust system.
      const q = params.filter.q;
      if (q) {
        params.filter.q = `${q} tag:${this.params.tags}`;
      }
    }
  });
}
<commit_msg>Fix tag page mismatches if accents/capitalizations differ in slug (#161)<commit_after>import { extend, override } from 'flarum/extend';
import IndexPage from 'flarum/components/IndexPage';
import DiscussionListState from 'flarum/states/DiscussionListState';
import GlobalSearchState from 'flarum/states/GlobalSearchState';
import classList from 'flarum/utils/classList';

import TagHero from './components/TagHero';

const findTag = slug => app.store.all('tags').find(tag => tag.slug().localeCompare(slug, undefined, { sensitivity: 'base' }) === 0);

export default function() {
  IndexPage.prototype.currentTag = function() {
    if (this.currentActiveTag) {
      return this.currentActiveTag;
    }

    const slug = app.search.params().tags;
    let tag = null;

    if (slug) {
      tag = findTag(slug);
    }

    if (slug && !tag || (tag && !tag.isChild() && !tag.children())) {
      if (this.currentTagLoading) {
        return;
      }

      this.currentTagLoading = true;

      // Unlike the backend, no need to fetch parent.children because if we're on
      // a child tag page, then either:
      //    - We loaded in that child tag (and its siblings) in the API document
      //    - We first navigated to the current tag's parent, which would have loaded in the current tag's siblings.
      app.store.find('tags', slug, { include: 'children,children.parent,parent,state'}).then(() => {
        this.currentActiveTag = findTag(slug);

        m.redraw();
      }).finally(() => {
        this.currentTagLoading = false;
      });
    }

    if (tag) {
      this.currentActiveTag = tag;
      return this.currentActiveTag;
    }
  };

  // If currently viewing a tag, insert a tag hero at the top of the view.
  override(IndexPage.prototype, 'hero', function(original) {
    const tag = this.currentTag();

    if (tag) return <TagHero model={tag} />;

    return original();
  });

  extend(IndexPage.prototype, 'view', function(vdom) {
    const tag = this.currentTag();

    if (tag) vdom.attrs.className += ' IndexPage--tag'+tag.id();
  });

  extend(IndexPage.prototype, 'setTitle', function() {
    const tag = this.currentTag();

    if (tag) {
      app.setTitle(tag.name());
    }
  });

  // If currently viewing a tag, restyle the 'new discussion' button to use
  // the tag's color, and disable if the user isn't allowed to edit.
  extend(IndexPage.prototype, 'sidebarItems', function(items) {
    const tag = this.currentTag();

    if (tag) {
      const color = tag.color();
      const canStartDiscussion = tag.canStartDiscussion() || !app.session.user;
      const newDiscussion = items.get('newDiscussion');

      if (color) {
        newDiscussion.attrs.className = classList([newDiscussion.attrs.className, 'Button--tagColored']);
        newDiscussion.attrs.style = { '--color': color };
      }

      newDiscussion.attrs.disabled = !canStartDiscussion;
      newDiscussion.children = app.translator.trans(canStartDiscussion ? 'core.forum.index.start_discussion_button' : 'core.forum.index.cannot_start_discussion_button');
    }
  });

  // Add a parameter for the global search state to pass on to the
  // DiscussionListState that will let us filter discussions by tag.
  extend(GlobalSearchState.prototype, 'params', function(params) {
    params.tags = m.route.param('tags');
  });

  // Translate that parameter into a gambit appended to the search query.
  extend(DiscussionListState.prototype, 'requestParams', function(params) {
    params.include.push('tags', 'tags.parent');

    if (this.params.tags) {
      params.filter.tag = this.params.tags;
      // TODO: replace this with a more robust system.
      const q = params.filter.q;
      if (q) {
        params.filter.q = `${q} tag:${this.params.tags}`;
      }
    }
  });
}
<|endoftext|>