📄 menu.js
字号:
// if items were specified as a tree or resultTree, skip over the root // (check for isc.Tree first to eliminate dependency) if (isc.Tree && isc.isA.Tree(this.data)) { // hang onto the Tree object since we set this.data to an Array of nodes this._treeData = this.data; // Hang onto the childrenProperty, so we can easily tell which menu should // have auto-generated submenus this.childrenProperty = this.data.childrenProperty; // if only one top-level item and it has children, we can merge it with its children // for usability. var topLevel = this.data.getChildren(), mergeSingleParent = this.mergeSingleParent && !isc.isA.ResultTree(this._treeData) && topLevel.length == 1 && this.data.hasChildren(topLevel[0]); if (mergeSingleParent) { var topLevelItem = topLevel[0]; // make a copy of the children array so we don't munge the data model this.data = this.data.getChildren(topLevelItem).duplicate(); // add a separator between the children and the original top-level item this.data.add({isSeparator:true}); // copy the top-level item, minus children var copiedItem = {}; isc.addProperties(copiedItem, topLevelItem); // clear out the 'children property' on the merged item, so we don't get another // submenu copiedItem[this.childrenProperty] = null; // append it to the new top-level list this.data.add(copiedItem); // otherwise just start with the top level of the tree } else { // this.data = topLevel this.data = null; } // submenus will be passed a treeParentNode - the node whose children this menu will // display. It's also possible to have a Menu show a portion of a Tree by passsing a // treeParentNode in as part of the constructor. }// alert(this.data); this.Super(this._$initWidget); // if the fields are not set, set with the class default items if (!this.fields) { // this flag can be used when creating submenus to detect the case where we have // explicitly specified fields that should be copied down to our children this._standardFields = true; this.fields = []; var submenusOnLeft = (this.submenuDirection == this._$left); if (submenusOnLeft && this.showSubmenus) this.fields.add(isc.Menu.SUBMENU_FIELD); if (this.showIcons) this.fields.add(isc.Menu.ICON_FIELD); this.fields.add(isc.Menu.TITLE_FIELD); if (this.showKeys) this.fields.add(isc.Menu.KEY_FIELD); if (!submenusOnLeft && this.showSubmenus) this.fields.add(isc.Menu.SUBMENU_FIELD); } else { this._standardFields= false; for (var i = 0; i < this.fields.length; i++) { var field = this.fields[i]; if (isc.isA.String(field)) { if (isc.Menu.standardFields[field] != null) { // Menu.standardFields is a mapping from the simple field name "title" etc // to the name of the constant containing the field definition this.fields[i] = isc.Menu[isc.Menu.standardFields[field]]; } else { this.logWarn("Menu field specified as :" + field + ". This is not a recognized standard field name"); this.fields.removeAt(i); i -= 1; } } } } // If you place an image without text into a table cell safari aligns it to the top of // the cell. Providing align=BOTTOM forces the image into the center of the cell. if (isc.Browser.isSafari) { isc.addProperties(this.submenuImage, { align: "BOTTOM"}); isc.addProperties(this.submenuDisabledImage, { align: "BOTTOM"}); } // set up key listening if necessary if (this.useKeys) this.setUpKeyListening(); // tree mode if (this._treeData) { if (!this.treeParentNode) this.treeParentNode = this._treeData.getRoot(); this.setTreeNode(this.treeParentNode); }},// Override setFields - if called with custom fields set the _standardFields flag to falsesetFields : function (fields, a,b,c,d) { if (fields && (fields != this.fields)) { this._standardFields = false; } return this.invokeSuper(isc.Menu, "setFields", fields, a,b,c,d);},// If we're loading our data up-front, this is notification that our data has been loaded.treeDataLoaded : function () { },setTreeNode : function (node) { var loadState = this._treeData.getLoadState(node); this._lastNode = node; // If the children array is already loaded ensure it's visible in the menu as items if (loadState == isc.Tree.LOADED) { this.treeDataArrived(node); // Otherwise, if we've never kicked off a fetch for the data (first time this menu shown) // do so now. } else if (loadState != isc.Tree.LOADING) { this._treeData.loadChildren(node, this.getID()+".treeDataArrived(node)"); this._loadingTreeNode = true; this.setData(null); // show loading message instead of current menu }},// called through from ResultTree whenever we get tree data from the server.treeDataArrived : function (node) { delete this._loadingTreeNode; if (node == this._lastNode) { this.setData(this._treeData.getChildren(node)); // Note: only show the submenu if we're still visible - the user may have made a // selection before the data came back. if (this.masterMenu && this.masterMenu.isVisible()) this.masterMenu.placeSubmenu(node, this); }},getEmptyMessage : function () { if (this._loadingTreeNode) return this.loadingDataMessage; return this.Super("getEmptyMessage", arguments); },isEmpty : function () { if (this._loadingTreeNode) return true; return this.Super("isEmpty", arguments); },// Ensure that the empty message shows up like a disabled menu item_setUpEmptyMessage : function () { isc.addProperties(this, { emptyMessageTableStyle : this.tableStyle, emptyMessageStyle : this.baseStyle + isc.GridRenderer.standardStyleSuffixes[4] });},//> @method menu._observeData() (A)// Override the _observeData method to set up the enableIf etc. functions// for the menu items.// @param data (object) new data to be observed//<_observeData : function (data, a,b,c,d) { // If we're working with a tree-menu, this.data will just be the array of children // which is not expected to change directly. // Therefore in this case observe this._treeData instead. var alreadyObserving; if (this._treeData) { // Note: For tree submenus, setData() is used to populate the menu with // data, in response to dataArrived(), or a change of parent node. // setData() falls through to _observeData(). Therefore we may already be observing // the tree-menu data - if so, avoid calling the method to observe the data again. alreadyObserving = this.isObserving(this._treeData, "dataChanged"); data = this._treeData; } if (!alreadyObserving) this.invokeSuper(isc.Menu, "_observeData", data, a,b,c,d); // initialize the enable/disable function if necessary if (this.autoSetDynamicItems) { this._makeDynamicItemsFunction(); }},//> @method menu._ignoreData() (A)// Override the _ignoreData method to clear the enableIf, etc. function.// @param data (object) old data to be ignored//<_ignoreData : function (data) { this.Super("_ignoreData", arguments); // initialize the enable/disable function if necessary if (this.autoSetDynamicItems) { // get rid of the setDynamicItems function delete this.setDynamicItems; }},// Event handling// --------------------------------------------------------------------------------------------//> @method menu.rowClick() (A)// Handle the rowClick pseudo-event in the menu. Selects the appropriate menu item// @return (boolean) false == stop processing this event// @group event handling//<rowClick : function (record, rowNum, colNum) { this.Super("rowClick", arguments); this.selectMenuItem(rowNum, colNum);},//> @method menu.selectMenuItem() (A)// Handle a selected menu item, either through a menu key or clicking on the item itself.// <p>// Calls item.click() or itemClick() for the selected item// @param item (item | number) pointer to or number of the item that was clicked on// @param colNum (number) Index of column that recieved the click. May be null if// the item was selected via keyboard selection.// @return (boolean) false == stop processing this event//<selectMenuItem : function (item, colNum) { if (item == null) item = this.getEventRecordNum(); // normalize item to the item pointer in case a number was passed in item = this.getItem(item); var returnValue = true; // if the item was not found, bail if (item == null || !this.itemIsEnabled(item)) { isc.Menu.hideAllMenus(); return false; } // if the item has a submenu or children, and parent selection is not // enabled, show the submenu // (clear the submenu timer and hide any other submenu first) if (this.hasSubmenu(item) && !this.canSelectParentItems) { if (this.submenuTimer) this.submenuTimer = isc.Timer.clear(this.submenuTimer); if (this._openItem != item) this.hideSubmenu(); this.showSubmenu(item); // return false so subclasses know not to do their thing return false; } // hide all menus automatically //get the autoDismiss property from the top level menu or the menu item var rootMenu = this; while (rootMenu._parentMenu) { rootMenu = rootMenu._parentMenu; } if (rootMenu.autoDismiss && (item.autoDismiss || item.autoDismiss == null) ) { isc.Menu.hideAllMenus(); } // if the item that was clicked on has an action, or click handler, call that if (item.action) { // Actions are a particular format of objects. // Also handle being pased an action string expression if (!isc.isA.Function(item.action)) { isc.Func.replaceWithMethod(item, "action", ""); } if (item.action() == false) return false; } if (item.click) { // if the handler was defined as a string, convert it to a function if (!isc.isA.Function(item.click)) { isc.Func.replaceWithMethod(item, "click", "target,item,menu,colNum"); } var target = (this.target ? this.target : this); // now call the handler -- return whether or not it returned false returnValue = item.click(target,item,this,colNum); } if (returnValue != false) { // otherwise call the generic itemClick() handler returnValue = this.itemClick(item, colNum); } //refresh the row after click if autoDismiss is false if (!(rootMenu.autoDismiss && (item.autoDismiss || item.autoDismiss == null))) { this.refreshRow(this.getRecordIndex(item)); } return returnValue;},//> @method menu.mouseOver() (A)// special mouseOver handler for submenus - simulates mouse over behavior for the // appropriate parent menu item. Ensures that item is hilited and this submenu // won't be hidden by the parent menu's submenuTimer// @group events, hiliting////<mouseOver : function () { // Make sure the appropriate parent menu item is hilighted // Will only be fired if necessary var parentMenu = this._parentMenu; if (parentMenu && parentMenu.body.lastOverRow != this._parentItemNum){ // Prevent this submenu from being killed by the parent's submenuTimer if (parentMenu.submenuTimer) parentMenu.submenuTimer = isc.Timer.clear(parentMenu.submenuTimer); // Update the parent's hilight to point to the appropriate row parentMenu._hiliteRecord(this._parentItemNum); } },//> @method menu.rowOver() (A)// When the mouse goes over a row, start the submenu timer to show the appropriate submenu// @group events, hiliting//<rowOver : function (row, field) { if (this.submenuTimer) this.submenuTimer = isc.Timer.clear(this.submenuTimer); this.submenuTimer = isc.Timer.setTimeout({target:this,method:this.changeSubmenu}, this.submenuDelay);},//> @method menu.itemClick() ([A])// Executed when a menu item with no click handler is clicked by the user. This// itemClick handler must be specified as a function. It is passed an item parameter that// is a reference to the clicked menu item.//// @visibility external// @param item (object) pointer to the item in question// @param [colNum] (number) Index of the column clicked by the user. May be null if// this menu item was activated in response to a keyboard event. //// @return (boolean) false if event processing should be stopped, true to continue// @example menuColumns//<itemClick : function (item, colNum) { // don't do anything by default},// show / hide submenus on right/left click [depending on which side they're being shown on] getShowSubmenuKey : function () { return this.submenuDirection == "right" ? "Arrow_Right" : "Arrow_Left";},getHideSubmenuKey : function () { return this.submenuDirection == "right" ? "Arrow_Left" : "Arrow_Right"; },//> @method menu.bodyKeyPress()// Handler for keypress events called from this.body.keyPress - overridden to allow arrow // key navigation of submenus, proper handling of "Enter" to select a menu item, // and "Escape" to hide the menu.// @group events//// @return (boolean) false == stop processing this event//<bodyKeyPress : function (event, eventInfo) { var keyName = isc.EventHandler.lastEvent.keyName; // Navigate submenus with arrow left / arrow right if (keyName == this.getHideSubmenuKey()) { if (this._parentMenu != null) { this._parentMenu.hideSubmenu(); this._parentMenu.focus(); return false; } } else if (keyName == this.getShowSubmenuKey()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -