diff --git a/doc/ui-dialogs.md b/doc/ui-dialogs.md index 938a28e..b976476 100644 --- a/doc/ui-dialogs.md +++ b/doc/ui-dialogs.md @@ -2,7 +2,7 @@ wolf.ui extension add capacity for pop-up dialogs in an easy way. -the extensionadds the next tree dialogs functions to wolf.js object: +the extensionadds the next three dialogs functions to wolf.js object: - wolf.dialog, to load a dialog out of an html file. - wolf.messaeDialog, to show simple message dialgs. - wolf.uiDialog, to create dialogs out of wolf.js UI templates (need knowledge about wolf.js UI templates). @@ -15,7 +15,7 @@ - app-element is the parent element of the dialog, the root node of the aplication is recommended, but can be any node. - modal, boolean defining if the dialog is modal. -- dialog-data, dialog usage specific data, this type and maning depends on the dialog method used. See bottom sections. +- dialog-data, dialog usage specific data, this type and meaning depends on the dialog method used. See bottom sections. - buttons-definition, optional but recommended, a definition of the buttons shown in the footer of the application. - controller, controller object used to catch elements events, recommended, if not defined app-element controller will be used instead (except buttons-definitnion). - creation-callback, callback to be executed once the dialog is ready and on screen, the dialog element is passed as parameter. diff --git a/doc/wolf.binding.md b/doc/wolf.binding.md new file mode 100644 index 0000000..6abfd1c --- /dev/null +++ b/doc/wolf.binding.md @@ -0,0 +1,30 @@ +# NAVIGATOR + +TODO! + +# READ + +TODO! + +# WRITE +By default wolf framework does not write back the data on form inputs to the model when changes but there is a way to define it using the wolf:write attribute. + +The wolf:write attribute uses a string with up to tree parts separated by colon (:) character +the parts are: + + + +where: +· __event__ is the DOM event raised by the HTML element when data is edited (Ex: change event for input, or input event on contenteditable=true elements) can be omitted, by default is "change" +· __modelpath__ is the path in the model where the data will be writen, the path follows all the navigator rules, context path is used. +· __valuepath__ is the path from the element instance with the value to be saved, the path follows all the navigator rules. + +There is also special cases for wolf:write + +if wolf:write attribute is defined wihtout value or with a value of "" an automatic assignment logic is fired. Works for input elements with simple bindings + +if wolf:write is set to "none" then the wolf:write is not set for this input this key is needed to ignore elements when the wolf_write attribute is set to automatic on the framework configuration. + +## Automatic write configuration + +with __wolf.configuration.autoWriteBinding__ (default false) the wolf:write attribute is applied to all supported elements. \ No newline at end of file diff --git a/ui/wolf.ui.js b/ui/wolf.ui.js index 20e4176..d200e49 100644 --- a/ui/wolf.ui.js +++ b/ui/wolf.ui.js @@ -460,7 +460,7 @@ data.bindExecutor(element, null, null, - read => element.nodeValue = read({ element: element }, "string") + read => element.nodeValue = read({ element: element }) ); else element.nodeValue = data; @@ -475,7 +475,7 @@ data.bindExecutor(element, null, null, - read => element.setAttribute(k, read({ element: element }, "string")) + read => element.setAttribute(k, read({ element: element })) ); else element.setAttribute(k, data); diff --git a/wolf.js b/wolf.js index 238b491..80ca912 100644 --- a/wolf.js +++ b/wolf.js @@ -45,7 +45,8 @@ var K = (() => { var objs = {}; //Map of objects by url var configuration = { - trimTextNodes: true, + trimTextNodes: true, //Trim emtpy text nodes between elements + autoWriteBinding: false, //Install the write procedure on binded inputs }; /** @@ -395,7 +396,7 @@ var procName = part.substr(1); var fmt = processors[procName]; if (fmt) - fmt(pdata, value, context); + fmt(pdata, context, value); else throw new Error("Processor '" + procName + "' not found on set."); } else @@ -576,9 +577,8 @@ * Executes the binding and return the value * @param {*} [context] additional data * @param {element} [context.element] DOM element of data processed when calling from binding - * @param {string} [type] type of field if "string" undefined values will be returned as "" */ - function read(context, type) { + function read(context) { var value; var contextPath = context.element.getContextPath; for (var i in parts) { @@ -593,8 +593,6 @@ else if (v !== undefined)// If v is undefined no concatenation is done at all value = String(value) + v; } - if (type === "string" && (value === undefined || value === null)) - value = ""; return value; } @@ -631,7 +629,10 @@ node: textNode, read: null, write: function () { - textNode.nodeValue = read({ element: textNode }, "string"); + var value = read({ element: textNode }); + if (value === undefined || value === null) + value = ""; + textNode.nodeValue = value; } }); } @@ -648,7 +649,11 @@ node: element, read: null, write: function () { - element.setAttribute(attribute, read({ element: element }, "string")); + var value = read({ element: element }); + if (value === undefined || value === null || value === false) + element.removeAttribute(attribute); + else + element.setAttribute(attribute, value); } } } @@ -720,18 +725,27 @@ } /** - * Return the actual value reflected bi the binding for the specified element + * Return the actual value reflected by the binding for the specified element * @param {*} element DOM element */ function getValue(element) { return read({ element: element }) } + /** + * Return the actual value reflected by the binding for the specified element + * @param {*} element DOM element + */ + function getParts() { + return parts; + } + this.bindTextNode = bindTextNode; this.bindElementAttribute = bindElementAttribute; this.bindRepeater = bindRepeater; this.bindExecutor = bindExecutor; this.getValue = getValue; + this.getParts = getParts; } return { @@ -930,6 +944,62 @@ initTemplate: (template, value) => { template.$id = value; } + }, + + /** + * wolf:write + * for data write logic definition + */ + + "write": { + bindable: false, + processor: function (element, value, template, auto) { + if (value == "none") + return; + if (!value) { + if (template.$t == "input") { + var type = template.type; + if (type instanceof D.Binding) + type = type.getValue(element); + var path = template.value; + if (!(path instanceof D.Binding)) { + if (!auto) + console.warn("A binding is needed to autodetect write path"); + return; + } + path = path.getParts(); + if (path.length != 1 || !path[0].bind) { + console.warn("A complex binding can not be used to autodetect write path"); + return; + } + path = path[0].path; + switch (type) { + case "checkbox": + case "radio": + value = ["click", path, "checked"] + break; + default: + value = ["change", path, "value"] + } + } else { + if (!auto) + console.warn("Can not autodetect write method for element ", element); + return; + } + } else + value = value.split(':'); + if (value.length <= 2) + value = ["change", value[0], value[1] || "value"]; + element.addEventListener(value[0], evt => { + var ctx = { event: evt }; + var obj; + if (value[1] && value[1][0] == '/') + obj = D.getModel().getProperty(); + else + obj = element.getContextData(); + D.setProperty(obj, value[1], D.getProperty(element, value[2], ctx), ctx); + }); + } } } })(); @@ -1170,6 +1240,10 @@ else element.setAttribute(k, value); } + // install write events prior to install events + if (K.configuration.autoWriteBinding) + if (!template["wolf:write"]) //TODO: adjust wolf attributes on framework + wolfAttributes.write.processor(element, null, template, true); // process events function installEvent(event, method) { if (customController)