Commit c56accc9 authored by Sven Franck's avatar Sven Franck

rewrite factory to handle widgets, gadgets, elements

parent e1636c58
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
// ERP5 custom methods // ERP5 custom methods
var erp5 = {}; var erp5 = {};
// JQM content generator // JQM content erateerator
var factory = {}; var factory = {};
/* ====================================================================== */ /* ====================================================================== */
...@@ -272,8 +272,8 @@ ...@@ -272,8 +272,8 @@
// NOTE: method must be present or added to validation handler // NOTE: method must be present or added to validation handler
if (prevail.properties.external_validator || if (prevail.properties.external_validator ||
spec.properties.external_validator) { spec.properties.external_validator) {
validation_list += prevail.properties.external_validator || validation_list += (prevail.properties.external_validator ||
spec.properties.external_validator; spec.properties.external_validator);
} }
// required // required
...@@ -600,7 +600,7 @@ ...@@ -600,7 +600,7 @@
/* ====================================================================== */ /* ====================================================================== */
/* ********************************************************************** */ /* ********************************************************************** */
/* "mapping to erp5" */ /* Factory Mappings (to ERP5) */
/* ********************************************************************** */ /* ********************************************************************** */
factory.map_buttons = erp5.map_buttons; factory.map_buttons = erp5.map_buttons;
factory.map_actions = erp5.map_actions; factory.map_actions = erp5.map_actions;
...@@ -608,923 +608,1403 @@ ...@@ -608,923 +608,1403 @@
factory.map_utils = erp5.map_utils; factory.map_utils = erp5.map_utils;
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM "Bar" */ /* Factory Utils */
/* ********************************************************************** */ /* ********************************************************************** */
factory.util = {};
/* /*
* Generate a generic bar (table wrapper, controlbar, collapsible header) * Forward to factory generator depending on "generate". This method will
* @method generateToolbar * handle generation of elements, widgets (and gadgets?)
* @param {object} config Elements to add to the bar * @method forward
* @param {boolean} slot Wrap element in a slot container * @param {object} spec Configuration object for the element to be created
* @param {string} reference Gadget reference pointer * @return {object} HTML object containing generated elements
* @returns {array} HTML fragment and flag for popups to be created
*/ */
factory.generateToolbar = function (elements, slot, reference) { factory.util.forward = function (spec) {
var element, switch (spec.generate) {
m, // widget generator
n, case "widget":
o, return factory["generate" + spec.type](spec);
item, break;
trigger_element, // gadget generator
target, case "gadget":
include,
wrapped_in_slot,
add_to_first,
flag = {},
config = {},
container = document.createDocumentFragment();
if (slot) { break;
wrapped_in_slot = true; // HTML element generator (case "undefined")
default:
switch (spec.type) {
case "input":
case "select":
return factory.generateFormElement(spec, false);
break;
default:
return factory.generateElement(
spec.type,
spec.direct,
spec.attributes,
spec.logic
);
break;
}
break;
} }
};
// loop functionalities /*
for (m = 0; m < elements.length; m += 1) { * Loop over a selection of elements and generate the respective content
element = elements[m]; * @method generateFromArray
if (wrapped_in_slot) { * @param {array} spec Array containing the elements to generate
target = factory.generateElement( * @param {string} type Requesting widget
"div", {}, {"data-slot": true, "data-slot-id": element.slot} * @param {object} hack
); * @return {object} fragment HTML object containing the elements
} else { */
target = container; // TODO: refactor. Remove hack!!!!
} // NOTE: this can only handle fully described elements in an array (no li!)
factory.util.generateFromArray = function (spec, type, hack) {
var i,
target,
class_list,
element,
order,
fragment = document.createDocumentFragment();
trigger_element = element.element || element.widget; for (i = 0; i < spec.length; i += 1) {
// TODO: don't set in every case (because of controlgroup); element = spec[i];
target = undefined;
switch (trigger_element.type) { // class string
case "input": if (element.direct) {
case "select": order = i === 0 ? " ui-first-child " :
trigger_element.attributes["data-reference"] = reference; (i === (spec.length - 1) ? " ui-last-child " : " ");
target.appendChild(
factory.generateFormElement(trigger_element, false) element.direct.className = (element.direct.className || "") + order +
(element.type === "a" ? (" ui-btn ui-shadow " +
factory.generateIconClassString(element)) : " ");
}
switch (type) {
case "panel":
// TODO: refactor panel_element CSS!
target = factory.generateElement(
"div",
{"className":"panel_element " + (i === 0 ?
"panel_element_first panel_header " :
((i === spec.length - 1) ?
"panel_element_last" : " "))
}
); );
break; // HACK: this adds the panel close button, don't do this here!
case "controlgroup": if (i === 0 && hack) {
for (o = 0; o < element.children.length; o += 1) { target.appendChild(hack);
element.children[o].attributes["data-reference"] = reference;
} }
target.appendChild(factory.generateControlgroup({
"type": "controlgroup",
"direction": trigger_element.direction,
"class": trigger_element.widget_class,
"buttons": element.children
}));
break; break;
default: case "navbar":
trigger_element.attributes["data-reference"] = reference; target = factory.generateElement(
target.appendChild(factory.generateElement( "li",
trigger_element.type, {"className": "ui-block-" + util.toLetters(i+1).toLowerCase()}
trigger_element.direct, );
(trigger_element.attributes),
(trigger_element.logic)
));
break; break;
case "header":
// TODO: mercy, refactor!
if (spec.length > 1 && i !== 1) {
target = factory.generateElement(
"div",
{
"className": " ui-" +
((i === 0 ? "first" : (i === 2 ? "last" : "no")) + "-wrap ")
}
);
}
}; };
// generate with/without wrapper
// TODO: do differently... if (target) {
if (element.global_popup) { target.appendChild(factory.util.forward(element));
flag.global_popup = true; fragment.appendChild(target);
}
if (element.local_popup) {
flag.local_popup = true;
}
if (wrapped_in_slot) {
container.appendChild(target);
} else { } else {
container = target; fragment.appendChild(factory.util.forward(element));
} }
} }
return [container, flag]; return fragment;
};
/**
* Generate a form wrapper
* @method wrapInForm
* @param {object} spec Configuration
* @return {object} form object of fragment
*/
factory.util.wrapInForm = function (id) {
if (id) {
return factory.generateElement(
"form",
{"method": "POST", "action": "#", "id": id},
{"data-ajax": false}
);
}
return document.createDocumentFragment();
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Page */ /* Factory Methods */
/* ********************************************************************** */
/* ********************************************************************** */
/* JQM POPUP */
/* ********************************************************************** */ /* ********************************************************************** */
/** /**
* Generate an empty JQM page * Generate a pre-enhanced popup and necessary elements
* @method generatePage * Full options (with defaults)
* @param {object} config Config object based on parsed link * {
* @param {object} layout Layout for the page to generate * "generate": "widget",
* @return {object} HTML fragment * "type":"popup",
*/ * "class_list": "",
// NOTE: we are defaulting to fixed toolbars! * "theme": "",
factory.generatePage = function (config, layout) { * "id": null,
var page = factory.generateElement( * "property_dict": {
"div", * "overlay-theme": null,
{ * "transition": "fade",
"id": config.id, * "position-to": "window",
"className": "ui-page " + ("ui-page-theme-" + layout.theme || "") + * "tolerance": "30,30,30,30",
" " + ((layout.fix && layout.fix === false) ? "" : * "shadow": true
" ui-page-header-fixed ui-page-footer-fixed") * },
}, { * "form": null,
"data-module": config.id, * "children": [],
"data-role": "page", * }
"data-url": config.url, * @method generatePopup
"data-external-page": true, * @param {object} spec JSON configuration for popup to be generated
"tabindex": 0, * @param {string} scope id of page to append popup
"data-enhanced": true * @return {object} documentFragment (global)/placeholder element (local)
*/
// TODO: missing state
// TODO: generate without referencing IDs
// NOTE: scope (element id) will make the popup local
factory.generatePopup = function (spec, scope) {
var target, popup, wrap, id, config, container, placeholder;
if (spec === undefined) {
util.errorHandler({"error": "GeneratePopup: Missing configuration"});
} else {
container = document.createDocumentFragment();
config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-popup") : "global_popup");
// container
container.appendChild(factory.generateElement(
"div",
{
"className": "ui-popup-screen ui-screen-hidden " +
(config.overlay_theme ?
("ui-overlay-" + config.overlay_theme) : ""),
"id": id + "-screen"
}
));
// popup wrapper
wrap = factory.generateElement(
"div",
{
"className": "ui-popup-container ui-corner-all ui-popup-hidden " +
" ui-popup-truncate " + (config.transition || "fade"),
"id": id + "-popup"
}
);
// popup
popup = factory.generateElement(
"div",
{
"className": "ui-popup ui-body-" + spec.theme +
(config.shadow ? " ui-overlay-shadow " : " ") +
" ui-corner-all " + spec.class_list,
"id": id
},
{
"data-transition": config.transition || "fade",
"data-role": "popup",
"data-enhanced": "true",
"data-position-to": config.position || "window",
"data-tolerance": config.tolerance || "30,30,30,30"
},
{
"data-theme": spec.theme || null,
"data-overlay-theme": config.overlay_theme || null
}
);
// placeholder
placeholder = factory.generateElement(
"div",
{"id": id + "-placeholder"},
{"style": "display:none;"}
);
// form
target = factory.util.wrapInForm(spec.form);
// children/action buttons
if (spec.children) {
popup.appendChild(
factory.util.generateFromArray(spec.children, "popup")
);
} }
);
// set state // assemble popup to target (form/fragment) to wrapper to container
target.appendChild(popup);
wrap.appendChild(target);
container.appendChild(wrap);
return page; // add to DOM if scoped
if (scope) {
document.getElementById(scope).appendChild(container);
// and return the placeholder for JQM
return placeholder;
}
// also add placeholder to fragment
container.appendChild(placeholder);
return container;
}
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Table */ /* JQM Header */
/* ********************************************************************** */ /* ********************************************************************** */
/* /**
* Generates a table header based on configuration and portal_type * Generates JQM header. Header buttons are wrapped in controlgroups!
* @method generateTableHeader * Full options (with defaults)
* @param {object} settings Configuration for table to create * {
* @param {object} fields Field configurations for this portal Type * "generate": "widget",
* "type": "Header",
* "class_list": "",
* "theme": "",
* "id": null,
* "form": null,
* "property_dict": {
* "title": "",
* "title_i18n":"",
* "fixed": true
* },
* "children": [],
* }
* @method generateHeader
* @param {object} spec JSON configuration
* @param {string} scope Id of page header should be appended to
* @return {object} HTML fragment
*/ */
// TODO: single row ok. multi row to make // NOTE: Logos should be added as children of the header!
factory.generateTableHeader = function (settings, fields) { // NOTE: page title set in pagehandler, this only sets a placeholder
var k, factory.generateHeader = function (spec, scope) {
l, var config, id, title, wrap, position, children, header, target;
cell,
field,
config,
field_config,
property,
keys,
title,
set,
text,
action,
temp = {},
link = undefined,
check = settings.configuration.table.checkbox_rows,
merger = settings.configuration.table.mergeable_columns,
target = settings.layout[0].columns,
table_header = factory.generateElement("thead"),
row = factory.generateElement("tr");
// tickbox - all
if (check) {
// allow to select all records (not only visible)
action = settings.configuration.table.select_all ?
"check_all" : "check_all_visible";
cell = factory.generateElement("th",{},{},{}); if (spec === undefined) {
config = { util.errorHandler({"error":"Generate Header: Missing configuration"});
"type":"input", } else {
"direct": { config = spec.property_dict || {};
"id": settings.portal_type_title + "_check_all", id = spec.id || (scope ? (scope + "-header") : "global_header");
"className": "action" children = spec.children.length
}, position = children === 2 ? 1 : (children === 0 ? 0 : 1);
// title
title = {
"type": "h1",
"direct": {"className":"translate ui-title"},
"attributes": { "attributes": {
"type": "checkbox", "data-i18n": config.title_i18n || "",
"value": "Select All/Unselect All", "role":"heading",
"data-iconpos":"notext", "aria-level":"1"
"data-reference": settings.base_element.direct.id,
"data-action": action
}, },
"logic": {} "logic": {"text": config.title || "\u00A0"}
} }
cell.appendChild(factory.generateFormElement(config, false, true)); spec.children.splice(position, 0, title);
row.appendChild( cell );
}
// reverse columns so they are mergeable :-) // header
if (merger) { header = factory.generateElement(
target = util.reverseArray(target); "div",
} {
"id": id,
"className":"ui-header " + (spec.class_list || " ") +
(config.fixed ? "ui-header-fixed " : " ") +
" slidedown ui-bar-" + (spec.theme || "inherit")
}, {
"data-role":"header",
"data-theme": spec.theme,
"data-enhanced":"true",
"role":"banner"
}, {
"data-position": config.fixed ? "fixed" : null
}
);
for (l = 0; l < target.length; l += 1) { // form
link = undefined; target = factory.util.wrapInForm(spec.form);
field = target[l];
config = {};
property = field.title;
field_config = {};
if (field.show) { // children/action buttons (wrap first/last)
// TODO: good mapping? if (spec.children) {
field_config = fields[field.title]; target.appendChild(
factory.util.generateFromArray(spec.children, "header")
);
}
if (field.merge === undefined) { // assemble
if (field_config) { header.appendChild(target);
config["data-i18n"] = field_config.widget.title_i18n;
} // add to DOM if scoped
if (field.persist === undefined) { if (scope) {
config["data-priority"] = field.priority || 6; document.getElementById(scope).appendChild(header);
} return undefined;
if (field_config) {
title = temp[property] || field_config.widget.title;
} else {
title = property;
}
if (settings.configuration.table.sorting_columns && field.sort) {
text = {}
// sorting link
link = factory.generateElement(
"a",
{"className":"action ui-sorting ui-btn ui-icon-sort " +
"ui-icon ui-btn-icon-right"},
{
"data-action":"sort",
"data-i18n":"",
"data-reference": settings.base_element.direct.id,
"data-column-title": field.title
},
{"text": title}
);
} else {
text = {"text": title }
}
cell = factory.generateElement(
"th", {"className":"translate"}, config, text
);
if (link) {
cell.appendChild(link);
}
if (merger) {
row.insertBefore(
cell,
(set === undefined ? null : row.childNodes[check ? 1 : 0])
);
set = true;
} else {
row.appendChild(cell);
}
} else {
temp[field.merge] = field.merge_title;
}
} }
}
table_header.appendChild( row );
return table_header; return header;
}
}; };
/* /* ********************************************************************** */
* Generate table rows based on configuration and data provided. Needed /* JQM PANEL */
* to switch between editable and readonly table rows /* ********************************************************************** */
* @method generateTableRow /**
* @param {object} settings Configuration for table row to create * Generates a JQM panel (needs enhancement!)
* @param {object} item Data for this table row * Full spec example (with defaults):
* @returns table_row * {
* "generate": "widget",
* "type": "panel",
* "class_list": null,
* "id": null,
* "theme": null,
* "property_dict" : {
* "close": true
* },
* "children": []
* }
* @method generatePanel
* @param {object} config JSON configuration
* @param {string} scope
* @param {string} scope id of page to append panel
* @return {object} HTML fragment
*/ */
factory.generateTableRow = function (settings, item) { // TODO: Needs pre-enhancement!
var k, factory.generatePanel = function (spec, scope) {
l, var config, id, panel, closer;
i,
cell,
property,
field,
link,
value,
fetch_value,
button,
logic,
keys,
action_menu,
action_buttons,
action_controls,
set,
temp = {},
row = factory.generateElement("tr"),
target = settings.layout[0].columns,
check = settings.configuration.table.checkbox_rows,
merger = settings.configuration.table.mergeable_columns;
if (check) { if (spec === undefined) {
cell = factory.generateElement("th",{},{},{}); util.errorHandler({"error": "Generate Panel: Missing configuration"});
cell.appendChild(factory.generateFormElement( } else {
config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-panel") : "global_panel");
// panel
panel = factory.generateElement(
"div",
{ {
"type":"input", "id": id,
"direct": { "className":"panel " + (spec.class_list || "")
"id": "select_" + item._id, },
"name": "select_" + item._id, {
"className": "action" "data-role":"panel",
"data-theme": spec.theme,
"data-position":"left",
"data-display":"push",
"data-position-fixed": true
}
);
// close button, needs to go into first panel element
// TODO: refactor!!!!!
if (config.close) {
closer = factory.generateElement(
"a",
{
"href":"#",
"className":"panel-close ui-icon-remove ui-btn " +
"ui-btn-icon-notext ui-shadow ui-corner-all"
}, },
"attributes": { {
"type": "checkbox", "data-enhanced": true,
"value": "Select item", "data-i18n": "",
"data-iconpos":"notext", "data-rel":"close"
"data-action":"check",
"data-reference": settings.base_element.direct.id
}, },
"logic": {} {"text":"Close"}
}, );
false, }
true
));
row.appendChild(cell);
}
// reverse if mergable columns // form
if (merger) { target = factory.util.wrapInForm(spec.form);
target = util.reverseArray(target);
// children
if (spec.children) {
target.appendChild(
factory.util.generateFromArray(spec.children, "panel", closer)
);
}
// assemble
panel.appendChild(target);
// add to DOM if scoped
if (scope) {
document.getElementById(scope).appendChild(panel);
return undefined;
}
return panel;
} }
};
// loop fields to display /* ********************************************************************** */
for (l = 0; l < target.length; l += 1) { /* JQM Footer */
field = target[l]; /* ********************************************************************** */
property = field.title; /**
value = item[property]; * Generates JQM footer with navbar or controlgroup based on JSON config
* Full options (with defaults):
* {
* "generate":"widget",
* "type": "footer",
* "class_list": null,
* "id": "null",
* "theme": "slapos-white",
* "form": null,
* "property_dict": {
* "fixed": true
* },
* "children": []
* }
* @method generateFooter
* @param {object} spec JSON configuration
* @param {string} scope ID of element to append footer to
* @return {object} HTML fragment
*/
factory.generateFooter = function (spec, scope) {
var config, id, footer, target;
if (field.show) { if (spec === undefined) {
if (field.merge === undefined) { util.errorHandler({"error": "Generate Footer: Missing config"});
cell = factory.generateElement("td",{},{},{}); } else {
// TODO: links should reflect value but communicate key aswell config = spec.property_dict || {};
link = "#" + settings.portal_type_title + "::" + item._id; id = spec.id || (scope ? (scope + "-footer") : "global_footer");
// TODO: crap...refactor whole section // footer
// fetch non portal_type values footer = factory.generateElement(
if (value === undefined && field.action === false) { "div",
// TODO: bah {
// fetchValue = priv.getERP5property(item._id, field.lookup); "id": id,
if (fetchValue.error) { "className":"ui-footer " + (spec.class_list || " ") +
value = "N/A"; (config.fixed ? "ui-footer-fixed " : " ") +
} "slideup ui-bar-" + (spec.theme || "inherit"),
} },
{
"data-role":"footer",
"data-theme":spec.theme,
"data-enhanced":"true",
"role":"contentinfo"
},
{"data-position": config.fixed ? "fixed" : undefined}
);
if (field.actions) { // form
action_controls = {"direction":"horizontal", "class":"","buttons":[]}; target = factory.util.wrapInForm(spec.form);
for (i = 0; i < field.actions.length; i += 1) {
action_button = factory.map_buttons[field.actions[i]];
if (action_button) {
action_controls.buttons.push({
"type":"a",
"direct": {"href": action_button.href, "className": action_button.classes + " translate ui-btn ui-btn-icon-notext ui-shadow ui-corner-all ui-icon-" + action_button.icon},
"attributes": {"data-enhanced":"true", "data-i18n": action_button.text_i18n, "data-action": field.actions[i]},
"logic": {"text": action_button.text}
});
}
}
action_menu = factory.generateControlgroup(action_controls);
cell.appendChild(action_menu);
} else if (field.status) {
cell.appendChild(factory.generateLinkButton({
"type":"a",
"direct": {"href": link, "className": "status error ui-btn-inline ui-btn translate responsive ui-btn-icon-left ui-shadow ui-corner-all ui-icon-bolt"},
"attributes": { "data-i18n": "[title:" + item.status.message_i18n + ";" + item.status.error_i18n + "]", "data-icon":"bolt", "title": item.status.message},
"logic": {"text": item.status.state}
}));
} else {
// default
if (field.image) {
logic = {"img": item.image}
} else {
// TODO: lame merge
if (temp[property]) {
value += " " + temp[property];
//delete temp[property];
}
logic = {"text":value}
}
// TODO: a link in every cell? binding? // children
// don't touch this just for some status if (spec.children) {
if (settings.configuration.table.linkable_rows) { target.appendChild(
cell.appendChild(factory.generateElement( factory.util.generateFromArray(spec.children, "footer")
"a", );
{"className": "table_link", "href": link},
{},
logic
));
} else {
cell.appendChild(factory.generateElement("span", {}, {}, logic));
}
}
// Grrr...
if (merger) {
row.insertBefore(cell, (set === undefined ? undefined : row.childNodes[check ? 1 : 0]) );
set = true;
} else {
row.appendChild(cell);
}
} else {
// keep the value of cells to be merged
temp[field.merge] = value;
}
} }
// assemble
footer.appendChild(target);
return footer;
} }
return row;
}; };
/* /* ********************************************************************** */
* Generates a table body based on configuration and data provided from JIO /* JQM Controlgroup */
* @method generateTableBody /* ********************************************************************** */
* @param {object} settings Configuration for table body to create /**
* @param {object} answer from JIO * Generate an controlgroup = a button or action menu
* @returns {object} table_body * {
* "generate": "controlgroup",
* "id": null,
* "class_list": null,
* "theme": null,
* "form": null,
* "property_dict": {
* "direction": "horizontal"
* },
* "children": [
* {"type":a, "direct": {}, "attributes": {}, "logic": {}}
* ]
* }
* @method generateControlgroup
* @param {object} spec Configuration for controlgroup
* @return controlgroup
*/ */
factory.generateTableBody = function (settings, answer) { factory.generateControlgroup = function (spec) {
var l, var config, group, direction, controls, target;
row,
item,
property,
field,
error,
max,
table_body = factory.generateElement("tbody",{},{"data-update":"true"});
if (answer && answer.data.total_rows > 0) { if (spec === undefined) {
max = answer.data.total_rows; util.errorHandler({"error":"Generate Controlgroup: Missing config"});
} else {
config = spec.property_dict || {};
direction = config.direction || "vertical";
for (l = 0; l < max; l += 1) { // group
item = answer.data.rows[l].doc; group = factory.generateElement(
row = factory.generateTableRow(settings, item); "div",
table_body.appendChild(row); {
"className":"ui-corner-all ui-controlgroup " +
(spec.class_list || "") + " ui-controlgroup-" + direction
},
{
"data-role": "controlgroup",
"data-enhanced":"true",
"data-type": direction
}
);
// controls
controls = factory.generateElement(
"div", {"className":"ui-controlgroup-controls"}
);
// children
if (spec.children) {
controls.appendChild(
factory.util.generateFromArray(spec.children, "controlgroup")
);
} }
// form
target = factory.util.wrapInForm(spec.form);
// assemble
group.appendChild(controls);
target.appendChild(group);
return target;
}
};
/* ********************************************************************** */
/* JQM Navbar */
/* ********************************************************************** */
/* Generate a navbar
* Full example of spec with all options:
* {
* "generate": "widget",
* "type": "navbar",
* "class_list": null,
* "id": null,
* "theme": "slapos-white",
* "property_dict": {},
* "children":[],
* "form": null
* }
* @method generateNavbar
* @param {object} config Configuration options
* @returns navbar HTML fragment
*/
factory.generateNavbar = function (spec) {
var navbar, controls, target;
if (spec === undefined) {
util.errorHandler({"error":"Generate Navbar: Missing Configuration"});
} else { } else {
// error or 0 results config = spec.property_dict || {};
row = factory.generateElement("tr");
l = settings.layout[0].columns.length;
if (answer === undefined) { // navbar
error = "Error retrieving Data"; navbar = factory.generateElement(
} else if (answer.data.total_rows === 0 ) { "div",
error = "No records found. Please modify your search!"; {"className":"navbar ui-navbar " + (spec.class_list || "")},
} else { {"data-role":"navbar", "role":"navigation", "data-enhanced":"true"}
error = "Internal error generating gadget"; );
}
if (settings.configuration.table.checkbox_rows) { // controls
l += 1; controls = factory.generateElement(
"ul",
{"className": "ui-grid-" +
util.toLetters(spec.children.length - 1).toLowerCase()
}
);
// children
if (spec.children) {
controls.appendChild(
factory.util.generateFromArray(spec.children, "navbar")
);
} }
row.appendChild(factory.generateElement( // form
"th", target = factory.util.wrapInForm(spec.form);
{"style":"text-align: center; line-height: 2em;"},
{"colspan":l}, // assemble
{"text": error} navbar.appendChild(controls);
)); target.appendChild(navbar);
table_body.appendChild(row);
return target;
} }
return table_body;
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Listview */ /* JQM Listview */
/* ********************************************************************** */ /* ********************************************************************** */
/* /*
* Generate a JQM listview * Generate a JQM listview
* Default spec with defaults and single list item with all options!
* {
* "generate": "gadget",
* "type": "listview",
* "class_list": "",
* "form": null,
* "theme": "slapos-black",
* "property_dict": {
* "alt_icon": null
* "numbered": false
* "inset": true,
* "reveal": true,
* "filter": true,
* "input": "#foo"
* "placeholder": null,
* "filter_theme": null,
* "divider_theme": "slapos-white",
* "autodividers": true,
* "count_theme": "slapos-white",
* "form_item": true
* "collapsible_item": true
* },
* "children": [
* {
* "type": "item/divider",
* "external": true,
* "href": "index.html",
* "icon": "foo"/null,
* "title": null,
* "title_i18n":"",
* "left": {
* "icon": "foo",
* "img": "http://www.xyz.com/img/foo.png",
* "alt": null
* },
* "center": {
* "count": 3689,
* "text": [
* {"aside": true, "type":"p", "text":"foo", "text_i18n":null}
* ]
* },
* "right": {
* "radio": true,
* "checkbox": true,
* "action": "foo",
* "href": "http://www.foo.com",
* "title": null,
* "title_i18n": "",
* "external": true
* }
* ]
*}
* @method generateListview * @method generateListview
* @param {object} config JSON configuration * @param {object} spec JSON configuration
* @return HTML object * @return HTML object
*/ */
// TODO: refactor // TODO: add to form support via children
factory.generateListview = function (config) { // TODO: add collapsible support if needed
var i, item_config, item, list, target, skip; // TODO: mesh with live data!
// TODO: redo like the above and handle the array creation in arrayHandler
list = factory.generateElement( // WARNING: JQM does not support enhanced on listview - update JQM!
config.element.type, factory.generateListview = function (spec) {
config.element.direct, var fragment,
config.element.attributes, config,
config.element.logic || {} list,
); i,
// TODO: this is crap! redo item API! item,
for (i = 0; i < config.items.length; i += 1) { props,
item_config = config.items[i]; divider,
if (item_config.type === "divider") { static,
j,
block,
target,
icon,
auto,
last,
theme;
if (spec === undefined) {
util.errorHanlder({"error": "Generate listview: Missing configuration"});
} else {
fragment = document.createDocumentFragment();
config = spec.property_dict || {};
// filter
if (config.filter) {
// NOTE: if input provided, the filter is already there!
// TODO: need a proper id!
if (config.input === undefined) {
fragment.appendChild(factory.generateFormElement({
"type": "input",
"direct":{
"id": "filter_items",
"className": "action"
},
"attributes":{
"data-action":"search",
"data-enhanced": true,
"data-i18n": "",
"placeholder":"Search",
"data-icon":"search"
},
"logic":{"clear":"true"}}
));
}
}
// list
list = factory.generateElement(
config.numbered ? "ol" : "ul",
{
"className": "ui-listview " + (config.inset ?
"ui-listview-inset ui-corner-all ui-shadow " : "")
},
{
"data-role":"listview",
"data-enhanced": true
},
{
"data-filter": config.filter || null,
"data-input": config.input || null,
"data-filter-theme": config.filter_theme || null,
"data-filter-placeholder": config.placeholder || null,
"data-divider-theme": config.divider_theme || null
}
);
// generate items
for (i = 0; i < spec.children.length; i += 1) {
props = spec.children[i];
divider = props.type === "divider" ? true : undefined;
static = (props.href === undefined && !divider) ? true : undefined;
icon = props.icon;
theme = config.divider_theme || spec.theme || "inherit";
// autodividers
if (config.autodividers) {
auto = props.text[0].text.slice(0,1).toUpperCase();
if (last !== auto) {
list.appendChild(factory.generateElement(
"li",
{
"className": "ui-li-divider ui-bar-" + theme +
(i === 0 ? " ui-first-child" :
((i === spec.children.length - 1) ? " ui-last-child" : ""))
},
{},
{"text": auto}
));
last = auto;
}
}
// list item
item = factory.generateElement( item = factory.generateElement(
"li", "li",
{ {
"className": "ui-li-divider ui-bar-" + config.theme + "className": divider ? ("ui-li-divider ui-bar-" + theme) : "" +
(i === 0 ? " ui-first-child" : "") (i === 0 ? " ui-first-child" :
((i === spec.children.length - 1) ? " ui-last-child" : "")) +
(static ? " ui-li-static ui-body-inherit " : "") +
(props.center.count ? " ui-li-has-count" : "") +
(config.alt_icon ? " ui-icon-alt " : "") +
(props.left ? (props.left.icon ? " ui-li-has-icon " : "") +
(props.left.img ? " ui-li-has-thumb " : "") : "") +
(props.right ? " ui-li-has-alt " : " ") +
(config.form_item ? "ui-field-contain " : "") +
(config.reveal ? "ui-screen-hidden " : "")
}, },
{},
{ {
"data-role":"list-divider", "data-role": divider ? "divider" : null,
"role":"heading", "role": divider ? "heading" : null,
"data-i18n": item_config.text_i18n "data-icon" : icon === null ? false :
}, (icon === undefined ? null : icon)
{"text": item_config.text}
);
} else {
item = factory.generateElement(
"li",
{
"className": "listview_item " +
((item_config.left && item_config.left.icon) ? "listview_icon " : "") +
(i === config.items-1 ? "ui-last-child" : "")
} }
); );
// link or no link
if (item_config.middle.href) {
if (config.role) {
target = factory.generateElement(
"a",
{
"href": item_config.middle.href,
"className": "ui-btn ui-btn-icon-right " + (item_config.right ? item_config.right.icon : "ui-icon-carat-r")
}
);
} else {
target = factory.generateElement(
"a",
{"href": item_config.middle.href}
);
}
} else {
// not done yet
skip = true;
target = item;
}
if (item_config.left && item_config.left.icon) { if (static || divider) {
target.appendChild(factory.generateElement( target = item;
"span", } else {
// link
target = factory.generateElement(
"a",
{
"className": "ui-btn " + (icon === null ? "" :
"ui-btn-icon-right ui-icon-" + (icon === undefined ?
"carat-r" : icon)),
"href": props.href,
},
{
"title": props.title || "",
"data-i18n": "[title]" + (props.title_i18n || "")
},
{ {
"className":"ui-li-icon ui-li-icon-custom ui-icon-" + item_config.left.icon + " ui-icon", "data-external": props.external ? true : null
"innerHTML": "&nbsp;"
} }
)); );
} }
if (item_config.middle.title) {
target.appendChild(factory.generateElement( // image
"h3", if (props.left) {
{}, if (props.left.img) {
{"data-i18n": item_config.middle.title_i18n}, target.appendChild(factory.generateElement(
{"text": item_config.middle.title} "img",
)); {"src": props.left.img, "alt": props.left.alt}
));
}
// custom icon
if (props.left.icon) {
target.appendChild(factory.generateElement(
"span",
{
"className":"ui-li-icon ui-li-icon-custom ui-icon-" +
props.left.icon +" ui-icon"
},
{},
{"text": "\u00A0"}
));
}
} }
if (item_config.middle.subtitle) { // text elements/aside elements
target.appendChild(factory.generateElement( for (j = 0; j < props.center.text.length; j += 1) {
"p", block = props.center.text[j];
{}, target.appendChild(
{"data-i18n": item_config.middle.subtitle_i18n}, factory.generateElement(
{"text": item_config.middle.subtitle} block.type,
)); {"className": block.aside ? "ui-li-aside": ""},
{"data-i18n": block.text_i18n || ""},
{"text": block.text}
)
);
} }
if (item_config.middle.info) { // count bubble
if (props.center.count) {
target.appendChild(factory.generateElement( target.appendChild(factory.generateElement(
"span", "span",
{"className": "ui-li-count ui-body-" +
(config.count_theme || spec.theme)
},
{}, {},
{"data-i18n": item_config.middle.info_i18n}, {"text": props.center.count}
{"text":item_config.middle.info} ));
}
// NOTE: if we made a link, target = a, else target = item
if (static || divider) {
item = target;
} else {
item.appendChild(target);
}
// split
if (props.right) {
// split button
if (props.right.link) {
item.appendChild(factory.generateElement(
"a",
{
"href": props.right.href,
"className": "ui-btn ui-btn-icon-notext ui-icon-" +
props.right.icon + " ui-btn-" +
(config.split_theme || spec.theme || "inherit"),
},
{
"title": props.right.title || "",
"data-i18n": "[title]" + (props.right.title_i18n || "")
},
{
"data-external": props.right.external || null
}
));
// split check/radio
if (props.right.check || props.right.radio) {
item.appendChild(factory.generateFormElement(
{
"type":"input",
"direct": {
"id": "select_" + props.right.check ? i : "",
"name": "select_" + i
},
"attributes": {
"type": props.right.check ? "checkbox" : "radio",
"data-i18n": "",
"value": "Select item",
"data-iconpos":"notext",
},
"logic": {}
},
false,
true
));
}
}
}
// done
list.appendChild(item);
}
// assemble
fragment.appendChild(list);
return fragment;
}
};
/* ********************************************************************** */
/* JQM "Bar" */
/* ********************************************************************** */
/*
* Generate a generic bar (table wrapper, controlbar, collapsible header)
* @method generateToolbar
* @param {object} config Elements to add to the bar
* @param {boolean} slot Wrap element in a slot container
* @param {string} reference Gadget reference pointer
* @returns {array} HTML fragment and flag for popups to be created
*/
factory.generateToolbar = function (elements, slot, reference) {
var element,
m,
n,
o,
item,
trigger_element,
target,
include,
wrapped_in_slot,
add_to_first,
flag = {},
config = {},
container = document.createDocumentFragment();
if (slot) {
wrapped_in_slot = true;
}
// loop functionalities
for (m = 0; m < elements.length; m += 1) {
element = elements[m];
if (wrapped_in_slot) {
target = factory.generateElement(
"div", {}, {"data-slot": true, "data-slot-id": element.slot}
);
} else {
target = container;
}
trigger_element = element.element || element.widget;
// TODO: don't set in every case (because of controlgroup);
switch (trigger_element.type) {
case "input":
case "select":
trigger_element.attributes["data-reference"] = reference;
target.appendChild(
factory.generateFormElement(trigger_element, false)
);
break;
case "controlgroup":
for (o = 0; o < element.children.length; o += 1) {
element.children[o].attributes["data-reference"] = reference;
}
target.appendChild(factory.generateControlgroup({
"type": "controlgroup",
"direction": trigger_element.direction,
"class": trigger_element.widget_class,
"buttons": element.children
}));
break;
default:
trigger_element.attributes["data-reference"] = reference;
target.appendChild(factory.generateElement(
trigger_element.type,
trigger_element.direct,
(trigger_element.attributes),
(trigger_element.logic)
)); ));
} break;
if (skip === undefined) { };
item.appendChild(target);
} // TODO: do differently...
if (element.global_popup) {
flag.global_popup = true;
}
if (element.local_popup) {
flag.local_popup = true;
}
if (wrapped_in_slot) {
container.appendChild(target);
} else {
container = target;
} }
list.appendChild(item);
} }
return [container, flag];
return list;
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM POPUP */ /* JQM Page */
/* ********************************************************************** */ /* ********************************************************************** */
/** /**
* Generate a pre-enhanced popup and necessary elements (without content!) * Generate an empty JQM page
* @method generatePopup * @method generatePage
* @param {object} config JSON configuration for popup to be generated * @param {object} config Config object based on parsed link
* @param {string} scope id of page to append popup * @param {object} layout Layout for the page to generate
* @return {object} documentFragment * @return {object} HTML fragment
*/ */
// TODO: make sure popups work inside the page, too // NOTE: we are defaulting to fixed toolbars!
factory.generatePopup = function (config, scope) { factory.generatePage = function (config, layout) {
var popup, var page = factory.generateElement(
popup_wrap,
constructor_id,
popup_id,
container = document.createDocumentFragment(),
placeholder = function (id) {
return factory.generateElement(
"div",
{"id": id + "-placeholder"},
{"style": "display:none;"}
);
};
// NOTE: passing both config and scope undefined creates global popup
// Passing a scope will make the popup local, passing config only,
// makes it global
// set identifier in case config and/or scope are undefined
if (config === undefined) {
config = {
"widget_class": scope ? "local_popup" : ""
};
constructor_id = scope ? util.generateUuid() : "global_popup";
} else {
constructor_id = config.id
}
popup_id = constructor_id + (scope ? ("_" + scope) : "");
container.appendChild(factory.generateElement(
"div",
{
"className": "ui-popup-screen ui-screen-hidden " +
(config.overlay_theme ? "ui-overlay-" + config.overlay_theme : ""),
"id": popup_id + "-screen"
}
));
popup_wrap = factory.generateElement(
"div",
{
"className": "ui-popup-container ui-corner-all ui-popup-hidden " +
" ui-popup-truncate " + (config.transition || "fade"),
"id": popup_id + "-popup"
}
);
popup = factory.generateElement(
"div", "div",
{ {
"className": "ui-popup ui-body-" + config.theme + "id": config.id,
(config.shadow ? " ui-overlay-shadow " : " ") + "className": "ui-page " + ("ui-page-theme-" + layout.theme || "") +
" ui-corner-all " + config.widget_class, " " + ((layout.fix && layout.fix === false) ? "" :
"id": popup_id " ui-page-header-fixed ui-page-footer-fixed")
}, }, {
{ "data-module": config.id,
"data-transition": config.transition || "fade", "data-role": "page",
"data-role": "popup", "data-url": config.url,
"data-enhanced": "true", "data-external-page": true,
"data-position-to": config.position || "window" "tabindex": 0,
}, "data-enhanced": true
{
"data-theme": config.theme || null,
"data-overlay-theme": config.overlay_theme || null,
"data-tolerance": config.tolerance || "30,30,30,30"
} }
); );
popup_wrap.appendChild(popup); // set state
container.appendChild(popup_wrap);
// local popup = needs to go on the page... needs enhancement, because
// we don't jQuery here...
if (scope) {
document.getElementById(scope).appendChild(container);
return placeholder(popup_id);
}
// global popup also gets a placeholder
container.appendChild(placeholder(popup_id));
return container; return page;
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Navbar */ /* JQM Table */
/* ********************************************************************** */ /* ********************************************************************** */
/* Generate a navbar /*
* @method generateNavbar * Generates a table header based on configuration and portal_type
* @param {object} config Configuration options * @method generateTableHeader
* @returns navbar HTML fragment * @param {object} settings Configuration for table to create
* @param {object} fields Field configurations for this portal Type
*/ */
factory.generateNavbar = function (config) { // TODO: single row ok. multi row to make
var i, navbar, controls; factory.generateTableHeader = function (settings, fields) {
var k,
navbar = factory.generateElement( l,
"div", cell,
{"className":"navbar ui-navbar " + (config.type_class || "")}, field,
{"data-role":"navbar", "role":"navigation", "data-enhanced":"true"} config,
); field_config,
controls = factory.generateElement( property,
"ul", keys,
{ title,
"className": "ui-grid-" + set,
util.toLetters(config.buttons.length-1).toLowerCase() text,
} action,
); temp = {},
link = undefined,
check = settings.configuration.table.checkbox_rows,
merger = settings.configuration.table.mergeable_columns,
target = settings.layout[0].columns,
table_header = factory.generateElement("thead"),
row = factory.generateElement("tr");
for (i = 0; i < config.buttons.length; i += 1) { // tickbox - all
button = config.buttons[i]; if (check) {
button.direct["className"] += " ui-btn ui-shadow " + // allow to select all records (not only visible)
factory.generateIconClassString(button); action = settings.configuration.table.select_all ?
"check_all" : "check_all_visible";
item = factory.generateElement( cell = factory.generateElement("th",{},{},{});
"li", {"className":"ui-block-" + util.toLetters(i+1).toLowerCase()} config = {
); "type":"input",
item.appendChild(factory.generateLinkButton(button)); "direct": {
"id": settings.portal_type_title + "_check_all",
"className": "action"
},
"attributes": {
"type": "checkbox",
"value": "Select All/Unselect All",
"data-iconpos":"notext",
"data-reference": settings.base_element.direct.id,
"data-action": action
},
"logic": {}
}
cell.appendChild(factory.generateFormElement(config, false, true));
row.appendChild( cell );
}
controls.appendChild(item); // reverse columns so they are mergeable :-)
if (merger) {
target = util.reverseArray(target);
} }
navbar.appendChild(controls);
return navbar; for (l = 0; l < target.length; l += 1) {
}; link = undefined;
field = target[l];
config = {};
property = field.title;
field_config = {};
/* ********************************************************************** */ if (field.show) {
/* JQM Footer */ // TODO: good mapping?
/* ********************************************************************** */ field_config = fields[field.title];
/**
* Generates JQM footer with navbar or controlgroup based on JSON config
* @method generateFooter
* @param {object} config JSON configuration
* @return {object} HTML fragment
*/
factory.generateFooter = function (config) {
var footer, wrap;
footer = factory.generateElement( if (field.merge === undefined) {
"div", if (field_config) {
{ config["data-i18n"] = field_config.widget.title_i18n;
"className":"ui-footer " + }
(config.widget_class || " ") + if (field.persist === undefined) {
(config.fixed ? "ui-footer-fixed " : " ") + "slideup ui-bar-" + config["data-priority"] = field.priority || 6;
(config.theme || "inherit"), }
}, if (field_config) {
{ title = temp[property] || field_config.widget.title;
"data-role":"footer", } else {
"data-theme":config.theme, title = property;
"data-enhanced":"true", }
"role":"contentinfo" if (settings.configuration.table.sorting_columns && field.sort) {
}, text = {}
{ // sorting link
"id": config.id || undefined, link = factory.generateElement(
"data-position": config.fixed ? "fixed" : undefined "a",
{"className":"action ui-sorting ui-btn ui-icon-sort " +
"ui-icon ui-btn-icon-right"},
{
"data-action":"sort",
"data-i18n":"",
"data-reference": settings.base_element.direct.id,
"data-column-title": field.title
},
{"text": title}
);
} else {
text = {"text": title }
}
cell = factory.generateElement(
"th", {"className":"translate"}, config, text
);
if (link) {
cell.appendChild(link);
}
if (merger) {
row.insertBefore(
cell,
(set === undefined ? null : row.childNodes[check ? 1 : 0])
);
set = true;
} else {
row.appendChild(cell);
}
} else {
temp[field.merge] = field.merge_title;
}
} }
);
// navbar or controlgroup
if (config.type === "navbar") {
wrap = factory.generateNavbar(config);
} else {
wrap = factory.generateControlgroup(config);
} }
footer.appendChild(wrap); table_header.appendChild( row );
return footer; return table_header;
}; };
/* ********************************************************************** */ /*
/* JQM Header */ * Generate table rows based on configuration and data provided. Needed
/* ********************************************************************** */ * to switch between editable and readonly table rows
/** * @method generateTableRow
* Generates JQM header. Header buttons are wrapped in controlgroups! * @param {object} settings Configuration for table row to create
* @method generateHeader * @param {object} item Data for this table row
* @param {object} config JSON configuration * @returns table_row
* @return {object} HTML fragment
*/ */
// TODO: logo instead of header factory.generateTableRow = function (settings, item) {
factory.generateHeader = function (config) { var k,
var header, l,
group,
wrap,
i, i,
direction, cell,
addTitle; property,
field,
link,
value,
fetch_value,
button,
logic,
keys,
action_menu,
action_buttons,
action_controls,
set,
temp = {},
row = factory.generateElement("tr"),
target = settings.layout[0].columns,
check = settings.configuration.table.checkbox_rows,
merger = settings.configuration.table.mergeable_columns;
// title if (check) {
addTitle = function (title, i18n) { cell = factory.generateElement("th",{},{},{});
return factory.generateElement( cell.appendChild(factory.generateFormElement(
"h1",
{"className":"translate ui-title"},
{ {
"data-i18n": i18n || "", "type":"input",
"role":"heading", "direct": {
"aria-level":"1" "id": "select_" + item._id,
"name": "select_" + item._id,
"className": "action"
},
"attributes": {
"type": "checkbox",
"value": "Select item",
"data-iconpos":"notext",
"data-action":"check",
"data-reference": settings.base_element.direct.id
},
"logic": {}
}, },
{"text": title || "&nbsp;"} false,
); true
};
// header element
header = factory.generateElement(
"div",
{
"className":"ui-header " + (config.widget_class || " ") +
(config.fixed ? "ui-header-fixed " : " ") +
" slidedown ui-bar-" + (config.theme || "inherit")
},
{
"data-role":"header",
"data-theme":config.theme,
"data-enhanced":"true",
"role":"banner"
},
{
"id": config.id || undefined,
"data-position": config.fixed ? "fixed" : undefined
}
);
// logo
if (config.logo) {
wrap = factory.generateElement(
"div", {"className":"ui-header-logo wrap " + config.logo.wrap}
);
wrap.appendChild(factory.generateElement(
"img",
{"src": config.logo.src, "alt":config.logo.alt},
{"data-i18n":"[alt]"}
)); ));
header.appendChild(wrap); row.appendChild(cell);
}
// reverse if mergable columns
if (merger) {
target = util.reverseArray(target);
} }
// button controlgroups // loop fields to display
if (config.controls && config.controls.length > 0) { for (l = 0; l < target.length; l += 1) {
for (i = 0; i < config.controls.length; i += 1) { field = target[l];
direction = i === 0 ? "left" : "right"; property = field.title;
value = item[property];
wrap = factory.generateElement( if (field.show) {
"div", {"className":"wrap " + direction} if (field.merge === undefined) {
); cell = factory.generateElement("td",{},{},{});
group = factory.generateControlgroup(config.controls[i]); // TODO: links should reflect value but communicate key aswell
link = "#" + settings.portal_type_title + "::" + item._id;
// TODO: crap...refactor whole section
// fetch non portal_type values
if (value === undefined && field.action === false) {
// TODO: bah
// fetchValue = priv.getERP5property(item._id, field.lookup);
if (fetchValue.error) {
value = "N/A";
}
}
wrap.appendChild(group); if (field.actions) {
header.appendChild(wrap); action_controls = {"direction":"horizontal", "class":"","buttons":[]};
for (i = 0; i < field.actions.length; i += 1) {
action_button = factory.map_buttons[field.actions[i]];
if (action_button) {
action_controls.buttons.push({
"type":"a",
"direct": {"href": action_button.href, "className": action_button.classes + " translate ui-btn ui-btn-icon-notext ui-shadow ui-corner-all ui-icon-" + action_button.icon},
"attributes": {"data-enhanced":"true", "data-i18n": action_button.text_i18n, "data-action": field.actions[i]},
"logic": {"text": action_button.text}
});
}
}
action_menu = factory.generateControlgroup(action_controls);
cell.appendChild(action_menu);
} else if (field.status) {
cell.appendChild(factory.generateElement(
"a",
{"href": link, "className": "status error ui-btn-inline ui-btn translate responsive ui-btn-icon-left ui-shadow ui-corner-all ui-icon-bolt"},
{ "data-i18n": "[title:" + item.status.message_i18n + ";" + item.status.error_i18n + "]", "data-icon":"bolt", "title": item.status.message},
{"text": item.status.state}
));
} else {
// default
if (field.image) {
logic = {"img": item.image}
} else {
// TODO: lame merge
if (temp[property]) {
value += " " + temp[property];
//delete temp[property];
}
logic = {"text":value}
}
// NOTE: page title set in pagehandler, this only sets a placeholder // TODO: a link in every cell? binding?
if (i === 0) { // don't touch this just for some status
header.appendChild(addTitle(config.title, config.title_i18n)); if (settings.configuration.table.linkable_rows) {
cell.appendChild(factory.generateElement(
"a",
{"className": "table_link", "href": link},
{},
logic
));
} else {
cell.appendChild(factory.generateElement("span", {}, {}, logic));
}
}
// Grrr...
if (merger) {
row.insertBefore(cell, (set === undefined ? undefined : row.childNodes[check ? 1 : 0]) );
set = true;
} else {
row.appendChild(cell);
}
} else {
// keep the value of cells to be merged
temp[field.merge] = value;
} }
} }
} else {
header.appendChild(addTitle(config.title, config.title_i18n));
} }
return row;
return header;
}; };
/* ********************************************************************** */ /*
/* JQM Controlgroup */ * Generates a table body based on configuration and data provided from JIO
/* ********************************************************************** */ * @method generateTableBody
/** * @param {object} settings Configuration for table body to create
* Generate an controlgroup = a button or action menu * @param {object} answer from JIO
* @method generateControlgroup * @returns {object} table_body
* @param {object} config Configuration options
* @return controlgroup
*/ */
// TODO: refactor factory.generateTableBody = function (settings, answer) {
factory.generateControlgroup = function (config) { var l,
var i, row,
action_menu, item,
action_controls, property,
element, field,
icon_string, error,
direction; max,
table_body = factory.generateElement("tbody",{},{"data-update":"true"});
direction = config.direction || "vertical"; if (answer && answer.data.total_rows > 0) {
max = answer.data.total_rows;
// group for (l = 0; l < max; l += 1) {
action_menu = factory.generateElement( item = answer.data.rows[l].doc;
"div", row = factory.generateTableRow(settings, item);
{ table_body.appendChild(row);
"className":"ui-corner-all ui-controlgroup " +
(config.widget_class || "") + " ui-controlgroup-" + direction
},
{
"data-role":"controlgroup",
"data-enhanced":"true",
"data-type": direction
} }
); } else {
// error or 0 results
row = factory.generateElement("tr");
l = settings.layout[0].columns.length;
// controls if (answer === undefined) {
action_controls = factory.generateElement( error = "Error retrieving Data";
"div", } else if (answer.data.total_rows === 0 ) {
{"className":"ui-controlgroup-controls " + (config.control_class || "")} error = "No records found. Please modify your search!";
); } else {
error = "Internal error generating gadget";
}
// buttons if (settings.configuration.table.checkbox_rows) {
for (i = 0; i < config.buttons.length; i += 1) { l += 1;
element = config.buttons[i]; }
switch(element.type) {
case "select":
case "input":
action_controls.appendChild(
factory.generateFormElement(element, false)
);
break;
default:
pos = factory.generateIconClassString(element);
// class String
element.direct.className += " ui-btn ui-corner-all ui-shadow " +
pos + ((i === 0) ? " ui-first-child" :
(i === (config.buttons.length-1) ? " ui-last-child" : "")
);
action_controls.appendChild(factory.generateLinkButton(element)); row.appendChild(factory.generateElement(
break; "th",
}; {"style":"text-align: center; line-height: 2em;"},
{"colspan":l},
{"text": error}
));
table_body.appendChild(row);
} }
action_menu.appendChild(action_controls); return table_body;
return action_menu;
};
/* ********************************************************************** */
/* JQM Link Button */
/* ********************************************************************** */
/**
* Generate a link button ("a")
* @method generateLinkButton
* @param {object} config Configuration options
* @return button object
*/
// TODO: add chunk of text here or via JSON?
factory.generateLinkButton = function (config) {
return button = factory.generateElement(
config.type,
config.direct,
config.attributes,
config.logic
);
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Form Element */ /* JQM Form Element */
/* ********************************************************************** */ /* ********************************************************************** */
...@@ -1542,6 +2022,7 @@ ...@@ -1542,6 +2022,7 @@
// TODO: mini? shadow? corners? // TODO: mini? shadow? corners?
// TODO: slider/custom-select/flip // TODO: slider/custom-select/flip
// TODO: refactor... // TODO: refactor...
// TODO: placeholder?
factory.generateFormElement = function (config, wrap, label, position) { factory.generateFormElement = function (config, wrap, label, position) {
var wrapper, var wrapper,
container, container,
...@@ -1771,71 +2252,7 @@ ...@@ -1771,71 +2252,7 @@
return wrapper; return wrapper;
}; };
/* ********************************************************************** */
/* JQM PANEL */
/* ********************************************************************** */
/**
* Generates a JQM panel (needs enhancement!)
* @method generatePanel
* @param {object} config JSON configuration
* @return {object} HTML fragment
*/
factory.generatePanel = function (config) {
var i, element, item, panel;
panel = factory.generateElement(
"div",
{"className":"panel " + config.widget_class, "id": config.id },
{
"data-role":"panel",
"data-theme":config.theme,
"data-position":"left",
"data-display":"push",
"data-position-fixed": true
}
);
for (i = 0; i < config.elements.length; i += 1) {
element = config.elements[i];
// TODO: refactor
switch (element.type || element.widget) {
case "global_search":
item = factory.generateElement(
"div",
{"className":"panel_element panel_element_first panel_header"}
);
item.appendChild(
factory.generateFormElement(element.element, false)
);
item.appendChild(factory.generateLinkButton({
"type":"a",
"direct": {
"href":"#",
"className":"panel-close ui-icon-remove ui-btn " +
"ui-btn-icon-notext ui-shadow ui-corner-all"
},
"attributes": {
"data-enhanced":"true",
"data-i18n":"",
"data-rel":"close"
},
"logic": {"text":"Close"}
}));
panel.appendChild(item);
break;
case "listview":
item = factory.generateElement(
"div", {"className":"panel_element"}
);
item.appendChild(factory.generateListview(element));
panel.appendChild(item);
break;
}
}
return panel;
};
/* ********************************************************************** */ /* ********************************************************************** */
...@@ -1877,6 +2294,7 @@ ...@@ -1877,6 +2294,7 @@
* @param: {object} setters Parameters requiring logic (if-else-etc) * @param: {object} setters Parameters requiring logic (if-else-etc)
* @returns: {object} HTML object * @returns: {object} HTML object
*/ */
// TODO: bundle into spec!
factory.generateElement = function (type, options, attributes, setters) { factory.generateElement = function (type, options, attributes, setters) {
var property, var property,
attribute, attribute,
...@@ -1915,11 +2333,11 @@ ...@@ -1915,11 +2333,11 @@
break; break;
case "id": case "id":
case "rows": case "rows":
case "innerHTML":
case "cols": case "cols":
case "name": case "name":
case "value": case "value":
case "data-": case "data-":
case "role":
case "type": case "type":
case "readonly": case "readonly":
case "size": case "size":
...@@ -2113,26 +2531,6 @@ ...@@ -2113,26 +2531,6 @@
return array; return array;
}; };
/**
* Generate a UUID
* @method generateUuid
* @return {string} UUID
*/
util.generateUuid = function () {
function S4() {
return ('0000' + Math.floor(
Math.random() * 0x10000 /* 65536 */
).toString(16)).slice(-4);
}
return S4() + S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + S4() + S4();
};
/** /**
* Create hashes of code snippets generated * Create hashes of code snippets generated
* @method crc32 * @method crc32
...@@ -2878,7 +3276,8 @@ ...@@ -2878,7 +3276,8 @@
*/ */
init.parsePage = function (e, data) { init.parsePage = function (e, data) {
var create, config, raw_url, handle; var create, config, raw_url, handle;
// console.log("pbc")
// TODO:maybe this is the problem???
if (data) { if (data) {
if (data.options.link) { if (data.options.link) {
raw_url = data.options.link[0].href; raw_url = data.options.link[0].href;
...@@ -2891,28 +3290,39 @@ ...@@ -2891,28 +3290,39 @@
if (typeof raw_url === "string") { if (typeof raw_url === "string") {
config = util.parseLink(raw_url); config = util.parseLink(raw_url);
if (e) { if (e) {
// console.log(document.getElementById(raw_url.replace("#", "")))
// console.log(data.options.role === "popup")
// console.log(raw_url === $.mobile.getDocumentUrl())
// console.log($.mobile.getDocumentUrl())
if (document.getElementById(raw_url.replace("#", "")) || if (document.getElementById(raw_url.replace("#", "")) ||
raw_url === $.mobile.getDocumentUrl() || raw_url === $.mobile.getDocumentUrl() ||
data.options.role === "popup") { data.options.role === "popup") {
// console.log("let JQM go")
return; return;
} }
if (document.getElementById(config.id)) { if (document.getElementById(config.id)) {
// console.log("stop JQM")
e.preventDefault(); e.preventDefault();
return; return;
} else { } else {
// PASS! // PASS!
// console.log("HIJACK and stop JQM")
handle = true; handle = true;
e.preventDefault(); e.preventDefault();
} }
} else {
// if ($.mobile.navigate.history.initialDst && location.hash !== "") {
// console.log("CLEANUP - set initialDst to ")
// $.mobile.navigate.history.initialDst = "";
// }
} }
} else { } else {
// once transition done. Update gadgets if going back to page in DOM // once transition done. Update gadgets if going back to page in DOM
if(data.options.fromHashChange) { if(data.options.fromHashChange) {
init.setPageTitle(data.toPage[0], {}); init.setPageTitle(data.toPage[0], {});
} }
return;
} }
if (e === undefined || handle) { if (e === undefined || handle) {
if (config.deeplink) { if (config.deeplink) {
...@@ -3178,7 +3588,7 @@ ...@@ -3178,7 +3588,7 @@
// JQM treatment // JQM treatment
$(document).enhanceWithin(); $(document).enhanceWithin();
// console.log("CHANGING PAGE")
$.mobile.changePage("#" + config.id); $.mobile.changePage("#" + config.id);
} else { } else {
// populate existing page and enhance // populate existing page and enhance
...@@ -3342,14 +3752,14 @@ ...@@ -3342,14 +3752,14 @@
/** /**
* Loads and runs application setters * Loads and runs application setters
* @method loadApplicationSettings * @method loadGlobalElements
* @return {object} promise object * @return {object} promise object
*/ */
init.loadApplicationSettings = function () { init.loadGlobalElements = function () {
return util.fetchConfiguration({ return util.fetchConfiguration({
"storage": "settings", "storage": "settings",
"file": "configuration", "file": "configuration",
"attachment": "app", "attachment": "global",
"baggage": undefined "baggage": undefined
}); });
}; };
...@@ -3379,25 +3789,19 @@ ...@@ -3379,25 +3789,19 @@
/** /**
* Sets up a global application element * Sets up a global application element
* @method setupGlobalElement * @method setupGlobalElement
* @param {object} config JSON configuration * @param {object} spec JSON configuration
*/ */
init.setupGobalElement = function (config) { init.setupGobalElement = function (spec) {
switch (config.widget) { var element = factory.util.forward(spec);
case "header":
document.body.appendChild(factory.generateHeader(config)); switch (spec.type) {
break; case "Panel":
case "footer":
document.body.appendChild(factory.generateFooter(config));
break;
case "popup":
document.body.appendChild(factory.generatePopup(config));
break;
case "panel":
// NOTE: panel must be either before or after everything else! // NOTE: panel must be either before or after everything else!
// WARNING: IE8- children() retrieves comments, too // WARNING: IE8- children() retrieves comments, too
document.body.insertBefore( document.body.insertBefore(element, document.body.children[0]);
factory.generatePanel(config), document.body.children[0] break;
); default:
document.body.appendChild(element);
break; break;
} }
}; };
...@@ -3407,6 +3811,7 @@ ...@@ -3407,6 +3811,7 @@
* @method setGlobalBindings * @method setGlobalBindings
*/ */
init.setGlobalBindings = function () { init.setGlobalBindings = function () {
$(document) $(document)
.enhanceWithin() .enhanceWithin()
...@@ -3546,7 +3951,7 @@ ...@@ -3546,7 +3951,7 @@
// "Application Setup" // "Application Setup"
.runApplicationSetup("settings", "storages") .runApplicationSetup("settings", "storages")
.then(init.setupStorages) .then(init.setupStorages)
.then(init.loadApplicationSettings) .then(init.loadGlobalElements)
.then(init.setupGlobalElements) .then(init.setupGlobalElements)
.then(init.setGlobalBindings) .then(init.setGlobalBindings)
// "Page Setup" // "Page Setup"
......
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