# inputEx-library

### inputEx 0.5.1

inputEx-library > inputEx > DataTable.js (source view)
Search:
Filters Show Private Show Protected Show Deprecated

    (function() {

       var util = YAHOO.util, lang = YAHOO.lang, Dom = util.Dom, Event = util.Event, msgs = inputEx.messages;

    /**
     * Create an editable datatable
     * @class inputEx.widget.DataTable
     * @constructor
     * @param {Object} options Options:
     * <ul>
     *    <li>parentEl: DOMelement in which we have to insert the datatable</li>
     *
     *		<li>datasource (or datasourceConfig)</li>
     *    <li>datatableOpts: additionnal datatable options</li>
     *    <li>fields: inputEx fields</li>
     *    <li>dialogLabel: title of the dialog</li>
     *    <li>columnDefs: YUI datatable columnDefs</li>
     *
     *    <li>id: (optional, default is autogenerated) sets the id of the div wrapper around the widget</li>
     *    <li>allowInsert: adds the 'Insert' button (optional, default true)</li>
     *    <li>allowModify: default true</li>
     *    <li>allowDelete: default true</li>
     *    <li>showHideColumnsDlg: add a link to a dialog to show/hide columns</li>
     * 	<li>panelConfig: (optional) YUI's dialog panelConfig object</li>
     *
     * </ul>
     */
    inputEx.widget.DataTable = function(options) {

       this.setOptions(options);

       this.render();

       this.initEvents();

    };

    inputEx.widget.DataTable.prototype = {

       /**
        * Set the options
        */
       setOptions: function(options) {

          this.options = {};
          this.options.id = options.id || Dom.generateId();
          this.options.parentEl = lang.isString(options.parentEl) ? Dom.get(options.parentEl) : options.parentEl;

    		this.options.columnDefs = options.columnDefs;

          this.options.allowInsert = lang.isUndefined(options.allowInsert) ? true : options.allowInsert;
          this.options.allowModify = lang.isUndefined(options.allowModify) ? true : options.allowModify;
          this.options.allowDelete = lang.isUndefined(options.allowDelete) ? true : options.allowDelete;

          this.options.showHideColumnsDlg = lang.isUndefined(options.showHideColumnsDlg) ? false : options.showHideColumnsDlg;

          this.options.datasource = options.datasource;

    		// Create a datasource if it does not exist, from the datasourceConfig Object
    		if(!options.datasource && options.datasourceConfig) {
    			var ds = new YAHOO.util.DataSource(options.datasourceConfig.url), fields = [];
    			if(options.datasourceConfig.keys) {
    				for ( var i = 0 ; i < options.datasourceConfig.keys.length ; i++ ) {
    	         	fields.push({ key: options.datasourceConfig.keys[i] });
    	      	}
    			}
    	      ds.responseType = options.datasourceConfig.responseType || YAHOO.util.DataSource.TYPE_JSON;
    	      ds.responseSchema = options.datasourceConfig.responseSchema || { resultsList : "Result", fields : fields};
    			this.options.datasource = ds;
    		}

          this.options.datatableOpts = options.datatableOpts;
          this.options.fields = options.fields;

    		this.options.dialogId = options.dialogId || null;
    		this.options.dialogLabel = options.dialogLabel || "";

    		this.options.panelConfig = options.panelConfig || {
    			constraintoviewport: true,
    			underlay:"shadow",
    			close:true,
    			fixedcenter: true,
    			visible:true,
    			draggable:true,
    			modal: true
    		};
       },

       /**
        * Init the events
        */
       initEvents: function() {

          // Call the rendering method when the container is available
          Event.onAvailable(this.options.id, this.renderDatatable, this, true);

          // Table options
          if(this.options.showHideColumnsDlg) {
             Event.addListener(this.tableOptions, 'click', this.showTableOptions, this, true);
          }

          /**
       	 * @event Event fired when an item is removed
       	 * @param {YAHOO.widget.Record} Removed record
       	 * @desc YAHOO custom event fired when an item is removed
       	 */
        	this.itemRemovedEvt = new util.CustomEvent('itemRemoved', this);

          /**
       	 * @event Event fired when an item is added
        	 * @param {YAHOO.widget.Record} Added record
       	 * @desc YAHOO custom event fired when an item is added
       	 */
        	this.itemAddedEvt = new util.CustomEvent('itemAdded', this);

          /**
       	 * @event Event fired when an item is modified
        	 * @param {YAHOO.widget.Record} Modified record
       	 * @desc YAHOO custom event fired when an item is modified
       	 */
        	this.itemModifiedEvt = new util.CustomEvent('itemModified', this);
       },

       /**
        * Render the main container only (not the datatable)
        */
       render: function() {

          /**
           * Main container
           */
          this.element = inputEx.cn('div', {id: this.options.id });

          if(this.options.showHideColumnsDlg) {
             this.renderShowHideColumnsDlg();
          }

          // append it immediatly to the parent DOM element
          this.options.parentEl.appendChild(this.element);

       },

       /**
        * Render the datatable
        */
       renderDatatable: function() {

          var columndefs = this.setColumnDefs();

    		/**
    		 * YUI's datatable instance
    		 */
          this.datatable = new YAHOO.widget.DataTable(this.element, columndefs, this.options.datasource, this.options.datatableOpts);
          this.datatable.subscribe('cellClickEvent', this._onCellClick, this, true);

    		// Automatically set up the paginator
    		if(this.options.datatableOpts && this.options.datatableOpts.paginator) {
    			this.datatable.handleDataReturnPayload = function(oRequest, oResponse, oPayload) {
    				if(oPayload) {
    	        		oPayload.totalRecords = oResponse.meta.totalRecords;
    				}
    	        	return oPayload;
    	    	};
    		}

          // Insert button
          if ( this.options.allowInsert ){
             this.insertButton = inputEx.cn('input', {type:'button', value:msgs.insertItemText}, null, null);
             Event.addListener(this.insertButton, 'click', this.onInsertButton, this, true);
             this.options.parentEl.appendChild(this.insertButton);
          }

          // Set up editing flow
          var highlightEditableCell = function(oArgs) {
              var elCell = oArgs.target;
              if(Dom.hasClass(elCell, "yui-dt-editable") || Dom.hasClass(elCell,"yui-dt-col-delete") || Dom.hasClass(elCell,"yui-dt-col-modify") ) {
                  this.highlightCell(elCell);
              }
          };

    		// Locals
    		this.datatable.set("MSG_LOADING", msgs.loadingText );
    		this.datatable.set("MSG_EMPTY", msgs.emptyDataText );
    		this.datatable.set("MSG_ERROR", msgs.errorDataText );

          this.datatable.subscribe("cellMouseoverEvent", highlightEditableCell);
          this.datatable.subscribe("cellMouseoutEvent", this.datatable.onEventUnhighlightCell);

       },

    	/**
    	 * Set the column definitions, create them if none from the fields, adds the modify and delete buttons
    	 */
    	setColumnDefs: function() {

    		var columndefs = this.options.columnDefs || this.fieldsToColumndefs(this.options.fields);

        	// Adding modify column if we use form editing and if allowModify is true
          if(this.options.allowModify ) {
        	   columndefs = columndefs.concat([{
        	      key:'modify',
        	      label:' ',
        	      formatter:function(elCell) {
                   elCell.innerHTML = msgs.modifyText;
                   elCell.style.cursor = 'pointer';
                }
             }]);
          }

          // Adding delete column
          if(this.options.allowDelete) {
          	 columndefs = columndefs.concat([{
          	    key:'delete',
          	    label:' ',
          	    formatter:function(elCell) {
                   elCell.innerHTML = msgs.deleteText;
                   elCell.style.cursor = 'pointer';
                }
             }]);
          }

    		return columndefs;
    	},

       /**
        * Render the dialog for row edition
        */
       renderDialog: function() {

         var that = this;

         this.dialog = new inputEx.widget.Dialog({
    				id: this.options.dialogId,
    				inputExDef: {
    				         type: 'form',
    			            fields: this.options.fields,
    			            buttons: [
    			               {type: 'submit', value: msgs.saveText, onClick: function() { that.onDialogSave(); return false; /* prevent form submit */} },
    			               {type: 'link', value: msgs.cancelText, onClick: function() { that.onDialogCancel(); } }
    			            ]
    				      },
    				title: this.options.dialogLabel,
    				panelConfig: this.options.panelConfig
    		});

    		// Add a listener on the closing button and hook it to onDialogCancel()
    		YAHOO.util.Event.addListener(that.dialog.close,"click",function(){
    			that.onDialogCancel();
    		},that);

       },

    	/**
        * When saving the Dialog
        */
       onDialogSave: function() {

    		var newvalues, record;

    	  	//Validate the Form
    	  	if ( !this.dialog.getForm().validate() ) return ;

    		// Update the record
    		if(!this.insertNewRecord){

    			// Update the row
    			newvalues = this.dialog.getValue();
    			this.datatable.updateRow( this.selectedRecord , newvalues );

    			// Get the new record
    			record = this.datatable.getRecord(this.selectedRecord);

    			// Fire the modify event
             this.itemModifiedEvt.fire(record);

    		}
    		// Adding new record
    		else{
    			// Insert a new row
    	      this.datatable.addRow({});

    			// Set the Selected Record
    			var rowIndex = this.datatable.getRecordSet().getLength() - 1;
    			this.selectedRecord = rowIndex;

    			// Update the row
    			newvalues = this.dialog.getValue();
    			this.datatable.updateRow( this.selectedRecord , newvalues );

    			// Get the new record
    			record = this.datatable.getRecord(this.selectedRecord);

    			// Fire the add event
             this.itemAddedEvt.fire(record);
    		}

          this.dialog.hide();
       },

    	/**
        * When canceling the Dialog
        */
    	onDialogCancel: function(){
    		this.insertNewRecord = false;
    		this.dialog.hide();
    	},

       /**
        * Handling cell click events
        */
       _onCellClick: function(ev,args) {
          var target = Event.getTarget(ev);
          var column = this.datatable.getColumn(target);
          var rowIndex = this.datatable.getTrIndex(target);
          if (column.key == 'delete') {
             if (confirm(msgs.confirmDeletion)) {
                var record = this.datatable.getRecord(target);
                if(this.editingNewRecord) {
                   this.editingNewRecord = false;
                }
                else {
                   this.itemRemovedEvt.fire( record );
                }
                this.datatable.deleteRow(target);
                this.hideSubform();
             }
          }
          else if(column.key == 'modify') {
             this.onClickModify(rowIndex);
          }
          else {
          	this.onCellClick(ev,rowIndex);
          }
       },

       /**
        * Public cell click handler
        */
       onCellClick: function(ev, rowIndex) {

       },

       /**
        * Opens the Dialog to edit the row
        * Called when the user clicked on modify button
        */
       onClickModify: function(rowIndex) {

          if(!this.dialog) {
             this.renderDialog();
          }

          // NOT Inserting new record
    		this.insertNewRecord = false;

    		// Set the selected Record
    		this.selectedRecord = rowIndex;

    		// Get the selected Record
    		var record = this.datatable.getRecord(this.selectedRecord);

    		this.dialog.whenFormAvailable({
    			fn: function() {
    				this.dialog.setValue(record.getData());
    				this.dialog.show();
    			},
    			scope: this
    		});

    	},

       /**
        * Insert button event handler
        */
       onInsertButton: function(e) {

          if(!this.dialog) {
             this.renderDialog();
          }

    		// Inserting new record
    		this.insertNewRecord = true;

    		this.dialog.whenFormAvailable({
    			fn: function() {
    				this.dialog.getForm().clear();
    				this.dialog.show();
    			},
    			scope: this
    		});

       },

       /**
        * Remove the record that has not been saved
        */
       removeUnsavedRecord: function(record) {
          this.datatable.deleteRow(record);
       },

       /**
        * Cancel row edition
        */
       onCancelForm: function(e) {
          Event.stopEvent(e);
          this.hideSubform();

          if(this.editingNewRecord) {
             this.removeUnsavedRecord();
             this.editingNewRecord = false;
          }
       },

       /**
        * Convert an inputEx fields definition to a DataTable columns definition
        */
       fieldsToColumndefs: function(fields) {
          var columndefs = [];
        	for(var i = 0 ; i < fields.length ; i++) {
        		columndefs.push( this.fieldToColumndef(fields[i]) );
        	}
        	return columndefs;
       },

       /**
        * Convert a single inputEx field definition to a DataTable column definition
        */
       fieldToColumndef: function(field) {

          var key, label, colmunDef;

          // Retro-compatibility with inputParms
          if (lang.isObject(field.inputParams)) {
             key = field.inputParams.name;
             label = field.inputParams.label;

          // New prefered way to set options of a field
          } else {
             key = field.name;
             label = field.label;
          }

          columnDef = {
             key: key,
             label: label,
             sortable: true,
             resizeable: true
          };

          // Field formatter
          if(field.type == "date") {
          	columnDef.formatter = YAHOO.widget.DataTable.formatDate;
          }
    		else if(field.type == "integer" || field.type == "number") {
    			columnDef.formatter = YAHOO.widget.DataTable.formatNumber;
    			/*columnDef.sortOptions = {
    				defaultDir: "asc",
    				sortFunction: // TODO: sort numbers !!!
    			}*/
    		}
          // TODO: other formatters
          return columnDef;
       },

       /**
        * Render the dialog (+link) to show/hide columns
        */
       renderShowHideColumnsDlg: function() {
          this.tableOptions = inputEx.cn('a', {href: '#'}, null, msgs.tableOptions);
          this.options.parentEl.appendChild(this.tableOptions);

          this.tableOptionsDlg = new YAHOO.widget.SimpleDialog( Dom.generateId(), {
                  width: "30em",
    		        visible: false,
    		        modal: true,
    		        buttons: [
    				      { text:msgs.columnDialogCloseButton,  handler: function(e) { this.hide(); } }
                  ],
                  fixedcenter: true,
                  constrainToViewport: true
    	   });

    		Dom.addClass(this.tableOptionsDlg.element.firstChild, "inputex-datatable-columnsDlg");

    	   this.tableOptionsDlg.bodyId = Dom.generateId();
    	   this.tableOptionsDlg.setHeader(msgs.columnDialogTitle);
    	   this.tableOptionsDlg.setBody("<div id='"+this.tableOptionsDlg.bodyId+"'></div>");
    	   this.tableOptionsDlg.render(document.body);
       },

       /**
        * Display the dialog to show/hide fields
        */
       showTableOptions: function(e) {

          Event.stopEvent(e);

          if(!this.noNewCols) {

              var that = this;
              var handleButtonClick = function(e, oSelf) {
                  var sKey = this.get("name");
                  if(this.get("value") === "Hide") {
                      // Hides a Column
                      that.datatable.hideColumn(sKey);
                  }
                  else {
                      // Shows a Column
                      that.datatable.showColumn(sKey);
                  }
              };

               // Populate Dialog
               // Using a template to create elements for the SimpleDialog
               var allColumns = this.datatable.getColumnSet().keys;
               var elPicker = Dom.get(this.tableOptionsDlg.bodyId);

               var elTemplateCol = document.createElement("div");
               Dom.addClass(elTemplateCol, "dt-dlg-pickercol");
               var elTemplateKey = elTemplateCol.appendChild(document.createElement("span"));
               Dom.addClass(elTemplateKey, "dt-dlg-pickerkey");
               var elTemplateBtns = elTemplateCol.appendChild(document.createElement("span"));
               Dom.addClass(elTemplateBtns, "dt-dlg-pickerbtns");
               var onclickObj = {fn:handleButtonClick, obj:this, scope:false };

               // Create one section in the SimpleDialog for each Column
               var elColumn, elKey, elButton, oButtonGrp;
               for(var i=0,l=allColumns.length;i<l;i++) {
                   var oColumn = allColumns[i];

                   // Use the template
                   elColumn = elTemplateCol.cloneNode(true);

                   // Write the Column key
                   elKey = elColumn.firstChild;
                   elKey.innerHTML = (oColumn.label && oColumn.label !== "") ? oColumn.label : oColumn.getKey();

                   if(oColumn.getKey() != "delete" && oColumn.getKey() != "modify") {

                      // Create a ButtonGroup
                      oButtonGrp = new YAHOO.widget.ButtonGroup({
                                      id: "buttongrp"+i,
                                      name: oColumn.getKey(),
                                      container: elKey.nextSibling
                      });
                      oButtonGrp.addButtons([
                          { label: msgs.showColumnButton, value: "Show", checked: ((!oColumn.hidden)), onclick: onclickObj},
                          { label: msgs.hideColumnButton, value: "Hide", checked: ((oColumn.hidden)), onclick: onclickObj}
                      ]);

                      elPicker.appendChild(elColumn);

                   }
               }
               this.noNewCols = true;
       	}
           this.tableOptionsDlg.show();

       }

    };

    msgs.saveText = "Save";
    msgs.cancelText = "Cancel";
    msgs.deleteText = "delete";
    msgs.modifyText = "modify";
    msgs.insertItemText = "Insert";
    msgs.addButtonText = "Add";
    msgs.loadingText = "Loading...";
    msgs.emptyDataText = "No records found.";
    msgs.errorDataText = "Data error.";
    msgs.confirmDeletion = "Are you sure?";

    msgs.tableOptions = "Table options";
    msgs.showColumnButton = "Show";
    msgs.hideColumnButton = "Hide";
    msgs.columnDialogTitle = "Choose which columns you would like to see";
    msgs.columnDialogCloseButton = "Close";

    })();

Copyright © 2010 Eric Abouaf All rights reserved.