Skip to content
This repository
Browse code

attempt to agaxify some links, work in progress

  • Loading branch information...
commit 4f0d177084cf38c6f9edb0f265ec59b9d2647d81 1 parent 3ae06c4
Dmitry Amelchenko authored December 23, 2009
5  app/controllers/conversations_controller.rb
@@ -272,7 +272,10 @@ def toogle_bookmark
272 272
     else
273 273
       current_user.tag(@conversation, :with => @conversation.bookmarks.collect{|tag| tag.name}.join(", ")  + ", " + current_user.bookmark_tag, :on => :bookmarks)
274 274
     end
275  
-    redirect_to :back    
  275
+    respond_to do |format|
  276
+      format.html { redirect_to :back }   
  277
+      format.js 
  278
+    end
276 279
   end
277 280
 
278 281
   #----------------------------------------------------------------------------
2  app/views/conversations/_star.html.erb
... ...
@@ -1,3 +1,3 @@
1 1
 <% if logged_in? %>
2  
-<%= link_to image_tag(conversation.bookmark_list.include?(current_user.bookmark_tag) ? "/images/icons/star.png" : "/images/icons/star_empty.png"), toogle_bookmark_conversation_path(conversation), :method => :put %>
  2
+	<%= link_to image_tag(conversation.bookmark_list.include? (current_user.bookmark_tag) ? "/images/icons/star.png" : "/images/icons/star_empty.png"), toogle_bookmark_conversation_path(conversation), :method => :post, :class => "togglable_bookmark", :id => 'togglable' + dom_id(conversation) %>
3 3
 <%end%>
3  app/views/conversations/index.html.erb
... ...
@@ -1,3 +1,6 @@
  1
+<%= javascript_include_tag 'jquery', 'jquery.form', 'conversations' %> 	
  2
+
  3
+
1 4
 <% content_for :header do %>
2 5
 	<%= tag(:link, :rel => "alternate",
3 6
 	:type => "application/atom+xml",
1  app/views/conversations/toogle_bookmark.js.erb
... ...
@@ -0,0 +1 @@
  1
+alert("hohoho");
2  config/routes.rb
@@ -23,7 +23,7 @@
23 23
   map.resources :conversations, :collection => {:bookmarked => :get, :new_messages => :get}, :member => {
24 24
     :toogle_private_status   => :put,
25 25
     :toogle_readwrite_status => :put,
26  
-    :toogle_bookmark         => :put,
  26
+    :toogle_bookmark         => :post,
27 27
     :follow                  => :post,
28 28
     :follow_with_token       => :get,
29 29
     :follow_email_with_token => :get,
17  public/javascripts/conversations.js
... ...
@@ -0,0 +1,17 @@
  1
+jQuery.noConflict();
  2
+// public/javascripts/application.js
  3
+jQuery.ajaxSetup({ 
  4
+  'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
  5
+})
  6
+
  7
+
  8
+jQuery(document).ready(function() {
  9
+    jQuery(".togglable_bookmark").bind('click', function(event) {
  10
+        event.preventDefault();		
  11
+        var convo_id = jQuery(this).attr('id').split('_')[1];
  12
+        // alert('/conversations/' + convo_id + '/toogle_bookmark');
  13
+        jQuery.post('/conversations/' + convo_id + '/toogle_bookmark', null, null, 'script');
  14
+        return false;
  15
+    })
  16
+})
  17
+
298  public/javascripts/jquery-ui.js
298 additions, 0 deletions not shown
386  public/javascripts/jquery.autocomplete.js
... ...
@@ -0,0 +1,386 @@
  1
+/*
  2
+*  Ajax Autocomplete for jQuery, version 1.1
  3
+*  (c) 2009 Tomas Kirda
  4
+*
  5
+*  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
  6
+*  For details, see the web site: http://www.devbridge.com/projects/autocomplete/jquery/
  7
+*
  8
+*  Last Review: 09/27/2009
  9
+*/
  10
+
  11
+/*jslint onevar: true, evil: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true */
  12
+/*global window: true, document: true, clearInterval: true, setInterval: true, jQuery: true */
  13
+
  14
+(function($) {
  15
+
  16
+  var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g');
  17
+
  18
+  function fnFormatResult(value, data, currentValue) {
  19
+    var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')';
  20
+    return value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
  21
+  }
  22
+
  23
+  function Autocomplete(el, options) {
  24
+    this.el = $(el);
  25
+    this.el.attr('autocomplete', 'off');
  26
+    this.suggestions = [];
  27
+    this.data = [];
  28
+    this.badQueries = [];
  29
+    this.selectedIndex = -1;
  30
+    this.currentValue = this.el.val();
  31
+    this.intervalId = 0;
  32
+    this.cachedResponse = [];
  33
+    this.onChangeInterval = null;
  34
+    this.ignoreValueChange = false;
  35
+    this.serviceUrl = options.serviceUrl;
  36
+    this.isLocal = false;
  37
+    this.options = {
  38
+      autoSubmit: false,
  39
+      minChars: 1,
  40
+      maxHeight: 300,
  41
+      deferRequestBy: 0,
  42
+      width: 0,
  43
+      highlight: true,
  44
+      params: {},
  45
+      fnFormatResult: fnFormatResult,
  46
+      delimiter: null,
  47
+      zIndex: 9999
  48
+    };
  49
+    this.initialize();
  50
+    this.setOptions(options);
  51
+  }
  52
+
  53
+  $.fn.autocomplete = function(options) {
  54
+    return new Autocomplete(this.get(0), options);
  55
+  };
  56
+
  57
+
  58
+  Autocomplete.prototype = {
  59
+
  60
+    killerFn: null,
  61
+
  62
+    initialize: function() {
  63
+
  64
+      var me, uid, autocompleteElId;
  65
+      me = this;
  66
+      uid = new Date().getTime();
  67
+      autocompleteElId = 'Autocomplete_' + uid;
  68
+
  69
+      this.killerFn = function(e) {
  70
+        if ($(e.target).parents('.autocomplete').size() === 0) {
  71
+          me.killSuggestions();
  72
+          me.disableKillerFn();
  73
+        }
  74
+      };
  75
+
  76
+      if (!this.options.width) { this.options.width = this.el.width(); }
  77
+      this.mainContainerId = 'AutocompleteContainter_' + uid;
  78
+
  79
+      $('<div id="' + this.mainContainerId + '" style="position:absolute;z-index:9999;"><div class="autocomplete-w1"><div class="autocomplete" id="' + autocompleteElId + '" style="display:none; width:300px;"></div></div></div>').appendTo('body');
  80
+
  81
+      this.container = $('#' + autocompleteElId);
  82
+      this.fixPosition();
  83
+      if (window.opera) {
  84
+        this.el.keypress(function(e) { me.onKeyPress(e); });
  85
+      } else {
  86
+        this.el.keydown(function(e) { me.onKeyPress(e); });
  87
+      }
  88
+      this.el.keyup(function(e) { me.onKeyUp(e); });
  89
+      this.el.blur(function() { me.enableKillerFn(); });
  90
+      this.el.focus(function() { me.fixPosition(); });
  91
+    },
  92
+
  93
+    setOptions: function(options){
  94
+      var o = this.options;
  95
+      $.extend(o, options);
  96
+      if(o.lookup){
  97
+        this.isLocal = true;
  98
+        if($.isArray(o.lookup)){ o.lookup = { suggestions:o.lookup, data:[] }; }
  99
+      }
  100
+      $('#'+this.mainContainerId).css({ zIndex:o.zIndex });
  101
+      this.container.css({ maxHeight: o.maxHeight + 'px', width:o.width });
  102
+    },
  103
+
  104
+    clearCache: function(){
  105
+      this.cachedResponse = [];
  106
+      this.badQueries = [];
  107
+    },
  108
+
  109
+    disable: function(){
  110
+      this.disabled = true;
  111
+    },
  112
+
  113
+    enable: function(){
  114
+      this.disabled = false;
  115
+    },
  116
+
  117
+    fixPosition: function() {
  118
+      var offset = this.el.offset();
  119
+      $('#' + this.mainContainerId).css({ top: (offset.top + this.el.innerHeight()) + 'px', left: offset.left + 'px' });
  120
+    },
  121
+
  122
+    enableKillerFn: function() {
  123
+      var me = this;
  124
+      $(document).bind('click', me.killerFn);
  125
+    },
  126
+
  127
+    disableKillerFn: function() {
  128
+      var me = this;
  129
+      $(document).unbind('click', me.killerFn);
  130
+    },
  131
+
  132
+    killSuggestions: function() {
  133
+      var me = this;
  134
+      this.stopKillSuggestions();
  135
+      this.intervalId = window.setInterval(function() { me.hide(); me.stopKillSuggestions(); }, 300);
  136
+    },
  137
+
  138
+    stopKillSuggestions: function() {
  139
+      window.clearInterval(this.intervalId);
  140
+    },
  141
+
  142
+    onKeyPress: function(e) {
  143
+      if (this.disabled || !this.enabled) { return; }
  144
+      // return will exit the function
  145
+      // and event will not be prevented
  146
+      switch (e.keyCode) {
  147
+        case 27: //KEY_ESC:
  148
+          this.el.val(this.currentValue);
  149
+          this.hide();
  150
+          break;
  151
+        case 9: //KEY_TAB:
  152
+        case 13: //KEY_RETURN:
  153
+          if (this.selectedIndex === -1) {
  154
+            this.hide();
  155
+            return;
  156
+          }
  157
+          this.select(this.selectedIndex);
  158
+          if (e.keyCode === 9/* KEY_TAB */) { return; }
  159
+          break;
  160
+        case 38: //KEY_UP:
  161
+          this.moveUp();
  162
+          break;
  163
+        case 40: //KEY_DOWN:
  164
+          this.moveDown();
  165
+          break;
  166
+        default:
  167
+          return;
  168
+      }
  169
+      e.stopImmediatePropagation();
  170
+      e.preventDefault();
  171
+    },
  172
+
  173
+    onKeyUp: function(e) {
  174
+      if(this.disabled){ return; }
  175
+      switch (e.keyCode) {
  176
+        case 38: //KEY_UP:
  177
+        case 40: //KEY_DOWN:
  178
+          return;
  179
+      }
  180
+      clearInterval(this.onChangeInterval);
  181
+      if (this.currentValue !== this.el.val()) {
  182
+        if (this.options.deferRequestBy > 0) {
  183
+          // Defer lookup in case when value changes very quickly:
  184
+          var me = this;
  185
+          this.onChangeInterval = setInterval(function() { me.onValueChange(); }, this.options.deferRequestBy);
  186
+        } else {
  187
+          this.onValueChange();
  188
+        }
  189
+      }
  190
+    },
  191
+
  192
+    onValueChange: function() {
  193
+      clearInterval(this.onChangeInterval);
  194
+      this.currentValue = this.el.val();
  195
+      var q = this.getQuery(this.currentValue);
  196
+      this.selectedIndex = -1;
  197
+      if (this.ignoreValueChange) {
  198
+        this.ignoreValueChange = false;
  199
+        return;
  200
+      }
  201
+      if (q === '' || q.length < this.options.minChars) {
  202
+        this.hide();
  203
+      } else {
  204
+        this.getSuggestions(q);
  205
+      }
  206
+    },
  207
+
  208
+    getQuery: function(val) {
  209
+      var d, arr;
  210
+      d = this.options.delimiter;
  211
+      if (!d) { return $.trim(val); }
  212
+      arr = val.split(d);
  213
+      return $.trim(arr[arr.length - 1]);
  214
+    },
  215
+
  216
+    getSuggestionsLocal: function(q) {
  217
+      var ret, arr, len, val, i;
  218
+      arr = this.options.lookup;
  219
+      len = arr.suggestions.length;
  220
+      ret = { suggestions:[], data:[] };
  221
+      q = q.toLowerCase();
  222
+      for(i=0; i< len; i++){
  223
+        val = arr.suggestions[i];
  224
+        if(val.toLowerCase().indexOf(q) === 0){
  225
+          ret.suggestions.push(val);
  226
+          ret.data.push(arr.data[i]);
  227
+        }
  228
+      }
  229
+      return ret;
  230
+    },
  231
+
  232
+    getSuggestions: function(q) {
  233
+      var cr, me;
  234
+      cr = this.isLocal ? this.getSuggestionsLocal(q) : this.cachedResponse[q];
  235
+      if (cr && $.isArray(cr.suggestions)) {
  236
+        this.suggestions = cr.suggestions;
  237
+        this.data = cr.data;
  238
+        this.suggest();
  239
+      } else if (!this.isBadQuery(q)) {
  240
+        me = this;
  241
+        me.options.params.query = q;
  242
+        $.get(this.serviceUrl, me.options.params, function(txt) { me.processResponse(txt); }, 'text');
  243
+      }
  244
+    },
  245
+
  246
+    isBadQuery: function(q) {
  247
+      var i = this.badQueries.length;
  248
+      while (i--) {
  249
+        if (q.indexOf(this.badQueries[i]) === 0) { return true; }
  250
+      }
  251
+      return false;
  252
+    },
  253
+
  254
+    hide: function() {
  255
+      this.enabled = false;
  256
+      this.selectedIndex = -1;
  257
+      this.container.hide();
  258
+    },
  259
+
  260
+    suggest: function() {
  261
+      if (this.suggestions.length === 0) {
  262
+        this.hide();
  263
+        return;
  264
+      }
  265
+
  266
+      var me, len, div, f, v, i, s, mOver, mClick;
  267
+      me = this;
  268
+      len = this.suggestions.length;
  269
+      f = this.options.fnFormatResult;
  270
+      v = this.getQuery(this.currentValue);
  271
+      mOver = function(xi) { return function() { me.activate(xi); }; };
  272
+      mClick = function(xi) { return function() { me.select(xi); }; };
  273
+      this.container.hide().empty();
  274
+      for (i = 0; i < len; i++) {
  275
+        s = this.suggestions[i];
  276
+        div = $((me.selectedIndex === i ? '<div class="selected"' : '<div') + ' title="' + s + '">' + f(s, this.data[i], v) + '</div>');
  277
+        div.mouseover(mOver(i));
  278
+        div.click(mClick(i));
  279
+        this.container.append(div);
  280
+      }
  281
+      this.enabled = true;
  282
+      this.container.show();
  283
+    },
  284
+
  285
+    processResponse: function(text) {
  286
+      var response;
  287
+      try {
  288
+        response = eval('(' + text + ')');
  289
+      } catch (err) { return; }
  290
+      if (!$.isArray(response.data)) { response.data = []; }
  291
+      this.cachedResponse[response.query] = response;
  292
+      if (response.suggestions.length === 0) { this.badQueries.push(response.query); }
  293
+      if (response.query === this.getQuery(this.currentValue)) {
  294
+        this.suggestions = response.suggestions;
  295
+        this.data = response.data;
  296
+        this.suggest();
  297
+      }
  298
+    },
  299
+
  300
+    activate: function(index) {
  301
+      var divs, activeItem;
  302
+      divs = this.container.children();
  303
+      // Clear previous selection:
  304
+      if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
  305
+        $(divs.get(this.selectedIndex)).attr('class', '');
  306
+      }
  307
+      this.selectedIndex = index;
  308
+      if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
  309
+        activeItem = divs.get(this.selectedIndex);
  310
+        $(activeItem).attr('class', 'selected');
  311
+      }
  312
+      return activeItem;
  313
+    },
  314
+
  315
+    deactivate: function(div, index) {
  316
+      div.className = '';
  317
+      if (this.selectedIndex === index) { this.selectedIndex = -1; }
  318
+    },
  319
+
  320
+    select: function(i) {
  321
+      var selectedValue, f;
  322
+      selectedValue = this.suggestions[i];
  323
+      if (selectedValue) {
  324
+        this.el.val(selectedValue);
  325
+        if (this.options.autoSubmit) {
  326
+          f = this.el.parents('form');
  327
+          if (f.length > 0) { f.get(0).submit(); }
  328
+        }
  329
+        this.ignoreValueChange = true;
  330
+        this.hide();
  331
+        this.onSelect(i);
  332
+      }
  333
+    },
  334
+
  335
+    moveUp: function() {
  336
+      if (this.selectedIndex === -1) { return; }
  337
+      if (this.selectedIndex === 0) {
  338
+        this.container.children().get(0).className = '';
  339
+        this.selectedIndex = -1;
  340
+        this.el.val(this.currentValue);
  341
+        return;
  342
+      }
  343
+      this.adjustScroll(this.selectedIndex - 1);
  344
+    },
  345
+
  346
+    moveDown: function() {
  347
+      if (this.selectedIndex === (this.suggestions.length - 1)) { return; }
  348
+      this.adjustScroll(this.selectedIndex + 1);
  349
+    },
  350
+
  351
+    adjustScroll: function(i) {
  352
+      var activeItem, offsetTop, upperBound, lowerBound;
  353
+      activeItem = this.activate(i);
  354
+      offsetTop = activeItem.offsetTop;
  355
+      upperBound = this.container.scrollTop();
  356
+      lowerBound = upperBound + this.options.maxHeight - 25;
  357
+      if (offsetTop < upperBound) {
  358
+        this.container.scrollTop(offsetTop);
  359
+      } else if (offsetTop > lowerBound) {
  360
+        this.container.scrollTop(offsetTop - this.options.maxHeight + 25);
  361
+      }
  362
+      //this.el.val(this.suggestions[i]);
  363
+    },
  364
+
  365
+    onSelect: function(i) {
  366
+      var me, onSelect, getValue, s, d;
  367
+      me = this;
  368
+      onSelect = me.options.onSelect;
  369
+      getValue = function(value) {
  370
+        var del, currVal, arr;
  371
+        del = me.options.delimiter;
  372
+        if (!del) { return value; }
  373
+        currVal = me.currentValue;
  374
+        arr = currVal.split(del);
  375
+        if (arr.length === 1) { return value; }
  376
+        return currVal.substr(0, currVal.length - arr[arr.length - 1].length) + value;
  377
+      };
  378
+      s = me.suggestions[i];
  379
+      d = me.data[i];
  380
+      me.el.val(getValue(s));
  381
+      if ($.isFunction(onSelect)) { onSelect(s, d); }
  382
+    }
  383
+
  384
+  };
  385
+
  386
+}(jQuery));
10  public/javascripts/jquery.bgiframe.min.js
... ...
@@ -0,0 +1,10 @@
  1
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
  2
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
  3
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
  4
+ *
  5
+ * $LastChangedDate: 2007-06-19 20:25:28 -0500 (Tue, 19 Jun 2007) $
  6
+ * $Rev: 2111 $
  7
+ *
  8
+ * Version 2.1
  9
+ */
  10
+(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&parseInt($.browser.version)<=6){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};if(!$.browser.version)$.browser.version=navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1];})(jQuery);
96  public/javascripts/jquery.cookie.js
... ...
@@ -0,0 +1,96 @@
162  public/javascripts/jquery.dependent.js
... ...
@@ -0,0 +1,162 @@
  1
+/********************************************************************
  2
+ * jQuery Dependent Select plug-in									*
  3
+ *																	* 
  4
+ * @version		2.5													*
  5
+ * @copyright	(c) Bau Alexandru 2009 								*
  6
+ * @author 		Bau Alexandru										*
  7
+ * @email		bau.alexandru@gmail.com								*
  8
+ *																	*
  9
+ * @depends		jQuery									            *
  10
+ * 																	*
  11
+ * 																	*
  12
+ * Do not delete or modify this header!								*
  13
+ *																	* 
  14
+ * 																	*
  15
+ * Plugin call example:												*
  16
+ * 																	*
  17
+ * jQuery(function($){												*
  18
+ *																	* 
  19
+ *		SINGLE CHILD												*
  20
+ *		$('#child_id').dependent({							        *
  21
+ *			parent:	'parent_id',									*
  22
+ *			group:	'common_class'									*
  23
+ *		});															*
  24
+ *																	* 
  25
+ *		MULTIPLE CHILDS												*
  26
+ *		$('#child_id').dependent({							        *
  27
+ *			parent:	'parent_id' 									*
  28
+ *		});															*
  29
+ *																	*
  30
+ *	});																*
  31
+ *																	*
  32
+ ********************************************************************/
  33
+
  34
+(function($){	// create closure
  35
+	
  36
+	/**
  37
+	 * Plug-in initialization
  38
+	 * @param	object	plug-in options
  39
+	 * @return 	object	this
  40
+	 */
  41
+	$.fn.dependent = function(settings){
  42
+		// merge default settings with dynamic settings
  43
+		$param = $.extend({}, $.fn.dependent.defaults, settings);
  44
+		
  45
+		this.each(function(){														// for each element
  46
+			$this = $(this);														// current element object
  47
+			
  48
+			var $parent 	= '#'+$param.parent;
  49
+			
  50
+			var $child	 	= $this;
  51
+			var $child_id 	= $($child).attr('id');
  52
+			var $child_cls 	= '.'+$child_id;
  53
+			
  54
+			if( $param.group != '' ){
  55
+				var $group	 	= '.'+$param.group;
  56
+			}
  57
+			
  58
+			var $index 		= 0;
  59
+			var $holder  	= 'dpslctholder';
  60
+			var $holder_cls	= '.'+$holder;
  61
+			
  62
+			_createHolder($holder, $holder_cls, $child, $child_id, $child_cls);
  63
+			
  64
+			// check if parent allready has an option selected
  65
+			if( $($parent).val() != 0 ) {
  66
+				$title = $($parent).find('option:selected').attr('title');
  67
+				$($child).find('option[class!='+$title+']').remove();
  68
+				$($child).prepend('<option value="">-- select --</option>');
  69
+			} else {
  70
+				// remove the child's options and add a default option
  71
+				$($child).find('option').remove();
  72
+				$($child).append('<option value="">-- select --</option>');
  73
+			}
  74
+			
  75
+			_parentChange($parent, $child, $group, $holder_cls, $child_cls);
  76
+			
  77
+		});
  78
+			
  79
+		return this;
  80
+	};
  81
+	
  82
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  83
+	
  84
+	/*********************************
  85
+	 * BEGIN PLUG-IN PRIVATE METHODS *
  86
+	 *********************************/
  87
+	
  88
+	/**
  89
+	 * Private function description
  90
+	 */
  91
+	 
  92
+	function _createHolder($holder, $holder_cls, $child, $child_id, $child_cls){
  93
+		
  94
+		// create a select to hold the options from all this child
  95
+		var $is_created = $($holder_cls+' '+$child_id).size();
  96
+		
  97
+		if( $is_created == 0 ){
  98
+			$('body').append('\n\n<select class="'+$holder+' '+$child_id+'" style="display:none">\n</select>\n');
  99
+		}
  100
+		
  101
+		// add options to the holder
  102
+		$($child).find('option[value!=]').each(function(){
  103
+			
  104
+			$value = $(this).attr('value');
  105
+			$class = $(this).attr('class');
  106
+			$title = $(this).attr('title');
  107
+			$text  = $(this).text();
  108
+			
  109
+			$($holder_cls+$child_cls).append('<option value="'+$value+'" class="'+$class+'" title="'+$title+'">'+$text+'</option>\n');
  110
+		});
  111
+		
  112
+	}
  113
+	
  114
+	function _parentChange($parent, $child, $group, $holder_cls, $child_cls){
  115
+		
  116
+		// on change event
  117
+		$($parent).bind('change', function(){
  118
+										   
  119
+			// remove all the child's options
  120
+			$($child).find('option[value!=]').remove();
  121
+			
  122
+			$index = $($group).index($(this))
  123
+			// set all the selects from the group to the default option
  124
+			if( $param.group != '' ){
  125
+				$($group+':gt('+ $index +')').find('option[value!=]').remove();
  126
+			}
  127
+			
  128
+			$title = $(this).find('option:selected').attr('title');
  129
+			// add options to the child mask from the holder
  130
+			$($holder_cls+$child_cls).find('option[class='+$title+']').each(function(){
  131
+																		  
  132
+				$value = $(this).attr('value');
  133
+				$class = $(this).attr('class');
  134
+				$title = $(this).attr('title');
  135
+				$text  = $(this).attr('text');
  136
+																		  
  137
+				$($child).append('<option value="'+$value+'" class="'+$class+'" title="'+$title+'">'+$text+'</option>');
  138
+			});
  139
+			
  140
+		});
  141
+		
  142
+	}
  143
+	
  144
+	/********************************
  145
+	 * /END PLUG-IN PRIVATE METHODS *
  146
+	 ********************************/
  147
+	
  148
+	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149
+	
  150
+	/************************************
  151
+	 * BEGIN PLUG-IN DEFAULT PARAMETERS *
  152
+	 ************************************/
  153
+	
  154
+	$.fn.dependent.defaults = {	
  155
+		parent:		'parent_id'
  156
+	};
  157
+	
  158
+	/***********************************
  159
+	 * /END PLUG-IN DEFAULT PARAMETERS *
  160
+	 ***********************************/
  161
+	
  162
+})(jQuery);		// end closure
161  public/javascripts/jquery.editable-1.3.3.js
... ...
@@ -0,0 +1,161 @@
  1
+(function($){
  2
+/*
  3
+ * Editable 1.3.3
  4
+ *
  5
+ * Copyright (c) 2009 Arash Karimzadeh (arashkarimzadeh.com)
  6
+ * Licensed under the MIT (MIT-LICENSE.txt)
  7
+ * http://www.opensource.org/licenses/mit-license.php
  8
+ *
  9
+ * Date: Mar 02 2009
  10
+ */
  11
+$.fn.editable = function(options){
  12
+	var defaults = {
  13
+		onEdit: null,
  14
+		onSubmit: null,
  15
+		onCancel: null,
  16
+		editClass: null,
  17
+		submit: null,
  18
+		cancel: null,
  19
+		type: 'text', //text, textarea or select
  20
+		submitBy: 'blur', //blur,change,dblclick,click
  21
+		editBy: 'click',
  22
+		options: null
  23
+	}
  24
+	if(options=='disable')
  25
+		return this.unbind(this.data('editable.options').editBy,this.data('editable.options').toEditable);
  26
+	if(options=='enable')
  27
+		return this.bind(this.data('editable.options').editBy,this.data('editable.options').toEditable);
  28
+	if(options=='destroy')
  29
+		return  this.unbind(this.data('editable.options').editBy,this.data('editable.options').toEditable)
  30
+					.data('editable.previous',null)
  31
+					.data('editable.current',null)
  32
+					.data('editable.options',null);
  33
+	
  34
+	var options = $.extend(defaults, options);
  35
+	
  36
+	options.toEditable = function(){
  37
+		$this = $(this);
  38
+		$this.data('editable.current',$this.html());
  39
+		opts = $this.data('editable.options');
  40
+		$.editableFactory[opts.type].toEditable($this.empty(),opts);
  41
+		// Configure events,styles for changed content
  42
+		$this.data('editable.previous',$this.data('editable.current'))
  43
+			 .children()
  44
+				 .focus()
  45
+				 .addClass(opts.editClass);
  46
+		// Submit Event
  47
+		if(opts.submit){
  48
+			$('<button/>').appendTo($this)
  49
+						.html(opts.submit)
  50
+						.one('mouseup',function(){opts.toNonEditable($(this).parent(),true)});
  51
+		}else
  52
+			$this.one(opts.submitBy,function(){opts.toNonEditable($(this),true)})
  53
+				 .children()
  54
+				 	.one(opts.submitBy,function(){opts.toNonEditable($(this).parent(),true)});
  55
+		// Cancel Event
  56
+		if(opts.cancel)
  57
+			$('<button/>').appendTo($this)
  58
+						.html(opts.cancel)
  59
+						.one('mouseup',function(){opts.toNonEditable($(this).parent(),false)});
  60
+		// Call User Function
  61
+		if($.isFunction(opts.onEdit))
  62
+			opts.onEdit.apply(	$this,
  63
+									[{
  64
+										current:$this.data('editable.current'),
  65
+										previous:$this.data('editable.previous')
  66
+									}]
  67
+								);
  68
+	}
  69
+	options.toNonEditable = function($this,change){
  70
+		opts = $this.data('editable.options');
  71
+		// Configure events,styles for changed content
  72
+		$this.one(opts.editBy,opts.toEditable)
  73
+			 .data( 'editable.current',
  74
+				    change 
  75
+						?$.editableFactory[opts.type].getValue($this,opts)
  76
+						:$this.data('editable.current')
  77
+					)
  78
+			 .html(
  79
+				    opts.type=='password'
  80
+				   		?'*****'
  81
+						:$this.data('editable.current')
  82
+					);
  83
+		// Call User Function
  84
+		var func = null;
  85
+		if($.isFunction(opts.onSubmit)&&change==true)
  86
+			func = opts.onSubmit;
  87
+		else if($.isFunction(opts.onCancel)&&change==false)
  88
+			func = opts.onCancel;
  89
+		if(func!=null)
  90
+			func.apply($this,
  91
+						[{
  92
+							current:$this.data('editable.current'),
  93
+							previous:$this.data('editable.previous')
  94
+						}]
  95
+					);
  96
+	}
  97
+	this.data('editable.options',options);
  98
+	return  this.one(options.editBy,options.toEditable);
  99
+}
  100
+$.editableFactory = {
  101
+	'text': {
  102
+		toEditable: function($this,options){
  103
+			$('<input/>').appendTo($this)
  104
+						 .val($this.data('editable.current'));
  105
+		},
  106
+		getValue: function($this,options){
  107
+			return $this.children().val();
  108
+		}
  109
+	},
  110
+	'password': {
  111
+		toEditable: function($this,options){
  112
+			$this.data('editable.current',$this.data('editable.password'));
  113
+			$this.data('editable.previous',$this.data('editable.password'));
  114
+			$('<input type="password"/>').appendTo($this)
  115
+										 .val($this.data('editable.current'));
  116
+		},
  117
+		getValue: function($this,options){
  118
+			$this.data('editable.password',$this.children().val());
  119
+			return $this.children().val();
  120
+		}
  121
+	},
  122
+	'textarea': {
  123
+		toEditable: function($this,options){
  124
+			$('<textarea/>').appendTo($this)
  125
+							.val($this.data('editable.current'));
  126
+		},
  127
+		getValue: function($this,options){
  128
+			return $this.children().val();
  129
+		}
  130
+	},
  131
+	'select': {
  132
+		toEditable: function($this,options){
  133
+			$select = $('<select/>').appendTo($this);
  134
+			$.each( options.options,
  135
+					function(key,value){
  136
+						$('<option/>').appendTo($select)
  137
+									.html(value)
  138
+									.attr('value',key);
  139
+					}
  140
+				   )
  141
+			$select.children().each(
  142
+				function(){
  143
+					var opt = $(this);
  144
+					if(opt.text()==$this.data('editable.current'))
  145
+						return opt.attr('selected', 'selected').text();
  146
+				}
  147
+			)
  148
+		},
  149
+		getValue: function($this,options){
  150
+			var item = null;
  151
+			$('select', $this).children().each(
  152
+				function(){
  153
+					if($(this).attr('selected'))
  154
+						return item = $(this).text();
  155
+				}
  156
+			)
  157
+			return item;
  158
+		}
  159
+	}
  160
+}
  161
+})(jQuery);
19  public/javascripts/jquery.editinplace.packed.js
... ...
@@ -0,0 +1,19 @@
  1
+/*
  2
+ * Another In Place Editor - a jQuery edit in place plugin
  3
+ *
  4
+ * Copyright (c) 2009 Dave Hauenstein
  5
+ *
  6
+ * License:
  7
+ * This source file is subject to the BSD license bundled with this package.
  8
+ * Available online: {@link http://www.opensource.org/licenses/bsd-license.php}
  9
+ * If you did not receive a copy of the license, and are unable to obtain it,
  10
+ * email davehauenstein@gmail.com,
  11
+ * and I will send you a copy.
  12
+ *
  13
+ * Project home:
  14
+ * http://code.google.com/p/jquery-in-place-editor/
  15
+ *
  16
+ * Version 1.0.1
  17
+ *
  18
+ */
  19
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('6.1w.1x=7(q){2 r={T:"",w:"",G:"x",16:"",17:"25",18:"10",19:"#1y",H:"1z",1a:"1b...",B:"",I:"(1A 1B J 1C x)",1c:"1D 1d u",1e:U,V:"V",W:"W",X:"X",1f:\'<K y="1g">1E</K>\',1h:\'<K y="1i">1F</K>\',Y:t,1j:"C",Z:U,L:U,M:7(a){11("1k J C u: "+a.1G||\'1H 1l\')}};3(q){6.1I(r,q)}3(r.B!=""){2 s=1d 1J();s.1m=r.B}1n.1o.D=7(){E 4.z(/^\\s+/,\'\').z(/\\s+$/,\'\')};1n.1o.F=7(){E 4.z(/&/g,"&1K;").z(/</g,"&1L;").z(/>/g,"&1M;").z(/"/g,"&1N;")};E 4.1O(7(){3(6(4).5()=="")6(4).5(r.I);2 n=t;2 o=6(4);2 p=0;6(4).1P(7(){6(4).N("O",r.19)}).1Q(7(){6(4).N("O",r.H)}).12(7(){p++;3(!n){n=1R;2 f=6(4).5();2 g=(r.Y)?r.1f+\' \'+r.1h:\'\';3(f==r.I)6(4).5(\'\');3(r.G=="13"){2 h=\'<13 14="15" y="A" 1S="\'+r.18+\'" 1T="\'+r.17+\'">\'+6(4).x().D().F()+\'</13>\'}v 3(r.G=="x"){2 h=\'<1U 1p="x" 14="15" y="A" u="\'+6(4).x().D().F()+\'" />\'}v 3(r.G=="P"){2 j=r.16.1q(\',\');2 h=\'<P 14="15" y="A"><Q u="">\'+r.1c+\'</Q>\';1V(2 i=0;i<j.1W;i++){2 k=j[i].1q(\':\');2 l=k[1]||k[0];2 m=l==f?\'1r="1r" \':\'\';h+=\'<Q \'+m+\'u="\'+l.D().F()+\'">\'+k[0].D().F()+\'</Q>\'}h+=\'</P>\'}6(4).5(\'<9 y="1X" 1Y="1Z: 20; 21: 0; 22: 0;">\'+h+\' \'+g+\'</9>\')}3(p==1){7 R(){n=t;p=0;o.N("O",r.H);o.5(f);E t}7 S(){o.N("O",r.H);2 c=6(4);2 d=(c.23(\'9\'))?c.8(0).1s():c.24().8(0).1s();3(r.B!=""){2 e=\'<26 1m="\'+r.B+\'" 28="1b..." />\'}v{2 e=r.1a}o.5(e);3(r.w!=""){r.w="&"+r.w}3(r.Z){5=r.Z(o.1t("1u"),d,f,r.w);n=t;p=0;3(5){o.5(5||d)}v{11("1k J C u: "+d);o.5(f)}}v 3(r.1e&&(d==""||d==29)){n=t;p=0;o.5(f);11("1l: 2a 2b 2c a u J C 4 2d")}v{6.2e({T:r.T,1p:"2f",2g:r.W+\'=\'+d+\'&\'+r.V+\'=\'+o.1t("1u")+r.w+\'&\'+r.X+\'=\'+f,2h:"5",2i:7(a){n=t;p=0},L:7(a){2 b=a||r.I;o.5(b);3(r.L)r.L(a,o)},M:7(a){o.5(f);3(r.M)r.M(a,o)}})}E t}o.8("9").8(".A").2j().P();o.8("9").8(".1i").12(R);o.8("9").8(".1g").12(S);3(!r.Y){3(r.1j=="C")o.8("9").8(".A").1v(S);v o.8("9").8(".A").1v(R)}$(2k).2l(7(a){3(a.2m==27){R()}});o.8("9").2n(S)}})})};',62,148,'||var|if|this|html|jQuery|function|children|form||||||||||||||||||||false|value|else|params|text|class|replace|inplace_field|saving_image|save|trim|return|escape_html|field_type|bg_out|default_text|to|button|success|error|css|background|select|option|cancelAction|saveAction|url|null|element_id|update_value|original_html|show_buttons|callback||alert|click|textarea|name|inplace_value|select_options|textarea_cols|textarea_rows|bg_over|saving_text|Saving|select_text|new|value_required|save_button|inplace_save|cancel_button|inplace_cancel|on_blur|Failed|Error|src|String|prototype|type|split|selected|val|attr|id|blur|fn|editInPlace|ffc|transparent|Click|here|add|Choose|Save|Cancel|responseText|Unspecified|extend|Image|amp|lt|gt|quot|each|mouseover|mouseout|true|rows|cols|input|for|length|inplace_form|style|display|inline|margin|padding|is|parent||img||alt|undefined|You|must|enter|field|ajax|POST|data|dataType|complete|focus|document|keyup|keyCode|submit'.split('|'),0,{}))
660  public/javascripts/jquery.form.js
... ...
@@ -0,0 +1,660 @@
  1
+/*
  2
+ * jQuery Form Plugin
  3
+ * version: 2.36 (07-NOV-2009)
  4
+ * @requires jQuery v1.2.6 or later
  5
+ *
  6
+ * Examples and documentation at: http://malsup.com/jquery/form/
  7
+ * Dual licensed under the MIT and GPL licenses:
  8
+ *   http://www.opensource.org/licenses/mit-license.php
  9
+ *   http://www.gnu.org/licenses/gpl.html
  10
+ */
  11
+;(function($) {
  12
+
  13
+/*
  14
+	Usage Note:
  15
+	-----------
  16
+	Do not use both ajaxSubmit and ajaxForm on the same form.  These
  17
+	functions are intended to be exclusive.  Use ajaxSubmit if you want
  18
+	to bind your own submit handler to the form.  For example,
  19
+
  20
+	$(document).ready(function() {
  21
+		$('#myForm').bind('submit', function() {
  22
+			$(this).ajaxSubmit({
  23
+				target: '#output'
  24
+			});
  25
+			return false; // <-- important!
  26
+		});
  27
+	});
  28
+
  29
+	Use ajaxForm when you want the plugin to manage all the event binding
  30
+	for you.  For example,
  31
+
  32
+	$(document).ready(function() {
  33
+		$('#myForm').ajaxForm({
  34
+			target: '#output'
  35
+		});
  36
+	});
  37
+
  38
+	When using ajaxForm, the ajaxSubmit function will be invoked for you
  39
+	at the appropriate time.
  40
+*/
  41
+
  42
+/**
  43
+ * ajaxSubmit() provides a mechanism for immediately submitting
  44
+ * an HTML form using AJAX.
  45
+ */
  46
+$.fn.ajaxSubmit = function(options) {
  47
+	// fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
  48
+	if (!this.length) {
  49
+		log('ajaxSubmit: skipping submit process - no element selected');
  50
+		return this;
  51
+	}
  52
+
  53
+	if (typeof options == 'function')
  54
+		options = { success: options };
  55
+
  56
+	var url = $.trim(this.attr('action'));
  57
+	if (url) {
  58
+		// clean url (don't include hash vaue)
  59
+		url = (url.match(/^([^#]+)/)||[])[1];
  60
+   	}
  61
+   	url = url || window.location.href || '';
  62
+
  63
+	options = $.extend({
  64
+		url:  url,
  65
+		type: this.attr('method') || 'GET',
  66
+		iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
  67
+	}, options || {});
  68
+
  69
+	// hook for manipulating the form data before it is extracted;
  70
+	// convenient for use with rich editors like tinyMCE or FCKEditor
  71
+	var veto = {};
  72
+	this.trigger('form-pre-serialize', [this, options, veto]);
  73
+	if (veto.veto) {
  74
+		log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
  75
+		return this;
  76
+	}
  77
+
  78
+	// provide opportunity to alter form data before it is serialized
  79
+	if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
  80
+		log('ajaxSubmit: submit aborted via beforeSerialize callback');
  81
+		return this;
  82
+	}
  83
+
  84
+	var a = this.formToArray(options.semantic);
  85
+	if (options.data) {
  86
+		options.extraData = options.data;
  87
+		for (var n in options.data) {
  88
+		  if(options.data[n] instanceof Array) {
  89
+			for (var k in options.data[n])
  90
+			  a.push( { name: n, value: options.data[n][k] } );
  91
+		  }
  92
+		  else
  93
+			 a.push( { name: n, value: options.data[n] } );
  94
+		}
  95
+	}
  96
+
  97
+	// give pre-submit callback an opportunity to abort the submit
  98
+	if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
  99
+		log('ajaxSubmit: submit aborted via beforeSubmit callback');
  100
+		return this;
  101
+	}
  102
+
  103
+	// fire vetoable 'validate' event
  104
+	this.trigger('form-submit-validate', [a, this, options, veto]);
  105
+	if (veto.veto) {
  106
+		log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
  107
+		return this;
  108
+	}
  109
+
  110
+	var q = $.param(a);
  111
+
  112
+	if (options.type.toUpperCase() == 'GET') {
  113
+		options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
  114
+		options.data = null;  // data is null for 'get'
  115
+	}
  116
+	else
  117
+		options.data = q; // data is the query string for 'post'
  118
+
  119
+	var $form = this, callbacks = [];
  120
+	if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
  121
+	if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
  122
+
  123
+	// perform a load on the target only if dataType is not provided
  124
+	if (!options.dataType && options.target) {
  125
+		var oldSuccess = options.success || function(){};
  126
+		callbacks.push(function(data) {
  127
+			$(options.target).html(data).each(oldSuccess, arguments);
  128
+		});
  129
+	}
  130
+	else if (options.success)
  131
+		callbacks.push(options.success);
  132
+
  133
+	options.success = function(data, status) {
  134
+		for (var i=0, max=callbacks.length; i < max; i++)
  135
+			callbacks[i].apply(options, [data, status, $form]);
  136
+	};
  137
+
  138
+	// are there files to upload?
  139
+	var files = $('input:file', this).fieldValue();
  140
+	var found = false;
  141
+	for (var j=0; j < files.length; j++)
  142
+		if (files[j])
  143
+			found = true;
  144
+
  145
+	var multipart = false;
  146
+//	var mp = 'multipart/form-data';
  147
+//	multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
  148
+
  149
+	// options.iframe allows user to force iframe mode
  150
+	// 06-NOV-09: now defaulting to iframe mode if file input is detected
  151
+   if ((files.length && options.iframe !== false) || options.iframe || found || multipart) {
  152
+	   // hack to fix Safari hang (thanks to Tim Molendijk for this)
  153
+	   // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
  154
+	   if (options.closeKeepAlive)
  155
+		   $.get(options.closeKeepAlive, fileUpload);
  156
+	   else
  157
+		   fileUpload();
  158
+	   }
  159
+   else
  160
+	   $.ajax(options);
  161
+
  162
+	// fire 'notify' event
  163
+	this.trigger('form-submit-notify', [this, options]);
  164
+	return this;
  165
+
  166
+
  167
+	// private function for handling file uploads (hat tip to YAHOO!)
  168
+	function fileUpload() {
  169
+		var form = $form[0];
  170
+
  171
+		if ($(':input[name=submit]', form).length) {
  172
+			alert('Error: Form elements must not be named "submit".');
  173
+			return;
  174
+		}
  175
+
  176
+		var opts = $.extend({}, $.ajaxSettings, options);
  177
+		var s = $.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
  178
+
  179
+		var id = 'jqFormIO' + (new Date().getTime());
  180
+		var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ opts.iframeSrc +'" />');
  181
+		var io = $io[0];
  182
+
  183
+		$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
  184
+
  185
+		var xhr = { // mock object
  186
+			aborted: 0,
  187
+			responseText: null,
  188
+			responseXML: null,
  189
+			status: 0,
  190
+			statusText: 'n/a',
  191
+			getAllResponseHeaders: function() {},
  192
+			getResponseHeader: function() {},
  193
+			setRequestHeader: function() {},
  194
+			abort: function() {