talho/openphin

View on GitHub
app/assets/javascripts/documents/Documents.js

Summary

Maintainability
F
1 wk
Test Coverage
//= require ext_extensions/xActionColumn
//= require ext_extensions/SubmitFalse
//= require ext_extensions/ImageDisplayField
//= require ./AddEditFolderWindow
//= require ./DocumentViews
//= require_self

Ext.ns('Talho');

Talho.Documents = Ext.extend(function(){}, {
    constructor: function(config){
        Ext.apply(this, config);

        var blank_store = new Ext.data.Store({});

        this.file_actions = new Talho.ux.Documents.FileActions({listeners: {
            scope: this,
            'refresh': this._refresh
        }});

        this._createFolderTreeGrid();
        this.file_actions.folder_tree = this._folderTreeGrid;

        var panelConfig = {
            closable: true,
            layout: 'border',
            items:[
                {region: 'west', itemId: 'folder_tree_holder', xtype:'panel', layout: 'border', margins: '5 0 5 5', width: 300, border: false, split: true, items:[
                    this._folderTreeGrid,
                    {xtype: 'button', text: 'Search', region: 'south', handler: function(){
                        Application.fireEvent('opentab', {title: 'Search for Files', initializer: 'Talho.DocumentSearch'});
                    }}
                ]},
                {xtype: 'container', itemId: 'file_grid_holder', region: 'center', layout: 'card', margins: '5 5 5 0', activeItem: 0, items: [this._createFileIconView(blank_store), this._createFileGrid(blank_store)] }
            ],
            reset: this._refresh.createDelegate(this)
        };

        Ext.apply(panelConfig, config);

        var panel = new Ext.Panel(panelConfig);

        panel.on('afterrender', function(){this.file_actions.download_frame_target = this.getPanel().getEl(); }, this, {delay: 1});

        this.getPanel = function(){
            return panel;
        }
    },

    /**
     * Tree grid for the folders. Should have: 1) status icons (shared, public, etc), 2) a root level for Users (and My Folders),
     * 3) a context menu for actions such as editing and setting up sharing options,
     */
    _createFolderTreeGrid: function(){
        return this._folderTreeGrid =  new Ext.ux.maximgb.tg.GridPanel({
            title: 'Folders',
            frame: true,
            region: 'center',
            itemId: 'folder_grid',
            bodyCssClass: 'document-folder-tree-grid',
            margins: '0 0 5 0',
            hideHeaders: true,
            store: new Ext.ux.maximgb.tg.AdjacencyListStore({
                url: '/folders.json',
                restful: true,
                reader: new Ext.data.JsonReader({
                    fields: ['name', 'id', 'safe_id', 'parent_id', 'safe_parent_id', 'leaf', 'shared', 'is_owner', 'is_author', {name: 'type', mapping:'ftype'}, {name:'created_at', type: 'date', dateFormat: 'Y-m-d\\Th:i:sP'}, {name: 'updated_at', type: 'date', dateFormat: 'Y-m-d\\Th:i:sP'}],
                    idProperty: 'safe_id',
                    root: 'folders'
                }),
                parent_id_field_name: 'safe_parent_id',
                leaf_field_name: 'leaf',
                autoLoad: true,
                listeners: {
                    scope: this,
                    'load': {
                        single: true,
                        fn: function(store){
                          if (this.selected_folder_id === undefined) { this.selected_folder_id = 0; }
                          rowToSelect  =  store.getById(this.selected_folder_id);
                          this._folderTreeGrid.getSelectionModel().selectRecords([rowToSelect]);
                          if ( this.selected_folder_id === 0){ store.expandNode(rowToSelect); }
                        }
                    }
                }
            }),
            master_column_id: 'name_column',
            columns: [
                {xtype: 'xactioncolumn', icon: '/assets/shared.png', iconCls: 'folder-shared-icon', showField: 'shared', tooltip: 'Folder is shared with other users'},
                {id: 'name_column', header: '', dataIndex: 'name'},
                {xtype: 'xactioncolumn', icon: '/assets/arrow_down2.png', iconCls: 'folder-context-icon', showField: 'is_owner', tooltip: 'Show the folder context menu', handler: this.showFolderContextMenu, scope: this}
            ],
            sm: new Ext.grid.RowSelectionModel({
                single:true,
                listeners: {
                    scope: this,
                    'rowselect': function(sm, row, record){
                        if(!this._fileGrid){
                            this._fileGrid = this.getPanel().getComponent('file_grid_holder').getComponent('file_grid');
                        }
                        if(!this._iconView){
                            this._iconView = this.getPanel().getComponent('file_grid_holder').getComponent('file_icon_holder').getComponent('file_icon_view');
                        }

                        this.getPanel().getComponent('file_grid_holder').getComponent('file_icon_holder').setTitle(record.get('name'));
                        this._fileGrid.setTitle(record.get('name'));
                        this.getPanel().setTitle("Documents: " + record.get('name'));
                        this.getPanel().tab_config.title = "Documents: " + record.get('name');
                        if (record.id == 0 ) {
                          this.getPanel().tab_config.selected_folder_id = null;
                          this.getPanel().tab_config.id = "documents";
                        } else {
                          this.getPanel().tab_config.selected_folder_id = record.id;
                          this.getPanel().tab_config.id = "documents-" + record.id;
                        }

                        if(record.get('type') == 'share' && record.get('id') == null){
                            if(this._fileGrid){
                                var store = this._fileGrid.getStore();
                                if(store.proxy){
                                    store.removeAll();

                                    if(store.proxy.activeRequest){
                                        Ext.Ajax.abort(store.proxy.activeRequest);
                                        delete store.proxy.activeRequest;
                                    }
                                }
                            }
                        }
                        else{
                            this.showFiles(record);
                        }
                    },
                    'selectionchange': this._setFileControlsState
                }
            }),
            loadMask: true,
            autoExpandColumn: 'name_column',
            bbar: ['->', {text: 'Refresh', iconCls: '', scope: this, handler: this._refresh}, {text: 'Add Folder', itemId: 'add_folder_button', iconCls: 'documents-add-folder-icon', scope: this.file_actions, handler: this.file_actions.createNewFolder}],
            listeners: {
              scope: this,
              'rowclick': function(grid, rowIndex, e) {
                if(this._folderTreeGrid.getSelectionModel().isSelected(rowIndex)) {
                  this._iconView.clearSelections();
                }
              }
            }
        });
    },

    ddConfig: {

    },

    showFiles: function(record){
        var store = new Talho.ux.Documents.FileStore({
            url: '/folders/' + record.get('id') + '.json',
            autoLoad: true,
            listeners: {
                scope: this,
                'load': {delay: 1,
                  fn: function(store){
                     if(!this._iconView){
                        this._iconView = this.getPanel().getComponent('file_grid_holder').getComponent('file_icon_holder').getComponent('file_icon_view');
                     }
                     store.each(function(r){
                       if (r.get('type') === 'folder' || r.get('type') === 'share' ){
                          var dragdrop = new Ext.dd.DragSource(this._iconView.getNode(r), {ignoreSelf: true, ddGroup: 'FolderDD'});
                          dragdrop.dragData = r;
                        }
                     }, this)
                  }
                },
                'beforeload': function(store, options){
                    options['params'] = options['params'] || {};
                    options['params']['type'] = record.get('type');
                    return true;
                }
            }
        });

        this._fileGrid.reconfigure(store, this._fileGrid.getColumnModel());
        this._iconView.bindStore(store);
    },

    /**
     * Push this off into its own extension
     */
    _createFileGrid: function(store){
        return {
            xtype: 'grid',
            title: 'Files',
            itemId: 'file_grid',
            frame: true,
            loadMask: true,
            store: store,
            columns: [
                {header: 'Filename', dataIndex: 'name', id: 'filename_column', sortable: true},
                {header: 'Type', dataIndex: 'type', sortable: true},
                {header: 'Size', dataIndex: 'size', sortable: true},
                {header: 'Uploader', dataIndex: 'user_display_name', sortable: true}
            ],
            viewConfig: {
                enableRowBody: true,
                getRowClass: function(record, rowIndex, rp){
                    rp.body = '<span class="documents-detail-row-body">';
                    rp.body += '<span class="row-body-button download"><span class="documents-download-icon icon-16">&nbsp;</span><span class="inlineLink">Download File</span></span>';
                    rp.body += '<span class="row-body-button move"><span class="documents-move-icon icon-16">&nbsp;</span><span class="inlineLink">Move File</span></span>';
                    rp.body += '<span class="row-body-button replace"><span class="documents-replace-icon icon-16">&nbsp;</span><span class="inlineLink">Replace File</span></span>';
                    rp.body += '<span class="row-body-button delete"><span class="documents-delete-file-icon icon-16">&nbsp;</span><span class="inlineLink">Delete File</span></span>';
                    rp.body += "</span>";
                    return "documents-detail-row"
                }
            },
            autoExpandColumn: 'filename_column',
            tools: [{id: 'icon-view', scope: this, qtip: 'Icon View', handler: function(){
                this.getPanel().getComponent('file_grid_holder').layout.setActiveItem(0);
                this.getPanel().doLayout();
            }}],
            sm: new Ext.grid.RowSelectionModel({
                single:true,
                listeners: {
                    scope: this,
                    'selectionchange': this._setFileControlsState
                }
            }),
            listeners: {
                scope: this,
                'rowbodyclick': function(grid, index, event){
                    var elem = event.getTarget('.row-body-button', null, true);
                    if(elem.hasClass('download')){
                       this.file_actions.downloadFile()
                    }
                    else if(elem.hasClass('move')){
                        this.file_actions.moveItem();
                    }
                    else if(elem.hasClass('replace')){
                        this.file_actions.uploadFile('replace');
                    }
                    else if(elem.hasClass('delete')){
                        this.file_actions.deleteItem()
                    }
                }
            }
        };
    },

    _createFileIconView: function(store){

        return {
            xtype: 'panel',
            title: 'Files',
            layout: 'border',
            cls: 'document-icon-view-wrap',
            itemId: 'file_icon_holder',
            frame: true,
            items: [{
                xtype: 'document-fileiconview',
                store: store,
                region: 'center',
                listeners:{
                    scope: this,
                    'selectionchange': this._setFileControlsState,
                    'dblclick': function(gv, index){
                        var store = gv.getStore();
                        var rec = store.getAt(index);
                        if(rec.get('type') == 'folder'){
                            // open this folder in the view by selecting it in the folder list
                            var ftstore = this._folderTreeGrid.getStore();
                            var folder = ftstore.getAt( ftstore.findExact('id', rec.get('id') ) );
                            var ancestors = ftstore.getNodeAncestors(folder);
                            Ext.each(ancestors, function(ancestor){
                                ftstore.expandNode(ancestor);
                            });
                            this._folderTreeGrid.getSelectionModel().selectRecords([folder]);
                        } else {
                          var file = gv.getSelectedRecords()[0].data.doc_path
                          // create a hidden iframe, open the file
                          if(Application.rails_environment === 'cucumber')
                          {
                              Ext.Ajax.request({
                                  url: file,
                                  method: 'GET',
                                  success: function(){
                                      alert("Success");
                                  },
                                  failure: function(){
                                      alert("File Download Failed");
                                  }
                              })
                          }
                          else
                          {
                              if(!this._downloadFrame){
                                  this._downloadFrame = Ext.DomHelper.append(this.file_actions.download_frame_target.dom, {tag: 'iframe', style: 'width:0;height:0;'});
                                  Ext.EventManager.on(this._downloadFrame, 'load', function(){
                                      // in a very strange bit of convenience, the frame load event will only fire here IF there is an error
                                      // need to test the convenience on IE.
                                      Ext.Msg.alert('Could Not Load File', 'There was an error downloading the file you have requested. Please contact an administrator');
                                  }, this);
                              }

                              if(file.length > 0){
                                  this._downloadFrame.src = window.location.protocol + "//" + window.location.host + file;
                              }
                          }
                        }
                    }
                }},
                {region: 'east', xtype: 'document-filecontrols', itemId: 'file_controls', hidden: true, file_actions: this.file_actions }],
            tools: [
                {id: 'detail-view', scope: this, qtip: 'Detail View', handler: function(){
                    this.getPanel().getComponent('file_grid_holder').layout.setActiveItem(1);
                    this.getPanel().doLayout();
                }}
            ]
        }
    },

    showFileContextMenu: function(grid, index, event){
        if(event && event.preventDefault)
            event.preventDefault();

        var record = grid.getStore().getAt(index);

        var row = grid.getView().getRow(index);

        var fileContextMenu = new Ext.menu.Menu({
            defaultAlign: 'tl-br',
            defaultOffsets: [0, 2],
            items:[{itemId:'download', text:'Download File', iconCls: 'documents-download-icon'},
                {itemId: 'move', text: 'Move File', iconCls: 'documents-move-icon'},
                {itemId: 'delete', text: 'Delete File', iconCls: 'documents-delete-file-icon'},
                {itemId: 'direct_link', text: 'Generate direct link to file'}]
        });

        fileContextMenu.show(row);
    },

    showFolderContextMenu: function(grid, index, event){
        if(event && event.preventDefault)
            event.preventDefault();

        var record = grid.getStore().getAt(index);

        var row = grid.getView().getRow(index);

        if(!grid.getSelectionModel().isSelected(record)) grid.getSelectionModel().selectRecords([record]);

        var items = [{itemId:'add', text:'Add New Folder', iconCls: 'documents-add-folder-icon', handler: this.file_actions.createNewFolder, scope: this.file_actions}];

        if(record.get('id') != null && record.get('id') != 'null'){
            items.push({itemId:'edit', text:'Edit Folder', iconCls: 'documents-edit-folder-icon', handler: this.file_actions.createNewFolder.createDelegate(this.file_actions, ['edit'])});
            if(record.get('ftype') == 'folder')
                items.push({itemId: 'move', text: 'Move Folder', iconCls: 'documents-move-icon', handler: this.file_actions.moveItem, scope: this.file_actions});
            items.push({itemId: 'delete', text: 'Delete Folder', iconCls: 'documents-delete-folder-icon', handler: this.file_actions.deleteItem, scope: this.file_actions});
        }

        var fileContextMenu = new Ext.menu.Menu({
            defaultAlign: 'tl-br',
            defaultOffsets: [0, 2],
            items: items
        });

        fileContextMenu.show(row);
    },

    _setFileControlsState: function(control){
        if(!this._fileControls){
            this._fileControls = this.getPanel().getComponent('file_grid_holder').getComponent('file_icon_holder').getComponent('file_controls');
        }
        if(!this._add_folder_button){
          this._add_folder_button = this._folderTreeGrid.getBottomToolbar().getComponent('add_folder_button');
        }
        this._add_folder_button.hide();

        var selections = (control.getSelectedRecords || control.getSelections).apply(control);

        var folderSelections = this._folderTreeGrid.getSelectionModel().getSelections();
        if(selections.length < 1){ // we have no selection
            // let's see if there are any selected folders
            selections = folderSelections;
        }

        this.file_actions.current_selections = this._current_selections = selections;

        if(this._iconView.isVisible())
        {
            this._fileControls.show();

            if(selections.length > 1){ // we have more than one selection: display the actions you can perform on more than one doc/file. Currently we're set to be single select on everything so this shouldn't be a worry.

            }
            else if(selections.length == 1){ // we have exactly one selection. Let's work with it.
                var sel = selections[0];
                var show = [];
                if(folderSelections[0] && folderSelections[0].get('type').match(/share|organization/)){
                    if(folderSelections[0].get('is_owner')){
                        show.push('base_actions');
                        this._add_folder_button.show();
                    }
                    else if(folderSelections[0].get('is_author')){
                        show.push('author_actions');
                    }
                }
                else{
                    show.push('base_actions');
                }

                var type = sel.get('type');
                if(type == 'folder'){
                  // Make sure My Documents isn't selected
                  this._add_folder_button.show();
                  if(folderSelections[0].data.id === null && selections[0].id == 0) show.push('folder_detail_container');
                  else show.push('folder_detail_container','folder_action_container', 'move_action_container');
                    this._fileControls.applySectionDetails('folder_detail_container', {
                        'name': sel.get('name'),
                        'image': Talho.ux.Documents.mimeToImageClass('folder'),
                        'created_at': Ext.util.Format.date(sel.get('created_at'), 'n/j/y h:i A'),
                        'updated_at': Ext.util.Format.date(sel.get('updated_at'), 'n/j/y h:i A')
                    });
                }
                else if(type.match(/share|organization/)){ // we want to figure out what sharing permissions we have, eventually, but for now, roll with it
                    show.push('folder_detail_container');
                    if(sel.get('is_owner')){
                        show.push('folder_action_container', 'move_action_container');
                        this._add_folder_button.show();
                    }
                    this._fileControls.applySectionDetails('folder_detail_container', {
                        'name': sel.get('name'),
                        'image': Talho.ux.Documents.mimeToImageClass('folder'),
                        'created_at': Ext.util.Format.date(sel.get('created_at'), 'n/j/y h:i A'),
                        'updated_at': Ext.util.Format.date(sel.get('updated_at'), 'n/j/y h:i A')
                    });
                }
                else{
                    if(folderSelections[0] && folderSelections[0].get('type').match(/share|organization/)){  // we want to figure out what sharing permissions we have, eventually, but for now, roll with it
                        show.push('copy_action_container', 'file_detail_container');
                        if(folderSelections[0].get('is_owner')){
                            show.push('move_action_container');
                        }
                        if(folderSelections[0].get('is_author')){
                            show.push('file_action_container');
                        }
                        else{
                            show.push('file_reader_action_container');
                        }
                    }
                    else{
                        show.push('file_detail_container', 'file_action_container', 'move_action_container');
                        this._add_folder_button.show();
                    }

                    this._fileControls.applySectionDetails('file_detail_container', {
                        'name': sel.get('name'),
                        'image': Talho.ux.Documents.mimeToImageClass(sel.get('type')),
                        'type': Talho.ux.Documents.translateMimeType(sel.get('type')),
                        'size': Ext.util.Format.fileSize(sel.get('size')),
                        'created_at': Ext.util.Format.date(sel.get('created_at'), 'n/j/y h:i A'),
                        'updated_at': Ext.util.Format.date(sel.get('updated_at'), 'n/j/y h:i A')
                    });
                }

                this._fileControls.setSectionVisibilities(show);
            }
            else{ // there really is no selection. Let's hide it all because we have no clue what to do
                this._fileControls.hide();
            }
            this._fileControls.ownerCt.doLayout();
        }
    },
        
    _refresh: function(){
        if(this._fileGrid) this._fileGrid.getStore().load();
        this._folderTreeGrid.getStore().setActiveNode(null);
        this._folderTreeGrid.getStore().load({scope: this, callback: function(){
            var sel = this._folderTreeGrid.getSelectionModel().getSelected();
            if(sel){
                var store = this._folderTreeGrid.getStore();
                var ancestors = store.getNodeAncestors(sel);
                Ext.each(ancestors, function(ancestor){
                    store.expandNode(ancestor);
                });
                store.expandNode(sel);
            }
        }});
    }

});

Talho.Documents.initializer = function(config){
    var documents = new Talho.Documents(config);
    return documents.getPanel();
};

Talho.ScriptManager.reg('Talho.Documents', Talho.Documents, Talho.Documents.initializer);