hta-ctx-menu
Version:
create real context menus for HTA (HTML Application)
1,126 lines (1,123 loc) • 241 kB
JavaScript
/*
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