From 0565235912c3577698211f2f7e95c747ea94436a Mon Sep 17 00:00:00 2001 From: Scott Langley Date: Thu, 28 Feb 2013 18:29:26 -0800 Subject: [PATCH 1/5] Scott's changes through February 28. --- src/views/CardLayoutTest.webpart.xml | 4 + src/views/FlowLayoutTest.webpart.xml | 4 + src/views/cardLayoutTest.html | 57 + src/views/cardLayoutTest.view.xml | 27 + src/views/comboTest.html | 53 + src/views/extjs4begin.html | 72 + src/views/extjs4begin.view.xml | 27 + src/views/extjs4begin.webpart.xml | 4 + src/views/flowLayoutTest.html | 57 + src/views/flowLayoutTest.view.xml | 27 + src/web/CardLayoutTest.js | 60 + src/web/ExtJS4OpenCytoPreprocessing.js | 1055 +++++++++ src/web/FlowLayoutTest.js | 15 + src/web/OpenCyto/ExtJS4ClearableComboBox.js | 45 + src/web/OpenCyto/ExtJS4OpenCyto.css | 224 ++ src/web/OpenCyto/ExtJS4OpenCyto.js | 314 +++ src/web/OpenCyto/ExtJS4ResizableCombo.js | 75 + src/web/OpenCyto/OpenCyto.css | 2 +- .../SuperBoxSelect/ExtJS4SuperBoxSelect.js | 1894 +++++++++++++++++ 19 files changed, 4015 insertions(+), 1 deletion(-) create mode 100644 src/views/CardLayoutTest.webpart.xml create mode 100644 src/views/FlowLayoutTest.webpart.xml create mode 100644 src/views/cardLayoutTest.html create mode 100644 src/views/cardLayoutTest.view.xml create mode 100644 src/views/comboTest.html create mode 100644 src/views/extjs4begin.html create mode 100644 src/views/extjs4begin.view.xml create mode 100644 src/views/extjs4begin.webpart.xml create mode 100644 src/views/flowLayoutTest.html create mode 100644 src/views/flowLayoutTest.view.xml create mode 100644 src/web/CardLayoutTest.js create mode 100644 src/web/ExtJS4OpenCytoPreprocessing.js create mode 100644 src/web/FlowLayoutTest.js create mode 100644 src/web/OpenCyto/ExtJS4ClearableComboBox.js create mode 100644 src/web/OpenCyto/ExtJS4OpenCyto.css create mode 100644 src/web/OpenCyto/ExtJS4OpenCyto.js create mode 100644 src/web/OpenCyto/ExtJS4ResizableCombo.js create mode 100644 src/web/OpenCyto/SuperBoxSelect/ExtJS4SuperBoxSelect.js diff --git a/src/views/CardLayoutTest.webpart.xml b/src/views/CardLayoutTest.webpart.xml new file mode 100644 index 0000000..a153c06 --- /dev/null +++ b/src/views/CardLayoutTest.webpart.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/FlowLayoutTest.webpart.xml b/src/views/FlowLayoutTest.webpart.xml new file mode 100644 index 0000000..c630ba5 --- /dev/null +++ b/src/views/FlowLayoutTest.webpart.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/cardLayoutTest.html b/src/views/cardLayoutTest.html new file mode 100644 index 0000000..b0e317a --- /dev/null +++ b/src/views/cardLayoutTest.html @@ -0,0 +1,57 @@ +
+ + + + diff --git a/src/views/cardLayoutTest.view.xml b/src/views/cardLayoutTest.view.xml new file mode 100644 index 0000000..d291fd9 --- /dev/null +++ b/src/views/cardLayoutTest.view.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/comboTest.html b/src/views/comboTest.html new file mode 100644 index 0000000..f99cbd6 --- /dev/null +++ b/src/views/comboTest.html @@ -0,0 +1,53 @@ +
+ + + + \ No newline at end of file diff --git a/src/views/extjs4begin.html b/src/views/extjs4begin.html new file mode 100644 index 0000000..5137e48 --- /dev/null +++ b/src/views/extjs4begin.html @@ -0,0 +1,72 @@ + + + + + + + + + + diff --git a/src/views/extjs4begin.view.xml b/src/views/extjs4begin.view.xml new file mode 100644 index 0000000..09708cb --- /dev/null +++ b/src/views/extjs4begin.view.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/extjs4begin.webpart.xml b/src/views/extjs4begin.webpart.xml new file mode 100644 index 0000000..de1f1f4 --- /dev/null +++ b/src/views/extjs4begin.webpart.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/flowLayoutTest.html b/src/views/flowLayoutTest.html new file mode 100644 index 0000000..ce6e47b --- /dev/null +++ b/src/views/flowLayoutTest.html @@ -0,0 +1,57 @@ +
+ + + + diff --git a/src/views/flowLayoutTest.view.xml b/src/views/flowLayoutTest.view.xml new file mode 100644 index 0000000..83f6d21 --- /dev/null +++ b/src/views/flowLayoutTest.view.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/web/CardLayoutTest.js b/src/web/CardLayoutTest.js new file mode 100644 index 0000000..505b694 --- /dev/null +++ b/src/web/CardLayoutTest.js @@ -0,0 +1,60 @@ + + + +Ext4.define('CardLayoutTest', { + extend : 'Ext.panel.Panel', + constructor : function(config) { + config = config || {}; // Make sure config is not totally null. + config = Ext4.applyIf(config, { + // width : 700, + height : 120, + layout : { + type : 'card' + }, + defaults: {bodyStyle:'padding:15px'}, + tbar: [ + { + id: 'move-prev', + text: '< Back', + handler: function(btn) { + navigate(btn.up("panel"), "prev"); + }, + disabled: true + }, + { + id: 'move-next', + text: 'Next >', + handler: function(btn) { + navigate(btn.up("panel"), "next"); + } + } + ], + // the panels (or "cards") within the layout + items: [{ + id: 'card-0', + html: '

Welcome to the Wizard!

Step 1 of 3

' + },{ + id: 'card-1', + html: '

Step 2 of 3

' + },{ + id: 'card-2', + html: '

Congratulations!

Step 3 of 3 - Complete

' + }] + + }); + this.callParent([ config ]); + } +}); + +var navigate = function(panel, direction){ + // This routine could contain business logic required to manage the navigation steps. + // It would call setActiveItem as needed, manage navigation button state, handle any + // branching logic that might be required, handle alternate actions like cancellation + // or finalization, etc. A complete wizard implementation could get pretty + // sophisticated depending on the complexity required, and should probably be + // done as a subclass of CardLayout in a real-world implementation. + var layout = panel.getLayout(); + layout[direction](); + Ext4.getCmp('move-prev').setDisabled(!layout.getPrev()); + Ext4.getCmp('move-next').setDisabled(!layout.getNext()); +}; \ No newline at end of file diff --git a/src/web/ExtJS4OpenCytoPreprocessing.js b/src/web/ExtJS4OpenCytoPreprocessing.js new file mode 100644 index 0000000..ab2b380 --- /dev/null +++ b/src/web/ExtJS4OpenCytoPreprocessing.js @@ -0,0 +1,1055 @@ +// vim: sw=4:ts=4:nu:nospell:fdc=4 +/* + * Copyright 2012 Fred Hutchinson Cancer Research Center + * + * 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. + */ + +// Ext4.namespace('LABKEY', 'LABKEY.ext'); +Ext4.define('LABKEY.ext.ExtJS4OpenCytoPreprocessing', { + extend : 'Ext.panel.Panel', + constructor : function(config) { + + config = Ext4.applyIf(config, { + border : false, + boxMinWidth : 370, + frame : false, + items : [], + layout : 'fit', + webPartDivId : config.webPartDivId, + renderTo : config.webPartDivId, + width : document.getElementById(config.webPartDivId).offsetWidth + }); + + this.callParent([config]); + + }, // end constructor + + initComponent : function() { + var me = this; + + this.callParent(); + + this.addEvents({ + 'preprocessed' : true + }); + + // ////////////////////////////////// + // Generate necessary HTML divs // + // ////////////////////////////////// + + $('#' + me.webPartDivId).append('
' + + + '' + + + '
' + + ); + + // /////////////////////////////////// + // Variables // + // /////////////////////////////////// + var pnlGlobal = this; + + this.rootPath = undefined; + this.maskGlobal = undefined; + this.notSorting = undefined; + this.selectedStudyVars = undefined; + + // /////////////////////////////////// + // Strings // + // /////////////////////////////////// + var strngErrorContactWithLink = ' Please, contact the developer, if you have questions.'; + + // ///////////////////////////////// + // Stores // + // ///////////////////////////////// + this.strSampleGroup = Ext4.create('Ext.data.ArrayStore', { + autoLoad : false, + data : [], + fields : [{ + name : 'SampleGroup', + type : 'string' + }] + }); + + this.strXML = Ext4.create('LABKEY.ext4.data.Store', { + autoLoad : true, + listeners : { + load : function() { + if (this.getCount() == 0) { + me.cbXml.disable(); + me.tfAnalysisName.disable(); + pnlWorkspaces.getEl().mask( + 'Seems like you have not imported any XML files, click here to do so.' + + strngErrorContactWithLink, + 'infoMask'); + } + } + }, + queryName : 'XmlFiles', + remoteSort : false, + schemaName : 'exp', + sort : 'FileName' + }); + + this.strngSqlStartTable = 'SELECT DISTINCT FCSFiles.Name AS FileName'; + this.strngSqlEndTable = ' FROM FCSFiles' + + ' WHERE FCSFiles.Run.FCSFileCount != 0 AND FCSFiles.Run.ProtocolStep = \'Keywords\''; + + this.strFilteredTable = Ext4.create('LABKEY.ext4.data.Store', { + listeners : { + load : function() { + console.log('listened to strFilteredTable load event'); + if (me.notSorting) { + me.pnlTable.getSelectionModel().selectAll(); + me.notSorting = false; + } + me.updateTableStatus(); + } + }, + // nullRecord: { + // displayColumn: 'myDisplayColumn', + // nullCaption: '0' + // }, + remoteSort : false, + schemaName : 'flow', + sortInfo : { + field : 'FileName', + direction : 'ASC' + }, + sql : me.strngSqlStartTable + me.strngSqlEndTable + }); + + // //////////////////////////////////////////////////////////////// + // Queries and associated functionality // + // //////////////////////////////////////////////////////////////// + LABKEY.Query.selectRows({ + columns : ['RootPath'], + failure : onFailure, + queryName : 'RootPath', + schemaName : 'flow', + success : function(data) { + var count = data.rowCount; + if (count == 1) { + this.rootPath = data.rows[0].RootPath; + } else if (count < 1) { + // disable all + btnNext.disable(); + me.cbStudyVarName.disable(); + me.pnlMain.getEl().mask( + 'Seems like you have not imported any FCS files, click here to do so.' + + strngErrorContactWithLink, + 'infoMask'); + } else { + // disable all + btnNext.disable(); + me.cbStudyVarName.disable(); + me.pnlMain.getEl().mask( + 'Cannot retrieve the path for the data files: it is non-unique.' + + strngErrorContactWithLink, + 'infoMask'); + } + } + }); + + this.smCheckBox = Ext4.create('Ext.selection.CheckboxModel', { + // new Ext.grid.CheckboxSelectionModel({ + checkOnly : true, + listeners : { + rowdeselect : this.updateTableStatus, + rowselect : this.updateTableStatus + }, + sortable : true + }); + + this.rowNumberer = Ext4.create('Ext.grid.RowNumberer', {}); + // new Ext.grid.RowNumberer(); + + this.pnlTable = Ext4.create('Ext.grid.Panel', { + // new Ext.grid.GridPanel({ + autoScroll : true, + // colModel: new Ext.ux.grid.LockingColumnModel([ + // { + // dataIndex: 'FileName', + // header: 'File Name', + // resizable: true, + // sortable: true + // } + // ]), + columns : [], + selModel : this.smCheckBox, + height : 200, + loadMask : { + msg : 'Loading data...', + msgCls : 'x-mask-loading-custom' + }, + // plugins: ['autosizecolumns', new + // Ext.ux.plugins.CheckBoxMemory({ idProperty: 'FileName' + // })], + store : me.strFilteredTable, + stripeRows : true, + title : 'Files', + // view: new Ext.ux.grid.LockingGridView(), + viewConfig : { + emptyText : 'No rows to display', + splitHandleWidth : 10 + } + }); + + this.pnlComp = Ext4.create('Ext.Panel', { + defaults : { + style : 'padding-bottom: 4px; padding-right: 4px; padding-left: 4px;' + }, + items : [], + title : 'Compensation' + }); + + this.add(this.pnlInitMainPanel()); + + }, + + // /////////////////////////////////// + // Functions // + // /////////////////////////////////// + updateInfoStatus : function(text, code) { + var me = this; + me.cmpStatus.update(text); + if (text != '') { + if (code == -1) { + me.cmpStatus.getEl().setStyle({ + color : 'red' + }); + me.cmpStatus.getEl().frame("ff0000", 1, { + duration : 3 + }); // RED ERROR + } else if (code == 1) { + me.cmpStatus.getEl().setStyle({ + color : 'black' + }); + } else { + me.cmpStatus.getEl().setStyle({ + color : 'black' + }); + me.cmpStatus.getEl().frame(); + } + } + }, + + updateTableStatus : function() { + var me = this; + + var selectedCount = me.pnlTable.getSelectionModel().getCount(); + + // Update the table's title + if (selectedCount == 1) { + me.pnlTable.setTitle(selectedCount + ' file is currently chosen'); + } else { + me.pnlTable.setTitle(selectedCount + ' files are currently chosen'); + } + + // Manage the 'check all' icon state + // innerHd doesn't exist in Ext JS 4. +/* + var t = Ext4.fly(me.pnlTable.getView().innerHd) + .child('.x-grid4-hd-checker'); + var isChecked = t.hasClass('x-grid4-hd-checker-on'); + var totalCount = me.pnlTable.getStore().getCount(); + + if (selectedCount != totalCount & isChecked) { + t.removeClass('x-grid4-hd-checker-on'); + } else if (selectedCount == totalCount & !isChecked) { + t.addClass('x-grid4-hd-checker-on'); + } +*/ + }, + + setStudyVars : function() { + var me = this; + + var temp = me.cbStudyVarName.getValue(); + if (temp != me.selectedStudyVars) { + me.selectedStudyVars = temp; + + var i, len, c, curLabel, curValue, curFlag, tempSQL, newColumns; + + // Grab the choices array + // getValueEx() defined on SuperBoxSelect + // var arrayStudyVars = me.cbStudyVarName.getValueEx(); + + var arrayStudyVars = []; + Ext4.each(me.cbStudyVarName.valueModels, function(value) { + + arrayStudyVars.push(value.data); + }); +/* + newColumns = [me.rowNumberer, me.smCheckBox, { + dataIndex : 'FileName', + header : 'File Name' + }]; +*/ + newColumns = [{dataIndex : 'FileName', header : 'File Name'}]; + + tempSQL = me.strngSqlStartTable; + + len = arrayStudyVars.length; + + for (i = 0; i < len; i++) { + c = arrayStudyVars[i]; + https : // www.google.com/search?q=%22ext+js4%22+%22createDelegate%22+convert&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a#hl=en&client=firefox-a&hs=DIa&rls=org.mozilla:en-US%3Aofficial&sclient=psy-ab&q=%22ext+js%22+%22createDelegate%22+convert&oq=%22ext+js%22+%22createDelegate%22+convert&gs_l=serp.3...3257.3257.0.4478.1.1.0.0.0.0.86.86.1.1.0.les%3Bcappsweb..0.0...1.1.5.psy-ab.LXb31BUKlgw&pbx=1&bav=on.2,or.r_gc.r_pw.r_cp.r_qf.&bvm=bv.43148975,d.cGE&fp=edee8122245b3399&biw=1280&bih=856 + curLabel = c.Display; + curValue = LABKEY.QueryKey.encodePart(c.Value); + curFlag = curLabel.slice(-2, -1); + + if (curFlag == 'l') { // External study variable + curLabel = curLabel.slice(0, -11); + tempSQL += ', FCSFiles.Sample."' + curLabel + '" AS "' + + curValue + '"'; + curLabel += ' (External)'; + } else if (curFlag == 'd') { // Keyword study variable + curLabel = curLabel.slice(0, -10); + tempSQL += ', FCSFiles.Keyword."' + curLabel + '" AS "' + + curValue + '"'; + curLabel += ' (Keyword)'; + } else { + i = len; + onFailure({ + exception : 'there was an error while executing this command: data format mismatch.' + }); + } + + newColumns.push({ + dataIndex : curValue, + header : curLabel + }); + + } // end of for ( i = 0; i < len; i ++ ) loop + + tempSQL += me.strngSqlEndTable; + + me.strFilteredTablesql = tempSQL; + me.strFilteredTable.load(); + + this.notSorting = true; + + this.pnlTable.reconfigure(me.strFilteredTable, newColumns); + /* + this.pnlTable.getStore(), // new + //Ext.grid.ColumnModel( + { + items : newColumns, + defaults : { + dragable : false, + hideable : false, + resizable : true, + sortable : true, + tooltip : 'double click the separator between two column headers to fit the column width to its contents' + } + })); + */ + if (me.cbSampleGroup.getValue() != '' & me.cbXml.getValue() != '') { + me.btnProcess.setDisabled(false); + } + } + }, // end of setStudyVars() + + pnlInitMainPanel : function() { + var me = this; + // /////////////////////////////////// + // Buttons // + // /////////////////////////////////// + me.btnProcess = Ext4.create('Ext.button.Button', { + disabled : true, + handler : function() { + + if (me.tfAnalysisName.getValue() == '') { + me.updateInfoStatus('Empty analysis name is not allowed', + -1); + + me.tfAnalysisName.focus(); + me.tfAnalysisName.getEl().frame("ff0000", 1, { + duration : 3 + }); + } else if (me.tfAnalysisDescription.getValue() == '') { + me.updateInfoStatus( + 'Empty analysis description is not allowed', -1); + + me.tfAnalysisDescription.focus(); + me.tfAnalysisDescription.getEl().frame("ff0000", 1, { + duration : 3 + }); + } else { + if (me.cbSampleGroup.getValue() != '') { + this.setDisabled(true); + me.cbXml.setDisabled(true); + me.cbSampleGroup.setDisabled(true); + me.tfAnalysisName.setDisabled(true); + me.tfAnalysisDescription.setDisabled(true); + + me.maskGlobal.msg = 'Generating and saving the analysis data, please, wait...'; + me.maskGlobal.show(); + + var records = me.pnlTable.getSelectionModel() + .getSelection(); + var files = []; + Ext4.each(records, function(record) { + files.push(record.data.FileName); + }); + me.wpParseConfig.files = files.join(';'); + + me.wpParseConfig.xmlPath = me.wpSampleGroupsFetchingConfig.path; + me.wpParseConfig.sampleGroupName = me.cbSampleGroup.getValue(); + me.wpParseConfig.analysisName = me.tfAnalysisName + .getValue(); + me.wpParseConfig.analysisDescription = me.tfAnalysisDescription + .getValue(); + me.wpParseConfig.studyVars = me.cbStudyVarName + .getValue(); + me.wpParseConfig.allStudyVars = me.cbStudyVarName + .getAllValuesAsArray().join(); + me.wpParseConfig.rootPath = Ext4.util.Format + .undef(this.rootPath); + + me.wpParse.render(); + } + } + + }, + text : 'Process' + }); + + var btnBack = Ext4.create('Ext.button.Button', { + disabled : true, + text : '< Back' + }); + + var btnNext = Ext4.create('Ext.button.Button', { + text : 'Next >' + }); + + this.cmpStatus = Ext4.create('Ext.Component', { + html : 'Set the study variables and click \'Next\'', + style : { + paddingLeft : '10px' + } + }); + + this.tableContainer = Ext4.create('Ext.container.Container', { + items : [this.pnlTable], + layout : 'fit' + }); + + var pnlMain = Ext4.create('Ext.Panel', { + activeItem : 0, + autoHeight : true, + bodyStyle : { + paddingTop : '3px' + }, + border : false, + defaults : { + autoHeight : true, + hideMode : 'offsets' + }, + deferredRender : false, + forceLayout : true, + items : [me.pnlInitStudyVarsPanel(), + me.pnlInitWorkspacesPanel(), this.tableContainer, + this.pnlComp], + layout : 'card', + listeners : { + afterrender : function() { + me.maskGlobal = new Ext4.LoadMask(this.getEl(), { + msgCls : 'x-mask-loading-custom' + }); + } + }, + tbar : Ext4.create('Ext.toolbar.Toolbar', { + items : [me.btnProcess, btnBack, btnNext, + me.cmpStatus] + }) + + }); + + var navHandler = function(direction) { + var oldIndex = pnlMain.items + .indexOf(pnlMain.getLayout().activeItem); + var newIndex = oldIndex + ((direction === 'next') ? 1 : -1); + var layout = pnlMain.getLayout(); + layout[direction](); + + if (newIndex == 0) { + btnBack.setDisabled(true); + me.btnProcess.setDisabled(true); + } + + if (newIndex == 1) { + btnBack.setDisabled(false); + if (oldIndex == 0) { + me.setStudyVars(); + } + } + + // if ( newIndex == 2 ){ btnNext.setDisabled(false); } + + // Disable Next button if there no cards after it, othwise enable + // it. + btnNext.setDisabled(!layout.getNext()); + // Disable Comp Panel + if (newIndex == 3) { + btnNext.setDisabled(true); + } + + me.updateInfoStatus(''); + + }; + + btnBack.on('click', Ext4.bind(navHandler, pnlMain, ["prev"])); + btnNext.on('click', Ext4.bind(navHandler, pnlMain, ["next"])); + + this.pnlMain = pnlMain; + // redudnant, yes. Refactor later. + return pnlMain; + }, + + pnlInitStudyVarsPanel : function() { + var me = this; + var listStudyVars = []; + + function fetchKeywords() { + LABKEY.Query.selectRows({ + columns : ['Name'], + filterArray : [ + LABKEY.Filter.create('Name', 'DISPLAY;BS;MS', + LABKEY.Filter.Types.CONTAINS_NONE_OF), + LABKEY.Filter + .create( + 'Name', + ['$', 'LASER', 'EXPORT', 'CST', + 'CYTOMETER', 'EXPORT', + 'FJ_', 'CREATOR', + 'TUBE NAME', + 'WINDOW EXTENSION', + 'SPILL'], + LABKEY.Filter.Types.DOES_NOT_START_WITH)], + queryName : 'Keyword', + schemaName : 'flow', + success : function(data) { + var toAdd; + Ext4.each(data.rows, function(r) { + toAdd = r.Name; + listStudyVars.push(['K', + toAdd + ' (Keyword)', + 'RowId/Keyword/' + toAdd]); + }); + + me.strStudyVarName.loadData(listStudyVars); + }, + failure : onFailure + }); + } + + LABKEY.Query.getQueries({ + schemaName : 'Samples', + success : function(queriesInfo) { + var queries = queriesInfo.queries, count = queries.length, j; + for (j = 0; j < count; j++) { + if (queries[j].name == 'Samples') { + j = count; + } + } + + if (j == count + 1) { + LABKEY.Domain.get(function(DomainDesign) { + var toAdd; + Ext4.each(DomainDesign.fields, + function(r) { + toAdd = r.name; + listStudyVars + .push([ + 'E', + toAdd + + ' (External)', + 'Sample/' + + toAdd]); + }); + + fetchKeywords(); + }, fetchKeywords, 'Samples', 'Samples'); + } else { + fetchKeywords(); + } + }, + failure : fetchKeywords + }); + + this.cmpStudyVars = Ext4.create('Ext.Component', { + cls : 'bold-text', + html : 'Select the study variables that are of interest for this project:' + }); + + this.strStudyVarName = Ext4.create('Ext.data.ArrayStore', { + data : [], + fields : ['Flag', 'Display', 'Value'], + sortInfo : { + field : 'Flag', + direction : 'ASC' + } + }); + + // /////////////////////////////////// + // ComboBoxes / TextFields // + // /////////////////////////////////// + this.cbStudyVarName = + // Ext4.create('Ext.ux.form.ExtJS4SuperBoxSelect',{ + Ext4.create('Ext.ux.CheckCombo', { + multiSelect : true, + // addAllSelector: true, + // new Ext.ux.form.SuperBoxSelect({ + allowBlank : true, + autoSelect : false, + displayField : 'Display', + emptyText : 'Select...', + forceSelection : true, + getAllValuesAsArray : function() { + var c = []; + + Ext4.each(this.store.data.items, function(r) { + c.push(r.data.Value); + }); + // usedRecords is a variable of the SuperBoxSelect. + /* + * Ext4.each(this.usedRecords.items, function(r) { + * c.push(r.data.Value); }); + */ + return c; + }, + lazyInit : false, + listeners : { + additem : function() { + me.updateInfoStatus( + 'Set the study variables and click \'Next\'', 1); + }, + clear : function() { + me + .updateInfoStatus('Set the study variables and click \'Next\''); + }, + // focus: function (){ // display the dropdown on focus + // this.expand(); + // }, + removeitem : function() { + me.updateInfoStatus( + 'Set the study variables and click \'Next\'', 1); + } + }, + minChars : 0, + queryMode : 'local', + resizable : true, + store : me.strStudyVarName, + supressClearValueRemoveEvents : true, + triggerAction : 'all', + typeAhead : true, + valueField : 'Value' + }); + + var pnlStudyVars = Ext4.create('Ext.Panel', { + defaults : { + style : 'padding-bottom: 4px; padding-right: 4px; padding-left: 4px;' + }, + items : [me.cmpStudyVars, Ext4.create('Ext.Panel', { + border : false, + items : [me.cbStudyVarName], + layout : 'fit' + })], + title : 'Configuration' + }); + + return pnlStudyVars; + }, + + pnlInitWorkspacesPanel : function() { + + var me = this; + + var lastlySelectedXML = undefined; + + // var me.cbXml = Ext4.create('Ext.form.field.ComboBox', { + me.cbXml = Ext4.create('Ext.form.ExtJS4ClearableComboBox', { + // new Ext.form.ClearableComboBox({ + allowBlank : true, + displayField : 'FileName', + emptyText : 'Select', + forceSelection : true, + listeners : { + change : function() { + // sample groups obtaining logic here? + if (this.getValue() == '') { + me.cbSampleGroup.setDisabled(true); + me.btnProcess.setDisabled(true); + + this.focus(); + } else { + me.cbSampleGroup.setDisabled(false); + + if (me.cbSampleGroup.getValue() != '') { + me.btnProcess.setDisabled(false); + + me.tfAnalysisName.focus(); // working? + } else { + me.cbSampleGroup.focus(); // working? + } + } + }, + cleared : function() { + me.cbSampleGroup.setDisabled(true); + me.btnProcess.setDisabled(true); + this.focus(); + }, + select : function(c, r, i) { + var value = this.getValue(); + + if (value != lastlySelectedXML) { + + me.maskGlobal.msg = 'Obtaining the available sample groups, please, wait...'; + me.maskGlobal.show(); + + this.setDisabled(true); // to prevent interaction with + // that combo while the mask is + // on + me.tfAnalysisName.setDisabled(true); // to prevent + // interaction + // with that + // combo while + // the mask is + // on + me.tfAnalysisDescription.setDisabled(true); // to + // prevent + // interaction + // with that + // combo + // while the + // mask is + // on + // do we need to also disable the navigation buttons ? + + // when we have an example with multiple xml workspaces, + // then probably need to clear out the me.cbSampleGroup + // ('s store) + + me.wpSampleGroupsFetchingConfig.path = decodeURI(value) + .slice(5); + + wpSampleGroupsFetching.render(); + } else { + me.cbSampleGroup.setDisabled(false); + + if (me.cbSampleGroup.getValue() != '') { + me.btnProcess.setDisabled(false); + + this.triggerBlur(); + + me.tfAnalysisName.focus(); + } else { + this.triggerBlur(); + + me.cbSampleGroup.focus(); + } + } + } + }, + minChars : 0, + mode : 'local', + store : me.strXML, + + // tpl: '
{FileName:htmlEncode}
', + triggerAction : 'all', + typeAhead : true, + valueField : 'FilePath', + + width : 200 + }); + + me.cbSampleGroup = Ext4.create('Ext.form.ExtJS4ClearableComboBox', { + // me.cbSampleGroup = new Ext.form.ClearableComboBox({ + + allowBlank : true, + disabled : true, + displayField : 'SampleGroup', + emptyText : 'Select...', + forceSelection : true, + listeners : { + change : function() { + if (this.getValue() != '') { + me.btnProcess.setDisabled(false); + + me.tfAnalysisName.focus(); // working? + } else { + me.btnProcess.setDisabled(true); + + this.focus(); + } + }, + cleared : function() { + me.btnProcess.setDisabled(true); + + this.focus(); + }, + select : function() { + me.btnProcess.setDisabled(false); + + this.triggerBlur(); + + me.tfAnalysisName.focus(); + } + }, + minChars : 0, + mode : 'local', + store : me.strSampleGroup, + // tpl: '
{SampleGroup:htmlEncode}
', + triggerAction : 'all', + typeAhead : true, + valueField : 'SampleGroup', + width : 200 + }); + + me.strSampleGroup.on({ + 'load' : function() { + me.cbSampleGroup.focus(); + me.cbSampleGroup.expand(); + console.log("listened to strSampleGroup load event"); + } + }); + + me.strSampleGroup.on({ + 'datachanged' : function() { + me.cbSampleGroup.focus(); + me.cbSampleGroup.expand(); + console + .log("listened to strSampleGroup store datachanged event"); + } + }); + + me.tfAnalysisName = Ext4.create('Ext.form.TextField', { + allowBlank : true, + emptyText : 'Type...', + width : 200 + }); + + me.tfAnalysisDescription = Ext4.create('Ext.form.TextField', { + allowBlank : true, + emptyText : 'Type...', + width : 200 + }); + + // /////////////////////////////////// + // Web parts // + // /////////////////////////////////// + this.wpSampleGroupsFetchingConfig = { + reportId : 'module:OpenCytoPreprocessing/SampleGroups.r', + // showSection: 'textOutput', // comment out to show debug output + title : 'HiddenDiv' + }; + + var wpSampleGroupsFetching = new LABKEY.WebPart({ + failure : function(errorInfo, options, responseObj) { + me.maskGlobal.hide(); + + me.cbXml.setDisabled(false); + me.tfAnalysisName.setDisabled(false); + me.tfAnalysisDescription.setDisabled(false); + + onFailure(errorInfo, options, responseObj); + }, + frame : 'none', + partConfig : me.wpSampleGroupsFetchingConfig, + partName : 'Report', + renderTo : 'wpSampleGroupsFetching' + me.webPartDivId, + success : function() { + me.maskGlobal.hide(); + + me.cbXml.setDisabled(false); + me.tfAnalysisName.setDisabled(false); + me.tfAnalysisDescription.setDisabled(false); + + var inputArray = $('#wpSampleGroupsFetching' + + me.webPartDivId + ' pre')[0].innerHTML; + console.log("inputArray for sample group store"); + console.log(inputArray); + if (inputArray.search('java.lang.RuntimeException') < 0) { + if (inputArray + .search('javax.script.ScriptException') < 0) { + me.cbSampleGroup.setDisabled(false); + inputArray = inputArray.replace(/\n/g, '') + .replace('All Samples;', '').split(';'); + + var len = inputArray.length; + for (var i = 0; i < len; i++) { + inputArray[i] = [inputArray[i]]; + } + me.strSampleGroup.loadData(inputArray); + + lastlySelectedXML = me.cbXml.getValue(); + } else { + onFailure({ + exception : inputArray.replace( + /Execution halted\n/, + 'Execution halted') + }); + } + } else { + onFailure({ + exception : inputArray + }); + } + } + }); + + this.wpParseConfig = { + reportId : 'module:OpenCytoPreprocessing/OpenCytoPreprocessing.r', + // showSection: 'textOutput', // comment out to show debug output + title : 'ParseDiv' + }; + + this.wpParse = new LABKEY.WebPart({ + failure : function(errorInfo, options, responseObj) { + me.maskGlobal.hide(); + + me.cbXml.setDisabled(false); + me.cbSampleGroup.setDisabled(false); + me.tfAnalysisName.setDisabled(false); + me.tfAnalysisDescription.setDisabled(false); + + me.btnProcess.setDisabled(false); + + onFailure(errorInfo, options, responseObj); + }, + frame : 'none', + partConfig : me.wpParseConfig, + partName : 'Report', + renderTo : 'wpParse' + this.webPartDivId, + success : function() { + me.maskGlobal.hide(); + + me.cbXml.setDisabled(false); + me.cbSampleGroup.setDisabled(false); + me.tfAnalysisName.setDisabled(false); + me.tfAnalysisDescription.setDisabled(false); + + me.btnProcess.setDisabled(false); + + // var activeIndex = this.items.indexOf( + // this.getLayout().activeItem ) + direction; + me.pnlMain.getLayout().setActiveItem(1); + + me.fireEvent('preprocessed'); + } + }); + + // /////////////////////////////////// + // Panels, Containers, Components // + // /////////////////////////////////// + + var pnlWorkspace = Ext4.create('Ext.Panel', { + border : false, + headerCssClass : 'simple-panel-header', + items : [me.cbXml], + layout : 'fit', + title : 'Select the workspace:' + }); + + var pnlSampleGroup = Ext4.create('Ext.Panel', { + border : false, + headerCssClass : 'simple-panel-header', + items : [me.cbSampleGroup], + layout : 'fit', + title : 'Select the sample group:' + }); + + var pnlAnalysisName = Ext4.create('Ext.Panel', { + border : false, + headerCssClass : 'simple-panel-header', + items : [me.tfAnalysisName], + layout : 'fit', + title : 'Enter analysis name:' + }); + + var pnlAnalysisDescription = Ext4.create('Ext.Panel', { + border : false, + headerCssClass : 'simple-panel-header', + items : [me.tfAnalysisDescription], + layout : 'fit', + title : 'Enter analysis description:' + }); + + var pnlList = Ext4.create('Ext.Panel', { + border : false, + layout : { + type : 'column' + }, + defaults : { + bodyStyle : 'padding:15px', + width : 200 + }, + id : + // contentEl: + 'ulList' + this.webPartDivId, + items : [pnlWorkspace, pnlSampleGroup, pnlAnalysisName, + pnlAnalysisDescription + ] + }); + + var pnlWorkspaces = Ext4.create('Ext.Panel', { + defaults : { + hideMode : 'visibility', // ? why not offsets ? + style : 'padding-bottom: 4px; padding-right: 4px; padding-left: 4px;' + }, + // disabled: true, + // forceLayout: true, + items : [ + pnlList, Ext4.create('Ext.Component', { + id : + // contentEl: + 'wpSampleGroupsFetching' + this.webPartDivId + }), Ext4.create('Ext.Component', { + id : + // contentEl: + 'wpParse' + this.webPartDivId + }) + ], + title : 'Workspaces' + }); + return pnlWorkspaces; + }, + + resize : function() { + // webPartContentWidth = + // document.getElementById(this.webPartDivId).offsetWidth; + + // if ( typeof resizableImage != 'undefined' ){ + // if ( $('#resultImage').width() > 2/3*pnlStudyVars.getWidth() ){ + // resizableImage.resizeTo( 2/3*pnlStudyVars.getWidth(), + // 2/3*pnlStudyVars.getWidth() ); + // } + // } + } +}); // end ExtJS4OpenCytoPreprocessing Panel class diff --git a/src/web/FlowLayoutTest.js b/src/web/FlowLayoutTest.js new file mode 100644 index 0000000..cac71ae --- /dev/null +++ b/src/web/FlowLayoutTest.js @@ -0,0 +1,15 @@ +Ext4.define('FlowLayoutTest', { + extend : 'Ext.panel.Panel', + constructor : function(config) { + config = config || {}; // Make sure config is not totally null. + config = Ext4.applyIf(config, { + // width : 700, + height : 500, + layout : { + type : 'column' + }, + defaults: {bodyStyle:'padding:15px'} + }); + this.callParent([ config ]); + } +}); diff --git a/src/web/OpenCyto/ExtJS4ClearableComboBox.js b/src/web/OpenCyto/ExtJS4ClearableComboBox.js new file mode 100644 index 0000000..dbcf1e6 --- /dev/null +++ b/src/web/OpenCyto/ExtJS4ClearableComboBox.js @@ -0,0 +1,45 @@ +// vim: sw=4:ts=4:nu:nospell:fdc=4 +/* + * Copyright 2012 Fred Hutchinson Cancer Research Center + * + * 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. + */ + +// --- A ComboBox with a secondary trigger button that clears the contents of the ComboBox + +Ext4.define('Ext.form.ExtJS4ClearableComboBox', { + extend : 'Ext.ux.ExtJS4ResizableCombo', + alias: 'clearcombo', +//Ext.form.ExtJS4ClearableComboBox = Ext.extend(Ext.ux.ExtJS4ResizableCombo, { + initComponent: function() { + this.triggerConfig = { + tag:'span', cls:'x-form-twin-triggers', cn:[ + {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger"}, + {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger x-form-clear-trigger"} + ]}; + //Ext.form.ExtJS4ClearableComboBox.superclass.initComponent.call(this); + this.callParent(); + }, + onTrigger2Click : function() + { + this.collapse(); + this.reset(); // clear contents of combobox + this.fireEvent('cleared'); // send notification that contents have been cleared + }, + + getTrigger: Ext4.form.TwinTriggerField.prototype.getTrigger, + initTrigger: Ext4.form.TwinTriggerField.prototype.initTrigger, + onTrigger1Click: Ext.ux.ExtJS4ResizableCombo.prototype.onTriggerClick, + trigger1Class: Ext.ux.ExtJS4ResizableCombo.prototype.triggerClass +}); +//Ext4.reg('clearcombo', Ext.form.ExtJS4ClearableComboBox); diff --git a/src/web/OpenCyto/ExtJS4OpenCyto.css b/src/web/OpenCyto/ExtJS4OpenCyto.css new file mode 100644 index 0000000..bcaac99 --- /dev/null +++ b/src/web/OpenCyto/ExtJS4OpenCyto.css @@ -0,0 +1,224 @@ +/* + vim: ts=4:sw=4:nu:fdc=4:nospell +*/ +/* + * Copyright 2012 Fred Hutchinson Cancer Research Center + * + * 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. + */ + +@charset 'utf-8'; + +/* Error code from R */ +pre { + /*text-align: center;*/ +} + +/* Class specs */ + +.right-text { + text-align: right; +} + +.left-text { + text-align: left; +} + +/* Centered text */ +.centered-text, .bold-centered-text, .sortable-list li, .x-grid3-hd-row { + text-align: center !important; +} + +/* Bold text */ +.bold-text, .bold-centered-text, .sortable-list li, .infoMask div, .x-mask-loading-custom div, .ux-lovcombo-list-item-all { + font-weight: bold; +} + +/* Auto margin */ +.centered-table { + margin: auto; +} + +.x-btn { + margin-right: 0px !important; +} + +/* Zero margin */ +.x-tab-strip, .sortable-list, .ulList { + margin: 0; +} + +/* Zero padding */ +.x-tab-panel-header, .sortable-list, .ulList { + padding: 0; +} + +/* Hidden class */ +.hidden { + display: none; + visibility: hidden; +} + +.simple-panel-header { + background-color: white; + border-bottom-width: 0px !important; + font-family: verdana, arial, helvetica, sans-serif; + padding-bottom: 3px; + padding-left: 0px; +} + +.x-mask-loading-custom { + border-left: 0px; + left: 0 !important; + margin-left: 0px; + padding-left: 0px; + width: 100%; + z-index: 9000; +} + +.x-mask-loading-custom div { + background: no-repeat 5px 5px; + background-color: white !important; + background-image: url(../ext-3.4.0/resources/images/default/grid/loading.gif) !important; + /*line-height:16px;*/ + padding: 5px 10px 5px 25px; + text-align: center; +} + +.infoMask { + width: 100% !important; + z-index: 9000; +} + +.infoMask div { + background-color: white; + cursor: default; + text-align: center; +} + +ul.x-tab-strip-top { + padding-top: 0px; +} + +.x-box-inner { + /*margin-top: 2px;*/ +} + +/* Ext4 */ +.x4-btn-inner { + padding-left: 4px; + padding-right: 4px; +} + + +/* Tweaks for jQuery drag-and-drop in particular and list in general */ +.draggableHandle { + cursor: move; +} + +.ui-state-highlight { + width: 1em; + line-height: 1.2em; +} + +.ui-sortable-helper, .sortable-list, .ulList { + list-style-type: none; +} + +.sortable-list li, .ulList li { + margin: 3px 5px 3px 5px; /* 0.2em 0.3em 0.2em 0.3em */ + padding: 1px; + float: left; +} + +.sortable-list li { + font-size: 1em; +} +/**********************************/ + +/* Ext TabPanel fixes */ +.x-tab-strip { + padding-left: 5px; +} + +.x-tab-right { + border-bottom-width: 0px !important; +} +/********************************/ + +/* Ext.Resizable fix */ +.xresizable-wrap { + margin: 0 auto; +} +/********************************/ + +/* ExtJS GridPanel */ +/* Override standard grid styles (add color to vertical grid lines) */ +.x-grid3-col { + border-left: 1px solid #EEEEEE; + border-right: 1px solid #D2D2D2; +} + +/* Also remove padding from table data (to compensate for added grid lines) */ +.x-grid3-row td, .x-grid3-summary-row td { + padding-left: 0px; + padding-right: 0px; +} + +.x-grid3-header-offset { + width: auto !important; +} + +/* ? */ +@media screen and (-webkit-min-device-pixel-ratio: 0) { + .x-grid3-cell { + box-sizing: border-box; + } +} +/*************************************/ + +/* Fix so that the buttons on toolbars look normal (not text) */ +.x-toolbar .x-btn-tl,.x-toolbar .x-btn-tr,.x-toolbar .x-btn-tc,.x-toolbar .x-btn-ml,.x-toolbar .x-btn-mr,.x-toolbar .x-btn-mc,.x-toolbar .x-btn-bl,.x-toolbar .x-btn-br,.x-toolbar .x-btn-bc { + background-image:url(../gtheme/img/lkbtn.gif); +} + +.x-toolbar .x-btn-tl{ + background-position: 0 0; +} +.x-toolbar .x-btn-tr{ + background-position: -3px 0; +} +.x-toolbar .x-btn-tc{ + background-position: 0 -6px; +} + +.x-toolbar .x-btn-ml{ + background-position: 0px -24px; +} +.x-toolbar .x-btn-mr{ + background-position: -3px -24px; +} + +.x-toolbar .x-btn-mc{ + background-position: 0 -1096px; +} +.x-toolbar .x-btn-bl{ + background-position: 0 -3px; +} +.x-toolbar .x-btn-br{ + background-position: -3px -3px; +} +.x-toolbar .x-btn-bc{ + background-position: 0 -15px; +} +/**********************************/ diff --git a/src/web/OpenCyto/ExtJS4OpenCyto.js b/src/web/OpenCyto/ExtJS4OpenCyto.js new file mode 100644 index 0000000..abcac6f --- /dev/null +++ b/src/web/OpenCyto/ExtJS4OpenCyto.js @@ -0,0 +1,314 @@ +// vim: sw=4:ts=4:nu:nospell:fdc=4 +/* + * Copyright 2012 Fred Hutchinson Cancer Research Center + * + * 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. + */ + +function removeById(elId) { + $( '#' + elId ).remove(); +}; + +function removeByClass(className) { + $( '.' + className ).remove(); +}; + +function captureEvents(observable) { + Ext.util.Observable.capture( + observable, + function(eventName) { + console.info(eventName); + }, + this + ); +}; + +function onFailure(errorInfo, options, responseObj){ + var strngErrorContact = ' Please, contact ldashevs@fhcrc.org, if you have questions.'; + + if (errorInfo && errorInfo.exception) + Ext.Msg.alert('Error', 'Failure: ' + errorInfo.exception + strngErrorContact); + else { + if ( responseObj != undefined ){ + Ext.Msg.alert('Error', 'Failure: ' + responseObj.statusText + strngErrorContact); + } else { + Ext.Msg.alert('Error', 'Failure: ' + errorInfo.statusText + (errorInfo.timedout==true?', timed out.':'') + strngErrorContact); + } + } +}; + +Ext4.Ajax.timeout = 60 * 60 * 1000; // override the timeout to be 60 mintues; value is in milliseconds + +Ext.QuickTips.init(); + +// IE 7 compatibility +Object.keys = Object.keys || (function () { + var hasOwnProperty = Object.prototype.hasOwnProperty, + hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"), + DontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ], + DontEnumsLength = DontEnums.length; + + return function (o) { + if (typeof o != "object" && typeof o != "function" || o === null) + throw new TypeError("Object.keys called on a non-object"); + + var result = []; + for (var name in o) { + if (hasOwnProperty.call(o, name)) + result.push(name); + } + + if (hasDontEnumBug) { + for (var i = 0; i < DontEnumsLength; i++) { + if (hasOwnProperty.call(o, DontEnums[i])) + result.push(DontEnums[i]); + } + } + + return result; + }; +})(); + +// Search in the middle of words / case insensitive +Ext.override (Ext.ux.form.SuperBoxSelect, { + anyMatch: true, + caseSensitive: false, + + //override doQuery function + doQuery : function(q, forceAll){ + + if(q === undefined || q === null){ + q = ''; + } + + var qe = { + query: q, + forceAll: forceAll, + combo: this, + cancel:false + }; + + if(this.fireEvent('beforequery', qe)===false || qe.cancel){ + return false; + } + + q = qe.query; + forceAll = qe.forceAll; + if(forceAll === true || (q.length >= this.minChars)){ + if(this.lastQuery !== q){ + this.lastQuery = q; + if(this.mode == 'local'){ + this.selectedIndex = -1; + if(forceAll){ + this.store.clearFilter(); + }else{ + this.store.filter(this.displayField, q, this.anyMatch, this.caseSensitive); + } + this.onLoad(); + }else{ + this.store.baseParams[this.queryParam] = q; + this.store.load({ + params: this.getParams(q) + }); + this.expand(); + } + }else{ + this.selectedIndex = -1; + this.onLoad(); + } + } + }, + onTypeAhead: function() { + var nodes = this.view.getNodes(); + for (var i = 0; i < nodes.length; i++) { + var n = nodes[i]; + var d = this.view.getRecord(n).data; + var re = new RegExp('(.*?)(' + '' + Ext.escapeRe(this.getRawValue()) + ')(.*)', this.caseSensitive ? '' : 'i'); + var h = d[this.displayField]; + + h=h.replace(re, '$1$2$3'); + n.innerHTML=h; + } + } +}); + + +/* + * Override to set Tab titles centered (can do any other customizations here) + */ +Ext.TabPanel.override({ + + tabStripInnerStyle : 'text-align: center;', + + onRender : function(ct, position){ + Ext.TabPanel.superclass.onRender.call(this, ct, position); + + if(this.plain){ + var pos = this.tabPosition == 'top' ? 'header' : 'footer'; + this[pos].addClass('x-tab-panel-'+pos+'-plain'); + } + + var st = this[this.stripTarget]; + + this.stripWrap = st.createChild({cls:'x-tab-strip-wrap', cn:{ + tag:'ul', cls:'x-tab-strip x-tab-strip-'+this.tabPosition}}); + + var beforeEl = (this.tabPosition=='bottom' ? this.stripWrap : null); + st.createChild({cls:'x-tab-strip-spacer'}, beforeEl); + this.strip = new Ext.Element(this.stripWrap.dom.firstChild); + + + this.edge = this.strip.createChild({tag:'li', cls:'x-tab-edge', cn: [{tag: 'span', cls: 'x-tab-strip-text', cn: ' '}]}); + this.strip.createChild({cls:'x-clear'}); + + this.body.addClass('x-tab-panel-body-'+this.tabPosition); + + + if(!this.itemTpl){ + var tt = new Ext.Template( + '
  • ', + '', + '{text}', + '
  • ' + ); + tt.disableFormats = true; + tt.compile(); + Ext.TabPanel.prototype.itemTpl = tt; + } + + this.items.each(this.initTab, this); + }, + + initTab : function(item, index){ + var before = this.strip.dom.childNodes[index], + p = this.getTemplateArgs(item); + p.tabStripInnerStyle = this.tabStripInnerStyle; + var el = before ? + this.itemTpl.insertBefore(before, p) : + this.itemTpl.append(this.strip, p), + cls = 'x-tab-strip-over', + tabEl = Ext.get(el); + + tabEl.hover(function(){ + if(!item.disabled){ + tabEl.addClass(cls); + } + }, function(){ + tabEl.removeClass(cls); + }); + + if(item.tabTip){ + tabEl.child('span.x-tab-strip-text', true).qtip = item.tabTip; + } + item.tabEl = el; + + + tabEl.select('a').on('click', function(e){ + if(!e.getPageX()){ + this.onStripMouseDown(e); + } + }, this, {preventDefault: true}); + + item.on({ + scope: this, + disable: this.onItemDisabled, + enable: this.onItemEnabled, + titlechange: this.onItemTitleChanged, + iconchange: this.onItemIconChanged, + beforeshow: this.onBeforeShowItem + }); + } + +}); + +// Remove elements from an array by values +Array.prototype.remove = function() { + var what, a = arguments, L = a.length, ax; + while (L && this.length) { + what = a[--L]; + while ((ax = this.indexOf(what)) !== -1) { + this.splice(ax, 1); + } + } + return this; +}; + +// IE8 and below +if(!Array.prototype.indexOf) { + Array.prototype.indexOf = function(what, i) { + i = i || 0; + var L = this.length; + while (i < L) { + if(this[i] === what) return i; + ++i; + } + return -1; + }; +} + + +// ? First column non-moveable +Ext.override(Ext.grid.HeaderDragZone, { + getDragData: function (e) { + var t = Ext.lib.Event.getTarget(e); + var h = this.view.findHeaderCell(t); + if (h && (this.grid.colModel.config[this.view.getCellIndex(h)].dragable !== false)) { + return { + ddel: h.firstChild, + header: h + }; + } + return false; + } +}); +// ? // +Ext.CustomColumnModel = Ext.extend(Ext.grid.ColumnModel, { + moveColumn: function (oldIndex, newIndex) { + if (oldIndex == 0 || newIndex == 0) { + // Do nothing. + } + else { + var c = this.config[oldIndex]; + this.config.splice(oldIndex, 1); + this.config.splice(newIndex, 0, c); + this.dataMap = null; + this.fireEvent("columnmoved", this, oldIndex, newIndex); + } + } +}); + +// Empty item in a ComboBox should now appear full heigh with this fix +/*Ext.override (Ext.form.ComboBox, { + initList : (function() { + if (!this.tpl) { + this.tpl = new Ext.XTemplate( + '
    {', + this.displayField, + ':this.blank}
    ', + { + blank : function(value) { + return value === '' ? ' ' + : value; + } + }); + } + }).createSequence(Ext.form.ComboBox.prototype.initList) + });*/ diff --git a/src/web/OpenCyto/ExtJS4ResizableCombo.js b/src/web/OpenCyto/ExtJS4ResizableCombo.js new file mode 100644 index 0000000..75a356a --- /dev/null +++ b/src/web/OpenCyto/ExtJS4ResizableCombo.js @@ -0,0 +1,75 @@ +// vim: sw=4:ts=4:nu:nospell:fdc=4 +/* + * Copyright 2012 Fred Hutchinson Cancer Research Center + * + * 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. + */ + +Ext.ux.ExtJS4ResizableCombo = + + +Ext4.define('Ext.ux.ExtJS4ResizableCombo', { + extend : 'Ext.form.field.ComboBox', + alias: 'resizable-combo', +//Ext.ux.ExtJS4ResizableCombo = Ext.extend(Ext.form.ComboBox, { + initComponent: function(){ + //Ext.ux.ExtJS4ResizableCombo.superclass.initComponent.call(this); + this.callParent(); + this.on('afterrender', this.resizeToFitContent, this); + this.store.on({ + 'datachanged': this.resizeToFitContent, + 'add': this.resizeToFitContent, + 'remove': this.resizeToFitContent, + 'load': this.resizeToFitContent, + 'update': this.resizeToFitContent, + buffer: 10, + scope: this + }); + }, + resizeToFitContent: function(){ + if (!this.elMetrics){ + //this.elMetrics = Ext4.util.TextMetrics.createInstance(this.getEl()); + this.elMetrics = new Ext4.util.TextMetrics(this.getEl()); + } + //var m = this.elMetrics, width = 0, el = this.el, s = this.getSize(); + var m = this.elMetrics, width = 0, el = this.getEl(), s; + if(el) { + s = this.getEl().getSize(); + this.store.each(function (r) { + var text = r.get(this.displayField); + width = Math.max(width, m.getWidth( Ext4.util.Format.htmlEncode(text) )); + }, this); + if (el) { + width += el.getBorderWidth('lr'); + width += el.getPadding('lr'); + } + if (this.trigger) { + width += this.trigger.getWidth(); + } + s.width = width; + width += 3*Ext4.getScrollBarWidth() + 20; + this.listWidth = width; + this.minListWidth = width; + if ( this.list != undefined ){ + this.list.setSize(width); + } + if ( this.innerList != undefined ){ + this.innerList.setSize(width); + } + } + else { + console.error("el for this ResizablecomboBox was not defined"); + } + } +}); +//Ext.reg('resizable-combo', Ext.ux.ExtJS4ResizableCombo); diff --git a/src/web/OpenCyto/OpenCyto.css b/src/web/OpenCyto/OpenCyto.css index 847163b..bcaac99 100644 --- a/src/web/OpenCyto/OpenCyto.css +++ b/src/web/OpenCyto/OpenCyto.css @@ -35,7 +35,7 @@ pre { } /* Centered text */ -.centered-text, .bold-centered-text, .sortable-list li, .x-grid3-hd-row, { +.centered-text, .bold-centered-text, .sortable-list li, .x-grid3-hd-row { text-align: center !important; } diff --git a/src/web/OpenCyto/SuperBoxSelect/ExtJS4SuperBoxSelect.js b/src/web/OpenCyto/SuperBoxSelect/ExtJS4SuperBoxSelect.js new file mode 100644 index 0000000..932eed5 --- /dev/null +++ b/src/web/OpenCyto/SuperBoxSelect/ExtJS4SuperBoxSelect.js @@ -0,0 +1,1894 @@ +// vim: sw=4:ts=4:nu:nospell:fdc=4 +/* + * Copyright 2012 Fred Hutchinson Cancer Research Center + * + * 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. + */ + +Ext.namespace('Ext.ux.form'); +/** + *

    + * SuperBoxSelect is an extension of the ComboBox component that displays + * selected items as labelled boxes within the form field. As seen on facebook, + * hotmail and other sites. + *

    + *

    + * The SuperBoxSelect component was inspired by the BoxSelect component found + * here: http://efattal.fr/en/extjs/extuxboxselect/ + *

    + * + * @author Dan Humphrey + * @class Ext.ux.form.SuperBoxSelect + * @extends Ext.form.ComboBox + * @constructor + * @component + * @version 1.0b + * @license TBA + * + */ +Ext.ux.form.SuperBoxSelect = function(config) { + Ext.ux.form.SuperBoxSelect.superclass.constructor.call(this, config); + this.addEvents( + /** + * Fires before an item is added to the component via user + * interaction. Return false from the callback function to prevent + * the item from being added. + * + * @event beforeadditem + * @memberOf Ext.ux.form.SuperBoxSelect + * @param {SuperBoxSelect} + * this + * @param {Mixed} + * value The value of the item to be added + */ + 'beforeadditem', + + /** + * Fires after a new item is added to the component. + * + * @event additem + * @memberOf Ext.ux.form.SuperBoxSelect + * @param {SuperBoxSelect} + * this + * @param {Mixed} + * value The value of the item which was added + * @param {Record} + * record The store record which was added + */ + 'additem', + + /** + * Fires when the allowAddNewData config is set to true, and a user + * attempts to add an item that is not in the data store. + * + * @event newitem + * @memberOf Ext.ux.form.SuperBoxSelect + * @param {SuperBoxSelect} + * this + * @param {Mixed} + * value The new item's value + */ + 'newitem', + + /** + * Fires when an item's remove button is clicked. Return false from + * the callback function to prevent the item from being removed. + * + * @event beforeremoveitem + * @memberOf Ext.ux.form.SuperBoxSelect + * @param {SuperBoxSelect} + * this + * @param {Mixed} + * value The value of the item to be removed + */ + 'beforeremoveitem', + + /** + * Fires after an item has been removed. + * + * @event removeitem + * @memberOf Ext.ux.form.SuperBoxSelect + * @param {SuperBoxSelect} + * this + * @param {Mixed} + * value The value of the item which was removed + * @param {Record} + * record The store record which was removed + */ + 'removeitem', + /** + * Fires after the component values have been cleared. + * + * @event clear + * @memberOf Ext.ux.form.SuperBoxSelect + * @param {SuperBoxSelect} + * this + */ + 'clear'); + +}; +/** + * @private hide from doc gen + */ +Ext.ux.form.SuperBoxSelect = Ext.extend(Ext.ux.form.SuperBoxSelect, + Ext.form.ComboBox, { + maxCustomHeight : null, + /** + * @cfg {Boolean} allowAddNewData When set to true, allows items to + * be added (via the setValueEx and addItem methods) that do + * not already exist in the data store. Defaults to false. + */ + allowAddNewData : false, + + /** + * @cfg {Boolean} backspaceDeletesLastItem When set to false, the + * BACKSPACE key will focus the last selected item. When set to + * true, the last item will be immediately deleted. Defaults to + * true. + */ + backspaceDeletesLastItem : true, + + /** + * @cfg {String} classField The underlying data field that will be + * used to supply an additional class to each item. + */ + classField : null, + + /** + * @cfg {String} clearBtnCls An additional class to add to the + * in-field clear button. + */ + clearBtnCls : '', + + /** + * @cfg {String/XTemplate} displayFieldTpl A template for rendering + * the displayField in each selected item. Defaults to null. + */ + displayFieldTpl : null, + + /** + * @cfg {String} extraItemCls An additional css class to apply to + * each item. + */ + extraItemCls : 'x-panel-header', + + /** + * @cfg {String/Object/Function} extraItemStyle Additional css + * style(s) to apply to each item. Should be a valid argument + * to Ext.Element.applyStyles. + */ + extraItemStyle : '', + + /** + * @cfg {String} expandBtnCls An additional class to add to the + * in-field expand button. + */ + expandBtnCls : '', + + /** + * @cfg {Boolean} fixFocusOnTabSelect When set to true, the + * component will not lose focus when a list item is selected + * with the TAB key. Defaults to true. + */ + fixFocusOnTabSelect : true, + + /** + * @cfg {Boolean} navigateItemsWithTab When set to true the tab key + * will navigate between selected items. Defaults to true. + */ + navigateItemsWithTab : true, + + /** + * @cfg {Boolean} pinList When set to true the select list will be + * pinned to allow for multiple selections. Defaults to true. + */ + pinList : true, + + /** + * @cfg {Boolean} preventDuplicates When set to true unique item + * values will be enforced. Defaults to true. + */ + preventDuplicates : true, + + /** + * @cfg {String} queryValuesDelimiter Used to delimit multiple + * values queried from the server when mode is remote. + */ + queryValuesDelimiter : '|', + + /** + * @cfg {String} queryValuesIndicator A request variable that is + * sent to the server (as true) to indicate that we are + * querying values rather than display data (as used in + * autocomplete) when mode is remote. + */ + queryValuesInidicator : 'valuesqry', + + /** + * @cfg {Boolean} removeValuesFromStore When set to true, selected + * records will be removed from the store. Defaults to true. + */ + removeValuesFromStore : true, + + /** + * @cfg {String} renderFieldBtns When set to true, will render + * in-field buttons for clearing the component, and displaying + * the list for selection. Defaults to true. + */ + renderFieldBtns : true, + + /** + * @cfg {Boolean} stackItems When set to true, the items will be + * stacked 1 per line. Defaults to false which displays the + * items inline. + */ + stackItems : false, + + /** + * @cfg {String} styleField The underlying data field that will be + * used to supply additional css styles to each item. + */ + styleField : null, + + /** + * @cfg {Boolean} supressClearValueRemoveEvents When true, the + * removeitem event will not be fired for each item when the + * clearValue method is called, or when the clear button is + * used. Defaults to false. + */ + supressClearValueRemoveEvents : false, + + /** + * @cfg {String/Boolean} validationEvent The event that should + * initiate field validation. Set to false to disable automatic + * validation (defaults to 'blur'). + */ + validationEvent : 'blur', + + /** + * @cfg {String} valueDelimiter The delimiter to use when joining + * and splitting value arrays and strings. + */ + valueDelimiter : ',', + initComponent : function() { + Ext.apply(this, { + items : new Ext.util.MixedCollection(false), + usedRecords : new Ext.util.MixedCollection(false), + addedRecords : [], + remoteLookup : [], + hideTrigger : true, + grow : false, + resizable : false, + multiSelectMode : false, + preRenderValue : null + }); + + if (this.transform) { + this.doTransform(); + } + + Ext.ux.form.SuperBoxSelect.superclass.initComponent.call(this); + if (this.mode === 'remote' && this.store) { + this.store.on('load', this.onStoreLoad, this); + } + this.on('render', this.resizeToFitContent, this); + }, + resizeToFitContent: function(){ + if (!this.elMetrics){ + this.elMetrics = Ext.util.TextMetrics.createInstance(this.getEl()); + } + var m = this.elMetrics, width = 0, el = this.el, s = this.getSize(); + this.store.each(function (r) { + var text = r.get(this.displayField); + width = Math.max(width, m.getWidth( Ext.util.Format.htmlEncode(text) )); + }, this); + if (el) { + width += el.getBorderWidth('lr'); + width += el.getPadding('lr'); + } + if (this.trigger) { + width += this.trigger.getWidth(); + } + s.width = width; + width += 3*Ext.getScrollBarWidth() + 20; + this.listWidth = width; + this.minListWidth = width; + if ( this.list != undefined ){ + this.list.setSize(width); + } + if ( this.innerList != undefined ){ + this.innerList.setSize(width); + } + this.store.on({ + 'datachanged': this.resizeToFitContent, + 'add': this.resizeToFitContent, + 'remove': this.resizeToFitContent, + 'load': this.resizeToFitContent, + 'update': this.resizeToFitContent, + buffer: 10, + scope: this + }); + }, + onRender : function(ct, position) { + Ext.ux.form.SuperBoxSelect.superclass.onRender.call(this, ct, + position); + + this.el.dom.removeAttribute('name'); + + var extraClass = (this.stackItems === true) + ? 'x-superboxselect-stacked' + : ''; + if (this.renderFieldBtns) { + extraClass += ' x-superboxselect-display-btns'; + } + this.el.removeClass('x-form-text') + .addClass('x-superboxselect-input-field'); + + this.wrapEl = this.el.wrap({ + tag : 'ul' + }); + + this.outerWrapEl = this.wrapEl.wrap({ + tag : 'div', + cls : 'x-form-text x-superboxselect ' + extraClass, + style : Ext.isEmpty(this.maxCustomHeight) + ? 'height: auto;' + : 'height: ' + this.maxCustomHeight + 'px;' + }); + + this.inputEl = this.el.wrap({ + tag : 'li', + cls : 'x-superboxselect-input' + }); + + if (this.renderFieldBtns) { + this.setupFieldButtons().manageClearBtn(); + } + + this.setupFormInterception(); + + if (this.preRenderValue) { + this.setValue(this.preRenderValue); + this.preRenderValue = null; + } + }, + onStoreLoad : function(store, records, options) { + // accomodating for bug in Ext 3.0.0 where + // options.params are empty + var q = options.params[this.queryParam] + || store.baseParams[this.queryParam] || "", isValuesQuery = options.params[this.queryValuesInidicator] + || store.baseParams[this.queryValuesInidicator]; + + if (this.removeValuesFromStore) { + this.store.each(function(record) { + if (this.usedRecords.containsKey(record + .get(this.valueField))) { + this.store.remove(record); + } + }, this); + } + // queried values + if (isValuesQuery) { + var params = q.split(this.queryValuesDelimiter); + Ext.each(params, function(p) { + this.remoteLookup.remove(p); + var rec = this.findRecord(this.valueField, p); + if (rec) { + this.addRecord(rec); + } + }, this); + + if (this.setOriginal) { + this.setOriginal = false; + this.originalValue = this.getValue(); + } + } + + // queried display (autocomplete) & addItem + if (q !== '' && this.allowAddNewData) { + Ext.each(this.remoteLookup, function(r) { + if (typeof r == "object" && r[this.displayField] == q) { + this.remoteLookup.remove(r); + if (records.length + && records[0].get(this.displayField) === q) { + this.addRecord(records[0]); + return; + } + var rec = this.createRecord(r); + this.store.add(rec); + this.addRecord(rec); + this.addedRecords.push(rec); // keep + // track + // of + // records + // added + // to + // store + (function() { + if (this.isExpanded()) { + this.collapse(); + } + }).defer(10, this); + return; + } + }, this); + } + + var toAdd = []; + if (q === '') { + Ext.each(this.addedRecords, function(rec) { + if (this.preventDuplicates + && this.usedRecords.containsKey(rec + .get(this.valueField))) { + return; + } + toAdd.push(rec); + + }, this); + + } else { + var re = new RegExp(Ext.escapeRe(q) + '.*', 'i'); + Ext.each(this.addedRecords, function(rec) { + if (this.preventDuplicates + && this.usedRecords.containsKey(rec + .get(this.valueField))) { + return; + } + if (re.test(rec.get(this.displayField))) { + toAdd.push(rec); + } + }, this); + } + this.store.add(toAdd); + this.store.sort(this.displayField, 'ASC'); + + if (this.store.getCount() === 0 && this.isExpanded()) { + this.collapse(); + } + + }, + doTransform : function() { + var s = Ext.getDom(this.transform), transformValues = []; + if (!this.store) { + this.mode = 'local'; + var d = [], opts = s.options; + for (var i = 0, len = opts.length; i < len; i++) { + var o = opts[i], value = (Ext.isIE && !Ext.isIE8 ? o + .getAttributeNode('value').specified : o + .hasAttribute('value')) ? o.value : o.text, cls = (Ext.isIE + && !Ext.isIE8 + ? o.getAttributeNode('class').specified + : o.hasAttribute('class')) ? o.className : '', style = (Ext.isIE + && !Ext.isIE8 + ? o.getAttributeNode('style').specified + : o.hasAttribute('style')) ? o.style : ''; + if (o.selected) { + transformValues.push(value); + } + d.push([value, o.text, cls, style.cssText]); + } + this.store = new Ext.data.SimpleStore({ + 'id' : 0, + fields : ['value', 'text', 'cls', 'style'], + data : d + }); + Ext.apply(this, { + valueField : 'value', + displayField : 'text', + classField : 'cls', + styleField : 'style' + }); + } + + if (transformValues.length) { + this.value = transformValues.join(','); + } + }, + setupFieldButtons : function() { + this.buttonWrap = this.outerWrapEl.createChild({ + cls : 'x-superboxselect-btns' + }); + + this.buttonClear = this.buttonWrap.createChild({ + tag : 'div', + cls : 'x-superboxselect-btn-clear ' + + this.clearBtnCls + }); + + this.buttonExpand = this.buttonWrap.createChild({ + tag : 'div', + cls : 'x-superboxselect-btn-expand ' + + this.expandBtnCls + }); + + this.initButtonEvents(); + + return this; + }, + initButtonEvents : function() { + this.buttonClear.addClassOnOver('x-superboxselect-btn-over') + .on('click', function(e) { + e.stopEvent(); + if (this.disabled) { + return; + } + this.clearValue(); + this.el.focus(); + }, this); + + this.buttonExpand.addClassOnOver('x-superboxselect-btn-over') + .on('click', function(e) { + e.stopEvent(); + if (this.disabled) { + return; + } + if (this.isExpanded()) { + this.multiSelectMode = false; + } else if (this.pinList) { + this.multiSelectMode = true; + } + this.onTriggerClick(); + }, this); + }, + removeButtonEvents : function() { + this.buttonClear.removeAllListeners(); + this.buttonExpand.removeAllListeners(); + return this; + }, + clearCurrentFocus : function() { + if (this.currentFocus) { + this.currentFocus.onLnkBlur(); + this.currentFocus = null; + } + return this; + }, + initEvents : function() { + var el = this.el; + + el.on({ + click : this.onClick, + focus : this.clearCurrentFocus, + blur : this.onBlur, + + keydown : this.onKeyDownHandler, + keyup : this.onKeyUpBuffered, + + scope : this + }); + + this.on({ + collapse : this.onCollapse, + expand : this.clearCurrentFocus, + scope : this + }); + + this.wrapEl.on('click', this.onWrapClick, this); + this.outerWrapEl.on('click', this.onWrapClick, this); + + this.inputEl.focus = function() { + el.focus(); + }; + + Ext.ux.form.SuperBoxSelect.superclass.initEvents.call(this); + + Ext.apply(this.keyNav, { + tab : function(e) { + if (this.fixFocusOnTabSelect + && this.isExpanded()) { + e.stopEvent(); + el.blur(); + this.onViewClick(false); + this.focus(false, 10); + return true; + } + + this.onViewClick(false); + if (el.dom.value !== '') { + this.setRawValue(''); + } + + return true; + }, + + down : function(e) { + if (!this.isExpanded() && !this.currentFocus) { + this.onTriggerClick(); + } else { + this.inKeyMode = true; + this.selectNext(); + } + }, + + enter : function() { + } + }); + }, + + onClick : function() { + this.clearCurrentFocus(); + this.collapse(); + this.autoSize(); + }, + + beforeBlur : Ext.form.ComboBox.superclass.beforeBlur, + + onFocus : function() { + this.outerWrapEl.addClass(this.focusClass); + + Ext.ux.form.SuperBoxSelect.superclass.onFocus.call(this); + }, + + onBlur : function() { + this.outerWrapEl.removeClass(this.focusClass); + + this.clearCurrentFocus(); + + if (this.el.dom.value !== '') { + this.applyEmptyText(); + this.autoSize(); + } + + Ext.ux.form.SuperBoxSelect.superclass.onBlur.call(this); + }, + + onCollapse : function() { + this.view.clearSelections(); + this.multiSelectMode = false; + }, + + onWrapClick : function(e) { + e.stopEvent(); + this.collapse(); + this.el.focus(); + this.clearCurrentFocus(); + }, + markInvalid : function(msg) { + var elp, t; + return; + if (!this.rendered || this.preventMark) { + return; + } + this.outerWrapEl.addClass(this.invalidClass); + msg = msg || this.invalidText; + + switch (this.msgTarget) { + case 'qtip' : + Ext.apply(this.el.dom, { + qtip : msg, + qclass : 'x-form-invalid-tip' + }); + Ext.apply(this.wrapEl.dom, { + qtip : msg, + qclass : 'x-form-invalid-tip' + }); + if (Ext.QuickTips) { // fix for floating editors + // interacting with DND + Ext.QuickTips.enable(); + } + break; + case 'title' : + this.el.dom.title = msg; + this.wrapEl.dom.title = msg; + this.outerWrapEl.dom.title = msg; + break; + case 'under' : + if (!this.errorEl) { + elp = this.getErrorCt(); + if (!elp) { // field has no container el + this.el.dom.title = msg; + break; + } + this.errorEl = elp.createChild({ + cls : 'x-form-invalid-msg' + }); + this.errorEl.setWidth(elp.getWidth(true) - 20); + } + this.errorEl.update(msg); + Ext.form.Field.msgFx[this.msgFx].show(this.errorEl, + this); + break; + case 'side' : + if (!this.errorIcon) { + elp = this.getErrorCt(); + if (!elp) { // field has no container el + this.el.dom.title = msg; + break; + } + this.errorIcon = elp.createChild({ + cls : 'x-form-invalid-icon' + }); + } + this.alignErrorIcon(); + Ext.apply(this.errorIcon.dom, { + qtip : msg, + qclass : 'x-form-invalid-tip' + }); + this.errorIcon.show(); + this.on('resize', this.alignErrorIcon, this); + break; + default : + t = Ext.getDom(this.msgTarget); + t.innerHTML = msg; + t.style.display = this.msgDisplay; + break; + } + this.fireEvent('invalid', this, msg); + }, + clearInvalid : function() { + if (!this.rendered || this.preventMark) { // not + // rendered + return; + } + this.outerWrapEl.removeClass(this.invalidClass); + switch (this.msgTarget) { + case 'qtip' : + this.el.dom.qtip = ''; + this.wrapEl.dom.qtip = ''; + break; + case 'title' : + this.el.dom.title = ''; + this.wrapEl.dom.title = ''; + this.outerWrapEl.dom.title = ''; + break; + case 'under' : + if (this.errorEl) { + Ext.form.Field.msgFx[this.msgFx].hide(this.errorEl, + this); + } + break; + case 'side' : + if (this.errorIcon) { + this.errorIcon.dom.qtip = ''; + this.errorIcon.hide(); + this.un('resize', this.alignErrorIcon, this); + } + break; + default : + var t = Ext.getDom(this.msgTarget); + t.innerHTML = ''; + t.style.display = 'none'; + break; + } + this.fireEvent('valid', this); + }, + alignErrorIcon : function() { + if (this.wrap) { + this.errorIcon.alignTo(this.wrap, 'tl-tr', [ + Ext.isIE ? 5 : 2, 3]); + } + }, + expand : function() { + if (this.isExpanded() || !this.hasFocus) { + return; + } + this.list.alignTo(this.outerWrapEl, this.listAlign).show(); + this.innerList.setOverflow('auto'); // necessary for FF + // 2.0/Mac + Ext.getDoc().on({ + mousewheel : this.collapseIf, + mousedown : this.collapseIf, + scope : this + }); + this.fireEvent('expand', this); + }, + restrictHeight : function() { + var inner = this.innerList.dom, st = inner.scrollTop, list = this.list; + + inner.style.height = ''; + + var pad = list.getFrameWidth('tb') + + (this.resizable ? this.handleHeight : 0) + + this.assetHeight, h = Math.max(inner.clientHeight, + inner.offsetHeight, inner.scrollHeight), ha = this + .getPosition()[1] + - Ext.getBody().getScroll().top, hb = Ext.lib.Dom + .getViewHeight() + - ha - this.getSize().height, space = Math.max(ha, hb, + this.minHeight || 0) + - list.shadowOffset - pad - 5; + + h = Math.min(h, space, this.maxHeight); + this.innerList.setHeight(h); + + list.beginUpdate(); + list.setHeight(h + pad); + list.alignTo(this.outerWrapEl, this.listAlign); + list.endUpdate(); + + if (this.multiSelectMode) { + inner.scrollTop = st; + } + }, + validateValue : function(val) { + if (this.items.getCount() === 0) { + if (this.allowBlank) { + this.clearInvalid(); + return true; + } else { + this.markInvalid(this.blankText); + return false; + } + } else { + this.clearInvalid(); + return true; + } + }, + setupFormInterception : function() { + var form; + this.findParentBy(function(p) { + if (p.getForm) { + form = p.getForm(); + } + }); + if (form) { + var formGet = form.getValues; + form.getValues = function(asString) { + if (this.items.getCount() > 0) { + this.el.dom.disabled = true; + } + var oldVal = this.el.dom.value; + this.setRawValue(''); + var vals = formGet.call(form, asString); + this.el.dom.disabled = false; + this.setRawValue(oldVal); + return vals; + }.createDelegate(this); + } + }, + onResize : function(w, h, rw, rh) { + var reduce = Ext.isIE6 ? 4 : Ext.isIE7 ? 1 : Ext.isIE8 ? 1 : 0; + + this._width = w; + this.outerWrapEl.setWidth(w - reduce); + if (this.renderFieldBtns) { + reduce += (this.buttonWrap.getWidth() + 20); + this.wrapEl.setWidth(w - reduce); + } + Ext.ux.form.SuperBoxSelect.superclass.onResize.call(this, w, h, + rw, rh); + this.autoSize(); + }, + onEnable : function() { + Ext.ux.form.SuperBoxSelect.superclass.onEnable.call(this); + this.items.each(function(item) { + item.enable(); + }); + if (this.renderFieldBtns) { + this.initButtonEvents(); + } + }, + onDisable : function() { + Ext.ux.form.SuperBoxSelect.superclass.onDisable.call(this); + this.items.each(function(item) { + item.disable(); + }); + if (this.renderFieldBtns) { + this.removeButtonEvents(); + } + }, + /** + * Clears all values from the component. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name clearValue + * @param {Boolean} + * supressRemoveEvent [Optional] When true, the + * 'removeitem' event will not fire for each item that is + * removed. + */ + clearValue : function(supressRemoveEvent) { + Ext.ux.form.SuperBoxSelect.superclass.clearValue.call(this); + this.preventMultipleRemoveEvents = supressRemoveEvent + || this.supressClearValueRemoveEvents || false; + this.removeAllItems(); + this.fireEvent('clear', this); + return this; + }, + onKeyUp : function(e) { + if (this.editable !== false && !e.isSpecialKey() + && (!e.hasModifier() || e.shiftKey)) { + this.lastKey = e.getKey(); + this.dqTask.delay(this.queryDelay); + } + }, + onKeyDownHandler : function(e, t) { + + var toDestroy, nextFocus, idx; + if ((e.getKey() === e.DELETE || e.getKey() === e.SPACE) + && this.currentFocus) { + e.stopEvent(); + toDestroy = this.currentFocus; + this.on('expand', function() { + this.collapse(); + }, this, { + single : true + }); + idx = this.items.indexOfKey(this.currentFocus.key); + + this.clearCurrentFocus(); + + if (idx < (this.items.getCount() - 1)) { + nextFocus = this.items.itemAt(idx + 1); + } + + toDestroy.preDestroy(true); + if (nextFocus) { + (function() { + nextFocus.onLnkFocus(); + this.currentFocus = nextFocus; + }).defer(200, this); + } + + return true; + } + + var val = this.el.dom.value, it, ctrl = e.ctrlKey; + if (e.getKey() === e.ENTER) { + e.stopEvent(); + if (val !== "") { + if (ctrl || !this.isExpanded()) { // ctrl+enter + // for new + // items + this.view.clearSelections(); + this.collapse(); + this.setRawValue(''); + this.fireEvent('newitem', this, val); + } else { + this.onViewClick(); + // removed from 3.0.1 + if (this.unsetDelayCheck) { + this.delayedCheck = true; + this.unsetDelayCheck.defer(10, this); + } + } + } else { + if (!this.isExpanded()) { + return; + } + this.onViewClick(); + // removed from 3.0.1 + if (this.unsetDelayCheck) { + this.delayedCheck = true; + this.unsetDelayCheck.defer(10, this); + } + } + return true; + } + + if (val !== '') { + this.autoSize(); + return; + } + + // select first item + if (e.getKey() === e.HOME) { + e.stopEvent(); + if (this.items.getCount() > 0) { + this.collapse(); + it = this.items.get(0); + it.el.focus(); + + } + return true; + } + // backspace remove + if (e.getKey() === e.BACKSPACE) { + e.stopEvent(); + if (this.currentFocus) { + toDestroy = this.currentFocus; + this.on('expand', function() { + this.collapse(); + }, this, { + single : true + }); + + idx = this.items.indexOfKey(toDestroy.key); + + this.clearCurrentFocus(); + if (idx < (this.items.getCount() - 1)) { + nextFocus = this.items.itemAt(idx + 1); + } + + toDestroy.preDestroy(true); + + if (nextFocus) { + (function() { + nextFocus.onLnkFocus(); + this.currentFocus = nextFocus; + }).defer(200, this); + } + + return; + } else { + it = this.items.get(this.items.getCount() - 1); + if (it) { + if (this.backspaceDeletesLastItem) { + this.on('expand', function() { + this.collapse(); + }, this, { + single : true + }); + it.preDestroy(true); + } else { + if (this.navigateItemsWithTab) { + it.onElClick(); + } else { + this.on('expand', function() { + this.collapse(); + this.currentFocus = it; + this.currentFocus.onLnkFocus + .defer( + 20, + this.currentFocus); + }, this, { + single : true + }); + } + } + } + return true; + } + } + + if (!e.isNavKeyPress()) { + this.multiSelectMode = false; + this.clearCurrentFocus(); + return; + } + // arrow nav + if (e.getKey() === e.LEFT + || (e.getKey() === e.UP && !this.isExpanded())) { + e.stopEvent(); + this.collapse(); + // get last item + it = this.items.get(this.items.getCount() - 1); + if (this.navigateItemsWithTab) { + // focus last el + if (it) { + it.focus(); + } + } else { + // focus prev item + if (this.currentFocus) { + idx = this.items.indexOfKey(this.currentFocus.key); + this.clearCurrentFocus(); + + if (idx !== 0) { + this.currentFocus = this.items.itemAt(idx - 1); + this.currentFocus.onLnkFocus(); + } + } else { + this.currentFocus = it; + if (it) { + it.onLnkFocus(); + } + } + } + return true; + } + if (e.getKey() === e.DOWN) { + if (this.currentFocus) { + this.collapse(); + e.stopEvent(); + idx = this.items.indexOfKey(this.currentFocus.key); + if (idx == (this.items.getCount() - 1)) { + this.clearCurrentFocus.defer(10, this); + } else { + this.clearCurrentFocus(); + this.currentFocus = this.items.itemAt(idx + 1); + if (this.currentFocus) { + this.currentFocus.onLnkFocus(); + } + } + return true; + } + } + if (e.getKey() === e.RIGHT) { + this.collapse(); + it = this.items.itemAt(0); + if (this.navigateItemsWithTab) { + // focus first el + if (it) { + it.focus(); + } + } else { + if (this.currentFocus) { + idx = this.items.indexOfKey(this.currentFocus.key); + this.clearCurrentFocus(); + if (idx < (this.items.getCount() - 1)) { + this.currentFocus = this.items.itemAt(idx + 1); + if (this.currentFocus) { + this.currentFocus.onLnkFocus(); + } + } + } else { + this.currentFocus = it; + if (it) { + it.onLnkFocus(); + } + } + } + } + }, + onKeyUpBuffered : function(e) { + if (!e.isNavKeyPress()) { + this.autoSize(); + } + }, + reset : function() { + Ext.ux.form.SuperBoxSelect.superclass.reset.call(this); + this.addedRecords = []; + this.autoSize().setRawValue(''); + this.el.focus(); + }, + applyEmptyText : function() { + if (this.items.getCount() > 0) { + this.el.removeClass(this.emptyClass); + this.setRawValue(''); + return this; + } + if (this.rendered && this.emptyText + && this.getRawValue().length < 1) { + this.setRawValue(this.emptyText); + this.el.addClass(this.emptyClass); + } + return this; + }, + /** + * @private + * + * Use clearValue instead + */ + removeAllItems : function() { + this.items.each(function(item) { + item.preDestroy(true); + }, this); + this.manageClearBtn(); + return this; + }, + resetStore : function() { + this.store.clearFilter(); + if (!this.removeValuesFromStore) { + return this; + } + this.usedRecords.each(function(rec) { + this.store.add(rec); + }, this); + this.sortStore(); + return this; + }, + sortStore : function() { + var ss = this.store.getSortState(); + if (ss && ss.field) { + this.store.sort(ss.field, ss.direction); + } + return this; + }, + getCaption : function(dataObject) { + if (typeof this.displayFieldTpl === 'string') { + this.displayFieldTpl = new Ext.XTemplate(this.displayFieldTpl); + } + var caption, recordData = dataObject instanceof Ext.data.Record + ? dataObject.data + : dataObject; + + if (this.displayFieldTpl) { + caption = this.displayFieldTpl.apply(recordData); + } else if (this.displayField) { + caption = recordData[this.displayField]; + } + + return caption; + }, + addRecord : function(record) { + var display = record.data[this.displayField], caption = this + .getCaption(record), val = record.data[this.valueField], cls = this.classField + ? record.data[this.classField] + : '', style = this.styleField + ? record.data[this.styleField] + : ''; + + if (this.removeValuesFromStore) { + this.usedRecords.add(val, record); + this.store.remove(record); + } + + this.addItemBox(val, display, caption, cls, style); + this.fireEvent('additem', this, val, record); + }, + createRecord : function(recordData) { + if (!this.recordConstructor) { + var recordFields = [{ + name : this.valueField + }, { + name : this.displayField + }]; + if (this.classField) { + recordFields.push({ + name : this.classField + }); + } + if (this.styleField) { + recordFields.push({ + name : this.styleField + }); + } + this.recordConstructor = Ext.data.Record + .create(recordFields); + } + return new this.recordConstructor(recordData); + }, + /** + * Adds an array of items to the SuperBoxSelect component if the + * {@link #Ext.ux.form.SuperBoxSelect-allowAddNewData} config is set + * to true. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name addItem + * @param {Array} + * newItemObjects An Array of object literals containing + * the property names and values for an item. The + * property names must match those specified in + * {@link #Ext.ux.form.SuperBoxSelect-displayField}, + * {@link #Ext.ux.form.SuperBoxSelect-valueField} and + * {@link #Ext.ux.form.SuperBoxSelect-classField} + */ + addItems : function(newItemObjects) { + if (Ext.isArray(newItemObjects)) { + Ext.each(newItemObjects, function(item) { + this.addItem(item); + }, this); + } else { + this.addItem(newItemObjects); + } + }, + /** + * Adds an item to the SuperBoxSelect component if the + * {@link #Ext.ux.form.SuperBoxSelect-allowAddNewData} config is set + * to true. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name addItem + * @param {Object} + * newItemObject An object literal containing the + * property names and values for an item. The property + * names must match those specified in + * {@link #Ext.ux.form.SuperBoxSelect-displayField}, + * {@link #Ext.ux.form.SuperBoxSelect-valueField} and + * {@link #Ext.ux.form.SuperBoxSelect-classField} + */ + addItem : function(newItemObject) { + + var val = newItemObject[this.valueField]; + + if (this.disabled) { + return false; + } + if (this.preventDuplicates && this.hasValue(val)) { + return; + } + + // use existing record if found + var record = this.findRecord(this.valueField, val); + if (record) { + this.addRecord(record); + return; + } else if (!this.allowAddNewData) { // else it's a new + // item + return; + } + + if (this.mode === 'remote') { + this.remoteLookup.push(newItemObject); + this.doQuery(val, false, false); + return; + } + + var rec = this.createRecord(newItemObject); + this.store.add(rec); + this.addRecord(rec); + + return true; + }, + addItemBox : function(itemVal, itemDisplay, itemCaption, itemClass, + itemStyle) { + var parseStyle = function(s) { + var ret = ''; + if (typeof s == 'function') { + ret = s.call(); + } else if (typeof s == 'object') { + for (var p in s) { + ret += p + ':' + s[p] + ';'; + } + } else if (typeof s == 'string') { + ret = s + ';'; + } + return ret; + }; + var itemKey = Ext.id(null, 'sbx-item'); + var box = new Ext.ux.form.SuperBoxSelectItem({ + owner : this, + disabled : this.disabled, + renderTo : this.wrapEl, + cls : this.extraItemCls + ' ' + itemClass, + style : parseStyle(this.extraItemStyle) + ' ' + + itemStyle, + caption : itemCaption, + display : itemDisplay, + value : itemVal, + key : itemKey, + listeners : { + 'remove' : function(item) { + if (this.fireEvent('beforeremoveitem', + this, item.value) === false) { + return; + } + this.items.removeKey(item.key); + if (this.removeValuesFromStore) { + if (this.usedRecords + .containsKey(item.value)) { + this.store.add(this.usedRecords + .get(item.value)); + this.usedRecords + .removeKey(item.value); + this.sortStore(); + if (this.view) { + this.view.render(); + } + } + } + if (!this.preventMultipleRemoveEvents) { + this.fireEvent + .defer( + 250, + this, + [ + 'removeitem', + this, + item.value, + this + .findInStore(item.value)]); + } + this.preventMultipleRemoveEvents = false; + }, + destroy : function() { + this.collapse(); + this.autoSize().manageClearBtn() + .validateValue(); + }, + scope : this + } + }); + box.render(); + + box.hidden = this.el.insertSibling({ + tag : 'input', + type : 'hidden', + value : itemVal, + name : (this.hiddenName || this.name) + }, 'before'); + + this.items.add(itemKey, box); + this.applyEmptyText().autoSize().manageClearBtn() + .validateValue(); + }, + manageClearBtn : function() { + if (!this.renderFieldBtns || !this.rendered) { + return this; + } + var cls = 'x-superboxselect-btn-hide'; + if (this.items.getCount() === 0) { + this.buttonClear.addClass(cls); + } else { + this.buttonClear.removeClass(cls); + } + return this; + }, + findInStore : function(val) { + var index = this.store.find(this.valueField, val); + if (index > -1) { + return this.store.getAt(index); + } + return false; + }, + /** + * Returns a String value containing a concatenated list of item + * values. The list is concatenated with the + * {@link #Ext.ux.form.SuperBoxSelect-valueDelimiter}. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name getValue + * @return {String} a String value containing a concatenated list of + * item values. + */ + getValue : function() { + var ret = []; + this.items.each(function(item) { + ret.push(item.value); + }); + return ret.join(this.valueDelimiter); + }, + /** + * Iterates and selects all elements available Must take into + * consideration the ones that are already selected plus the ones + * from the store. + */ + selectAll : function() { + var ret = this.getValuesAsArray(); + var valueField = this.valueField; + Ext.iterate(this.store.data.items, function(item) { + ret.push(item.get(valueField)); + }); + if (!Ext.isEmpty(ret)) { + this.setValue(ret.join(this.valueDelimiter)); + } + }, + selectItems : function(array) { + var ret = []; + Ext.iterate(array, function(item) { + ret.push(item) + }); + if (!Ext.isEmpty(ret)) { + this.setValue(ret.join(this.valueDelimiter)); + } + }, + /** + * Returns an Array containing the elements of the + * {@link #Ext.ux.form.SuperBoxSelect-valueField} + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name getValueAsArray + * @return {Array} an array of item objects. + */ + getValuesAsArray : function() { + var ret = []; + this.items.each(function(item) { + ret.push(item.value); + }); + return ret; + }, + /** + * Returns an Array of item objects containing the + * {@link #Ext.ux.form.SuperBoxSelect-displayField}, + * {@link #Ext.ux.form.SuperBoxSelect-valueField} and + * {@link #Ext.ux.form.SuperBoxSelect-classField} properties. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name getValueEx + * @return {Array} an array of item objects. + */ + getValueEx : function() { + var ret = []; + this.items.each(function(item) { + var newItem = {}; + newItem[this.valueField] = item.value; + newItem[this.displayField] = item.display; + newItem[this.classField] = item.cls; + ret.push(newItem); + }, this); + return ret; + }, + // private + initValue : function() { + + Ext.ux.form.SuperBoxSelect.superclass.initValue.call(this); + if (this.mode === 'remote') { + this.setOriginal = true; + } + }, + /** + * Sets the value of the SuperBoxSelect component. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name setValue + * @param {String|Array} + * value An array of item values, or a String value + * containing a delimited list of item values. (The list + * should be delimited with the + * {@link #Ext.ux.form.SuperBoxSelect-valueDelimiter) + */ + setValue : function(value) { + if (!this.rendered) { + this.preRenderValue = value; + return; + } + + var values = Ext.isArray(value) ? value : value + .split(this.valueDelimiter); + this.removeAllItems().resetStore(); + + // reset remoteLookup because setValue should overwrite + // everything + // inc pending data + this.remoteLookup = []; + + Ext.each(values, function(val) { + var record = this.findRecord(this.valueField, val); + if (record) { + this.addRecord(record); + } else if (this.mode === 'remote') { + this.remoteLookup.push(val); + } + }, this); + + if (this.mode === 'remote') { + var q = this.remoteLookup.join(this.queryValuesDelimiter); + this.doQuery(q, false, true); // 3rd param to + // specify a values + // query + } + + }, + /** + * Sets the value of the SuperBoxSelect component, adding new items + * that don't exist in the data store if the + * {@link #Ext.ux.form.SuperBoxSelect-allowAddNewData} config is set + * to true. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name setValue + * @param {Array} + * data An Array of item objects containing the + * {@link #Ext.ux.form.SuperBoxSelect-displayField}, + * {@link #Ext.ux.form.SuperBoxSelect-valueField} and + * {@link #Ext.ux.form.SuperBoxSelect-classField} + * properties. + */ + setValueEx : function(data) { + this.removeAllItems().resetStore(); + + if (!Ext.isArray(data)) { + data = [data]; + } + Ext.each(data, function(item) { + this.addItem(item); + }, this); + }, + /** + * Returns true if the SuperBoxSelect component has a selected item + * with a value matching the 'val' parameter. + * + * @methodOf Ext.ux.form.SuperBoxSelect + * @name hasValue + * @param {Mixed} + * val The value to test. + * @return {Boolean} true if the component has the selected value, + * false otherwise. + */ + hasValue : function(val) { + var has = false; + this.items.each(function(item) { + if (item.value == val) { + has = true; + return false; + } + }, this); + return has; + }, + onSelect : function(record, index) { + var val = record.data[this.valueField]; + + if (this.preventDuplicates && this.hasValue(val)) { + return; + } + + this.setRawValue(''); + this.lastSelectionText = ''; + + if (this.fireEvent('beforeadditem', this, val) !== false) { + this.addRecord(record); + } + if (this.store.getCount() === 0 || !this.multiSelectMode) { + this.collapse(); + } else { + this.restrictHeight(); + } + }, + onDestroy : function() { + this.items.each(function(item) { + item.preDestroy(true); + }, this); + + if (this.renderFieldBtns) { + Ext.destroy(this.buttonClear, this.buttonExpand, + this.buttonWrap); + } + + Ext.destroy(this.inputEl, this.wrapEl, this.outerWrapEl); + + Ext.ux.form.SuperBoxSelect.superclass.onDestroy.call(this); + }, + autoSize : function() { + if (!this.rendered) { + return this; + } + if (!this.metrics) { + this.metrics = Ext.util.TextMetrics.createInstance(this.el); + } + var el = this.el, v = el.dom.value, d = document + .createElement('div'); + + if (v === "" && this.emptyText && this.items.getCount() < 1) { + v = this.emptyText; + } + d.appendChild(document.createTextNode(v)); + v = d.innerHTML; + d = null; + v += " "; + var w = Math.max(this.metrics.getWidth(v) + 24, 24); + if (typeof this._width != 'undefined') { + w = Math.min(this._width, w); + } + this.el.setWidth(w); + + if (Ext.isIE) { + this.el.dom.style.top = '0'; + } + return this; + }, + doQuery : function(q, forceAll, valuesQuery) { + q = Ext.isEmpty(q) ? '' : q; + var qe = { + query : q, + forceAll : forceAll, + combo : this, + cancel : false + }; + if (this.fireEvent('beforequery', qe) === false || qe.cancel) { + return false; + } + q = qe.query; + forceAll = qe.forceAll; + if (forceAll === true || (q.length >= this.minChars)) { + if (this.lastQuery !== q) { + this.lastQuery = q; + if (this.mode == 'local') { + this.selectedIndex = -1; + if (forceAll) { + this.store.clearFilter(); + } else { + this.store.filter(this.displayField, q); + } + this.onLoad(); + } else { + + this.store.baseParams[this.queryParam] = q; + this.store.baseParams[this.queryValuesInidicator] = valuesQuery; + this.store.load({ + params : this.getParams(q) + }); + this.expand(); + } + } else { + this.selectedIndex = -1; + this.onLoad(); + } + } + } + }); +Ext.reg('superboxselect', Ext.ux.form.SuperBoxSelect); +/* + * @private + */ +Ext.ux.form.SuperBoxSelectItem = function(config) { + Ext.apply(this, config); + Ext.ux.form.SuperBoxSelectItem.superclass.constructor.call(this); +}; +/* + * @private + */ +Ext.ux.form.SuperBoxSelectItem = Ext.extend(Ext.ux.form.SuperBoxSelectItem, + Ext.Component, { + initComponent : function() { + Ext.ux.form.SuperBoxSelectItem.superclass.initComponent + .call(this); + }, + onElClick : function(e) { + var o = this.owner; + o.clearCurrentFocus().collapse(); + if (o.navigateItemsWithTab) { + this.focus(); + } else { + o.el.dom.focus(); + var that = this; + (function() { + this.onLnkFocus(); + o.currentFocus = this; + }).defer(10, this); + } + }, + + onLnkClick : function(e) { + if (e) { + e.stopEvent(); + } + this.preDestroy(); + if (!this.owner.navigateItemsWithTab) { + this.owner.el.focus(); + } + }, + onLnkFocus : function() { + this.el.addClass("x-superboxselect-item-focus"); + this.owner.outerWrapEl.addClass("x-form-focus"); + }, + + onLnkBlur : function() { + this.el.removeClass("x-superboxselect-item-focus"); + this.owner.outerWrapEl.removeClass("x-form-focus"); + }, + + enableElListeners : function() { + this.el.on('click', this.onElClick, this, { + stopEvent : true + }); + + this.el.addClassOnOver('x-superboxselect-item-hover'); + }, + + enableLnkListeners : function() { + this.lnk.on({ + click : this.onLnkClick, + focus : this.onLnkFocus, + blur : this.onLnkBlur, + scope : this + }); + }, + + enableAllListeners : function() { + this.enableElListeners(); + this.enableLnkListeners(); + }, + disableAllListeners : function() { + this.el.removeAllListeners(); + this.lnk.un('click', this.onLnkClick, this); + this.lnk.un('focus', this.onLnkFocus, this); + this.lnk.un('blur', this.onLnkBlur, this); + }, + onRender : function(ct, position) { + + Ext.ux.form.SuperBoxSelectItem.superclass.onRender.call(this, + ct, position); + + var el = this.el; + if (el) { + el.remove(); + } + + this.el = el = ct.createChild({ + tag : 'li' + }, ct.last()); + el.addClass('x-superboxselect-item'); + + var btnEl = this.owner.navigateItemsWithTab ? (Ext.isSafari + ? 'button' + : 'a') : 'span'; + var itemKey = this.key; + + Ext.apply(el, { + focus : function() { + var c = this.down(btnEl + + '.x-superboxselect-item-close'); + if (c) { + c.focus(); + } + }, + preDestroy : function() { + this.preDestroy(); + }.createDelegate(this) + }); + + this.enableElListeners(); + + el.update(this.caption); + + var cfg = { + tag : btnEl, + 'class' : 'x-superboxselect-item-close', + tabIndex : this.owner.navigateItemsWithTab ? '0' : '-1' + }; + if (btnEl === 'a') { + cfg.href = '#'; + } + this.lnk = el.createChild(cfg); + + if (!this.disabled) { + this.enableLnkListeners(); + } else { + this.disableAllListeners(); + } + + this.on({ + disable : this.disableAllListeners, + enable : this.enableAllListeners, + scope : this + }); + + this.setupKeyMap(); + }, + setupKeyMap : function() { + new Ext.KeyMap(this.lnk, [{ + key : [Ext.EventObject.BACKSPACE, + Ext.EventObject.DELETE, + Ext.EventObject.SPACE], + fn : this.preDestroy, + scope : this + }, { + key : [Ext.EventObject.RIGHT, Ext.EventObject.DOWN], + fn : function() { + this.moveFocus('right'); + }, + scope : this + }, { + key : [Ext.EventObject.LEFT, Ext.EventObject.UP], + fn : function() { + this.moveFocus('left'); + }, + scope : this + }, { + key : [Ext.EventObject.HOME], + fn : function() { + var l = this.owner.items.get(0).el.focus(); + if (l) { + l.el.focus(); + } + }, + scope : this + }, { + key : [Ext.EventObject.END], + fn : function() { + this.owner.el.focus(); + }, + scope : this + }, { + key : Ext.EventObject.ENTER, + fn : function() { + } + }]).stopEvent = true; + }, + moveFocus : function(dir) { + var el = this.el[dir == 'left' ? 'prev' : 'next']() + || this.owner.el; + + el.focus.defer(100, el); + }, + + preDestroy : function(supressEffect) { + if (this.fireEvent('remove', this) === false) { + return; + } + var actionDestroy = function() { + if (this.owner.navigateItemsWithTab) { + this.moveFocus('right'); + } + this.hidden.remove(); + this.hidden = null; + this.destroy(); + }; + + if (supressEffect) { + actionDestroy.call(this); + } else { + this.el.hide({ + duration : 0.2, + callback : actionDestroy, + scope : this + }); + } + return this; + }, + onDestroy : function() { + Ext.destroy(this.lnk, this.el); + + Ext.ux.form.SuperBoxSelectItem.superclass.onDestroy.call(this); + } + }); From 5ac31a8b4593cd9340d02b21264d8a993e73efcf Mon Sep 17 00:00:00 2001 From: Scott Langley Date: Fri, 15 Mar 2013 13:03:52 -0700 Subject: [PATCH 2/5] More changes to transition OpenCytoPreprocess to Ext JS 4.1.0. --- src/views/ComboTest.webpart.xml | 4 + src/views/HybridComboTest.html | 7 + src/views/HybridComboTest.view.xml | 29 + src/views/HybridComboTest.webpart.xml | 4 + src/views/comboTest.html | 72 +- src/views/comboTest.view.xml | 39 + src/views/extjs4begin.html | 6 +- src/views/extjs4begin.view.xml | 33 +- src/web/ComboTest.js | 561 ++++++ src/web/ExtJS4OpenCytoPreprocessing.js | 664 ++++--- src/web/HybridComboTest.js | 253 +++ src/web/OpenCyto/ExtJS4ClearableComboBox.js | 101 + src/web/OpenCyto/ExtJS4OpenCyto.css | 208 ++- src/web/OpenCyto/ExtJS4OpenCyto.js | 72 +- src/web/OpenCyto/ux/BoxSelect/BoxSelect.css | 82 + src/web/OpenCyto/ux/BoxSelect/BoxSelect.js | 1662 +++++++++++++++++ src/web/OpenCyto/ux/CheckCombo/CheckCombo.css | 15 + src/web/OpenCyto/ux/CheckCombo/CheckCombo.js | 240 +++ .../OpenCyto/ux/ClearButton/ClearButton.css | 48 + .../OpenCyto/ux/ClearButton/ClearButton.js | 415 ++++ .../ux/ClearButton/ClearButtonDemoPanel.js | 66 + .../ux/ClearButton/clear-text-icon.gif | Bin 0 -> 936 bytes src/web/OpenCyto/ux/ColumnAutoWidthPlugin.js | 190 ++ .../ux/ComboFieldBox/ComboFieldBox.css | 104 ++ .../ux/ComboFieldBox/ComboFieldBox.js | 370 ++++ .../OpenCyto/ux/ComboFieldBox/ComboView.js | 135 ++ src/web/OpenCyto/ux/SelectedCount.css | 20 + src/web/OpenCyto/ux/SelectedCount.js | 68 + .../OpenCyto/ux/images/clear-text-icon.gif | Bin 0 -> 936 bytes src/web/OpenCyto/white_85_trans.png | Bin 0 -> 781 bytes 30 files changed, 5085 insertions(+), 383 deletions(-) create mode 100644 src/views/ComboTest.webpart.xml create mode 100644 src/views/HybridComboTest.html create mode 100644 src/views/HybridComboTest.view.xml create mode 100644 src/views/HybridComboTest.webpart.xml create mode 100644 src/views/comboTest.view.xml create mode 100644 src/web/ComboTest.js create mode 100644 src/web/HybridComboTest.js create mode 100644 src/web/OpenCyto/ux/BoxSelect/BoxSelect.css create mode 100644 src/web/OpenCyto/ux/BoxSelect/BoxSelect.js create mode 100644 src/web/OpenCyto/ux/CheckCombo/CheckCombo.css create mode 100644 src/web/OpenCyto/ux/CheckCombo/CheckCombo.js create mode 100644 src/web/OpenCyto/ux/ClearButton/ClearButton.css create mode 100644 src/web/OpenCyto/ux/ClearButton/ClearButton.js create mode 100644 src/web/OpenCyto/ux/ClearButton/ClearButtonDemoPanel.js create mode 100644 src/web/OpenCyto/ux/ClearButton/clear-text-icon.gif create mode 100644 src/web/OpenCyto/ux/ColumnAutoWidthPlugin.js create mode 100644 src/web/OpenCyto/ux/ComboFieldBox/ComboFieldBox.css create mode 100644 src/web/OpenCyto/ux/ComboFieldBox/ComboFieldBox.js create mode 100644 src/web/OpenCyto/ux/ComboFieldBox/ComboView.js create mode 100644 src/web/OpenCyto/ux/SelectedCount.css create mode 100644 src/web/OpenCyto/ux/SelectedCount.js create mode 100644 src/web/OpenCyto/ux/images/clear-text-icon.gif create mode 100644 src/web/OpenCyto/white_85_trans.png diff --git a/src/views/ComboTest.webpart.xml b/src/views/ComboTest.webpart.xml new file mode 100644 index 0000000..f253c42 --- /dev/null +++ b/src/views/ComboTest.webpart.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/HybridComboTest.html b/src/views/HybridComboTest.html new file mode 100644 index 0000000..cb1ab9a --- /dev/null +++ b/src/views/HybridComboTest.html @@ -0,0 +1,7 @@ +
    + + diff --git a/src/views/HybridComboTest.view.xml b/src/views/HybridComboTest.view.xml new file mode 100644 index 0000000..95dbb01 --- /dev/null +++ b/src/views/HybridComboTest.view.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/HybridComboTest.webpart.xml b/src/views/HybridComboTest.webpart.xml new file mode 100644 index 0000000..d781369 --- /dev/null +++ b/src/views/HybridComboTest.webpart.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/views/comboTest.html b/src/views/comboTest.html index f99cbd6..4762c86 100644 --- a/src/views/comboTest.html +++ b/src/views/comboTest.html @@ -1,53 +1,23 @@ -
    - - - + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    \ No newline at end of file + Ext4.onReady(init); + + diff --git a/src/views/comboTest.view.xml b/src/views/comboTest.view.xml new file mode 100644 index 0000000..c968f5b --- /dev/null +++ b/src/views/comboTest.view.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/views/extjs4begin.html b/src/views/extjs4begin.html index 5137e48..c3fc5e8 100644 --- a/src/views/extjs4begin.html +++ b/src/views/extjs4begin.html @@ -5,8 +5,6 @@ - -