"use strict"; var LinkedTreeTable; +function($) { //Pass an element (jquery or html reference), an options object (see DEFAULTS), and an array of node metadata objects (see NODE_DEFAULTS). LinkedTreeTable = function(element, options, nodeMetadata) { var _this = this; this.$element = $(element); this.options = $.extend({}, LinkedTreeTable.DEFAULTS, options); this.nodes = []; this.$selectedRow = null; this.selectionHandler = function(event) { $(this).addClass(_this.options.selectionCSS).siblings().removeClass(_this.options.selectionCSS); _this.$selectedRow = $(this); }; this.addNodeMetadata = function(nodeMetadata) { nodeMetadata = $.extend({}, LinkedTreeTable.NODE_DEFAULTS, nodeMetadata); var nodes = this.nodes[nodeMetadata.type]; nodeMetadata.cls = "NODE"; if(typeof nodes == 'object') { if(nodes.cls == 'NODE') { this.nodes[nodeMetadata.type] = [nodes, nodeMetadata]; } else { nodes.push(nodeMetadata); } } else { this.nodes[nodeMetadata.type] = nodeMetadata } }; //Add the node metadata to the mapping. for(var index = 0; index < nodeMetadata.length; index++) { this.addNodeMetadata(nodeMetadata[index]); } }; LinkedTreeTable.DEFAULTS = { dataAttr: 'data-key-name', //The property name to use to attach the model sent by the server to the table row created for the data. typeAttr: 'data-type-name', //The attribute name used to attach the type to the table row. selectionCSS: 'selected', selection: 'row', //Currently only row is supported. getIdHandler: null //Optional global function that gets the id for an object. No ID will be used if not provided, in which case the row will not be re-opened or re-selected after refreshing the data from the server. }; LinkedTreeTable.NODE_DEFAULTS = { type: '', //The type name this node metadata applies to. Must be provided. The empty type is used to identify the metadata for collecting root nodes. url: '', //The absolute or relative path to use to query the initial data. Server is expected to respond with a JSON array of objects. typeHandler: null, //The optional handler called to determine the type for the model sent by the server. Must return a type name that is then matched to the node metadata to get children. defaultType: null, //The default type to assign to the node if the type handler does not provide one. This normally should be set, particularly if a handler won't always provide a type. postAddRowHandler: null, //Optional function that is passed the jquery table row and the data object sent by the server for that row. Allows post processing of the row prior to display. parameters: null, //Optional function that returns an object, or an object whose attributes are passed to the URL as parameters. getIdHandler: null //Optional function that gets the id for an object. The global version will be used if this one is not provided. }; LinkedTreeTable.prototype.getSelectedRow = function() { return this.$selectedRow; }; //A function that will clean and rebuild the table displaying all the users. //Note that each row of the table will have a data element attached to the table row. The key will be "model" and the value will be the object sent by the server. //Pass an optional table row or data object to reference a node in the tree whose children will be refreshed. If not provided then the root nodes will be refreshed. LinkedTreeTable.prototype.refresh = function(node) { var _this = this; var table = this.$element; var thead = table.find("thead tr"); var tbody = table.find("tbody"); var selection = this.options.selection; var dataAttr = this.options.dataAttr; var selectionHandler = this.selectionHandler; var params; //TODO: Need to identify the top most visible row? //TODO: Otherwise identify the scroll position so we can reset it if necessary? //TODO: Find the ID's of all rows at this tree level or lower that are open so we can re-open them after refreshing? //TODO: Otherwise map the new data by ID to the rows at this tree level so we can update the rows instead of replacing them? if(thead.length == 0) { return; } //Empty or Create the table body. if(tbody.length != 0) { //Remove the row selection handler. if(selection == 'row') this.$element.off('click', 'tbody tr', selectionHandler); //Empty the table of data. tbody.empty(); } else { tbody = $("
"); tbody.appendTo(table); } if(typeof this.options.parameters == 'function') { params = this.options.parameters(); //Must be an object. if(typeof params != 'object') { params = {}; } } else if(typeof this.options.parameters == 'object') { params = this.options.parameters; } else {params = {};} $.getJSON(this.options.url, params, function(data) { var headers = thead.children(); var attributes = []; //Read the table headers to get the data object keys. for(var headerIndex = 0; headerIndex < headers.length; headerIndex++) { var nextHeader = headers[headerIndex]; attributes[headerIndex] = $(nextHeader).attr(dataAttr); } //Add the table data. for(var dataIndex = 0; dataIndex < data.length; dataIndex++) { var rowData = data[dataIndex]; var row = $("