devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
222 lines (184 loc) • 9.06 kB
JavaScript
var $ = require("../../core/renderer"),
ko = require("knockout"),
Callbacks = require("../../core/utils/callbacks"),
errors = require("../../core/errors"),
inflector = require("../../core/utils/inflector"),
isPlainObject = require("../../core/utils/type").isPlainObject,
registerComponentCallbacks = require("../../core/component_registrator_callbacks"),
Widget = require("../../ui/widget/ui.widget"),
KoTemplate = require("./template"),
Editor = require("../../ui/editor/editor"),
Locker = require("../../core/utils/locker"),
config = require("../../core/config");
var LOCKS_DATA_KEY = "dxKoLocks",
CREATED_WITH_KO_DATA_KEY = "dxKoCreation";
var editorsBindingHandlers = [];
var registerComponentKoBinding = function registerComponentKoBinding(componentName, componentClass) {
if (componentClass.subclassOf(Editor)) {
editorsBindingHandlers.push(componentName);
}
ko.bindingHandlers[componentName] = {
init: function init(domNode, valueAccessor) {
var $element = $(domNode),
optionChangedCallbacks = Callbacks(),
optionsByReference = {},
component,
knockoutConfig = config().knockout,
isBindingPropertyPredicateName = knockoutConfig && knockoutConfig.isBindingPropertyPredicateName,
isBindingPropertyPredicate,
ctorOptions = {
onInitializing: function onInitializing() {
optionsByReference = this._getOptionsByReference();
ko.computed(function () {
var model = ko.unwrap(valueAccessor());
if (component) {
component.beginUpdate();
}
isBindingPropertyPredicate = isBindingPropertyPredicateName && model && model[isBindingPropertyPredicateName];
unwrapModel(model);
if (component) {
component.endUpdate();
}
}, null, { disposeWhenNodeIsRemoved: domNode });
component = this;
},
modelByElement: function modelByElement($element) {
if ($element.length) {
return ko.dataFor($element.get(0));
}
},
nestedComponentOptions: function nestedComponentOptions(component) {
return {
modelByElement: component.option("modelByElement"),
nestedComponentOptions: component.option("nestedComponentOptions")
};
},
_optionChangedCallbacks: optionChangedCallbacks,
integrationOptions: {
watchMethod: function watchMethod(fn, callback, options) {
options = options || {};
var skipCallback = options.skipImmediate;
var watcher = ko.computed(function () {
var newValue = ko.unwrap(fn());
if (!skipCallback) {
callback(newValue);
}
skipCallback = false;
});
return function () {
watcher.dispose();
};
},
templates: {
"dx-polymorph-widget": {
render: function render(options) {
var widgetName = ko.utils.unwrapObservable(options.model.widget);
if (!widgetName) {
return;
}
if (widgetName === "button" || widgetName === "tabs" || widgetName === "dropDownMenu") {
var deprecatedName = widgetName;
widgetName = inflector.camelize("dx-" + widgetName);
errors.log("W0001", "dxToolbar - 'widget' item field", deprecatedName, "16.1", "Use: '" + widgetName + "' instead");
}
var markup = $("<div>").attr("data-bind", widgetName + ": options").get(0);
$(options.container).append(markup);
ko.applyBindings(options.model, markup);
}
}
},
createTemplate: function createTemplate(element) {
return new KoTemplate(element);
}
}
},
optionNameToModelMap = {};
var applyModelValueToOption = function applyModelValueToOption(optionName, modelValue, unwrap) {
var locks = $element.data(LOCKS_DATA_KEY),
optionValue = unwrap ? ko.unwrap(modelValue) : modelValue;
if (ko.isWriteableObservable(modelValue)) {
optionNameToModelMap[optionName] = modelValue;
}
if (component) {
if (locks.locked(optionName)) {
return;
}
locks.obtain(optionName);
try {
if (ko.ignoreDependencies) {
ko.ignoreDependencies(component.option, component, [optionName, optionValue]);
} else {
component.option(optionName, optionValue);
}
} finally {
locks.release(optionName);
}
} else {
ctorOptions[optionName] = optionValue;
}
};
var handleOptionChanged = function handleOptionChanged(args) {
var optionName = args.fullName,
optionValue = args.value;
if (!(optionName in optionNameToModelMap)) {
return;
}
var $element = this._$element,
locks = $element.data(LOCKS_DATA_KEY);
if (locks.locked(optionName)) {
return;
}
locks.obtain(optionName);
try {
optionNameToModelMap[optionName](optionValue);
} finally {
locks.release(optionName);
}
};
var createComponent = function createComponent() {
optionChangedCallbacks.add(handleOptionChanged);
$element.data(CREATED_WITH_KO_DATA_KEY, true).data(LOCKS_DATA_KEY, new Locker());
new componentClass($element, ctorOptions);
ctorOptions = null;
};
var unwrapModelValue = function unwrapModelValue(currentModel, propertyName, propertyPath) {
if (propertyPath === isBindingPropertyPredicateName) {
return;
}
if (!isBindingPropertyPredicate || isBindingPropertyPredicate(propertyPath, propertyName, currentModel)) {
var unwrappedPropertyValue;
ko.computed(function () {
var propertyValue = currentModel[propertyName];
applyModelValueToOption(propertyPath, propertyValue, true);
unwrappedPropertyValue = ko.unwrap(propertyValue);
}, null, { disposeWhenNodeIsRemoved: domNode });
if (isPlainObject(unwrappedPropertyValue)) {
if (!optionsByReference[propertyPath]) {
unwrapModel(unwrappedPropertyValue, propertyPath);
}
}
} else {
applyModelValueToOption(propertyPath, currentModel[propertyName], false);
}
};
var unwrapModel = function unwrapModel(model, propertyPath) {
for (var propertyName in model) {
if (model.hasOwnProperty(propertyName)) {
unwrapModelValue(model, propertyName, propertyPath ? [propertyPath, propertyName].join(".") : propertyName);
}
}
};
createComponent();
return {
controlsDescendantBindings: componentClass.subclassOf(Widget)
};
}
};
if (componentName === "dxValidator") {
ko.bindingHandlers["dxValidator"].after = editorsBindingHandlers;
}
};
registerComponentCallbacks.add(function (name, componentClass) {
registerComponentKoBinding(name, componentClass);
});
;