topical media & game development

talk show tell print

lib-jquery-plugin-charts-lib--old-jquery.tablelib.js / js



  /*
   * Copyright (c) 2008 Greg Weber greg at gregweber.info
   * Dual licensed under the MIT and GPL licenses:
   * http://www.opensource.org/licenses/mit-license.php
   * http://www.gnu.org/licenses/gpl.html
   *
   * jquery plugin for working with tables and table rows
   * create table objects and table row objects and use convenience methods
   * serialize objects to table rows and extract objects from table rows
   * support for saving object properties as row attributes
   * advanced querying of table rows
   *
   * documentation at http://gregweber.info/projects/tablelib
   *   also in the source
   *
   * plugin dependent on lib/iterator.js (included in tarball)
   */
  
  // support both .table() interface and .table(selector) interface
  jQuery.fn.table = function(jq){
    if( this instanceof jQuery.fn.table ){
      this. = jq;
      return this;
    }
    return new jQuery.fn.table(this);
  }
  // .table(selector) interface
  jQuery.table = function(selector){
    return new jQuery.fn.table(jQuery(selector));
  }
  
  jQuery.fn.table.prototype = jQuery.fn.table.fn = {
    //: null, // constructor fills this in!
    
    table: function(){return this},
  
    filter_query: function(obj, query ){
      for( var i in query ) {
        var qv = query[i], ov = obj[i];
  
        if(typeof(qv) == "function"){ if( isTrue(qv(ov)) ) return true }
        else if ( ov === qv ) return true;
      }
      return false;
    },
  
    // by default try to parse to a float
    // turn off by setting to false (or set your own parse function)
    parse: function(val){ var p = parseFloat(val); return isNaN(p) ? val :
      (p.toString() === val) // extra verification
        ? p : val },
  
    head_row: function(){
      return jQuery.headRow( this..find("thead > tr:last") );
    },
  
    titles: function(){ return jQuery.map( this..find("thead > tr:last > th"),
                 function(th) { return jQuery(th).text() });
    },
  
    clear_rows: function(){ this..find("tbody").html( "" ); return this },
  
    column: function( columns, query ) {
      if( typeof(columns) == "string" ){
        var index = this.i(columns);
        return map( this.rows(query), function(row){
            return jQuery.row(row).at(index) });
      } else { //array
        var that = this;
        var indices = jQuery.map( columns, function(column) { return that.i(column) });
        return map( this.rows( query ), function(row) {
            return jQuery.row(row).at(indices) });
      }
    },
  
    // given a th name, return the index of the column
    i: function(text){
      var f = first( this.titles(), function(t,i){ if( t == text ) return i; } );
      if( isTrue(f) ) return f;
      throw("could not find column title: " + text );
    },
  
    // see objs documentation, but there is no fields parameter
    // returns jquery object of table body rows
    rows: function( query, attributes ){
      var that = this;
      if( !(query) || query === "all" ) {
        if( attributes ) {
          return this..find("tbody > tr").filter( function() {
            return that.filter_query( jQuery.row(this).attrs(), attributes );
          });
        }
        else return this..find("tbody > tr");
      }
  
      // convert each query field to a column index
      var titles = invert( this.titles() );
      query = rekey( query, function(val,key,i){ return titles[ key ]; });
  
      if( attributes ) {
        return this..find("tbody > tr").filter( function(){
          var row = .row(this)
          if( that.filter_query( row.texts(), query ) ) return true;
  
          return that.filter_query( row.attrs(), attributes );
        });
      }
  
      return this..find("tbody > tr").filter( function(){
        return that.filter_query( jQuery.row(this).texts(), query )
      });
    },
  
    // two options passed as objects, 
    //   query for table data cells, query for row attributes
    // two minor options, both have two properties: query and fields
    // query is a filtering expression
    // fields is an array of keys that will be present in the returned objects
    // by default, no query is performed, all table data keys are present,
    //   and none of the row attributes are present
    // query can be abbreviated as q, fields as f
    // the fields value is an array
    // if no fields parameter is passed, there is no need to pass the query of fields keys
    // objs( {query : {k:v}, fields : [f]}, {query : {k:a}, fields : [a]}
    // objs( {q: {k:v}, f: [f]}, {q: {k:a}, f: [a]}
    // objs( {k:v}, {k:a} )
    // objs( "all", {k:a} )
    // if attributes are queried and there are no fields specified,
    //   by default all queried fields will become members of the object
    objs: function( query, attributes ){
      var parse_args = function( query ){
        var fields; var q;
        if( query && query != "all" ) {
          q = query.query || query.q
          fields = query.fields || query.f
  
          // not a query object, coincidental
          if( q && ( typeof(q) != "object" ) )
          { q = null }
  
          // not a field object, coincidental
          if( !(fields) || ( typeof(fields) != "object" ) )
          { fields = null }
  
          // did not decalre a query or fields parameter, default is a query
          if( !(fields) && !(q) )
          { q = query }
        }
        return { query : q, fields : fields }
      }
      var q_f = parse_args( query );
      var q = q_f.query;      var fields = q_f.fields;
      var a_f = parse_args( attributes )
      var aquery = a_f.query; var afields = a_f.fields;
  
      var ths_text = this.titles();
      if( fields ) {
        fields = map( fields, function( field ) {
          var i = jQuery.inArray( field, ths_text )
          return i === -1 ? null : { field : field, i : i }
        })
      } else {
        fields = map(ths_text, function(th,i){ return {field : th, i : i} })
      }
  
      var af;
      if( afields ) af = invert( afields, true );
  
      var that = this;
      return map( this.rows(q, aquery), function(row){ return jQuery.row( row )
          .to_object( { fields : fields, attributes : af, table : that } );
      })
    },
  
    object_to_html: function(obj, attribute_fields, titles){
      titles = titles || this.titles();
      var attrs = null;
      // turn array of fields into obj
      if( attribute_fields ) {
        attrs = {};
        jQuery.each( attribute_fields, function(i){
          attrs[ this ] = obj[ this ];
        });
      }
  
      return this.array_to_tr( jQuery.map( titles,
            function(text){ return obj[ text ] }), attrs )
    },
  
    // [""], {"":""} -> ""
    array_to_tr: function(arr, attributes){
      var tr = null;
      if( attributes ) {
        var at = [];
        for(key in attributes){ at.push(key + '="' + attributes[key]); }
        tr = '<tr ' + at.join('" ') + '">';
      }
      else { tr = "<tr>"; }
  
      if( arr.length === 0 ) return tr + "</tr>";
      return tr + "<td>" + arr.join("</td><td>") + "</td></tr>";
    },
  
    // objs : an array of objects
    // options.attributes : attributes to be saved, see save
    // options.clear : clear all existing rows before saving
    save: function( objects, options ) {
      var attributes, clear
      if( options ){
        attributes = options.attributes;
        if( typeof attributes == "string" ) attributes = [attributes]
        clear = options.clear;
      }
      if( objects.constructor != Array ) objects = [objects]
      var ths_text = this.titles();
  
      var that = this;
      if( clear ) this.clear_rows();
      this..find("tbody").append(
        jQuery.map( objects, function(obj){
          return that.object_to_html( obj, attributes, ths_text )
        }).join("")
      )
      return this;
    }
  };
  
  /* row() interface */
  jQuery.fn.row = function(jq){
    if( this instanceof jQuery.fn.row ){
      this. = jq;
      return this;
    }
    return new jQuery.fn.row(this);
  }
  jQuery.fn.headRow = function(jq){
    if( this instanceof jQuery.fn.headRow ){
      this. = jq;
      return this;
    }
    return new jQuery.fn.headRow(this);
  }
  
  // type = td or th
  //  should be new jQuery object
  jQuery.fn.row.genericRowProperties = function(type){
    this.row = function(){return this;}
    this.table = function(){return jQuery.table(this..parents('table:first').get(0))};
  
    this[type + "s"] = function(){
      var d = jQuery(this..children(type));
      d.row   = this;
      d.table = this.table;
      return d;
    }
  
    this.texts = function(){ return jQuery.map( this..children(type),
      function(td) { return jQuery(td).text() }) };
  
    // table is optional parameter to avoid Dom lookup of table
    this.td_helper = function(column, tds, table){
      switch( typeof(column) ) {
        case "string": return jQuery(tds[(table || this.table()).i(column)]);
        case "number": return jQuery(tds[column]);
        default      : throw( "invalid column type: " + typeof(column) );
      }
    }
  
    // table is optional parameter to avoid Dom lookup of table
    this[type] = function (columns, table) {
      var tds = this[ type + "s" ]();
      if( typeof(columns) != "object" ) return this.td_helper(columns, tds, table);
  
      var that = this;
      return jQuery.map( columns, function( column,i ) {
        return that.td_helper( column, tds, table ) });
    };
  
    // table is optional parameter to avoid Dom lookup of table
    this.at = function (column, table) {
      // one column
      if( typeof(column) != "object" ) return (this[type](column, table)).text();
      // multiple columns
      return map( this[type](column, table), function(td){ return td.text() });
    };
  
    // fields is an object with each attribute set to a true value
    this.attrs = function(fields, obj){
      var attrs = obj || {};
      var a_filter = function(i,attr){
        var v = attr.value;
        if( isTrue(v) ) { attrs[ attr.name ] = v; }
      }
      var a_filter_fields = function(i,attr){
        var v = attr.value;
        if( isTrue(v) ) {
          var n = attr.name;
          if( fields[n] ) { attrs[ n ] = v; }
        }
      }
      jQuery.each( this..get(0).attributes,
          ((fields && typeof(fields) === "object") ? a_filter_fields : a_filter));
      return attrs;
    }
  
    // options.parse = false  prevents trying to parse fields as floats
    // options.table is performance optimization if fields are not given
    // options.attributes - see row.attrs
    this.to_object = function( options ) { // fields, attributes, table, parse
      var obj = {}; // to be returned
      options = options || {};
      var table = options.table;
      var fields = options.fields || map( (table || this.table()).head_row().ths(),
          function(th,i){ return { field : jQuery(th).text(), i : i } } );
      var texts = this.texts();
  
      // convert the table text (probably to a number)
      var parse = options.parse || (table && table.parse);
      if( parse ){
        if( typeof( parse ) == "function" ) {
          jQuery.each( fields, function( i, fi ) {
            var field = fi.field;
            var text = texts[ fi.i ];
            obj[ field ] = parse(text);
          });
        }else{ //object
          jQuery.each( fields, function( i, fi ) {
            var field = fi.field;
            var transform = parse[ field ];
            var text = texts[ fi.i ];
            obj[ field ] = transform ? transform(text) : text;
          });
        }
      }else{
        jQuery.each( fields, function( i, fi ) {
          obj[ fi.field ] = texts[ fi.i ];
        });
      }
      if( options.attributes ) { this.attrs( options.attributes, obj ); }
      return obj;
    }
  
    // current_table optional performance enhancement
    this.transfer_to = function( table, current_table )
    {
      var obj = this.to_object( { table : current_table } );
      this..remove();
      table.save( obj );
      return table..find("tbody > tr:last");
    }
    return this;
  };
  
  jQuery.fn.row.prototype = jQuery.fn.row.fn =
    new jQuery.fn.row.genericRowProperties("td");
  jQuery.fn.headRow.prototype = jQuery.fn.headRow.fn =
    new jQuery.fn.row.genericRowProperties("th");
  
  jQuery.row = function(selector){
    return new jQuery.fn.row(jQuery(selector));
  }
  jQuery.headRow = function(selector){
    return new jQuery.fn.headRow(jQuery(selector));
  }
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.