<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,93 +1,332 @@
-
 function $(element) {
-  if (typeof element == &quot;string&quot;) {
-    element=document.getElementById(element);
-  }
-  if (element)
-    extend_instance(element,Element);
-  return element;
+    if (typeof element == &quot;string&quot;) {
+        element=document.getElementById(element);
+    }
+    if (element)
+        extendInstance(element,Element);
+    return element;
 }
 
-function extend_instance(instance,hash) {
-  for (var name in hash) {
-    instance[name] = hash[name];
-  }
+function getElementsByName(elementName) {        
+    var matcher = function(element) {
+        return (element.getName() === elementName);				
+    };			        
+    return domCollect(document.getRootElement(), matcher);
+}
+function getElementsByClass(classname) {    
+    var matcher = function(element) {
+        return (element.getClassName() === classname);
+    };
+    return domCollect(document.getRootElement(), matcher);
+}
+//function getElementsByTagName(tagName) -&gt; native to FJBS
+
+extendInstance(Ajax, { //Extends the native Facebook Ajax object
+    /*
+     * Make a request to a remote server. Call the 'success' callback with the result.
+     * Ex: 	Ajax.Load('JSON','http://...',{ success: function(result){console.log(result.toSource())} }, {'json':test_content})
+     */
+    Load: function(response_type, action_path, callbacks, post_parameters) {
+        callbacks = Ajax.checkCallbacks(callbacks);		
+        var ajax = new Ajax();
+        switch(response_type) {
+            case 'FBML':
+                ajax.responseType = Ajax.FBML;
+                break;
+            case 'JSON':
+                ajax.responseType = Ajax.JSON;
+                break;
+            case 'RAW':
+                ajax.responseType = Ajax.RAW;
+                break;
+            default:
+                console.error(&quot;Unknow respons format requested. You supplied %s. Supported: 'FBML', 'RAW'&quot;, response_type);
+                return;										
+        }
+        ajax.ondone = function(result){
+            callbacks.success(result);
+            callbacks.complete();
+        }
+        ajax.onerror = function(error_string) {
+            callbacks.failure(error_string);
+            callbacks.complete();
+        }
+        
+        post_parameters = post_parameters || {}
+        post_parameters['authenticity_token'] = _token;
+
+        if(action_path.indexOf('http') == -1) {
+            action_path = _hostname + action_path;			
+        }                      
+
+        callbacks.begin();
+        ajax.post(action_path,post_parameters);
+    },
+    /*
+     * Make a request to a remote server. Update target_element with result. Calls the 'success' callback with the result
+     * Ex: Ajax.Update('test1', 'FBML', 'http://...',{ success: function(result){console.log(result)} })
+     */
+    Update: function(target_element, response_type, action_path, callbacks, post_parameters) {
+        callbacks = Ajax.checkCallbacks(callbacks);        
+        var update_element = function(content) {
+            switch(response_type) {
+                case 'FBML':
+                    $(target_element).setInnerFBML(content);
+                    break;
+                case 'RAW':
+                    $(target_element).setTextValue(content);					
+                    break;
+                default:
+                    console.log(&quot;Unsupported response type &quot;+response_type);
+                    break;
+            }
+        };
+
+        var onsuccess = (callbacks.success == null)?
+        update_element :
+        chainMethods([update_element,callbacks.success]);
+
+        callbacks.success = onsuccess;        
+        Ajax.Load(response_type, action_path, callbacks, post_parameters);
+    },
+
+
+    InPlaceInputEditor: function(target_element, action_path, post_parameters) {
+        var classname = $(target_element).getClassName() || &quot;&quot;;
+
+        this.edit = function() {
+            var target = $(target_element);	
+            var wrapper = target.getParentNode();			
+            var dimensions = $(target_element).getDimensions();	
+            var value = $(target_element+'__value').getValue();
+
+            var editArea = document.createElement('input');
+            editArea.setType($(target_element+'__value').getType());
+            editArea.setId(target_element+&quot;__editor&quot;);
+            editArea.setValue(value);
+            //editArea.focus();
+            //editArea.setStyle(&quot;width&quot;,dimensions.width+&quot;px&quot;);
+            //editArea.setStyle(&quot;height&quot;, dimensions.height+'px');
+
+            $(target_element+'__value').remove();
+            wrapper.removeChild(target);
+            wrapper.appendChild(editArea);
+        }
+        this.save = function(callbacks){
+            var newValue = $(target_element + &quot;__editor&quot;).getValue();
+            var wrapper = $(target_element + &quot;__editor&quot;).getParentNode();
+            callbacks = Ajax.checkCallbacks(callbacks);
+            Ajax.Load(&quot;RAW&quot;, action_path + &quot;?raw=&quot; + escape(newValue), {
+                success: chainMethods([
+                    callbacks.success,						
+                    function(result){
+                        wrapper.setInnerXHTML('&lt;span&gt;'+
+                            '&lt;input id=&quot;'+target_element+'__value&quot; name=&quot;'+target_element+'__value&quot; style=&quot;display:none;&quot; type=&quot;text&quot; value=&quot;'+unescape(result)+'&quot; /&gt;'+
+                            '&lt;span&gt;&lt;span id=&quot;'+target_element+'&quot; class=&quot;'+classname+'&quot; type=&quot;text&quot;&gt;'+unescape(result)+'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;');
+                    }
+                    ])
+            }, post_parameters)
+        };
+    },
+    InPlaceTextAreaEditor: function(target_element, action_path, post_parameters) {
+        var classname = $(target_element).getClassName() || &quot;&quot;;
+				
+        this.edit = function() {
+            var target = $(target_element);	
+            var wrapper = target.getParentNode();			
+            var dimensions = $(target_element).getDimensions();	
+            var value = $(target_element+'__value').getValue();
+
+            var editArea = document.createElement('textarea');
+            editArea.setId(target_element+&quot;__editor&quot;);
+            editArea.setValue(value.replace(/&lt;br \/&gt;|&lt;br\/&gt;/g,'\n').replace(/&lt;p&gt;|&lt;\/p&gt;/g,''));
+            editArea.addEventListener('keyup', function() {
+                autoExpandTextarea(editArea);
+            });
+            //editArea.focus();
+            editArea.setStyle(&quot;width&quot;,dimensions.width+&quot;px&quot;);
+            //editArea.setStyle(&quot;height&quot;, dimensions.height+'px');
+
+            $(target_element+'__value').remove();
+            wrapper.removeChild(target);
+            wrapper.appendChild(editArea);
+            autoExpandTextarea(editArea);
+        }
+        this.save = function(callbacks){
+            var newValue = $(target_element + &quot;__editor&quot;).getValue();
+            var wrapper = $(target_element + &quot;__editor&quot;).getParentNode();
+            callbacks = Ajax.checkCallbacks(callbacks);
+            Ajax.Load(&quot;RAW&quot;, action_path + &quot;?raw=&quot; + escape(newValue), {
+                success: chainMethods([
+                    callbacks.success,						
+                    function(result){
+                        wrapper.setInnerXHTML('&lt;span&gt;'+
+                            '&lt;textarea id=&quot;'+target_element+'__value&quot; name=&quot;'+target_element+'__value&quot; style=&quot;display:none;&quot;&gt;'+unescape(result.replace(/&lt;br \/&gt;|&lt;br\/&gt;/g,'\n').replace(/&lt;p&gt;|&lt;\/p&gt;/g,''))+'&lt;/textarea&gt;'+
+                            '&lt;div&gt;&lt;div id=&quot;'+target_element+'&quot; class=&quot;'+classname+'&quot; type=&quot;text&quot;&gt;'+unescape(result)+'&lt;/div&gt;&lt;/div&gt;&lt;/span&gt;');
+                    }
+                    ])
+            }, post_parameters)
+        };
+    },
+    /*
+     * Pass the data inside of a form to a target url and place the result inside target_element. 
+     * Calls the 'success' callback with the result
+     */
+    UpdateRemoteForm: function(form_element, target_element, response_type, target_action, callbacks) {
+        callbacks = callbacks || {};
+        Ajax.Update(target_element, response_type, target_action, callbacks, $(form_element).serialize());
+    },	
+    checkCallbacks:function(callbacks) {
+        callbacks = callbacks || {};		
+        var donothing = function(){};
+        return callbacks = {
+            success: callbacks.success 		|| donothing,
+            failure: callbacks.failure		|| donothing,
+            begin: callbacks.begin 		|| donothing,
+            complete: callbacks.complete 	|| donothing	
+        };
+    }
+});
+
+/*
+ * Displays a confirmation dialog. If the user clicks &quot;continue&quot; then callback will be evaluated.
+ * title and message can be strings or fb:js-string objects
+ */
+function confirm(title,message,callback) {
+    dialog = new Dialog(Dialog.DIALOG_POP);
+
+    dialog.showChoice(
+        title,
+        message, // Content
+        'Continue',
+        'Cancel');
+
+    dialog.onconfirm = function() {
+        callback();
+    };
+}
+
+function chainMethods(callbacks) {
+    return function(par1,par2,par3,par4,par5,par6) {
+        for (var i = 0, l = callbacks.length; i &lt; l; i++) {
+            callbacks[i](par1, par2, par3, par4, par5, par6);
+        }
+    }
+}
+
+function extendInstance(instance,hash) {
+    for (var name in hash) {
+        instance[name] = hash[name];
+    }
 }
 
 var Element = {
-  &quot;hide&quot;: function () {
-    this.setStyle(&quot;display&quot;,&quot;none&quot;)
-  },
-  &quot;show&quot;: function () {
-    this.setStyle(&quot;display&quot;,&quot;block&quot;)
-  },
-  &quot;visible&quot;: function () {
-    return (this.getStyle(&quot;display&quot;) != &quot;none&quot;);
-  },
-  &quot;toggle&quot;: function () {
-    if (this.visible) {
-      this.hide();
-    } else {
-      this.show();
+    visible: function() {
+        return (this.getStyle('display') != 'none');
+    },
+    toggle: function() {
+        if (this.visible()) {
+            this.hide();
+        } else {		
+            this.show();
+        }
+    },
+    hide: function() {
+        this.setStyle({
+            display:'none'
+        });
+        return this;
+    },
+    show: function(element) {
+        this.setStyle({
+            display:''
+        });
+        return this;	
+    },
+    remove: function() {
+        this.getParentNode().removeChild(this);
+        return null;
+    },
+    /*
+     * Returns calculated element size
+     */
+    getDimensions: function() {
+        var display = this.getStyle('display');
+        if (display != 'none' &amp;&amp; display != null) // Safari bug
+            return {
+                width: this.getOffsetWidth(),
+                height: this.getOffsetHeight()
+                };
+
+        // All *Width and *Height properties give 0 on elements with display none,
+        // so enable the element temporarily
+        var originalVisibility = this.getStyle(&quot;visibility&quot;);
+        var originalDisplay = this.getStyle(&quot;display&quot;);
+        var originalPosition = this.getStyle(&quot;position&quot;);
+        this.setStyle('visibility','none');
+        this.setStyle('display','block');
+        this.setStyle('position','absolute');
+        var originalWidth = this.getClientWidth();
+        var originalHeight = this.getClientHeight();
+        this.setStyle('visibility',originalVisibility);
+        this.setStyle('display',originalDisplay);
+        this.setStyle('position',originalPosition);
+
+        return {
+            width: originalWidth,
+            height: originalHeight
+        };
     }
-  }
-};
+}
 
 function encodeURIComponent(str) {
-  if (typeof(str) == &quot;string&quot;) {
-    return str.replace(/=/g,'%3D').replace(/&amp;/g,'%26');
-  }
-  //checkboxes and radio buttons return objects instead of a string
-  else if(typeof(str) == &quot;object&quot;){
-    for (prop in str)
-    {
-      return str[prop].replace(/=/g,'%3D').replace(/&amp;/g,'%26');
+    if (typeof(str) == &quot;string&quot;) {
+        return str.replace(/=/g,'%3D').replace(/&amp;/g,'%26');
     }
-  }
-};
-
-var Form = {};
-Form.serialize = function(form_element) {
-  return  $(form_element).serialize();  
-};
-
-Ajax.Updater = function (container,url,options) {
-  this.container = container;
-  this.url=url;
-  this.ajax = new Ajax();
-  this.ajax.requireLogin = 1;
-  if (options[&quot;onSuccess&quot;]) {
-    this.ajax.responseType = Ajax.JSON;
-    this.ajax.ondone = options[&quot;onSuccess&quot;];
-  } else {
-    this.ajax.responseType = Ajax.FBML;
-    this.ajax.ondone = function(data) {
-      $(container).setInnerFBML(data);
+    //checkboxes and radio buttons return objects instead of a string
+    else if(typeof(str) == &quot;object&quot;){
+        for (prop in str)
+        {
+            return str[prop].replace(/=/g,'%3D').replace(/&amp;/g,'%26');
+        }
+    }
+    return &quot;&quot;;
+}
+
+/*
+ * Applies block to all elements of an array. Return the array itself.
+ */
+function map(array, block){ 
+    results = [];
+    for (var i=0,l=array.length;i&lt;l;i++){ 
+        results.push(block(array[i]));
     }
-  }
-  if (options[&quot;onFailure&quot;]) {
-    this.ajax.onerror = options[&quot;onFailure&quot;];
-  }
-
-  if (!options['parameters']) {
-    options['parameters'] = {}
-  }
-
-  // simulate other verbs over post
-  if (options['method']) {
-    options['parameters']['_method'] = options['method'];
-  }
-
-  this.ajax.post(url,options['parameters']); 
-  if (options[&quot;onLoading&quot;]) {
-     options[&quot;onLoading&quot;].call() 
-  }
-};
-Ajax.Request = function(url,options) {
-  Ajax.Updater('unused',url,options);
-};
+    return results;
+}
+
+/*
+ * Collects all elements within the 'element' tree that 'matcher' returns true for
+ * For an example, see selectElementsByClass
+ */
+function domCollect(element, matcher) {
+    collection = [];
+    var recurse = function(subelement){		
+        var nodes = subelement.getChildNodes();
+        map(nodes, function(node){
+            if (matcher(node)) {                
+                extendInstance(node,Element)
+                collection.push(node);
+            }
+            if (node.getFirstChild()) {
+                recurse(node);
+            }
+        });
+    };
+    recurse(element);
+    return collection;
+}
 
 PeriodicalExecuter = function (callback, frequency) {
         setTimeout(callback, frequency *1000);
         setTimeout(function() { new PeriodicalExecuter(callback,frequency); }, frequency*1000);
-};
+};
\ No newline at end of file</diff>
      <filename>generators/facebook/templates/public/javascripts/facebooker.js</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>ae6030b5582bc5f1170f786ee002232d65d01902</id>
    </parent>
  </parents>
  <author>
    <name>Joseph Sofaer</name>
    <email>joseph.sofaer@gmail.com</email>
  </author>
  <url>http://github.com/mmangino/facebooker/commit/708056b949c2c45ef6505ee38accf30dbe4835b1</url>
  <id>708056b949c2c45ef6505ee38accf30dbe4835b1</id>
  <committed-date>2009-10-01T12:23:02-07:00</committed-date>
  <authored-date>2009-10-01T12:23:02-07:00</authored-date>
  <message>Enhance facebooker.js, Prototype style ajax methods, var Element functions, getElementsByName, getElementsByClass, FB confirmation dialog</message>
  <tree>4752367f6ea596faede04930022bcb35ab253715</tree>
  <committer>
    <name>Joseph Sofaer</name>
    <email>joseph.sofaer@gmail.com</email>
  </committer>
</commit>
