devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
549 lines (547 loc) • 24.2 kB
JavaScript
/**
* DevExtreme (integration/angular/component_registrator.js)
* Version: 18.2.18
* Build date: Tue Oct 18 2022
*
* Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
var _typeof = "function" === typeof Symbol && "symbol" === typeof Symbol.iterator ? function(obj) {
return typeof obj
} : function(obj) {
return obj && "function" === typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
};
var _renderer = require("../../core/renderer");
var _renderer2 = _interopRequireDefault(_renderer);
var _events_engine = require("../../events/core/events_engine");
var _events_engine2 = _interopRequireDefault(_events_engine);
var _config = require("../../core/config");
var _config2 = _interopRequireDefault(_config);
var _component_registrator_callbacks = require("../../core/component_registrator_callbacks");
var _component_registrator_callbacks2 = _interopRequireDefault(_component_registrator_callbacks);
var _class = require("../../core/class");
var _class2 = _interopRequireDefault(_class);
var _callbacks = require("../../core/utils/callbacks");
var _callbacks2 = _interopRequireDefault(_callbacks);
var _type = require("../../core/utils/type");
var _type2 = _interopRequireDefault(_type);
var _iterator = require("../../core/utils/iterator");
var _iterator2 = _interopRequireDefault(_iterator);
var _array = require("../../core/utils/array");
var _array2 = _interopRequireDefault(_array);
var _locker = require("../../core/utils/locker");
var _locker2 = _interopRequireDefault(_locker);
var _ui = require("../../ui/widget/ui.widget");
var _ui2 = _interopRequireDefault(_ui);
var _editor = require("../../ui/editor/editor");
var _editor2 = _interopRequireDefault(_editor);
var _template = require("./template");
var _template2 = _interopRequireDefault(_template);
var _module = require("./module");
var _module2 = _interopRequireDefault(_module);
var _uiCollection_widget = require("../../ui/collection/ui.collection_widget.edit");
var _uiCollection_widget2 = _interopRequireDefault(_uiCollection_widget);
var _data = require("../../core/utils/data");
var _data2 = _interopRequireDefault(_data);
var _extend = require("../../core/utils/extend");
var _extend2 = _interopRequireDefault(_extend);
var _inflector = require("../../core/utils/inflector");
var _inflector2 = _interopRequireDefault(_inflector);
var _errors = require("../../core/errors");
var _errors2 = _interopRequireDefault(_errors);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
"default": obj
}
}
var each = _iterator2.default.each;
var inArray = _array2.default.inArray;
var compileSetter = _data2.default.compileSetter;
var compileGetter = _data2.default.compileGetter;
var extendFromObject = _extend2.default.extendFromObject;
var ITEM_ALIAS_ATTRIBUTE_NAME = "dxItemAlias";
var SKIP_APPLY_ACTION_CATEGORIES = ["rendering"];
var NG_MODEL_OPTION = "value";
var safeApply = function(func, scope) {
if (scope.$root.$$phase) {
return func(scope)
} else {
return scope.$apply(function() {
return func(scope)
})
}
};
var ComponentBuilder = _class2.default.inherit({
ctor: function(options) {
this._componentDisposing = (0, _callbacks2.default)();
this._optionChangedCallbacks = (0, _callbacks2.default)();
this._ngLocker = new _locker2.default;
this._scope = options.scope;
this._$element = options.$element;
this._$templates = options.$templates;
this._componentClass = options.componentClass;
this._parse = options.parse;
this._compile = options.compile;
this._itemAlias = options.itemAlias;
this._transcludeFn = options.transcludeFn;
this._digestCallbacks = options.dxDigestCallbacks;
this._normalizeOptions(options.ngOptions);
this._initComponentBindings();
this._initComponent(this._scope);
if (!options.ngOptions) {
this._addOptionsStringWatcher(options.ngOptionsString)
}
},
_addOptionsStringWatcher: function(optionsString) {
var _this = this;
var clearOptionsStringWatcher = this._scope.$watch(optionsString, function(newOptions) {
if (!newOptions) {
return
}
clearOptionsStringWatcher();
_this._normalizeOptions(newOptions);
_this._initComponentBindings();
_this._component.option(_this._evalOptions(_this._scope))
});
this._componentDisposing.add(clearOptionsStringWatcher)
},
_normalizeOptions: function(options) {
var _this2 = this;
this._ngOptions = extendFromObject({}, options);
if (!options) {
return
}
if (!options.hasOwnProperty("bindingOptions") && options.bindingOptions) {
this._ngOptions.bindingOptions = options.bindingOptions
}
if (options.bindingOptions) {
each(options.bindingOptions, function(key, value) {
if ("string" === _type2.default.type(value)) {
_this2._ngOptions.bindingOptions[key] = {
dataPath: value
}
}
})
}
},
_initComponent: function(scope) {
this._component = new this._componentClass(this._$element, this._evalOptions(scope));
this._component._isHidden = true;
this._handleDigestPhase()
},
_handleDigestPhase: function() {
var _this3 = this;
var beginUpdate = function() {
_this3._component.beginUpdate()
};
var endUpdate = function() {
_this3._component.endUpdate()
};
this._digestCallbacks.begin.add(beginUpdate);
this._digestCallbacks.end.add(endUpdate);
this._componentDisposing.add(function() {
_this3._digestCallbacks.begin.remove(beginUpdate);
_this3._digestCallbacks.end.remove(endUpdate)
})
},
_initComponentBindings: function() {
var _this4 = this;
var optionDependencies = {};
if (!this._ngOptions.bindingOptions) {
return
}
each(this._ngOptions.bindingOptions, function(optionPath, value) {
var separatorIndex = optionPath.search(/\[|\./);
var optionForSubscribe = separatorIndex > -1 ? optionPath.substring(0, separatorIndex) : optionPath;
var prevWatchMethod = void 0;
var clearWatcher = void 0;
var valuePath = value.dataPath;
var deepWatch = true;
var forcePlainWatchMethod = false;
if (void 0 !== value.deep) {
forcePlainWatchMethod = deepWatch = !!value.deep
}
if (!optionDependencies[optionForSubscribe]) {
optionDependencies[optionForSubscribe] = {}
}
optionDependencies[optionForSubscribe][optionPath] = valuePath;
var watchCallback = function(newValue, oldValue) {
if (_this4._ngLocker.locked(optionPath)) {
return
}
_this4._ngLocker.obtain(optionPath);
_this4._component.option(optionPath, newValue);
updateWatcher();
if (_this4._component._optionValuesEqual(optionPath, oldValue, newValue) && _this4._ngLocker.locked(optionPath)) {
_this4._ngLocker.release(optionPath)
}
};
var updateWatcher = function() {
var watchMethod = Array.isArray(_this4._scope.$eval(valuePath)) && !forcePlainWatchMethod ? "$watchCollection" : "$watch";
if (prevWatchMethod !== watchMethod) {
if (clearWatcher) {
clearWatcher()
}
clearWatcher = _this4._scope[watchMethod](valuePath, watchCallback, deepWatch);
prevWatchMethod = watchMethod
}
};
updateWatcher();
_this4._componentDisposing.add(clearWatcher)
});
this._optionChangedCallbacks.add(function(args) {
var optionName = args.name;
var fullName = args.fullName;
var component = args.component;
if (_this4._ngLocker.locked(fullName)) {
_this4._ngLocker.release(fullName);
return
}
if (!optionDependencies || !optionDependencies[optionName]) {
return
}
var isActivePhase = _this4._scope.$root.$$phase;
var obtainOption = function() {
_this4._ngLocker.obtain(fullName)
};
if (isActivePhase) {
_this4._digestCallbacks.begin.add(obtainOption)
} else {
obtainOption()
}
safeApply(function() {
each(optionDependencies[optionName], function(optionPath, valuePath) {
if (!_this4._optionsAreLinked(fullName, optionPath)) {
return
}
var value = component.option(optionPath);
_this4._parse(valuePath).assign(_this4._scope, value);
var scopeValue = _this4._parse(valuePath)(_this4._scope);
if (scopeValue !== value) {
args.component.option(optionPath, scopeValue)
}
})
}, _this4._scope);
var releaseOption = function releaseOption() {
if (_this4._ngLocker.locked(fullName)) {
_this4._ngLocker.release(fullName)
}
_this4._digestCallbacks.begin.remove(obtainOption);
_this4._digestCallbacks.end.remove(releaseOption)
};
if (isActivePhase) {
_this4._digestCallbacks.end.addPrioritized(releaseOption)
} else {
releaseOption()
}
})
},
_optionsAreNested: function(optionPath1, optionPath2) {
var parentSeparator = optionPath1[optionPath2.length];
return 0 === optionPath1.indexOf(optionPath2) && ("." === parentSeparator || "[" === parentSeparator)
},
_optionsAreLinked: function(optionPath1, optionPath2) {
if (optionPath1 === optionPath2) {
return true
}
return optionPath1.length > optionPath2.length ? this._optionsAreNested(optionPath1, optionPath2) : this._optionsAreNested(optionPath2, optionPath1)
},
_compilerByTemplate: function(template) {
var _this5 = this;
var scopeItemsPath = this._getScopeItemsPath();
return function(options) {
var $resultMarkup = (0, _renderer2.default)(template).clone();
var dataIsScope = options.model && options.model.constructor === _this5._scope.$root.constructor;
var templateScope = dataIsScope ? options.model : options.noModel ? _this5._scope : _this5._createScopeWithData(options);
if (scopeItemsPath) {
_this5._synchronizeScopes(templateScope, scopeItemsPath, options.index)
}
$resultMarkup.appendTo(options.container);
if (!options.noModel) {
_events_engine2.default.on($resultMarkup, "$destroy", function() {
var destroyAlreadyCalled = !templateScope.$parent;
if (destroyAlreadyCalled) {
return
}
templateScope.$destroy()
})
}
var ngTemplate = _this5._compile($resultMarkup, _this5._transcludeFn);
_this5._applyAsync(function(scope) {
ngTemplate(scope, null, {
parentBoundTranscludeFn: _this5._transcludeFn
})
}, templateScope);
return $resultMarkup
}
},
_applyAsync: function(func, scope) {
var _this6 = this;
func(scope);
if (!scope.$root.$$phase) {
if (!this._renderingTimer) {
this._renderingTimer = setTimeout(function() {
scope.$apply();
_this6._renderingTimer = null
})
}
this._componentDisposing.add(function() {
clearTimeout(_this6._renderingTimer)
})
}
},
_getScopeItemsPath: function() {
if (this._componentClass.subclassOf(_uiCollection_widget2.default) && this._ngOptions.bindingOptions && this._ngOptions.bindingOptions.items) {
return this._ngOptions.bindingOptions.items.dataPath
}
},
_createScopeWithData: function(options) {
var newScope = this._scope.$new();
if (this._itemAlias) {
newScope[this._itemAlias] = options.model
}
if (_type2.default.isDefined(options.index)) {
newScope.$index = options.index
}
return newScope
},
_synchronizeScopes: function(itemScope, parentPrefix, itemIndex) {
if (this._itemAlias && "object" !== _typeof(itemScope[this._itemAlias])) {
this._synchronizeScopeField({
parentScope: this._scope,
childScope: itemScope,
fieldPath: this._itemAlias,
parentPrefix: parentPrefix,
itemIndex: itemIndex
})
}
},
_synchronizeScopeField: function(args) {
var parentScope = args.parentScope;
var childScope = args.childScope;
var fieldPath = args.fieldPath;
var parentPrefix = args.parentPrefix;
var itemIndex = args.itemIndex;
var innerPathSuffix = fieldPath === this._itemAlias ? "" : "." + fieldPath;
var collectionField = void 0 !== itemIndex;
var optionOuterBag = [parentPrefix];
var optionOuterPath = void 0;
if (collectionField) {
if (!_type2.default.isNumeric(itemIndex)) {
return
}
optionOuterBag.push("[", itemIndex, "]")
}
optionOuterBag.push(innerPathSuffix);
optionOuterPath = optionOuterBag.join("");
var clearParentWatcher = parentScope.$watch(optionOuterPath, function(newValue, oldValue) {
if (newValue !== oldValue) {
compileSetter(fieldPath)(childScope, newValue)
}
});
var clearItemWatcher = childScope.$watch(fieldPath, function(newValue, oldValue) {
if (newValue !== oldValue) {
if (collectionField && !compileGetter(parentPrefix)(parentScope)[itemIndex]) {
clearItemWatcher();
return
}
compileSetter(optionOuterPath)(parentScope, newValue)
}
});
this._componentDisposing.add([clearParentWatcher, clearItemWatcher])
},
_evalOptions: function(scope) {
var _this8 = this;
var result = extendFromObject({}, this._ngOptions);
delete result.bindingOptions;
if (this._ngOptions.bindingOptions) {
each(this._ngOptions.bindingOptions, function(key, value) {
result[key] = scope.$eval(value.dataPath)
})
}
result._optionChangedCallbacks = this._optionChangedCallbacks;
result._disposingCallbacks = this._componentDisposing;
result.onActionCreated = function(component, action, config) {
if (config && inArray(config.category, SKIP_APPLY_ACTION_CATEGORIES) > -1) {
return action
}
var wrappedAction = function() {
var _this7 = this;
var args = arguments;
if (!scope || !scope.$root || scope.$root.$$phase) {
return action.apply(this, args)
}
return safeApply(function() {
return action.apply(_this7, args)
}, scope)
};
return wrappedAction
};
result.beforeActionExecute = result.onActionCreated;
result.nestedComponentOptions = function(component) {
return {
templatesRenderAsynchronously: component.option("templatesRenderAsynchronously"),
forceApplyBindings: component.option("forceApplyBindings"),
modelByElement: component.option("modelByElement"),
onActionCreated: component.option("onActionCreated"),
beforeActionExecute: component.option("beforeActionExecute"),
nestedComponentOptions: component.option("nestedComponentOptions")
}
};
result.templatesRenderAsynchronously = true;
if ((0, _config2.default)().wrapActionsBeforeExecute) {
result.forceApplyBindings = function() {
safeApply(function() {}, scope)
}
}
result.integrationOptions = {
createTemplate: function(element) {
return new _template2.default(element, _this8._compilerByTemplate.bind(_this8))
},
watchMethod: function(fn, callback, options) {
options = options || {};
var immediateValue = void 0;
var skipCallback = options.skipImmediate;
var disposeWatcher = scope.$watch(function() {
var value = fn();
if (value instanceof Date) {
value = value.valueOf()
}
return value
}, function(newValue) {
var isSameValue = immediateValue === newValue;
if (!skipCallback && (!isSameValue || isSameValue && options.deep)) {
callback(newValue)
}
skipCallback = false
}, options.deep);
if (!skipCallback) {
immediateValue = fn();
callback(immediateValue)
}
if ((0, _config2.default)().wrapActionsBeforeExecute) {
_this8._applyAsync(function() {}, scope)
}
return disposeWatcher
},
templates: {
"dx-polymorph-widget": {
render: function(options) {
var widgetName = options.model.widget;
if (!widgetName) {
return
}
if ("button" === widgetName || "tabs" === widgetName || "dropDownMenu" === widgetName) {
var deprecatedName = widgetName;
widgetName = _inflector2.default.camelize("dx-" + widgetName);
_errors2.default.log("W0001", "dxToolbar - 'widget' item field", deprecatedName, "16.1", "Use: '" + widgetName + "' instead")
}
var markup = (0, _renderer2.default)("<div>").attr(_inflector2.default.dasherize(widgetName), "options").get(0);
var newScope = _this8._scope.$new();
newScope.options = options.model.options;
options.container.append(markup);
_this8._compile(markup)(newScope)
}
}
}
};
result.modelByElement = function() {
return scope
};
return result
}
});
ComponentBuilder = ComponentBuilder.inherit({
ctor: function(options) {
this._componentName = options.componentName;
this._ngModel = options.ngModel;
this._ngModelController = options.ngModelController;
this.callBase.apply(this, arguments)
},
_isNgModelRequired: function() {
return (this._componentClass.subclassOf(_editor2.default) || this._componentClass.prototype instanceof _editor2.default) && this._ngModel
},
_initComponentBindings: function() {
this.callBase.apply(this, arguments);
this._initNgModelBinding()
},
_initNgModelBinding: function() {
var _this9 = this;
if (!this._isNgModelRequired()) {
return
}
var clearNgModelWatcher = this._scope.$watch(this._ngModel, function(newValue, oldValue) {
if (_this9._ngLocker.locked(NG_MODEL_OPTION)) {
return
}
if (newValue === oldValue) {
return
}
_this9._component.option(NG_MODEL_OPTION, newValue)
});
this._optionChangedCallbacks.add(function(args) {
_this9._ngLocker.obtain(NG_MODEL_OPTION);
try {
if (args.name !== NG_MODEL_OPTION) {
return
}
_this9._ngModelController.$setViewValue(args.value)
} finally {
if (_this9._ngLocker.locked(NG_MODEL_OPTION)) {
_this9._ngLocker.release(NG_MODEL_OPTION)
}
}
});
this._componentDisposing.add(clearNgModelWatcher)
},
_evalOptions: function() {
if (!this._isNgModelRequired()) {
return this.callBase.apply(this, arguments)
}
var result = this.callBase.apply(this, arguments);
result[NG_MODEL_OPTION] = this._parse(this._ngModel)(this._scope);
return result
}
});
var registeredComponents = {};
var registerComponentDirective = function(name) {
var priority = "dxValidator" !== name ? 1 : 10;
_module2.default.directive(name, ["$compile", "$parse", "dxDigestCallbacks", function($compile, $parse, dxDigestCallbacks) {
return {
restrict: "A",
require: "^?ngModel",
priority: priority,
compile: function($element) {
var componentClass = registeredComponents[name];
var $content = componentClass.subclassOf(_ui2.default) ? $element.contents().detach() : null;
return function(scope, $element, attrs, ngModelController, transcludeFn) {
$element.append($content);
safeApply(function() {
new ComponentBuilder({
componentClass: componentClass,
componentName: name,
compile: $compile,
parse: $parse,
$element: $element,
scope: scope,
ngOptionsString: attrs[name],
ngOptions: attrs[name] ? scope.$eval(attrs[name]) : {},
ngModel: attrs.ngModel,
ngModelController: ngModelController,
transcludeFn: transcludeFn,
itemAlias: attrs[ITEM_ALIAS_ATTRIBUTE_NAME],
dxDigestCallbacks: dxDigestCallbacks
})
}, scope)
}
}
}
}])
};
_component_registrator_callbacks2.default.add(function(name, componentClass) {
if (!registeredComponents[name]) {
registerComponentDirective(name)
}
registeredComponents[name] = componentClass
});