Ext.namespace('ui', 'ui.cmp', 'ui.cmp._WorkTreeGrid', 'ui.cmp._WorkTreeGrid.menu'); //------------------------------------------------------------------------------ // WorkTreeGrid internals ui.cmp._WorkTreeGrid.SetProgress = new Ext.util.DelayedTask(function(){ new ui.task.SetFileProgressTask({ idDB: this.node.attributes.idDB, progress: this.node.attributes.progress }); }); // WorkTreeGrid : adminstrator items for the context menu // config - { module, from, node, folderNode, userNode } ui.cmp._WorkTreeGrid.menu.admin = function(config){ Ext.apply(this, config); this.init(); ui.cmp._WorkTreeGrid.menu.admin.superclass.constructor.call(this); }; Ext.extend(ui.cmp._WorkTreeGrid.menu.admin, Ext.menu.Item, { init: function() { var items; switch(this.from) { case 'file' : items = [{ scope: this, iconCls: 'iconSwitchLang', text: _('Change file\'s owner'), handler: function() { new ui.cmp.ChangeFileOwner({ fileIdDB: this.node.attributes.idDB, fileFolder: this.folderNode.attributes.task, fileName: this.node.attributes.task, currentOwner: this.userNode.attributes.task }); } },{ scope: this, iconCls: 'iconPageDelete', text: ((this.node.attributes.type === 'delete') ? _('Cancel this deletion') : _('Clear this change')), handler: function() { new ui.task.ClearLocalChangeTask({ ftype: this.node.attributes.type, fpath: this.folderNode.attributes.task, fname: this.node.attributes.task }); } }]; break; case 'patch' : items = [{ scope: this, iconCls: 'iconTrash', text: _('Delete this patch'), handler: function() { ui.task.DeletePatchTask({ patchID: this.node.attributes.idDB }); } }]; break; } Ext.apply(this, { text: _('Administrator menu'), iconCls: 'iconAdmin', handler: function(){ return false; }, menu: new Ext.menu.Menu({ items: items }) }); } }); // WorkTreeGrid : commit items for the context menu // config - { module, from, node, folderNode, userNode } ui.cmp._WorkTreeGrid.menu.commit = function(config){ Ext.apply(this, config); this.init(); ui.cmp._WorkTreeGrid.menu.commit.superclass.constructor.call(this); }; Ext.extend(ui.cmp._WorkTreeGrid.menu.commit, Ext.menu.Item, { init: function(){ Ext.apply(this, { text: _('Commit...'), iconCls: 'iconCommitFileVcs', disabled: (!PhDOE.user.haveKarma), handler: function(){ return false; }, menu: new Ext.menu.Menu({ items: [{ scope: this, text: _('...this file'), hidden: (this.from === 'user' || this.from === 'folder' || this.from === 'patch' || this.from === 'anonymousPatch'), iconCls: 'iconCommitFileVcs', handler: function(){ var file = [{ fid: Ext.util.md5(this.folderNode.attributes.task + this.node.attributes.task), fpath: this.folderNode.attributes.task, fname: this.node.attributes.task, fdbid: this.node.attributes.idDB, ftype: this.node.attributes.type, fdate: Date.parseDate(this.node.attributes.last_modified,'Y-m-d H:i:s'), fby: this.userNode.attributes.task }]; new ui.cmp.CommitPrompt({ files: file }).show(); } }, { scope: this, text: _('...all files from this folder'), hidden: (this.from === 'user' || this.from === 'patch' || this.from === 'anonymousPatch'), iconCls: 'iconCommitFileVcs', handler: function(){ var files = []; this.folderNode.cascade(function(node){ if (node.attributes.type !== 'folder' && node.attributes.type !== 'user') { files.push({ fid: Ext.util.md5(this.folderNode.attributes.task + node.attributes.task), fpath: this.folderNode.attributes.task, fname: node.attributes.task, fdbid: node.attributes.idDB, ftype: node.attributes.type, fdate: Date.parseDate(node.attributes.last_modified,'Y-m-d H:i:s'), fby: this.userNode.attributes.task }); } }, this); new ui.cmp.CommitPrompt({ files: files }).show(); } }, { scope: this, text: _('...all files from this patch'), hidden: (this.module !== 'patches' || this.from === 'user'), iconCls: 'iconCommitFileVcs', handler: function(){ var files = [], defaultCommitMessage = '', patchID = false; // We build the default commit message for a commit issue from an anonymous patch if( this.from === 'anonymousPatch' ) { defaultCommitMessage = this.patchNode.attributes.patchDescription + "\n\n-- \nProvided by "+this.patchNode.parentNode.attributes.task+' ('+this.patchNode.attributes.patchEmail+')'; patchID = this.patchNode.attributes.idDB; } this.patchNode.cascade(function(node){ if (node.attributes.type !== 'folder' && node.attributes.type !== 'user' && node.attributes.type !== 'patch') { files.push({ fid: Ext.util.md5(node.parentNode.attributes.task + node.attributes.task), fpath: node.parentNode.attributes.task, fname: node.attributes.task, fdbid: node.attributes.idDB, ftype: node.attributes.type, fdate: Date.parseDate(node.attributes.last_modified,'Y-m-d H:i:s'), fby: this.userNode.attributes.task }); } }, this); new ui.cmp.CommitPrompt({ files: files, defaultMessage: defaultCommitMessage, patchID: patchID }).show(); } }, { scope: this, text: _('...all files modified by me'), hidden: (this.from === 'anonymousPatch'), iconCls: 'iconCommitFileVcs', handler: function(){ var files = []; this.userNode.cascade(function(node){ if (node.attributes.type !== 'folder' && node.attributes.type !== 'user' && node.attributes.type !== 'patch') { files.push({ fid: Ext.util.md5(node.parentNode.attributes.task + node.attributes.task), fpath: node.parentNode.attributes.task, fname: node.attributes.task, fdbid: node.attributes.idDB, ftype: node.attributes.type, fdate: Date.parseDate(node.attributes.last_modified,'Y-m-d H:i:s'), fby: this.userNode.attributes.task }); } }, this); new ui.cmp.CommitPrompt({ files: files }).show(); } }] }) }); } }); ui.cmp._WorkTreeGrid.menu.usersPatch = function(config){ Ext.apply(this, config); var menu = Ext.getCmp(this.menuID), newItem, patchesList; if (!menu.itemRendered) { menu.removeAll(); menu.doLayout(); patchesList = ui.cmp.PatchesTreeGrid.getInstance().getUserPatchesList(); if (patchesList) { Ext.each(patchesList, function(item){ newItem = new Ext.menu.Item({ id: Ext.id(), text: item.attributes.task, handler: function(){ ui.task.MoveToPatch({ patchID: item.attributes.idDB, patchName: item.attributes.task, nodesToAdd: menu.nodesToAdd }); } }); menu.add(newItem); }, this); } else { newItem = new Ext.menu.Item({ disabled: true, text: _('You have no patch currently. You must create one.') }); menu.add(newItem); } // Set the default action : Add a new patch newItem = new Ext.menu.Item({ text: _('Create a new patch'), iconCls: 'iconAdd', handler: function(){ var win = new ui.cmp.ManagePatchPrompt({ title: _('Create a new patch'), nodesToAdd: menu.nodesToAdd }); win.show(this.el); } }); menu.add('-', newItem); menu.doLayout(); menu.itemRendered = true; } }; // WorkTreeGrid : context menu for users items // config - { node } ui.cmp._WorkTreeGrid.menu.users = function(config){ Ext.apply(this, config); this.init(); ui.cmp._WorkTreeGrid.menu.users.superclass.constructor.call(this); }; Ext.extend(ui.cmp._WorkTreeGrid.menu.users, Ext.menu.Menu, { listeners: { show: function(){ if (this.node.attributes.task === PhDOE.user.login) { ui.cmp._WorkTreeGrid.menu.usersPatch({ menuID: 'usersPatchesMenu' }); } } }, init: function(){ var allFiles = [], items; // We search for files to pass to patch this.node.cascade(function(node){ if (node.attributes.type !== 'user' && node.attributes.type !== 'folder') { allFiles.push(node); } }, this); items = (this.node.attributes.task === PhDOE.user.login) ? [{ text: _('Submit all files for review in patch:'), iconCls: 'iconPendingPatch', handler: function(){ return false; }, menu: new Ext.menu.Menu({ id: 'usersPatchesMenu', itemRendered: false, nodesToAdd: allFiles }) }, { xtype: 'menuseparator', hidden: !PhDOE.user.haveKarma }, new ui.cmp._WorkTreeGrid.menu.commit({ hidden: !PhDOE.user.haveKarma, from: 'user', node: false, folderNode: false, userNode: this.node }) ] : [{ scope: this, text: String.format(_('Send an email to {0}'), "" + this.node.attributes.task + ""), iconCls: 'iconSendEmail', hidden: !this.node.attributes.email, handler: function(){ var win = new ui.cmp.EmailPrompt(); win.setData(this.node.attributes.task, this.node.attributes.email); win.show(this.node.el); } }]; Ext.apply(this, { items: items }); } }); // WorkTreeGrid : context menu for folders items // config - { node } ui.cmp._WorkTreeGrid.menu.folders = function(config){ Ext.apply(this, config); this.init(); ui.cmp._WorkTreeGrid.menu.folders.superclass.constructor.call(this); }; Ext.extend(ui.cmp._WorkTreeGrid.menu.folders, Ext.menu.Menu, { listeners: { show: function(){ if (this.node.parentNode.attributes.task === PhDOE.user.login) { ui.cmp._WorkTreeGrid.menu.usersPatch({ menuID: 'foldersPatchesMenu' }); } } }, init: function(){ var allFiles = []; // We don't display all of this menu if the current user isn't the owner if (this.node.parentNode.attributes.task !== PhDOE.user.login) { return false; } // We search for files to pass to patch this.node.cascade(function(node){ if (node.attributes.type !== 'folder') { allFiles.push(node); } }, this); Ext.apply(this, { items: [{ text: _('Submit all files in this directory in patch:'), iconCls: 'iconPendingPatch', handler: function(){ return false; }, menu: new Ext.menu.Menu({ id: 'foldersPatchesMenu', itemRendered: false, nodesToAdd: allFiles }) }, { xtype: 'menuseparator', hidden: !PhDOE.user.haveKarma }, new ui.cmp._WorkTreeGrid.menu.commit({ hidden: !PhDOE.user.haveKarma, from: 'folder', node: false, folderNode: this.node, userNode: this.node.parentNode })] }); } }); // WorkTreeGrid : context menu for files items // config - { node, progressValue } ui.cmp._WorkTreeGrid.menu.files = function(config){ Ext.apply(this, config); this.init(); ui.cmp._WorkTreeGrid.menu.files.superclass.constructor.call(this); }; Ext.extend(ui.cmp._WorkTreeGrid.menu.files, Ext.menu.Menu, { listeners: { show: function(){ if (this.node.parentNode.parentNode.attributes.task === PhDOE.user.login) { ui.cmp._WorkTreeGrid.menu.usersPatch({ menuID: 'filePatchesMenu' }); } } }, init: function(){ var node = this.node, FileType = node.attributes.type, FileLang, FilePath = node.parentNode.attributes.task, FileName = node.attributes.task, treeGrid = node.ownerTree, owner = node.parentNode.parentNode.attributes.task, allFiles = [], tmp; // Get the lang of this file tmp = node.parentNode.attributes.task.split('/'); FileLang = tmp[0]; allFiles.push(this.node); Ext.apply(this, { items: [{ text: '' + ((FileType === 'delete') ? _('View in a new tab') : _('Edit in a new tab')) + '', iconCls: 'iconEdit', handler: function(){ treeGrid.openFile(node); } }, { text: _('Submit as patch for review in:'), iconCls: 'iconPendingPatch', hidden: (owner !== PhDOE.user.login), handler: function(){ return false; }, menu: new Ext.menu.Menu({ id: 'filePatchesMenu', itemRendered: false, nodesToAdd: allFiles }) }, { text: _('Set the progress...'), iconCls: 'iconProgress', hidden: (FileType === 'delete' || owner !== PhDOE.user.login), menu: { xtype: 'menu', showSeparator: false, items: [{ xtype: 'slider', width: 200, value: this.node.attributes.progress, increment: 10, minValue: 0, maxValue: 100, plugins: new Ext.slider.Tip({ getText: function(thumb){ return String.format('' + _('{0}% complete') + '', thumb.value); } }), refreshNodeColumns: function(n){ var t = n.getOwnerTree(), a = n.attributes, cols = t.columns, el = n.ui.getEl().firstChild, cells = el.childNodes, i, d, v, len; for (i = 1, len = cols.length; i < len; i++) { d = cols[i].dataIndex; v = (a[d] !== null) ? a[d] : ''; if (cols[i].tpl && cols[i].tpl.html === "{progress:this.formatProgress}") { cells[i].firstChild.innerHTML = cols[i].tpl.apply('out:' + v); } } }, listeners: { scope: this, change: function(s, n){ this.node.attributes.progress = n; s.refreshNodeColumns(this.node); ui.cmp._WorkTreeGrid.SetProgress.delay(1000, null, this); } } }] } }, '-', { scope: this, text: _('View diff'), iconCls: 'iconViewDiff', handler: function() { Ext.getCmp('main-panel').openDiffTab({ DiffType: 'file', FileName: FileName, FilePath: FilePath, currentOwner: owner, fileIdDB: node.attributes.idDB }); } }, { text: _('Download the diff as a patch'), iconCls: 'iconDownloadDiff', handler: function(){ window.location.href = './do/downloadPatch' + '?FilePath=' + FilePath + '&FileName=' + FileName + '&csrfToken=' + csrfToken; } }, { xtype: 'menuseparator', hidden: owner !== PhDOE.user.login }, { text: ((FileType === 'delete') ? _('Cancel this deletion') : _('Clear this change')), iconCls: 'iconPageDelete', hidden: owner !== PhDOE.user.login, handler: function(){ new ui.task.ClearLocalChangeTask({ ftype: FileType, fpath: FilePath, fname: FileName }); } }, { xtype: 'menuseparator', hidden: !(PhDOE.user.haveKarma && owner === PhDOE.user.login) }, new ui.cmp._WorkTreeGrid.menu.commit({ from: 'file', hidden: !(PhDOE.user.haveKarma && owner === PhDOE.user.login), node: this.node, folderNode: this.node.parentNode, userNode: this.node.parentNode.parentNode }), { xtype: 'menuseparator', hidden: !(PhDOE.user.isGlobalAdmin || PhDOE.user.isLangAdmin) }, new ui.cmp._WorkTreeGrid.menu.admin({ fileLang: FileLang, from: 'file', hidden: !(PhDOE.user.isGlobalAdmin || PhDOE.user.isLangAdmin), node: this.node, folderNode: this.node.parentNode, userNode: this.node.parentNode.parentNode }) ] }); } }); //------------------------------------------------------------------------------ // WorkTreeGrid ui.cmp.WorkTreeGrid = Ext.extend(Ext.ux.tree.TreeGrid, { onContextMenu: function(node, e){ e.stopEvent(); var selectedNodes, NBselectedNodes, type, contextMenu; selectedNodes = this.getSelectionModel().getSelectedNodes(); NBselectedNodes = selectedNodes.length; // We clean up the multi-selection and keep only files own by the current user if( NBselectedNodes > 1 ) { for( var i=0; i < NBselectedNodes; i++ ) { if( selectedNodes[i].attributes.type == 'folder' || selectedNodes[i].attributes.type == 'user') { selectedNodes[i].unselect(true); } if( selectedNodes[i].attributes.type != 'folder' && selectedNodes[i].attributes.type != 'user') { var fileOwner = selectedNodes[i].parentNode.parentNode.attributes.task; if( fileOwner != PhDOE.user.login ) { selectedNodes[i].unselect(true); } } } selectedNodes = this.getSelectionModel().getSelectedNodes(); NBselectedNodes = selectedNodes.length; } // Now we have only owns files selected if( NBselectedNodes > 1 ) { contextMenu = new Ext.menu.Menu({ listeners: { show: function() { ui.cmp._WorkTreeGrid.menu.usersPatch({ menuID: 'globalPatchesMenu' }); } }, items: [{ text: _('Submit all this files for review in patch:'), iconCls: 'iconPendingPatch', handler: function(){ return false; }, menu: new Ext.menu.Menu({ id: 'globalPatchesMenu', itemRendered: false, nodesToAdd: selectedNodes }) }] }); contextMenu.showAt(e.getXY()); return; } type = node.attributes.type; switch (type) { case "user": // We only select this row/ If there is multi-selection, this clear the selection and select only the current one. node.select(); contextMenu = new ui.cmp._WorkTreeGrid.menu.users({ node: node }); break; case "folder": node.select(); contextMenu = new ui.cmp._WorkTreeGrid.menu.folders({ node: node }); break; default: // Use default for file as the type can be update, delete or new node.select(); contextMenu = new ui.cmp._WorkTreeGrid.menu.files({ node: node }); break; } contextMenu.showAt(e.getXY()); }, initComponent: function(){ function renderProgress(v, p){ p.css += ' x-grid3-progresscol'; return String.format('