Commit 700be286 authored by Sven Franck's avatar Sven Franck

app: switch to current version of app

parent 2a89df83
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
case "type": case "type":
case "rel": case "rel":
case "alt": case "alt":
case "src":
case "readonly": case "readonly":
case "size": case "size":
case "colspan": case "colspan":
...@@ -178,7 +179,7 @@ ...@@ -178,7 +179,7 @@
theme, icon_string, input_type, need_text_node, container_class_list, theme, icon_string, input_type, need_text_node, container_class_list,
label_class_list, index, disabled, active, text, addLabel, readonly, label_class_list, index, disabled, active, text, addLabel, readonly,
mask_set, mask, star, hidden_field, icon, no_validate, has_opts, mask_set, mask, star, hidden_field, icon, no_validate, has_opts,
push_label, no_text; push_label, no_text, label_set;
// exit early with a span tag // exit early with a span tag
// TODO: make this with label et al // TODO: make this with label et al
...@@ -269,7 +270,7 @@ ...@@ -269,7 +270,7 @@
// optionally wrap input in a div-fieldcontain // optionally wrap input in a div-fieldcontain
// NOTE: route is for custom HTML elements... service_instance_status // NOTE: route is for custom HTML elements... service_instance_status
if (!spec.logic.route && (spec.logic.wrap !== true || hidden_field)) { if (!spec.logic.route && (spec.logic.wrap !== true && spec.wrap !== true) || hidden_field) {
wrapper = document.createDocumentFragment(); wrapper = document.createDocumentFragment();
} else { } else {
wrapper = factory.element({ wrapper = factory.element({
...@@ -437,12 +438,14 @@ ...@@ -437,12 +438,14 @@
// This saves doing "invalid" handler with javascript // This saves doing "invalid" handler with javascript
if (spec.logic.add_label !== false && ((need_text_node === undefined && if (spec.logic.add_label !== false && ((need_text_node === undefined &&
(push_label || !label_inside) && !hidden_field) || spec.logic.route)) { (push_label || !label_inside) && !hidden_field) || spec.logic.route)) {
label_set = true;
label_target.appendChild(addLabel(spec, label_class_list)); label_target.appendChild(addLabel(spec, label_class_list));
} }
// add <span> which contains JQM current select // add <span> which contains JQM current select
if (element_reverse) { if (element_reverse) {
element_target.appendChild(factory.element({"type": "span"})); element_target.appendChild(factory.element({
"type": "span"}));
} else { } else {
element_target = container; element_target = container;
} }
...@@ -456,7 +459,7 @@ ...@@ -456,7 +459,7 @@
element_target.appendChild(factory.element(spec)); element_target.appendChild(factory.element(spec));
// checkbox radio need label after input // checkbox radio need label after input
if (label_inside) { if (label_inside && !label_set) {
label_target.appendChild(addLabel(spec, label_class_list)); label_target.appendChild(addLabel(spec, label_class_list));
} }
...@@ -466,9 +469,8 @@ ...@@ -466,9 +469,8 @@
if (!no_validate && !spec.logic.route) { if (!no_validate && !spec.logic.route) {
element_target.appendChild(factory.element({ element_target.appendChild(factory.element({
"type": "span", "type": "span",
"direct": {"className": "ui-invalid-label"}, "direct": {"className": "ui-invalid-label translate"},
"attributes": {"data-i18n":"validation_dict.required_field"}, "attributes": {"data-i18n":"validation_dict.required_field"}
"logic": {"text": "Ce champ est obligatoire."}
})); }));
} }
...@@ -540,7 +542,8 @@ ...@@ -540,7 +542,8 @@
* "title": "", * "title": "",
* "title_i18n": null, * "title_i18n": null,
* "theme": null, * "theme": null,
* "fix": true, * "fix_footer": null,
* "fix_header": null
* "create": null (added automatically) * "create": null (added automatically)
* "data_url": null (added automatically) * "data_url": null (added automatically)
* "fragment_list": [] (added automatically) * "fragment_list": [] (added automatically)
...@@ -560,14 +563,13 @@ ...@@ -560,14 +563,13 @@
// new page // new page
if (container === null || spec.create === true) { if (container === null || spec.create === true) {
container = factory.element({ container = factory.element({
"type": "div", "type": "div",
"direct": { "direct": {
"className": " ui-page " + ("ui-page-theme-" + "className": " ui-page " + ("ui-page-theme-" +
spec.theme || "") + " " + ((spec.fix && spec.theme || "") + " " +
spec.fix === false) ? "" : (spec.fix_header ? " ui-page-header-fixed" : " ") +
" ui-page-header-fixed ui-page-footer-fixed") (spec.fix_footer ? " ui-page-footer-fixed" : " ")
}, },
"attributes": { "attributes": {
"data-role": "page", "data-role": "page",
...@@ -927,7 +929,7 @@ ...@@ -927,7 +929,7 @@
"direct": { "direct": {
"id": id, "id": id,
"className": (spec.class_list || " ") + "className": (spec.class_list || " ") +
(spec.fixed ? " ui-header-fixed " : " ") + " bar ui-header foo " + (spec.fixed ? " ui-header-fixed " : " ") + " ui-header " +
" slidedown ui-bar-" + (spec.theme || "inherit") " slidedown ui-bar-" + (spec.theme || "inherit")
}, },
"attributes": { "attributes": {
...@@ -995,6 +997,7 @@ ...@@ -995,6 +997,7 @@
direction = spec.direction || "vertical"; direction = spec.direction || "vertical";
// NOTE: will only be used for dynamic element creation // NOTE: will only be used for dynamic element creation
// TODO: what does this do here?
generator = function (generator_spec) { generator = function (generator_spec) {
var element = generator_spec.item; var element = generator_spec.item;
// TODO: no! // TODO: no!
...@@ -1011,6 +1014,7 @@ ...@@ -1011,6 +1014,7 @@
// controlgroup label // controlgroup label
if (spec.label) { if (spec.label) {
// TODO: how to get required on the legend? or off?
// NOTE: this will always wrap controlgroups!!! // NOTE: this will always wrap controlgroups!!!
i18n = spec.label.title_i18n || spec.label.text_i18n; i18n = spec.label.title_i18n || spec.label.text_i18n;
contain = factory.element({ contain = factory.element({
...@@ -1028,9 +1032,11 @@ ...@@ -1028,9 +1032,11 @@
}); });
label.appendChild(factory.element({ label.appendChild(factory.element({
"type": "legend", "type": "legend",
"logic": { "direct": {
"text": spec.label.text, "className": "translate required_label"
"data-i18n": i18n ? (spec.label.text_i18n) : null },
"attributes": {
"data-i18n": spec.label.text_i18n
} }
})); }));
contain.appendChild(label); contain.appendChild(label);
...@@ -1049,7 +1055,10 @@ ...@@ -1049,7 +1055,10 @@
"data-enhanced": "true", "data-enhanced": "true",
"data-type": direction "data-type": direction
}, },
"logic": {"id": spec.id || null} "logic": {
"id": spec.id || null,
"data-persist": spec.persist || null
}
}); });
// controls // controls
...@@ -1335,8 +1344,8 @@ ...@@ -1335,8 +1344,8 @@
"direct": { "direct": {
"className": class_list "className": class_list
}, },
"attributes": {},
"logic": { "logic": {
"data-persist": spec.persist || null,
"data-wrap": slot ? null : true, "data-wrap": slot ? null : true,
"data-slot": slot ? true : null, "data-slot": slot ? true : null,
"data-slot-id": slot || null, "data-slot-id": slot || null,
...@@ -1477,6 +1486,9 @@ ...@@ -1477,6 +1486,9 @@
container = document.createDocumentFragment(); container = document.createDocumentFragment();
form_id = "form_" + util.uuid(); form_id = "form_" + util.uuid();
item_id = spec.data ? (spec.data._id || undefined) : undefined; item_id = spec.data ? (spec.data._id || undefined) : undefined;
if (spec.update) {
form = document.createDocumentFragment();
} else {
form = factory.element({ form = factory.element({
"type": "form", "type": "form",
"direct": { "direct": {
...@@ -1485,13 +1497,17 @@ ...@@ -1485,13 +1497,17 @@
"action": "#", "action": "#",
"className": (spec.class_list || "") "className": (spec.class_list || "")
}, },
"attributes": {"data-ajax": false, "autocomplete": "off"}, "attributes": {
"data-ajax": false,
"autocomplete": "off",
"data-widget": "form"
},
"logic": { "logic": {
"data-reference": spec.reference || null, "data-reference": spec.reference || null,
"data-depend": spec.depend || null, "data-map": spec.map_children || null
"data-reset": spec.reset || null
} }
}); });
}
// NOTE: needed to differentiate between PUT/POST // NOTE: needed to differentiate between PUT/POST
// TODO: block_identifier is only used for release_install, find better! // TODO: block_identifier is only used for release_install, find better!
...@@ -1826,6 +1842,7 @@ ...@@ -1826,6 +1842,7 @@
*/ */
// TODO: add collapsible support if needed // TODO: add collapsible support if needed
// TODO: dividers? will not be in spec, so can only be listview option! // TODO: dividers? will not be in spec, so can only be listview option!
// TODO: find better way to set mapper/widget
factory.widget.listview = function (spec) { factory.widget.listview = function (spec) {
var fragment, has_filter, generator; var fragment, has_filter, generator;
...@@ -1916,25 +1933,17 @@ ...@@ -1916,25 +1933,17 @@
// search filter // search filter
if (spec.update !== true) { if (spec.update !== true) {
// NOTE: if input provided, the filter is already there! // NOTE: if input provided, the filter is already there!
if (spec.filter && spec.input === undefined) { // THIS MAKES B
if (spec.filter && !spec.input) {
has_filter = true; has_filter = true;
fragment.appendChild(factory.widget.formElement({ fragment.appendChild(factory.widget.formElement(
"type": "input", factory.util.searchBarTemplate({
"direct": { "search_id": spec.id || "search",
"id": "filter_" + (spec.id || "items"), "text": spec.text || "",
"className": "action" "text_i18n": spec.text_i18n || null
}, })
"attributes": {
"data-action": "search", ));
"data-enhanced": true,
"data-i18n": "",
"placeholder": "Search",
"data-icon": "search"
},
"logic": {
"clear": "true"
}
}));
} }
fragment.appendChild(factory.element({ fragment.appendChild(factory.element({
...@@ -1944,18 +1953,22 @@ ...@@ -1944,18 +1953,22 @@
(spec.inset ? (spec.inset ?
" ui-listview-inset ui-corner-all ui-shadow " : "") " ui-listview-inset ui-corner-all ui-shadow " : "")
}, },
"attributes": {"data-role": "listview", "data-enhanced": true}, "attributes": {
"data-role": "listview",
"data-enhanced": true,
// NOTE: on updates, we need wrapper with generator and mapper???
"data-widget": "listview"
},
"logic": { "logic": {
"id": spec.id || null, "id": spec.id || null,
"data-update": spec.dynamic ? true : null, "data-update": spec.dynamic ? true : null,
// NOTE: on updates, we need wrapper with generator...
"data-widget": "listview",
"data-reference": spec.reference || null, "data-reference": spec.reference || null,
"data-filter": spec.filter || null, "data-filter": spec.filter || null,
"data-input": spec.input || null, "data-input": spec.input || null,
"data-filter-theme": spec.filter_theme || null, "data-filter-theme": spec.filter_theme || null,
"data-filter-placeholder": spec.placeholder || null, "data-filter-placeholder": spec.placeholder || null,
"data-divider-theme": spec.divider_theme || null "data-divider-theme": spec.divider_theme || null,
"data-map": spec.map_children || null
} }
})); }));
} }
...@@ -2037,8 +2050,7 @@ ...@@ -2037,8 +2050,7 @@
*/ */
// TODO: pre-enhance! // TODO: pre-enhance!
factory.widget.table = function (spec) { factory.widget.table = function (spec) {
var fragment, container, generator, counter, target, section, i, tag, var fragment, container, generator, counter, section, i, tag, image;
image;
counter = function (scheme) { counter = function (scheme) {
var m, field, k; var m, field, k;
...@@ -2060,13 +2072,6 @@ ...@@ -2060,13 +2072,6 @@
return config.text; return config.text;
}; };
target = function () {
return factory.widget.controlbar({
"wrap": "section",
"class_list": "span_1"
});
};
generator = function (generator_spec) { generator = function (generator_spec) {
var quirk_dict, row, temp, cell, j, field, link, logic, faux_id, var quirk_dict, row, temp, cell, j, field, link, logic, faux_id,
attributes, property, snippet, title, k, button, group, dict, set, attributes, property, snippet, title, k, button, group, dict, set,
...@@ -2291,9 +2296,12 @@ ...@@ -2291,9 +2296,12 @@
case "header": case "header":
tag = factory.element({"type": "thead"}); tag = factory.element({"type": "thead"});
tag.appendChild( tag.appendChild(
generator(section.field_list, { generator({
"wrap": true, "item":section.field_list,
"property_dict": spec "wrapper": {
"property_dict": spec,
"wrap": true
}
}).content }).content
); );
container.appendChild(tag); container.appendChild(tag);
...@@ -2304,22 +2312,21 @@ ...@@ -2304,22 +2312,21 @@
"attributes": { "attributes": {
"data-update": "true", "data-update": "true",
"data-widget": "table" "data-widget": "table"
} },
"logic": {"data-map": spec.map_children || null}
})); }));
break; break;
} }
} }
fragment.appendChild(container); fragment.appendChild(container);
} }
return { return {
"fragment": fragment, "fragment": fragment,
"child_selector": fragment.querySelector("tbody"), "child_selector": fragment.querySelector("tbody"),
"child_constructor": generator, "child_constructor": generator,
"child_mapper": spec.map_children, "child_mapper": spec.map_children,
"base": "tr", "base": "tr",
"count": counter, "count": counter
"target": target
}; };
}; };
...@@ -2411,9 +2418,9 @@ ...@@ -2411,9 +2418,9 @@
for (section in config) { for (section in config) {
if (config.hasOwnProperty(section)) { if (config.hasOwnProperty(section)) {
arr = config[section]; arr = config[section];
if (typeof arr === "object" && arr !== null) { if (typeof arr === "object" && arr !== null) {
len = arr.length; for (k = 0, len = arr.length; k < len; k += 1) {
for (k = 0; k < len; k += 1) {
block = arr[k]; block = arr[k];
content = factory.util.generateContentElement( content = factory.util.generateContentElement(
block.type, block.type,
...@@ -2431,6 +2438,7 @@ ...@@ -2431,6 +2438,7 @@
} }
} }
} }
// TODO: return an object...
return [fragment, appendix, class_string]; return [fragment, appendix, class_string];
}; };
...@@ -2493,10 +2501,10 @@ ...@@ -2493,10 +2501,10 @@
"type": "span", "type": "span",
"direct": { "direct": {
"className": "ui-li-icon ui-li-icon-custom ui-icon-" + "className": "ui-li-icon ui-li-icon-custom ui-icon-" +
spec.icon + " ui-icon" (spec.icon || spec.value) + " ui-icon"
}, },
"logic": {"text": "\u00A0"} "logic": {"text": "\u00A0"}
}), "ui-li-has-icon"]; }), " ui-li-has-icon"];
// main link, split button // main link, split button
// TODO: make icon generic! what about util.class_string // TODO: make icon generic! what about util.class_string
...@@ -2683,7 +2691,9 @@ ...@@ -2683,7 +2691,9 @@
string = ""; string = "";
// NOTE: we only set on <a> // NOTE: we only set on <a>
if (element.type === "a") { // TODO: find a better way than to run everything through here...!
if (element.type === "a" ||
(element.attributes && element.attributes.type === "submit")) {
icon = (element.attributes || {})["data-icon"] || default_icon; icon = (element.attributes || {})["data-icon"] || default_icon;
// because of custom a in service_instance_status! // because of custom a in service_instance_status!
if (!(element.logic || {}).plain_link) { if (!(element.logic || {}).plain_link) {
...@@ -2702,38 +2712,52 @@ ...@@ -2702,38 +2712,52 @@
return string; return string;
}; };
/** Generate a seach bar (controlbar) /** Generate a configuration object for a search input
* @method searchBar * @method searchBar
* @param {object} spec Pagination configuration * @param {object} spec Search bar configuration
* @return {object} finished config object * @return {object} finished search bar config
**/ **/
factory.util.searchBar = function (spec) { factory.util.searchBarTemplate = function (spec) {
var i, element_list, search_id, props, class_list; return {
search_id = "search_" + util.uuid();
class_list = spec.class_list || "";
props = spec.slot ? {"slot": spec.slot} : {};
element_list = [{
"type": "input", "type": "input",
"direct": {"id": search_id, "className": "translate"}, "direct": {"id": spec.search_id, "className": "translate"},
"attributes": { "attributes": {
"data-action": "search", "data-action": "search",
"data-enhanced": "true", "data-enhanced": "true",
"data-i18n": "[placeholder]" + spec.text_i18n,
"placeholder": spec.text, "placeholder": spec.text,
"data-icon": "search", "data-icon": "search",
"data-action-btn": "true", "data-action-btn": "true",
"data-type": "search", "data-type": "search",
"type": "search" "type": "search"
}, },
"logic": {"clear": "true", "action": "search"} "logic": {
}]; "clear": "true",
"action": "search",
"data-i18n": spec.text_i18n ?
("[placeholder]" + spec.text_i18n) : null
}
};
};
for (i = 0; i < spec.info_list.length; i += 1) { /** Generate a seach bar (controlbar)
* @method searchBar
* @param {object} spec Pagination configuration
* @return {object} finished config object
**/
factory.util.searchBar = function (spec) {
var i, element_list, search_id, props, class_list, spec_list;
search_id = spec.search_id = "search_" + util.uuid();
props = spec.slot ? {"slot": spec.slot} : {};
props.class_list = spec.class_list || "";
element_list = [factory.util.searchBarTemplate(spec)];
spec_list = spec.info_list || [];
for (i = 0; i < spec_list.length; i += 1) {
element_list.push({ element_list.push({
"type": "div", "type": "div",
"direct": {"className": "info"}, "direct": {"className": "info"},
"attributes": {"data-info": spec.info_list[i]} "attributes": {"data-info": spec_list[i]}
}); });
} }
...@@ -2741,7 +2765,6 @@ ...@@ -2741,7 +2765,6 @@
"config": { "config": {
"generate": "widget", "generate": "widget",
"type": "controlbar", "type": "controlbar",
"class_list": class_list,
"property_dict": props, "property_dict": props,
"children": element_list "children": element_list
}, },
...@@ -2750,19 +2773,21 @@ ...@@ -2750,19 +2773,21 @@
}; };
/** Generate a pagination toolbar (controlbar) /** Generate a pagination toolbar (controlbar)
* @method paginate * @method paginationBar
* @param {object} spec Pagination configuration * @param {object} spec Pagination configuration
* @return {object} finished config object * @return {object} finished config object
**/ **/
// TODO: make this a real widget with methods!
factory.util.paginationBar = function (spec) { factory.util.paginationBar = function (spec) {
var n, option, props, option_list, class_list, config; var n, option, props, option_list, config, len, opts, pointer;
option_list = [{"value": "", "text": "", "text_i18n": ""}]; option_list = [{"value": "", "text": "", "text_i18n": ""}];
opts = spec.option_list || [];
props = spec.slot ? {"slot": spec.slot} : {}; props = spec.slot ? {"slot": spec.slot} : {};
class_list = spec.class_list || ""; props.class_list = spec.class_list || "";
for (n = 0; n < spec.option_list.length; n += 1) { for (n = 0, len = opts.length; n < len; n += 1) {
option = spec.option_list[n]; option = opts[n];
option_list.push({ option_list.push({
"value": option.value, "value": option.value,
"text": option.text, "text": option.text,
...@@ -2773,13 +2798,20 @@ ...@@ -2773,13 +2798,20 @@
config = { config = {
"generate": "widget", "generate": "widget",
"type": "controlbar", "type": "controlbar",
"class_list": class_list,
"property_dict": props, "property_dict": props,
"children": [{ "children": [{
"generate": "widget", "generate": "widget",
"type": "controlgroup", "type": "controlgroup",
"property_dict": {"direction": "horizontal"}, "property_dict": {"direction": "horizontal"},
"children": [{ "children": []
}]
};
pointer = config.children[0].children;
// first
if (!spec.single) {
config.children[0].property_dict.class_list = "ui-pagination-single";
pointer.push({
"type": "a", "type": "a",
"direct": {"className": "action", "href": "#"}, "direct": {"className": "action", "href": "#"},
"attributes": { "attributes": {
...@@ -2789,7 +2821,11 @@ ...@@ -2789,7 +2821,11 @@
"data-iconpos": "notext" "data-iconpos": "notext"
}, },
"logic": {"text": "First"} "logic": {"text": "First"}
}, { });
}
// always add previous
pointer.push({
"type": "a", "type": "a",
"direct": {"className": "action", "href": "#"}, "direct": {"className": "action", "href": "#"},
"attributes": { "attributes": {
...@@ -2799,7 +2835,11 @@ ...@@ -2799,7 +2835,11 @@
"data-iconpos": "notext" "data-iconpos": "notext"
}, },
"logic": {"text": "Previous"} "logic": {"text": "Previous"}
}, { });
// select
if (len > 0) {
pointer.push({
"type": "select", "type": "select",
"direct": {"id": "select_" + util.uuid(), "className": "action"}, "direct": {"id": "select_" + util.uuid(), "className": "action"},
"attributes": { "attributes": {
...@@ -2808,7 +2848,11 @@ ...@@ -2808,7 +2848,11 @@
"data-iconpos": "notext" "data-iconpos": "notext"
}, },
"logic": {"options": option_list} "logic": {"options": option_list}
}, { });
}
// always add next
pointer.push({
"type": "a", "type": "a",
"direct": {"className": "action", "href": "#"}, "direct": {"className": "action", "href": "#"},
"attributes": { "attributes": {
...@@ -2818,13 +2862,11 @@ ...@@ -2818,13 +2862,11 @@
"data-iconpos": "notext" "data-iconpos": "notext"
}, },
"logic": {"text": "Next"} "logic": {"text": "Next"}
}] });
}]
};
// only add last button, if total is available // only add last button, if total is available
if (!app.storage_dict.property_dict.skip_total_records) { if (!app.storage_dict.property_dict.skip_total_records && !spec.single) {
config.children[0].children.push({ pointer.push({
"type": "a", "type": "a",
"direct": {"className": "action", "href": "#"}, "direct": {"className": "action", "href": "#"},
"attributes": { "attributes": {
...@@ -2941,20 +2983,113 @@ ...@@ -2941,20 +2983,113 @@
// content.set..., no need for dynamic content and pointer // content.set..., no need for dynamic content and pointer
map.actions = { map.actions = {
"set_search": function (obj) { /**
factory.util.setDynamicPointer(obj, "ui_panel_detail_search"); * POST an object
* @method new
* @param {object} obj Action Object
**/
"new": function (obj) {
storage.write(obj)
.then(function (response) {
app.util.loader("", "status_dict.saved", "check");
app.navigate(obj, response);
})
.fail(function (error) {
switch (error.status) {
case 408: app.util.loader("", "status_dict.timeout", "clock-o"); break;
case 400: app.util.loader("", "validation_dict.general", "ban"); break;
default: app.util.loader("", "status_dict.error", "ban"); break;
}
});
}, },
"set_filter": function (obj) { /**
factory.util.setDynamicPointer(obj, "ui_panel_groups"); * GET an object
* @method get
* @param {object} obj Action Object
**/
"get": function (obj) {
storage.fetch(obj);
}, },
"set_sorting": function (obj) { /**
factory.util.setDynamicPointer(obj, "ui_panel_sort"); * PUT an object
* @method update
* @param {object} obj Action Object
**/
"update": function (obj) {
storage.write(obj)
.then(function (response) {
app.util.loader("", "status_dict.saved", "check");
app.navigate(obj, response);
})
.fail(function (error) {
switch (error.status) {
case 408: app.util.loader("", "status_dict.timeout", "clock-o"); break;
case 400: app.util.loader("", "validation_dict.general", "ban"); break;
default: app.util.loader("", "status_dict.error", "ban"); break;
}
});
}, },
"set_sales": function (obj) { /**
factory.util.setDynamicPointer(obj, "ui_panel_sales"); * Same as put but since there is no time to make dyno interaction, we cheat!
* @method update
* @param {object} obj Action Object
**/
"update_custom": function (obj) {
storage.write(obj)
.then(function (response) {
var i, len, dyno_list, dyno, promise_list, dump;
// clear active page, because we need to reload
dump = document.querySelector("div.ui-content");
util.deleteChildren(dump);
// refresh dynos that are left!
dyno_list = document.querySelectorAll("div.dyno");
// set first page to reload and clean it up!
delete app.deeplink_flag;
promise_list = [];
for (i = 0, len = dyno_list.length; i < len; i += 1) {
dyno = dyno_list[i];
// update gadgets
promise_list[i] = app.content.set(
{
"portal_type_source": dyno.state.type,
"portal_type_title": dyno.state.title,
"property_dict": util.mergeObject(
{"dynamic": true},
dyno.state.dyno_dict),
"scheme": dyno.state.scheme
},
{
"reference": dyno.id,
"href": dyno.state.href,
"fragment_list": dyno.state.fragment_list,
"layout_level": dyno.state.layout_level
},
false
)
.fail(app.util.error);
}
return RSVP.all(promise_list)
.then(function (response_list) {
app.util.loader("", "status_dict.saved", "check");
//app.navigate(obj, response);
})
.fail(app.util.error);
})
.then(app.setPageBindings)
.fail(function (error) {
switch (error.status) {
case 408: app.util.loader("", "status_dict.timeout", "clock-o"); break;
case 400: app.util.loader("", "validation_dict.general", "ban"); break;
default: app.util.loader("", "status_dict.error", "ban"); break;
}
});
}, },
/** /**
...@@ -2979,14 +3114,14 @@ ...@@ -2979,14 +3114,14 @@
* @param {object} nodeList Nodelist to translate * @param {object} nodeList Nodelist to translate
* @param {boolean} single Single element * @param {boolean} single Single element
**/ **/
// TODO: no solution yet for selectMenu-refesh and input (submit/reset/btn) // TODO: don't call this so often on init
"translateNodeList": function (nodeList, single) { "translateNodeList": function (nodeList, single) {
var i, l, element, lookup, targets, target, route_text, elements; var i, l, element, lookup, targets, target, route_text, elements, len;
elements = single ? [nodeList] : nodeList.querySelectorAll(".translate"); elements = single ? [nodeList] : nodeList.querySelectorAll(".translate");
if (i18n) { if (i18n) {
for (i = 0; i < elements.length; i += 1) { for (i = 0, len = elements.length; i < len; i += 1) {
element = elements[i]; element = elements[i];
lookup = element.getAttribute("data-i18n"); lookup = element.getAttribute("data-i18n");
...@@ -3032,14 +3167,19 @@ ...@@ -3032,14 +3167,19 @@
break; break;
default: default:
// NOTE: empty - setting .translate on a wrapper will empty it // NOTE: empty - setting .translate on a wrapper will empty it
while (element.hasChildNodes()) { util.deleteChildren(element);
element.removeChild(element.firstChild);
}
element.appendChild(document.createTextNode(i18n.t(target[0]))); element.appendChild(document.createTextNode(i18n.t(target[0])));
break; break;
} }
} }
} }
// handle select > span!
if (element.tagName === "OPTION") {
if (element.selected && element.parentNode.previousSibling) {
element.parentNode.previousSibling.textContent =
element.textContent;
}
}
} }
} else { } else {
app.util.error("Translate NodeList - i18n not defined"); app.util.error("Translate NodeList - i18n not defined");
...@@ -3063,8 +3203,8 @@ ...@@ -3063,8 +3203,8 @@
current_language = $.i18n.lng(), current_language = $.i18n.lng(),
shortcut = function (language) { shortcut = function (language) {
switch (language) { switch (language) {
case "zh-CN": case "fr-FR":
return "flag-cn"; return "flag-fr";
case "en-EN": case "en-EN":
return "flag-en"; return "flag-en";
} }
...@@ -3099,42 +3239,6 @@ ...@@ -3099,42 +3239,6 @@
} }
}, },
/**
* Show jumps popup
* @method jump
* @param {object} obj Action Object
**/
"browse": function (obj) {
factory.util.setDynamicPointer(obj, "browse");
},
/**
* Show task popup
* @method tasks
* @param {object} obj Action Object
**/
"tasks": function (obj) {
factory.util.setDynamicPointer(obj, "tasks");
},
/**
* Show application popup
* @method login
* @param {object} obj Action Object
**/
"login": function (obj) {
factory.util.setDynamicPointer(obj, "login");
},
/**
* Show export popup
* @method export
* @param {object} obj Action Object
**/
"export": function (obj) {
factory.util.setDynamicPointer(obj, "export");
},
/** /**
* Generic pagination method changing number of records displayed * Generic pagination method changing number of records displayed
* @method limit * @method limit
...@@ -3316,14 +3420,19 @@ ...@@ -3316,14 +3420,19 @@
}) })
.fail(app.util.error); .fail(app.util.error);
} }
return RSVP.resolve(wrapper.child_constructor({ return RSVP.resolve(wrapper.child_constructor({
"item": element, "item": element,
"wrapper": wrapper, "wrapper": wrapper,
"count": i "count": i
})); }));
} }
// NOTE: when loading content via href, element is set to undefined // NOTE: when loading content via href, element is set to undefined
// TODO: Why? ^^^^^^
// NOTE: fetch subordinate fields
if (element && element.needs_subordination) {
return app.util.setSubordinate(element, wrapper);
}
return RSVP.resolve(element || wrapper.inherit); return RSVP.resolve(element || wrapper.inherit);
}; };
...@@ -3339,12 +3448,14 @@ ...@@ -3339,12 +3448,14 @@
// TODO: multiple header rows! // TODO: multiple header rows!
// TODO: action_menu input + form? // TODO: action_menu input + form?
// TODO: how to handle translations of record texts? // TODO: how to handle translations of record texts?
// TODO: subordinate handling
// TODO: pick translations from field_dict for header!
map.tableItem = function (spec) { map.tableItem = function (spec) {
var j, k, segment, row, cell, id, quirk_dict, record, new_item, item; var j, k, segment, row, cell, id, quirk_dict, record, new_item, item;
quirk_dict = spec.parent.property_dict; quirk_dict = spec.wrapper.property_dict;
item = spec.item; item = spec.item;
record = item.doc; record = item.doc || {};
id = record[quirk_dict.link_identifier] || record._id || item._id; id = record[quirk_dict.link_identifier] || record._id || item._id;
new_item = {}; new_item = {};
...@@ -3396,17 +3507,20 @@ ...@@ -3396,17 +3507,20 @@
**/ **/
// TODO: move radio/check into property_dict and item? or do same on tableItem // TODO: move radio/check into property_dict and item? or do same on tableItem
// TODO: not nice & find better handling for text elements and i18n tags // TODO: not nice & find better handling for text elements and i18n tags
// TODO: subordinated fields should have links, not id only!!!
// NOTE: make sure there is no "id" flying through here!!! only _id // NOTE: make sure there is no "id" flying through here!!! only _id
map.listItem = function (spec) { map.listItem = function (spec) {
var quirk_dict, section, pos, label, j, k, field, setter, record, new_item, var quirk_dict, section, label, j, k, field, setter, record, new_item,
id, key, obj, translation_fields, item; id, key, translation_fields, item, relation, promise_list, pass, count;
promise_list = [];
translation_fields = "titletextlabel"; translation_fields = "titletextlabel";
quirk_dict = spec.wrapper.property_dict; quirk_dict = spec.wrapper.property_dict;
item = spec.item; item = spec.item;
record = item.doc; record = item.doc;
id = record[quirk_dict.link_identifier] || record._id || item._id; id = record[quirk_dict.link_identifier] || record._id || item._id;
new_item = {}; new_item = {};
count = 0;
// radio // radio
if (quirk_dict.radio) { if (quirk_dict.radio) {
...@@ -3435,27 +3549,58 @@ ...@@ -3435,27 +3549,58 @@
// loop scheme sections // loop scheme sections
for (j = 0; j < item.scheme.length; j += 1) { for (j = 0; j < item.scheme.length; j += 1) {
section = item.scheme[j]; section = item.scheme[j];
pos = section.position;
new_item[pos] = new_item[pos] || [];
// loop scheme fields // loop scheme fields
for (k = 0; k < section.field_list.length; k += 1) { for (k = 0; k < section.field_list.length; k += 1) {
field = section.field_list[k]; field = section.field_list[k];
key = field.value || field.field || "";
relation = key.split("subordinate_");
pass = {
"record": record,
"position": section.position,
"key": key,
"field": field,
"text_element": translation_fields.indexOf(key) > -1
};
// fetch values of subordinate fields via query or flux/memory
if (relation.length > 1) {
pass.relation = record[key];
pass.subordinate = relation[1];
promise_list[count + k] = storage.subordinate(pass);
} else {
pass.value = util.generateText(record[key], field, record);
promise_list[count + k] = RSVP.resolve(pass);
}
}
count += k;
}
return RSVP.all(promise_list)
.then(function(response_list) {
var l, len, response, obj, setter, pos;
for (l = 0, len = response_list.length; l < len; l += 1) {
response = response_list[l];
pos = response.position;
obj = {}; obj = {};
key = field.value || field.field; new_item[pos] = new_item[pos] || [];
if (translation_fields.indexOf(key) > -1) { // text/label/... all stuff translateable
if (response.text_element) {
obj[response.key + "_18n"] = record[response.key + "_i18n"];
setter = key; setter = key;
obj[setter + "_i18n"] = record[key + "_i18n"];
} else { } else {
setter = "value"; setter = "value";
} }
obj[setter] = util.generateText(record[key], field, record);
new_item[pos].push(util.mergeObject(field, obj));
}
}
return RSVP.resolve(new_item); obj[setter] = response.value;
new_item[pos].push(util.mergeObject(response.field, obj));
}
return new_item;
})
.fail(app.util.error);
}; };
/* ********************************************************************** */ /* ********************************************************************** */
...@@ -3469,6 +3614,7 @@ ...@@ -3469,6 +3614,7 @@
**/ **/
// TODO: should a span still have full structure (label/container)? // TODO: should a span still have full structure (label/container)?
// TODO: should we wrap in span_12 here. why do we wrap at all, do with CSS // TODO: should we wrap in span_12 here. why do we wrap at all, do with CSS
// TODO: subordinate value
map.formItem = function (spec) { map.formItem = function (spec) {
var helper, getHelp, j, k, segment, section, field, setValue, root, veto, var helper, getHelp, j, k, segment, section, field, setValue, root, veto,
textarea_value, override_value, value, field_value, validation_list, textarea_value, override_value, value, field_value, validation_list,
...@@ -3488,23 +3634,25 @@ ...@@ -3488,23 +3634,25 @@
// TODO: remove this crap or make it generic... // TODO: remove this crap or make it generic...
// set = setter_list ... JSLINT // set = setter_list ... JSLINT
setValue = function (setter) { setValue = function (setter) {
var n, len, set_value, set_flux, set, val, set_reference; var n, len, set_value, set_flux, set, val, set_reference, logic,
selection, split;
if (setter.logic) { logic = setter.logic;
set_reference = setter.logic.setReference; if (logic) {
set_value = setter.logic.setValue; set_reference = logic.setReference;
val = setter.logic.lookupValue; set_value = logic.setValue;
set = setter.logic.setters; val = logic.lookupValue;
set_flux = setter.logic.setFlux; set = logic.setters;
set_flux = logic.setFlux;
if (set) { if (set) {
len = set.length; len = set.length;
for (n = 0; n < len; n += 1) { for (n = 0; n < len; n += 1) {
if (val) { if (val) {
// FU§$%&/NG HAL // FU§$%&/NG HAL
setter.logic[set[n]] = item.doc[val[n][0]][val[n][1]][val[n][2]]; logic[set[n]] = item.doc[val[n][0]][val[n][1]][val[n][2]];
} else { } else {
setter.logic[set[n]] = item.doc[set_value]; logic[set[n]] = item.doc[set_value];
} }
} }
} else if (set_value) { } else if (set_value) {
...@@ -3522,7 +3670,7 @@ ...@@ -3522,7 +3670,7 @@
delete flux._temp[set_flux]; delete flux._temp[set_flux];
} else { } else {
// translation!? // translation!?
setter.direct.value = setter.logic.noFlux; setter.direct.value = logic.noFlux;
} }
} }
} }
...@@ -3534,15 +3682,24 @@ ...@@ -3534,15 +3682,24 @@
if (!!item.direct) { if (!!item.direct) {
setValue(item); setValue(item);
} else if (!!item.generate) { } else if (!!item.generate) {
// we must declare wrap for non-form elements here, because they // NOTE: we must declare wrap for non-form elements here, because they
// don't belong into any widget // don't belong into any widget
// NOTE: persist if set!
container = getHelp({ container = getHelp({
"wrap": "section", "wrap": "section",
"persist": item.property_dict.persist,
"class_list": "span_" + (item.property_dict.wrap || 1) "class_list": "span_" + (item.property_dict.wrap || 1)
}); });
container.children.push(item); container.children.push(item);
} else { } else {
helper = getHelp({"wrap": "fragment"}); // NOTE: since we are creating 2 levels in the DOM tree (fragment &
// sections), the normal inheritance will break, because a wrapper
// will be missing state. Therefore we add the state manually here,
// TODO: don't do 2 level stuff.... and complain later when debugging
helper = getHelp({
"wrap": "fragment",
"state": spec.wrapper.property_dict.state
});
} }
// nothing to do, pass back directly // nothing to do, pass back directly
...@@ -3580,6 +3737,7 @@ ...@@ -3580,6 +3737,7 @@
field.overrides || {}, field.overrides || {},
{"properties": {}, "widget": {}} {"properties": {}, "widget": {}}
); );
value = item.doc[field.setValue || field.field]; value = item.doc[field.setValue || field.field];
// flag false/missing field_dict // flag false/missing field_dict
...@@ -3727,8 +3885,8 @@ ...@@ -3727,8 +3885,8 @@
pass = { pass = {
"push": { "push": {
"type": el, "type": el,
"wrap": true, "wrap": veto.wrap || true,
"label": true, "label": veto.label || true,
"direct": { "direct": {
"id": item.reference + "_" + "id": item.reference + "_" +
(veto.widget.id || root.widget.id), (veto.widget.id || root.widget.id),
...@@ -3768,7 +3926,7 @@ ...@@ -3768,7 +3926,7 @@
} }
// need to set position here to also include custom fields // need to set position here to also include custom fields
pass.position = segment.position === "center" ? 2 : 1; pass.position = segment.position === "center" ? 1 : 2;
// fetch dynamic options // fetch dynamic options
if (fetch_items === null) { if (fetch_items === null) {
...@@ -3857,6 +4015,8 @@ ...@@ -3857,6 +4015,8 @@
.fail(app.util.error); .fail(app.util.error);
} }
// NOTE: must set property_dict on the controlbar in order to inherit
// dynamic data to the contained field elements
section_list[j] = RSVP.all(field_list) section_list[j] = RSVP.all(field_list)
.then(function (field_response_list) { .then(function (field_response_list) {
section = getHelp({ section = getHelp({
...@@ -3888,49 +4048,86 @@ ...@@ -3888,49 +4048,86 @@
// generate storage object with placeholders // generate storage object with placeholders
storage = { storage = {
"obj": {}, "empty_obj": {},
"arr": [], "arr": [],
"span": document.createElement("span") "span": document.createElement("span")
}; };
/**
* Get a subordinate record and store in flux in case multiple properties
* of this object are requested
* @method subordinate
* @param {object} spec Current record
* @return {promise}
*/
storage.subordinate = function (spec) {
var output;
// fetch from cache or query
if (flux.active_record[spec.relation]) {
output = flux.active_record[spec.relation];
} else {
output = flux.active_record[spec.relation] = storage.fetch({
"pass": spec,
"query": {"_id": spec.relation}
});
}
return output.then(function (answer) {
var data = answer.response.data;
// set subordinate value
if (data.total_rows > 0) {
spec.value = data.rows[0].doc[spec.subordinate]
}
// NOTE: delete here, otherwise impossible to track. This will still
// work cause subsequent requests will fire async and be set from flux
delete flux.active_record[spec.relation];
return spec;
}).fail(app.util.error);
};
/** /**
* Fetch data from storage = GET or ALLDOCS * Fetch data from storage = GET or ALLDOCS
* @method fetch * @method fetch
* @param {object} obj Action object * @param {object} obj Action object
*/ */
// TODO: merge pass.x or pass.state.x // TODO: convert config/url_dict into state and save 50000 assignments
// TODO: set pointer directly inside data-action, remove pointer! // TODO: set pointer directly inside data-action.... remove pointer!
// TODO: state needs to have url_pointer set earlier, so
// there is no need to look it up in pass.config.property_dict...
// TODO: jump is bad, it is the lookup for the data to display. rename! // TODO: jump is bad, it is the lookup for the data to display. rename!
// TODO: the whole assignments are crap
// TODO: action_id > this should be triggered via form submit not links!!!
// TODO: does _id always include portal_type? if link, yes, else no.
storage.fetch = function (obj) { storage.fetch = function (obj) {
var pass, query, method, mapper, config, answer, lookup, pointer, action_id, var pass, query, method, mapper, config, answer, lookup, pointer, empty,
quirk; action_id, quirk;
empty = storage.empty_obj;
pass = obj.pass; pass = obj.pass;
quirk = obj.state || pass.config_dict; quirk = obj.state || pass.config_dict || empty;
lookup = obj.state || quirk.property_dict || storage.obj; lookup = obj.state || quirk.property_dict || empty;
query = obj.query || lookup.query || storage.obj; query = obj.query || lookup.query || empty;
pointer = (lookup.url_pointer || storage.obj).jump; pointer = (lookup.url_pointer || empty).jump;
action_id = ((obj.element || empty).href || "").split("/").pop();
// TODO: action > id, this should be triggered via form submit not link!
action_id = ((obj.element || storage.obj).href || "").split("/").pop();
if (action_id) { if (action_id) {
pointer = undefined; pointer = undefined;
query = {"_id": window.decodeURIComponent(action_id)}; query = {"_id": window.decodeURIComponent(action_id)};
} }
// F%&/() JSLINT... // JSLINT my ...
if (!!pointer) {
// TODO: "hack" for forcing get into allDocs, don't overwrite criteria! // TODO: "hack" for forcing get into allDocs, don't overwrite criteria!
if (!!pointer) {
mapper = "values"; mapper = "values";
query.select_list = query.select_list || pass.data_dict.field_list; query.select_list = query.select_list || pass.data_dict.field_list;
query.limit = query.limit || pass.config_dict.initial_query.limit; query.limit = query.limit || pass.config_dict.initial_query.limit;
} else if ((query.select_list || storage.arr).length > 0 && } else if ((query.select_list || storage.arr).length > 0 &&
!query.include_docs !query.include_docs
) { ) {
mapper = "values"; mapper = "values";
} else if (!!query._id) { } else if (!!query._id) {
mapper = "single_item"; mapper = "single_item";
method = "get"; method = "get";
...@@ -3983,11 +4180,11 @@ ...@@ -3983,11 +4180,11 @@
// TODO: storage.add included prefetch of field_items and validation // TODO: storage.add included prefetch of field_items and validation
// TODO: storage.add deleted identifier if create_new was set // TODO: storage.add deleted identifier if create_new was set
storage.write = function (obj) { storage.write = function (obj) {
var form, data, valid, prefix, config, method, action, pointer; var form, data, valid, prefix, config, method, action, pointer, sample;
form = obj.form; form = obj.form;
pointer = (obj.element || storage.span).getAttribute("data-action"); pointer = (obj.element || storage.span).getAttribute("data-action");
action = (obj.state.url_pointer || storage.obj)[pointer]; action = (obj.state.url_pointer || storage.empty_obj)[pointer];
config = {}; config = {};
prefix = obj.id + "_"; prefix = obj.id + "_";
valid = obj.sample_store || storage.validate(form); valid = obj.sample_store || storage.validate(form);
...@@ -3999,9 +4196,9 @@ ...@@ -3999,9 +4196,9 @@
config._force_data = true; config._force_data = true;
} }
if (obj.sample_data._id || form.identifier) { if (data._id || form.identifier) {
// PUT > set id, method and view // PUT > set id, method and view
data._id = obj.sample_data._id || form.identifier.value; data._id = data._id || form.identifier.value;
method = "put"; method = "put";
config._view = obj.state.view; config._view = obj.state.view;
} }
...@@ -4377,6 +4574,7 @@ ...@@ -4377,6 +4574,7 @@
} }
} }
} }
return answer || response; return answer || response;
}; };
...@@ -4487,8 +4685,9 @@ ...@@ -4487,8 +4685,9 @@
/** /**
* @object flux Maintain flux in memory. * @object flux Maintain flux in memory.
**/ **/
// TODO: secure? flux = {
flux = {}; "active_record": {}
};
/* ====================================================================== */ /* ====================================================================== */
/* APP */ /* APP */
...@@ -4523,7 +4722,6 @@ ...@@ -4523,7 +4722,6 @@
id = answer.id; id = answer.id;
decode = /%[0-9a-f]{2}/i.test(id); decode = /%[0-9a-f]{2}/i.test(id);
goto_page = decode ? id : window.encodeURIComponent(id); goto_page = decode ? id : window.encodeURIComponent(id);
$.mobile.changePage(obj.state.callback.replace("__id__", goto_page)); $.mobile.changePage(obj.state.callback.replace("__id__", goto_page));
} }
}; };
...@@ -4547,7 +4745,14 @@ ...@@ -4547,7 +4745,14 @@
// update gadget // update gadget
app.content.set( app.content.set(
{}, {
"portal_type_source": config.state.type,
"portal_type_title": config.state.title,
"property_dict": util.mergeObject(
{"dynamic": true},
config.state.dyno_dict),
"scheme": config.state.scheme
},
{ {
"reference": config.id, "reference": config.id,
"href": config.state.href, "href": config.state.href,
...@@ -4570,10 +4775,11 @@ ...@@ -4570,10 +4775,11 @@
*/ */
// TODO: overwrite direction on single state sorting // TODO: overwrite direction on single state sorting
app.sort = function (config, direction, prev, next, single) { app.sort = function (config, direction, prev, next, single) {
var i, in_array, sort_by, delay; var i, in_array, sort_by, delay, state;
// NOTE: if column title is not set, we might be sortling a list! // NOTE: if column title is not set, we might be sortling a list!
sort_by = config.element.getAttribute("data-column-title"); sort_by = config.element.getAttribute("data-column-title");
state = config.state;
if (sort_by) { if (sort_by) {
// sorting button update // sorting button update
...@@ -4592,8 +4798,8 @@ ...@@ -4592,8 +4798,8 @@
util.clearTimer(); util.clearTimer();
// check if we are already sorting by this sort_by value // check if we are already sorting by this sort_by value
for (i = 0; i < config.state.query.sort_on.length; i += 1) { for (i = 0; i < state.query.sort_on.length; i += 1) {
if (config.state.query.sort_on[i][0] === sort_by) { if (state.query.sort_on[i][0] === sort_by) {
in_array = true; in_array = true;
break; break;
} }
...@@ -4605,9 +4811,9 @@ ...@@ -4605,9 +4811,9 @@
case "desc_abc": case "desc_abc":
if (sort_by) { if (sort_by) {
if (in_array === undefined) { if (in_array === undefined) {
config.state.query.sort_on.push([sort_by, "descending"]); state.query.sort_on.push([sort_by, "descending"]);
} else { } else {
config.state.query.sort_on.splice(i, 1) state.query.sort_on.splice(i, 1)
.push([sort_by, "descending"]); .push([sort_by, "descending"]);
} }
} }
...@@ -4616,9 +4822,9 @@ ...@@ -4616,9 +4822,9 @@
case "asc_abc": case "asc_abc":
if (sort_by) { if (sort_by) {
if (in_array === undefined) { if (in_array === undefined) {
config.state.query.sort_on.push([sort_by, "ascending"]); state.query.sort_on.push([sort_by, "ascending"]);
} else { } else {
config.state.query.sort_on.splice(i, 1) state.query.sort_on.splice(i, 1)
.push([sort_by, "ascending"]); .push([sort_by, "ascending"]);
} }
} }
...@@ -4626,7 +4832,7 @@ ...@@ -4626,7 +4832,7 @@
default: default:
// need to remove a column from sorting when set to undefined // need to remove a column from sorting when set to undefined
if (sort_by && in_array) { if (sort_by && in_array) {
config.state.query.sort_on.splice(i, 1); state.query.sort_on.splice(i, 1);
} }
break; break;
} }
...@@ -4637,9 +4843,9 @@ ...@@ -4637,9 +4843,9 @@
{}, {},
{ {
"reference": config.id, "reference": config.id,
"href": config.state.href, "href": state.href,
"fragment_list": config.state.fragment_list, "fragment_list": state.fragment_list,
"layout_level": config.state.layout_level "layout_level": state.layout_level
}, },
false false
) )
...@@ -4749,31 +4955,33 @@ ...@@ -4749,31 +4955,33 @@
* @param {string} value New limit when changing number of records * @param {string} value New limit when changing number of records
*/ */
app.paginate = function (config, type, value) { app.paginate = function (config, type, value) {
var start, records, total; var start, records, total, state, current_limit;
total = config.state.total; state = config.state;
total = state.total;
current_limit = state.query.limit || state.initial_query.limit;
if (config.gadget) { if (config.gadget) {
if (config.state) { if (state && current_limit) {
switch (type) { switch (type) {
case "first": case "first":
start = 0; start = 0;
records = config.state.query.limit[1]; records = current_limit[1];
break; break;
case "next": case "next":
start = config.state.query.limit[0] + config.state.query.limit[1]; start = current_limit[0] + current_limit[1];
records = config.state.query.limit[1]; records = current_limit[1];
break; break;
case "prev": case "prev":
start = config.state.query.limit[0] - config.state.query.limit[1]; start = current_limit[0] - current_limit[1];
records = config.state.query.limit[1]; records = current_limit[1];
break; break;
case "last": case "last":
start = total - config.state.query.limit[1]; start = total - current_limit[1];
records = config.state.query.limit[1]; records = current_limit[1];
break; break;
case "limit": case "limit":
start = config.state.query.limit[0]; start = current_limit[0];
records = parseInt(value, null); records = parseInt(value, null);
break; break;
} }
...@@ -4783,37 +4991,35 @@ ...@@ -4783,37 +4991,35 @@
} }
// set new limits // set new limits
config.state.query.limit = [start, records]; state.query.limit = [start, records];
// reset selected // reset selected
if (config.state.selected) { if (state.selected) {
config.state.selected = []; state.selected = [];
} }
// update gadget // update gadget
app.content.set( app.content.set(
{ {
"portal_type_source": config.state.type, "portal_type_source": state.type,
"portal_type_title": config.state.title, "portal_type_title": state.title,
"property_dict": util.mergeObject({ "property_dict": util.mergeObject(
"dynamic": true, {"dynamic": true},
"map_children": "listItem" state.dyno_dict),
}, "scheme": state.scheme
config.state.dyno_dict),
"scheme": config.state.scheme
}, },
{ {
"reference": config.id, "reference": config.id,
"href": config.state.href, "href": state.href,
"fragment_list": config.state.fragment_list, "fragment_list": state.fragment_list,
"layout_level": config.state.layout_level "layout_level": state.layout_level
}, },
false false
) )
.fail(app.util.error); .fail(app.util.error);
} else { } else {
app.util.error("No state information stored for gadget"); app.util.error("No state/limit information stored for gadget");
} }
} else { } else {
app.util.error("Action is missing reference gadget"); app.util.error("Action is missing reference gadget");
...@@ -4841,11 +5047,12 @@ ...@@ -4841,11 +5047,12 @@
info = ""; info = "";
no_total = total === undefined && no_total = total === undefined &&
app.storage_dict.property_dict.skip_total_records; app.storage_dict.property_dict.skip_total_records;
generateInfo = function (text, text_i18n) { generateInfo = function (text, text_i18n) {
return factory.element( return factory.element(
"span", "span",
{"className": "translate"}, {"className": "translate"},
{"data-i18n": "global_dict.info_dict." + text_i18n}, {"data-i18n": "global_dict." + text_i18n},
{"text": text} {"text": text}
); );
}; };
...@@ -4937,7 +5144,7 @@ ...@@ -4937,7 +5144,7 @@
} }
// initial fill or update // initial fill or update
if (slot !== undefined) { if (!slot) {
if (info_field.children.length === 0) { if (info_field.children.length === 0) {
first = document.createTextNode(info); first = document.createTextNode(info);
last = generateInfo(text_snippet, i18n_snippet); last = generateInfo(text_snippet, i18n_snippet);
...@@ -5029,6 +5236,10 @@ ...@@ -5029,6 +5236,10 @@
"gadget": document.getElementById(id) "gadget": document.getElementById(id)
}; };
if (response.gadget === null) {
return response;
}
has_form = response.gadget.getElementsByTagName("form"); has_form = response.gadget.getElementsByTagName("form");
return util.mergeObject( return util.mergeObject(
{ {
...@@ -5069,16 +5280,27 @@ ...@@ -5069,16 +5280,27 @@
* @param {object} data Data passed along with this (JQM) event * @param {object} data Data passed along with this (JQM) event
*/ */
app.parsePage = function (e, data) { app.parsePage = function (e, data) {
var page, base, config, raw_url, handle, clean_url, parsed_url, first; var page, base, config, raw_url, handle, clean_url, parsed_url, first,
skipper, base_page;
if (data) { if (data) {
// update page title on backwards transition to the first page (still // update page title on backwards transition to the first page (still
// is in DOM, so no new page created, so no title update...) // is in DOM, so no new page created, so no title update...)
// TODO: not bulletproof i18n handling... we expect i18n to be defined // TODO: not bulletproof i18n handling... we expect i18n to be defined
// TODO: blocker is not nice
if (typeof data.toPage === "object") { if (typeof data.toPage === "object") {
base_page = data.toPage[0];
if ($.mobile.firstPage[0].getAttribute("data-url") === if ($.mobile.firstPage[0].getAttribute("data-url") ===
data.toPage[0].getAttribute("data-url")) { base_page.getAttribute("data-url")) {
app.setPageTitle("global_dict.home"); app.setPageTitle("global_dict.home");
// NOTE: this will allow going back, but only if we are not
// coming from root
if (!app.deeplink_flag) {
skipper = true;
app.deeplink_flag = true;
}
} }
} }
...@@ -5089,25 +5311,35 @@ ...@@ -5089,25 +5311,35 @@
} else { } else {
raw_url = data.toPage; raw_url = data.toPage;
} }
} else { } else {
raw_url = window.location.href; raw_url = window.location.href;
} }
if (typeof raw_url === "string") { if (typeof raw_url === "string") {
// decode // decode
if (data && data.options.reverse) { if (data && data.options.reverse) {
raw_url = window.decodeURIComponent(raw_url); raw_url = window.decodeURIComponent(raw_url);
} }
config = app.util.parseLink(raw_url); config = app.util.parseLink(raw_url);
// NOTE: if we start from home we must prevent reloading home
// because it will be kept in the DOM
if (!config.deeplink) {
// we start from home, so we must not allow going back
// and reloading
app.deeplink_flag = true;
}
if (e) { if (e) {
page = util.getPage(raw_url.split("#").pop()); page = util.getPage(raw_url.split("#").pop());
base = page ? page.getAttribute("data-external-page") : null; base = page ? page.getAttribute("data-external-page") : null;
first = $.mobile.firstPage[0].getAttribute("data-url") === first = $.mobile.firstPage[0].getAttribute("data-url") ===
config.data_url; config.data_url;
if (first || (page && base) || raw_url === $.mobile.getDocumentUrl() || if ((first || (page && base) || raw_url === $.mobile.getDocumentUrl() ||
data.options.role === "popup") { data.options.role === "popup") && !skipper) {
// stop us, JQM can go // stop us, JQM can go
return RSVP.resolve(undefined); return RSVP.resolve(undefined);
} }
...@@ -5301,17 +5533,24 @@ ...@@ -5301,17 +5533,24 @@
// generateFormElement // generateFormElement
$(form_element).validVal({ $(form_element).validVal({
validate: { "validate": {
onKeyup: "valid", "onKeyup": "valid",
onBlur: "valid" "onBlu": "valid"
},
"fields": {
"hidden": true
}, },
//customValidations: util.declareJS(), //customValidations: util.declareJS(),
form: { "form": {
onInvalid: function () { "onInvalid": function () {
util.return_out(); util.return_out();
} }
} }
}); });
} else {
// TODO: AAAARGH! so much jquery...
// TODO: AND IT DOES NOT WORK... §$%&/()=!
$(form_element).trigger("addField", $(form_element).find(".required"));
} }
} }
}; };
...@@ -5575,13 +5814,14 @@ ...@@ -5575,13 +5814,14 @@
* Get the active JQM page in JavaScript-only * Get the active JQM page in JavaScript-only
* @method getPage * @method getPage
* @param {string} url url of the page to fetch * @param {string} url url of the page to fetch
* @param {string} straight If not set, we start searching from behind
* @return {string} id of active page * @return {string} id of active page
*/ */
util.getPage = function (url) { util.getPage = function (url, straight) {
var i, kid, kids = document.body.children; var i, kid, len, kids = document.body.children;
// reverse, because in JQM last page is the active page! // reverse, because in JQM last page is the active page!
for (i = kids.length - 1; i >= 0; i -= 1) { for (len = kids.length, i = len - 1; i >= 0; i -= 1) {
kid = kids[i]; kid = kids[i];
if (util.testForString("ui-page", kid.className)) { if (util.testForString("ui-page", kid.className)) {
...@@ -5593,6 +5833,17 @@ ...@@ -5593,6 +5833,17 @@
return undefined; return undefined;
}; };
/**
* Remove all children of an element
* @method deleteChildren
* @param {object} el Element to remove children from
*/
util.deleteChildren = function (el) {
while (el.hasChildNodes()) {
el.removeChild(el.lastChild);
}
};
/** /**
* Reverse an array * Reverse an array
* @method reverseArray * @method reverseArray
...@@ -5647,6 +5898,22 @@ ...@@ -5647,6 +5898,22 @@
return new RegExp("(?:^|\\s)" + className + "(?!\\S)", "g"); return new RegExp("(?:^|\\s)" + className + "(?!\\S)", "g");
}; };
// /**
// * Property to set whether classlist is supported
// * @property support_classList
// */
// // TODO: add to support module/Modernizr
// util.no_support_classList = document.documentElement.classList === undefined;
//
// util.testForString = util.no_support_classList ?
// function(el, clss) {
// return el.className && new RegExp("(^|\\s)" +
// clss + "(\\s|$)").test(el.className);
// } :
// function(el, clss) {
// return el.classList.contains(clss);
// };
/** /**
* Test for a class name * Test for a class name
* @method testForString * @method testForString
...@@ -5655,7 +5922,6 @@ ...@@ -5655,7 +5922,6 @@
* @param {boolean} nowrap Whether to wrap in space * @param {boolean} nowrap Whether to wrap in space
* @return {boolean} result True/False * @return {boolean} result True/False
*/ */
// WARNING: requires IE8- requires shim
util.testForString = function (search_string, full_string, nowrap) { util.testForString = function (search_string, full_string, nowrap) {
var s = nowrap ? "" : " "; var s = nowrap ? "" : " ";
return (s + full_string + s).indexOf(s + search_string + s) > -1; return (s + full_string + s).indexOf(s + search_string + s) > -1;
...@@ -5757,17 +6023,37 @@ ...@@ -5757,17 +6023,37 @@
* @return {object} field defintions and pass through * @return {object} field defintions and pass through
*/ */
app.content.fields = function (reply) { app.content.fields = function (reply) {
var pass = reply.pass; var pass = reply.pass, query, crop;
if (!pass.skip) { if (!pass.skip) {
// (dynamic element) config_dict // (dynamic element) config_dict
// NOTE: so config_dict will always be present and we don't need to
// ever test for it again after here.... because if we fetch by URL
// whatever was fetched is here and if we just render it will be
// on content_dict.
pass.config_dict = util.parse(reply.response) || pass.content_dict; pass.config_dict = util.parse(reply.response) || pass.content_dict;
delete pass.no_config; delete pass.no_config;
// test for auth based access // test for auth based access
pass.grant = true; pass.grant = true;
// update initial query with urlQuery if one was passed
if (pass.url_dict.url_query) {
crop = pass.config_dict.property_dict.url_crop;
query = util.mergeObject(
pass.url_dict.url_query,
pass.config_dict.initial_query || {}
);
// TODO: TOTALLY UGLY hack to allow 2 gadgets who require different urls
// to share... remove ASAP
if (crop) {
query.query = query.query.replace(crop, "");
}
pass.config_dict.initial_query = query;
}
// fetch field definitions - why make a query without fieldlist? // fetch field definitions - why make a query without fieldlist?
if (pass.grant || pass.mode === "new") { if (pass.grant || pass.mode === "new") {
app.util.loader("", "status_dict.loading_config"); app.util.loader("", "status_dict.loading_config");
...@@ -5856,14 +6142,8 @@ ...@@ -5856,14 +6142,8 @@
return RSVP.all(promise_list) return RSVP.all(promise_list)
.then(function (response_list) { .then(function (response_list) {
if (!response_list[0]) { if (!response_list[0] && promise_list.length !== 0) {
app.util.loader( app.util.loader("", "status_dict.internal_error", "ban");
"",
"status_dict.internal_error",
"ban-circle"
);
} else {
app.util.loader("", "status_dict.success", "check");
} }
// just return pass and continue // just return pass and continue
return { return {
...@@ -5902,7 +6182,7 @@ ...@@ -5902,7 +6182,7 @@
if (pass.create === false) { if (pass.create === false) {
pass.state = document.getElementById(pass.url_dict.reference).state; pass.state = document.getElementById(pass.url_dict.reference).state;
pass.store_limit = pass.state.query.limit; pass.store_limit = pass.state.query.limit;
pass.state.query.lfimit = []; pass.state.query.limit = [];
// create state object // create state object
} else { } else {
...@@ -5951,7 +6231,8 @@ ...@@ -5951,7 +6231,8 @@
pass.config_dict.skip_total_records !== true) && pass.config_dict.skip_total_records !== true) &&
((pass.grant || pass.url_dict.mode === "new") && ((pass.grant || pass.url_dict.mode === "new") &&
(pass.state && pass.state.query._id === undefined) && (pass.state && pass.state.query._id === undefined) &&
pass.config_dict.initial_query) (pass.config_dict.initial_query || pass.create === false) &&
!pass.config_dict.property_dict.force_new)
) { ) {
// reset limit from sampling [0,1] and store query // reset limit from sampling [0,1] and store query
pass.state.query.limit = []; pass.state.query.limit = [];
...@@ -5978,7 +6259,6 @@ ...@@ -5978,7 +6259,6 @@
var pass = reply.pass; var pass = reply.pass;
if (!pass.skip) { if (!pass.skip) {
// set total rows // set total rows
if (reply.response) { if (reply.response) {
pass.state.total = util.parse(reply.response).data.total_rows; pass.state.total = util.parse(reply.response).data.total_rows;
...@@ -6014,7 +6294,7 @@ ...@@ -6014,7 +6294,7 @@
} }
// get items/item // get items/item
if (pass.grant && if (pass.grant && !pass.config_dict.property_dict.force_new &&
(pass.url_dict.mode !== "new" || !pass.config_dict.initial_query) (pass.url_dict.mode !== "new" || !pass.config_dict.initial_query)
) { ) {
app.util.loader("", "status_dict.loading_set"); app.util.loader("", "status_dict.loading_set");
...@@ -6037,11 +6317,15 @@ ...@@ -6037,11 +6317,15 @@
* @return {object} response object/promise * @return {object} response object/promise
**/ **/
// TODO: refactor... appocalyptic // TODO: refactor... appocalyptic
// TODO: determine what should be inherit and make inherit object, that
// will be passed down the rendering tree
app.content.make = function (reply) { app.content.make = function (reply) {
var pass, method, type, kids, promise_list, route, var pass, method, type, kids, promise_list, route,
search, search_id, kid, is_html, is_dynamic, is_id, i, j, last, search, search_id, kid, is_html, is_dynamic, is_id, i, j, k, last,
encoded, wrapper, active, selector, update_target, target, widget, encoded, wrapper, active, selector, update_target, target, widget,
grant_child, quirk_dict, generator, pointer_results, data_total_rows; quirk_dict, generator, pointer_results, data_total_rows, is_parameter,
param_len, parameter, no_item, dyno, container, has_props, widget_dyno,
set_reference;
pass = reply.pass; pass = reply.pass;
pass.config_dict = pass.config_dict || {}; pass.config_dict = pass.config_dict || {};
...@@ -6049,44 +6333,25 @@ ...@@ -6049,44 +6333,25 @@
method = factory.widget[type] || undefined; method = factory.widget[type] || undefined;
promise_list = []; promise_list = [];
// set results, here, so dynamic kids are correct! // NOTE:
if (pass.grant && reply.response) { // set results here, so kids.length is available in wrapper generation.
pointer_results = util.parse(reply.response); // Also, if dynamic and no response (eg for "new" record, we set an empty
// placeholder here which will generate an empty form
if (!pass.skip) {
pointer_results = util.parse(reply.response) ||
{"data": {"total_rows": 0, "rows": []}};
data_total_rows = pointer_results.data.total_rows; data_total_rows = pointer_results.data.total_rows;
} }
// kids (must be declared before wrapper, because some wrapper need length
if (pass.content_dict.view_dict) {
kids = pass.content_dict.view_dict[pass.url_dict.mode || "default"];
} else {
kids = pass.content_dict.children || pass.config_dict.children || [];
}
// ============= TODO: improve property_dict generation ==============
// TODO: no all elements need them?
// wrapper object and properties
quirk_dict = util.mergeObject(
(pass[method ? "content_dict" : "config_dict"].property_dict),
{
"create": pass.create,
"update": pass.create === false ? true : null,
"total_rows": data_total_rows,
"length": kids.length,
"layout_level": pass.url_dict.layout_level,
"fragment_list": pass.url_dict.fragment_list,
"data_url": pass.url_dict.data_url,
"scheme": pass.config_dict.scheme,
"field_dict": (pass.data_dict || {}).field_dict,
"skip": pass.skip
}
);
// set generator // set generator
if (quirk_dict.skip) { if (pass.skip) {
if (!pass.content_dict.generate) { if (!pass.content_dict.generate) {
route = type; route = type;
// force custom elements into form layout... // force custom elements into form layout...
// NOTE: only used in service_instance_status to make a link go
// through formElement, not sure this must be a viable option,
// maybe better with custom, question is were do wrapper, label
// come from.
if (pass.content_dict.logic && pass.content_dict.logic.route) { if (pass.content_dict.logic && pass.content_dict.logic.route) {
route = pass.content_dict.logic.route; route = pass.content_dict.logic.route;
} }
...@@ -6114,6 +6379,31 @@ ...@@ -6114,6 +6379,31 @@
} }
} }
// kids (must be declared before wrapper, because some wrapper need length
if (pass.content_dict.view_dict) {
kids = pass.content_dict.view_dict[pass.url_dict.mode] ||
pass.content_dict.view_dict["default"];
} else {
kids = pass.content_dict.children || pass.config_dict.children || [];
}
// wrapper object and properties
quirk_dict = util.mergeObject(
(pass[method ? "content_dict" : "config_dict"].property_dict),
{
"create": pass.create,
"update": pass.create === false ? true : null,
"total_rows": data_total_rows,
"length": kids.length,
"layout_level": pass.url_dict.layout_level,
"fragment_list": pass.url_dict.fragment_list,
"data_url": pass.url_dict.data_url,
"scheme": pass.config_dict.scheme,
"field_dict": (pass.data_dict || {}).field_dict,
"skip": pass.skip
}
);
if (!generator) { if (!generator) {
if (method) { if (method) {
generator = method(quirk_dict); generator = method(quirk_dict);
...@@ -6124,48 +6414,84 @@ ...@@ -6124,48 +6414,84 @@
// switch back // switch back
wrapper = generator; wrapper = generator;
// make properties available to children in need // make properties available to children in need
wrapper.property_dict = quirk_dict; wrapper.property_dict = quirk_dict;
// =============================
// no records returned, no_show set below on dyno // no records returned, no_show set below on dyno
// TODO: find better way to set dynamic flag
if (quirk_dict.no_show) { if (quirk_dict.no_show) {
kids.push(factory.util.noItems( no_item = factory.util.noItems(
quirk_dict.no_show, quirk_dict.no_show,
wrapper.base, wrapper.base,
wrapper.count ? wrapper.count(quirk_dict.scheme[0]) : null wrapper.count ? wrapper.count(quirk_dict.scheme[0]) : null
)); );
kids = util.inherit(
no_item,
{"scheme": quirk_dict.scheme, "field_dict": quirk_dict.field_dict}
);
} }
// dynamic content // dynamic content
// TODO: 10 if-else... // TODO: 10 if-else...
if (!pass.skip) { if (!pass.skip) {
// =====================================================================
// NOTE: store state on wrapper property_dict to inherit!
wrapper.property_dict.state = pass.state
// =====================================================================
// inherit item id, so it's available in form as indentifier // inherit item id, so it's available in form as indentifier
if (pointer_results.data.total_rows === 1) { if (pointer_results.data.total_rows === 1) {
quirk_dict.data = {"_id": pointer_results.data.rows[0].doc._id}; quirk_dict.data = {"_id": pointer_results.data.rows[0].doc._id};
} }
// no items, need no show! (default to empty {} if none provided // no items, need no show! (default to empty {} if none provided
if (pointer_results.data.total_rows === 0) { if (pointer_results.data.total_rows === 0) {
if (quirk_dict.allow_new) { if (quirk_dict.allow_new || quirk_dict.force_new) {
pointer_results = {"data": {"total_rows": 1, "rows": [{"doc": {}}]}};
// NOTE: on updates with force_new, reference must be passed to not
// have undefined form-id values
if (quirk_dict.update) {
set_reference = {
"doc": {},
"reference": pass.url_dict.reference
};
}
pointer_results = {
"data": {
"total_rows": 1,
"rows": [set_reference || {"doc": {}}]
}
};
} else { } else {
quirk_dict.no_show = quirk_dict.no_items || {}; quirk_dict.no_show = quirk_dict.no_items || {};
} }
} }
// set up fragment and child_selector // set up fragment and child_selector
if (quirk_dict.update !== true) { if (quirk_dict.update !== true) {
if (!quirk_dict.no_content) {
// set reference for children in need // set reference for children in need
quirk_dict.reference = "dyno_" + util.uuid(); quirk_dict.reference = "dyno_" + util.uuid();
dyno = factory.element({
// setup fragment and child_selector
wrapper.fragment.appendChild(factory.element({
"type": "div", "type": "div",
"direct": { "direct": {
"id": quirk_dict.reference, "id": quirk_dict.reference,
"className": "dyno" "className": "dyno"
} }
})); });
// setup fragment and child_selector
if (quirk_dict.wrap_gadget) {
container = factory.element({
"type": "div",
"direct": {
"className": "span_" + quirk_dict.wrap_gadget
}
});
container.appendChild(dyno);
}
wrapper.fragment.appendChild(container || dyno);
wrapper.child_selector = wrapper.fragment.querySelector( wrapper.child_selector = wrapper.fragment.querySelector(
"#" + quirk_dict.reference "#" + quirk_dict.reference
); );
...@@ -6210,13 +6536,19 @@ ...@@ -6210,13 +6536,19 @@
} }
break; break;
} }
}
} else { } else {
widget = pass.state.gadget.querySelector("[data-update]") // TODO: can this be done without storing on and querying DOM???!!!
.getAttribute("data-widget"); // TODO: THIS MAKES ME INSANE... qsa || widget does not work!
widget = pass.state.gadget;
widget_dyno = widget.querySelector("[data-update]") || widget.getElementsByTagName("form")[0];
wrapper.property_dict.map_children = widget_dyno.getAttribute("data-map");
wrapper = util.mergeObject( wrapper = util.mergeObject(
factory.widget[widget](wrapper.property_dict), factory.widget[widget_dyno.getAttribute("data-widget")](wrapper.property_dict),
wrapper wrapper
); );
// add scheme and field_dict to list // add scheme and field_dict to list
kids = util.inherit( kids = util.inherit(
pointer_results.data.rows, pointer_results.data.rows,
...@@ -6240,7 +6572,6 @@ ...@@ -6240,7 +6572,6 @@
is_dynamic = kid.property_dict && kid.property_dict.dynamic; is_dynamic = kid.property_dict && kid.property_dict.dynamic;
is_html = kid.direct; is_html = kid.direct;
// inherit item id to child elements (see above) // inherit item id to child elements (see above)
if (is_id) { if (is_id) {
if (is_html && is_html.href) { if (is_html && is_html.href) {
...@@ -6260,27 +6591,36 @@ ...@@ -6260,27 +6591,36 @@
kid.property_dict.input = "#" + search_id; kid.property_dict.input = "#" + search_id;
} }
// inherit properties of parent (> dynamic!) and add data to kid // map on kid directly and inherit data down (only single items)
if (quirk_dict.direct_map) {
kid.property_dict.data = pointer_results.data.rows[0];
// NOTE: we may be setting on a wrapper!
} else {
kid.property_dict = util.mergeObject(kid.property_dict, quirk_dict); kid.property_dict = util.mergeObject(kid.property_dict, quirk_dict);
kid.children = util.inherit( kid.children = util.inherit(
pointer_results.data.rows.concat(kid.children || []), pointer_results.data.rows.concat(kid.children || []),
{"scheme": quirk_dict.scheme, "field_dict": quirk_dict.field_dict} {"scheme": quirk_dict.scheme, "field_dict": quirk_dict.field_dict}
); );
} }
}
// HACK for setParam in login window // ===================================================================
if (kid.logic && kid.logic.setParam) { is_parameter = (kid.logic || {}).setParam;
kid.direct.href += kid.direct.href.indexOf("?") > 0 ? "&" : "?"; has_props = kid.property_dict;
switch (kid.logic.setParam[1]) {
case "location": // inherit dynamic state to all children with property_dict
target = window.location.origin + if (has_props && wrapper.property_dict.state) {
window.location.pathname + kid.property_dict.state = wrapper.property_dict.state;
window.location.hash.split("?")[0];
break;
} }
kid.direct.href += window.encodeURIComponent(kid.logic.setParam[0]) +
"=" + window.encodeURIComponent(target); // set dynamic Param(s)
if (is_parameter) {
kid = app.util.setParam(kid, wrapper);
} }
// ===================================================================
if (quirk_dict.update !== true || is_dynamic || quirk_dict.dynamic) { if (quirk_dict.update !== true || is_dynamic || quirk_dict.dynamic) {
// for content loaded via href, generate URL dict and undefine kid // for content loaded via href, generate URL dict and undefine kid
...@@ -6288,6 +6628,7 @@ ...@@ -6288,6 +6628,7 @@
if (wrapper.is_page && kid.href) { if (wrapper.is_page && kid.href) {
wrapper.inherit = { wrapper.inherit = {
"href": kid.href, "href": kid.href,
"url_query": pass.url_dict.url_query,
"fragment_list": pass.url_dict.fragment_list, "fragment_list": pass.url_dict.fragment_list,
"layout_level": pass.url_dict.layout_level, "layout_level": pass.url_dict.layout_level,
"inherit": true, "inherit": true,
...@@ -6329,12 +6670,13 @@ ...@@ -6329,12 +6670,13 @@
return RSVP.all(promise_list) return RSVP.all(promise_list)
.then(function (response_list) { .then(function (response_list) {
var k, l, done_target, wrapper_selector, response, content, var k, l, m, len, done_target, wrapper_selector, response, content,
content_target; content_target, last_child, detach, child_list;
for (k = 0, l = response_list.length; k < l; k += 1) { for (k = 0, l = response_list.length; k < l; k += 1) {
response = response_list[k]; response = response_list[k];
done_target = undefined; done_target = undefined;
if (response) { if (response) {
// generate target for and append response // generate target for and append response
// NOTE: wrapper.spec is used for header only. // NOTE: wrapper.spec is used for header only.
...@@ -6347,6 +6689,7 @@ ...@@ -6347,6 +6689,7 @@
"len": kids.length, "len": kids.length,
"config": wrapper.spec "config": wrapper.spec
}); });
// NOTE: wrapper_selector will return a fragment (set to // NOTE: wrapper_selector will return a fragment (set to
// first/last-ElementChild or a DOM node // first/last-ElementChild or a DOM node
done_target = done_target =
...@@ -6395,21 +6738,39 @@ ...@@ -6395,21 +6738,39 @@
} }
// only for dynamic content // only for dynamic content
if (!pass.skip) { if (!pass.skip && !quirk_dict.no_content) {
// UPDATES // UPDATES - same %&/( as above
if (quirk_dict.update) { if (quirk_dict.update) {
selector = pass.state.gadget; selector = pass.state.gadget;
update_target = selector.querySelector("[data-update]"); update_target = widget.querySelector("[data-update]") || widget.getElementsByTagName("form")[0];
// dump
while (update_target.hasChildNodes()) { // TODO: generic method!
update_target.removeChild(update_target.lastChild); // TODO: or inherit reference to controlgroup without being child of form?
// rescue persistent elements from dump
detach = document.createDocumentFragment();
child_list = update_target.children;
for (m = 0, len = child_list.length; m < len; m += 1) {
last_child = child_list[m];
if (last_child.getAttribute("data-persist")) {
detach.appendChild(last_child.cloneNode(true));
}
} }
//and add new dynamic content //empty target, add new dynamic content and detached elements
util.deleteChildren(update_target);
update_target.appendChild(wrapper.fragment); update_target.appendChild(wrapper.fragment);
update_target.appendChild(detach);
// CREATE // CREATE
} else { } else {
selector = wrapper.fragment.firstElementChild || wrapper.fragment; selector = wrapper.fragment.firstElementChild || wrapper.fragment;
// TODO: find way to dig down into tree
if (util.testForString("dyno", selector.className) === false) {
selector = selector.firstChild;
}
pass.state.gadget = selector; pass.state.gadget = selector;
} }
...@@ -6419,6 +6780,8 @@ ...@@ -6419,6 +6780,8 @@
} }
// if a callback is provided, set it on state // if a callback is provided, set it on state
// TODO: once containers work, submit_to should change the container
// vs the whole page?
if (pass.config_dict.property_dict.submit_to) { if (pass.config_dict.property_dict.submit_to) {
pass.state.callback = pass.config_dict.property_dict.submit_to; pass.state.callback = pass.config_dict.property_dict.submit_to;
} }
...@@ -6432,7 +6795,8 @@ ...@@ -6432,7 +6795,8 @@
app.setInfo( app.setInfo(
pass.create ? wrapper.fragment : selector, pass.create ? wrapper.fragment : selector,
pass.state.query, pass.state.query,
pass.state.total pass.state.total,
pass.state.selected
); );
} }
} }
...@@ -6479,6 +6843,167 @@ ...@@ -6479,6 +6843,167 @@
/* ********************************************************************** */ /* ********************************************************************** */
app.util = {}; app.util = {};
/** Fetch a subordinate record to set values of an object
* @method setSubordinate
* @method setParam
* @param {object} kid Element configuration object
* @param {object} wrapper Wrapping document
* @returns {object} kid
*/
// TODO: change setParams into scheme like structure to use same handler?
app.util.setSubordinate = function (element, wrapper) {
var i, len, param_list, param, promise_list, field, pass, data;
param_list = element.logic.setParam;
promise_list = [];
data = wrapper.property_dict.data;
// NOTE: data may be undefined - no records because of missing link
// NOTE: throw?
if (data) {
for (i = 0, len = param_list.length; i < len; i += 1) {
param = param_list[i];
// NOTE: all regular params should be deleted by now!
field = param[1];
pass = {
"field": field,
"relation": data.doc[field],
"subordinate": field.split("subordinate_")[1]
};
promise_list[i] = storage.subordinate(pass);
}
}
return RSVP.all(promise_list)
.then(function (response_list) {
var j, k, res_len, response, param_len, out_param, val;
// TODO: CUSTOM CODE, wrap in callback and make generic handler
for (j = 0, res_len = response_list.length; j < res_len; j += 1) {
response = response_list[j];
for (k = 0, param_len = param_list.length; k < param_len; k += 1) {
out_param = param_list[k];
if (response.field === out_param[1]) {
val = out_param[0];
element.logic[val] = element.logic[val] || "";
element.logic[val] += response.value;
}
}
}
return element;
})
.fail(app.util.error);
};
/** Set parameters on an object or flag object for subordination =
* fetch related record to get value
* @method setParam
* @param {object} kid Element configuration object
* @param {object} wrapper Wrapping document
* @returns {object} kid
*/
// TODO: clean up, no exceptions (location), clear key + val!
// TODO: make lookup parsing robust!
app.util.setParam = function (kid, wrapper) {
var i, len, param_list, param, href, loc, splitter, key, val, lookup, new_val;
param_list = kid.logic.setParam;
for (i = 0, len = param_list.length; i < len; i += 1) {
param = param_list[i];
val = param[1];
key = param[0];
switch (val) {
// NOTE: hacked for oauth redirect url
// TODO: find way to include encoding when setting a href
case "location":
href = kid.direct.href;
splitter = href.indexOf("?") > 0 ? "&" : "?";
loc = window.location;
kid.direct.href += splitter + window.encodeURIComponent(key) +
"=" + window.encodeURIComponent(
loc.origin + loc.pathname + loc.hash.split("?")[0]
);
break;
// set values or flag for subordination inside map.element
default:
kid.logic[key] = kid.logic[key] || "";
if (val.split("subordinate_").length > 1) {
// NOTE: try to get value from state/URL before flagging
// NOTE: must check for equality, otherwise id foo > foofoo
// TODO: this is still super-not-robust... redo!
lookup = wrapper.property_dict.state.query.query;
if (lookup && lookup.indexOf(val) > -1) {
new_val = lookup.split(val)[1].split("+")[0]
.replace(":=", "").replace(")","");
if (kid.logic[key] !== new_val) {
kid.logic[key] += new_val;
}
} else {
kid.needs_subordination = true;
}
} else {
kid.logic[key] += wrapper.property_dict.data.doc[val];
delete kid.logic.setParam[i];
}
}
}
return kid;
};
/**
* Parse url query parameter into storage query object
* Expects the following URL format:
*
* #foo&
* query:id=bar+foo=baz&
* limit:start=0+items=5&
* sort:id=ascending+foo=descending&
* select:id+foo+baz+cous
*
* @method parseUrlQuery
* @param {string} str String to parse
* @returns {object} Query to run based on parameters
*/
app.util.parseQueryParameter = function (str) {
var i, param_list, param_len, param, initial_query, indicator,
value_list;
param_list = str.split("&");
initial_query = {};
for (i = 0, param_len = param_list.length; i < param_len; i += 1) {
param = param_list[i].split(":");
indicator = param[0];
value_list = param[1];
switch (indicator) {
case "query":
initial_query.query = param[1].replace("=", ":=", "g")
.replace("+", " AND ", "g");
break;
case "limit":
// NOTE: Thanks Tristan!
initial_query.limit = param[1].split("+")
.map(function (part) { return part.split("=")[1]; });
break;
case "sort":
initial_query.sort_on = param[1].split("+").map(function (part) {
var s = part.split("=");
return [s[0], s[1]];
});
break;
case "select":
initial_query.select_list = param[1].replace("+", ",", "g");
break;
}
}
return initial_query;
};
/** /**
* Parse a clicked link to determine which page to load * Parse a clicked link to determine which page to load
* @method parseLink * @method parseLink
...@@ -6486,14 +7011,14 @@ ...@@ -6486,14 +7011,14 @@
* @return {object} navigation object * @return {object} navigation object
**/ **/
app.util.parseLink = function (url) { app.util.parseLink = function (url) {
var i, hash, path, clean_hash, backup, decode, mode, root; var i, hash, path, clean_hash, decode, root, last, stripped, url_query,
strip;
hash = $.mobile.path.parseUrl( hash = $.mobile.path.parseUrl(
url.replace($.mobile.dialogHashKey, "") url.replace($.mobile.dialogHashKey, "")
).hash.replace("#", ""); ).hash.replace("#", "");
// decode = /^[^\/]*%2[^\/]*$/.test(hash); // decode = /^[^\/]*%2[^\/]*$/.test(hash);
decode = /%[0-9a-f]{2}/i.test(hash); decode = /%[0-9a-f]{2}/i.test(hash);
backup = 0;
// decode (allowing URI encoded identifiers) // decode (allowing URI encoded identifiers)
if (decode) { if (decode) {
...@@ -6502,7 +7027,15 @@ ...@@ -6502,7 +7027,15 @@
clean_hash = hash; clean_hash = hash;
} }
if (clean_hash === "") { // query parameters
strip = clean_hash.split("&");
stripped = strip[0];
if (strip.length > 1) {
url_query = app.util.parseQueryParameter(strip[1]);
}
if (stripped === "") {
root = util.getPage().getAttribute("data-url"); root = util.getPage().getAttribute("data-url");
return { return {
"data_url": root, "data_url": root,
...@@ -6510,26 +7043,15 @@ ...@@ -6510,26 +7043,15 @@
}; };
} }
// check for mode // check for mode
path = clean_hash.split("/"); path = stripped.split("/");
last = path.length -1;
// TODO: this should be generic and without a backup....
// TODO: REFACTOR!!!
for (i = 0; i < path.length; i += 1) {
switch (path[i]) {
case "plan":
case "personal":
case "order":
backup = 1;
mode = path[i];
break;
}
}
return { return {
"mode": mode, "mode": path[last],
"fragment_list": path, "fragment_list": path,
"url_query": url_query,
"data_url": clean_hash, "data_url": clean_hash,
"layout_level": path.length - 1 - backup, "layout_level": last,
"deeplink": true, "deeplink": true,
"root": path[0] "root": path[0]
}; };
...@@ -6543,7 +7065,9 @@ ...@@ -6543,7 +7065,9 @@
* @return {string} href * @return {string} href
*/ */
app.util.generateLink = function (spec, id) { app.util.generateLink = function (spec, id) {
var level, core, separator; var level, core, separator, empty_string;
empty_string = "";
// external link // external link
if (spec.source) { if (spec.source) {
...@@ -6551,15 +7075,15 @@ ...@@ -6551,15 +7075,15 @@
} }
// link current segment parameter vs segment // link current segment parameter vs segment
if (spec.link_core.split("::").length > 1) { if ((spec.link_core || empty_string).split("%26").length > 1) {
separator = ""; separator = empty_string;
} else { } else {
separator = "/"; separator = "/";
} }
level = spec.layout_level || 0; level = spec.layout_level || 0;
core = spec.link_core || (spec.fragment_list ? core = spec.link_core || (spec.fragment_list ?
spec.fragment_list.slice(0, level + 1).join("/") : ""); spec.fragment_list.slice(0, level + 1).join("/") : empty_string);
return ("#" + core + separator + window.encodeURIComponent(id)); return ("#" + core + separator + window.encodeURIComponent(id));
}; };
...@@ -6678,11 +7202,6 @@ ...@@ -6678,11 +7202,6 @@
* @param {Object} spec The configuration for the module to load * @param {Object} spec The configuration for the module to load
* @param {Promise} The promise * @param {Promise} The promise
*/ */
/**
* Generate storages if specified in storage recipe/definition
* @method setStorage
* @param {object} content_dict JSON configuration for storage
**/
app.init.config = function (content_dict) { app.init.config = function (content_dict) {
var i, j, arr, promise_list, len, feature, feature_len, name, dict, var i, j, arr, promise_list, len, feature, feature_len, name, dict,
set, type, nav, language, target, initializer; set, type, nav, language, target, initializer;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment