diff --git a/doc/wolf.binding.md b/doc/wolf.binding.md
index 6abfd1c..cb81293 100644
--- a/doc/wolf.binding.md
+++ b/doc/wolf.binding.md
@@ -1,11 +1,61 @@
-# NAVIGATOR
+# DATA NAVIGATOR
+
+Wolf.js expands the root object prototype with the navigate function, this navigate function allow datan path navigation with null controls and data processors execution.
+
+For examble with this object:
+
+ var data={
+ "author":"PMS",
+ "books":[
+ {
+ "title":"The very first",
+ "date":"12-12-1866",
+ "publishedBy":{
+ "name":"Ancient publisher"
+ }
+ }
+ ]
+ }
+
+is easy to get the name of the publisher of the first book with:
+
+ data.navigate("books/0/publishedBy/name");
+
+note the usage of the index in arrays.
+
+or the title:
+
+ data.navigate("books/0/title");
+
+but if the path refer to the next book or the first book does not exists this return undefined, and do not throw any errors.
+
+## NAVIGATOR PROCESSORS
TODO!
-# READ
+# MODEL
TODO!
+# READ & BIND
+
+Using the data navigator rules, any field or text node defined in the html between { and } will refer to this path and the data will be used instead of the text.
+
+if the binding is done in a HTML attribute and the result is null, undefined or empty string, the attribute will not be drawn on HTML.
+if it is a text node the text node will be empty.
+
+the binding can be mixed with literals:
+
+
And the winner is {winner}.
+
+or
+
+
+
+in this case a null or undefined data will have the same effect as an empty string.
+
+The reference between the HTML element and the data path is maintaned and handled in the way that any chagne to the model will update automatically the HTML on screen
+
# 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.
diff --git a/doc/wolf.fragments & templates.md b/doc/wolf.fragments & templates.md
new file mode 100755
index 0000000..bc860a6
--- /dev/null
+++ b/doc/wolf.fragments & templates.md
@@ -0,0 +1 @@
+TODO!
\ No newline at end of file
diff --git a/doc/wolf.introduction.md b/doc/wolf.introduction.md
new file mode 100755
index 0000000..cdd72e5
--- /dev/null
+++ b/doc/wolf.introduction.md
@@ -0,0 +1,3 @@
+# WOLF.JS
+
+TODO!
\ No newline at end of file
diff --git a/doc/wolf.navigation.md b/doc/wolf.navigation.md
new file mode 100755
index 0000000..52300d1
--- /dev/null
+++ b/doc/wolf.navigation.md
@@ -0,0 +1,56 @@
+# NAVIGATOR
+
+As the application can be divided into multiple fragments the fragment composition in screen can be automated with paths in the URL hash creating
+an effect of paths inside the page.
+
+For this wolf provide the Navigator object.
+
+A navigator can be created using:
+
+ wolf.createNavigator(element, "app/navigation.json", (navigator) => {
+ });
+
+The first parameter is the element that will handle the navigation this must be a framework managed element, the application root is recommended refer to [introduction](wolf.introduction.md).
+The second is the path of the navigation json containing all the navigation definitnion.
+The third is a callback, executed when the navigation is loaded and first navigation raised.
+
+## NAVIGATION PATH
+
+The navigator uses a path after the hash symbol in the url to create the ilusion of a filesystem based on path patterns.
+
+## NAVIGATION DEFINITION JSON
+
+The navigation file is a json object with the next structure
+
+ {
+ "":{
+ "pattern":"",
+ "set":{
+ // simple definition
+ "":"",
+ // extended definition
+ "":{
+ "to":"",
+ "event":"",
+ "then":{
+ //more elements to map once this fragment is ready, same structure as "set" node.
+ }
+ },
+ "event":""
+ }
+ }
+
+· is the id of the navigation, any navigation order will use this id.
+· is the path pattern to use for this navigation, can contain data parts, see path structure section below.
+· is the id of an element in the HTML that will hold the included html, refer to [introduction](wolf.introduction.md) for details about fragments and inclusion.
+· is the path of the html fragment file to include.
+· is the name of the event inside the loaded fragment controller that will be executed when this fragment is ready ignoring the status of any sub include.
+· is the name of the event inside the first element controller to be executed when all the navigation process is ready.
+
+Note: The "then" section on a extended definitnion will be processed only when the "to" file to include has been satisfied and all the new DOM ready.
+
+Note: If any of the event names have a "/" starting character, the event is executed on the application controller instead.
+
+## PATH STRUCTURE
+
+TODO!
\ No newline at end of file
diff --git a/wolf.js b/wolf.js
index 80ca912..3fae664 100644
--- a/wolf.js
+++ b/wolf.js
@@ -55,8 +55,9 @@
* passed prior to the object initialization function.
* @param {object} objd object definition
* @param {function} [callback] callback to be called once the object has been loaded
+ * @param {string} url url of instantiated code
*/
- function instantiate(objd, callback) {
+ function instantiate(objd, callback, url) {
var deps = {};
var constructor;
// ==== Process arguments
@@ -95,8 +96,13 @@
checkFinish();
}
}
+ function loadDependency(name) {
+ require(name, checkFactory(name), error => {
+ console.error("Error loading module '" + url + "', can not load dependency '" + name + "'.");
+ });
+ }
for (var i in deps)
- require(i, checkFactory(i));
+ loadDependency(i);
checkFinish();
}
@@ -106,18 +112,26 @@
* @param {function} [callback] callback to be called once the object has been loaded
* @param {fetcher_callfail} [callfail] callback to be called once the object has been loaded
*/
- function require(url, callback) {
+ function require(url, callback, callfail) {
if (!url)
return;
url = new URL(url, document.baseURI).href;
var obj = objs[url];
if (!obj) {
TOOLS.wGet(url, data => {
- var inc = Function(`'use strict';return ${data};\n//# sourceURL=${url}`);
+ try {
+ var inc = Function(`'use strict';return ${data};\n//# sourceURL=${url}`);
+ } catch (e) {
+ throw new Error("Error in module '" + url + "' parsing file: " + e.message);
+ }
instantiate(inc(), (lobj) => {
objs[url] = lobj;
callback && callback(lobj);
- });
+ }, url);
+ }, (error, stage) => {
+ if (error && error.status && error.status == 404)
+ console.error("Error loading module '" + url + "', not found on server.");
+ callfail && callfail(error, stage)
});
} else
callback && callback(obj);
@@ -830,6 +844,10 @@
template.$controller = template.controller;
delete template.controller;
}
+ if (template.forcecontroller) {
+ template.$forcecontroller = template.forcecontroller == "true";
+ delete template.forcecontroller;
+ }
/**
* Inserts the element into a parent element (replacing any content)
* @param {element} parentElement
@@ -842,7 +860,7 @@
parentElement.appendChild(nodes[i]);
var ptmpl = parentElement.getTemplate();
if (template.$controller)
- if (!ptmpl.$controller || ptmpl.$fragmentedController) {
+ if (!ptmpl.$controller || ptmpl.$fragmentedController || template.$forcecontroller) {
ptmpl.$controller = template.$controller;
ptmpl.$fragmentedController = true;
} else {
@@ -861,6 +879,9 @@
},
controller: {
bindable: false
+ },
+ forcecontroller: {
+ bindable: false
}
},
@@ -1626,35 +1647,55 @@
throw new Error(`Navigation "${id}" not defined.`)
current = { id: id, data: data };
var lh = new K.LoadHandler(() => {
- if (navEntry.event) {
- var eventName = navEntry.event;
- var ctrl;
- if (eventName[0] == '/') {
- eventName = eventName.substr(1);
- ctrl = lh.__elem.getApplicationController();
- } else
- ctrl = lh.__elem.getController();
- if (ctrl[eventName])
- ctrl[eventName](lh.__elem, id, data);
- }
+ if (navEntry.event)
+ callEvent(lh.__elem, navEntry.event);
for (var i in nav.onChange) try {
nav.onChange[i](id, data);
} catch { };
});
- if (navEntry.set) {
- for (var k in navEntry.set) {
- var dest = navEntry.set[k];
+ function callEvent(element, eventName) {
+ var ctrl;
+ if (eventName[0] == '/') {
+ eventName = eventName.substr(1);
+ ctrl = element.getApplicationController();
+ } else
+ ctrl = element.getController();
+ if (ctrl[eventName])
+ ctrl[eventName](lh.__elem, id, data);
+ else
+ console.error("Navigation event '" + eventName + "' doest not exists");
+ }
+
+ function navFragment(dest, elem) {
+ lh.enter();
+ loadFragmentTo(dest.to, elem, (templ, setElem) => {
+ lh.__elem = lh.__elem || setElem;
+ if (dest.then)
+ processSet(dest.then);
+ if (dest.event)
+ callEvent(setElem, dest.event);
+ lh.leave();
+ });
+ }
+
+ function processSet(navset) {
+ for (var k in navset) {
+ var dest = navset[k];
var elem = element.byId(k);
- if (elem) {
- lh.enter();
- loadFragmentTo(dest, elem, (templ, setElem) => {
- lh.__elem = setElem;
- lh.leave();
- });
- }
+ if (typeof dest === "string")
+ dest = { to: dest };
+ if (elem)
+ navFragment(dest, elem);
+ else
+ console.error("Navigation '" + id + "' not completed, element with id '" + k + "' not found")
}
- } else { lh.clear(); }
+ }
+
+ if (navEntry.set)
+ processSet(navEntry.set)
+ else
+ lh.clear();
}
/**
@@ -1914,8 +1955,12 @@
function fail(error, stage) {
if (callfail)
callfail(error, stage);
- else
- console.error(error, stage);
+ else {
+ if (error && error.status && error.status == 404)
+ console.error("Error loading '" + url + "', not found");
+ else
+ console.error(error, stage);
+ }
}
if (!url) {
fail(new Error("Missing url"), "init");