]> git.proxmox.com Git - pve-manager.git/blobdiff - www/manager6/Toolkit.js
dc/OptionView: cleanup & use new features from ObjectGrid
[pve-manager.git] / www / manager6 / Toolkit.js
index e23985e8e866622a727953dc8a543f52b8f53ca6..c7f9a0c45d231ea34f318d5ab14e996bc046cfbb 100644 (file)
@@ -1,6 +1,6 @@
 // ExtJS related things
 
-PVE.Utils.toolkit = 'extjs';
+Proxmox.Utils.toolkit = 'extjs';
 
  // do not send '_dc' parameter
 Ext.Ajax.disableCaching = false;
@@ -8,13 +8,13 @@ Ext.Ajax.disableCaching = false;
 // custom Vtypes
 Ext.apply(Ext.form.field.VTypes, {
     IPAddress:  function(v) {
-       return PVE.Utils.IP4_match.test(v);
+       return Proxmox.Utils.IP4_match.test(v);
     },
     IPAddressText:  gettext('Example') + ': 192.168.1.1',
     IPAddressMask: /[\d\.]/i,
 
     IPCIDRAddress:  function(v) {
-       var result = PVE.Utils.IP4_cidr_match.exec(v);
+       var result = Proxmox.Utils.IP4_cidr_match.exec(v);
        // limits according to JSON Schema see
        // pve-common/src/PVE/JSONSchema.pm
        return (result !== null && result[1] >= 8 && result[1] <= 32);
@@ -23,13 +23,13 @@ Ext.apply(Ext.form.field.VTypes, {
     IPCIDRAddressMask: /[\d\.\/]/i,
 
     IP6Address:  function(v) {
-        return PVE.Utils.IP6_match.test(v);
+        return Proxmox.Utils.IP6_match.test(v);
     },
     IP6AddressText:  gettext('Example') + ': 2001:DB8::42',
     IP6AddressMask: /[A-Fa-f0-9:]/,
 
     IP6CIDRAddress:  function(v) {
-       var result = PVE.Utils.IP6_cidr_match.exec(v);
+       var result = Proxmox.Utils.IP6_cidr_match.exec(v);
        // limits according to JSON Schema see
        // pve-common/src/PVE/JSONSchema.pm
        return (result !== null && result[1] >= 8 && result[1] <= 120);
@@ -44,7 +44,7 @@ Ext.apply(Ext.form.field.VTypes, {
     IP6PrefixLengthMask:  /[0-9]/,
 
     IP64Address:  function(v) {
-        return PVE.Utils.IP64_match.test(v);
+        return Proxmox.Utils.IP64_match.test(v);
     },
     IP64AddressText:  gettext('Example') + ': 192.168.1.1 2001:DB8::42',
     IP64AddressMask: /[A-Fa-f0-9\.:]/,
@@ -55,6 +55,12 @@ Ext.apply(Ext.form.field.VTypes, {
     MacAddressMask: /[a-fA-F0-9:]/,
     MacAddressText: gettext('Example') + ': 01:23:45:67:89:ab',
 
+    MacPrefix:  function(v) {
+       return (/^[a-f0-9]{2}(?::[a-f0-9]{2}){0,2}:?$/i).test(v);
+    },
+    MacPrefixMask: /[a-fA-F0-9:]/,
+    MacPrefixText: gettext('Example') + ': 02:8f',
+
     BridgeName: function(v) {
         return (/^vmbr\d{1,4}$/).test(v);
     },
@@ -99,7 +105,7 @@ Ext.apply(Ext.form.field.VTypes, {
     HttpProxyText: gettext('Example') + ": http://username:password&#64;host:port/",
 
     DnsName: function(v) {
-       return PVE.Utils.DnsName_match.test(v);
+       return Proxmox.Utils.DnsName_match.test(v);
     },
     DnsNameText: gettext('This is not a valid DNS name'),
 
@@ -117,9 +123,9 @@ Ext.apply(Ext.form.field.VTypes, {
                continue;
            }
 
-           if (!PVE.Utils.HostPort_match.test(list[i]) &&
-               !PVE.Utils.HostPortBrackets_match.test(list[i]) &&
-               !PVE.Utils.IP6_dotnotation_match.test(list[i])) {
+           if (!Proxmox.Utils.HostPort_match.test(list[i]) &&
+               !Proxmox.Utils.HostPortBrackets_match.test(list[i]) &&
+               !Proxmox.Utils.IP6_dotnotation_match.test(list[i])) {
                return false;
            }
        }
@@ -129,6 +135,13 @@ Ext.apply(Ext.form.field.VTypes, {
     HostListText: gettext('Not a valid list of hosts')
 });
 
+// since we always want the number in
+// x.y format and never in e.g. x,y
+Ext.define('PVE.form.field.Number', {
+    override: 'Ext.form.field.Number',
+    submitLocaleSeparator: false
+});
+
 // ExtJs 5-6 has an issue with caching
 // see https://www.sencha.com/forum/showthread.php?308989
 Ext.define('PVE.UnderlayPool', {
@@ -162,6 +175,20 @@ Ext.define('PVE.UnderlayPool', {
     }
 });
 
+// 'Enter' in Textareas and aria multiline fields should not activate the
+// defaultbutton, fixed in extjs 6.0.2
+Ext.define('PVE.panel.Panel', {
+    override: 'Ext.panel.Panel',
+
+    fireDefaultButton: function(e) {
+       if (e.target.getAttribute('aria-multiline') === 'true' ||
+           e.target.tagName === "TEXTAREA") {
+           return true;
+       }
+       return this.callParent(arguments);
+    }
+});
+
 // if the order of the values are not the same in originalValue and value
 // extjs will not overwrite value, but marks the field dirty and thus
 // the reset button will be enabled (but clicking it changes nothing)
@@ -174,7 +201,6 @@ Ext.define('PVE.form.ComboBox', {
        // copied from combobox
        var me = this;
        me.callParent();
-       me.applyEmptyText();
 
        // clear and set when not the same
        var value = me.getValue();
@@ -185,6 +211,80 @@ Ext.define('PVE.form.ComboBox', {
     }
 });
 
+// when refreshing the view of a grid/tree
+// the restoring of the focus brings the
+// focused item back in the view, even when we scrolled away
+Ext.define(null, {
+    override: 'Ext.view.Table',
+
+    jumpToFocus: false,
+
+    saveFocusState: function() {
+        var me = this,
+            store = me.dataSource,
+            actionableMode = me.actionableMode,
+            navModel = me.getNavigationModel(),
+            focusPosition = actionableMode ? me.actionPosition : navModel.getPosition(true),
+            refocusRow, refocusCol;
+
+        if (focusPosition) {
+            // Separate this from the instance that the nav model is using.
+            focusPosition = focusPosition.clone();
+
+            // Exit actionable mode.
+            // We must inform any Actionables that they must relinquish control.
+            // Tabbability must be reset.
+            if (actionableMode) {
+                me.ownerGrid.setActionableMode(false);
+            }
+
+            // Blur the focused descendant, but do not trigger focusLeave.
+            me.el.dom.focus();
+
+            // Exiting actionable mode navigates to the owning cell, so in either focus mode we must
+            // clear the navigation position
+            navModel.setPosition();
+
+            // The following function will attempt to refocus back in the same mode to the same cell
+            // as it was at before based upon the previous record (if it's still inthe store), or the row index.
+            return function() {
+                // If we still have data, attempt to refocus in the same mode.
+                if (store.getCount()) {
+
+                    // Adjust expectations of where we are able to refocus according to what kind of destruction
+                    // might have been wrought on this view's DOM during focus save.
+                    refocusRow = Math.min(focusPosition.rowIdx, me.all.getCount() - 1);
+                    refocusCol = Math.min(focusPosition.colIdx, me.getVisibleColumnManager().getColumns().length - 1);
+                    focusPosition = new Ext.grid.CellContext(me).setPosition(
+                            store.contains(focusPosition.record) ? focusPosition.record : refocusRow, refocusCol);
+
+                    if (actionableMode) {
+                        me.ownerGrid.setActionableMode(true, focusPosition);
+                    } else {
+                        me.cellFocused = true;
+
+                       // we sometimes want to scroll back to where we were
+                       var x = me.getScrollX();
+                       var y = me.getScrollY();
+
+                        // Pass "preventNavigation" as true so that that does not cause selection.
+                        navModel.setPosition(focusPosition, null, null, null, true);
+
+                       if (!me.jumpToFocus) {
+                           me.scrollTo(x,y);
+                       }
+                    }
+                }
+                // No rows - focus associated column header
+                else {
+                    focusPosition.column.focus();
+                }
+            };
+        }
+        return Ext.emptyFn;
+    }
+});
+
 // should be fixed with ExtJS 6.0.2, see:
 // https://www.sencha.com/forum/showthread.php?307244-Bug-with-datefield-in-window-with-scroll
 Ext.define('PVE.Datepicker', {
@@ -192,6 +292,33 @@ Ext.define('PVE.Datepicker', {
     hideMode: 'visibility'
 });
 
+// this should be fixed with ExtJS 6.0.2
+// this makes mousescrolling work in firefox in the overflowhandler
+// and does not change behaviour in any other browser
+Ext.define(null, {
+    override: 'Ext.layout.container.boxOverflow.Scroller',
+
+    createWheelListener: function() {
+       var me = this;
+       if (Ext.isFirefox) {
+           me.wheelListener = me.layout.innerCt.on('wheel', me.onMouseWheelFirefox, me, {destroyable: true});
+       } else {
+           me.wheelListener = me.layout.innerCt.on('mousewheel', me.onMouseWheel, me, {destroyable: true});
+       }
+    },
+
+    // special wheel handler for firefox
+    // nearly the same as the default onMouseWheel handler,
+    // but using deltaY instead of wheelDeltaY
+    // and no normalizing, because it is already normalized
+    onMouseWheelFirefox: function(e) {
+       e.stopEvent();
+       var delta = e.browserEvent.deltaY || 0;
+       this.scrollBy(delta * this.wheelIncrement, false);
+    }
+
+});
+
 // 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