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,455 +608,637 @@ ...@@ -608,455 +608,637 @@
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.util.forward = function (spec) {
factory.generateToolbar = function (elements, slot, reference) { switch (spec.generate) {
var element, // widget generator
m, case "widget":
n, return factory["generate" + spec.type](spec);
o, break;
item, // gadget generator
trigger_element, case "gadget":
break;
// 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 over a selection of elements and generate the respective content
* @method generateFromArray
* @param {array} spec Array containing the elements to generate
* @param {string} type Requesting widget
* @param {object} hack
* @return {object} fragment HTML object containing the elements
*/
// 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, target,
include, class_list,
wrapped_in_slot, element,
add_to_first, order,
flag = {}, fragment = document.createDocumentFragment();
config = {},
container = document.createDocumentFragment();
if (slot) { for (i = 0; i < spec.length; i += 1) {
wrapped_in_slot = true; element = spec[i];
target = undefined;
// class string
if (element.direct) {
order = i === 0 ? " ui-first-child " :
(i === (spec.length - 1) ? " ui-last-child " : " ");
element.direct.className = (element.direct.className || "") + order +
(element.type === "a" ? (" ui-btn ui-shadow " +
factory.generateIconClassString(element)) : " ");
} }
// loop functionalities switch (type) {
for (m = 0; m < elements.length; m += 1) { case "panel":
element = elements[m]; // TODO: refactor panel_element CSS!
if (wrapped_in_slot) {
target = factory.generateElement( target = factory.generateElement(
"div", {}, {"data-slot": true, "data-slot-id": element.slot} "div",
); {"className":"panel_element " + (i === 0 ?
} else { "panel_element_first panel_header " :
target = container; ((i === spec.length - 1) ?
"panel_element_last" : " "))
} }
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; // 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!
// TODO: do differently... if (spec.length > 1 && i !== 1) {
if (element.global_popup) { target = factory.generateElement(
flag.global_popup = true; "div",
{
"className": " ui-" +
((i === 0 ? "first" : (i === 2 ? "last" : "no")) + "-wrap ")
} }
if (element.local_popup) { );
flag.local_popup = true;
} }
if (wrapped_in_slot) { };
container.appendChild(target); // generate with/without wrapper
if (target) {
target.appendChild(factory.util.forward(element));
fragment.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": "",
* "theme": "",
* "id": null,
* "property_dict": {
* "overlay-theme": null,
* "transition": "fade",
* "position-to": "window",
* "tolerance": "30,30,30,30",
* "shadow": true
* },
* "form": null,
* "children": [],
* }
* @method generatePopup
* @param {object} spec JSON configuration for popup to be generated
* @param {string} scope id of page to append popup
* @return {object} documentFragment (global)/placeholder element (local)
*/ */
// NOTE: we are defaulting to fixed toolbars! // TODO: missing state
factory.generatePage = function (config, layout) { // TODO: generate without referencing IDs
var page = factory.generateElement( // 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", "div",
{ {
"id": config.id, "className": "ui-popup-screen ui-screen-hidden " +
"className": "ui-page " + ("ui-page-theme-" + layout.theme || "") + (config.overlay_theme ?
" " + ((layout.fix && layout.fix === false) ? "" : ("ui-overlay-" + config.overlay_theme) : ""),
" ui-page-header-fixed ui-page-footer-fixed") "id": id + "-screen"
}, { }
"data-module": config.id, ));
"data-role": "page",
"data-url": config.url, // popup wrapper
"data-external-page": true, wrap = factory.generateElement(
"tabindex": 0, "div",
"data-enhanced": true {
"className": "ui-popup-container ui-corner-all ui-popup-hidden " +
" ui-popup-truncate " + (config.transition || "fade"),
"id": id + "-popup"
} }
); );
// set state // 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
}
);
return page; // 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")
);
}
// assemble popup to target (form/fragment) to wrapper to container
target.appendChild(popup);
wrap.appendChild(target);
container.appendChild(wrap);
// 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 (spec === undefined) {
if (check) { util.errorHandler({"error":"Generate Header: Missing configuration"});
// allow to select all records (not only visible) } else {
action = settings.configuration.table.select_all ? config = spec.property_dict || {};
"check_all" : "check_all_visible"; id = spec.id || (scope ? (scope + "-header") : "global_header");
children = spec.children.length
position = children === 2 ? 1 : (children === 0 ? 0 : 1);
cell = factory.generateElement("th",{},{},{}); // title
config = { title = {
"type":"input", "type": "h1",
"direct": { "direct": {"className":"translate ui-title"},
"id": settings.portal_type_title + "_check_all",
"className": "action"
},
"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));
row.appendChild( cell );
}
// reverse columns so they are mergeable :-)
if (merger) {
target = util.reverseArray(target);
} }
spec.children.splice(position, 0, title);
for (l = 0; l < target.length; l += 1) { // header
link = undefined; header = factory.generateElement(
field = target[l]; "div",
config = {}; {
property = field.title; "id": id,
field_config = {}; "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
}
);
if (field.show) { // form
// TODO: good mapping? target = factory.util.wrapInForm(spec.form);
field_config = fields[field.title];
if (field.merge === undefined) { // children/action buttons (wrap first/last)
if (field_config) { if (spec.children) {
config["data-i18n"] = field_config.widget.title_i18n; target.appendChild(
factory.util.generateFromArray(spec.children, "header")
);
} }
if (field.persist === undefined) {
config["data-priority"] = field.priority || 6; // assemble
header.appendChild(target);
// add to DOM if scoped
if (scope) {
document.getElementById(scope).appendChild(header);
return undefined;
} }
if (field_config) {
title = temp[property] || field_config.widget.title; return header;
}
};
/* ********************************************************************** */
/* JQM PANEL */
/* ********************************************************************** */
/**
* Generates a JQM panel (needs enhancement!)
* Full spec example (with defaults):
* {
* "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
*/
// TODO: Needs pre-enhancement!
factory.generatePanel = function (spec, scope) {
var config, id, panel, closer;
if (spec === undefined) {
util.errorHandler({"error": "Generate Panel: Missing configuration"});
} else { } else {
title = property; config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-panel") : "global_panel");
// panel
panel = factory.generateElement(
"div",
{
"id": id,
"className":"panel " + (spec.class_list || "")
},
{
"data-role":"panel",
"data-theme": spec.theme,
"data-position":"left",
"data-display":"push",
"data-position-fixed": true
} }
if (settings.configuration.table.sorting_columns && field.sort) { );
text = {}
// sorting link // close button, needs to go into first panel element
link = factory.generateElement( // TODO: refactor!!!!!
if (config.close) {
closer = factory.generateElement(
"a", "a",
{"className":"action ui-sorting ui-btn ui-icon-sort " +
"ui-icon ui-btn-icon-right"},
{ {
"data-action":"sort", "href":"#",
"data-i18n":"", "className":"panel-close ui-icon-remove ui-btn " +
"data-reference": settings.base_element.direct.id, "ui-btn-icon-notext ui-shadow ui-corner-all"
"data-column-title": field.title
}, },
{"text": title} {
); "data-enhanced": true,
} else { "data-i18n": "",
text = {"text": title } "data-rel":"close"
} },
cell = factory.generateElement( {"text":"Close"}
"th", {"className":"translate"}, config, text
); );
if (link) {
cell.appendChild(link);
} }
if (merger) {
row.insertBefore( // form
cell, target = factory.util.wrapInForm(spec.form);
(set === undefined ? null : row.childNodes[check ? 1 : 0])
// children
if (spec.children) {
target.appendChild(
factory.util.generateFromArray(spec.children, "panel", closer)
); );
set = true;
} else {
row.appendChild(cell);
}
} else {
temp[field.merge] = field.merge_title;
} }
// assemble
panel.appendChild(target);
// add to DOM if scoped
if (scope) {
document.getElementById(scope).appendChild(panel);
return undefined;
} }
return panel;
} }
table_header.appendChild( row );
return table_header;
}; };
/* /* ********************************************************************** */
* Generate table rows based on configuration and data provided. Needed /* JQM Footer */
* to switch between editable and readonly table rows /* ********************************************************************** */
* @method generateTableRow /**
* @param {object} settings Configuration for table row to create * Generates JQM footer with navbar or controlgroup based on JSON config
* @param {object} item Data for this table row * Full options (with defaults):
* @returns table_row * {
* "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.generateTableRow = function (settings, item) { factory.generateFooter = function (spec, scope) {
var k, var config, id, footer, target;
l,
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 Footer: Missing config"});
cell.appendChild(factory.generateFormElement( } else {
config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-footer") : "global_footer");
// footer
footer = factory.generateElement(
"div",
{ {
"type":"input", "id": id,
"direct": { "className":"ui-footer " + (spec.class_list || " ") +
"id": "select_" + item._id, (config.fixed ? "ui-footer-fixed " : " ") +
"name": "select_" + item._id, "slideup ui-bar-" + (spec.theme || "inherit"),
"className": "action"
},
"attributes": {
"type": "checkbox",
"value": "Select item",
"data-iconpos":"notext",
"data-action":"check",
"data-reference": settings.base_element.direct.id
}, },
"logic": {} {
"data-role":"footer",
"data-theme":spec.theme,
"data-enhanced":"true",
"role":"contentinfo"
}, },
false, {"data-position": config.fixed ? "fixed" : undefined}
true );
));
row.appendChild(cell);
}
// reverse if mergable columns // form
if (merger) { target = factory.util.wrapInForm(spec.form);
target = util.reverseArray(target);
}
// loop fields to display // children
for (l = 0; l < target.length; l += 1) { if (spec.children) {
field = target[l]; target.appendChild(
property = field.title; factory.util.generateFromArray(spec.children, "footer")
value = item[property]; );
}
if (field.show) { // assemble
if (field.merge === undefined) { footer.appendChild(target);
cell = factory.generateElement("td",{},{},{});
// TODO: links should reflect value but communicate key aswell
link = "#" + settings.portal_type_title + "::" + item._id;
// TODO: crap...refactor whole section return footer;
// 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";
}
} }
};
if (field.actions) { /* ********************************************************************** */
action_controls = {"direction":"horizontal", "class":"","buttons":[]}; /* JQM Controlgroup */
for (i = 0; i < field.actions.length; i += 1) { /* ********************************************************************** */
action_button = factory.map_buttons[field.actions[i]]; /**
if (action_button) { * Generate an controlgroup = a button or action menu
action_controls.buttons.push({ * {
"type":"a", * "generate": "controlgroup",
"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}, * "id": null,
"attributes": {"data-enhanced":"true", "data-i18n": action_button.text_i18n, "data-action": field.actions[i]}, * "class_list": null,
"logic": {"text": action_button.text} * "theme": null,
}); * "form": null,
} * "property_dict": {
} * "direction": "horizontal"
action_menu = factory.generateControlgroup(action_controls); * },
cell.appendChild(action_menu); * "children": [
} else if (field.status) { * {"type":a, "direct": {}, "attributes": {}, "logic": {}}
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"}, * @method generateControlgroup
"attributes": { "data-i18n": "[title:" + item.status.message_i18n + ";" + item.status.error_i18n + "]", "data-icon":"bolt", "title": item.status.message}, * @param {object} spec Configuration for controlgroup
"logic": {"text": item.status.state} * @return controlgroup
})); */
} else { factory.generateControlgroup = function (spec) {
// default var config, group, direction, controls, target;
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? if (spec === undefined) {
// don't touch this just for some status util.errorHandler({"error":"Generate Controlgroup: Missing config"});
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 { } else {
// keep the value of cells to be merged config = spec.property_dict || {};
temp[field.merge] = value; direction = config.direction || "vertical";
// group
group = factory.generateElement(
"div",
{
"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;
} }
return row;
}; };
/* /* ********************************************************************** */
* Generates a table body based on configuration and data provided from JIO /* JQM Navbar */
* @method generateTableBody /* ********************************************************************** */
* @param {object} settings Configuration for table body to create /* Generate a navbar
* @param {object} answer from JIO * Full example of spec with all options:
* @returns {object} table_body * {
* "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.generateTableBody = function (settings, answer) { factory.generateNavbar = function (spec) {
var l, var navbar, 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 Navbar: Missing Configuration"});
for (l = 0; l < max; l += 1) {
item = answer.data.rows[l].doc;
row = factory.generateTableRow(settings, item);
table_body.appendChild(row);
}
} 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"; );
// controls
controls = factory.generateElement(
"ul",
{"className": "ui-grid-" +
util.toLetters(spec.children.length - 1).toLowerCase()
} }
);
if (settings.configuration.table.checkbox_rows) { // children
l += 1; 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;
}; };
/* ********************************************************************** */ /* ********************************************************************** */
...@@ -1064,467 +1246,765 @@ ...@@ -1064,467 +1246,765 @@
/* ********************************************************************** */ /* ********************************************************************** */
/* /*
* 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
// WARNING: JQM does not support enhanced on listview - update JQM!
factory.generateListview = function (spec) {
var fragment,
config,
list,
i,
item,
props,
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( list = factory.generateElement(
config.element.type, config.numbered ? "ol" : "ul",
config.element.direct,
config.element.attributes,
config.element.logic || {}
);
// TODO: this is crap! redo item API!
for (i = 0; i < config.items.length; i += 1) {
item_config = config.items[i];
if (item_config.type === "divider") {
item = factory.generateElement(
"li",
{ {
"className": "ui-li-divider ui-bar-" + config.theme + "className": "ui-listview " + (config.inset ?
(i === 0 ? " ui-first-child" : "") "ui-listview-inset ui-corner-all ui-shadow " : "")
}, },
{ {
"data-role":"list-divider", "data-role":"listview",
"role":"heading", "data-enhanced": true
"data-i18n": item_config.text_i18n
}, },
{"text": item_config.text} {
"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
}
); );
} else {
item = factory.generateElement( // 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", "li",
{ {
"className": "listview_item " + "className": "ui-li-divider ui-bar-" + theme +
((item_config.left && item_config.left.icon) ? "listview_icon " : "") + (i === 0 ? " ui-first-child" :
(i === config.items-1 ? "ui-last-child" : "") ((i === spec.children.length - 1) ? " ui-last-child" : ""))
},
{},
{"text": auto}
));
last = auto;
} }
); }
// link or no link
if (item_config.middle.href) { // list item
if (config.role) { item = factory.generateElement(
target = factory.generateElement( "li",
"a",
{ {
"href": item_config.middle.href, "className": divider ? ("ui-li-divider ui-bar-" + theme) : "" +
"className": "ui-btn ui-btn-icon-right " + (item_config.right ? item_config.right.icon : "ui-icon-carat-r") (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": divider ? "divider" : null,
"role": divider ? "heading" : null,
"data-icon" : icon === null ? false :
(icon === undefined ? null : icon)
} }
); );
if (static || divider) {
target = item;
} else { } else {
// link
target = factory.generateElement( target = factory.generateElement(
"a", "a",
{"href": item_config.middle.href} {
); "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 || "")
},
{
"data-external": props.external ? true : null
} }
} else { );
// not done yet
skip = true;
target = item;
} }
if (item_config.left && item_config.left.icon) { // image
if (props.left) {
if (props.left.img) {
target.appendChild(factory.generateElement( target.appendChild(factory.generateElement(
"span", "img",
{ {"src": props.left.img, "alt": props.left.alt}
"className":"ui-li-icon ui-li-icon-custom ui-icon-" + item_config.left.icon + " ui-icon",
"innerHTML": "&nbsp;"
}
)); ));
} }
if (item_config.middle.title) { // custom icon
if (props.left.icon) {
target.appendChild(factory.generateElement( target.appendChild(factory.generateElement(
"h3", "span",
{
"className":"ui-li-icon ui-li-icon-custom ui-icon-" +
props.left.icon +" ui-icon"
},
{}, {},
{"data-i18n": item_config.middle.title_i18n}, {"text": "\u00A0"}
{"text": item_config.middle.title}
)); ));
} }
if (item_config.middle.subtitle) {
target.appendChild(factory.generateElement(
"p",
{},
{"data-i18n": item_config.middle.subtitle_i18n},
{"text": item_config.middle.subtitle}
));
} }
if (item_config.middle.info) { // text elements/aside elements
for (j = 0; j < props.center.text.length; j += 1) {
block = props.center.text[j];
target.appendChild(
factory.generateElement(
block.type,
{"className": block.aside ? "ui-li-aside": ""},
{"data-i18n": block.text_i18n || ""},
{"text": block.text}
)
);
}
// 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}
)); ));
} }
if (skip === undefined) {
// NOTE: if we made a link, target = a, else target = item
if (static || divider) {
item = target;
} else {
item.appendChild(target); 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); list.appendChild(item);
} }
// assemble
fragment.appendChild(list);
return list; return fragment;
}
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM POPUP */ /* JQM "Bar" */
/* ********************************************************************** */ /* ********************************************************************** */
/** /*
* Generate a pre-enhanced popup and necessary elements (without content!) * Generate a generic bar (table wrapper, controlbar, collapsible header)
* @method generatePopup * @method generateToolbar
* @param {object} config JSON configuration for popup to be generated * @param {object} config Elements to add to the bar
* @param {string} scope id of page to append popup * @param {boolean} slot Wrap element in a slot container
* @return {object} documentFragment * @param {string} reference Gadget reference pointer
*/ * @returns {array} HTML fragment and flag for popups to be created
// TODO: make sure popups work inside the page, too */
factory.generatePopup = function (config, scope) { factory.generateToolbar = function (elements, slot, reference) {
var popup, var element,
popup_wrap, m,
constructor_id, n,
popup_id, o,
container = document.createDocumentFragment(), item,
placeholder = function (id) { trigger_element,
return factory.generateElement( target,
"div", include,
{"id": id + "-placeholder"}, wrapped_in_slot,
{"style": "display:none;"} add_to_first,
); flag = {},
}; config = {},
container = document.createDocumentFragment();
// NOTE: passing both config and scope undefined creates global popup if (slot) {
// Passing a scope will make the popup local, passing config only, wrapped_in_slot = true;
// makes it global }
// set identifier in case config and/or scope are undefined // loop functionalities
if (config === undefined) { for (m = 0; m < elements.length; m += 1) {
config = { element = elements[m];
"widget_class": scope ? "local_popup" : "" if (wrapped_in_slot) {
}; target = factory.generateElement(
constructor_id = scope ? util.generateUuid() : "global_popup"; "div", {}, {"data-slot": true, "data-slot-id": element.slot}
);
} else { } else {
constructor_id = config.id target = container;
} }
popup_id = constructor_id + (scope ? ("_" + scope) : "");
container.appendChild(factory.generateElement( trigger_element = element.element || element.widget;
"div", // TODO: don't set in every case (because of controlgroup);
{
"className": "ui-popup-screen ui-screen-hidden " +
(config.overlay_theme ? "ui-overlay-" + config.overlay_theme : ""),
"id": popup_id + "-screen"
}
));
popup_wrap = factory.generateElement( switch (trigger_element.type) {
"div", case "input":
{ case "select":
"className": "ui-popup-container ui-corner-all ui-popup-hidden " + trigger_element.attributes["data-reference"] = reference;
" ui-popup-truncate " + (config.transition || "fade"), target.appendChild(
"id": popup_id + "-popup" factory.generateFormElement(trigger_element, false)
}
); );
break;
popup = factory.generateElement( case "controlgroup":
"div", for (o = 0; o < element.children.length; o += 1) {
{ element.children[o].attributes["data-reference"] = reference;
"className": "ui-popup ui-body-" + config.theme +
(config.shadow ? " ui-overlay-shadow " : " ") +
" ui-corner-all " + config.widget_class,
"id": popup_id
},
{
"data-transition": config.transition || "fade",
"data-role": "popup",
"data-enhanced": "true",
"data-position-to": config.position || "window"
},
{
"data-theme": config.theme || null,
"data-overlay-theme": config.overlay_theme || null,
"data-tolerance": config.tolerance || "30,30,30,30"
} }
); target.appendChild(factory.generateControlgroup({
"type": "controlgroup",
popup_wrap.appendChild(popup); "direction": trigger_element.direction,
container.appendChild(popup_wrap); "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;
};
// local popup = needs to go on the page... needs enhancement, because // TODO: do differently...
// we don't jQuery here... if (element.global_popup) {
if (scope) { flag.global_popup = true;
document.getElementById(scope).appendChild(container);
return placeholder(popup_id);
} }
if (element.local_popup) {
// global popup also gets a placeholder flag.local_popup = true;
container.appendChild(placeholder(popup_id)); }
if (wrapped_in_slot) {
return container; container.appendChild(target);
} else {
container = target;
}
}
return [container, flag];
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Navbar */ /* JQM Page */
/* ********************************************************************** */ /* ********************************************************************** */
/* Generate a navbar /**
* @method generateNavbar * Generate an empty JQM page
* @param {object} config Configuration options * @method generatePage
* @returns navbar HTML fragment * @param {object} config Config object based on parsed link
* @param {object} layout Layout for the page to generate
* @return {object} HTML fragment
*/ */
factory.generateNavbar = function (config) { // NOTE: we are defaulting to fixed toolbars!
var i, navbar, controls; factory.generatePage = function (config, layout) {
var page = factory.generateElement(
navbar = factory.generateElement(
"div", "div",
{"className":"navbar ui-navbar " + (config.type_class || "")},
{"data-role":"navbar", "role":"navigation", "data-enhanced":"true"}
);
controls = factory.generateElement(
"ul",
{ {
"className": "ui-grid-" + "id": config.id,
util.toLetters(config.buttons.length-1).toLowerCase() "className": "ui-page " + ("ui-page-theme-" + layout.theme || "") +
" " + ((layout.fix && layout.fix === false) ? "" :
" ui-page-header-fixed ui-page-footer-fixed")
}, {
"data-module": config.id,
"data-role": "page",
"data-url": config.url,
"data-external-page": true,
"tabindex": 0,
"data-enhanced": true
} }
); );
for (i = 0; i < config.buttons.length; i += 1) { // set state
button = config.buttons[i];
button.direct["className"] += " ui-btn ui-shadow " +
factory.generateIconClassString(button);
item = factory.generateElement(
"li", {"className":"ui-block-" + util.toLetters(i+1).toLowerCase()}
);
item.appendChild(factory.generateLinkButton(button));
controls.appendChild(item);
}
navbar.appendChild(controls);
return navbar; return page;
}; };
/* ********************************************************************** */ /* ********************************************************************** */
/* JQM Footer */ /* JQM Table */
/* ********************************************************************** */ /* ********************************************************************** */
/** /*
* Generates JQM footer with navbar or controlgroup based on JSON config * Generates a table header based on configuration and portal_type
* @method generateFooter * @method generateTableHeader
* @param {object} config JSON configuration * @param {object} settings Configuration for table to create
* @return {object} HTML fragment * @param {object} fields Field configurations for this portal Type
*/ */
factory.generateFooter = function (config) { // TODO: single row ok. multi row to make
var footer, wrap; factory.generateTableHeader = function (settings, fields) {
var k,
l,
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");
footer = factory.generateElement( // tickbox - all
"div", if (check) {
{ // allow to select all records (not only visible)
"className":"ui-footer " + action = settings.configuration.table.select_all ?
(config.widget_class || " ") + "check_all" : "check_all_visible";
(config.fixed ? "ui-footer-fixed " : " ") + "slideup ui-bar-" +
(config.theme || "inherit"), cell = factory.generateElement("th",{},{},{});
config = {
"type":"input",
"direct": {
"id": settings.portal_type_title + "_check_all",
"className": "action"
}, },
{ "attributes": {
"data-role":"footer", "type": "checkbox",
"data-theme":config.theme, "value": "Select All/Unselect All",
"data-enhanced":"true", "data-iconpos":"notext",
"role":"contentinfo" "data-reference": settings.base_element.direct.id,
"data-action": action
}, },
"logic": {}
}
cell.appendChild(factory.generateFormElement(config, false, true));
row.appendChild( cell );
}
// reverse columns so they are mergeable :-)
if (merger) {
target = util.reverseArray(target);
}
for (l = 0; l < target.length; l += 1) {
link = undefined;
field = target[l];
config = {};
property = field.title;
field_config = {};
if (field.show) {
// TODO: good mapping?
field_config = fields[field.title];
if (field.merge === undefined) {
if (field_config) {
config["data-i18n"] = field_config.widget.title_i18n;
}
if (field.persist === undefined) {
config["data-priority"] = field.priority || 6;
}
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"},
{ {
"id": config.id || undefined, "data-action":"sort",
"data-position": config.fixed ? "fixed" : undefined "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;
// navbar or controlgroup } else {
if (config.type === "navbar") { row.appendChild(cell);
wrap = factory.generateNavbar(config); }
} else { } else {
wrap = factory.generateControlgroup(config); temp[field.merge] = field.merge_title;
}
}
} }
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"
}, },
{"text": title || "&nbsp;"} "attributes": {
); "type": "checkbox",
}; "value": "Select item",
"data-iconpos":"notext",
// header element "data-action":"check",
header = factory.generateElement( "data-reference": settings.base_element.direct.id
"div",
{
"className":"ui-header " + (config.widget_class || " ") +
(config.fixed ? "ui-header-fixed " : " ") +
" slidedown ui-bar-" + (config.theme || "inherit")
}, },
{ "logic": {}
"data-role":"header",
"data-theme":config.theme,
"data-enhanced":"true",
"role":"banner"
}, },
{ false,
"id": config.id || undefined, true
"data-position": config.fixed ? "fixed" : undefined ));
row.appendChild(cell);
} }
);
// logo // reverse if mergable columns
if (config.logo) { if (merger) {
wrap = factory.generateElement( target = util.reverseArray(target);
"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);
} }
// 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;
wrap.appendChild(group); // TODO: crap...refactor whole section
header.appendChild(wrap); // 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";
}
}
// NOTE: page title set in pagehandler, this only sets a placeholder if (field.actions) {
if (i === 0) { action_controls = {"direction":"horizontal", "class":"","buttons":[]};
header.appendChild(addTitle(config.title, config.title_i18n)); 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 { } else {
header.appendChild(addTitle(config.title, config.title_i18n)); // TODO: lame merge
if (temp[property]) {
value += " " + temp[property];
//delete temp[property];
}
logic = {"text":value}
} }
return header; // TODO: a link in every cell? binding?
// don't touch this just for some status
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;
}
}
}
return row;
}; };
/* ********************************************************************** */ /*
/* 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
// controls row = factory.generateElement("tr");
action_controls = factory.generateElement( l = settings.layout[0].columns.length;
"div",
{"className":"ui-controlgroup-controls " + (config.control_class || "")}
);
// buttons
for (i = 0; i < config.buttons.length; i += 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)); if (answer === undefined) {
break; error = "Error retrieving Data";
}; } else if (answer.data.total_rows === 0 ) {
error = "No records found. Please modify your search!";
} else {
error = "Internal error generating gadget";
} }
action_menu.appendChild(action_controls);
return action_menu; if (settings.configuration.table.checkbox_rows) {
}; l += 1;
}
/* ********************************************************************** */ row.appendChild(factory.generateElement(
/* JQM Link Button */ "th",
/* ********************************************************************** */ {"style":"text-align: center; line-height: 2em;"},
/** {"colspan":l},
* Generate a link button ("a") {"text": error}
* @method generateLinkButton ));
* @param {object} config Configuration options table_body.appendChild(row);
* @return button object }
*/ return table_body;
// 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;
...@@ -2893,26 +3292,37 @@ ...@@ -2893,26 +3292,37 @@
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