},
DnsOrIpText: gettext('Not a valid DNS name or IP address.'),
+ HostPort: function(v) {
+ return Proxmox.Utils.HostPort_match.test(v) ||
+ Proxmox.Utils.HostPortBrackets_match.test(v) ||
+ Proxmox.Utils.IP6_dotnotation_match.test(v);
+ },
+ HostPortText: gettext('Host/IP address or optional port is invalid'),
+
HostList: function(v) {
let list = v.split(/[ ,;]+/);
let i;
},
passwordText: gettext('Passwords do not match'),
+
+ email: function(value) {
+ let emailre = /^[\w+~-]+(\.[\w+~-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)$/;
+ return emailre.test(value);
+ },
});
// Firefox 52+ Touchscreen bug
validIdRe: /^[a-z_][a-z0-9\-_@]*$/i,
});
+Ext.define('Proxmox.selection.CheckboxModel', {
+ override: 'Ext.selection.CheckboxModel',
+
+ // [P] use whole checkbox cell to multiselect, not only the checkbox
+ checkSelector: '.x-grid-cell-row-checker',
+
+ // TODO: remove all optimizations below to an override for parent 'Ext.selection.Model' ??
+
+ // [ P: optimized to remove all records at once as single remove is O(n^3) slow ]
+ // records can be an index, a record or an array of records
+ doDeselect: function(records, suppressEvent) {
+ var me = this,
+ selected = me.selected,
+ i = 0,
+ len, record,
+ commit;
+ if (me.locked || !me.store) {
+ return false;
+ }
+ if (typeof records === "number") {
+ // No matching record, jump out
+ record = me.store.getAt(records);
+ if (!record) {
+ return false;
+ }
+ records = [
+ record,
+ ];
+ } else if (!Ext.isArray(records)) {
+ records = [
+ records,
+ ];
+ }
+ // [P] a beforedeselection, triggered by me.onSelectChange below, can block removal by
+ // returning false, thus the original implementation removed only here in the commit fn,
+ // which has an abysmal performance O(n^3). As blocking removal is not the norm, go do the
+ // reverse, record blocked records and remove them from the to-be-removed array before
+ // applying it. A FF86 i9-9900K on 10k records goes from >40s to ~33ms for >90% deselection
+ let committed = false;
+ commit = function() {
+ committed = true;
+ if (record === me.selectionStart) {
+ me.selectionStart = null;
+ }
+ };
+ let removalBlocked = [];
+ len = records.length;
+ me.suspendChanges();
+ for (; i < len; i++) {
+ record = records[i];
+ if (me.isSelected(record)) {
+ committed = false;
+ me.onSelectChange(record, false, suppressEvent, commit);
+ if (!committed) {
+ removalBlocked.push(record);
+ }
+ if (me.destroyed) {
+ return false;
+ }
+ }
+ }
+ if (removalBlocked.length > 0) {
+ records.remove(removalBlocked);
+ }
+ selected.remove(records); // [P] FAST(er)
+ me.lastSelected = selected.last();
+ me.resumeChanges();
+ // fire selchange if there was a change and there is no suppressEvent flag
+ me.maybeFireSelectionChange(records.length > 0 && !suppressEvent);
+ return records.length;
+ },
+
+
+ doMultiSelect: function(records, keepExisting, suppressEvent) {
+ var me = this,
+ selected = me.selected,
+ change = false,
+ result, i, len, record, commit;
+
+ if (me.locked) {
+ return;
+ }
+
+ records = !Ext.isArray(records) ? [records] : records;
+ len = records.length;
+ if (!keepExisting && selected.getCount() > 0) {
+ result = me.deselectDuringSelect(records, suppressEvent);
+ if (me.destroyed) {
+ return;
+ }
+ if (result[0]) {
+ // We had a failure during selection, so jump out
+ // Fire selection change if we did deselect anything
+ me.maybeFireSelectionChange(result[1] > 0 && !suppressEvent);
+ return;
+ } else {
+ // Means something has been deselected, so we've had a change
+ change = result[1] > 0;
+ }
+ }
+
+ let gotBlocked, blockedRecords = [];
+ commit = function() {
+ if (!selected.getCount()) {
+ me.selectionStart = record;
+ }
+ gotBlocked = false;
+ change = true;
+ };
+
+ for (i = 0; i < len; i++) {
+ record = records[i];
+ if (me.isSelected(record)) {
+ continue;
+ }
+
+ gotBlocked = true;
+ me.onSelectChange(record, true, suppressEvent, commit);
+ if (me.destroyed) {
+ return;
+ }
+ if (gotBlocked) {
+ blockedRecords.push(record);
+ }
+ }
+ if (blockedRecords.length > 0) {
+ records.remove(blockedRecords);
+ }
+ selected.add(records);
+ me.lastSelected = record;
+
+ // fire selchange if there was a change and there is no suppressEvent flag
+ me.maybeFireSelectionChange(change && !suppressEvent);
+ },
+ deselectDuringSelect: function(toSelect, suppressEvent) {
+ var me = this,
+ selected = me.selected.getRange(),
+ changed = 0,
+ failed = false;
+ // Prevent selection change events from firing, will happen during select
+ me.suspendChanges();
+ me.deselectingDuringSelect = true;
+ let toDeselect = selected.filter(item => !Ext.Array.contains(toSelect, item));
+ if (toDeselect.length > 0) {
+ changed = me.doDeselect(toDeselect, suppressEvent);
+ if (!changed) {
+ failed = true;
+ }
+ if (me.destroyed) {
+ failed = true;
+ changed = 0;
+ }
+ }
+ me.deselectingDuringSelect = false;
+ me.resumeChanges();
+ return [
+ failed,
+ changed,
+ ];
+ },
+});
+
// force alert boxes to be rendered with an Error Icon
// since Ext.Msg is an object and not a prototype, we need to override it
// after the framework has been initiated
Ext.onReady(function() {
-/*jslint confusion: true */
Ext.override(Ext.Msg, {
alert: function(title, message, fn, scope) { // eslint-disable-line consistent-return
if (Ext.isString(title)) {
}
},
});
-/*jslint confusion: false */
});
Ext.define('Ext.ux.IFrame', {
extend: 'Ext.Component',
// the event reaches listeners on elements like the document body. The effected
// mechanisms that depend on this bubbling behavior are listed to the right
// of the event.
- /*jslint nomen: true*/
Ext.get(doc).on(
me._docListeners = {
mousedown: fn, // menu dismisal (MenuManager) and Window onMouseDown (toFront)
scope: me,
},
);
- /*jslint nomen: false*/
} catch (e) {
// cannot do this xss
}