devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
460 lines (452 loc) • 17.5 kB
JavaScript
/**
* DevExtreme (core/component.js)
* Version: 19.2.6
* Build date: Thu Jan 30 2020
*
* Copyright (c) 2012 - 2020 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread()
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance")
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || "[object Arguments]" === Object.prototype.toString.call(iter)) {
return Array.from(iter)
}
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) {
arr2[i] = arr[i]
}
return arr2
}
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function")
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) {
descriptor.writable = true
}
Object.defineProperty(target, descriptor.key, descriptor)
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) {
_defineProperties(Constructor.prototype, protoProps)
}
if (staticProps) {
_defineProperties(Constructor, staticProps)
}
return Constructor
}
var Config = require("./config");
var extend = require("./utils/extend").extend;
var optionManager = require("./option_manager").OptionManager;
var bracketsToDots = require("./utils/data").bracketsToDots;
var Class = require("./class");
var Action = require("./action");
var errors = require("./errors");
var commonUtils = require("./utils/common");
var typeUtils = require("./utils/type");
var objectUtils = require("./utils/object");
var deferredUtils = require("../core/utils/deferred");
var Deferred = deferredUtils.Deferred;
var when = deferredUtils.when;
var Callbacks = require("./utils/callbacks");
var EventsMixin = require("./events_mixin");
var publicComponentUtils = require("./utils/public_component");
var devices = require("./devices");
var isFunction = typeUtils.isFunction;
var noop = commonUtils.noop;
var PostponedOperations = function() {
function PostponedOperations() {
_classCallCheck(this, PostponedOperations);
this._postponedOperations = {}
}
_createClass(PostponedOperations, [{
key: "add",
value: function(key, fn, postponedPromise) {
if (key in this._postponedOperations) {
postponedPromise && this._postponedOperations[key].promises.push(postponedPromise)
} else {
var completePromise = new Deferred;
this._postponedOperations[key] = {
fn: fn,
completePromise: completePromise,
promises: postponedPromise ? [postponedPromise] : []
}
}
return this._postponedOperations[key].completePromise.promise()
}
}, {
key: "callPostponedOperations",
value: function() {
for (var key in this._postponedOperations) {
var operation = this._postponedOperations[key];
if (typeUtils.isDefined(operation)) {
if (operation.promises && operation.promises.length) {
when.apply(void 0, _toConsumableArray(operation.promises)).done(operation.fn).then(operation.completePromise.resolve)
} else {
operation.fn().done(operation.completePromise.resolve)
}
}
}
this._postponedOperations = {}
}
}]);
return PostponedOperations
}();
var normalizeOptions = function(options, value) {
if ("string" !== typeof options) {
return options
}
var result = {};
result[options] = value;
return result
};
var Component = Class.inherit({
_setDeprecatedOptions: function() {
this._deprecatedOptions = {}
},
_getDeprecatedOptions: function() {
return this._deprecatedOptions
},
_getOptionAliasesByName: function(optionName) {
var _this = this;
return Object.keys(this._deprecatedOptions).filter(function(aliasName) {
return optionName === _this._deprecatedOptions[aliasName].alias
})
},
_getDefaultOptions: function() {
return {
onInitialized: null,
onOptionChanged: null,
onDisposing: null,
defaultOptionsRules: null
}
},
_defaultOptionsRules: function() {
return []
},
_getOptionByRules: function(customRules) {
var rules = this._defaultOptionsRules();
if (Array.isArray(customRules)) {
rules = rules.concat(customRules)
}
return this._convertRulesToOptions(rules)
},
_setOptionsByDevice: function(customRules) {
var rulesOptions = this._getOptionByRules(customRules);
this._setOptionByStealth(rulesOptions)
},
_convertRulesToOptions: function(rules) {
var options = {};
var currentDevice = devices.current();
var deviceMatch = function(device, filter) {
var filterArray = [];
Array.prototype.push.call(filterArray, filter);
return 1 === filterArray.length && typeUtils.isEmptyObject(filterArray[0]) || commonUtils.findBestMatches(device, filterArray).length > 0
};
for (var i = 0; i < rules.length; i++) {
var rule = rules[i];
var deviceFilter = rule.device || {};
var match;
if (isFunction(deviceFilter)) {
match = deviceFilter(currentDevice)
} else {
match = deviceMatch(currentDevice, deviceFilter)
}
if (match) {
extend(options, rule.options)
}
}
return options
},
_isInitialOptionValue: function(name) {
var optionValue = this.option(name);
var initialOptionValue = this.initialOption(name);
var isInitialOption = isFunction(optionValue) && isFunction(initialOptionValue) ? optionValue.toString() === initialOptionValue.toString() : commonUtils.equalByValue(optionValue, initialOptionValue);
return isInitialOption
},
_setOptionsByReference: function() {
this._optionsByReference = {}
},
_getOptionsByReference: function() {
return this._optionsByReference
},
ctor: function(options) {
var _this2 = this;
this.NAME = publicComponentUtils.name(this.constructor);
options = options || {};
if (options.eventsStrategy) {
this.setEventsStrategy(options.eventsStrategy)
}
this._options = {};
this._updateLockCount = 0;
this._optionChangedCallbacks = options._optionChangedCallbacks || Callbacks();
this._disposingCallbacks = options._disposingCallbacks || Callbacks();
this.postponedOperations = new PostponedOperations;
this.beginUpdate();
try {
this._setOptionsByReference();
this._setDeprecatedOptions();
this._options = this._getDefaultOptions();
this._optionManager = new optionManager(this._options, this._getOptionsByReference(), this._deprecatedOptions);
this._optionManager.onChanging(function(name, previousValue, value) {
if (_this2._initialized) {
_this2._optionChanging(name, previousValue, value)
}
});
this._optionManager.onDeprecated(function(option, info) {
_this2._logDeprecatedWarning(option, info)
});
this._optionManager.onChanged(function(name, value, previousValue) {
_this2._notifyOptionChanged(name, value, previousValue)
});
if (options && options.onInitializing) {
options.onInitializing.apply(this, [options])
}
this._setOptionsByDevice(options.defaultOptionsRules);
this._initOptions(options)
} finally {
this.endUpdate()
}
},
_initOptions: function(options) {
this.option(options)
},
_init: function() {
this._createOptionChangedAction();
this.on("disposing", function(args) {
this._disposingCallbacks.fireWith(this, [args])
}.bind(this))
},
_logDeprecatedWarning: function(option, info) {
var message = info.message || "Use the '" + info.alias + "' option instead";
errors.log("W0001", this.NAME, option, info.since, message)
},
_createOptionChangedAction: function() {
this._optionChangedAction = this._createActionByOption("onOptionChanged", {
excludeValidators: ["disabled", "readOnly"]
})
},
_createDisposingAction: function() {
this._disposingAction = this._createActionByOption("onDisposing", {
excludeValidators: ["disabled", "readOnly"]
})
},
_optionChanged: function(args) {
switch (args.name) {
case "onDisposing":
case "onInitialized":
break;
case "onOptionChanged":
this._createOptionChangedAction();
break;
case "defaultOptionsRules":
}
},
_dispose: function() {
this._optionChangedCallbacks.empty();
this._createDisposingAction();
this._disposingAction();
this._disposeEvents();
this._optionManager.dispose();
this._disposed = true
},
instance: function() {
return this
},
beginUpdate: function() {
this._updateLockCount++
},
endUpdate: function() {
this._updateLockCount = Math.max(this._updateLockCount - 1, 0);
if (!this._updateLockCount) {
this.postponedOperations.callPostponedOperations();
if (!this._initializing && !this._initialized) {
this._initializing = true;
try {
this._init()
} finally {
this._initializing = false;
this._updateLockCount++;
this._createActionByOption("onInitialized", {
excludeValidators: ["disabled", "readOnly"]
})();
this._updateLockCount--;
this._initialized = true
}
}
}
},
_optionChanging: noop,
_notifyOptionChanged: function(option, value, previousValue) {
var that = this;
if (this._initialized) {
var optionNames = [option].concat(that._getOptionAliasesByName(option));
for (var i = 0; i < optionNames.length; i++) {
var name = optionNames[i];
var args = {
name: name.split(/[.[]/)[0],
fullName: name,
value: value,
previousValue: previousValue
};
that._optionChangedCallbacks.fireWith(that, [extend(that._defaultActionArgs(), args)]);
that._optionChangedAction(extend({}, args));
if (!that._disposed && this._cancelOptionChange !== args.name) {
that._optionChanged(args)
}
}
}
},
initialOption: function(optionName) {
if (!this._initialOptions) {
this._initialOptions = this._getDefaultOptions();
var rulesOptions = this._getOptionByRules(this._getOptionByStealth("defaultOptionsRules"));
this._optionManager.setValueByReference(this._initialOptions, rulesOptions)
}
return this._initialOptions[optionName]
},
_defaultActionConfig: function() {
return {
context: this,
component: this
}
},
_defaultActionArgs: function() {
return {
component: this
}
},
_createAction: function(actionSource, config) {
var that = this;
var action;
return function(e) {
if (!arguments.length) {
e = {}
}
if (!typeUtils.isPlainObject(e)) {
e = {
actionValue: e
}
}
action = action || new Action(actionSource, extend(config, that._defaultActionConfig()));
return action.execute.call(action, extend(e, that._defaultActionArgs()))
}
},
_createActionByOption: function(optionName, config) {
var that = this;
var action;
var eventName;
var actionFunc;
var result = function() {
if (!eventName) {
config = config || {};
if ("string" !== typeof optionName) {
throw errors.Error("E0008")
}
if (0 === optionName.indexOf("on")) {
eventName = that._getEventName(optionName)
}
actionFunc = that.option(optionName)
}
if (!action && !actionFunc && !config.beforeExecute && !config.afterExecute && !that.hasEvent(eventName)) {
return
}
if (!action) {
var beforeExecute = config.beforeExecute;
config.beforeExecute = function(args) {
beforeExecute && beforeExecute.apply(that, arguments);
that.fireEvent(eventName, args.args)
};
action = that._createAction(actionFunc, config)
}
if (Config().wrapActionsBeforeExecute) {
var beforeActionExecute = that.option("beforeActionExecute") || noop;
var wrappedAction = beforeActionExecute(that, action, config) || action;
return wrappedAction.apply(that, arguments)
}
return action.apply(that, arguments)
};
if (!Config().wrapActionsBeforeExecute) {
var onActionCreated = that.option("onActionCreated") || noop;
result = onActionCreated(that, result, config) || result
}
return result
},
_getOptionByStealth: function(name) {
return this._optionManager.getValueSilently(name)
},
_setOptionByStealth: function(options, value) {
this._optionManager.setValueSilently(normalizeOptions(options, value))
},
_getEventName: function(actionName) {
return actionName.charAt(2).toLowerCase() + actionName.substr(3)
},
hasActionSubscription: function(actionName) {
return !!this.option(actionName) || this.hasEvent(this._getEventName(actionName))
},
isOptionDeprecated: function(name) {
var deprecatedOptions = this._getDeprecatedOptions();
return Object.prototype.hasOwnProperty.call(deprecatedOptions, name)
},
_setOptionSilent: function(name, value) {
this._cancelOptionChange = name;
this.option(name, value);
this._cancelOptionChange = false
},
_getOptionValue: function(name, context) {
var value = this.option(name);
if (isFunction(value)) {
return value.bind(context)()
}
return value
},
option: function(options, value) {
if (arguments.length < 2 && "object" !== typeUtils.type(options)) {
return this._optionManager.getValue(options)
}
this.beginUpdate();
try {
this._optionManager.setValue(normalizeOptions(options, value))
} finally {
this.endUpdate()
}
},
resetOption: function(name) {
var _this3 = this;
if (!name) {
return
}
var defaultValue;
if (name.search(/\.|\[/) !== -1) {
name = bracketsToDots(name);
var fullPath = name.split(".");
fullPath.forEach(function(path) {
defaultValue = defaultValue ? defaultValue[path] : _this3.initialOption(path)
})
} else {
defaultValue = this.initialOption(name)
}
defaultValue = typeUtils.isObject(defaultValue) ? objectUtils.clone(defaultValue) : defaultValue;
this.beginUpdate();
this._optionManager.setValue(normalizeOptions(name, defaultValue), false);
this.endUpdate()
}
}).include(EventsMixin);
module.exports = Component;
module.exports.PostponedOperations = PostponedOperations;