--- /dev/null
+BEGIN;
+
+CREATE OR REPLACE VIEW reporter.classic_current_circ AS
+SELECT cl.shortname AS circ_lib,
+ cl.id AS circ_lib_id,
+ circ.xact_start AS xact_start,
+ circ_type.type AS circ_type,
+ cp.id AS copy_id,
+ cp.circ_modifier,
+ ol.shortname AS owning_lib_name,
+ lm.value AS language,
+ lfm.value AS lit_form,
+ ifm.value AS item_form,
+ itm.value AS item_type,
+ sl.name AS shelving_location,
+ p.id AS patron_id,
+ g.name AS profile_group,
+ dem.general_division AS demographic_general_division,
+ circ.id AS id,
+ cn.id AS call_number,
+ cn.label AS call_number_label,
+ call_number_dewey(cn.label) AS dewey,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 10 * floor((call_number_dewey(cn.label)::float) / 10), '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_block_tens,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 100 * floor((call_number_dewey(cn.label)::float) / 100), '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_block_hundreds,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 10 * floor((call_number_dewey(cn.label)::float) / 10), '000'
+ )
+ )
+ || '-' ||
+ btrim(
+ to_char(
+ 10 * floor((call_number_dewey(cn.label)::float) / 10) + 9, '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_range_tens,
+ CASE
+ WHEN call_number_dewey(cn.label) ~ E'^[0-9.]+$'
+ THEN
+ btrim(
+ to_char(
+ 100 * floor((call_number_dewey(cn.label)::float) / 100), '000'
+ )
+ )
+ || '-' ||
+ btrim(
+ to_char(
+ 100 * floor((call_number_dewey(cn.label)::float) / 100) + 99, '000'
+ )
+ )
+ ELSE NULL
+ END AS dewey_range_hundreds,
+ hl.id AS patron_home_lib,
+ hl.shortname AS patron_home_lib_shortname,
+ paddr.county AS patron_county,
+ paddr.city AS patron_city,
+ paddr.post_code AS patron_zip,
+ sc1.stat_cat_entry AS stat_cat_1,
+ sc2.stat_cat_entry AS stat_cat_2,
+ sce1.value AS stat_cat_1_value,
+ sce2.value AS stat_cat_2_value
+ FROM action.circulation circ
+ JOIN reporter.circ_type circ_type ON (circ.id = circ_type.id)
+ JOIN asset.copy cp ON (cp.id = circ.target_copy)
+ JOIN asset.copy_location sl ON (cp.location = sl.id)
+ JOIN asset.call_number cn ON (cp.call_number = cn.id)
+ JOIN actor.org_unit ol ON (cn.owning_lib = ol.id)
+ JOIN metabib.rec_descriptor rd ON (rd.record = cn.record)
+ JOIN actor.org_unit cl ON (circ.circ_lib = cl.id)
+ JOIN actor.usr p ON (p.id = circ.usr)
+ JOIN actor.org_unit hl ON (p.home_ou = hl.id)
+ JOIN permission.grp_tree g ON (p.profile = g.id)
+ JOIN reporter.demographic dem ON (dem.id = p.id)
+ JOIN actor.usr_address paddr ON (paddr.id = p.billing_address)
+ LEFT JOIN config.language_map lm ON (rd.item_lang = lm.code)
+ LEFT JOIN config.lit_form_map lfm ON (rd.lit_form = lfm.code)
+ LEFT JOIN config.item_form_map ifm ON (rd.item_form = ifm.code)
+ LEFT JOIN config.item_type_map itm ON (rd.item_type = itm.code)
+ LEFT JOIN asset.stat_cat_entry_copy_map sc1 ON (sc1.owning_copy = cp.id AND sc1.stat_cat = 1)
+ LEFT JOIN asset.stat_cat_entry sce1 ON (sce1.id = sc1.stat_cat_entry)
+ LEFT JOIN asset.stat_cat_entry_copy_map sc2 ON (sc2.owning_copy = cp.id AND sc2.stat_cat = 2)
+ LEFT JOIN asset.stat_cat_entry sce2 ON (sce2.id = sc2.stat_cat_entry);
+
+CREATE OR REPLACE VIEW reporter.legacy_cat1 AS
+SELECT id,
+ owner,
+ value
+ FROM asset.stat_cat_entry
+ WHERE stat_cat = 1;
+
+CREATE OR REPLACE VIEW reporter.legacy_cat2 AS
+SELECT id,
+ owner,
+ value
+ FROM asset.stat_cat_entry
+ WHERE stat_cat = 2;
+
+
+COMMIT;
+
--- /dev/null
+
+var OILS_RPT_FILTERS = {
+ '=' : {
+ label : 'Equals',
+ },
+
+ 'like' : {
+ label : 'Contains Matching substring',
+ },
+
+ ilike : {
+ label : 'Contains Matching substring (ignore case)',
+ },
+
+ '>' : {
+ label : 'Greater than',
+ labels : { timestamp : 'After (Date/Time)' }
+ },
+
+ '>=' : {
+ label : 'Greater than or equal to',
+ labels : { timestamp : 'On or After (Date/Time)' }
+ },
+
+
+ '<' : {
+ label : 'Less than',
+ labels : { timestamp : 'Before (Date/Time)' }
+ },
+
+ '<=' : {
+ label : 'Less than or equal to',
+ labels : { timestamp : 'On or Before (Date/Time)' }
+ },
+
+ 'in' : {
+ label : 'In list',
+ },
+
+ 'not in' : {
+ label : 'Not in list',
+ },
+
+ 'between' : {
+ label : 'Between',
+ },
+
+ 'not between' : {
+ label : 'Not between',
+ },
+
+ 'is' : {
+ label : 'Is NULL'
+ },
+
+ 'is not' : {
+ label : 'Is not NULL'
+ }
+}
+
--- /dev/null
+
+function sourceTreeHandlerDblClick (ev) { return sourceTreeHandler(ev,true) }
+
+function sourceTreeHandler (ev, dbl) {
+
+ var row = {}, col = {}, part = {}, item;
+ var tree = $('idl-browse-tree');
+
+
+ try {
+ tree.treeBoxObject.getCellAt(ev.clientX, ev.clientY, row, col, part);
+ item = tree.contentView.getItemAtIndex(row.value);
+ } catch (e) {
+ // ... meh
+ }
+
+ if (part.value == 'twisty' || dbl) { // opening or closing
+ if (item.getAttribute('open') == 'true' && item.lastChild.childNodes.length == 0) {
+ //var subtree = item.lastChild;
+ //while (subtree.childNodes.length)
+ // subtree.removeChild(subtree.lastChild);
+
+ var p = getIDLClass( item.getAttribute('idlclass') );
+
+ var subtreeList = [];
+ var link_fields = p.getElementsByTagName('link');
+
+ for ( var i = 0; i < link_fields.length; i++ ) {
+ var field = getIDLField( p, link_fields[i].getAttribute('field') );
+
+ if (!field) continue;
+
+ var name = field.getAttributeNS(rptNS,'label');
+ if (!name) name = field.getAttribute('name');
+
+ var idlclass = link_fields[i].getAttribute('class');
+ var map = link_fields[i].getAttribute('map');
+ var link = link_fields[i].getAttribute('field');
+ var key = link_fields[i].getAttribute('key');
+ var reltype = link_fields[i].getAttribute('reltype');
+
+ if (map) continue;
+
+ var pathList = [];
+ findAnscestorStack( item, 'treeitem', pathList );
+
+ var fullpath = '';
+ for (var j in pathList.reverse()) {
+ var n = pathList[j].getAttribute('idlclass');
+ var f = pathList[j].getAttribute('field');
+
+ if (f) fullpath += "-" + f;
+
+ if (fullpath) fullpath += ".";
+ fullpath += n;
+
+ }
+
+ fullpath += "-" + link;
+
+ subtreeList.push(
+ { name : name,
+ idlclass : idlclass,
+ map : map,
+ key : key,
+ field : field.getAttribute('name'),
+ reltype : reltype,
+ link : link,
+ fullpath : fullpath
+ }
+ );
+ }
+
+ populateSourcesSubtree( item.lastChild, subtreeList );
+ }
+ } else if (item) {
+ var classtree = $('class-treetop');
+
+ while (classtree.childNodes.length)
+ classtree.removeChild(classtree.lastChild);
+
+ var c = getIDLClass( item.getAttribute('idlclass') );
+
+ populateDetailTree(
+ classtree,
+ c,
+ item
+ );
+ }
+
+ return true;
+}
+
+function transformSelectHandler (noswap) {
+ var transform_tree = $('trans-view');
+ var transform = getSelectedItems(transform_tree)[0];
+
+ if (transform) {
+ if (transform.getAttribute('aggregate') == 'true') {
+ $( 'filter_tab' ).setAttribute('disabled','true');
+ $( 'aggfilter_tab' ).setAttribute('disabled','false');
+
+ if (!noswap && $( 'filter_tab' ).selected)
+ $( 'filter_tab' ).parentNode.selectedItem = $( 'aggfilter_tab' );
+ } else {
+ $( 'filter_tab' ).setAttribute('disabled','false');
+ $( 'aggfilter_tab' ).setAttribute('disabled','true');
+
+ if (!noswap && $( 'aggfilter_tab' ).selected)
+ $( 'aggfilter_tab' ).parentNode.selectedItem = $( 'filter_tab' );
+ }
+ }
+
+ if ($( 'filter_tab' ).selected) {
+ if ($( 'filter_tab' ).getAttribute('disabled') == 'true')
+ $( 'source-add' ).setAttribute('disabled','true');
+ else
+ $( 'source-add' ).setAttribute('disabled','false');
+
+ } else if ($( 'aggfilter_tab' ).selected) {
+ if ($( 'aggfilter_tab' ).getAttribute('disabled') == 'true')
+ $( 'source-add' ).setAttribute('disabled','true');
+ else
+ $( 'source-add' ).setAttribute('disabled','false');
+
+ } else if ($( 'dis_tab' ).selected) {
+ $( 'source-add' ).setAttribute('disabled','false');
+ }
+}
+
+function detailTreeHandler (args) {
+ var class_tree = $('class-view');
+ var transform_tree = $('trans-treetop');
+
+ while (transform_tree.childNodes.length)
+ transform_tree.removeChild(transform_tree.lastChild);
+
+ var class_items = getSelectedItems(class_tree);;
+
+ var transforms = new Object();
+ for (var i in class_items) {
+ var item = class_items[i];
+ var dtype = item.lastChild.lastChild.getAttribute('label');
+
+ var item_transforms = getTransforms({ datatype : dtype });
+
+ for (var j in item_transforms) {
+ transforms[item_transforms[j]] = OILS_RPT_TRANSFORMS[item_transforms[j]];
+ transforms[item_transforms[j]].name = item_transforms[j];
+ }
+ }
+
+ var transformList = [];
+ for (var i in transforms) {
+ transformList.push( transforms[i] );
+ }
+
+ transformList.sort( sortHashLabels );
+
+ $( 'aggfilter_tab' ).setAttribute('disabled','true');
+
+ for (var i in transformList) {
+ var t = transformList[i];
+ transform_tree.appendChild(
+ createTreeItem(
+ { aggregate : t.aggregate,
+ name : t.name,
+ alias : t.label,
+ params : t.params,
+ },
+ createTreeRow(
+ {},
+ createTreeCell( { label : t.label } ),
+ createTreeCell( { label : t.params ? t.params : '0' } ),
+ createTreeCell( { label : t.datatype.length > 0 ? t.datatype.join(', ') : 'all' } ),
+ createTreeCell( { label : t.aggregate ? 'Aggregate' : 'Non-Aggregate' } )
+ )
+ )
+ );
+
+ if (t.aggregate) $( 'aggfilter_tab' ).setAttribute('disabled','false');
+ }
+
+ transformSelectHandler(true);
+
+ return true;
+}
+
+
+
--- /dev/null
+
+var idlNS = "http://opensrf.org/spec/IDL/base/v1";
+var persistNS = "http://open-ils.org/spec/opensrf/IDL/persistance/v1";
+var objNS = "http://open-ils.org/spec/opensrf/IDL/objects/v1";
+var rptNS = "http://open-ils.org/spec/opensrf/IDL/reporter/v1";
+var gwNS = "http://opensrf.org/-/namespaces/gateway/v1";
+var xulNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
+
+var oilsIDL;
+var rpt_rel_cache = {};
+
+function sortHashLabels (a,b) { return a.label.toLowerCase() < b.label.toLowerCase() ? -1 : 1; }
+
+function sortNames (a,b) {
+ var aname = a.name.toLowerCase();
+ if (!aname) aname = a.idlclass.toLowerCase();
+
+ var bname = b.name.toLowerCase();
+ if (!bname) bname = b.idlclass.toLowerCase();
+
+ return aname < bname ? -1 : 1;
+}
+
+function sortLabels (a,b) {
+ var aname = a.getAttributeNS(rptNS, 'label').toLowerCase();
+ if (!aname) aname = a.getAttribute('name');
+ if (!aname) aname = a.getAttribute('id');
+
+ var bname = b.getAttributeNS(rptNS, 'label').toLowerCase();
+ if (!bname) bname = b.getAttribute('name');
+ if (!bname) bname = b.getAttribute('id');
+
+ return aname < bname ? -1 : 1;
+}
+
+
+function loadTemplate(id) {
+ var cgi = new CGI();
+ var session = cgi.param('ses');
+
+ var r = new Request('open-ils.reporter:open-ils.reporter.template.retrieve', session, id);
+
+ r.callback(
+ function(res) {
+ var tmpl = res.getResultObject();
+ var template = JSON2js( tmpl.data() );
+
+ resetUI( template.core_class );
+
+ $('template-name').value = tmpl.name() + ' (clone)';
+ $('template-description').value = tmpl.description();
+
+ rpt_rel_cache = template.rel_cache;
+ renderSources();
+ }
+ );
+
+ r.send();
+}
+
+
+function loadIDL() {
+ var req = new XMLHttpRequest();
+ req.open('GET', '../fm_IDL.xml', true);
+ req.onreadystatechange = function() {
+ if( req.readyState == 4 ) {
+ oilsIDL = req.responseXML;
+ populateSourcesMenu(
+ filterByAttributeNS( oilsIDL.getElementsByTagName('class'), rptNS, 'core', 'true' )
+ );
+
+ var cgi = new CGI();
+ var template_id = cgi.param('ct');
+ if (template_id) loadTemplate(template_id);
+ }
+ }
+ req.send(null);
+
+}
+
+function getIDLClass (id) { return filterByAttribute( oilsIDL.getElementsByTagName('class'), 'id', id )[0] }
+function getIDLField (classNode,field) { return filterByAttribute( classNode.getElementsByTagName('field'), 'name', field )[0] }
+function getIDLLink (classNode,field) { return filterByAttribute( classNode.getElementsByTagName('link'), 'field', field )[0] }
+
+function resetUI (idlclass) {
+ if (getKeys(rpt_rel_cache).length > 0) {
+ if (!confirm(
+ "You have started building a template!\n" +
+ "Selecting a new starting source will destroy " +
+ "the current template and start over. Is this OK?"
+ )) return false;
+ }
+
+ rpt_rel_cache = {};
+ try { renderSources(); } catch (e) {}
+
+ populateSourcesTree( idlclass );
+
+ var tree = $('sources-treetop').parentNode;
+ tree.focus();
+ tree.view.selection.select(0);
+ tree.click();
+}
+
+function populateSourcesMenu (classList) {
+ classList.sort( sortLabels );
+
+ var menu = $('source-menu');
+
+ menu.appendChild(
+ createMenuItem(
+ { label : 'Core Sources',
+ disabled : 'true',
+ style : 'color: black; text-decoration: underline;'
+ }
+ )
+ );
+
+
+ for (var i in classList) {
+
+ var name = classList[i].getAttributeNS(rptNS,'label');
+ var id = classList[i].getAttribute('id');
+ if (!name) name = id;
+
+ menu.appendChild(
+ createMenuItem(
+ { container : 'true',
+ idlclass : id,
+ label : name,
+ onmouseup : 'resetUI( "' + id + '");'
+ }
+ )
+ );
+
+ }
+
+ menu.appendChild( createMenuSeparator() );
+
+ var _m = createMenu(
+ { label : 'All Available Sources' },
+ createMenuPopup(
+ {},
+ createMenuItem(
+ { label : 'All Available Sources',
+ disabled : 'true',
+ style : 'color: black; '
+ }
+ ),
+ createMenuSeparator()
+ )
+ );
+
+ menu.appendChild( _m );
+ menu = _m.firstChild;
+
+ var all = map(function(x){return x;}, oilsIDL.getElementsByTagNameNS(idlNS,'class'));
+ all.sort( sortLabels );
+
+ for (var i = 0; i < all.length; i++) {
+
+ if (all[i].getAttributeNS(persistNS,'virtual') == 'true') continue;
+
+ var name = all[i].getAttributeNS(rptNS,'label');
+ var id = all[i].getAttribute('id');
+ if (!name) name = id;
+
+ menu.appendChild(
+ createMenuItem(
+ { container : 'true',
+ idlclass : id,
+ label : name,
+ onmouseup : 'resetUI( "' + id + '");'
+ }
+ )
+ );
+
+ }
+
+
+}
+
+function populateSourcesTree (idlclass) {
+
+ var tcNode = $('sources-treetop');
+ while (tcNode.childNodes.length) tcNode.removeChild(tcNode.lastChild);
+
+ var c = getIDLClass( idlclass );
+ var name = c.getAttributeNS(rptNS,'label');
+ if (!name) name = idlclass;
+
+ tcNode.appendChild(
+ createTreeItem(
+ { container : 'true',
+ idlclass : idlclass,
+ fullpath : idlclass
+ },
+ createTreeRow(
+ { },
+ createTreeCell( { label : name } )
+ ),
+ createTreeChildren( { alternatingbackground : true } )
+ )
+ );
+}
+
+function populateSourcesSubtree (tcNode, classList) {
+ classList.sort(sortNames);
+ for (var i in classList) {
+ var obj = classList[i];
+
+ var p = getIDLClass( obj.idlclass );
+ var cont = p.getElementsByTagName('link').length ? 'true' : 'false';
+
+ tcNode.appendChild(
+ createTreeItem(
+ { container : cont,
+ idlclass : obj.idlclass,
+ map : obj.map,
+ key : obj.key,
+ field : obj.field,
+ link : obj.link,
+ reltype : obj.reltype,
+ fullpath : obj.fullpath,
+ },
+ createTreeRow(
+ { },
+ createTreeCell( { label : obj.name } )
+ ),
+ createTreeChildren( { alternatingbackground : true } )
+ )
+ );
+
+
+ }
+}
+
+function populateDetailTree (tcNode, c, item) {
+ var fullpath = item.getAttribute('fullpath');
+ var reltype = item.getAttribute('reltype');
+
+ var fields = filterByAttributeNS(c.getElementsByTagName('field'),persistNS, 'virtual','false');
+ fields.sort( sortLabels );
+
+ var id = c.getAttribute('id');
+ var path_label = [];
+
+ var steps = fullpath.split('.');
+ for (var k in steps) {
+
+ if (!steps[k]) continue;
+
+ var atom = steps[k].split('-');
+ var classNode = getIDLClass(atom[0]);
+
+ var _cname = classNode.getAttributeNS(rptNS, 'label');
+ if (!_cname) _cname = classNode.getAttribute('id');
+
+ var _label = _cname;
+
+ if (atom.length > 1 && k == steps.length - 1) {
+ var _f = getIDLField(classNode, atom[1]);
+ var _fname = _f.getAttributeNS(rptNS, 'label');
+ if (!_fname) _fname = _f.getAttribute('name');
+ if (_fname) _label += ' :: ' + _fname;
+ }
+
+ path_label.push(_label);
+ }
+
+ $('path-label').value = path_label.join(' -> ');
+ $('path-label').setAttribute('reltype',reltype);
+
+ for (var i in fields) {
+
+ var type = fields[i].getAttributeNS(rptNS, 'datatype');
+ //if (!type) type = 'text';
+
+ var label = fields[i].getAttributeNS(rptNS, 'label');
+ var name = fields[i].getAttribute('name');
+ if (!label) label = name;
+
+ tcNode.appendChild(
+ createTreeItem(
+ { idlclass : id,
+ idlfield : name,
+ datatype : type,
+ fullpath : fullpath
+ },
+ createTreeRow(
+ { },
+ createTreeCell( { label : label } ),
+ createTreeCell( { label : type } )
+ )
+ )
+ );
+ }
+}
+
+
--- /dev/null
+function removeReportAtom (args) {
+ if (!args) args = {};
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var fields = getSelectedItems(tree);
+
+
+ for (var i in fields) {
+ var field = fields[i];
+ var colname = field.firstChild.firstChild.nextSibling.getAttribute('label');
+ var relation_alias = field.getAttribute('relation');
+
+ delete rpt_rel_cache[relation_alias].fields[tabname][colname];
+ if (tabname == 'dis_tab') {
+ var _o_tmp = [];
+ for each (var _o_col in rpt_rel_cache.order_by) {
+ if (_o_col.relation == relation_alias && _o_col.field == colname) continue;
+ _o_tmp.push( _o_col );
+ }
+ rpt_rel_cache.order_by = _o_tmp
+ }
+
+ with (rpt_rel_cache[relation_alias].fields) {
+ if ( getKeys(dis_tab).length == 0 && getKeys(filter_tab).length == 0 && getKeys(aggfilter_tab).length == 0 )
+ delete rpt_rel_cache[relation_alias];
+ }
+ }
+
+ renderSources();
+
+ return true;
+}
+
+function addReportAtoms () {
+ var nope = $( 'source-add' ).getAttribute('disabled');
+ if (nope == 'true') return false;
+
+ var class_tree = $('class-view');
+ var transform_tree = $('trans-view');
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id')
+
+ var items = getSelectedItems(class_tree);
+ var transform = getSelectedItems(transform_tree)[0];
+
+ var reltype = $('path-label').getAttribute('reltype');
+ var class_label = $('path-label').value;
+ var relation_alias = hex_md5(class_label);
+
+ for (var i in items) {
+ var item = items[i];
+
+ var class_path = item.getAttribute('fullpath');
+ var field_class = item.getAttribute('idlclass');
+ var datatype = item.getAttribute('datatype');
+ var colname = item.getAttribute('idlfield');
+ var field_label = item.firstChild.firstChild.getAttribute('label');
+
+ var table_name = getIDLClass(field_class).getAttributeNS(persistNS,'tablename');
+
+ if ( !rpt_rel_cache[relation_alias] ) {
+ rpt_rel_cache[relation_alias] =
+ { label : class_label,
+ alias : relation_alias,
+ path : class_path,
+ reltype : reltype,
+ idlclass : field_class,
+ table : table_name,
+ fields: { dis_tab : {}, filter_tab : {}, aggfilter_tab : {} }
+ };
+ }
+
+ if ( !rpt_rel_cache[relation_alias].fields[tabname][colname] ) {
+ rpt_rel_cache[relation_alias].fields[tabname][colname] =
+ { colname : colname,
+ transform : (transform && transform.getAttribute('name')) || 'Bare',
+ aggregate : transform && transform.getAttribute('aggregate'),
+ params : transform && transform.getAttribute('params'),
+ transform_label: (transform && transform.getAttribute('alias')) || 'Raw Data',
+ alias : field_label,
+ datatype : datatype,
+ op : '=',
+ op_label : 'Equals',
+ op_value : {},
+ };
+
+ if (!rpt_rel_cache.order_by)
+ rpt_rel_cache.order_by = [];
+
+ if (tabname == 'dis_tab')
+ rpt_rel_cache.order_by.push( { relation : relation_alias, field : colname } );
+
+ } else if (
+ confirm(
+ 'You have already added the [' + field_label +
+ '] field\nfrom the [' + class_label + '] source. Click OK if you\nwould like ' +
+ 'to reset this field.'
+ )
+ ) {
+ rpt_rel_cache[relation_alias].fields[tabname][colname] =
+ { colname : colname,
+ transform : (transform && transform.getAttribute('name')) || 'Bare',
+ aggregate : transform && transform.getAttribute('aggregate'),
+ params : transform && transform.getAttribute('params'),
+ transform_label: (transform && transform.getAttribute('alias')) || 'Raw Data',
+ alias : field_label,
+ datatype : datatype,
+ op : '=',
+ op_label : 'Equals',
+ op_value : {},
+ };
+ }
+ }
+
+ renderSources();
+
+ return true;
+}
+
+function changeDisplayOrder (dir) {
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var item = getSelectedItems(tree)[0];
+
+ var item_pos = tree.view.selection.currentIndex;
+
+ if (dir == 'u') {
+ if ( item.previousSibling ) {
+ item.parentNode.insertBefore( item, item.previousSibling );
+ item_pos--;
+ }
+ } else if (dir == 'd') {
+ if ( item.nextSibling ) {
+ if (item.nextSibling.nextSibling ) item.parentNode.insertBefore( item, item.nextSibling.nextSibling );
+ else item.parentNode.appendChild( item );
+ item_pos++;
+ }
+ }
+
+ rpt_rel_cache.order_by = [];
+ var ordered_list = tree.getElementsByTagName('treeitem');
+ for (var i = 0; i < ordered_list.length; i++) {
+ rpt_rel_cache.order_by.push(
+ { relation : ordered_list[i].getAttribute('relation'),
+ field : ordered_list[i].firstChild.firstChild.nextSibling.getAttribute('label')
+ }
+ );
+ }
+
+ tree.view.selection.select( item_pos );
+ return true;
+}
+
+function alterColumnLabel () {
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var item_pos = tree.view.selection.currentIndex;
+
+ var item = getSelectedItems(tree)[0];
+ var relation_alias = item.getAttribute('relation');
+
+ var field = item.firstChild.firstChild;
+ var colname = field.nextSibling.getAttribute('label');
+
+ var new_label = prompt(
+ "Change the column header to:",
+ field.getAttribute("label")
+ );
+
+ if (new_label) {
+ rpt_rel_cache[relation_alias].fields[tabname][colname].alias = new_label;
+ renderSources(true);
+ tree.view.selection.select( item_pos );
+ tree.focus();
+ tree.click();
+ }
+
+ return true;
+}
+
+function alterColumnTransform (trans) {
+
+ var transform = OILS_RPT_TRANSFORMS[trans];
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var item_pos = tree.view.selection.currentIndex;
+ var item = getSelectedItems(tree)[0];
+ var relation_alias = item.getAttribute('relation');
+
+ var field = item.firstChild.firstChild;
+ var colname = field.nextSibling.getAttribute('label');
+
+ rpt_rel_cache[relation_alias].fields[tabname][colname].transform = trans;
+ rpt_rel_cache[relation_alias].fields[tabname][colname].aggregate = transform.aggregate;
+ rpt_rel_cache[relation_alias].fields[tabname][colname].params = transform.params;
+ rpt_rel_cache[relation_alias].fields[tabname][colname].transform_label = transform.label;
+
+ renderSources(true);
+ tree.view.selection.select( item_pos );
+ tree.focus();
+ tree.click();
+
+ $(tabname + '_trans_menu').hidePopup();
+ return true;
+}
+
+function changeOperator (args) {
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var item_pos = tree.view.selection.currentIndex;
+ var item = getSelectedItems(tree)[0];
+
+ var relation_alias = item.getAttribute('relation');
+
+ var field = item.firstChild.firstChild;
+ var colname = field.nextSibling.getAttribute('label');
+
+ rpt_rel_cache[relation_alias].fields[tabname][colname].op = args.op;
+ rpt_rel_cache[relation_alias].fields[tabname][colname].op_label = args.label;
+
+ renderSources(true);
+ tree.view.selection.select( item_pos );
+ tree.focus();
+ tree.click();
+
+ $(tabname + '_op_menu').hidePopup();
+ return true;
+}
+
+function removeTemplateFilterValue () {
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var item_pos = tree.view.selection.currentIndex;
+ var items = getSelectedItems(tree);
+
+ for (var i in items) {
+ var item = items[i];
+ var relation_alias = item.getAttribute('relation');
+
+ var field = item.firstChild.firstChild;
+ var colname = field.nextSibling.getAttribute('label');
+
+ rpt_rel_cache[relation_alias].fields[tabname][colname].op_value = {};
+ }
+
+ renderSources(true);
+ tree.view.selection.select( item_pos );
+ return true;
+}
+
+function timestampSetDate (obj, cal, date) {
+ obj.op_value.value = date;
+ obj.op_value.object = cal.date;
+ obj.op_value.label = '"' + date + '"';
+
+ renderSources(true);
+ return true;
+}
+
+var __handler_cache;
+
+function changeTemplateFilterValue () {
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var items = getSelectedItems(tree);
+
+ var targetCmd = $( tabname + '_value_action' );
+
+ targetCmd.menu = null;
+ targetCmd.command = null;
+ targetCmd.oncommand = null;
+ targetCmd.removeEventListener( 'command', __handler_cache, true );
+
+ for (var i in items) {
+ var item = items[i];
+ var relation_alias = item.getAttribute('relation');
+
+ var field = item.firstChild.firstChild;
+ var colname = field.nextSibling.getAttribute('label');
+
+ var obj = rpt_rel_cache[relation_alias].fields[tabname][colname]
+ var operation = OILS_RPT_FILTERS[obj.op];
+
+ switch (obj.datatype) {
+ case 'timestamp':
+ var cal_popup = $('calendar-widget');
+
+ while (cal_popup.firstChild) cal_popup.removeChild(cal_popup.lastChild);
+ var calendar = new Calendar(
+ 0,
+ obj.op_value.object,
+ function (cal,date) { return timestampSetDate(obj,cal,date) },
+ function (cal) { cal_popup.hidePopup(); cal.destroy(); return true; }
+ );
+
+ var format = OILS_RPT_TRANSFORMS[obj.transform].cal_format || '%Y-%m-%d';
+
+ calendar.setDateFormat(format);
+ calendar.create(cal_popup);
+
+ targetCmd.menu = 'calendar-widget';
+
+ break;
+
+ case 'bool':
+
+ function __bool_value_event_handler () {
+ var state, answer;
+
+ try {
+ // get a reference to the prompt service component.
+ var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
+ .getService(Components.interfaces.nsIPromptService);
+
+ // set the buttons that will appear on the dialog. It should be
+ // a set of constants multiplied by button position constants. In this case,
+ // three buttons appear, Save, Cancel and a custom button.
+ var flags=promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
+ promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
+ promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_2;
+
+ // display the dialog box. The flags set above are passed
+ // as the fourth argument. The next three arguments are custom labels used for
+ // the buttons, which are used if BUTTON_TITLE_IS_STRING is assigned to a
+ // particular button. The last two arguments are for an optional check box.
+ answer = promptService.select(
+ window,
+ "Boolean Value",
+ "Select the value, or cancel:",
+ 2, ["True", "False"], state
+ );
+ } catch (e) {
+ answer = true;
+ state = confirm("Click OK for TRUE and Cancel for FALSE.");
+ state ? state = 0 : state = 1;
+ }
+
+ if (answer) {
+ if (state) {
+ obj.op_value.value = 'f';
+ obj.op_value.label = 'False';
+ } else {
+ obj.op_value.value = 't';
+ obj.op_value.label = 'True';
+ }
+ }
+
+ targetCmd.removeEventListener( 'command', __bool_value_event_handler, true );
+ renderSources(true);
+ tree.view.selection.select( item_pos );
+ return true;
+ }
+
+ __handler_cache = __bool_value_event_handler;
+ targetCmd.addEventListener( 'command', __bool_value_event_handler, true );
+
+ break;
+
+ default:
+
+
+ var promptstring = "Field does not match one of list (comma separated):";
+
+ switch (obj.op) {
+ case 'not between':
+ promptstring = "Field value is not between (comma separated):";
+ break;
+
+ case 'between':
+ promptstring = "Field value is between (comma separated):";
+ break;
+
+ case 'not in':
+ promptstring = "Field does not match one of list (comma separated):";
+ break;
+
+ case 'in':
+ promptstring = "Field matches one of list (comma separated):";
+ break;
+
+ default:
+ promptstring = "Value " + obj.op_label + ":";
+ break;
+ }
+
+ function __default_value_event_handler () {
+ var _v;
+ if (_v = prompt( promptstring, obj.op_value.value || '' )) {
+ switch (obj.op) {
+ case 'between':
+ case 'not between':
+ case 'not in':
+ case 'in':
+ obj.op_value.value = _v.split(/\s*,\s*/);
+ break;
+
+ default:
+ obj.op_value.value = _v;
+ break;
+ }
+
+ obj.op_value.label = '"' + obj.op_value.value + '"';
+ }
+
+ targetCmd.removeEventListener( 'command', __default_value_event_handler, true );
+ renderSources(true);
+ tree.view.selection.select( item_pos );
+ return true;
+ }
+
+ __handler_cache = __default_value_event_handler;
+ targetCmd.addEventListener( 'command', __default_value_event_handler, true );
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+function populateOperatorContext () {
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var items = getSelectedItems(tree);
+
+ var dtypes = [];
+ for (var i in items) {
+ var item = items[i];
+ dtypes.push( item.getAttribute('datatype') );
+ }
+
+ var menu = $(tabname + '_op_menu');
+ while (menu.firstChild) menu.removeChild(menu.lastChild);
+
+ for (var i in OILS_RPT_FILTERS) {
+ var o = OILS_RPT_FILTERS[i];
+ menu.appendChild(
+ createMenuItem(
+ { label : o.label,
+ onmouseup : "changeOperator({op:'"+i+"',label:'"+o.label+"'})"
+ }
+ )
+ );
+ if (o.labels) {
+ var keys = getKeys(o.labels);
+ for ( var k in keys ) {
+ var key = keys[k];
+ if ( grep(function(x){return key==x},dtypes).length ) {
+ menu.appendChild(
+ createMenuItem(
+ { label : o.labels[key],
+ onmouseup : "changeOperator({op:'"+i+"',label:'"+o.labels[key]+"'});"
+ }
+ )
+ );
+ }
+ }
+ }
+ }
+}
+
+function populateTransformContext () {
+
+ var active_tab = filterByAttribute(
+ $('used-source-fields-tabbox').getElementsByTagName('tab'),
+ 'selected',
+ 'true'
+ )[0];
+
+ var tabname = active_tab.getAttribute('id');
+
+ var tabpanel = $( tabname + 'panel' );
+ var tree = tabpanel.getElementsByTagName('tree')[0];
+ var items = getSelectedItems(tree);
+
+ var transforms = {};
+ for (var i in items) {
+ var item = items[i];
+ var dtype = item.getAttribute('datatype');
+ var item_transforms = getTransforms({ datatype : dtype });
+
+ for (var j in item_transforms) {
+ transforms[item_transforms[j]] = OILS_RPT_TRANSFORMS[item_transforms[j]];
+ transforms[item_transforms[j]].name = item_transforms[j];
+ }
+ }
+
+ var transformList = [];
+ for (var i in transforms) {
+ transformList.push( transforms[i] );
+ }
+
+ transformList.sort( sortHashLabels );
+
+ var menu = $(tabname + '_trans_menu');
+ while (menu.firstChild) menu.removeChild(menu.lastChild);
+
+ for (var i in transformList) {
+ var t = transformList[i];
+
+ if (tabname.match(/filter/)) {
+ if (tabname.match(/^agg/)) {
+ if (!t.aggregate) continue;
+ } else {
+ if (t.aggregate) continue;
+ }
+ }
+
+ menu.appendChild(
+ createMenuItem(
+ { aggregate : t.aggregate,
+ name : t.name,
+ alias : t.label,
+ label : t.label,
+ params : t.params,
+ onmouseup : "alterColumnTransform('"+t.name+"')"
+ }
+ )
+ );
+ }
+
+ menu.parentNode.setAttribute('disabled','false');
+ if (menu.childNodes.length == 0) {
+ menu.parentNode.setAttribute('disabled','true');
+ }
+}
+
+
+function renderSources (selected) {
+
+ var tree = $('used-sources');
+ var sources = $('used-sources-treetop');
+ var tabs = $('used-source-fields-tabbox').getElementsByTagName('tab');
+
+ if (!selected) {
+ while (sources.firstChild) sources.removeChild(sources.lastChild);
+ } else {
+ selected = getSelectedItems(tree);
+ if (!selected.length) {
+ selected = undefined;
+ while (sources.firstChild) sources.removeChild(sources.lastChild);
+ }
+ }
+
+ for (var j = 0; j < tabs.length; j++) {
+ var tab = tabs[j];
+ var tabname = tab.getAttribute('id')
+ var tabpanel = $( tab.getAttribute('id') + 'panel' );
+ var fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
+
+ while (fieldtree.firstChild) fieldtree.removeChild(fieldtree.lastChild);
+ }
+
+ for (var relation_alias in rpt_rel_cache) {
+ if (!rpt_rel_cache[relation_alias].fields) continue;
+
+ if (selected) {
+ if (
+ !grep(
+ function (x) {
+ return x.getAttribute('relation') == relation_alias;
+ },
+ selected
+ ).length
+ ) continue;
+ } else {
+
+ $('used-sources-treetop').appendChild(
+ createTreeItem(
+ { relation : rpt_rel_cache[relation_alias].alias,
+ idlclass : rpt_rel_cache[relation_alias].idlclass,
+ reltype : rpt_rel_cache[relation_alias].reltype,
+ path : rpt_rel_cache[relation_alias].path,
+ },
+ createTreeRow(
+ {},
+ createTreeCell({ label : rpt_rel_cache[relation_alias].label }),
+ createTreeCell({ label : rpt_rel_cache[relation_alias].table }),
+ createTreeCell({ label : rpt_rel_cache[relation_alias].alias }),
+ createTreeCell({ label : rpt_rel_cache[relation_alias].reltype })
+ )
+ )
+ );
+ }
+
+ for each (var tabname in ['filter_tab','aggfilter_tab']) {
+ tabpanel = $( tabname + 'panel' );
+ fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
+
+ for (var colname in rpt_rel_cache[relation_alias].fields[tabname]) {
+ with (rpt_rel_cache[relation_alias].fields[tabname][colname]) {
+ fieldtree.appendChild(
+ createTreeItem(
+ { relation : relation_alias, datatype : datatype },
+ createTreeRow(
+ {},
+ createTreeCell({ label : alias }),
+ createTreeCell({ label : colname }),
+ createTreeCell({ label : datatype }),
+ createTreeCell({ label : transform_label }),
+ createTreeCell({ label : transform })
+ )
+ )
+ );
+
+ fieldtree.lastChild.firstChild.appendChild(
+ createTreeCell({ op : op, label : op_label })
+ );
+
+ if (op_value.value != undefined) {
+ fieldtree.lastChild.firstChild.appendChild(
+ createTreeCell({ label : op_value.label })
+ );
+ }
+ }
+ }
+ }
+ }
+
+ tabpanel = $( 'dis_tabpanel' );
+ fieldtree = tabpanel.getElementsByTagName('treechildren')[0];
+ for each (var order in rpt_rel_cache.order_by) {
+
+ if (selected) {
+ if (
+ !grep(
+ function (x) {
+ return x.getAttribute('relation') == order.relation;
+ },
+ selected
+ ).length
+ ) continue;
+ }
+
+ with (rpt_rel_cache[order.relation].fields.dis_tab[order.field]) {
+ fieldtree.appendChild(
+ createTreeItem(
+ { relation : order.relation, datatype : datatype },
+ createTreeRow(
+ {},
+ createTreeCell({ label : alias }),
+ createTreeCell({ label : colname }),
+ createTreeCell({ label : datatype }),
+ createTreeCell({ label : transform_label }),
+ createTreeCell({ label : transform })
+ )
+ )
+ );
+
+ fieldtree.lastChild.firstChild.appendChild(
+ createTreeCell({ op : op, label : op_label })
+ );
+
+ if (op_value.value != undefined) {
+ fieldtree.lastChild.firstChild.appendChild(
+ createTreeCell({ label : op_value.label })
+ );
+ }
+ }
+ }
+}
+
+var param_count;
+var tab_use = {
+ dis_tab : 'select',
+ filter_tab : 'where',
+ aggfilter_tab : 'having',
+};
+
+
+function save_template () {
+ param_count = 0;
+
+ var template = {
+ version : 2,
+ core_class : $('sources-treetop').getElementsByTagName('treeitem')[0].getAttribute('idlclass'),
+ select : [],
+ from : {},
+ where : [],
+ having : [],
+ order_by : []
+ };
+
+ for (var relname in rpt_rel_cache) {
+ var relation = rpt_rel_cache[relname];
+ if (!relation.fields) continue;
+
+ // first, add the where and having clauses (easier)
+ for each (var tab_name in [ 'filter_tab', 'aggfilter_tab' ]) {
+ var tab = relation.fields[tab_name];
+ for (var field in tab) {
+ fleshTemplateField( template, relation, tab_name, field );
+ }
+ }
+
+ // now the from clause
+ fleshFromPath( template, relation );
+ }
+
+ // and now for select (based on order_by)
+ for each (var order in rpt_rel_cache.order_by)
+ fleshTemplateField( template, rpt_rel_cache[order.relation], 'dis_tab', order.field );
+
+ template.rel_cache = rpt_rel_cache;
+
+ //prompt( 'template', js2JSON( template ) );
+
+ // and the saving throw ...
+ var cgi = new CGI();
+ var session = cgi.param('ses');
+ fetchUser( session );
+
+ var tmpl = new rt();
+ tmpl.name( $('template-name').value );
+ tmpl.description( $('template-description').value );
+ tmpl.owner(USER.id());
+ tmpl.folder(cgi.param('folder'));
+ tmpl.data(js2JSON(template));
+
+ if(!confirm('Name : '+tmpl.name() + '\nDescription: ' + tmpl.description()+'\nSave Template?'))
+ return;
+
+ var req = new Request('open-ils.reporter:open-ils.reporter.template.create', session, tmpl);
+ req.request.alertEvent = false;
+ req.callback(
+ function(r) {
+ var res = r.getResultObject();
+ if(checkILSEvent(res)) {
+ alertILSEvent(res);
+ } else {
+ if( res && res != '0' ) {
+ confirm('Template ' + tmpl.name() + ' was successfully saved.');
+ _l('../oils_rpt.xhtml');
+ }
+ }
+ }
+ );
+
+ req.send();
+}
+
+function fleshFromPath ( template, rel ) {
+ var table_path = rel.path.split( /\./ );
+ if (table_path.length > 1 || rel.path.indexOf('-') > -1) table_path.push( rel.idlclass );
+
+ var prev_type = '';
+ var prev_link = '';
+ var current_path = '';
+ var current_obj = template.from;
+ var link;
+ while (link = table_path.shift()) {
+ if (current_path) current_path += '-';
+ current_path += link;
+
+ var leaf = table_path.length == 0 ? true : false;
+
+ current_obj.path = current_path;
+ current_obj.table = getIDLClass( link.split(/-/)[0] ).getAttributeNS( persistNS, 'tablename' );
+
+ if (prev_link != '') {
+ var prev_class = getIDLClass( prev_link.split(/-/)[0] );
+ var prev_field = prev_link.split(/-/)[1];
+
+ var current_link = getIDLLink( prev_class, prev_field );
+ current_obj.key = current_link.getAttribute('key');
+
+ if (
+ current_link.getAttribute('reltype') != 'has_a' ||
+ prev_type == 'left' ||
+ rel.reltype != 'has_a'
+ ) current_obj.type = 'left';
+
+ prev_type = current_obj.type;
+ }
+
+ if (leaf) {
+ current_obj.label = rel.label;
+ current_obj.alias = rel.alias;
+ current_obj.idlclass = rel.idlclass;
+ current_obj.template_path = rel.path;
+ } else {
+ var current_class = getIDLClass( link.split(/-/)[0] );
+ var join_field = link.split(/-/)[1];
+ var join_link = getIDLLink(current_class, join_field);
+
+ if (join_link.getAttribute('reltype') != 'has_a') {
+ var fields_el = current_class.getElementsByTagName('fields')[0];
+ join_field = fields_el.getAttributeNS(persistNS, 'primary') + '-' + join_link.getAttribute('key');
+ }
+
+ current_obj.alias = hex_md5( current_path ) ;
+ join_field += '-' + current_obj.alias;
+ if (table_path.length == 1) join_field += '-' + rel.alias;
+
+ if (!current_obj.join) current_obj.join = {};
+ if (!current_obj.join[join_field]) current_obj.join[join_field] = {};
+
+ if (current_obj.type == 'left') current_obj.join[join_field].type = 'left';
+
+ current_obj = current_obj.join[join_field];
+ }
+
+ prev_link = link;
+ }
+
+
+}
+
+function fleshTemplateField ( template, rel, tab_name, field ) {
+
+ if (!rel.fields[tab_name] || !rel.fields[tab_name][field]) return;
+
+ var tab = rel.fields[tab_name];
+
+ var table_path = rel.path.split( /\./ );
+ if (table_path.length > 1 || rel.path.indexOf('-') > -1)
+ table_path.push( rel.idlclass );
+
+ table_path.push( field );
+
+ var field_path = table_path.join('-');
+
+ var element = {
+ alias : tab[field].alias,
+ column :
+ { colname : field,
+ transform : tab[field].transform,
+ transform_label : tab[field].transform_label
+ },
+ path : field_path,
+ relation : rel.alias
+ };
+
+ if (tab_name.match(/filter/)) {
+ element.condition = {};
+ element.condition[tab[field].op] =
+ tab[field].op_value.value ?
+ tab[field].op_value.value :
+ '::P' + param_count++;
+ }
+
+ template[tab_use[tab_name]].push(element);
+}
+
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="reporter.css" type="text/css"?>
+<?xml-stylesheet href="/opac/common/js/jscalendar/calendar-brown.css" type="text/css" ?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xhtml="http://www.w3.org/1999/xhtml" onload="loadIDL()">
+
+<script src='/opac/common/js/utils.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/config.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/CGI.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/JSON.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/fmall.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/fmgen.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/Cookies.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/opac_utils.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/OrgTree.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/org_utils.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/RemoteRequest.js' type="application/x-javascript; e4x=1"/>
+<script src='/opac/common/js/md5.js' type="application/x-javascript; e4x=1"/>
+
+<script src="../adminlib.js" type="application/x-javascript; e4x=1"/>
+
+<script src="utilities.js" type="application/x-javascript; e4x=1"/>
+<script src="xulbuilder.js" type="application/x-javascript; e4x=1"/>
+<script src="source-setup.js" type="application/x-javascript; e4x=1"/>
+<script src="source-browse.js" type="application/x-javascript; e4x=1"/>
+<script src="template-config.js" type="application/x-javascript; e4x=1"/>
+<script src="transforms.js" type="application/x-javascript; e4x=1"/>
+<script src="operators.js" type="application/x-javascript; e4x=1"/>
+
+<script type="application/x-javascript; e4x=1" src="/opac/common/js/jscalendar/calendar.js"/>
+<script type="application/x-javascript; e4x=1" src="/opac/common/js/jscalendar/lang/calendar-en.js"/>
+<script type="application/x-javascript; e4x=1" src="/opac/common/js/jscalendar/calendar-setup.js"/>
+
+<groupbox flex="1">
+ <caption label="Database Source Browser"/>
+ <hbox flex="1">
+ <hbox flex="1">
+ <vbox flex="1">
+ <menulist label="Sources" popup="source-menu"/>
+ <tree
+ id="idl-browse-tree"
+ flex="2"
+ onclick="sourceTreeHandler(event)"
+ ondblclick="sourceTreeHandlerDblClick(event)"
+ >
+ <treecols>
+ <treecol primary="true" label="Source Name" flex="1"/>
+ </treecols>
+ <treechildren id="sources-treetop" alternatingbackground="true" />
+ </tree>
+ </vbox>
+ </hbox>
+
+ <splitter id="rtp-browse-splitter" collapse="before" persist="state hidden"><grippy/></splitter>
+
+ <hbox flex="2">
+ <vbox flex="1">
+ <hbox>
+ <label control="path-label" value="Source Specifier:"/>
+ <textbox id="path-label" flex="1"/>
+ </hbox>
+ <hbox flex="1">
+ <hbox flex="3">
+ <vbox flex="1">
+ <tree
+ id="class-view"
+ flex="3"
+ onclick="detailTreeHandler()"
+ ondblclick="addReportAtoms()"
+ enableColumnDrag="true"
+ >
+ <treecols>
+ <treecol label="Field Name" flex="1"/>
+ <treecol label="Data Type" flex="0"/>
+ </treecols>
+ <treechildren id="class-treetop" alternatingbackground="true" />
+ </tree>
+ </vbox>
+ </hbox>
+
+ <splitter><grippy/></splitter>
+
+ <hbox flex="2">
+ <vbox flex="1">
+ <tree
+ id="trans-view"
+ flex="1"
+ seltype="single"
+ onclick="transformSelectHandler()"
+ ondblclick="addReportAtoms()"
+ enableColumnDrag="true"
+ >
+ <treecols>
+ <treecol label="Field Transform" flex="1"/>
+ <treecol label="Params" flex="0" hidden="true"/>
+ <treecol label="Applicable Datatypes" flex="1" hidden="true"/>
+ <treecol label="Output Type" flex="1" />
+ </treecols>
+ <treechildren id="trans-treetop" alternatingbackground="true" />
+ </tree>
+ </vbox>
+ </hbox>
+ </hbox>
+ <hbox>
+ <spacer flex="1"/>
+ <button label="Add Selected Fields" id="source-add" oncommand="addReportAtoms()"/>
+ </hbox>
+ </vbox>
+ </hbox>
+ </hbox>
+</groupbox>
+
+<splitter style="margin:3px" id="rtp-browse-build-splitter" collapse="before" persist="state hidden"><grippy/></splitter>
+
+
+<groupbox flex="1" orient="horizontal">
+ <caption label="Template Configuration"/>
+
+ <hbox flex="1">
+ <vbox flex="1">
+ <hbox>
+ <vbox>
+ <label control="template-name" value="Name:" style="height:2em"/>
+ <label control="template-description" value="Description:"/>
+ </vbox>
+ <vbox flex="1">
+ <textbox id="template-name" flex="1"/>
+ <textbox id="template-description" multiline="true" flex="1" style="max-height:3em"/>
+ </vbox>
+ <vbox pack="end">
+ <button onclick="save_template();" label="Save"/>
+ </vbox>
+ </hbox>
+
+ <hbox flex="1">
+ <tabbox flex="2" id="used-source-fields-tabbox">
+ <tabs>
+ <tab
+ id="dis_tab"
+ label="Displayed Fields"
+ onclick="transformSelectHandler(true);"
+ />
+ <tab
+ id="filter_tab"
+ label="Base Filters"
+ onclick="transformSelectHandler(true);"
+ />
+ <tab
+ id="aggfilter_tab"
+ label="Aggregate Filters"
+ disabled="true"
+ onclick="transformSelectHandler(true);"
+ />
+ <!--
+ <tab
+ id="order_tab"
+ label="Field Order"
+ onclick="transformSelectHandler(true);"
+ />
+ -->
+ </tabs>
+
+ <tabpanels flex="1">
+ <tabpanel id="dis_tabpanel" orient="vertical">
+ <vbox flex="1">
+ <hbox flex="1">
+ <tree
+ id="dis-col-view"
+ flex="1"
+ seltype="single"
+ ondblclick="alterColumnLabel()"
+ onselect="populateTransformContext()"
+ enableColumnDrag="true"
+ >
+ <treecols>
+ <treecol label="Display Name" flex="3"/>
+ <treecol label="Field Name" hidden="true" flex="1"/>
+ <treecol label="Data Type" flex="1"/>
+ <treecol label="Field Transform" flex="1"/>
+ <treecol label="Field Transform Type" hidden="true" flex="1"/>
+ </treecols>
+ <treechildren id="dis-col-treetop" alternatingbackground="true" />
+ </tree>
+ </hbox>
+ <hbox pack="center">
+ <button label="Alter Display Header" oncommand="alterColumnLabel()"/>
+ <button type="menu" label="Change Transform">
+ <menupopup id='dis_tab_trans_menu'/>
+ </button>
+ <spacer flex="1"/>
+ <button label="Move Up" oncommand="changeDisplayOrder('u')"/>
+ <button label="Move Down" oncommand="changeDisplayOrder('d')"/>
+ <spacer flex="1"/>
+ <button label="Remove Selected Field" oncommand="removeReportAtom()"/>
+ </hbox>
+ </vbox>
+ </tabpanel>
+
+ <tabpanel id="filter_tabpanel" orient="vertical">
+ <vbox flex="1">
+ <hbox flex="1">
+ <tree
+ id="filter-col-view"
+ flex="1"
+ seltype="single"
+ onselect="populateTransformContext();populateOperatorContext();changeTemplateFilterValue();"
+ enableColumnDrag="true"
+ >
+ <treecols>
+ <treecol label="Filter Field" flex="2"/>
+ <treecol label="Field Name" hidden="true" flex="1"/>
+ <treecol label="Data Type" hidden="true" flex="1"/>
+ <treecol label="Field Transform" flex="1"/>
+ <treecol label="Field Transform Type" hidden="true" flex="1"/>
+ <treecol label="Operator" flex="1"/>
+ <treecol label="Value" flex="1"/>
+ </treecols>
+ <treechildren id="filter-col-treetop" alternatingbackground="true" />
+ </tree>
+ </hbox>
+ <hbox pack="center">
+ <button type="menu" label="Change Transform">
+ <menupopup id='filter_tab_trans_menu'/>
+ </button>
+ <button type="menu" label="Change Operator">
+ <menupopup id='filter_tab_op_menu'/>
+ </button>
+ <button label="Change value" command="filter_tab_value_action"/>
+ <button label="Remove value" oncommand="removeTemplateFilterValue()"/>
+ <spacer flex="1"/>
+ <button label="Remove Selected Fields" oncommand="removeReportAtom()"/>
+ </hbox>
+ </vbox>
+ </tabpanel>
+
+ <tabpanel id="aggfilter_tabpanel" orient="vertical">
+ <vbox flex="1">
+ <hbox flex="1">
+ <tree
+ id="aggfilter-col-view"
+ flex="1"
+ seltype="single"
+ onselect="populateTransformContext();populateOperatorContext();changeTemplateFilterValue();"
+ enableColumnDrag="true"
+ >
+ <treecols>
+ <treecol label="Filter Field" flex="2"/>
+ <treecol label="Field Name" hidden="true" flex="1"/>
+ <treecol label="Data Type" hidden="true" flex="1"/>
+ <treecol label="Field Transform" flex="1"/>
+ <treecol label="Field Transform Type" hidden="true" flex="1"/>
+ <treecol label="Operator" flex="1"/>
+ <treecol label="Value" flex="1"/>
+ </treecols>
+ <treechildren id="aggfilter-col-treetop" alternatingbackground="true" />
+ </tree>
+ </hbox>
+ <hbox pack="center">
+ <button type="menu" label="Change Transform">
+ <menupopup id='aggfilter_tab_trans_menu'/>
+ </button>
+ <button type="menu" label="Change Operator">
+ <menupopup id='aggfilter_tab_op_menu'/>
+ </button>
+ <button label="Change value" command="aggfilter_tab_value_action"/>
+ <button label="Remove value" oncommand="removeTemplateFilterValue()"/>
+ <spacer flex="1"/>
+ <button label="Remove Selected Fields" oncommand="removeReportAtom()"/>
+ </hbox>
+ </vbox>
+ </tabpanel>
+ </tabpanels>
+ </tabbox>
+ </hbox>
+ </vbox>
+ </hbox>
+
+ <splitter id="rtp-build-splitter" collapse="after" persist="state hidden"><grippy/></splitter>
+
+ <hbox flex="3">
+ <tree
+ id="used-sources"
+ flex="1"
+ onclick="renderSources(true)"
+ ondblclick="changeTemplateFilterValue()"
+ enableColumnDrag="true"
+ >
+ <treecols>
+ <treecol label="Source Specifier" flex="2"/>
+ <treecol label="Table Name" flex="1" hidden="true"/>
+ <treecol label="SQL Alias" flex="1" hidden="true"/>
+ <treecol label="Relationship" flex="1" hidden="true"/>
+ </treecols>
+ <treechildren id="used-sources-treetop" alternatingbackground="true" />
+ </tree>
+ </hbox>
+
+</groupbox>
+
+<commandset>
+ <command id='filter_tab_value_action'/>
+ <command id='aggfilter_tab_value_action'/>
+</commandset>
+
+<popupset>
+ <popup id="source-menu" position="after_start"/>
+ <popup
+ id="calendar-widget"
+ position="before_start"
+ />
+</popupset>
+
+</window>
+
--- /dev/null
+var OILS_RPT_DTYPE_STRING = 'text';
+var OILS_RPT_DTYPE_MONEY = 'money';
+var OILS_RPT_DTYPE_BOOL = 'bool';
+var OILS_RPT_DTYPE_INT = 'int';
+var OILS_RPT_DTYPE_ID = 'id';
+var OILS_RPT_DTYPE_FLOAT = 'float';
+var OILS_RPT_DTYPE_TIMESTAMP = 'timestamp';
+
+var OILS_RPT_DTYPE_ALL = [OILS_RPT_DTYPE_STRING,OILS_RPT_DTYPE_MONEY,OILS_RPT_DTYPE_INT,OILS_RPT_DTYPE_ID,OILS_RPT_DTYPE_FLOAT,OILS_RPT_DTYPE_TIMESTAMP,OILS_RPT_DTYPE_BOOL];
+var OILS_RPT_DTYPE_NOT_ID = [OILS_RPT_DTYPE_STRING,OILS_RPT_DTYPE_MONEY,OILS_RPT_DTYPE_INT,OILS_RPT_DTYPE_FLOAT,OILS_RPT_DTYPE_TIMESTAMP];
+var OILS_RPT_DTYPE_NOT_BOOL = [OILS_RPT_DTYPE_STRING,OILS_RPT_DTYPE_MONEY,OILS_RPT_DTYPE_INT,OILS_RPT_DTYPE_FLOAT,OILS_RPT_DTYPE_TIMESTAMP,OILS_RPT_DTYPE_ID];
+
+var OILS_RPT_TRANSFORMS = {
+ Bare : {
+ datatype : OILS_RPT_DTYPE_ALL,
+ label : 'Raw Data'
+ },
+
+ first : {
+ datatype : OILS_RPT_DTYPE_NOT_ID,
+ label : 'First Value'
+ },
+
+ last : {
+ datatype : OILS_RPT_DTYPE_NOT_ID,
+ label : 'Last Value'
+ },
+
+ count : {
+ datatype : OILS_RPT_DTYPE_NOT_BOOL,
+ aggregate : true,
+ label : 'Count'
+ },
+
+ count_distinct : {
+ datatype : OILS_RPT_DTYPE_NOT_BOOL,
+ aggregate : true,
+ label : 'Count Distinct'
+ },
+
+ min : {
+ datatype : OILS_RPT_DTYPE_NOT_ID,
+ aggregate : true,
+ label : 'Min'
+ },
+
+ max : {
+ datatype : OILS_RPT_DTYPE_NOT_ID,
+ aggregate : true,
+ label : 'Max'
+ },
+
+ /* string transforms ------------------------- */
+
+ substring : {
+ datatype : [ OILS_RPT_DTYPE_STRING ],
+ params : 2,
+ label : 'Substring'
+ },
+
+ lower : {
+ datatype : [ OILS_RPT_DTYPE_STRING ],
+ label : 'Lower case'
+ },
+
+ upper : {
+ datatype : [ OILS_RPT_DTYPE_STRING ],
+ label : 'Upper case'
+ },
+
+ /* timestamp transforms ----------------------- */
+ dow : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Day of Week',
+ cal_format : '%w',
+ regex : /^[0-6]$/
+ },
+ dom : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Day of Month',
+ cal_format : '%e',
+ regex : /^[0-9]{1,2}$/
+ },
+
+ doy : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Day of Year',
+ cal_format : '%j',
+ regex : /^[0-9]{1,3}$/
+ },
+
+ woy : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Week of Year',
+ cal_format : '%U',
+ regex : /^[0-9]{1,2}$/
+ },
+
+ moy : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Month of Year',
+ cal_format : '%m',
+ regex : /^\d{1,2}$/
+ },
+
+ qoy : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Quarter of Year',
+ regex : /^[1234]$/
+ },
+
+ hod : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Hour of day',
+ cal_format : '%H',
+ regex : /^\d{1,2}$/
+ },
+
+ date : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Date',
+ regex : /^\d{4}-\d{2}-\d{2}$/,
+ hint : 'YYYY-MM-DD',
+ cal_format : '%Y-%m-%d',
+ input_size : 10
+ },
+
+ month_trunc : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Year + Month',
+ regex : /^\d{4}-\d{2}$/,
+ hint : 'YYYY-MM',
+ cal_format : '%Y-%m',
+ input_size : 7
+ },
+
+ year_trunc : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Year',
+ regex : /^\d{4}$/,
+ hint : 'YYYY',
+ cal_format : '%Y',
+ input_size : 4
+ },
+
+ hour_trunc : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Hour',
+ regex : /^\d{2}$/,
+ hint : 'HH',
+ cal_format : '%Y-%m-$d %H',
+ input_size : 2
+ },
+
+ day_name : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ cal_format : '%A',
+ label : 'Day Name'
+ },
+
+ month_name : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ cal_format : '%B',
+ label : 'Month Name'
+ },
+ age : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Age'
+ },
+
+ months_ago : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Months ago'
+ },
+
+ quarters_ago : {
+ datatype : [ OILS_RPT_DTYPE_TIMESTAMP ],
+ label : 'Quarters ago'
+ },
+
+ /* int / float transforms ----------------------------------- */
+ sum : {
+ datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT, OILS_RPT_DTYPE_MONEY ],
+ label : 'Sum',
+ aggregate : true
+ },
+
+ average : {
+ datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT, OILS_RPT_DTYPE_MONEY ],
+ label : 'Average',
+ aggregate : true
+ },
+
+ round : {
+ datatype : [ OILS_RPT_DTYPE_INT, OILS_RPT_DTYPE_FLOAT ],
+ label : 'Round',
+ },
+
+ 'int' : {
+ datatype : [ OILS_RPT_DTYPE_FLOAT ],
+ label : 'Drop trailing decimals'
+ }
+}
+
+function getTransforms(args) {
+ var dtype = args.datatype;
+ var agg = args.aggregate;
+ var tforms = OILS_RPT_TRANSFORMS;
+ var nonagg = args.non_aggregate;
+
+ var keys = getKeys(OILS_RPT_TRANSFORMS)
+ var tforms = [];
+
+ for( var i = 0; i < keys.length; i++ ) {
+ var key = keys[i];
+ var obj = OILS_RPT_TRANSFORMS[key];
+ if( agg && !nonagg && !obj.aggregate ) continue;
+ if( !agg && nonagg && obj.aggregate ) continue;
+ if( !dtype && obj.datatype.length > 0 ) continue;
+ if( dtype && obj.datatype.length > 0 && transformIsForDatatype(key,dtype).length == 0 ) continue;
+ tforms.push(key);
+ }
+
+ return tforms;
+}
+
+
+function transformIsForDatatype(tform, dtype) {
+ var obj = OILS_RPT_TRANSFORMS[tform];
+ return grep(function(d) { return (d == dtype) }, obj.datatype);
+}
+
+
--- /dev/null
+function $ () {
+ var elements = new Array();
+
+ for (var i = 0; i < arguments.length; i++) {
+ var element = arguments[i];
+
+ if (typeof element == 'string')
+ element = document.getElementById(element) || undefined;
+
+ if (arguments.length == 1)
+ return element;
+
+ elements.push( element );
+ }
+
+ return elements;
+}
+
+function _l(l) { location.href = l + location.search; }
+
+function map (func, list) {
+ var ret = [];
+ for (var i = 0; i < list.length; i++) ret.push(func(list[i]));
+ return ret;
+}
+
+function grep (func, list) {
+ var ret = [];
+ for (var i = 0; i < list.length; i++) if(func(list[i])) ret.push(list[i]);
+ return ret;
+}
+
+function getSelectedItems(tree) {
+ var start = new Object();
+ var end = new Object();
+ var numRanges = tree.view.selection.getRangeCount();
+
+ var itemList = [];
+ for (var t=0; t<numRanges; t++){
+ tree.view.selection.getRangeAt(t,start,end);
+ for (var v=start.value; v<=end.value; v++){
+ itemList.push( tree.getElementsByTagName('treeitem')[v]);
+ }
+ }
+
+ return itemList;
+}
+
+function findAnscestor (node, name) {
+ if (node.nodeName == name) return node;
+ if (!node.parentNode) return null;
+ return findAnscestor(node.parentNode, name);
+}
+
+function findAnscestorStack (node, name, stack) {
+ if (node.nodeName == name) stack.push(node);
+ if (!node.parentNode) return null;
+ findAnscestorStack(node.parentNode, name, stack);
+}
+
+function filterByAttribute(nodes,attrN,attrV) {
+ var aResponse = [];
+ for ( var i = 0; i < nodes.length; i++ ) {
+ if ( nodes[i].getAttribute(attrN) == attrV ) aResponse.push(nodes[i]);
+ }
+ return aResponse;
+}
+
+function filterByAttributeNS(nodes,ns,attrN,attrV) {
+ var aResponse = [];
+ for ( var i = 0; i < nodes.length; i++ ) {
+ if ( nodes[i].getAttributeNS(ns,attrN) == attrV ) aResponse.push(nodes[i]);
+ }
+ return aResponse;
+}
+
+function getKeys (hash) {
+ var k = [];
+ for (var i in hash) k.push(i);
+ return k;
+}
+
+
--- /dev/null
+function createComplexHTMLElement (e, attrs, objects, text) {
+ var l = document.createElementNS('http://www.w3.org/1999/xhtml',e);
+
+ if (attrs) {
+ for (var i in attrs) l.setAttribute(i,attrs[i]);
+ }
+
+ if (objects) {
+ for ( var i in objects ) l.appendChild( objects[i] );
+ }
+
+ if (text) {
+ l.appendChild( document.createTextNode(text) )
+ }
+
+ return l;
+}
+
+function createComplexXULElement (e, attrs, objects) {
+ var l = document.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul',e);
+
+ if (attrs) {
+ for (var i in attrs) {
+ if (typeof attrs[i] == 'function') {
+ l.addEventListener( i, attrs[i], true );
+ } else {
+ l.setAttribute(i,attrs[i]);
+ }
+ }
+ }
+
+ if (objects) {
+ for ( var i in objects ) l.appendChild( objects[i] );
+ }
+
+ return l;
+}
+
+function createDescription (attrs) {
+ return createComplexXULElement('description', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createTooltip (attrs) {
+ return createComplexXULElement('tooltip', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createLabel (attrs) {
+ return createComplexXULElement('label', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createVbox (attrs) {
+ return createComplexXULElement('vbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createHbox (attrs) {
+ return createComplexXULElement('hbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createRow (attrs) {
+ return createComplexXULElement('row', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createTextbox (attrs) {
+ return createComplexXULElement('textbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createCheckbox (attrs) {
+ return createComplexXULElement('checkbox', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createTreeChildren (attrs) {
+ return createComplexXULElement('treechildren', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createTreeItem (attrs) {
+ return createComplexXULElement('treeitem', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createTreeRow (attrs) {
+ return createComplexXULElement('treerow', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createTreeCell (attrs) {
+ return createComplexXULElement('treecell', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createPopup (attrs) {
+ return createComplexXULElement('popup', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createMenuPopup (attrs) {
+ return createComplexXULElement('menupopup', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createMenu (attrs) {
+ return createComplexXULElement('menu', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createMenuItem (attrs) {
+ return createComplexXULElement('menuitem', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+function createMenuSeparator (attrs) {
+ return createComplexXULElement('menuseparator', attrs, Array.prototype.slice.apply(arguments, [1]) );
+}
+
+