UNPKG

hta-ctx-menu

Version:

create real context menus for HTA (HTML Application)

1,126 lines (1,123 loc) 241 kB
/* title: hta-ctx-menu version: 0.0.38 github: https://github.com/gitcobra/hta-ctx-menu */ var HtaContextMenu = (function () { 'use strict'; var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var _a$1, _b$1, _c; /** * IE version * Trident: 4.0=IE8, 5.0=IE9, 6.0=IE10, 7.0=IE11 * */ var IE_Version = { MSIE: 0, Trident: 0, real: 0, OS: '' }; IE_Version.MSIE = Number((_a$1 = navigator.appVersion.match(/MSIE ([\d.]+)/)) === null || _a$1 === void 0 ? void 0 : _a$1[1]) || 11; IE_Version.Trident = Number((_b$1 = navigator.appVersion.match(/Trident\/([\d.]+)/)) === null || _b$1 === void 0 ? void 0 : _b$1[1]); IE_Version.OS = (_c = navigator.appVersion.match(/Windows (\d+|CE|NT [\d\.]+)/)) === null || _c === void 0 ? void 0 : _c[1]; IE_Version.real = (function () { switch (IE_Version.Trident | 0) { case 4: return 8; case 5: return 9; case 6: return 10; case 7: return 11; default: return IE_Version.MSIE; } })(); // logger var _log = function () { }; var _console = typeof console !== 'undefined' ? console : { log: function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } _log.apply(void 0, args); }, time: function () { }, timeEnd: function () { }, setLogger: function (func) { _log = func; } }; // IE10 lacks console.time ? if (IE_Version.MSIE === 10) { _console.time = _console.timeEnd = _console.log; } // bind this function bind(thisObj, func) { var args = Array.prototype.slice.call(arguments, 2); return function () { var funcArgs = args.concat(Array.prototype.slice.call(arguments)); return func.apply(thisObj, funcArgs); }; } // simple queue creator var Queue = /** @class */ (function () { function Queue(manualStart) { this._started = false; this._list = []; this._manualStart = false; this._queueTimeoutId = -1; this._manualStart = !!manualStart; this._checkAutoStart(); } Queue.prototype.start = function () { var _this_1 = this; if (this._started) return; this._started = true; this._queueTimeoutId = window.setTimeout(function () { return _this_1._processNext(); }, 0); return true; }; Queue.prototype.stop = function () { //console.log(`Queue#stop ${this._list.length}`, 'green'); this._started = false; clearTimeout(this._queueTimeoutId); }; Queue.prototype.clear = function () { this.stop(); this._list.length = 0; }; Queue.prototype.isActive = function () { return !!(this._started && this._list.length); }; Queue.prototype.next = function (callback) { this._list.push({ type: 'next', callback: callback }); this._checkAutoStart(); return this; }; Queue.prototype.resolve = function (callback) { this._list.push({ type: 'resolve', callback: callback }); this._checkAutoStart(); return this; }; Queue.prototype["catch"] = function (callback) { this._list.push({ type: 'catch', callback: callback }); this._checkAutoStart(); return this; }; Queue.prototype.sleep = function (msec, addFirst) { this._list[!addFirst ? 'push' : 'unshift']({ type: 'sleep', delay: msec }); this._checkAutoStart(); return this; }; Queue.prototype._checkAutoStart = function () { if (!this._manualStart) { this.start(); } }; // process the queue Queue.prototype._processNext = function (passedValue) { var _this_1 = this; var _a; //console.log(`Queue#_processNext length:${this._list.length} val:${passedValue}`, 'green'); var item = this._list.shift(); if (!item) { this.stop(); return; } var nextValue; var nextDelay = 0; var alreadyConsumed = false; var repeat = -1; var hookNextItem = function (passedValue) { if (alreadyConsumed) return; // repeat the callback if repeat is greater than or equal 0 if (repeat >= 0) { _this_1._list.unshift(item); nextDelay = repeat; } _this_1._queueTimeoutId = window.setTimeout(function () { return _this_1._processNext(passedValue); }, nextDelay); alreadyConsumed = true; }; var type = item.type; switch (type) { case 'next': case 'resolve': try { if (type === 'next') nextValue = item.callback(passedValue, function (msec) { if (msec === void 0) { msec = 0; } repeat = msec; }); else if (type === 'resolve') { item.callback(passedValue, function (value) { if (!_this_1._started) return; nextValue = value; hookNextItem(nextValue); }); return; // *interrupt here when type is "resolve" } } catch (e) { // search a catch queue when an exception occurs var caughtFlag = false; while (this._list.length) { var citem = this._list.shift(); if (citem.type !== 'catch') { continue; } nextValue = (_a = citem.callback) === null || _a === void 0 ? void 0 : _a.call(citem, e, passedValue); caughtFlag = true; break; } // throw an Error if no "catch" items were found if (!caughtFlag) { var message = "".concat(e.message, "\ncallback: ").concat(String(item.callback)); throw new Error(message); } } break; case 'sleep': nextDelay = item.delay; nextValue = passedValue; break; case 'catch': nextValue = passedValue; // just get rid of the catch queue break; default: throw new Error("unexpected Queue type \"".concat(item.type, "\"")); } hookNextItem(nextValue); }; return Queue; }()); // simplify attaching or detaching event listeners var EventAttacher = /** @class */ (function () { function EventAttacher(element, thisObj, IE11) { if (IE11 === void 0) { IE11 = false; } this._listeners = []; this._IE11 = false; // use addEventListener instead if the element is in IE11 or later this._element = element; this._this = thisObj || null; this._IE11 = IE11; } EventAttacher.prototype.attach = function (handler, callback) { var listener = this._this ? bind(this._this, callback) : callback; if (!this._IE11) this._element.attachEvent(handler, listener); else this._element.addEventListener(handler.substring(2), listener); this._listeners.push([handler, callback, listener]); }; EventAttacher.prototype.detach = function (handler, target) { for (var _i = 0, _a = this._listeners; _i < _a.length; _i++) { var _b = _a[_i], handler_1 = _b[0], callback = _b[1], listener = _b[2]; if (target === callback) { if (!this._IE11) this._element.detachEvent(handler_1, listener); else // @ts-ignore this._element.removeEventListener(handler_1, listener); return true; } } return false; }; EventAttacher.prototype.detachAll = function () { for (var _i = 0, _a = this._listeners; _i < _a.length; _i++) { var _b = _a[_i], handler = _b[0], listener = _b[2]; if (!this._IE11) this._element.detachEvent(handler, listener); else // @ts-ignore this._element.removeEventListener(handler, listener); } this._listeners.length = 0; }; EventAttacher.prototype.element = function () { return this._element; }; EventAttacher.prototype.dispose = function () { this.detachAll(); this._element = null; this._this = null; }; return EventAttacher; }()); var _a, _b; var AllMenuTypesList = ['normal', 'radio', 'checkbox', 'separator', 'submenu', 'popup', 'demand', 'radios', 'checkboxes']; function convertCheckableIconPairParam(param) { if (param instanceof Array) { if (param.length !== 2) throw new Error("CheckableIconPair must be [IconSettingType, IconSettingType]"); return param; } var icon = param; var blank = {}; if (!icon.path && !icon.text) throw new Error("pairIcons parameter must be type CheckableIconPair"); // copy props for (var p in icon) { blank[p] = icon[p]; } // set blank flag for the unchecked icon blank.blank = true; return [icon, blank]; } var _MenuModel_uniqueId = 0; /** * base menu item class. * all menu items are descended from this. * @abstract * @class _MenuModelBase */ var _MenuModelBase = /** @class */ (function () { function _MenuModelBase(args, parent, demanded) { if (demanded === void 0) { demanded = false; } this._uniqueId = 'uid_' + String(++_MenuModel_uniqueId); this._index = -1; this._customClassNames = []; this._isDynamicallyProduced = false; // true if it was produced by type demand item this._menuModelEventListeners = {}; this._listenerIdCounter = 0; //this._type = args.type || 'normal'; if (args.type && !RegExp('\\b' + args.type + '\\b', 'i').test(AllMenuTypesList)) { this._unexpectedTypeError(); } this._parent = parent; //this._name = args.name; this._id = args.id; if (demanded || (parent === null || parent === void 0 ? void 0 : parent.isDynamicallyProduced())) { this._isDynamicallyProduced = true; } if ('customClass' in args) { var classNames = []; var cstr = String(args.customClass).replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' '); if (!/((^|\s)\S+)$/.test(cstr)) throw new Error("classNames parameter must be a space separated string. \"".concat(cstr, "\"")); var classes = cstr.split(' '); for (var _i = 0, classes_1 = classes; _i < classes_1.length; _i++) { var name_1 = classes_1[_i]; classNames.push(name_1); } this._customClassNames = classNames; } } _MenuModelBase.prototype._unexpectedTypeError = function () { throw new Error("type \"".concat(this._type, "\" could not be applied to \"").concat(String(this.constructor).replace(/^function\s+([^(]+)[\s\S]+$/, '$1'), "\" class")); }; _MenuModelBase.prototype.getType = function () { return this._type; }; _MenuModelBase.prototype.getId = function () { return this._id; }; _MenuModelBase.prototype.getUniqueId = function () { return this._uniqueId; }; _MenuModelBase.prototype.getCustomClassNames = function () { return this._customClassNames; }; _MenuModelBase.prototype.getFlags = function () { return {}; }; _MenuModelBase.prototype.getIcon = function () { return undefined; }; _MenuModelBase.prototype.getLabel = function () { }; _MenuModelBase.prototype.getIndex = function () { return this._index; }; _MenuModelBase.prototype.setIndex = function (num) { return this._index = num; }; _MenuModelBase.prototype.isDynamicallyProduced = function () { return this._isDynamicallyProduced; }; _MenuModelBase.prototype.getRealParentSubmenu = function () { return !this._parent ? null : this._parent.isDynamicallyProduced() ? this._parent.getRealParentSubmenu() : this._parent; }; /** * set internal model event listeners * @param {MenuModelEventNames} handler * @param {Function} listener * @memberof MenuModel */ _MenuModelBase.prototype.addMenuModelEvent = function (handler, listener) { var listeners = this._menuModelEventListeners[handler] = this._menuModelEventListeners[handler] || {}; listeners[this._listenerIdCounter] = listener; return this._listenerIdCounter++; }; _MenuModelBase.prototype.removeMenuModelEvent = function (handler, listenerId) { var listeners = this._menuModelEventListeners[handler] = this._menuModelEventListeners[handler] || {}; if (listeners[listenerId]) { delete listeners[listenerId]; return true; } return false; }; /** * fire events * @param {string} handler */ _MenuModelBase.prototype.fireMenuModelEvent = function (handler) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } for (var ename in this._menuModelEventListeners) { if (ename !== handler) continue; var listeners = this._menuModelEventListeners[ename]; for (var id in listeners) { listeners[Number(id)].apply(listeners, args); } } }; // type guards _MenuModelBase.prototype.isNormal = function () { return this instanceof MenuNormal; }; _MenuModelBase.prototype.isSubmenu = function () { return this instanceof MenuSubmenu; }; _MenuModelBase.prototype.isPopup = function () { return this instanceof MenuPopup; }; _MenuModelBase.prototype.isCheckable = function () { return this instanceof _MenuCheckable; }; _MenuModelBase.prototype.isRadio = function () { return this instanceof MenuRadio; }; _MenuModelBase.prototype.isCheckbox = function () { return this instanceof MenuCheckbox; }; _MenuModelBase.prototype.isSeparator = function () { return this instanceof MenuSeparator; }; _MenuModelBase.prototype.isDemandable = function () { return this instanceof MenuDemand; }; _MenuModelBase.prototype.$L = function () { if (this._parent) return "L(".concat(this._parent.getLayer(), ")i[").concat(this._index, "]"); else return "L(R)"; }; _MenuModelBase.prototype.dispose = function () { // }; return _MenuModelBase; }()); /** * MenuNormal items have basic menu item functions * @class MenuNormal * @extends {_MenuModelBase} */ var MenuNormal = /** @class */ (function (_super) { __extends(MenuNormal, _super); function MenuNormal(args, parent, demanded) { var _this = this; var _c, _d; _this = _super.call(this, args, parent, demanded) || this; _this._type = 'normal'; _this._useHTML = false; _this._nowrap = true; _this._union = false; // no left and right padding spaces _this._unselectable = false; // unselectable items will not be highlighted _this._disabled = false; // disabled _this._unlistening = false; _this._hold = false; // hold on after a clickable item was clicked _this._unholdByDblclick = false; // when hold is true, close menu by double click or enter key _this._holdParent = false; // when an item is clicked, hold on parent menu _this._flash = 0; // flash in some msec after clicking the item _this._ignoreGlobalEvents = false; _this._ignoreErrors = false; _this._selected = false; var param = args; _this._label = String(args.label); _this._icon = 'icon' in args ? args.icon : undefined; _this._cssText = param.cssText || ''; _this._fontSize = param.fontSize || ''; _this._fontFamily = param.fontFamily || ''; _this._title = param.title; // flags _this._union = !!param.union; _this._hold = (_d = (_c = param.hold) !== null && _c !== void 0 ? _c : parent === null || parent === void 0 ? void 0 : parent._hold) !== null && _d !== void 0 ? _d : false; _this._holdParent = !!param.holdParent; _this._unholdByDblclick = !!param.unholdByDblclick; _this._disabled = !!param.disabled; _this._unselectable = !!param.unselectable; _this._unlistening = !!param.unlistening; _this._align = param.align; _this._flash = param.flash || 0; _this._useHTML = !!param.html; if (typeof param.nowrap === 'boolean') _this._nowrap = param.nowrap; // events _this.onclick = param.onclick; _this.ondblclick = param.ondblclick; _this.onhighlight = param.onhighlight; _this.onactivate = param.onactivate; _this._ignoreGlobalEvents = !!param.ignoreGlobalEvents; _this._ignoreErrors = !!param.ignoreErrors; return _this; } /** * fire user events such as onclick, onchange, etc */ MenuNormal.prototype.fireUserEvent = function (handler, ctx, eventObj) { var _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q; if (this._unlistening) return; var notFired = false; try { switch (handler) { case 'activate': (_c = this.onactivate) === null || _c === void 0 ? void 0 : _c.call(this, eventObj, ctx); break; case 'click': (_d = this.onclick) === null || _d === void 0 ? void 0 : _d.call(this, eventObj, ctx); break; case 'dblclick': (_e = this.ondblclick) === null || _e === void 0 ? void 0 : _e.call(this, eventObj, ctx); break; case 'change': { if (this.isCheckable()) { if (this.getType() === 'radio') { // indivisual onchange (_f = this.onchange) === null || _f === void 0 ? void 0 : _f.call(this, eventObj, ctx); } else (_g = this.onchange) === null || _g === void 0 ? void 0 : _g.call(this, eventObj, ctx); } break; } case 'highlight': (_h = this.onhighlight) === null || _h === void 0 ? void 0 : _h.call(this, eventObj, ctx); break; case 'beforeload': if (this.isSubmenu()) (_j = this.onbeforeload) === null || _j === void 0 ? void 0 : _j.call(this, eventObj, ctx); break; case 'load': if (this.isSubmenu()) (_k = this.onload) === null || _k === void 0 ? void 0 : _k.call(this, eventObj, ctx); break; case 'unload': if (this.isSubmenu()) (_l = this.onunload) === null || _l === void 0 ? void 0 : _l.call(this, eventObj, ctx); break; default: notFired = true; } } catch (e) { if (!this._ignoreErrors) alert("an error occurred while firing an user event.\n\nhandler: \"on".concat(handler, "\"\nlayer: ").concat((_m = this._parent) === null || _m === void 0 ? void 0 : _m.getLayer(), "\nindex: ").concat(this._index, "\ntype: ").concat(this._type, "\nlabel: \"").concat(this.getLabel().replace(/[\r\n]/g, ''), "\"\nmessage: ").concat(e.message)); } //if( !notFired ) // console.log('FIRED!', 'red'); // fire global user events if (eventObj.cancelGlobal !== true && !this._ignoreGlobalEvents) { if (this.isNormal()) { try { (_p = (_o = this._parent) === null || _o === void 0 ? void 0 : _o.getGlobalEvent(handler)) === null || _p === void 0 ? void 0 : _p(eventObj, ctx); } catch (e) { if (!this._ignoreErrors) alert("an error occurred while firing an global user event.\n\nhandler: \"on".concat(handler, "\"\nlayer: ").concat((_q = this._parent) === null || _q === void 0 ? void 0 : _q.getLayer(), "\nindex: ").concat(this._index, "\ntype: ").concat(this._type, "\nlabel: \"").concat(this.getLabel().replace(/[\r\n]/g, ''), "\"\nmessage: ").concat(e.message)); } } } // dispose event object eventObj.dispose(); }; MenuNormal.prototype.setLabel = function (label, asHtml) { var beforeLabel = this._label; this._label = label; this.fireMenuModelEvent('label', label, beforeLabel); }; MenuNormal.prototype.getLabel = function (asHtml) { return this._label; }; MenuNormal.prototype.setIcon = function (icon) { this._applyIcon(icon); }; MenuNormal.prototype._applyIcon = function (icon) { var before = this._icon; this._icon = icon; this.fireMenuModelEvent('icon', icon, before); }; MenuNormal.prototype.getIcon = function () { return this._icon; }; MenuNormal.prototype.hasUsersIcon = function () { return !!this._icon; }; /** * get item flags * @return {*} * @memberof MenuNormal */ MenuNormal.prototype.getFlags = function () { return { union: this._union, hold: this._hold, unholdByDblclick: this._unholdByDblclick, holdParent: this._holdParent, flash: this._flash, html: this._useHTML, nowrap: this._nowrap, unselectable: this._unselectable, disabled: this._disabled, unlistening: this._unlistening, align: this._align, fontSize: this._fontSize || '', fontFamily: this._fontFamily, cssText: this._cssText }; }; MenuNormal.prototype.dispose = function () { _super.prototype.dispose.call(this); // }; return MenuNormal; }(_MenuModelBase)); /** * radio or checkbox item * @abstract * @class MenuCheckable * @extends {MenuNormal} */ var _MenuCheckable = /** @class */ (function (_super) { __extends(_MenuCheckable, _super); function _MenuCheckable(args, parent, demanded) { var _this = _super.call(this, args, parent, demanded) || this; _this._isNamed = false; // set the flag on if name is set by user _this._global = false; // group the same name items in the entire menus _this._checked = false; // checked flag for radio or checkbox _this._pairIcons = null; // checked, unchecked //this._parent = parent; //this._type = args.type; // set item name for a record var name; // user specified name if (args.name) { if (!/^\w/.test(args.name)) throw new Error("name parameter must be started with an alphabet. \"".concat(args.name, "\" is invalid.")); _this._isNamed = true; name = String(args.name); //this._recordRepository = this.getRealParentSubmenu()!; } else { //throw new Error('a type "radio" or "checkbox" item needs "name" parameter'); // generate name automatically name = args.type === 'radio' ? '!radio_noname' : '!checkbox_' + _MenuModel_uniqueId++; } _this._name = name; // use global repository for the name _this._global = !!args.global; _this._recordSubmenu = _this._global ? _this._parent.getRoot() : _this._parent; _this.onchange = args.onchange; _this._checked = !!args.checked; // user specified record object if (args.record) { if (typeof args.record !== 'object') throw new Error("\"record\" parameter must be an object."); _this._record = args.record; } // generate a record else { _this._record = _this._parent.getNamedCheckableItemRecord(_this._name, _this._global); } // set item value _this._value = args.value; return _this; // update the icon //this.updateCheckableIcon(true); } _MenuCheckable.prototype.updateCheckableIcon = function (force) { var prev = this._previousChecked; var current = this._checked; if (prev !== current || force) { var icon = this._pairIcons || this._parent.getDefaultCheckableIcon(this._type) || this._defaultPairIcons; this._applyIcon(current ? icon[0] : icon[1]); this.fireMenuModelEvent('checked', current, this._value); this._previousChecked = current; } }; _MenuCheckable.prototype.getFlags = function () { return __assign({ checked: this._checked, usericon: this.hasUsersIcon() }, _super.prototype.getFlags.call(this)); }; _MenuCheckable.prototype.getName = function () { return this._name; }; _MenuCheckable.prototype.setValue = function (val) { this._value = val; }; _MenuCheckable.prototype.getValue = function () { return this._value; }; _MenuCheckable.prototype.isChecked = function () { return this._checked; }; _MenuCheckable.prototype.isGlobal = function () { return this._global; }; _MenuCheckable.prototype.getRecord = function () { return this._record; }; _MenuCheckable.prototype.getRecordRopository = function () { return this._recordSubmenu; }; _MenuCheckable.prototype.setIcon = function (icon, apply) { if (apply === void 0) { apply = true; } this._pairIcons = icon ? convertCheckableIconPairParam(icon) : null; if (apply) this.updateCheckableIcon(true); }; _MenuCheckable.prototype.hasUsersIcon = function () { return !!(this._pairIcons || this._parent.getDefaultCheckableIcon(this._type)); }; _MenuCheckable.prototype.setChecked = function (flag) { var prev = this._checked; flag = typeof flag === 'undefined' ? !prev : !!flag; // flip if flag is undefined if (flag === prev) return false; var result = this._setChecked(flag, true); // work for each Checkable type if (result) { this.updateCheckableIcon(); } return result; }; return _MenuCheckable; }(MenuNormal)); _a = _MenuCheckable; // prototype static properties (function () { _a.prototype._defaultPairIcons = [{ text: '\xfc', fontFamily: 'Wingdings' }, { text: '\xfc', fontFamily: 'Wingdings', blank: true }]; })(); var MenuCheckbox = /** @class */ (function (_super) { __extends(MenuCheckbox, _super); function MenuCheckbox(args, parent, demanded) { var _this = _super.call(this, args, parent, demanded) || this; _this._type = 'checkbox'; // set key records if (args.key) { _this._key = args.key; _this._keyRecords = args.records; if (!_this._keyRecords) // disable key if keyRecords doesn't exist _this._key = undefined; } // set the pair of icons if (args.checkboxIcon) { _this.setIcon(args.checkboxIcon, false); } var rchecked = _this._getRecordChecked(); if (typeof rchecked === 'boolean') _this._checked = rchecked; //this._record.checked = this._checked; _this._setRecordChecked(_this._checked); // update the icon _this.updateCheckableIcon(true); return _this; } MenuCheckbox.prototype._setChecked = function (flag, fromPublic) { if (fromPublic === void 0) { fromPublic = false; } this._checked = flag; if (fromPublic) { //this._record.checked = flag; this._setRecordChecked(flag); this._linkOtherCheckboxesInParents(flag); } this.updateCheckableIcon(); return true; }; MenuCheckbox.prototype._linkOtherCheckboxesInParents = function (flag) { var parent = this._parent; var global = this._global; while (parent) { var list = parent.getItemsByName(this._name); for (var _i = 0, list_1 = list; _i < list_1.length; _i++) { var item_1 = list_1[_i]; if (item_1 === this || !item_1.isCheckbox() || global !== item_1._global) continue; item_1._setChecked(flag); } parent = global ? parent.getParent() : null; } }; MenuCheckbox.prototype.updateCheckedStatByRecord = function () { //this._checked = !!this._record.checked; this._checked = !!this._getRecordChecked(); this.updateCheckableIcon(); }; // they are needed when the checkbox has key records MenuCheckbox.prototype._setRecordChecked = function (checked) { if (this._key) { this._keyRecords[this._key] = checked; } this._record.checked = checked; }; MenuCheckbox.prototype._getRecordChecked = function () { if (this._key) { return this._keyRecords[this._key]; } else { return this._record.checked; } }; return MenuCheckbox; }(_MenuCheckable)); var MenuRadio = /** @class */ (function (_super) { __extends(MenuRadio, _super); function MenuRadio(args, parent, demanded) { var _this = _super.call(this, args, parent, demanded) || this; _this._type = 'radio'; _this._uncheckable = false; // allow unckeck the radio button // set the pair of icons if (args.radioIcon) { _this.setIcon(args.radioIcon, false); } // initialize radio index //this._radioIndex = this._recordSubmenu.countRadioIndex(this._name); _this._radioIndex = _this._parent.countRadioIndex(_this._name, _this._global, _this._id); //console.log([this._radioIndex, this._label]); _this._uncheckable = !!args.uncheckable; // decide checked status if (_this._checked) { _this._record.selectedIndex = _this._radioIndex; } else { /* // always check index 0 by default unless _uncheckable flag is true if( typeof this._record.selectedIndex !== 'number' ) { this._record.selectedIndex = this._uncheckable ? -1 : 0; } */ if (_this._record.selectedIndex === _this._radioIndex) _this._checked = true; } // update the icon _this.updateCheckableIcon(true); return _this; } MenuRadio.prototype.getRadioIndex = function () { return this._radioIndex; }; MenuRadio.prototype.isUncheckable = function () { return this._uncheckable; }; MenuRadio.prototype._setChecked = function (flag, fromPublic) { if (fromPublic === void 0) { fromPublic = false; } if (!flag) { if (fromPublic && !this._uncheckable) return false; this._checked = false; if (fromPublic) { this._record.selectedIndex = -1; } this.updateCheckableIcon(); return true; } this._checked = true; this._record.selectedIndex = this._radioIndex; this.updateCheckableIcon(); this._clearOtherRadios(); return true; }; /** * clear all other radios with same name * @private * @param {boolean} [recursive=false] * @memberof MenuRadio */ MenuRadio.prototype._clearOtherRadios = function () { var parent = this._parent; var global = false; while (parent) { var list = parent.getItemsByName(this._name); for (var _i = 0, list_2 = list; _i < list_2.length; _i++) { var item_2 = list_2[_i]; if (item_2 === this || !item_2.isRadio() || global && !item_2._global) continue; item_2._setChecked(false); } global = this._global; parent = global ? parent.getParent() : null; } }; MenuRadio.prototype.updateCheckedStatByRecord = function () { this._checked = this._record.selectedIndex === this._radioIndex; this.updateCheckableIcon(); }; return MenuRadio; }(_MenuCheckable)); /** * a MenuDemand can emit appropriate menu items dynamically on demand. * @class MenuDemand * @extends {_MenuModelBase} */ var MenuDemand = /** @class */ (function (_super) { __extends(MenuDemand, _super); function MenuDemand(args, parent, demanded) { var _this = _super.call(this, args, parent, demanded) || this; _this._type = 'demand'; if (args.type !== 'demand') _this._unexpectedTypeError(); if (typeof args.ondemand !== 'function') throw new Error('type demand item needs ondemand event handler'); _this.ondemand = args.ondemand; return _this; } /** * execute the ondemand callback * @param {*} [eventObj] * @return {*} {MenuItemsCreateParameter[]} * @memberof MenuDemand */ MenuDemand.prototype.extract = function (eventObj) { var _c; var resultParameter; try { var demanded = this.ondemand.call(this._parent, eventObj, eventObj.ctx) || []; if (demanded && typeof (demanded) !== 'object') throw new Error('ondemand callback must returns an object type MenuItemsCreateParameter'); if (demanded instanceof Array) resultParameter = demanded; else resultParameter = [demanded]; for (var _i = 0, resultParameter_1 = resultParameter; _i < resultParameter_1.length; _i++) { var param = resultParameter_1[_i]; if ((param === null || param === void 0 ? void 0 : param.type) === 'demand') throw new Error('type "demand" item must returns other type parameter.'); } } catch (e) { alert("an error occurred while extracting a demandable item\n\nmessage: ".concat(e.message, "\n\nparent label: \"").concat((_c = this._parent) === null || _c === void 0 ? void 0 : _c.getLabel(), "\"")); resultParameter = []; } return resultParameter; }; return MenuDemand; }(_MenuModelBase)); /** * for a separator * @class MenuSeparator * @extends {_MenuModelBase} */ var MenuSeparator = /** @class */ (function (_super) { __extends(MenuSeparator, _super); function MenuSeparator(param, parent, demanded) { var _this = _super.call(this, param, parent, demanded) || this; _this._type = 'separator'; if (param.type !== 'separator') _this._unexpectedTypeError(); return _this; } return MenuSeparator; }(_MenuModelBase)); /** * MenuSubmenu contains all other menu items includes MenuSubmenu itself. * when it does not have parent MenuSubmenu, it is the root of all menus. * @class SubmenuItem * @extends {_MenuModelBase} */ var MenuSubmenu = /** @class */ (function (_super) { __extends(MenuSubmenu, _super); function MenuSubmenu(param, parent /*, inheritOnly:boolean = false*/, demanded) { var _this = _super.call(this, param, parent, demanded) || this; _this._type = 'submenu'; _this._items = []; // ready items to use _this._layer = 0; _this._flashItems = false; _this._customDialogClass = ''; // have records for named child submenus because demandable items lose records after closed _this._namedCheckableItemRecords = {}; // records for MenuCheckable items _this._globalNamedCheckableItemRecords = null; // global records only for the root menu _this._radioCount = {}; _this._globalRadioCount = null; _this._checkablePairIcons = {}; _this._globalEvents = null; // default inheritance settings _this._inherit = { skin: true, cssText: true, globalEvents: true, checkboxIcon: true, radioIcon: true, arrowIcon: true, flashItems: true, childLeftMargin: true, autoClose: true, fontSize: true, fontFamily: true }; _this.onload = param.onload; _this.onbeforeload = param.onbeforeload; _this.onunload = param.onunload; _this._globalEvents = param.globalEvents; _this._skinCSSPath = param.skin; _this._menuCssText = param.menuCssText || ''; _this._menuFontSize = param.menuFontSize || ''; _this._menuFontFamily = param.menuFontFamily || ''; _this._childLeftMargin = param.childLeftMargin; _this._arrowIcon = param.arrowIcon || _this._arrowIcon; if (param.checkboxIcon) _this._checkablePairIcons['checkbox'] = convertCheckableIconPairParam(param.checkboxIcon); if (param.radioIcon) _this._checkablePairIcons['radio'] = convertCheckableIconPairParam(param.radioIcon); var className = String(param.customDialogClass || ''); if (className && !/(^\S+)$/.test(className)) throw new Error("invalid customDialogClass parameter. \"".concat(className, "\"")); _this._customDialogClass = className; if (typeof param.autoClose === 'boolean') _this._disableAutoClose = param.autoClose; // set inherit attributes from parent if (parent) { if (typeof param.inherit !== 'undefined') { var _inherit = _this._inherit; var pinherit = param.inherit; for (var attr in _this._inherit) { var key = attr; if (typeof pinherit === 'boolean') { // set all as the same flag if the value is boolean _inherit[key] = pinherit; continue; } if (key in pinherit === false) continue; _inherit[key] = pinherit[key]; } } } /* if( typeof this._childLeftMargin === 'undefined' ) this._childLeftMargin = 0; */ // decide whether this is the root if (parent /*&& !inheritOnly*/) { _this._root = parent._root; _this._layer = parent._layer + 1; } else { _this._root = _this; _this._globalNamedCheckableItemRecords = {}; _this._globalRadioCount = {}; } _this._pre_items = _this._preCreateItems(param.items); return _this; } /** * create pre-items * MenuDemand items are not extracted yet at this time */ MenuSubmenu.prototype._preCreateItems = function (args, demanded) { if (!(args instanceof Array)) args = [args]; var resultItems = []; for (var _i = 0, args_1 = args; _i < args_1.length; _i++) { var param = args_1[_i]; if (!param) continue; var type = param.type || 'normal'; if (!RegExp('\\b' + type + '\\b', 'i').test(AllMenuTypesList)) throw new Error('unexpected menu type: ' + type); // extract radio group parameter else { var item_3 = void 0; var items = null; switch (param.type) { case 'radios': items = this._extractRadiosParameter(param, demanded); break; case 'checkboxes': items = this._extractCheckboxParameter(param, demanded); break; case 'submenu': item_3 = new MenuSubmenu(param, this, demanded); break; case 'popup': item_3 = new MenuPopup(param, this, demanded); break; case 'checkbox': item_3 = new MenuCheckbox(param, this, demanded); break; case 'radio': item_3 = new MenuRadio(param, this, demanded); break; case 'separator': item_3 = new MenuSeparator(param, this, demanded); break; case 'demand': item_3 = new MenuDemand(param, this, demanded); break; case 'normal': default: item_3 = new MenuNormal(param, this, demanded); break; } resultItems.push.apply(resultItems, (items || [item_3])); } } return resultItems; }; MenuSubmenu.prototype._extractRadiosParameter = function (param, demanded) { var _c; var list = []; if (param.hasOwnProperty('labels')) { var labels = param.labels; // generate radio names automatically if doesn't exist var name_2 = param.name || 'nonameradios_' + _MenuModel_uniqueId++; var serialId = param.serialId; var selectedIndex = typeof param.selectedIndex !== 'number' ? -1 : param.selectedIndex; var disabledAll = !!param.disabled; var setChecked = param.setChecked; var alignAll = param.align; for (var i = 0; i < labels.length; i++) { var label = void 0, checked = void 0, value = void 0, disabled = void 0, unselectable = void 0, unlistening = void 0, id = void 0, align = void 0; label = labels[i]; if (!label) continue; // set id automatically if (serialId) { id = name_2 + '_serialID_' + i; } if (label instanceof Array) { _c = label, label = _c[0], value = _c[1], checked = _c[2]; } else { label = String(label); value = label; } //value ??= label; checked = !!checked; if (setChecked) checked = setChecked(value, i, label); di