Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 6813

Show
Ignore:
Timestamp:
05/22/07 23:40:40 (1 year ago)
Author:
andrew
Message:

Introduced a pared-down version of Alex Arnell's inheritance scheme. Class.create can now take an object argument -- it'll assign the properties defined therein to the class's prototype.

Rewrote source:ajax.js to take advantage of some of the new stuff -- take a look if you need examples. I'll get the rest of the low-hanging fruit in the next couple days.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • spinoffs/prototype/branches/inheritance/CHANGELOG

    r6812 r6813  
    1 * Test commit (having trouble with svn) 
    2  
    31*SVN* 
    42 
  • spinoffs/prototype/branches/inheritance/src/ajax.js

    r6725 r6813  
    1 var Ajax = { 
     1var Ajax = Class.create({ 
     2  setOptions: function(options) { 
     3    this.options = Object.extend({ 
     4      method: 'post', 
     5      asynchronous: true, 
     6      contentType: 'application/x-www-form-urlencoded', 
     7      encoding: 'UTF-8', 
     8      parameters: '' 
     9    }, options || {}); 
     10     
     11    this.options.method = this.options.method.toLowerCase(); 
     12    if (typeof this.options.parameters === 'string') 
     13      this.options.parameters = this.options.parameters.toQueryParams(); 
     14  } 
     15}); 
     16 
     17Object.extend(Ajax, { 
    218  getTransport: function() { 
    319    return Try.these( 
    4       function() {return new XMLHttpRequest()}, 
    5       function() {return new ActiveXObject('Msxml2.XMLHTTP')}, 
    6       function() {return new ActiveXObject('Microsoft.XMLHTTP')
     20      function() { return new XMLHttpRequest(); }, 
     21      function() { return new ActiveXObject('Msxml2.XMLHTTP'); }, 
     22      function() { return new ActiveXObject('Microsoft.XMLHTTP');
    723    ) || false; 
    824  }, 
    925   
    1026  activeRequestCount: 0 
    11 } 
     27}); 
    1228 
    1329Ajax.Responders = { 
    1430  responders: [], 
    15    
    1631  _each: function(iterator) { 
    1732    this.responders._each(iterator); 
    1833  }, 
    19  
     34   
    2035  register: function(responder) { 
    2136    if (!this.include(responder)) 
     
    2843   
    2944  dispatch: function(callback, request, transport, json) { 
    30     this.each(function(responder) { 
    31       if (typeof responder[callback] == 'function') { 
     45    this.each( function(responder) { 
     46      if (typeof responder[callback] === 'function') { 
    3247        try { 
    3348          responder[callback].apply(responder, [request, transport, json]); 
    34         } catch (e) {} 
     49        } catch(e) {} 
    3550      } 
    3651    }); 
     
    4358  onCreate: function() { 
    4459    Ajax.activeRequestCount++; 
    45   },  
     60  }, 
     61   
    4662  onComplete: function() { 
    4763    Ajax.activeRequestCount--; 
     
    4965}); 
    5066 
    51 Ajax.Base = function() {}; 
    52 Ajax.Base.prototype = { 
    53   setOptions: function(options) { 
    54     this.options = { 
    55       method:       'post', 
    56       asynchronous: true, 
    57       contentType:  'application/x-www-form-urlencoded', 
    58       encoding:     'UTF-8', 
    59       parameters:   '' 
    60     } 
    61     Object.extend(this.options, options || {}); 
    62      
    63     this.options.method = this.options.method.toLowerCase(); 
    64     if (typeof this.options.parameters == 'string')  
    65       this.options.parameters = this.options.parameters.toQueryParams(); 
    66   } 
    67 
    68  
    69 Ajax.Request = Class.create(); 
    70 Ajax.Request.Events =  
    71   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; 
    72  
    73 Ajax.Request.prototype = Object.extend(new Ajax.Base(), { 
     67Ajax.Request = Class.extend(Ajax, { 
    7468  _complete: false, 
    75    
    7669  initialize: function(url, options) { 
     70    this.setOptions(options); 
     71     
    7772    this.transport = Ajax.getTransport(); 
    78     this.setOptions(options); 
    7973    this.request(url); 
    8074  }, 
    81  
     75   
    8276  request: function(url) { 
    8377    this.url = url; 
    8478    this.method = this.options.method; 
    8579    var params = Object.clone(this.options.parameters); 
    86  
    87     if (!['get', 'post'].include(this.method)) { 
     80    if (!$w('get post').include(this.method)) { 
    8881      // simulate other verbs over post 
    8982      params['_method'] = this.method; 
    9083      this.method = 'post'; 
    9184    } 
    92      
    9385    this.parameters = params; 
    94  
    9586    if (params = Hash.toQueryString(params)) { 
    96       // when GET, append parameters to URL 
    97       if (this.method == 'get') 
     87      if (this.method === 'get') 
    9888        this.url += (this.url.include('?') ? '&' : '?') + params; 
    99       else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)
     89      else if (Prototype.Browser.Webkit
    10090        params += '&_='; 
    10191    } 
    102        
    103     try { 
    104       if (this.options.onCreate) this.options.onCreate(this.transport); 
     92     
     93    try { 
     94      if (this.options.onCreate) 
     95        this.options.onCreate(this.transport);         
    10596      Ajax.Responders.dispatch('onCreate', this, this.transport); 
    106      
    107       this.transport.open(this.method.toUpperCase(), this.url,  
    108         this.options.asynchronous); 
    109  
    110       if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); 
    111        
     97 
     98      this.transport.open(this.method.toUpperCase(), this.url, 
     99       this.options.asynchronous); 
     100 
     101      if (this.options.asynchronous) 
     102        this.respondToReadyState.bind(this, 1).defer(); 
     103         
    112104      this.transport.onreadystatechange = this.onStateChange.bind(this); 
    113105      this.setRequestHeaders(); 
     
    115107      this.body = this.method == 'post' ? (this.options.postBody || params) : null; 
    116108      this.transport.send(this.body); 
    117  
    118       /* Force Firefox to handle ready state 4 for synchronous requests */ 
     109       
    119110      if (!this.options.asynchronous && this.transport.overrideMimeType) 
    120111        this.onStateChange(); 
    121          
    122     } 
    123     catch (e) { 
    124       this.dispatchException(e); 
    125     } 
    126   }, 
    127  
     112    } catch(e) { this.dispatchException(e); } 
     113  }, 
     114   
    128115  onStateChange: function() { 
    129116    var readyState = this.transport.readyState; 
     
    138125      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' 
    139126    }; 
    140  
    141     if (this.method == 'post') { 
     127     
     128    if (this.method === 'post') { 
    142129      headers['Content-type'] = this.options.contentType + 
    143         (this.options.encoding ? '; charset=' + this.options.encoding : ''); 
    144        
     130       (this.options.encoding ? '; charset=' + this.options.encoding : ''); 
     131       
    145132      /* Force "Connection: close" for older Mozilla browsers to work 
    146133       * around a bug where XMLHttpRequest sends an incorrect 
    147        * Content-length header. See Mozilla Bugzilla #246651.  
     134       * Content-length header. See Mozilla Bugzilla #246651. 
    148135       */ 
    149136      if (this.transport.overrideMimeType && 
    150           (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 
    151             headers['Connection'] = 'close'; 
     137       (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) 
     138        headers['Connection'] = 'close'; 
    152139    } 
    153140     
    154141    // user-defined headers 
    155     if (typeof this.options.requestHeaders == 'object') { 
     142    if (typeof this.options.requestHeaders === 'object') { 
    156143      var extras = this.options.requestHeaders; 
    157  
    158       if (typeof extras.push == 'function') 
    159         for (var i = 0, length = extras.length; i < length; i += 2)  
    160           headers[extras[i]] = extras[i+1]; 
     144      if (typeof extras.push === 'function') 
     145        for (var i = 0, l = extras.length; i < l; i += 2) 
     146          headers[extras[i]] = extras[i + 1]; 
    161147      else 
    162         $H(extras).each(function(pair) { headers[pair.key] = pair.value }); 
    163     } 
    164  
    165     for (var name in headers)  
     148        $H(extras).each( function(pair) { headers[pair.key] = pair.value }); 
     149    } 
     150     
     151    for (var name in headers) 
    166152      this.transport.setRequestHeader(name, headers[name]); 
    167153  }, 
     
    185171        this.dispatchException(e); 
    186172      } 
    187        
     173 
    188174      var contentType = this.getHeader('Content-type'); 
    189175      if (contentType && contentType.strip(). 
     
    198184      this.dispatchException(e); 
    199185    } 
    200      
     186 
    201187    if (state == 'Complete') { 
    202188      // avoid memory leak in MSIE: clean up 
     
    204190    } 
    205191  }, 
    206    
     192 
    207193  getHeader: function(name) { 
    208194    try { 
     
    210196    } catch (e) { return null } 
    211197  }, 
    212    
     198 
    213199  evalJSON: function() { 
    214200    try { 
     
    217203    } catch (e) { return null } 
    218204  }, 
    219    
     205 
    220206  evalResponse: function() { 
    221207    try { 
     
    229215    (this.options.onException || Prototype.emptyFunction)(this, exception); 
    230216    Ajax.Responders.dispatch('onException', this, exception); 
    231   } 
    232 }); 
    233  
    234 Ajax.Updater = Class.create(); 
    235  
    236 Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { 
     217  }   
     218}); 
     219 
     220Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive',  
     221                       'Complete']; 
     222 
     223Ajax.Updater = Class.extend(Ajax.Request, { 
    237224  initialize: function(container, url, options) { 
    238225    this.container = { 
    239226      success: (container.success || container), 
    240227      failure: (container.failure || (container.success ? null : container)) 
    241     } 
    242      
    243     this.transport = Ajax.getTransport(); 
     228    }; 
     229     
    244230    this.setOptions(options); 
    245  
    246     var onComplete = this.options.onComplete || Prototype.emptyFunction; 
     231     
     232    var onComplete = this.options.onComplete || Prototype.emptyFunction;     
    247233    this.options.onComplete = (function(transport, param) { 
    248234      this.updateContent(); 
     
    250236    }).bind(this); 
    251237 
    252     this.request(url); 
    253   }, 
    254  
     238    this.parent(url, options);     
     239  }, 
     240   
    255241  updateContent: function() { 
    256242    var receiver = this.container[this.success() ? 'success' : 'failure']; 
    257     var response = this.transport.responseText, options = this.options
    258      
    259     if (!options.evalScripts) response = response.stripScripts(); 
     243    var response = this.transport.responseText
     244     
     245    if (!this.options.evalScripts) responde = response.stripScripts(); 
    260246     
    261247    if (receiver = $(receiver)) { 
    262       if (options.insertion) { 
    263         if (typeof options.insertion == 'string') 
    264           receiver.insert(response, options.insertion); 
    265         else options.insertion(receiver, response); 
    266       }  
     248      if (this.options.insertion) 
     249        new this.options.insertion(receiver, response); 
    267250      else receiver.update(response); 
    268251    } 
    269252     
    270     if (this.success()) { 
     253    if (this.success()) 
    271254      if (this.onComplete) this.onComplete.bind(this).defer(); 
    272     } 
    273   } 
    274 }); 
    275  
    276 Ajax.PeriodicalUpdater = Class.create(); 
    277 Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { 
     255  } 
     256}); 
     257 
     258Ajax.PeriodicalUpdater = Class.extend(Ajax, { 
    278259  initialize: function(container, url, options) { 
    279260    this.setOptions(options); 
    280261    this.onComplete = this.options.onComplete; 
    281  
    282     this.frequency = (this.options.frequency || 2)
    283     this.decay = (this.options.decay || 1)
     262     
     263    this.frequency = this.options.frequency || 2
     264    this.decay     = this.options.decay || 1
    284265     
    285266    this.updater = {}; 
    286267    this.container = container; 
    287268    this.url = url; 
    288  
     269     
    289270    this.start(); 
    290271  }, 
    291  
     272   
    292273  start: function() { 
    293274    this.options.onComplete = this.updateComplete.bind(this); 
    294275    this.onTimerEvent(); 
    295276  }, 
    296  
     277   
    297278  stop: function() { 
    298279    this.updater.options.onComplete = undefined; 
    299     clearTimeout(this.timer); 
     280    window.clearTimeout(this.timer); 
    300281    (this.onComplete || Prototype.emptyFunction).apply(this, arguments); 
    301282  }, 
    302  
     283   
    303284  updateComplete: function(request) { 
    304285    if (this.options.decay) { 
    305       this.decay = (request.responseText == this.lastText ?  
    306         this.decay * this.options.decay : 1); 
    307  
     286      this.decay = (request.responseText === this.lastText ? 
     287       this.decay * this.options.decay : 1); 
     288        
    308289      this.lastText = request.responseText; 
    309290    } 
    310     this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); 
    311   }, 
    312  
     291    this.timer = this.onTimerEvent.bind(this).delay(this.decay * 
     292     this.frequency); 
     293  }, 
     294   
    313295  onTimerEvent: function() { 
    314296    this.updater = new Ajax.Updater(this.container, this.url, this.options); 
  • spinoffs/prototype/branches/inheritance/src/base.js

    r6723 r6813  
     1// Based on Alex Arnell's inheritance implementation. 
    12var Class = { 
    2   create: function() { 
    3     return function() {  
    4       this.initialize.apply(this, arguments); 
    5     } 
    6   } 
    7 
     3  extend: function(parent, methods) { 
     4    if (arguments.length == 1) { 
     5      methods = parent; parent = null; 
     6    } 
     7    var method = function() { 
     8      if (!Class.extending) this.initialize.apply(this, arguments); 
     9    }; 
     10     
     11    if (typeof parent === 'function') { 
     12      Class.extending = true; 
     13      method.prototype = new parent(); 
     14      delete Class.extending; 
     15    } 
     16     
     17    if (methods) Class.inherit(method.prototype, methods); 
     18    return method;     
     19  }, 
     20   
     21  inherit: function(destination, source, name) { 
     22    if (arguments.length === 3) { 
     23      var ancestor = destination[name], descendant = source[name], 
     24       method = descendant; 
     25        
     26      descendant = function() { 
     27        var ref = this.parent; this.parent = ancestor; 
     28        var result = method.apply(this, arguments); 
     29        if (ref) this.parent = ref; else delete this.parent; 
     30        return result; 
     31      }; 
     32     
     33      Object.extend(descendant, { 
     34        valueOf:  function() { return method; }, 
     35        toString: function() { return method.toString(); } 
     36      }); 
     37      destination[name] = descendant; 
     38    } else { 
     39      for (var property in source) { 
     40        if (destination[property] && typeof source[property] === 'function') 
     41          Class.inherit(destination, source, property); 
     42        else destination[property] = source[property]; 
     43      } 
     44    } 
     45    return destination; 
     46  }, 
     47   
     48  mixin: function(destination, source) { 
     49    return Object.extend(destination.prototype, source); 
     50  } 
     51}; 
     52 
     53Class.create = function() { 
     54  return Class.extend.apply(this, arguments); 
     55}; 
    856 
    957var Abstract = new Object(); 
     
    1462  } 
    1563  return destination; 
    16 } 
     64}; 
    1765 
    1866Object.extend(Object, { 
     
    165213/*--------------------------------------------------------------------------*/ 
    166214 
    167 var PeriodicalExecuter = Class.create(); 
    168 PeriodicalExecuter.prototype = { 
     215var PeriodicalExecuter = Class.create({ 
    169216  initialize: function(callback, frequency) { 
    170217    this.callback = callback; 
     
    195242    } 
    196243  } 
    197 } 
     244});