Ext.define('Netzke.Grid.EventHandlers', { override: 'Netzke.Grid.EventHandlers', netzkeHandleItemdblclick: function(view, record) { if (this.editsInline) return; // inline editing is handled elsewhere // MONKEY: add view in form capability var has_perm = (this.permissions || {}); if (has_perm.read !== false && !has_perm.update) { this.doViewInForm(record); } else if (has_perm.update !== false) { this.doEditInForm(record); } }, netzkeReloadStore: function(opts={}) { var store = this.getStore(); // MONKEY: add beforenetzkereload and netzkerevent on store store.fireEvent('beforenetzkereload'); var callback = opts.callback; opts.callback = function() { if (callback) { callback() } store.fireEvent('netzkereload'); } // NETZKE'S HACK to work around buffered store's buggy reload() if (!store.lastRequestStart) { store.load(opts); } else store.reload(opts); }, }); Ext.define('Ext.toolbar.Paging', { override: 'Ext.toolbar.Paging', handleRefresh: Ext.emptyFn, doRefresh: function() { var me = this, current = me.store.currentPage; // MONKEY: add netzkerefresh to ExtJS paging toolbar refresh // as beforechange is too generic me.store.fireEvent('netzkerefresh', me); if (me.fireEvent('beforechange', me, current) !== false) { me.store.loadPage(current); me.handleRefresh(); } } }); Ext.define('Netzke.Grid.Columns', { override: 'Netzke.Grid.Columns', netzkeNormalizeAssociationRenderer: function(c) { var passedRenderer = c.renderer, // renderer we got from netzkeNormalizeRenderer assocValue; c.scope = this; c.renderer = function(value, a, r, ri, ci, store, view){ var column = view.headerCt.items.getAt(ci), editor = column.getEditor && column.getEditor(), /* MONKEY: use findRecordByValue instead of findRecord to remedy inline editing temporarily changing N/A columns to the recently changed value. */ recordFromStore = editor && editor.isXType('combobox') && editor.findRecordByValue(value), renderedValue; if (recordFromStore) { renderedValue = recordFromStore.get('text'); } else if ((assocValue = (r.get('association_values') || {})[c.name]) !== undefined) { renderedValue = (assocValue == undefined) ? c.emptyText : assocValue; } else { renderedValue = value; } return passedRenderer ? passedRenderer.call(this, renderedValue) : renderedValue; }; }, }); /* This is a modified version of the ExtJS Codemirror component from http://www.mzsolutions.eu/Extjs-CodeMirror-component.html. It's been modified to remove the toolbar and also it uses delorean mode by default. */ /** * @private * @class Ext.ux.layout.component.field.CodeMirror * @extends Ext.layout.component.field.Field * @author Adrian Teodorescu (ateodorescu@gmail.com) * * Layout class for {@link Ext.ux.form.field.CodeMirror} fields. Handles sizing the codemirror field. */ Ext.define('Ext.ux.layout.component.field.CodeMirror', { extend: 'Ext.layout.component.Auto', alias: ['layout.codemirror'], type: 'codemirror', beginLayout: function(ownerContext) { this.callParent(arguments); ownerContext.textAreaContext = ownerContext.getEl('textareaEl'); ownerContext.editorContext = ownerContext.getEl('editorEl'); }, renderItems: Ext.emptyFn, getRenderTarget: function() { return this.owner.bodyEl; }, publishInnerHeight: function (ownerContext, height) { var me = this, innerHeight = height - me.measureLabelErrorHeight(ownerContext) - ownerContext.bodyCellContext.getPaddingInfo().height; if (Ext.isNumber(innerHeight)) { ownerContext.textAreaContext.setHeight(innerHeight); ownerContext.editorContext.setHeight(innerHeight); } else { me.done = false; } }, publishInnerWidth: function (ownerContext, width) { var me = this; if (Ext.isNumber(width)) { ownerContext.textAreaContext.setWidth(width); ownerContext.editorContext.setWidth(width); } else { me.done = false; } } }); Ext.define('Ext.ux.form.field.CodeMirror', { extend: 'Ext.Component', mixins: { labelable: 'Ext.form.Labelable', field: 'Ext.form.field.Field' }, alias: 'widget.codemirror', alternateClassName: 'Ext.form.CodeMirror', requires: [ 'Ext.tip.QuickTipManager', 'Ext.util.Format', 'Ext.ux.layout.component.field.CodeMirror' ], childEls: [ 'editorEl', 'textareaEl' ], fieldSubTpl: [ '', '
', { disableFormats: true } ], // FIXME: the layout mechanism is currently busted // componentLayout: 'codemirror', editorWrapCls: Ext.baseCSSPrefix + 'html-editor-wrap', maskOnDisable: true, afterBodyEl: '', /* // map tabs to 4 spaces -- arman (doesn't work - may need new version) extraKeys: { "Tab": function() { editor.replaceSelection(" " , "end"); } }, */ /** * @cfg {String} mode The default mode to use when the editor is initialized. When not given, this will default to the first mode that was loaded. * It may be a string, which either simply names the mode or is a MIME type associated with the mode. Alternatively, * it may be an object containing configuration options for the mode, with a name property that names the mode * (for example {name: "javascript", json: true}). The demo pages for each mode contain information about what * configuration parameters the mode supports. */ mode: 'text/plain', /** * @cfg {Boolean} showAutoIndent Enable auto indent button for indenting the selected range */ showAutoIndent: true, /** * @cfg {Boolean} showLineNumbers Enable line numbers button in the toolbar. */ showLineNumbers: true, /** * @cfg {Boolean} enableMatchBrackets Force matching-bracket-highlighting to happen */ enableMatchBrackets: true, /** * @cfg {Boolean} enableElectricChars Configures whether the editor should re-indent the current line when a character is typed * that might change its proper indentation (only works if the mode supports indentation). */ enableElectricChars: false, /** * @cfg {Boolean} enableIndentWithTabs Whether, when indenting, the first N*tabSize spaces should be replaced by N tabs. */ enableIndentWithTabs: true, /** * @cfg {Boolean} enableSmartIndent Whether to use the context-sensitive indentation that the mode provides (or just indent the same as the line before). */ enableSmartIndent: true, /** * @cfg {Boolean} enableLineWrapping Whether CodeMirror should scroll or wrap for long lines. */ enableLineWrapping: false, /** * @cfg {Boolean} enableLineNumbers Whether to show line numbers to the left of the editor. */ enableLineNumbers: true, /** * @cfg {Boolean} enableGutter Can be used to force a 'gutter' (empty space on the left of the editor) to be shown even * when no line numbers are active. This is useful for setting markers. */ enableGutter: true, /** * @cfg {Boolean} enableFixedGutter When enabled (off by default), this will make the gutter stay visible when the * document is scrolled horizontally. */ enableFixedGutter: false, /** * @cfg {Number} firstLineNumber At which number to start counting lines. */ firstLineNumber: 1, /** * @cfg {Boolean} readOnly true to mark the field as readOnly. */ readOnly : false, /** * @cfg {Number} pollInterval Indicates how quickly (miliseconds) CodeMirror should poll its input textarea for changes. * Most input is captured by events, but some things, like IME input on some browsers, doesn't generate events * that allow CodeMirror to properly detect it. Thus, it polls. */ pollInterval: 100, /** * @cfg {Number} indentUnit How many spaces a block (whatever that means in the edited language) should be indented. */ indentUnit: 4, /** * @cfg {Number} tabSize The width of a tab character. */ tabSize: 4, /** * @cfg {String} theme The theme to style the editor with. You must make sure the CSS file defining the corresponding * .cm-s-[name] styles is loaded (see the theme directory in the distribution). The default is "default", for which * colors are included in codemirror.css. It is possible to use multiple theming classes at onceā€”for example * "foo bar" will assign both the cm-s-foo and the cm-s-bar classes to the editor. */ theme: 'default', /** * @property {String} pathModes Path to the modes folder to dinamically load the required scripts. You could also * include all your required modes in a big script file and this path will be ignored. * Do not fill in the trailing slash. */ pathModes: 'mode', /** * @property {String} pathExtensions Path to the extensions folder to dinamically load the required scripts. You could also * include all your required extensions in a big script file and this path will be ignored. * Do not fill in the trailing slash. */ pathExtensions: 'lib/util', /** * @property {Array} extensions Define here extensions script dependencies; This is used by toolbar buttons to automatically * load the scripts before using an extension. */ extensions:{ format: { dependencies: ['formatting.js'] } }, scriptsLoaded: [], lastMode: '', initComponent : function(){ var me = this; me.callParent(arguments); me.initLabelable(); me.initField(); /* Fix resize issues as suggested by user koblass on the Extjs forums http://www.sencha.com/forum/showthread.php?167047-Ext.ux.form.field.CodeMirror-for-Ext-4.x&p=860535&viewfull=1#post860535 */ me.on('resize', function() { if (me.editor) { me.editor.refresh(); } }, me); }, getMaskTarget: function(){ return this.bodyEl; }, /** * @private override */ getSubTplData: function() { var cssPrefix = Ext.baseCSSPrefix; return { $comp : this, cmpId : this.id, id : this.getInputId(), toolbarWrapCls : cssPrefix + 'html-editor-tb', textareaCls : cssPrefix + 'hidden', editorCls : cssPrefix + 'codemirror', editorName : Ext.id(), //size : 'height:100px;width:100%' // PennyMac: setting height to 100%. size : 'height:100%;width:100%', }; }, getSubTplMarkup: function() { return this.getTpl('fieldSubTpl').apply(this.getSubTplData()); }, /** * @private override */ onRender: function() { var me = this; me.callParent(arguments); me.editorEl = me.getEl('editorEl'); me.bodyEl = me.getEl('bodyEl'); me.disableItems(true); me.initEditor(); me.rendered = true; }, initRenderData: function() { this.beforeSubTpl = '
'; return Ext.applyIf(this.callParent(), this.getLabelableRenderData()); }, /** * @private override */ initEditor : function(){ var me = this; var mode = me.mode; // if no mode is loaded we could get an error like "Object # has no method 'startState'" // search mime to find script dependencies var item = me.getMime(me.mode); if(item) { mode = me.getMimeMode(me.mode); if(!mode){ mode = "text/x-delorean"; } } me.editor = CodeMirror(me.editorEl, { matchBrackets: me.enableMatchBrackets, electricChars: me.enableElectricChars, autoClearEmptyLines:true, value: me.rawValue || "", indentUnit: me.indentUnit, smartIndent: me.enableSmartIndent, indentWithTabs: me.indentWithTabs, pollInterval: me.pollInterval, lineNumbers: me.enableLineNumbers, lineWrapping: me.enableLineWrapping, firstLineNumber: me.firstLineNumber, tabSize: me.tabSize, gutter: me.enableGutter, fixedGutter: me.enableFixedGutter, theme: me.theme, mode: mode, onChange: function(editor, tc){ me.checkChange(); //me.fireEvent('change', me, tc.from, tc.to, tc.text, tc.next || null); }, onCursorActivity: function(editor){ me.fireEvent('cursoractivity', me); }, onGutterClick: function(editor, line, event){ me.fireEvent('gutterclick', me, line, event); }, onFocus: function(editor){ me.fireEvent('activate', me); }, onBlur: function(editor){ me.fireEvent('deactivate', me); }, onScroll: function(editor){ me.fireEvent('scroll', me); }, onHighlightComplete: function(editor){ me.fireEvent('highlightcomplete', me); }, onUpdate: function(editor){ me.fireEvent('update', me); }, onKeyEvent: function(editor, event){ event.cancelBubble = true; // fix suggested by koblass user on Sencha forums (http://www.sencha.com/forum/showthread.php?167047-Ext.ux.form.field.CodeMirror-for-Ext-4.x&p=862029&viewfull=1#post862029) me.fireEvent('keyevent', me, event); } }); //me.editor.setValue(me.rawValue); me.setMode(me.mode); me.setReadOnly(me.readOnly); me.fireEvent('initialize', me); // change the codemirror css var css = Ext.util.CSS.getRule('.CodeMirror'); if(css){ css.style.height = '100%'; css.style.position = 'relative'; css.style.overflow = 'hidden'; } var css = Ext.util.CSS.getRule('.CodeMirror-Scroll'); if(css){ css.style.height = '100%'; } // PennyMac: align the body to the top. Otherwise it ends up // in the center of the enclosing table. var el = document.getElementById(me.bodyEl.id); el.setAttribute("valign", "top"); }, /** * @private */ relayBtnCmd: function(btn){ this.relayCmd(btn.getItemId()); }, /** * @private */ relayCmd: function(cmd){ Ext.defer(function() { var me = this; me.editor.focus(); switch(cmd){ // auto formatting case 'justifycenter': if(!CodeMirror.extensions.autoIndentRange){ me.loadDependencies(me.extensions.format, me.pathExtensions, me.doIndentSelection, me); }else{ me.doIndentSelection(); } break; // line numbers case 'insertorderedlist': me.doChangeLineNumbers(); break; } }, 10, this); }, /** * @private * Reload all CodeMirror extensions for the current instance; * */ reloadExtentions: function(){ var me = this; for (var ext in CodeMirror.extensions) if (CodeMirror.extensions.propertyIsEnumerable(ext) && !me.editor.propertyIsEnumerable(ext)) me.editor[ext] = CodeMirror.extensions[ext]; }, doChangeLineNumbers: function(){ var me = this; me.enableLineNumbers = !me.enableLineNumbers; me.editor.setOption('lineNumbers', me.enableLineNumbers); }, /** * @private */ doIndentSelection: function(){ var me = this; me.reloadExtentions(); try{ var range = { from: me.editor.getCursor(true), to: me.editor.getCursor(false) }; me.editor.autoIndentRange(range.from, range.to); }catch(err){} }, modes: [ { mime: CodeMirror.mimeModes, dependencies: [] }, ], /** * @private */ getMime: function(mime){ var me = this, item, found = false; for(var i=0;i