Report abuse

The rewrite of TableKit.Editable module for Prototype 1.6.0


			
// based on version 1.2.1 (2007-03-11)
// http://www.millstream.com.au/view/code/tablekit/
// (original code below)

TableKit.Editable = {
  AjaxURL: '',

  init: function(element, url){
    this.table = $(element)
    this.url = url
    Event.observe(this.table.tBodies[0], 'click', this.editCell.bindAsEventListener(this))
  },

  editCell: function(event) {
    var cell = event.findElement('td')
    if (cell.hasClassName('editing')) return

    var header = cell.getHeaderCell(this.table)
    if (header.hasClassName('noedit')) return

    var editable = new TableKit.Editable.CellEditor({ url: this.url });
    editable.edit(cell, cell.parentNode.id, header.id);
  }
};

TableKit.Editable.CellEditor = Class.create({
  initialize: function(options) {
    this.options = Object.extend({
      showSubmit : true,
      submitText : 'OK',
      showCancel : true,
      cancelText : 'Cancel',
      url : null,
      ajaxOptions : null
    }, options || {});
  },

  edit: function(cell, id, field) {
    this.cell = cell = $(cell);
    this.id = id
    this.field = field
    cell.addClassName('editing')

    this.form = new Element('form',
      { method: 'post', action: (this.options.url || TableKit.Editable.AjaxURL) })

    this.form.observe('submit', this.submit.bindAsEventListener(this))
    this.originalValue = cell.getTextContent()
    cell.update(this.form)

    this.generateInput()

    if (this.options.showCancel) {
      this.cancelButton = new Element('a', { href: '#' }).update(this.options.cancelText)
      this.cancelButton.observe('click', this.cancel.bindAsEventListener(this))
      this.form.insert(' ').insert(this.cancelButton)
    }
  },

  generateInput: function() {
    var input = new Element('input', { name: 'value', type: 'text' })
    this.form.appendChild(input)
    input.setValue(this.originalValue).activate()
  },

  update: function(value) {
    this.cell.removeClassName('editing').update(value)
  },

  cancel: function(e) {
    e.stop()
    this.update(this.originalValue)
  },

  submit : function(e) {
    e.stop()
    this.cancelButton.hide()
    this.form.request({
      parameters: {
        id:    this.id,
        field: this.field,
        cell:  this.cell.getCellIndex(),
        row:   this.cell.getRowIndex()
      },
      onComplete: this.callback.bind(this)
    })
    this.form.disable()
  },

  callback: function(ajax) {
    this.update(ajax.responseText)
  }
})

/** Useful DOM extensions **/

Element.addMethods('table', {
  getHeaderRow: function(table) {
    table = $(table)
    return Element.extend((table.tHead ? table.tHead : table).rows[0])
  }
})

Element.addMethods('td', {
  getHeaderCell: function(cell, table) {
    cell = $(cell)
    var header = ($(table) || cell.up('table')).getHeaderRow()
    return Element.extend(header.cells[cell.getCellIndex()])
  }
})

Element.addMethods($w('td th'), {
  // investigate: needed?
  getCellIndex: function(cell) {
    cell = $(cell)
    if (Object.isNumber(cell.cellIndex)) return cell.cellIndex
    var row = cell.parentNode
    for (var i = 0; row.cells[i] != cell; i++);
    return i
  },

  getRowIndex: function(cell) {
    cell = $(cell)
    var row = cell.parentNode
    if (Object.isNumber(row.rowIndex)) return row.rowIndex
    var tbody = row.parentNode
    for (var i = 0; tbody.rows[i] != row; i++);
    if (cell.tagName.toUpperCase() == 'TD' && tbody.tagName.toUpperCase() != 'TBODY') i--
    return i
  },

  getTextContent: function(cell) {
    cell = $(cell)
    return Object.isUndefined(cell.textContent) ? cell.innerText : cell.textContent
  }
})

Original TableKit.Editable


			
/*
*
* Copyright (c) 2007 Andrew Tetlaw & Millstream Web Software
* http://www.millstream.com.au/view/code/tablekit/
* Version: 1.2.1 2007-03-11
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* * 
*/

TableKit.Editable = {
  init : function(elm, options){
    var table = $(elm);
    if(table.tagName !== "TABLE") {return;}
    TableKit.register(table,Object.extend(options || {},{editable:true}));
    Event.observe(table.tBodies[0], 'click', TableKit.Editable._editCell);
  },
  _editCell : function(e) {
    e = TableKit.e(e);
    var cell = Event.findElement(e,'td');
    TableKit.Editable.editCell(null, cell);
  },
  editCell : function(table, index, cindex) {
    var cell, row;
    if(typeof index === 'number') {
      if(!table || (table.tagName && table.tagName !== "TABLE")) {return;}
      table = $(table);
      index = Math.min(table.tBodies[0].rows.length, index);
      index = Math.max(1, index);
      index -= 1;
      cindex = Math.min(table.rows[0].cells.length, cindex);
      cindex = Math.max(1, cindex);
      cindex -= 1;
      row = $(table.tBodies[0].rows[index]);
      cell = $(row.cells[cindex]);
    } else {
      cell = $(index);
      table = (table && table.tagName && table.tagName !== "TABLE") ? $(table) : cell.up('table');
      row = cell.up('tr');
    }
    var op = TableKit.option('noEditClass', table.id);
    if(cell.hasClassName(op.noEditClass)) {return;}

    var head = $(TableKit.getHeaderCells(table, cell)[TableKit.getCellIndex(cell)]);
    if(head.hasClassName(op.noEditClass)) {return;}

    TableKit.registerCell(cell);
    var data = TableKit.cells[cell.id];
    if(data.active) {return;}
    data.htmlContent = cell.innerHTML;
    var ftype = TableKit.Editable.types['text-input'];
    if(head.id && TableKit.Editable.types[head.id]) {
      ftype = TableKit.Editable.types[head.id];
    } else {
      var n = head.classNames().detect(function(n){
          return (TableKit.Editable.types[n]) ? true : false;
      });
      ftype = n ? TableKit.Editable.types[n] : ftype;
    }
    ftype.edit(cell);
    data.active = true;
  },
  types : {},
  addCellEditor : function(o) {
    if(o && o.name) { TableKit.Editable.types[o.name] = o; }
  }
};

TableKit.Editable.CellEditor = Class.create();
TableKit.Editable.CellEditor.prototype = {
  initialize : function(name, options){
    this.name = name;
    this.options = Object.extend({
      element : 'input',
      attributes : {name : 'value', type : 'text'},
      selectOptions : [],
      showSubmit : true,
      submitText : 'OK',
      showCancel : true,
      cancelText : 'Cancel',
      ajaxURI : null,
      ajaxOptions : null
    }, options || {});
  },
  edit : function(cell) {
    cell = $(cell);
    var op = this.options;
    var table = cell.up('table');

    var form = $(document.createElement("form"));
    form.id = cell.id + '-form';
    form.addClassName(TableKit.option('formClassName', table.id)[0]);
    form.onsubmit = this._submit.bindAsEventListener(this);

    var field = document.createElement(op.element);
      $H(op.attributes).each(function(v){
        field[v.key] = v.value;
      });
      switch(op.element) {
        case 'input':
        case 'textarea':
        field.value = TableKit.getCellText(cell);
        break;

        case 'select':
        var txt = TableKit.getCellText(cell);
        $A(op.selectOptions).each(function(v){
          field.options[field.options.length] = new Option(v[0], v[1]);
          if(txt === v[1]) {
            field.options[field.options.length-1].selected = 'selected';
          }
        });
        break;
      }
      form.appendChild(field);
      if(op.element === 'textarea') {
        form.appendChild(document.createElement("br"));
      }
      if(op.showSubmit) {
        var okButton = document.createElement("input");
        okButton.type = "submit";
        okButton.value = op.submitText;
        okButton.className = 'editor_ok_button';
        form.appendChild(okButton);
      }
      if(op.showCancel) {
        var cancelLink = document.createElement("a");
        cancelLink.href = "#";
        cancelLink.appendChild(document.createTextNode(op.cancelText));
        cancelLink.onclick = this._cancel.bindAsEventListener(this);
        cancelLink.className = 'editor_cancel';      
        form.appendChild(cancelLink);
      }
      cell.innerHTML = '';
      cell.appendChild(form);
  },
  _submit : function(e) {
    var cell = Event.findElement(e,'td');
    var form = Event.findElement(e,'form');
    Event.stop(e);
    this.submit(cell,form);
  },
  submit : function(cell, form) {
    var op = this.options;
    form = form ? form : cell.down('form');
    var head = $(TableKit.getHeaderCells(null, cell)[TableKit.getCellIndex(cell)]);
    var row = cell.up('tr');
    var table = cell.up('table');
    var s = '&row=' + (TableKit.getRowIndex(row)+1) + '&cell=' + (TableKit.getCellIndex(cell)+1) + '&id=' + row.id + '&field=' + head.id + '&' + Form.serialize(form);
    this.ajax = new Ajax.Updater(cell, op.ajaxURI || TableKit.option('editAjaxURI', table.id)[0], Object.extend(op.ajaxOptions || TableKit.option('editAjaxOptions', table.id)[0], {
      postBody : s,
      onComplete : function() {
        var data = TableKit.cells[cell.id];
        data.active = false;
        data.refresh = true; // mark cell cache for refreshing, in case cell contents has changed and sorting is applied
      }
    }));
  },
  _cancel : function(e) {
    var cell = Event.findElement(e,'td');
    Event.stop(e);
    this.cancel(cell);
  },
  cancel : function(cell) {
    this.ajax = null;
    var data = TableKit.cells[cell.id];
    cell.innerHTML = data.htmlContent;
    data.htmlContent = '';
    data.active = false;
  },
  ajax : null
};

TableKit.Editable.textInput = function(n,attributes) {
  TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {
    element : 'input',
    attributes : Object.extend({name : 'value', type : 'text'}, attributes||{})
  }));
};
TableKit.Editable.textInput('text-input');

TableKit.Editable.multiLineInput = function(n,attributes) {
  TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {
    element : 'textarea',
    attributes : Object.extend({name : 'value', rows : '5', cols : '20'}, attributes||{})
  }));  
};  
TableKit.Editable.multiLineInput('multi-line-input');

TableKit.Editable.selectInput = function(n,attributes,selectOptions) {
  TableKit.Editable.addCellEditor(new TableKit.Editable.CellEditor(n, {
    element : 'select',
    attributes : Object.extend({name : 'value'}, attributes||{}),
    'selectOptions' : selectOptions
  }));  
};