Commit c56accc9 authored by Sven Franck's avatar Sven Franck

rewrite factory to handle widgets, gadgets, elements

parent e1636c58
......@@ -9,7 +9,7 @@
// ERP5 custom methods
var erp5 = {};
// JQM content generator
// JQM content erateerator
var factory = {};
/* ====================================================================== */
......@@ -272,8 +272,8 @@
// NOTE: method must be present or added to validation handler
if (prevail.properties.external_validator ||
spec.properties.external_validator) {
validation_list += prevail.properties.external_validator ||
spec.properties.external_validator;
validation_list += (prevail.properties.external_validator ||
spec.properties.external_validator);
}
// required
......@@ -600,7 +600,7 @@
/* ====================================================================== */
/* ********************************************************************** */
/* "mapping to erp5" */
/* Factory Mappings (to ERP5) */
/* ********************************************************************** */
factory.map_buttons = erp5.map_buttons;
factory.map_actions = erp5.map_actions;
......@@ -608,923 +608,1403 @@
factory.map_utils = erp5.map_utils;
/* ********************************************************************** */
/* JQM "Bar" */
/* Factory Utils */
/* ********************************************************************** */
factory.util = {};
/*
* 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
* Forward to factory generator depending on "generate". This method will
* handle generation of elements, widgets (and gadgets?)
* @method forward
* @param {object} spec Configuration object for the element to be created
* @return {object} HTML object containing generated elements
*/
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();
factory.util.forward = function (spec) {
switch (spec.generate) {
// widget generator
case "widget":
return factory["generate" + spec.type](spec);
break;
// gadget generator
case "gadget":
if (slot) {
wrapped_in_slot = true;
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 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;
}
/*
* 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,
class_list,
element,
order,
fragment = document.createDocumentFragment();
trigger_element = element.element || element.widget;
// TODO: don't set in every case (because of controlgroup);
for (i = 0; i < spec.length; i += 1) {
element = spec[i];
target = undefined;
switch (trigger_element.type) {
case "input":
case "select":
trigger_element.attributes["data-reference"] = reference;
target.appendChild(
factory.generateFormElement(trigger_element, false)
// 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)) : " ");
}
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;
case "controlgroup":
for (o = 0; o < element.children.length; o += 1) {
element.children[o].attributes["data-reference"] = reference;
// HACK: this adds the panel close button, don't do this here!
if (i === 0 && hack) {
target.appendChild(hack);
}
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)
));
case "navbar":
target = factory.generateElement(
"li",
{"className": "ui-block-" + util.toLetters(i+1).toLowerCase()}
);
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 ")
}
);
}
};
// 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);
// generate with/without wrapper
if (target) {
target.appendChild(factory.util.forward(element));
fragment.appendChild(target);
} 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
* @method generatePage
* @param {object} config Config object based on parsed link
* @param {object} layout Layout for the page to generate
* @return {object} HTML fragment
*/
// NOTE: we are defaulting to fixed toolbars!
factory.generatePage = function (config, layout) {
var page = factory.generateElement(
"div",
{
"id": config.id,
"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
* Generate a pre-enhanced popup and necessary elements
* Full options (with defaults)
* {
* "generate": "widget",
* "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)
*/
// 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
* @method generateTableHeader
* @param {object} settings Configuration for table to create
* @param {object} fields Field configurations for this portal Type
/**
* Generates JQM header. Header buttons are wrapped in controlgroups!
* Full options (with defaults)
* {
* "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
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");
// tickbox - all
if (check) {
// allow to select all records (not only visible)
action = settings.configuration.table.select_all ?
"check_all" : "check_all_visible";
// NOTE: Logos should be added as children of the header!
// NOTE: page title set in pagehandler, this only sets a placeholder
factory.generateHeader = function (spec, scope) {
var config, id, title, wrap, position, children, header, target;
cell = factory.generateElement("th",{},{},{});
config = {
"type":"input",
"direct": {
"id": settings.portal_type_title + "_check_all",
"className": "action"
},
if (spec === undefined) {
util.errorHandler({"error":"Generate Header: Missing configuration"});
} else {
config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-header") : "global_header");
children = spec.children.length
position = children === 2 ? 1 : (children === 0 ? 0 : 1);
// title
title = {
"type": "h1",
"direct": {"className":"translate ui-title"},
"attributes": {
"type": "checkbox",
"value": "Select All/Unselect All",
"data-iconpos":"notext",
"data-reference": settings.base_element.direct.id,
"data-action": action
"data-i18n": config.title_i18n || "",
"role":"heading",
"aria-level":"1"
},
"logic": {}
"logic": {"text": config.title || "\u00A0"}
}
cell.appendChild(factory.generateFormElement(config, false, true));
row.appendChild( cell );
}
spec.children.splice(position, 0, title);
// reverse columns so they are mergeable :-)
if (merger) {
target = util.reverseArray(target);
}
// header
header = factory.generateElement(
"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) {
link = undefined;
field = target[l];
config = {};
property = field.title;
field_config = {};
// form
target = factory.util.wrapInForm(spec.form);
if (field.show) {
// TODO: good mapping?
field_config = fields[field.title];
// children/action buttons (wrap first/last)
if (spec.children) {
target.appendChild(
factory.util.generateFromArray(spec.children, "header")
);
}
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"},
{
"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;
}
// assemble
header.appendChild(target);
// add to DOM if scoped
if (scope) {
document.getElementById(scope).appendChild(header);
return undefined;
}
}
table_header.appendChild( row );
return table_header;
return header;
}
};
/*
* Generate table rows based on configuration and data provided. Needed
* to switch between editable and readonly table rows
* @method generateTableRow
* @param {object} settings Configuration for table row to create
* @param {object} item Data for this table row
* @returns table_row
/* ********************************************************************** */
/* 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
*/
factory.generateTableRow = function (settings, item) {
var k,
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;
// TODO: Needs pre-enhancement!
factory.generatePanel = function (spec, scope) {
var config, id, panel, closer;
if (check) {
cell = factory.generateElement("th",{},{},{});
cell.appendChild(factory.generateFormElement(
if (spec === undefined) {
util.errorHandler({"error": "Generate Panel: Missing configuration"});
} else {
config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-panel") : "global_panel");
// panel
panel = factory.generateElement(
"div",
{
"type":"input",
"direct": {
"id": "select_" + item._id,
"name": "select_" + item._id,
"className": "action"
"id": id,
"className":"panel " + (spec.class_list || "")
},
{
"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",
"value": "Select item",
"data-iconpos":"notext",
"data-action":"check",
"data-reference": settings.base_element.direct.id
{
"data-enhanced": true,
"data-i18n": "",
"data-rel":"close"
},
"logic": {}
},
false,
true
));
row.appendChild(cell);
}
{"text":"Close"}
);
}
// reverse if mergable columns
if (merger) {
target = util.reverseArray(target);
// form
target = factory.util.wrapInForm(spec.form);
// 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) {
field = target[l];
property = field.title;
value = item[property];
/* ********************************************************************** */
/* JQM Footer */
/* ********************************************************************** */
/**
* 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 (field.merge === undefined) {
cell = factory.generateElement("td",{},{},{});
// TODO: links should reflect value but communicate key aswell
link = "#" + settings.portal_type_title + "::" + item._id;
if (spec === undefined) {
util.errorHandler({"error": "Generate Footer: Missing config"});
} else {
config = spec.property_dict || {};
id = spec.id || (scope ? (scope + "-footer") : "global_footer");
// 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";
}
}
// footer
footer = factory.generateElement(
"div",
{
"id": id,
"className":"ui-footer " + (spec.class_list || " ") +
(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) {
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.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}
}
// form
target = factory.util.wrapInForm(spec.form);
// 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;
}
// children
if (spec.children) {
target.appendChild(
factory.util.generateFromArray(spec.children, "footer")
);
}
// assemble
footer.appendChild(target);
return footer;
}
return row;
};
/*
* Generates a table body based on configuration and data provided from JIO
* @method generateTableBody
* @param {object} settings Configuration for table body to create
* @param {object} answer from JIO
* @returns {object} table_body
/* ********************************************************************** */
/* JQM Controlgroup */
/* ********************************************************************** */
/**
* Generate an controlgroup = a button or action menu
* {
* "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) {
var l,
row,
item,
property,
field,
error,
max,
table_body = factory.generateElement("tbody",{},{"data-update":"true"});
factory.generateControlgroup = function (spec) {
var config, group, direction, controls, target;
if (answer && answer.data.total_rows > 0) {
max = answer.data.total_rows;
if (spec === undefined) {
util.errorHandler({"error":"Generate Controlgroup: Missing config"});
} else {
config = spec.property_dict || {};
direction = config.direction || "vertical";
for (l = 0; l < max; l += 1) {
item = answer.data.rows[l].doc;
row = factory.generateTableRow(settings, item);
table_body.appendChild(row);
// 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;
}
};
/* ********************************************************************** */
/* 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 {
// error or 0 results
row = factory.generateElement("tr");
l = settings.layout[0].columns.length;
config = spec.property_dict || {};
if (answer === undefined) {
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";
}
// navbar
navbar = factory.generateElement(
"div",
{"className":"navbar ui-navbar " + (spec.class_list || "")},
{"data-role":"navbar", "role":"navigation", "data-enhanced":"true"}
);
if (settings.configuration.table.checkbox_rows) {
l += 1;
// controls
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(
"th",
{"style":"text-align: center; line-height: 2em;"},
{"colspan":l},
{"text": error}
));
table_body.appendChild(row);
// form
target = factory.util.wrapInForm(spec.form);
// assemble
navbar.appendChild(controls);
target.appendChild(navbar);
return target;
}
return table_body;
};
/* ********************************************************************** */
/* ********************************************************************** */
/* 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
* @param {object} config JSON configuration
* @param {object} spec JSON configuration
* @return HTML object
*/
// TODO: refactor
factory.generateListview = function (config) {
var i, item_config, item, list, target, skip;
list = factory.generateElement(
config.element.type,
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") {
// TODO: add to form support via children
// TODO: add collapsible support if needed
// 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(
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(
"li",
{
"className": "ui-li-divider ui-bar-" + config.theme +
(i === 0 ? " ui-first-child" : "")
"className": divider ? ("ui-li-divider ui-bar-" + theme) : "" +
(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",
"role":"heading",
"data-i18n": item_config.text_i18n
},
{"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" : "")
"data-role": divider ? "divider" : null,
"role": divider ? "heading" : null,
"data-icon" : icon === null ? false :
(icon === undefined ? null : icon)
}
);
// 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) {
target.appendChild(factory.generateElement(
"span",
if (static || divider) {
target = item;
} 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",
"innerHTML": "&nbsp;"
"data-external": props.external ? true : null
}
));
);
}
if (item_config.middle.title) {
target.appendChild(factory.generateElement(
"h3",
{},
{"data-i18n": item_config.middle.title_i18n},
{"text": item_config.middle.title}
));
// image
if (props.left) {
if (props.left.img) {
target.appendChild(factory.generateElement(
"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) {
target.appendChild(factory.generateElement(
"p",
{},
{"data-i18n": item_config.middle.subtitle_i18n},
{"text": item_config.middle.subtitle}
));
// 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}
)
);
}
if (item_config.middle.info) {
// count bubble
if (props.center.count) {
target.appendChild(factory.generateElement(
"span",
{"className": "ui-li-count ui-body-" +
(config.count_theme || spec.theme)
},
{},
{"data-i18n": item_config.middle.info_i18n},
{"text":item_config.middle.info}
{"text": props.center.count}
));
}
// 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)
));
}
if (skip === undefined) {
item.appendChild(target);
}
break;
};
// 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 list;
return [container, flag];
};
/* ********************************************************************** */
/* JQM POPUP */
/* JQM Page */
/* ********************************************************************** */
/**
* Generate a pre-enhanced popup and necessary elements (without content!)
* @method generatePopup
* @param {object} config JSON configuration for popup to be generated
* @param {string} scope id of page to append popup
* @return {object} documentFragment
*/
// TODO: make sure popups work inside the page, too
factory.generatePopup = function (config, scope) {
var popup,
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(
* Generate an empty JQM page
* @method generatePage
* @param {object} config Config object based on parsed link
* @param {object} layout Layout for the page to generate
* @return {object} HTML fragment
*/
// NOTE: we are defaulting to fixed toolbars!
factory.generatePage = function (config, layout) {
var page = factory.generateElement(
"div",
{
"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"
"id": config.id,
"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
}
);
popup_wrap.appendChild(popup);
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));
// set state
return container;
return page;
};
/* ********************************************************************** */
/* JQM Navbar */
/* JQM Table */
/* ********************************************************************** */
/* Generate a navbar
* @method generateNavbar
* @param {object} config Configuration options
* @returns navbar HTML fragment
/*
* Generates a table header based on configuration and portal_type
* @method generateTableHeader
* @param {object} settings Configuration for table to create
* @param {object} fields Field configurations for this portal Type
*/
factory.generateNavbar = function (config) {
var i, navbar, controls;
navbar = factory.generateElement(
"div",
{"className":"navbar ui-navbar " + (config.type_class || "")},
{"data-role":"navbar", "role":"navigation", "data-enhanced":"true"}
);
controls = factory.generateElement(
"ul",
{
"className": "ui-grid-" +
util.toLetters(config.buttons.length-1).toLowerCase()
}
);
// TODO: single row ok. multi row to make
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");
for (i = 0; i < config.buttons.length; i += 1) {
button = config.buttons[i];
button.direct["className"] += " ui-btn ui-shadow " +
factory.generateIconClassString(button);
// tickbox - all
if (check) {
// allow to select all records (not only visible)
action = settings.configuration.table.select_all ?
"check_all" : "check_all_visible";
item = factory.generateElement(
"li", {"className":"ui-block-" + util.toLetters(i+1).toLowerCase()}
);
item.appendChild(factory.generateLinkButton(button));
cell = factory.generateElement("th",{},{},{});
config = {
"type":"input",
"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 = {};
/* ********************************************************************** */
/* JQM Footer */
/* ********************************************************************** */
/**
* 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;
if (field.show) {
// TODO: good mapping?
field_config = fields[field.title];
footer = factory.generateElement(
"div",
{
"className":"ui-footer " +
(config.widget_class || " ") +
(config.fixed ? "ui-footer-fixed " : " ") + "slideup ui-bar-" +
(config.theme || "inherit"),
},
{
"data-role":"footer",
"data-theme":config.theme,
"data-enhanced":"true",
"role":"contentinfo"
},
{
"id": config.id || undefined,
"data-position": config.fixed ? "fixed" : undefined
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"},
{
"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 */
/* ********************************************************************** */
/**
* Generates JQM header. Header buttons are wrapped in controlgroups!
* @method generateHeader
* @param {object} config JSON configuration
* @return {object} HTML fragment
/*
* Generate table rows based on configuration and data provided. Needed
* to switch between editable and readonly table rows
* @method generateTableRow
* @param {object} settings Configuration for table row to create
* @param {object} item Data for this table row
* @returns table_row
*/
// TODO: logo instead of header
factory.generateHeader = function (config) {
var header,
group,
wrap,
factory.generateTableRow = function (settings, item) {
var k,
l,
i,
direction,
addTitle;
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;
// title
addTitle = function (title, i18n) {
return factory.generateElement(
"h1",
{"className":"translate ui-title"},
if (check) {
cell = factory.generateElement("th",{},{},{});
cell.appendChild(factory.generateFormElement(
{
"data-i18n": i18n || "",
"role":"heading",
"aria-level":"1"
"type":"input",
"direct": {
"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;"}
);
};
// 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]"}
false,
true
));
header.appendChild(wrap);
row.appendChild(cell);
}
// reverse if mergable columns
if (merger) {
target = util.reverseArray(target);
}
// button controlgroups
if (config.controls && config.controls.length > 0) {
for (i = 0; i < config.controls.length; i += 1) {
direction = i === 0 ? "left" : "right";
// loop fields to display
for (l = 0; l < target.length; l += 1) {
field = target[l];
property = field.title;
value = item[property];
wrap = factory.generateElement(
"div", {"className":"wrap " + direction}
);
group = factory.generateControlgroup(config.controls[i]);
if (field.show) {
if (field.merge === undefined) {
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
// 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);
header.appendChild(wrap);
if (field.actions) {
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
if (i === 0) {
header.appendChild(addTitle(config.title, config.title_i18n));
// 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;
}
}
} else {
header.appendChild(addTitle(config.title, config.title_i18n));
}
return header;
return row;
};
/* ********************************************************************** */
/* JQM Controlgroup */
/* ********************************************************************** */
/**
* Generate an controlgroup = a button or action menu
* @method generateControlgroup
* @param {object} config Configuration options
* @return controlgroup
/*
* Generates a table body based on configuration and data provided from JIO
* @method generateTableBody
* @param {object} settings Configuration for table body to create
* @param {object} answer from JIO
* @returns {object} table_body
*/
// TODO: refactor
factory.generateControlgroup = function (config) {
var i,
action_menu,
action_controls,
element,
icon_string,
direction;
factory.generateTableBody = function (settings, answer) {
var l,
row,
item,
property,
field,
error,
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
action_menu = factory.generateElement(
"div",
{
"className":"ui-corner-all ui-controlgroup " +
(config.widget_class || "") + " ui-controlgroup-" + direction
},
{
"data-role":"controlgroup",
"data-enhanced":"true",
"data-type": direction
for (l = 0; l < max; l += 1) {
item = answer.data.rows[l].doc;
row = factory.generateTableRow(settings, item);
table_body.appendChild(row);
}
);
} else {
// error or 0 results
row = factory.generateElement("tr");
l = settings.layout[0].columns.length;
// controls
action_controls = factory.generateElement(
"div",
{"className":"ui-controlgroup-controls " + (config.control_class || "")}
);
if (answer === undefined) {
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";
}
// 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" : "")
);
if (settings.configuration.table.checkbox_rows) {
l += 1;
}
action_controls.appendChild(factory.generateLinkButton(element));
break;
};
row.appendChild(factory.generateElement(
"th",
{"style":"text-align: center; line-height: 2em;"},
{"colspan":l},
{"text": error}
));
table_body.appendChild(row);
}
action_menu.appendChild(action_controls);
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
);
return table_body;
};
/* ********************************************************************** */
/* JQM Form Element */
/* ********************************************************************** */
......@@ -1542,6 +2022,7 @@
// TODO: mini? shadow? corners?
// TODO: slider/custom-select/flip
// TODO: refactor...
// TODO: placeholder?
factory.generateFormElement = function (config, wrap, label, position) {
var wrapper,
container,
......@@ -1771,71 +2252,7 @@
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 @@
* @param: {object} setters Parameters requiring logic (if-else-etc)
* @returns: {object} HTML object
*/
// TODO: bundle into spec!
factory.generateElement = function (type, options, attributes, setters) {
var property,
attribute,
......@@ -1915,11 +2333,11 @@
break;
case "id":
case "rows":
case "innerHTML":
case "cols":
case "name":
case "value":
case "data-":
case "role":
case "type":
case "readonly":
case "size":
......@@ -2113,26 +2531,6 @@
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
* @method crc32
......@@ -2878,7 +3276,8 @@
*/
init.parsePage = function (e, data) {
var create, config, raw_url, handle;
// console.log("pbc")
// TODO:maybe this is the problem???
if (data) {
if (data.options.link) {
raw_url = data.options.link[0].href;
......@@ -2891,28 +3290,39 @@
if (typeof raw_url === "string") {
config = util.parseLink(raw_url);
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("#", "")) ||
raw_url === $.mobile.getDocumentUrl() ||
data.options.role === "popup") {
// console.log("let JQM go")
return;
}
if (document.getElementById(config.id)) {
// console.log("stop JQM")
e.preventDefault();
return;
} else {
// PASS!
// console.log("HIJACK and stop JQM")
handle = true;
e.preventDefault();
}
} else {
// if ($.mobile.navigate.history.initialDst && location.hash !== "") {
// console.log("CLEANUP - set initialDst to ")
// $.mobile.navigate.history.initialDst = "";
// }
}
} else {
// once transition done. Update gadgets if going back to page in DOM
if(data.options.fromHashChange) {
init.setPageTitle(data.toPage[0], {});
}
return;
}
if (e === undefined || handle) {
if (config.deeplink) {
......@@ -3178,7 +3588,7 @@
// JQM treatment
$(document).enhanceWithin();
// console.log("CHANGING PAGE")
$.mobile.changePage("#" + config.id);
} else {
// populate existing page and enhance
......@@ -3342,14 +3752,14 @@
/**
* Loads and runs application setters
* @method loadApplicationSettings
* @method loadGlobalElements
* @return {object} promise object
*/
init.loadApplicationSettings = function () {
init.loadGlobalElements = function () {
return util.fetchConfiguration({
"storage": "settings",
"file": "configuration",
"attachment": "app",
"attachment": "global",
"baggage": undefined
});
};
......@@ -3379,25 +3789,19 @@
/**
* Sets up a global application element
* @method setupGlobalElement
* @param {object} config JSON configuration
* @param {object} spec JSON configuration
*/
init.setupGobalElement = function (config) {
switch (config.widget) {
case "header":
document.body.appendChild(factory.generateHeader(config));
break;
case "footer":
document.body.appendChild(factory.generateFooter(config));
break;
case "popup":
document.body.appendChild(factory.generatePopup(config));
break;
case "panel":
init.setupGobalElement = function (spec) {
var element = factory.util.forward(spec);
switch (spec.type) {
case "Panel":
// NOTE: panel must be either before or after everything else!
// WARNING: IE8- children() retrieves comments, too
document.body.insertBefore(
factory.generatePanel(config), document.body.children[0]
);
document.body.insertBefore(element, document.body.children[0]);
break;
default:
document.body.appendChild(element);
break;
}
};
......@@ -3407,6 +3811,7 @@
* @method setGlobalBindings
*/
init.setGlobalBindings = function () {
$(document)
.enhanceWithin()
......@@ -3546,7 +3951,7 @@
// "Application Setup"
.runApplicationSetup("settings", "storages")
.then(init.setupStorages)
.then(init.loadApplicationSettings)
.then(init.loadGlobalElements)
.then(init.setupGlobalElements)
.then(init.setGlobalBindings)
// "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