| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710 |
- /*
- Copyright (c) 2010, Yahoo! Inc. All rights reserved.
- Code licensed under the BSD License:
- http://developer.yahoo.com/yui/license.html
- version: 3.4.0
- build: nightly
- */
- YUI.add('datatable-base', function(Y) {
-
- var YLang = Y.Lang,
- YisValue = YLang.isValue,
- fromTemplate = Y.Lang.sub,
- YNode = Y.Node,
- Ycreate = YNode.create,
- YgetClassName = Y.ClassNameManager.getClassName,
-
- DATATABLE = "datatable",
- COLUMN = "column",
-
- FOCUS = "focus",
- KEYDOWN = "keydown",
- MOUSEENTER = "mouseenter",
- MOUSELEAVE = "mouseleave",
- MOUSEUP = "mouseup",
- MOUSEDOWN = "mousedown",
- CLICK = "click",
- DBLCLICK = "dblclick",
-
- CLASS_COLUMNS = YgetClassName(DATATABLE, "columns"),
- CLASS_DATA = YgetClassName(DATATABLE, "data"),
- CLASS_MSG = YgetClassName(DATATABLE, "msg"),
- CLASS_LINER = YgetClassName(DATATABLE, "liner"),
- CLASS_FIRST = YgetClassName(DATATABLE, "first"),
- CLASS_LAST = YgetClassName(DATATABLE, "last"),
- CLASS_EVEN = YgetClassName(DATATABLE, "even"),
- CLASS_ODD = YgetClassName(DATATABLE, "odd"),
-
- TEMPLATE_TABLE = '<table></table>',
- TEMPLATE_COL = '<col></col>',
- TEMPLATE_THEAD = '<thead class="'+CLASS_COLUMNS+'"></thead>',
- TEMPLATE_TBODY = '<tbody class="'+CLASS_DATA+'"></tbody>',
- TEMPLATE_TH = '<th id="{id}" rowspan="{rowspan}" colspan="{colspan}" class="{classnames}" abbr="{abbr}"><div class="'+CLASS_LINER+'">{value}</div></th>',
- TEMPLATE_TR = '<tr id="{id}"></tr>',
- TEMPLATE_TD = '<td headers="{headers}" class="{classnames}"><div class="'+CLASS_LINER+'">{value}</div></td>',
- TEMPLATE_VALUE = '{value}',
- TEMPLATE_MSG = '<tbody class="'+CLASS_MSG+'"></tbody>';
-
-
-
- /**
- * The Column class defines and manages attributes of Columns for DataTable.
- *
- * @class Column
- * @extends Widget
- * @constructor
- */
- function Column(config) {
- Column.superclass.constructor.apply(this, arguments);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // STATIC PROPERTIES
- //
- /////////////////////////////////////////////////////////////////////////////
- Y.mix(Column, {
- /**
- * Class name.
- *
- * @property NAME
- * @type {String}
- * @static
- * @final
- * @value "column"
- */
- NAME: "column",
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // ATTRIBUTES
- //
- /////////////////////////////////////////////////////////////////////////////
- ATTRS: {
- /**
- Unique internal identifier, used to stamp ID on TH element.
-
- @attribute id
- @type {String}
- @readOnly
- **/
- id: {
- valueFn: "_defaultId",
- readOnly: true
- },
-
- /**
- User-supplied identifier. Defaults to id.
- @attribute key
- @type {String}
- **/
- key: {
- valueFn: "_defaultKey"
- },
-
- /**
- Points to underlying data field (for sorting or formatting, for
- example). Useful when column doesn't hold any data itself, but is just
- a visual representation of data from another column or record field.
- Defaults to key.
-
- @attribute field
- @type {String}
- @default (column key)
- **/
- field: {
- valueFn: "_defaultField"
- },
-
- /**
- Display label for column header. Defaults to key.
-
- @attribute label
- @type {String}
- **/
- label: {
- valueFn: "_defaultLabel"
- },
-
- /**
- Array of child column definitions (for nested headers).
-
- @attribute children
- @type {String}
- @default null
- **/
- children: {
- value: null
- },
-
- /**
- TH abbr attribute.
-
- @attribute abbr
- @type {String}
- @default ""
- **/
- abbr: {
- value: ""
- },
-
- //TODO: support custom classnames
- // TH CSS classnames
- classnames: {
- readOnly: true,
- getter: "_getClassnames"
- },
-
- /**
- Formating template string or function for cells in this column.
-
- Function formatters receive a single object (described below) and are
- expected to output the `innerHTML` of the cell.
-
- String templates can include markup and {placeholder} tokens to be
- filled in from the object passed to function formatters.
-
- @attribute formatter
- @type {String|Function}
- @param {Object} data Data relevant to the rendering of this cell
- @param {String} data.classnames CSS classes to add to the cell
- @param {Column} data.column This Column instance
- @param {Object} data.data The raw object data from the Record
- @param {String} data.field This Column's "field" attribute value
- @param {String} data.headers TH ids to reference in the cell's
- "headers" attribute
- @param {Record} data.record The Record instance for this row
- @param {Number} data.rowindex The index for this row
- @param {Node} data.tbody The TBODY Node that will house the cell
- @param {Node} data.tr The row TR Node that will house the cell
- @param {Any} data.value The raw Record data for this cell
- **/
- formatter: {},
-
- /**
- The default markup to display in cells that have no corresponding record
- data or content from formatters.
-
- @attribute emptyCellValue
- @type {String}
- @default ''
- **/
- emptyCellValue: {
- value: '',
- validator: Y.Lang.isString
- },
-
- //requires datatable-sort
- sortable: {
- value: false
- },
- //sortOptions:defaultDir, sortFn, field
-
- //TODO: support editable columns
- // Column editor
- editor: {},
-
- //TODO: support resizeable columns
- //TODO: support setting widths
- // requires datatable-colresize
- width: {},
- resizeable: {},
- minimized: {},
- minWidth: {},
- maxAutoWidth: {}
- }
- });
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // PROTOTYPE
- //
- /////////////////////////////////////////////////////////////////////////////
- Y.extend(Column, Y.Widget, {
- /////////////////////////////////////////////////////////////////////////////
- //
- // ATTRIBUTE HELPERS
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * Return ID for instance.
- *
- * @method _defaultId
- * @return {String}
- * @private
- */
- _defaultId: function() {
- return Y.guid();
- },
-
- /**
- * Return key for instance. Defaults to ID if one was not provided.
- *
- * @method _defaultKey
- * @return {String}
- * @private
- */
- _defaultKey: function(key) {
- return key || Y.guid();
- },
-
- /**
- * Return field for instance. Defaults to key if one was not provided.
- *
- * @method _defaultField
- * @return {String}
- * @private
- */
- _defaultField: function(field) {
- return field || this.get("key");
- },
-
- /**
- * Return label for instance. Defaults to key if one was not provided.
- *
- * @method _defaultLabel
- * @return {String}
- * @private
- */
- _defaultLabel: function(label) {
- return label || this.get("key");
- },
-
- /**
- * Updates the UI if changes are made to abbr.
- *
- * @method _afterAbbrChange
- * @param e {Event} Custom event for the attribute change.
- * @private
- */
- _afterAbbrChange: function (e) {
- this._uiSetAbbr(e.newVal);
- },
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // PROPERTIES
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * Reference to Column's current position index within its Columnset's keys
- * array, if applicable. This property only applies to non-nested and bottom-
- * level child Columns. Value is set by Columnset code.
- *
- * @property keyIndex
- * @type {Number}
- */
- keyIndex: null,
-
- /**
- * Array of TH IDs associated with this column, for TD "headers" attribute.
- * Value is set by Columnset code
- *
- * @property headers
- * @type {String[]}
- */
- headers: null,
-
- /**
- * Number of cells the header spans. Value is set by Columnset code.
- *
- * @property colSpan
- * @type {Number}
- * @default 1
- */
- colSpan: 1,
-
- /**
- * Number of rows the header spans. Value is set by Columnset code.
- *
- * @property rowSpan
- * @type {Number}
- * @default 1
- */
- rowSpan: 1,
-
- /**
- * Column's parent Column instance, if applicable. Value is set by Columnset
- * code.
- *
- * @property parent
- * @type {Column}
- */
- parent: null,
-
- /**
- * The Node reference to the associated TH element.
- *
- * @property thNode
- * @type {Node}
- */
-
- thNode: null,
-
- /*TODO
- * The Node reference to the associated liner element.
- *
- * @property thLinerNode
- * @type {Node}
-
- thLinerNode: null,*/
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // METHODS
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * Initializer.
- *
- * @method initializer
- * @param config {Object} Config object.
- * @private
- */
- initializer: function(config) {
- },
-
- /**
- * Destructor.
- *
- * @method destructor
- * @private
- */
- destructor: function() {
- },
-
- /**
- * Returns classnames for Column.
- *
- * @method _getClassnames
- * @private
- */
- _getClassnames: function () {
- return Y.ClassNameManager.getClassName(COLUMN, this.get("key").replace(/[^\w\-]/g,""));
- },
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // SYNC
- //
- ////////////////////////////////////////////////////////////////////////////
- /**
- * Syncs UI to intial state.
- *
- * @method syncUI
- * @private
- */
- syncUI: function() {
- this._uiSetAbbr(this.get("abbr"));
- },
-
- /**
- * Updates abbr.
- *
- * @method _uiSetAbbr
- * @param val {String} New abbr.
- * @protected
- */
- _uiSetAbbr: function(val) {
- this.thNode.set("abbr", val);
- }
- });
-
- Y.Column = Column;
- /**
- * The Columnset class defines and manages a collection of Columns.
- *
- * @class Columnset
- * @extends Base
- * @constructor
- */
- function Columnset(config) {
- Columnset.superclass.constructor.apply(this, arguments);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // STATIC PROPERTIES
- //
- /////////////////////////////////////////////////////////////////////////////
- Y.mix(Columnset, {
- /**
- * Class name.
- *
- * @property NAME
- * @type String
- * @static
- * @final
- * @value "columnset"
- */
- NAME: "columnset",
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // ATTRIBUTES
- //
- /////////////////////////////////////////////////////////////////////////////
- ATTRS: {
- /**
- * @attribute definitions
- * @description Array of column definitions that will populate this Columnset.
- * @type Array
- */
- definitions: {
- setter: "_setDefinitions"
- }
-
- }
- });
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // PROTOTYPE
- //
- /////////////////////////////////////////////////////////////////////////////
- Y.extend(Columnset, Y.Base, {
- /////////////////////////////////////////////////////////////////////////////
- //
- // ATTRIBUTE HELPERS
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * @method _setDefinitions
- * @description Clones definitions before setting.
- * @param definitions {Array} Array of column definitions.
- * @return Array
- * @private
- */
- _setDefinitions: function(definitions) {
- return Y.clone(definitions);
- },
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // PROPERTIES
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * Top-down tree representation of Column hierarchy. Used to create DOM
- * elements.
- *
- * @property tree
- * @type {Column[]}
- */
- tree: null,
-
- /**
- * Hash of all Columns by ID.
- *
- * @property idHash
- * @type Object
- */
- idHash: null,
-
- /**
- * Hash of all Columns by key.
- *
- * @property keyHash
- * @type Object
- */
- keyHash: null,
-
- /**
- * Array of only Columns that are meant to be displayed in DOM.
- *
- * @property keys
- * @type {Column[]}
- */
- keys: null,
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // METHODS
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * Initializer. Generates all internal representations of the collection of
- * Columns.
- *
- * @method initializer
- * @param config {Object} Config object.
- * @private
- */
- initializer: function() {
-
- // DOM tree representation of all Columns
- var tree = [],
- // Hash of all Columns by ID
- idHash = {},
- // Hash of all Columns by key
- keyHash = {},
- // Flat representation of only Columns that are meant to display data
- keys = [],
- // Original definitions
- definitions = this.get("definitions"),
-
- self = this;
-
- // Internal recursive function to define Column instances
- function parseColumns(depth, currentDefinitions, parent) {
- var i=0,
- len = currentDefinitions.length,
- currentDefinition,
- column,
- currentChildren;
-
- // One level down
- depth++;
-
- // Create corresponding dom node if not already there for this depth
- if(!tree[depth]) {
- tree[depth] = [];
- }
-
- // Parse each node at this depth for attributes and any children
- for(; i<len; ++i) {
- currentDefinition = currentDefinitions[i];
-
- currentDefinition = YLang.isString(currentDefinition) ? {key:currentDefinition} : currentDefinition;
-
- // Instantiate a new Column for each node
- column = new Y.Column(currentDefinition);
-
- // Cross-reference Column ID back to the original object literal definition
- currentDefinition.yuiColumnId = column.get("id");
-
- // Add the new Column to the hash
- idHash[column.get("id")] = column;
- keyHash[column.get("key")] = column;
-
- // Assign its parent as an attribute, if applicable
- if(parent) {
- column.parent = parent;
- }
-
- // The Column has descendants
- if(YLang.isArray(currentDefinition.children)) {
- currentChildren = currentDefinition.children;
- column._set("children", currentChildren);
-
- self._setColSpans(column, currentDefinition);
-
- self._cascadePropertiesToChildren(column, currentChildren);
-
- // The children themselves must also be parsed for Column instances
- if(!tree[depth+1]) {
- tree[depth+1] = [];
- }
- parseColumns(depth, currentChildren, column);
- }
- // This Column does not have any children
- else {
- column.keyIndex = keys.length;
- // Default is already 1
- //column.colSpan = 1;
- keys.push(column);
- }
-
- // Add the Column to the top-down dom tree
- tree[depth].push(column);
- }
- depth--;
- }
-
- // Parse out Column instances from the array of object literals
- parseColumns(-1, definitions);
-
-
- // Save to the Columnset instance
- this.tree = tree;
- this.idHash = idHash;
- this.keyHash = keyHash;
- this.keys = keys;
-
- this._setRowSpans();
- this._setHeaders();
- },
-
- /**
- * Destructor.
- *
- * @method destructor
- * @private
- */
- destructor: function() {
- },
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // COLUMN HELPERS
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * Cascade certain properties to children if not defined on their own.
- *
- * @method _cascadePropertiesToChildren
- * @private
- */
- _cascadePropertiesToChildren: function(column, currentChildren) {
- //TODO: this is all a giant todo
- var i = 0,
- len = currentChildren.length,
- child;
-
- // Cascade certain properties to children if not defined on their own
- for(; i<len; ++i) {
- child = currentChildren[i];
- if(column.get("className") && (child.className === undefined)) {
- child.className = column.get("className");
- }
- if(column.get("editor") && (child.editor === undefined)) {
- child.editor = column.get("editor");
- }
- if(column.get("formatter") && (child.formatter === undefined)) {
- child.formatter = column.get("formatter");
- }
- if(column.get("resizeable") && (child.resizeable === undefined)) {
- child.resizeable = column.get("resizeable");
- }
- if(column.get("sortable") && (child.sortable === undefined)) {
- child.sortable = column.get("sortable");
- }
- if(column.get("hidden")) {
- child.hidden = true;
- }
- if(column.get("width") && (child.width === undefined)) {
- child.width = column.get("width");
- }
- if(column.get("minWidth") && (child.minWidth === undefined)) {
- child.minWidth = column.get("minWidth");
- }
- if(column.get("maxAutoWidth") && (child.maxAutoWidth === undefined)) {
- child.maxAutoWidth = column.get("maxAutoWidth");
- }
- }
- },
-
- /**
- * @method _setColSpans
- * @description Calculates and sets colSpan attribute on given Column.
- * @param column {Array} Column instance.
- * @param definition {Object} Column definition.
- * @private
- */
- _setColSpans: function(column, definition) {
- // Determine COLSPAN value for this Column
- var terminalChildNodes = 0;
-
- function countTerminalChildNodes(ancestor) {
- var descendants = ancestor.children,
- i = 0,
- len = descendants.length;
-
- // Drill down each branch and count terminal nodes
- for(; i<len; ++i) {
- // Keep drilling down
- if(YLang.isArray(descendants[i].children)) {
- countTerminalChildNodes(descendants[i]);
- }
- // Reached branch terminus
- else {
- terminalChildNodes++;
- }
- }
- }
- countTerminalChildNodes(definition);
- column.colSpan = terminalChildNodes;
- },
-
- /**
- * @method _setRowSpans
- * @description Calculates and sets rowSpan attribute on all Columns.
- * @private
- */
- _setRowSpans: function() {
- // Determine ROWSPAN value for each Column in the DOM tree
- function parseDomTreeForRowSpan(tree) {
- var maxRowDepth = 1,
- currentRow,
- currentColumn,
- m,p;
-
- // Calculate the max depth of descendants for this row
- function countMaxRowDepth(row, tmpRowDepth) {
- tmpRowDepth = tmpRowDepth || 1;
-
- var i = 0,
- len = row.length,
- col;
-
- for(; i<len; ++i) {
- col = row[i];
- // Column has children, so keep counting
- if(YLang.isArray(col.children)) {
- tmpRowDepth++;
- countMaxRowDepth(col.children, tmpRowDepth);
- tmpRowDepth--;
- }
- // Column has children, so keep counting
- else if(col.get && YLang.isArray(col.get("children"))) {
- tmpRowDepth++;
- countMaxRowDepth(col.get("children"), tmpRowDepth);
- tmpRowDepth--;
- }
- // No children, is it the max depth?
- else {
- if(tmpRowDepth > maxRowDepth) {
- maxRowDepth = tmpRowDepth;
- }
- }
- }
- }
-
- // Count max row depth for each row
- for(m=0; m<tree.length; m++) {
- currentRow = tree[m];
- countMaxRowDepth(currentRow);
-
- // Assign the right ROWSPAN values to each Column in the row
- for(p=0; p<currentRow.length; p++) {
- currentColumn = currentRow[p];
- if(!YLang.isArray(currentColumn.get("children"))) {
- currentColumn.rowSpan = maxRowDepth;
- }
- // Default is already 1
- // else currentColumn.rowSpan =1;
- }
-
- // Reset counter for next row
- maxRowDepth = 1;
- }
- }
- parseDomTreeForRowSpan(this.tree);
- },
-
- /**
- * @method _setHeaders
- * @description Calculates and sets headers attribute on all Columns.
- * @private
- */
- _setHeaders: function() {
- var headers, column,
- allKeys = this.keys,
- i=0, len = allKeys.length;
-
- function recurseAncestorsForHeaders(headers, column) {
- headers.push(column.get("id"));
- if(column.parent) {
- recurseAncestorsForHeaders(headers, column.parent);
- }
- }
- for(; i<len; ++i) {
- headers = [];
- column = allKeys[i];
- recurseAncestorsForHeaders(headers, column);
- column.headers = headers.reverse().join(" ");
- }
- },
-
- //TODO
- getColumn: function() {
- }
- });
-
- Y.Columnset = Columnset;
- /**
- * The DataTable widget provides a progressively enhanced DHTML control for
- * displaying tabular data across A-grade browsers.
- *
- * @module datatable
- * @main datatable
- */
-
- /**
- * Provides the base DataTable implementation, which can be extended to add
- * additional functionality, such as sorting or scrolling.
- *
- * @module datatable
- * @submodule datatable-base
- */
-
- /**
- * Base class for the DataTable widget.
- * @class DataTable.Base
- * @extends Widget
- * @constructor
- */
- function DTBase(config) {
- DTBase.superclass.constructor.apply(this, arguments);
- }
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // STATIC PROPERTIES
- //
- /////////////////////////////////////////////////////////////////////////////
- Y.mix(DTBase, {
-
- /**
- * Class name.
- *
- * @property NAME
- * @type String
- * @static
- * @final
- * @value "dataTable"
- */
- NAME: "dataTable",
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // ATTRIBUTES
- //
- /////////////////////////////////////////////////////////////////////////////
- ATTRS: {
- /**
- * @attribute columnset
- * @description Pointer to Columnset instance.
- * @type Array | Y.Columnset
- */
- columnset: {
- setter: "_setColumnset"
- },
-
- /**
- * @attribute recordset
- * @description Pointer to Recordset instance.
- * @type Array | Y.Recordset
- */
- recordset: {
- valueFn: '_initRecordset',
- setter: "_setRecordset"
- },
-
- /*TODO
- * @attribute state
- * @description Internal state.
- * @readonly
- * @type
- */
- /*state: {
- value: new Y.State(),
- readOnly: true
-
- },*/
-
- /**
- * @attribute summary
- * @description Summary.
- * @type String
- */
- summary: {
- },
-
- /**
- * @attribute caption
- * @description Caption
- * @type String
- */
- caption: {
- },
-
- /**
- * @attribute thValueTemplate
- * @description Tokenized markup template for TH value.
- * @type String
- * @default '{value}'
- */
- thValueTemplate: {
- value: TEMPLATE_VALUE
- },
-
- /**
- * @attribute tdValueTemplate
- * @description Tokenized markup template for TD value.
- * @type String
- * @default '{value}'
- */
- tdValueTemplate: {
- value: TEMPLATE_VALUE
- },
-
- /**
- * @attribute trTemplate
- * @description Tokenized markup template for TR node creation.
- * @type String
- * @default '<tr id="{id}"></tr>'
- */
- trTemplate: {
- value: TEMPLATE_TR
- }
- },
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // TODO: HTML_PARSER
- //
- /////////////////////////////////////////////////////////////////////////////
- HTML_PARSER: {
- /*caption: function (srcNode) {
-
- }*/
- }
- });
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // PROTOTYPE
- //
- /////////////////////////////////////////////////////////////////////////////
- Y.extend(DTBase, Y.Widget, {
- /**
- * @property thTemplate
- * @description Tokenized markup template for TH node creation.
- * @type String
- * @default '<th id="{id}" rowspan="{rowspan}" colspan="{colspan}" class="{classnames}" abbr="{abbr}"><div class="'+CLASS_LINER+'">{value}</div></th>'
- */
- thTemplate: TEMPLATE_TH,
-
- /**
- * @property tdTemplate
- * @description Tokenized markup template for TD node creation.
- * @type String
- * @default '<td headers="{headers}" class="{classnames}"><div class="yui3-datatable-liner">{value}</div></td>'
- */
- tdTemplate: TEMPLATE_TD,
-
- /**
- * @property _theadNode
- * @description Pointer to THEAD node.
- * @type {Node}
- * @private
- */
- _theadNode: null,
-
- /**
- * @property _tbodyNode
- * @description Pointer to TBODY node.
- * @type {Node}
- * @private
- */
- _tbodyNode: null,
-
- /**
- * @property _msgNode
- * @description Pointer to message display node.
- * @type {Node}
- * @private
- */
- _msgNode: null,
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // ATTRIBUTE HELPERS
- //
- /////////////////////////////////////////////////////////////////////////////
- /**
- * @method _setColumnset
- * @description Converts Array to Y.Columnset.
- * @param columns {Array | Y.Columnset}
- * @return {Columnset}
- * @private
- */
- _setColumnset: function(columns) {
- return YLang.isArray(columns) ? new Y.Columnset({definitions:columns}) : columns;
- },
-
- /**
- * Updates the UI if Columnset is changed.
- *
- * @method _afterColumnsetChange
- * @param e {Event} Custom event for the attribute change.
- * @protected
- */
- _afterColumnsetChange: function (e) {
- this._uiSetColumnset(e.newVal);
- },
-
- /**
- * @method _setRecordset
- * @description Converts Array to Y.Recordset.
- * @param records {Array | Recordset}
- * @return {Recordset}
- * @private
- */
- _setRecordset: function(rs) {
- if(YLang.isArray(rs)) {
- rs = new Y.Recordset({records:rs});
- }
-
- rs.addTarget(this);
- return rs;
- },
-
- /**
- * Updates the UI if Recordset is changed.
- *
- * @method _afterRecordsetChange
- * @param e {Event} Custom event for the attribute change.
- * @protected
- */
- _afterRecordsetChange: function (e) {
- this._uiSetRecordset(e.newVal);
- },
-
- /**
- * Updates the UI if Recordset records are changed.
- *
- * @method _afterRecordsChange
- * @param e {Event} Custom event for the attribute change.
- * @protected
- */
- _afterRecordsChange: function (e) {
- this._uiSetRecordset(this.get('recordset'));
- },
-
- /**
- * Updates the UI if summary is changed.
- *
- * @method _afterSummaryChange
- * @param e {Event} Custom event for the attribute change.
- * @protected
- */
- _afterSummaryChange: function (e) {
- this._uiSetSummary(e.newVal);
- },
-
- /**
- * Updates the UI if caption is changed.
- *
- * @method _afterCaptionChange
- * @param e {Event} Custom event for the attribute change.
- * @protected
- */
- _afterCaptionChange: function (e) {
- this._uiSetCaption(e.newVal);
- },
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // METHODS
- //
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Destructor.
- *
- * @method destructor
- * @private
- */
- destructor: function() {
- this.get("recordset").removeTarget(this);
- },
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // RENDER
- //
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Renders UI.
- *
- * @method renderUI
- * @private
- */
- renderUI: function() {
- // TABLE
- this._addTableNode(this.get("contentBox"));
-
- // COLGROUP
- this._addColgroupNode(this._tableNode);
-
- // THEAD
- this._addTheadNode(this._tableNode);
-
- // Primary TBODY
- this._addTbodyNode(this._tableNode);
-
- // Message TBODY
- this._addMessageNode(this._tableNode);
-
- // CAPTION
- this._addCaptionNode(this._tableNode);
- },
-
- /**
- * Creates and attaches TABLE element to given container.
- *
- * @method _addTableNode
- * @param containerNode {Node} Parent node.
- * @protected
- * @return {Node}
- */
- _addTableNode: function(containerNode) {
- if (!this._tableNode) {
- this._tableNode = containerNode.appendChild(Ycreate(TEMPLATE_TABLE));
- }
- return this._tableNode;
- },
-
- /**
- * Creates and attaches COLGROUP element to given TABLE.
- *
- * @method _addColgroupNode
- * @param tableNode {Node} Parent node.
- * @protected
- * @return {Node}
- */
- _addColgroupNode: function(tableNode) {
- // Add COLs To DoCUMENT FRAGMENT
- var len = this.get("columnset").keys.length,
- i = 0,
- allCols = ["<colgroup>"];
-
- for(; i<len; ++i) {
- allCols.push(TEMPLATE_COL);
- }
-
- allCols.push("</colgroup>");
-
- // Create COLGROUP
- this._colgroupNode = tableNode.insertBefore(Ycreate(allCols.join("")), tableNode.get("firstChild"));
-
- return this._colgroupNode;
- },
-
- /**
- * Creates and attaches THEAD element to given container.
- *
- * @method _addTheadNode
- * @param tableNode {Node} Parent node.
- * @protected
- * @return {Node}
- */
- _addTheadNode: function(tableNode) {
- if(tableNode) {
- this._theadNode = tableNode.insertBefore(Ycreate(TEMPLATE_THEAD), this._colgroupNode.next());
- return this._theadNode;
- }
- },
-
- /**
- * Creates and attaches TBODY element to given container.
- *
- * @method _addTbodyNode
- * @param tableNode {Node} Parent node.
- * @protected
- * @return {Node}
- */
- _addTbodyNode: function(tableNode) {
- this._tbodyNode = tableNode.appendChild(Ycreate(TEMPLATE_TBODY));
- return this._tbodyNode;
- },
-
- /**
- * Creates and attaches message display element to given container.
- *
- * @method _addMessageNode
- * @param tableNode {Node} Parent node.
- * @protected
- * @return {Node}
- */
- _addMessageNode: function(tableNode) {
- this._msgNode = tableNode.insertBefore(Ycreate(TEMPLATE_MSG), this._tbodyNode);
- return this._msgNode;
- },
-
- /**
- * Creates and attaches CAPTION element to given container.
- *
- * @method _addCaptionNode
- * @param tableNode {Node} Parent node.
- * @protected
- * @return {Node}
- */
- _addCaptionNode: function(tableNode) {
- this._captionNode = Y.Node.create('<caption></caption>');
- },
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // BIND
- //
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Binds events.
- *
- * @method bindUI
- * @private
- */
- bindUI: function() {
- this.after({
- columnsetChange: this._afterColumnsetChange,
- summaryChange : this._afterSummaryChange,
- captionChange : this._afterCaptionChange,
- recordsetChange: this._afterRecordsChange,
- "recordset:tableChange": this._afterRecordsChange
- });
- },
-
- delegate: function(type) {
- //TODO: is this necessary?
- if(type==="dblclick") {
- this.get("boundingBox").delegate.apply(this.get("boundingBox"), arguments);
- }
- else {
- this.get("contentBox").delegate.apply(this.get("contentBox"), arguments);
- }
- },
-
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // SYNC
- //
- ////////////////////////////////////////////////////////////////////////////
-
- /**
- * Syncs UI to intial state.
- *
- * @method syncUI
- * @private
- */
- syncUI: function() {
- // THEAD ROWS
- this._uiSetColumnset(this.get("columnset"));
- // DATA ROWS
- this._uiSetRecordset(this.get("recordset"));
- // SUMMARY
- this._uiSetSummary(this.get("summary"));
- // CAPTION
- this._uiSetCaption(this.get("caption"));
- },
-
- /**
- * Updates summary.
- *
- * @method _uiSetSummary
- * @param val {String} New summary.
- * @protected
- */
- _uiSetSummary: function(val) {
- val = YisValue(val) ? val : "";
- this._tableNode.set("summary", val);
- },
-
- /**
- * Updates caption.
- *
- * @method _uiSetCaption
- * @param val {String} New caption.
- * @protected
- */
- _uiSetCaption: function(val) {
- var caption = this._captionNode,
- inDoc = caption.inDoc(),
- method = val ? (!inDoc && 'prepend') : (inDoc && 'removeChild');
-
- caption.setContent(val || '');
-
- if (method) {
- // prepend of remove necessary
- this._tableNode[method](caption);
- }
- },
-
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // THEAD/COLUMNSET FUNCTIONALITY
- //
- ////////////////////////////////////////////////////////////////////////////
- /**
- * Updates THEAD.
- *
- * @method _uiSetColumnset
- * @param cs {Columnset} New Columnset.
- * @protected
- */
- _uiSetColumnset: function(cs) {
- var tree = cs.tree,
- thead = this._theadNode,
- i = 0,
- len = tree.length,
- parent = thead.get("parentNode"),
- nextSibling = thead.next();
-
- // Move THEAD off DOM
- thead.remove();
-
- thead.get("children").remove(true);
-
- // Iterate tree of columns to add THEAD rows
- for(; i<len; ++i) {
- this._addTheadTrNode({
- thead: thead,
- columns: tree[i],
- id : '' // to avoid {id} leftovers from the trTemplate
- }, (i === 0), (i === len - 1));
- }
-
- // Column helpers needs _theadNode to exist
- //this._createColumnHelpers();
-
-
- // Re-attach THEAD To DoM
- parent.insert(thead, nextSibling);
-
- },
-
- /**
- * Creates and attaches header row element.
- *
- * @method _addTheadTrNode
- * @param o {Object} {thead, columns}.
- * @param isFirst {Boolean} Is first row.
- * @param isFirst {Boolean} Is last row.
- * @protected
- */
- _addTheadTrNode: function(o, isFirst, isLast) {
- o.tr = this._createTheadTrNode(o, isFirst, isLast);
- this._attachTheadTrNode(o);
- },
-
-
- /**
- * Creates header row element.
- *
- * @method _createTheadTrNode
- * @param o {Object} {thead, columns}.
- * @param isFirst {Boolean} Is first row.
- * @param isLast {Boolean} Is last row.
- * @protected
- * @return {Node}
- */
- _createTheadTrNode: function(o, isFirst, isLast) {
- //TODO: custom classnames
- var tr = Ycreate(fromTemplate(this.get("trTemplate"), o)),
- i = 0,
- columns = o.columns,
- len = columns.length,
- column;
-
- // Set FIRST/LAST class
- if(isFirst) {
- tr.addClass(CLASS_FIRST);
- }
- if(isLast) {
- tr.addClass(CLASS_LAST);
- }
-
- for(; i<len; ++i) {
- column = columns[i];
- this._addTheadThNode({value:column.get("label"), column: column, tr:tr});
- }
-
- return tr;
- },
-
- /**
- * Attaches header row element.
- *
- * @method _attachTheadTrNode
- * @param o {Object} {thead, columns, tr}.
- * @protected
- */
- _attachTheadTrNode: function(o) {
- o.thead.appendChild(o.tr);
- },
-
- /**
- * Creates and attaches header cell element.
- *
- * @method _addTheadThNode
- * @param o {Object} {value, column, tr}.
- * @protected
- */
- _addTheadThNode: function(o) {
- o.th = this._createTheadThNode(o);
- this._attachTheadThNode(o);
- //TODO: assign all node pointers: thNode, thLinerNode, thLabelNode
- o.column.thNode = o.th;
- },
-
- /**
- * Creates header cell element.
- *
- * @method _createTheadThNode
- * @param o {Object} {value, column, tr}.
- * @protected
- * @return {Node}
- */
- _createTheadThNode: function(o) {
- var column = o.column;
-
- // Populate template object
- o.id = column.get("id");//TODO: validate 1 column ID per document
- o.colspan = column.colSpan;
- o.rowspan = column.rowSpan;
- o.abbr = column.get("abbr");
- o.classnames = column.get("classnames");
- o.value = fromTemplate(this.get("thValueTemplate"), o);
-
- /*TODO
- // Clear minWidth on hidden Columns
- if(column.get("hidden")) {
- //this._clearMinWidth(column);
- }
- */
-
- return Ycreate(fromTemplate(this.thTemplate, o));
- },
-
- /**
- * Attaches header cell element.
- *
- * @method _attachTheadThNode
- * @param o {Object} {value, column, tr}.
- * @protected
- */
- _attachTheadThNode: function(o) {
- o.tr.appendChild(o.th);
- },
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // TBODY/RECORDSET FUNCTIONALITY
- //
- ////////////////////////////////////////////////////////////////////////////
- /**
- * Updates TBODY.
- *
- * @method _uiSetRecordset
- * @param rs {Recordset} New Recordset.
- * @protected
- */
- _uiSetRecordset: function(rs) {
- var self = this,
- oldTbody = this._tbodyNode,
- parent = oldTbody.get("parentNode"),
- nextSibling = oldTbody.next(),
- columns = this.get('columnset').keys,
- cellValueTemplate = this.get('tdValueTemplate'),
- o = {},
- newTbody, i, len, column, formatter;
-
- // Replace TBODY with a new one
- //TODO: split _addTbodyNode into create/attach
- oldTbody.remove();
- oldTbody = null;
- newTbody = this._addTbodyNode(this._tableNode);
- newTbody.remove();
- this._tbodyNode = newTbody;
- o.tbody = newTbody;
-
- o.rowTemplate = this.get('trTemplate');
- o.columns = [];
-
- // Build up column data to avoid passing through Attribute APIs inside
- // render loops for rows and cells
- for (i = columns.length - 1; i >= 0; --i) {
- column = columns[i];
- o.columns[i] = {
- column : column,
- fields : column.get('field'),
- classnames : column.get('classnames'),
- emptyCellValue: column.get('emptyCellValue')
- }
-
- formatter = column.get('formatter');
-
- if (YLang.isFunction(formatter)) {
- // function formatters need to run before checking if the value
- // needs defaulting from column.emptyCellValue
- formatter = Y.bind(this._functionFormatter, this, formatter);
- } else {
- if (!YLang.isString(formatter)) {
- formatter = cellValueTemplate;
- }
-
- // string formatters need the value defaulted before processing
- formatter = Y.bind(this._templateFormatter, this, formatter);
- }
-
- o.columns[i].formatter = formatter;
- }
-
-
- // Iterate Recordset to use existing TR when possible or add new TR
- // TODO i = this.get("state.offsetIndex")
- // TODO len =this.get("state.pageLength")
- for (i = 0, len = rs.size(); i < len; ++i) {
- o.record = rs.item(i);
- o.data = o.record.get("data");
- o.rowindex = i;
- this._addTbodyTrNode(o); //TODO: sometimes rowindex != recordindex
- }
-
- // TBODY To DoM
- parent.insert(this._tbodyNode, nextSibling);
- },
-
- _functionFormatter: function (formatter, o) {
- var value = formatter.call(this, o);
-
- return (value !== undefined) ? value : o.emptyCellValue;
- },
-
- _templateFormatter: function (template, o) {
- if (o.value === undefined) {
- o.value = o.emptyCellValue;
- }
-
- return fromTemplate(template, o);
- },
-
- /**
- * Creates and attaches data row element.
- *
- * @method _addTbodyTrNode
- * @param o {Object} {tbody, record}
- * @protected
- */
- _addTbodyTrNode: function(o) {
- var row = o.tbody.one("#" + o.record.get("id"));
-
- o.tr = row || this._createTbodyTrNode(o);
-
- this._attachTbodyTrNode(o);
- },
-
- /**
- * Creates data row element.
- *
- * @method _createTbodyTrNode
- * @param o {Object} {tbody, record}
- * @protected
- * @return {Node}
- */
- _createTbodyTrNode: function(o) {
- var columns = o.columns,
- i, len, columnInfo;
-
- o.tr = Ycreate(fromTemplate(o.rowTemplate, { id: o.record.get('id') }));
-
- for (i = 0, len = columns.length; i < len; ++i) {
- columnInfo = columns[i];
- o.column = columnInfo.column;
- o.field = columnInfo.fields;
- o.classnames = columnInfo.classnames;
- o.formatter = columnInfo.formatter;
- o.emptyCellValue= columnInfo.emptyCellValue;
-
- this._addTbodyTdNode(o);
- }
-
- return o.tr;
- },
-
- /**
- * Attaches data row element.
- *
- * @method _attachTbodyTrNode
- * @param o {Object} {tbody, record, tr}.
- * @protected
- */
- _attachTbodyTrNode: function(o) {
- var tbody = o.tbody,
- tr = o.tr,
- index = o.rowindex,
- nextSibling = tbody.get("children").item(index) || null,
- isOdd = (index % 2);
-
- if(isOdd) {
- tr.replaceClass(CLASS_EVEN, CLASS_ODD);
- } else {
- tr.replaceClass(CLASS_ODD, CLASS_EVEN);
- }
-
- tbody.insertBefore(tr, nextSibling);
- },
-
- /**
- * Creates and attaches data cell element.
- *
- * @method _addTbodyTdNode
- * @param o {Object} {record, column, tr}.
- * @protected
- */
- _addTbodyTdNode: function(o) {
- o.td = this._createTbodyTdNode(o);
- this._attachTbodyTdNode(o);
- delete o.td;
- },
-
- /**
- Creates a TD Node from the tdTemplate property using the input object as
- template {placeholder} values. The created Node is also assigned to the
- `td` property on the input object.
-
- If the input object already has a `td` property, it is returned an no new
- Node is created.
-
- @method createCell
- @param {Object} data Template values
- @return {Node}
- **/
- createCell: function (data) {
- return data && (data.td ||
- (data.td = Ycreate(fromTemplate(this.tdTemplate, data))));
- },
-
- /**
- * Creates data cell element.
- *
- * @method _createTbodyTdNode
- * @param o {Object} {record, column, tr}.
- * @protected
- * @return {Node}
- */
- _createTbodyTdNode: function(o) {
- o.headers = o.column.headers;
- o.value = this.formatDataCell(o);
-
- return o.td || this.createCell(o);
- },
-
- /**
- * Attaches data cell element.
- *
- * @method _attachTbodyTdNode
- * @param o {Object} {record, column, tr, headers, classnames, value}.
- * @protected
- */
- _attachTbodyTdNode: function(o) {
- o.tr.appendChild(o.td);
- },
-
- /**
- * Returns markup to insert into data cell element.
- *
- * @method formatDataCell
- * @param @param o {Object} {record, column, tr, headers, classnames}.
- */
- formatDataCell: function (o) {
- o.value = o.data[o.field];
-
- return o.formatter.call(this, o);
- },
-
- _initRecordset: function () {
- return new Y.Recordset({ records: [] });
- }
- });
-
- Y.namespace("DataTable").Base = DTBase;
-
-
- }, '3.4.0' ,{requires:['recordset-base','widget','substitute','event-mouseenter']});
|