/* * Copyright 2017 Anyware Services * * 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. */ // ------------------------------ // Here are ExtJS bug fixes // ------------------------------ (function() { Ext.override(Ext.layout.ContextItem, { // Fix CMS-5908 http://www.sencha.com/forum/showthread.php?291412-Error-after-upgrade-to-ExtJS-4.2.3 init: function (full, options) { var me = this; var protection = false; if (me.ownerLayout && !target.ownerLayout.isItemBoxParent) { target.ownerLayout.isItemBoxParent = function() { return false; }; protection = true; } var returnValue = this.callParent(arguments); if (protection) { delete target.ownerLayout.isItemBoxParent; } return returnValue; } }); Ext.override(Ext.menu.Menu, { initComponent: function() { this.callParent(arguments); this.on('resize', this._onResize, this); }, // Fix for CMS-5997 http://www.sencha.com/forum/showthread.php?297558-ExtJs-4.2.3-Adding-items-to-an-opened-menu-on-a-floating-parent&p=1086597#post1086597 _onResize: function(menu, width, height, oldWidth, oldHeight, eOpts) { if (this.isVisible() /*&& oldHeight != null && oldWidth != null */&& this.floatParent && !this._doingShowBy) { this._doingShowBy = true; // let's avoid infinite showBy -> needResize -> showBy -> ... this.showBy(this.ownerCmp, this.ownerCmp.menuAlign); this._doingShowBy = false; } } }); Ext.override(Ext.view.DropZone, { // Fix for CMS-6262 https://www.sencha.com/forum/showthread.php?301552-ExtJS-4.2.3-Drag-n-drop-in-a-grid-and-invalid-zone.&p=1101961#post1101961 containsRecordAtOffset: function(records, record, offset) { if (!record) { return false; } var view = this.view, recordIndex = view.indexOf(record), nodeBefore = view.getNode(recordIndex + offset, true), recordBefore = nodeBefore ? view.getRecord(nodeBefore) : null; var containsRecordAtOffset = recordBefore && Ext.Array.contains(records, recordBefore); if (!containsRecordAtOffset) { return false; } else if (record.store.getGroupField() != null && Ext.Array.findBy(this.view.features, function(item) { return item.ftype == "grouping" }) != null) { // using groups, we need to ignore items from different groups var groups = []; for (var i = 0; i < records.length; i++) { groups.push(records[i].get(record.store.getGroupField())); } var targetGroup = record.get(record.store.getGroupField()); return Ext.Array.contains(groups, targetGroup); } else { return true; } } }); // Fix for CMS-6366 https://www.sencha.com/forum/showthread.php?304867-D-n-D-over-an-IFrame-issue if (Ext.ux && Ext.ux.IFrame) { Ext.override(Ext.dd.DragDropManager, { /** * @private * @member Ext.dd.DragDropManager * @method _onAll * @ametys * @since Ametys Runtime 4.1 * Execute action on all that need to be protected * @param {Function} action The action to do * @param {Ext.Component} action.component The component to act on */ _onAll: function(action) { Ext.ComponentManager.each(function(key, component) { if (component.isXType('uxiframe') || component.isXType('richtextfield')) { action(component); } }); }, handleMouseDown: function(e, oDD) { this.callParent(arguments); // Find all iframes to "protect them" this._onAll(function (component) { component = component.bodyEl ? /* richtext or code, need to apply on underlying element, if not a UI issue will appear */ component.bodyEl : /* iframe */component; component.addCls("iframe-protected") component.mask(); }); }, handleMouseUp: function(e) { this.callParent(arguments); // Find all iframes to "unprotect them" this._onAll(function (component) { component = component.bodyEl ? /* richtext or code, need to apply on underlying element, if not a UI issue will appear */ component.bodyEl : /* iframe */component; component.removeCls("iframe-protected") component.unmask(); }); } }); Ext.override(Ext.ux.IFrame, { // Fix for RUNTIME-3116 // Loading url while iframe is not rendered yet load: function(src) { var me = this; if (me.rendered) { me.callParent(arguments); } else { // We will load when the rendering will be done var args = Array.from(arguments); me.on({'render': { fn: function() { me.load.call(me, args); }, scope: me, single: true }}); } } }); } Ext.override(Ext.data.Model, { privates: { statics: { // Fix for https://issues.ametys.org/browse/CMS-6363 // Actually, this enables to specify a convert or calculate function for an id field in a Ext.data.Model (which does not work, is it a bug ?) // See https://www.sencha.com/forum/showthread.php?292044-Ext.data.Field.convert%28%29-not-called-for-idField-if-only-calculated initFields: function (data, cls, proto) { var me = this, idField; me.callParent(arguments); idField = proto.idField; idField.defaultValue = (idField.convert) ? undefined : null; // defaultValue must be undefined instead of null if a convert function is specified } } }, inheritableStatics: { // Fix for https://issues.ametys.org/browse/CMS-8330 // When updating model and reconfiguring columns, the new columns sometimes did not have their value set (cache on fieldExtractors not cleared) replaceFields: function(newFields, removeFields) { var me = this; me.callParent(arguments); if (me.fieldExtractors) { delete me.fieldExtractors[me.getProxy().getReader().$className]; } } } }); Ext.override(Ext.form.field.Base, { // Fix for https://issues.ametys.org/browse/RUNTIME-1858 // See https://www.sencha.com/forum/showthread.php?311209-Autocomplete-with-Chrome&p=1136279#post1136279 getSubTplMarkup: function(fieldData) { var value = this.callParent(arguments); if (Ext.isChrome && fieldData.$comp && fieldData.$comp.inputType == 'password') { value = value.replace('autocomplete="off"', 'autocomplete="new-password"'); } return value; } }); Ext.override(Ext.form.field.Date, { // Fix for https://issues.ametys.org/browse/RUNTIME-2658 formatText: null }); Ext.override(Ext.form.field.Time, { // Fix for https://issues.ametys.org/browse/RUNTIME-2658 formatText: null }); Ext.override(Ext.form.field.ComboBox, { // Fix for https://issues.ametys.org/browse/CMS-5934 // https://www.sencha.com/forum/showthread.php?339854-ExtJS-6-2-Filtering-a-combox-tagfield-and-backspace&p=1179339#post1179339 // Also fix for https://issues.ametys.org/browse/CMS-8760 [Widget] Typing a comma in the select-referencetable-content widget // as we still want to search the entire user input if it contains the delimiter /** * @private * @member Ext.form.field.ComboBox * @property {String} _lastRawValue The last raw input value * @since Ametys Runtime 4.0 * @ametys */ _lastRawValue: null, doRawQuery: function() { var me = this, rawValue = me.inputEl.dom.value; // Use final bit after comma as query value if multiselecting (Ametys edit: no !!) // if (me.multiSelect) { // rawValue = rawValue.split(me.delimiter).pop(); // } // Here is the fix if (Ext.isString(me._lastRawValue) && Ext.isString(rawValue) && rawValue.length < me.minChars && me.minChars <= me._lastRawValue.length) { // last value is longer than current, so the user removed some characters in the query (by pressing BACKSPACE for instance...) // and current value is shorter than the threshold (me.minChars) // and last value is equal or greater than the threshold // So force to query in order to always have the same results with the same inputs me.doQuery("", true, true); } else { me.doQuery(rawValue, false, true); } me._lastRawValue = rawValue; } }); // Fix for RUNTIME-2575 https://www.sencha.com/forum/showthread.php?454691-In-Ext-data-Store-the-remove-method-is-not-ok-with-doc Ext.override(Ext.data.Store, { remove: function(records, isMove, silent) { if (Ext.isNumber(records)) { records = [records]; } return this.callParent(arguments); } }); // Fix for CTREE-19 https://www.sencha.com/forum/showthread.php?366515-Untranslated-labels-in-ExtJS-6-5-1&p=1210058#post1210058 Ext.override(Ext.tree.plugin.TreeViewDragDrop, { dragText: "{{i18n PLUGINS_CORE_UI_TREEDRAGNDROP_LABEL}}" }); // Fix for RUNTIME-1640 https://www.sencha.com/forum/showthread.php?366515-Untranslated-labels-in-ExtJS-6-5-1&p=1210058#post1210058 Ext.override(Ext.panel.Panel, { collapseToolText: "{{i18n PLUGINS_CORE_UI_PANEL_COLLAPSE}}", expandToolText: "{{i18n PLUGINS_CORE_UI_PANEL_EXPAND}}" }); // Fix for CMS-8635 Ext.override(Ext.tree.Panel, { ensureVisible: function() { if (this.getView().getNodeContainer()) { this.callParent(arguments); } else { this.getLogger().warn("Avoid a UI crash by discarding Ext.tree.Panel#ensureVisible on a semi rendered tree view"); } } }); // Fix for CMS-8958 Ext.override(Ext.view.BoundList, { onEndUpdate: function() { var me = this; if (me.updateSuspendCounter) { --me.updateSuspendCounter; Ext.resumeLayouts(true); // The fix is putting this line inside the if instead of after } else { this.getLogger().warn("resuming an unsuspended layout"); } if (me.refreshSizePending) { me.refreshSize(true); me.refreshSizePending = false; } } }); // Fix for FRONTEDIT-100 (already fixed in extjs 6.5.3) Ext.override(Ext.util.Positionable, { getAlignToRegion: function(alignToEl, posSpec, offset, minHeight) { var me = this, inside, newRegion; alignToEl = Ext.fly(alignToEl.el || alignToEl); if (!alignToEl || !alignToEl.dom) { //<debug> Ext.raise({ sourceClass: 'Ext.util.Positionable', sourceMethod: 'getAlignToXY', msg: 'Attempted to align an element that doesn\'t exist' }); //</debug> } posSpec = me.convertPositionSpec(posSpec); // If position spec ended with a "?" or "!", then constraining is necessary if (posSpec.constrain) { // Constrain to the correct enclosing object: // If the assertive form was used (like "tl-bl!"), constrain to the alignToEl. if (posSpec.constrain === '!') { inside = alignToEl; } else { // Otherwise, attempt to use the constrainTo property. // Otherwise, if we are a Component, there will be a container property. // Otherwise, use this Positionable's element's parent node. inside = me.constrainTo || me.container || me.el.parent(); } inside = Ext.fly(inside.el || inside).getConstrainRegion(); } // Back from extjs 6.5.3 if (alignToEl === Ext.getBody()) { bodyScroll = alignToEl.getScroll(); offset = [bodyScroll.left, bodyScroll.top]; } newRegion = me.getRegion().alignTo({ target: alignToEl.getRegion(), inside: inside, minHeight: minHeight, offset: offset, align: posSpec, axisLock: true }); return newRegion; } }); Ext.override(Ext.window.Window, { getAlignToRegion: function(alignToEl, posSpec, offset, minHeight) { var me = this, inside, newRegion; alignToEl = Ext.fly(alignToEl.el || alignToEl); if (!alignToEl || !alignToEl.dom) { //<debug> Ext.raise({ sourceClass: 'Ext.util.Positionable', sourceMethod: 'getAlignToXY', msg: 'Attempted to align an element that doesn\'t exist' }); //</debug> } posSpec = me.convertPositionSpec(posSpec); // If position spec ended with a "?" or "!", then constraining is necessary if (posSpec.constrain) { // Constrain to the correct enclosing object: // If the assertive form was used (like "tl-bl!"), constrain to the alignToEl. if (posSpec.constrain === '!') { inside = alignToEl; } else { // Otherwise, attempt to use the constrainTo property. // Otherwise, if we are a Component, there will be a container property. // Otherwise, use this Positionable's element's parent node. inside = me.constrainTo || me.container || me.el.parent(); } inside = Ext.fly(inside.el || inside).getConstrainRegion(); } // Back from extjs 6.5.3 if (alignToEl === Ext.getBody()) { bodyScroll = alignToEl.getScroll(); offset = [bodyScroll.left, bodyScroll.top]; } newRegion = me.getRegion().alignTo({ target: alignToEl.getRegion(), inside: inside, minHeight: minHeight, offset: offset, align: posSpec, axisLock: true }); return newRegion; } }); // Fix for RUNTIME-3119 Ext.override(Ext.Component, { mask: function() { if (this.rendered) { this.callParent(arguments); } else { this._shouldBeMasked = Ext.Array.from(arguments); } }, unmask: function() { if (this.rendered) { this.callParent(arguments); } else { this._shouldBeMasked = null; } }, afterRender: function() { this.callParent(arguments); if (this._shouldBeMasked) { this.mask.call(this, this._shouldBeMasked); } }, destroy: function() { this._shouldBeMasked = null; this.callParent(arguments); } }); /** * @member Ext.app.ViewController * @method afterRender * After render */ /** * @member Ext.util.Floating * @event tofront * When bring to front */ /** * @member Ext.data.proxy.Server * @event beginprocessresponse * When starting to process answer * @param {Object} response The response * @param {Object} operation The running operation */ /** * @member Ext.data.proxy.Server * @event endprocessresponse * When starting to process answer * @param {Object} response The response * @param {Object} operation The running operation */ /** * @member Ext.panel.Table * @event viewcreated * When a table view was created * @param {Ext.panel.Table} panel The view owner * @param {Ext.view.Table} view The view */ /** * @member Ext.panel.Panel * @event beginfloat * When a collasped panel is starting to float * @param {Ext.panel.Panel} panel The panel */ /** * @member Ext.panel.Panel * @event endfloat * When a collasped panel is stopping to float * @param {Ext.panel.Panel} panel The panel */ })();