Commit 3b473853 authored by Sven Franck's avatar Sven Franck

app: made link and content element generation generic

parent 1e14661d
......@@ -983,12 +983,26 @@
* @return controlgroup
*/
factory.widget.controlgroup = function (spec) {
var container, group, direction, contain, label, i18n, target;
var container, group, direction, contain, label, i18n, target, generator;
container = document.createDocumentFragment();
direction = spec.direction || "vertical";
// label
// NOTE: will only be used for dynamic element creation
generator = function (el, wrapper, i) {
// TODO: no!
if (el.center) {
el.text = el.center[0].title;
el.text_i18n = el.center[0].title_i18n;
}
el.iconpos = "right";
return {
"type": "item",
"content": factory.util.generateContentElement("link", el, {})[0]
};
};
// controlgroup label
if (spec.label) {
// NOTE: this will always wrap controlgroups!!!
i18n = spec.label.title_i18n || spec.label.text_i18n;
......@@ -1043,7 +1057,9 @@
return {
"fragment": target,
"child_selector": target.querySelector("div.ui-controlgroup-controls")
"child_selector": target.querySelector("div.ui-controlgroup-controls"),
"child_constructor": generator,
"child_mapper": spec.map_children
};
};
......@@ -1596,12 +1612,10 @@
// makes carousel elements
generator = function (element, wrapper, i) {
var item, config, target, has_link, caption_wrapper, j, len, block,
is_img, section, arr, len, k;
var item, config, target, has_link;
config = wrapper.property_dict;
has_link = element.href;
len = element.content.length;
item = factory.element({
"type": "li",
"direct": {"className": (i === 0 ? "ui-carousel-active" : "")}
......@@ -1616,21 +1630,8 @@
target = item;
}
// loop over all sections = array (left|center|right...?)
for (section in element) {
if (element.hasOwnProperty(section)) {
arr = element[section];
if (typeof arr === "object" && arr !== null) {
len = arr.length;
for (k = 0; k < len; k += 1) {
block = arr[k];
target.appendChild(
factory.util.generateCustomElement(block.type, block, element)[0]
);
}
}
}
}
// generate contents
target.appendChild(factory.util.generateContent(element)[0]);
if (has_link) {
item.appendChild(target);
......@@ -1804,14 +1805,12 @@
// generate list item
generator = function (element, wrapper, i) {
var divider, static_item, theme, config, auto, last, item, section,
target, block, j, section, len, k, made, class_string, split, arr;
var divider, static_item, theme, config, auto, last, item, target, content;
config = wrapper.property_dict;
divider = element.type === "divider" ? true : undefined;
static_item = (element.href === undefined && !divider) ? true : undefined;
theme = config.divider_theme || config.theme || "inherit";
class_string = "";
// autodividers (TODO: does this work?)
if (config.autodividers) {
......@@ -1837,30 +1836,12 @@
target = document.createDocumentFragment();
} else {
element.is_main = true;
target = factory.util.generateCustomElement("link", element, config)[0];
target = factory.util.generateContentElement("link", element, config)[0];
}
// loop over all sections = array (left|center|right...?)
for (section in element) {
if (element.hasOwnProperty(section)) {
arr = element[section];
if (typeof arr === "object" && arr !== null) {
len = arr.length;
for (k = 0; k < len; k += 1) {
block = arr[k];
made = factory.util.generateCustomElement(block.type, block, element);
class_string += made[1];
// split
if (made[1] === "ui-li-has-alt") {
split = made[0];
} else {
target.appendChild(made[0]);
}
}
}
}
}
// generate contents, split button will return [frag1, frag2, class_list]
content = factory.util.generateContent(element, "ui-li-has-alt");
target.appendChild(content[0]);
// list item spec
item = factory.element({
......@@ -1869,7 +1850,7 @@
"className": divider ? ("ui-li-divider ui-bar-" + theme) : " " +
(i === 0 ? " ui-first-child " :
((i === config.length - 1) ?
" ui-last-child " : " ")) + class_string +
" ui-last-child " : " ")) + content.pop() +
(static_item ? " ui-li-static ui-body-inherit " : " ") +
(config.form_item ? "ui-field-contain " : " ") +
(config.reveal ? "ui-screen-hidden " : " ")
......@@ -1882,8 +1863,10 @@
// assemble
item.appendChild(target);
if (split) {
item.appendChild(split);
// link-alt
if (!!content[1]) {
item.appendChild(content[1]);
}
return {
......@@ -2371,18 +2354,54 @@
return breadcrumb;
};
/**
* Loop over object and generate content elements inside array
* @method generateContent
* @param {object} config Custom content config object
* @param {string} split Indicator whether to split content
* @return {array} [content fragment, split content, class_string]
**/
// TODO: evolve into something not requiring this and the next method...
factory.util.generateContent = function (config, split) {
var section, arr, len, k, block, content, class_string, fragment, appendix;
class_string = "";
fragment = document.createDocumentFragment();
for (section in config) {
if (config.hasOwnProperty(section)) {
arr = config[section];
if (typeof arr === "object" && arr !== null) {
len = arr.length;
for (k = 0; k < len; k += 1) {
block = arr[k];
content = factory.util.generateContentElement(block.type, block, config);
class_string += content[1];
if (content[1] === split) {
appendix = content[0];
} else {
fragment.appendChild(content[0]);
}
}
}
}
}
return [fragment, appendix, class_string];
};
/**
* central method to generate custom-type elements
* @method generateCustomElement
* @method generateContentElement
* @param {string} type Type of custom element
* @param {object} spec Configuration object
* @param {object} config Parent element configuration properties
* @return {array} [element, parent_class]
**/
// TODO: in case other elements also need parent_class, map here
// TODO: spec.value contains record values, so make sure they are here
factory.util.generateCustomElement = function (type, spec, config) {
var id, is_type, is_main, no_icon, input_dict, container;
// TODO: class_string only works for listview, could be expanded
// TODO: this is crap though....
factory.util.generateContentElement = function (type, spec, config) {
var id, is_type, is_main, no_icon, input_dict, container, is_text;
switch (type) {
......@@ -2436,7 +2455,7 @@
}), "ui-li-has-icon"];
// main link, split button
// TODO: make icon generic!
// TODO: make icon generic! what about util.class_string
case "link":
is_main = !!spec.is_main;
no_icon = config.icon === null;
......@@ -2448,11 +2467,11 @@
(config.split_theme || config.theme || "inherit") +
(no_icon ? " " : (is_main ? " ui-btn-icon-right ":
" ui-btn-icon-" + (spec.iconpos || "notext")) +
"ui-icon-" + (config.icon || spec.icon || "carat-r"))
" ui-icon-" + (config.icon || spec.icon || "carat-r"))
},
"attributes": {
"title": spec.title || "",
"data-i18n": "[title]" + (spec.title_i18n || "")
"data-i18n": "[title]" + (spec.title_i18n || "") + ";" + (spec.text_i18n || "")
},
"logic":{
"rel": spec.external ? "external" : null,
......@@ -2462,7 +2481,7 @@
}), "ui-li-has-alt"];
// checkbox/radio
// TODO: fiddle in refrence here
// TODO: reference??
case "check":
case "radio":
// need to do this out here to account for action
......@@ -2510,15 +2529,15 @@
return [factory.element(spec), ""];
}
return [factory.element({
"type": spec.type,
"type": spec.type || "span",
"direct": {
"className": (spec.aside ? "ui-li-aside " : " ") +
(spec.text_i18n ? "translate " : " ") +
(spec.class_list || "")
},
"logic": {
"text": (spec.value || spec.text),
"data-i18n": spec.text_i18n || null
"text": (spec.value || spec.title || spec.text),
"data-i18n": spec.text_i18n || spec.title_i18n || null
}
}), ""];
......@@ -2578,80 +2597,8 @@
}]
}
};
default: alert("default needs noItems"); break;
}
/*
output = {"children": []};
data = content_dict || {};
switch (type) {
case "td": class_string = "ui-no-result"; break;
case "li": class_string = "ui-li ui-li-static ui-first-child ui-last-child " +
"ui-no-result ui-body-inherit";
break;
default: class_string = "responsive ui-content-element"; break;
};
// container
fragment = {
"type": type || "p",
"direct": {"className": class_string},
"attributes": {"colspan": count || null},
"children":[{
"type": "span",
"direct": {"className": "translate"},
"attributes": {"data-i18n": data.message_i18n || "validation_dict.no_items_found"},
"logic": {"text": data.message || "No items found."}
}]
};
// custom message (e.g. modernizr features)
if (data.dynamic) {
fragment.children.push({
"type": "span",
"logic": {"text": message}
});
default: alert("placeholder for no items missing"); break;
}
// action menu
if (data.children && data.children.length > 0) {
action_menu = {
"generate": "widget",
"type": "controlgroup",
"property_dict": {"direction": "horizontal"},
"children": []
};
for (i = 0; i < data.children.length; i += 1) {
button = data.children[i];
back = button.back;
action_menu.children.push({
"type": "a",
"direct": {
"href": back ? "#" : button.href,
"className": "ui-corner-all ui-btn ui-shadow ui-btn-inline " +
(back ? "ui-icon-chevron-sign-left ui-btn-icon-left " :
(button.icon ? "ui-icon-" + button.icon +
" ui-btn-icon-left " : " ")) + (button.class_list || "")
},
"attributes": {
"data-action": button.action || null,
"data-rel": back ? "back" : (button.rel || null),
"data-i18n": back ?
"global_dict.back" : button.text_i18n
},
"logic": {"text": back ? "Back" : button.text}
});
}
fragment.children.push(action_menu);
}
// table cells need a wrapping row
if (type === "td") {
return {"type": "tr", "children": [fragment]};
}*/
};
/* ********************************************************************** */
......@@ -3553,27 +3500,22 @@
**/
// TODO: multiple header rows!
// TODO: action_menu input + form?
// TODO: merge with list mapping
// TODO: how to handle translations of record texts?
// TODO: merge link building with listItem (allow custom core)
map.tableItem = function (item, wrapper, i) {
var j, k, l, segment, map_section, section, row, cell, fragment,
base, quirk_dict, record, record_id, core, crop, re;
var j, k, segment, row, cell, id, quirk_dict, record, new_item;
quirk_dict = wrapper.property_dict;
record = item.doc;
record_id = record[quirk_dict.link_identifier || "id"];
core = {"id": record_id || item["id"] || null};
// link base
if (quirk_dict.link && !quirk_dict.link_source) {
fragment = quirk_dict.fragment_list;
if (fragment.length > 0) {
base = fragment.slice(0, (quirk_dict.layout_level || 0) + 1).join("/");
}
core.href = record[quirk_dict.link_source] ||
("#" + (base || "") + "/" + window.encodeURIComponent(record_id));
core.external = quirk_dict.link_external || null;
id = record[quirk_dict.link_identifier] || record["_id"] || item["_id"];
new_item = {};
// id
new_item.id = id;
// link
if (quirk_dict.link) {
new_item.href = app.util.generateLink(quirk_dict, id);
new_item.external = quirk_dict.external;
}
// loop schemes
......@@ -3581,14 +3523,13 @@
segment = item.scheme[j];
row = [];
// loop field_list = cells per row
// loop field_list = cells
for (k = 0; k < segment.field_list.length; k += 1) {
cell = util.mergeObject(core, util.cloneObject(segment.field_list[k]));
cell = util.mergeObject(new_item, util.cloneObject(segment.field_list[k]));
// custom header (!) cells have text/i18n defined
// TODO: convert to input field here?
if (!cell.custom) {
cell.text = util.generateText(record[cell.field], cell, record)
cell.text = util.generateText(record[field.value || field.field], cell, record);
cell.text_i18n = record.text_i18n || null;
}
row.push(cell);
......@@ -3609,40 +3550,18 @@
* @param {integer} i Counter indicating current item
* @return {object} mapped object
**/
// TODO: move radio/check into property_dict and on item level?
// 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: core?
// NOTE: make sure there is no "id" flying through here!!! only _id
map.listItem = function (item, wrapper, i) {
var quirk_dict, level, core, new_item, section, pos, label, j, k, field,
record, property, source;
var quirk_dict, core, section, pos, label, j, k, field, setter,
record, property, source, new_item, id, key, obj, translation_fields;
translation_fields = "titletextlabel";
quirk_dict = wrapper.property_dict;
record = item.doc;
new_item = {
"type": "item"
};
// link base
if (quirk_dict.link) {
label = true;
source = quirk_dict.link_source;
if (source) {
new_item.href = source;
} else {
level = quirk_dict.layout_level || 0;
core = quirk_dict.link_core || (quirk_dict.fragment_list ?
quirk_dict.fragment_list.slice(0, level + 1).join("/") : "");
// set
new_item.href = ("#" + core + "/" + window.encodeURIComponent(
record[quirk_dict.link_identifier || "_id"])
);
}
if (quirk_dict.link_external) {
new_item.external = true;
}
}
id = record[quirk_dict.link_identifier] || record["_id"] || item["_id"];
new_item = {};
// radio
if (quirk_dict.radio) {
......@@ -3656,10 +3575,16 @@
new_item.right = [{"type": "check", "action": "check"}];
}
// add record id for radio/check/linking
// TODO: develop a clean way to use _id and id. this is bad!
// link
if (quirk_dict.link) {
label = true;
new_item.href = app.util.generateLink(quirk_dict, id);
new_item.external = quirk_dict.external;
}
// id
if (label) {
new_item.id = record["id"] || record["_id"] || null;
new_item.id = id;
}
// loop scheme sections
......@@ -3671,14 +3596,17 @@
// loop scheme fields
for (k = 0; k < section.field_list.length; k += 1) {
field = section.field_list[k];
new_item[pos].push(util.mergeObject(
field,
{
"value": util.generateText(
record[field.value || field.field], field, record
)
}
));
obj = {};
key = field.value || field.field;
if (translation_fields.indexOf(key) > -1) {
setter = key;
obj[setter + "_i18n"] = record[key + "_i18n"];
} else {
setter = "value";
}
obj[setter] = util.generateText(record[key], field, record);
new_item[pos].push(util.mergeObject(field, obj));
}
}
......@@ -5320,69 +5248,6 @@
document.title = value;
};
/**
* Parse a clicked link to determine which page to load
* @method parseLink
* @param {string} url Url being navigated to
* @return {object} navigation object
**/
app.parseLink = function (url) {
var i, hash, path, clean_hash, backup, decode, mode, root;
hash = $.mobile.path.parseUrl(
url.replace($.mobile.dialogHashKey, "")
).hash.replace("#", "");
decode = /^[^\/]*%2[^\/]*$/.test(hash);
backup = 0;
// decode (allowing URI encoded identifiers)
if (decode) {
clean_hash = window.decodeURIComponent(hash);
} else {
clean_hash = hash;
}
if (clean_hash === "") {
root = util.getPage().getAttribute("data-url");
return {
"data_url": root,
"root": root
};
}
// check for mode
path = clean_hash.split("/");
// TODO: this should be generic and without a backup....
// TODO: REFACTOR!!!
for (i = 0; i < path.length; i += 1) {
switch (path[i]) {
case "new":
mode = "new";
backup = 1;
break;
case "add":
case "config":
case "scope":
case "ssl_on":
case "ssl_off":
case "ssl":
case "request":
case "installation":
mode = path[i];
break;
}
}
return {
"mode": mode,
"fragment_list": path,
"data_url": clean_hash,
"layout_level": path.length - 1 - backup,
"deeplink": true,
"root": path[0]
};
};
/**
* Parse a page for gadgets and run page setup
* @method parsePage
......@@ -5419,7 +5284,7 @@
if (data && data.options.reverse) {
raw_url = window.decodeURIComponent(raw_url);
}
config = app.parseLink(raw_url);
config = app.util.parseLink(raw_url);
if (e) {
page = util.getPage(raw_url.split("#").pop());
......@@ -6767,6 +6632,91 @@
/* ********************************************************************** */
app.util = {};
/**
* Parse a clicked link to determine which page to load
* @method parseLink
* @param {string} url Url being navigated to
* @return {object} navigation object
**/
app.util.parseLink = function (url) {
var i, hash, path, clean_hash, backup, decode, mode, root;
hash = $.mobile.path.parseUrl(
url.replace($.mobile.dialogHashKey, "")
).hash.replace("#", "");
decode = /^[^\/]*%2[^\/]*$/.test(hash);
backup = 0;
// decode (allowing URI encoded identifiers)
if (decode) {
clean_hash = window.decodeURIComponent(hash);
} else {
clean_hash = hash;
}
if (clean_hash === "") {
root = util.getPage().getAttribute("data-url");
return {
"data_url": root,
"root": root
};
}
// check for mode
path = clean_hash.split("/");
// TODO: this should be generic and without a backup....
// TODO: REFACTOR!!!
for (i = 0; i < path.length; i += 1) {
switch (path[i]) {
case "new":
mode = "new";
backup = 1;
break;
case "add":
case "config":
case "scope":
case "ssl_on":
case "ssl_off":
case "ssl":
case "request":
case "installation":
mode = path[i];
break;
}
}
return {
"mode": mode,
"fragment_list": path,
"data_url": clean_hash,
"layout_level": path.length - 1 - backup,
"deeplink": true,
"root": path[0]
};
};
/**
* Generate a link based on hierarchy and record
* @method generateLink
* @param {object} spec Object containing query/link related info
* @param {object} record Object containing data including link id
* @return {string} href
*/
app.util.generateLink = function (spec, id) {
var level, core;
if (spec.source) {
return spec.source;
}
level = spec.layout_level || 0;
core = spec.link_core || (spec.fragment_list ?
spec.fragment_list.slice(0, level + 1).join("/") : "");
return ("#" + core + "/" + window.encodeURIComponent(id)
);
};
/**
* Main error handler
* @method error
......
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