Changeset 1346
- Timestamp:
- 02/10/08 11:52:39 (5 months ago)
- Files:
-
- mrblog/trunk/app/controllers/admin.rb (modified) (4 diffs)
- mrblog/trunk/app/controllers/blog.rb (modified) (2 diffs)
- mrblog/trunk/app/models/post.rb (modified) (1 diff)
- mrblog/trunk/app/views/admin/show.html.erb (modified) (2 diffs)
- mrblog/trunk/app/views/blog/_comments.html.erb (modified) (1 diff)
- mrblog/trunk/app/views/blog/show.html.erb (modified) (1 diff)
- mrblog/trunk/public/javascripts/prototype.js (modified) (72 diffs)
- mrblog/trunk/schema/migrations/002_create_users.rb (modified) (1 diff)
- mrblog/trunk/schema/migrations/100_add_test_data.rb (modified) (1 diff)
- mrblog/trunk/schema/schema.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
mrblog/trunk/app/controllers/admin.rb
r1343 r1346 5 5 def index 6 6 @pager = ::Paginator.new(Post.count, MrBlog::PER_PAGE) do |offset, per_page| 7 Post.get(:all, :limit => per_page, :offset => offset, :order => 'created_at DESC')8 end9 @page = @pager.page(params[:page])10 render :action => "index"7 Post.get(:all, :limit => per_page, :offset => offset, :order => 'created_at DESC') 8 end 9 @page = @pager.page(params[:page]) 10 render :action => "index" 11 11 end 12 12 … … 17 17 18 18 def update 19 if @post = Post.find(params[: post][:id])19 if @post = Post.find(params[:id]) 20 20 @post.update_attributes(params[:post]) 21 21 redirect "/admin/show/#{@post.id}" … … 26 26 27 27 def show 28 @post = Post.find params[:id]28 @post = Post.find(params[:id]) 29 29 @comments = @post.comments 30 30 render … … 49 49 50 50 def delete_comment 51 Comment.find(params[:id]).destroy 52 redirect "/admin" 51 c = Comment.find(params[:id]) 52 post = c.post 53 c.destroy 54 redirect "/admin/show/#{post.id}" 53 55 end 54 56 end mrblog/trunk/app/controllers/blog.rb
r1343 r1346 2 2 3 3 def show 4 @post = Post.find_by_id params[:id]4 @post = Post.find_by_id(params[:id]) 5 5 if @post.nil? 6 6 redirect_back_or_default("/") 7 7 else 8 8 @comments = @post.comments 9 @comment = @comments.new 10 @user = @post.user 9 11 render 10 12 end … … 14 16 @pager = ::Paginator.new(Post.count, MrBlog::PER_PAGE) do |offset, per_page| 15 17 Post.find(:all, :limit => per_page, :offset => offset) 16 end17 @page = @pager.page(params[:page])18 render :action => "index"18 end 19 @page = @pager.page(params[:page]) 20 render :action => "index" 19 21 end 20 22 21 23 def add_comment 22 @post = Post.find params[:post_id] 23 @post.comments.create(:name => params[:comment_name], 24 :text => params[:comment_text]) 25 @comments = @post.comments.reload 26 render_js 'comments' 24 @post = Post.find(params[:id]) 25 @post.comments.create(params[:comment]) 26 redirect "/blog/show/#{@post.id}" 27 27 end 28 29 def delete_comment30 @post = Post.find params[:post_id]31 @post.comments.destroy params[:id]32 @comments = @post.comments.reload33 render_js 'comments'34 end35 36 28 end mrblog/trunk/app/models/post.rb
r1343 r1346 2 2 belongs_to :user 3 3 has_many :comments 4 5 validates_presence_of :user 4 6 5 7 def self.get(how_many = :all, options = {}) mrblog/trunk/app/views/admin/show.html.erb
r1343 r1346 3 3 <h2><%= @post.title %></h2> 4 4 <div class="maintext"> 5 <%= @post.text%> 5 <%= @post.text%> 6 6 </div> 7 7 8 <% @comments.each do |c| %> 8 9 <div> … … 17 18 <% end %> 18 19 19 20 20 <%= link_to image_tag('edit.gif'), "/admin/edit/#{@post.id}", :class => "button" %> mrblog/trunk/app/views/blog/_comments.html.erb
r1343 r1346 1 1 <% @comments.each do |c| %> 2 <div id='<%= c.id %>'> 3 <p><%= c.name %>: <%= c.text %></p> 2 <div> 3 <p> 4 <b><%= c.name %></b>, on <%= c.created_at.strftime("%B %d, %Y") %> said: <br /> 5 <%= c.text %> <br /> 6 </p> 4 7 </div> 5 8 <% end %> mrblog/trunk/app/views/blog/show.html.erb
r1343 r1346 1 1 <h1><%= @post.title %></h1> 2 <div><%= @post.text%></div> 3 <hr /> 2 <div> 3 <%= @post.text.gsub("\n", "<br />") %> 4 <br /> 5 <b><%= @user.login %></b>, on <%= @post.created_at.strftime("%B %d, %Y") %> 6 <%= @post.updated_at > @post.created_at ? "(edited on #{@post.updated_at.strftime('%B %d, %Y')})" : "" %> 7 </div> 8 <hr /> 4 9 <p>Comments:<%= " None yet" if @comments.empty? %></p> 5 10 <% if !@comments.empty? %> 6 11 <div id='comments'> 7 <%= partial(:comments) %> 12 <%= partial(:comments) %> 8 13 </div> 9 14 <% end %> 10 <div id="comment-form"> 11 <form class="mascot" onsubmit="new Ajax.Request('/blog/add_comment?post_id=<%= @post.id %>', 12 {asynchronous:'true', 13 evalScripts:'true', 14 parameters: Form.serialize(this)}); 15 return false;" method="post" action="/posts/add_comment" id='c-form'> 16 15 <div id="comment-form"> 16 <% form_for :comment, :action => url(:controller => "blog", 17 :action => "add_comment", 18 :id => @post.id) do %> 17 19 <p> 18 <label for="comment_name">Name</label> 19 <input type="text" size="20" name="comment_name" id="comment_name" /> 20 <%= text_control :name, :label => 'Name', :cols => 50 %> 20 21 </p> 21 22 <p> 22 <label for="comment_text">Comment</label> 23 <textarea cols="20" id="comment_text" name="comment_text" rows="8"></textarea> 23 <%= text_area_control :text, :label => 'Text', :rows => 20, :cols => 50 %> 24 24 </p> 25 26 <p class="buttons"> 27 <button name="commit" type="submit" value="Submit" class="imaged">Submit</button> 25 <p class='button'> 26 <%= submit_button(image_tag('save.gif')) %> 28 27 </p> 29 </form> 30 <script type='text/javascript'> 31 Form.reset('c-form'); 32 </script> 28 <% end %> 33 29 </div> mrblog/trunk/public/javascripts/prototype.js
r1294 r1346 1 /* Prototype JavaScript framework, version 1. 5.0_rc12 * (c) 2005 Sam Stephenson <sam@conio.net>1 /* Prototype JavaScript framework, version 1.6.0.2 2 * (c) 2005-2008 Sam Stephenson 3 3 * 4 4 * Prototype is freely distributable under the terms of an MIT-style license. 5 * For details, see the Prototype web site: http:// prototype.conio.net/5 * For details, see the Prototype web site: http://www.prototypejs.org/ 6 6 * 7 /*--------------------------------------------------------------------------*/7 *--------------------------------------------------------------------------*/ 8 8 9 9 var Prototype = { 10 Version: '1.5.0_rc1', 10 Version: '1.6.0.2', 11 12 Browser: { 13 IE: !!(window.attachEvent && !window.opera), 14 Opera: !!window.opera, 15 WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, 16 Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, 17 MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) 18 }, 19 11 20 BrowserFeatures: { 12 XPath: !!document.evaluate 13 }, 14 15 ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', 16 emptyFunction: function() {}, 21 XPath: !!document.evaluate, 22 ElementExtensions: !!window.HTMLElement, 23 SpecificElementExtensions: 24 document.createElement('div').__proto__ && 25 document.createElement('div').__proto__ !== 26 document.createElement('form').__proto__ 27 }, 28 29 ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', 30 JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, 31 32 emptyFunction: function() { }, 17 33 K: function(x) { return x } 18 } 19 34 }; 35 36 if (Prototype.Browser.MobileSafari) 37 Prototype.BrowserFeatures.SpecificElementExtensions = false; 38 39 40 /* Based on Alex Arnell's inheritance implementation. */ 20 41 var Class = { 21 42 create: function() { 22 return function() { 43 var parent = null, properties = $A(arguments); 44 if (Object.isFunction(properties[0])) 45 parent = properties.shift(); 46 47 function klass() { 23 48 this.initialize.apply(this, arguments); 24 49 } 25 } 26 } 27 28 var Abstract = new Object(); 50 51 Object.extend(klass, Class.Methods); 52 klass.superclass = parent; 53 klass.subclasses = []; 54 55 if (parent) { 56 var subclass = function() { }; 57 subclass.prototype = parent.prototype; 58 klass.prototype = new subclass; 59 parent.subclasses.push(klass); 60 } 61 62 for (var i = 0; i < properties.length; i++) 63 klass.addMethods(properties[i]); 64 65 if (!klass.prototype.initialize) 66 klass.prototype.initialize = Prototype.emptyFunction; 67 68 klass.prototype.constructor = klass; 69 70 return klass; 71 } 72 }; 73 74 Class.Methods = { 75 addMethods: function(source) { 76 var ancestor = this.superclass && this.superclass.prototype; 77 var properties = Object.keys(source); 78 79 if (!Object.keys({ toString: true }).length) 80 properties.push("toString", "valueOf"); 81 82 for (var i = 0, length = properties.length; i < length; i++) { 83 var property = properties[i], value = source[property]; 84 if (ancestor && Object.isFunction(value) && 85 value.argumentNames().first() == "$super") { 86 var method = value, value = Object.extend((function(m) { 87 return function() { return ancestor[m].apply(this, arguments) }; 88 })(property).wrap(method), { 89 valueOf: function() { return method }, 90 toString: function() { return method.toString() } 91 }); 92 } 93 this.prototype[property] = value; 94 } 95 96 return this; 97 } 98 }; 99 100 var Abstract = { }; 29 101 30 102 Object.extend = function(destination, source) { 31 for (var property in source) {103 for (var property in source) 32 104 destination[property] = source[property]; 33 }34 105 return destination; 35 } 106 }; 36 107 37 108 Object.extend(Object, { 38 109 inspect: function(object) { 39 110 try { 40 if ( object == undefined) return 'undefined';41 if (object == null) return 'null';42 return object.inspect ? object.inspect() : object.toString();111 if (Object.isUndefined(object)) return 'undefined'; 112 if (object === null) return 'null'; 113 return object.inspect ? object.inspect() : String(object); 43 114 } catch (e) { 44 115 if (e instanceof RangeError) return '...'; 45 116 throw e; 46 117 } 118 }, 119 120 toJSON: function(object) { 121 var type = typeof object; 122 switch (type) { 123 case 'undefined': 124 case 'function': 125 case 'unknown': return; 126 case 'boolean': return object.toString(); 127 } 128 129 if (object === null) return 'null'; 130 if (object.toJSON) return object.toJSON(); 131 if (Object.isElement(object)) return; 132 133 var results = []; 134 for (var property in object) { 135 var value = Object.toJSON(object[property]); 136 if (!Object.isUndefined(value)) 137 results.push(property.toJSON() + ': ' + value); 138 } 139 140 return '{' + results.join(', ') + '}'; 141 }, 142 143 toQueryString: function(object) { 144 return $H(object).toQueryString(); 145 }, 146 147 toHTML: function(object) { 148 return object && object.toHTML ? object.toHTML() : String.interpret(object); 47 149 }, 48 150 … … 62 164 63 165 clone: function(object) { 64 return Object.extend({}, object); 166 return Object.extend({ }, object); 167 }, 168 169 isElement: function(object) { 170 return object && object.nodeType == 1; 171 }, 172 173 isArray: function(object) { 174 return object != null && typeof object == "object" && 175 'splice' in object && 'join' in object; 176 }, 177 178 isHash: function(object) { 179 return object instanceof Hash; 180 }, 181 182 isFunction: function(object) { 183 return typeof object == "function"; 184 }, 185 186 isString: function(object) { 187 return typeof object == "string"; 188 }, 189 190 isNumber: function(object) { 191 return typeof object == "number"; 192 }, 193 194 isUndefined: function(object) { 195 return typeof object == "undefined"; 65 196 } 66 197 }); 67 198 68 Function.prototype.bind = function() { 69 var __method = this, args = $A(arguments), object = args.shift(); 70 return function() { 71 return __method.apply(object, args.concat($A(arguments))); 72 } 73 } 74 75 Function.prototype.bindAsEventListener = function(object) { 76 var __method = this, args = $A(arguments), object = args.shift(); 77 return function(event) { 78 return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); 79 } 80 } 81 82 Object.extend(Number.prototype, { 83 toColorPart: function() { 84 var digits = this.toString(16); 85 if (this < 16) return '0' + digits; 86 return digits; 87 }, 88 89 succ: function() { 90 return this + 1; 91 }, 92 93 times: function(iterator) { 94 $R(0, this, true).each(iterator); 95 return this; 199 Object.extend(Function.prototype, { 200 argumentNames: function() { 201 var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); 202 return names.length == 1 && !names[0] ? [] : names; 203 }, 204 205 bind: function() { 206 if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; 207 var __method = this, args = $A(arguments), object = args.shift(); 208 return function() { 209 return __method.apply(object, args.concat($A(arguments))); 210 } 211 }, 212 213 bindAsEventListener: function() { 214 var __method = this, args = $A(arguments), object = args.shift(); 215 return function(event) { 216 return __method.apply(object, [event || window.event].concat(args)); 217 } 218 }, 219 220 curry: function() { 221 if (!arguments.length) return this; 222 var __method = this, args = $A(arguments); 223 return function() { 224 return __method.apply(this, args.concat($A(arguments))); 225 } 226 }, 227 228 delay: function() { 229 var __method = this, args = $A(arguments), timeout = args.shift() * 1000; 230 return window.setTimeout(function() { 231 return __method.apply(__method, args); 232 }, timeout); 233 }, 234 235 wrap: function(wrapper) { 236 var __method = this; 237 return function() { 238 return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); 239 } 240 }, 241 242 methodize: function() { 243 if (this._methodized) return this._methodized; 244 var __method = this; 245 return this._methodized = function() { 246 return __method.apply(null, [this].concat($A(arguments))); 247 }; 96 248 } 97 249 }); 250 251 Function.prototype.defer = Function.prototype.delay.curry(0.01); 252 253 Date.prototype.toJSON = function() { 254 return '"' + this.getUTCFullYear() + '-' + 255 (this.getUTCMonth() + 1).toPaddedString(2) + '-' + 256 this.getUTCDate().toPaddedString(2) + 'T' + 257 this.getUTCHours().toPaddedString(2) + ':' + 258 this.getUTCMinutes().toPaddedString(2) + ':' + 259 this.getUTCSeconds().toPaddedString(2) + 'Z"'; 260 }; 98 261 99 262 var Try = { … … 101 264 var returnValue; 102 265 103 for (var i = 0 ; i < arguments.length; i++) {266 for (var i = 0, length = arguments.length; i < length; i++) { 104 267 var lambda = arguments[i]; 105 268 try { 106 269 returnValue = lambda(); 107 270 break; 108 } catch (e) { }271 } catch (e) { } 109 272 } 110 273 111 274 return returnValue; 112 275 } 113 } 276 }; 277 278 RegExp.prototype.match = RegExp.prototype.test; 279 280 RegExp.escape = function(str) { 281 return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); 282 }; 114 283 115 284 /*--------------------------------------------------------------------------*/ 116 285 117 var PeriodicalExecuter = Class.create(); 118 PeriodicalExecuter.prototype = { 286 var PeriodicalExecuter = Class.create({ 119 287 initialize: function(callback, frequency) { 120 288 this.callback = callback; … … 129 297 }, 130 298 299 execute: function() { 300 this.callback(this); 301 }, 302 131 303 stop: function() { 132 304 if (!this.timer) return; … … 139 311 try { 140 312 this.currentlyExecuting = true; 141 this. callback(this);313 this.execute(); 142 314 } finally { 143 315 this.currentlyExecuting = false; … … 145 317 } 146 318 } 147 } 319 }); 320 Object.extend(String, { 321 interpret: function(value) { 322 return value == null ? '' : String(value); 323 }, 324 specialChar: { 325 '\b': '\\b', 326 '\t': '\\t', 327 '\n': '\\n', 328 '\f': '\\f', 329 '\r': '\\r', 330 '\\': '\\\\' 331 } 332 }); 333 148 334 Object.extend(String.prototype, { 149 335 gsub: function(pattern, replacement) { … … 154 340 if (match = source.match(pattern)) { 155 341 result += source.slice(0, match.index); 156 result += (replacement(match) || '').toString();342 result += String.interpret(replacement(match)); 157 343 source = source.slice(match.index + match[0].length); 158 344 } else { … … 165 351 sub: function(pattern, replacement, count) { 166 352 replacement = this.gsub.prepareReplacement(replacement); 167 count = count === undefined? 1 : count;353 count = Object.isUndefined(count) ? 1 : count; 168 354 169 355 return this.gsub(pattern, function(match) { … … 175 361 scan: function(pattern, iterator) { 176 362 this.gsub(pattern, iterator); 177 return this;363 return String(this); 178 364 }, 179 365 180 366 truncate: function(length, truncation) { 181 367 length = length || 30; 182 truncation = truncation === undefined? '...' : truncation;368 truncation = Object.isUndefined(truncation) ? '...' : truncation; 183 369 return this.length > length ? 184 this.slice(0, length - truncation.length) + truncation : this;370 this.slice(0, length - truncation.length) + truncation : String(this); 185 371 }, 186 372 … … 210 396 211 397 escapeHTML: function() { 212 var div = document.createElement('div'); 213 var text = document.createTextNode(this); 214 div.appendChild(text); 215 return div.innerHTML; 398 var self = arguments.callee; 399 self.text.data = this; 400 return self.div.innerHTML; 216 401 }, 217 402 218 403 unescapeHTML: function() { 219 var div = document.createElement('div');404 var div = new Element('div'); 220 405 div.innerHTML = this.stripTags(); 221 return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; 222 }, 223 224 toQueryParams: function() { 225 var pairs = this.match(/^\??(.*)$/)[1].split('&'); 226 return pairs.inject({}, function(params, pairString) { 227 var pair = pairString.split('='); 228 var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; 229 params[decodeURIComponent(pair[0])] = value; 230 return params; 406 return div.childNodes[0] ? (div.childNodes.length > 1 ? 407 $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : 408 div.childNodes[0].nodeValue) : ''; 409 }, 410 411 toQueryParams: function(separator) { 412 var match = this.strip().match(/([^?#]*)(#.*)?$/); 413 if (!match) return { }; 414 415 return match[1].split(separator || '&').inject({ }, function(hash, pair) { 416 if ((pair = pair.split('='))[0]) { 417 var key = decodeURIComponent(pair.shift()); 418 var value = pair.length > 1 ? pair.join('=') : pair[0]; 419 if (value != undefined) value = decodeURIComponent(value); 420 421 if (key in hash) { 422 if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; 423 hash[key].push(value); 424 } 425 else hash[key] = value; 426 } 427 return hash; 231 428 }); 232 429 }, … … 236 433 }, 237 434 435 succ: function() { 436 return this.slice(0, this.length - 1) + 437 String.fromCharCode(this.charCodeAt(this.length - 1) + 1); 438 }, 439 440 times: function(count) { 441 return count < 1 ? '' : new Array(count + 1).join(this); 442 }, 443 238 444 camelize: function() { 239 var oStringList = this.split('-'); 240 if (oStringList.length == 1) return oStringList[0]; 241 242 var camelizedString = this.indexOf('-') == 0 243 ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) 244 : oStringList[0]; 245 246 for (var i = 1, len = oStringList.length; i < len; i++) { 247 var s = oStringList[i]; 248 camelizedString += s.charAt(0).toUpperCase() + s.substring(1); 249 } 250 251 return camelizedString; 445 var parts = this.split('-'), len = parts.length; 446 if (len == 1) return parts[0]; 447 448 var camelized = this.charAt(0) == '-' 449 ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) 450 : parts[0]; 451 452 for (var i = 1; i < len; i++) 453 camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); 454 455 return camelized; 456 }, 457 458 capitalize: function() { 459 return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); 460 }, 461 462 underscore: function() { 463 return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); 464 }, 465 466 dasherize: function() { 467 return this.gsub(/_/,'-'); 252 468 }, 253 469 254 470 inspect: function(useDoubleQuotes) { 255 var escapedString = this.replace(/\\/g, '\\\\'); 256 if (useDoubleQuotes) 257 return '"' + escapedString.replace(/"/g, '\\"') + '"'; 258 else 259 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 471 var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { 472 var character = String.specialChar[match[0]]; 473 return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); 474 }); 475 if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; 476 return "'" + escapedString.replace(/'/g, '\\\'') + "'"; 477 }, 478 479 toJSON: function() { 480 return this.inspect(true); 481 }, 482 483 unfilterJSON: function(filter) { 484 return this.sub(filter || Prototype.JSONFilter, '#{1}'); 485 }, 486 487 isJSON: function() { 488 var str = this; 489 if (str.blank()) return false; 490 str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); 491 return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); 492 }, 493 494 evalJSON: function(sanitize) { 495 var json = this.unfilterJSON(); 496 try { 497 if (!sanitize || json.isJSON()) return eval('(' + json + ')'); 498 } catch (e) { } 499 throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); 500 }, 501 502 include: function(pattern) { 503 return this.indexOf(pattern) > -1; 504 }, 505 506 startsWith: function(pattern) { 507 return this.indexOf(pattern) === 0; 508 }, 509 510 endsWith: function(pattern) { 511 var d = this.length - pattern.length; 512 return d >= 0 && this.lastIndexOf(pattern) === d; 513 }, 514 515 empty: function() { 516 return this == ''; 517 }, 518 519 blank: function() { 520 return /^\s*$/.test(this); 521 }, 522 523 interpolate: function(object, pattern) { 524 return new Template(this, pattern).evaluate(object); 260 525 } 261 526 }); 262 527 528 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { 529 escapeHTML: function() { 530 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 531 }, 532 unescapeHTML: function() { 533 return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); 534 } 535 }); 536 263 537 String.prototype.gsub.prepareReplacement = function(replacement) { 264 if ( typeof replacement == 'function') return replacement;538 if (Object.isFunction(replacement)) return replacement; 265 539 var template = new Template(replacement); 266 540 return function(match) { return template.evaluate(match) }; 267 } 541 }; 268 542 269 543 String.prototype.parseQuery = String.prototype.toQueryParams; 270 544 271 var Template = Class.create(); 272 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 273 Template.prototype = { 545 Object.extend(String.prototype.escapeHTML, { 546 div: document.createElement('div'), 547 text: document.createTextNode('') 548 }); 549 550 with (String.prototype.escapeHTML) div.appendChild(text); 551 552 var Template = Class.create({ 274 553 initialize: function(template, pattern) { 275 554 this.template = template.toString(); 276 this.pattern = pattern || Template.Pattern;555 this.pattern = pattern || Template.Pattern; 277 556 }, 278 557 279 558 evaluate: function(object) { 559 if (Object.isFunction(object.toTemplateReplacements)) 560 object = object.toTemplateReplacements(); 561 280 562 return this.template.gsub(this.pattern, function(match) { 281 var before = match[1]; 563 if (object == null) return ''; 564 565 var before = match[1] || ''; 282 566 if (before == '\\') return match[2]; 283 return before + (object[match[3]] || '').toString(); 567 568 var ctx = object, expr = match[3]; 569 var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; 570 match = pattern.exec(expr); 571 if (match == null) return before; 572 573 while (match != null) { 574 var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; 575 ctx = ctx[comp]; 576 if (null == ctx || '' == match[3]) break; 577 expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); 578 match = pattern.exec(expr); 579 } 580 581 return before + String.interpret(ctx); 284 582 }); 285 583 } 286 } 287 288 var $break = new Object(); 289 var $ continue = new Object();584 }); 585 Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; 586 587 var $break = { }; 290 588 291 589 var Enumerable = { 292 each: function(iterator ) {590 each: function(iterator, context) { 293 591 var index = 0; 592 iterator = iterator.bind(context); 294 593 try { 295 594 this._each(function(value) { 296 try { 297 iterator(value, index++); 298 } catch (e) { 299 if (e != $continue) throw e; 300 } 595 iterator(value, index++); 301 596 }); 302 597 } catch (e) { 303 598 if (e != $break) throw e; 304 599 } 305 }, 306 307 all: function(iterator) { 600 return this; 601 }, 602 603 eachSlice: function(number, iterator, context) { 604 iterator = iterator ? iterator.bind(context) : Prototype.K; 605 var index = -number, slices = [], array = this.toArray(); 606 while ((index += number) < array.length) 607 slices.push(array.slice(index, index+number)); 608 return slices.collect(iterator, context); 609 }, 610 611 all: function(iterator, context) { 612 iterator = iterator ? iterator.bind(context) : Prototype.K; 308 613 var result = true; 309 614 this.each(function(value, index) { 310 result = result && !! (iterator || Prototype.K)(value, index);615 result = result && !!iterator(value, index); 311 616 if (!result) throw $break; 312 617 }); … … 314 619 }, 315 620 316 any: function(iterator) { 621 any: function(iterator, context) { 622 iterator = iterator ? iterator.bind(context) : Prototype.K; 317 623 var result = false; 318 624 this.each(function(value, index) { 319 if (result = !! (iterator || Prototype.K)(value, index))625 if (result = !!iterator(value, index)) 320 626 throw $break; 321 627 }); … … 323 629 }, 324 630 325 collect: function(iterator) { 631 collect: function(iterator, context) { 632 iterator = iterator ? iterator.bind(context) : Prototype.K; 326 633 var results = []; 327 634 this.each(function(value, index) { … … 331 638 }, 332 639 333 detect: function (iterator) { 640 detect: function(iterator, context) { 641 iterator = iterator.bind(context); 334 642 var result; 335 643 this.each(function(value, index) { … … 342 650 }, 343 651 344 findAll: function(iterator) { 652 findAll: function(iterator, context) { 653 iterator = iterator.bind(context); 345 654 var results = []; 346 655 this.each(function(value, index) { … … 351 660 }, 352 661 353 grep: function(pattern, iterator) { 662 grep: function(filter, iterator, context) { 663 iterator = iterator ? iterator.bind(context) : Prototype.K; 354 664 var results = []; 665 666 if (Object.isString(filter)) 667 filter = new RegExp(filter); 668 355 669 this.each(function(value, index) { 356 var stringValue = value.toString(); 357 if (stringValue.match(pattern)) 358 results.push((iterator || Prototype.K)(value, index)); 359 }) 670 if (filter.match(value)) 671 results.push(iterator(value, index)); 672 }); 360 673 return results; 361 674 }, 362 675 363 676 include: function(object) { 677 if (Object.isFunction(this.indexOf)) 678 if (this.indexOf(object) != -1) return true; 679 364 680 var found = false; 365 681 this.each(function(value) { … … 372 688 }, 373 689 374 inject: function(memo, iterator) { 690 inGroupsOf: function(number, fillWith) { 691 fillWith = Object.isUndefined(fillWith) ? null : fillWith; 692 return this.eachSlice(number, function(slice) { 693 while(slice.length < number) slice.push(fillWith); 694 return slice; 695 }); 696 }, 697 698 inject: function(memo, iterator, context) { 699 iterator = iterator.bind(context); 375 700 this.each(function(value, index) { 376 701 memo = iterator(memo, value, index); … … 381 706 invoke: function(method) { 382 707 var args = $A(arguments).slice(1); 383 return this. collect(function(value) {708 return this.map(function(value) { 384 709 return value[method].apply(value, args); 385 710 }); 386 711 }, 387 712 388 max: function(iterator) { 713 max: function(iterator, context) { 714 iterator = iterator ? iterator.bind(context) : Prototype.K; 389 715 var result; 390 716 this.each(function(value, index) { 391 value = (iterator || Prototype.K)(value, index);392 if (result == undefined|| value >= result)717 value = iterator(value, index); 718 if (result == null || value >= result) 393 719 result = value; 394 720 }); … … 396 722 }, 397 723 398 min: function(iterator) { 724 min: function(iterator, context) { 725 iterator = iterator ? iterator.bind(context) : Prototype.K; 399 726 var result; 400 727 this.each(function(value, index) { 401 value = (iterator || Prototype.K)(value, index);402 if (result == undefined|| value < result)728 value = iterator(value, index); 729 if (result == null || value < result) 403 730 result = value; 404 731 }); … … 406 733 }, 407 734 408 partition: function(iterator) { 735 partition: function(iterator, context) { 736 iterator = iterator ? iterator.bind(context) : Prototype.K; 409 737 var trues = [], falses = []; 410 738 this.each(function(value, index) { 411 ( (iterator || Prototype.K)(value, index) ?739 (iterator(value, index) ? 412 740 trues : falses).push(value); 413 741 }); … … 417 745 pluck: function(property) { 418 746 var results = []; 419 this.each(function(value , index) {747 this.each(function(value) { 420 748 results.push(value[property]); 421 749 }); … … 423 751 }, 424 752 425 reject: function(iterator) { 753 reject: function(iterator, context) { 754 iterator = iterator.bind(context); 426 755 var results = []; 427 756 this.each(function(value, index) { … … 432 761 }, 433 762 434 sortBy: function(iterator) { 435 return this.collect(function(value, index) { 763 sortBy: function(iterator, context) { 764 iterator = iterator.bind(context); 765 return this.map(function(value, index) { 436 766 return {value: value, criteria: iterator(value, index)}; 437 767 }).sort(function(left, right) { … … 442 772 443 773 toArray: function() { 444 return this. collect(Prototype.K);774 return this.map(); 445 775 }, 446 776 447 777 zip: function() { 448 778 var iterator = Prototype.K, args = $A(arguments); 449 if ( typeof args.last() == 'function')779 if (Object.isFunction(args.last())) 450 780 iterator = args.pop(); 451 781 … … 456 786 }, 457 787 788 size: function() { 789 return this.toArray().length; 790 }, 791 458 792 inspect: function() { 459 793 return '#<Enumerable:' + this.toArray().inspect() + '>'; 460 794 } 461 } 795 }; 462 796 463 797 Object.extend(Enumerable, { … … 465 799 find: Enumerable.detect, 466 800 select: Enumerable.findAll, 801 filter: Enumerable.findAll, 467 802 member: Enumerable.include, 468 entries: Enumerable.toArray 803 entries: Enumerable.toArray, 804 every: Enumerable.all, 805 some: Enumerable.any 469 806 }); 470 var $A = Array.from = function(iterable) {807 function $A(iterable) { 471 808 if (!iterable) return []; 472 if (iterable.toArray) { 473 return iterable.toArray(); 474 } else { 475 var results = []; 476 for (var i = 0; i < iterable.length; i++) 477 results.push(iterable[i]); 809 if (iterable.toArray) return iterable.toArray(); 810 var length = iterable.length || 0, results = new Array(length); 811 while (length--) results[length] = iterable[length]; 812 return results; 813 } 814 815 if (Prototype.Browser.WebKit) { 816 $A = function(iterable) { 817 if (!iterable) return []; 818 if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && 819 iterable.toArray) return iterable.toArray(); 820 var length = iterable.length || 0, results = new Array(length); 821 while (length--) results[length] = iterable[length]; 478 822 return results; 479 } 823 }; 480 824 } 481 825 826 Array.from = $A; 827 482 828 Object.extend(Array.prototype, Enumerable); 483 829 484 if (!Array.prototype._reverse) 485 Array.prototype._reverse = Array.prototype.reverse; 830 if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; 486 831 487 832 Object.extend(Array.prototype, { 488 833 _each: function(iterator) { 489 for (var i = 0 ; i < this.length; i++)834 for (var i = 0, length = this.length; i < length; i++) 490 835 iterator(this[i]); 491 836 }, … … 506 851 compact: function() { 507 852 return this.select(function(value) { 508 return value != undefined || value !=null;853 return value != null; 509 854 }); 510 855 }, … … 512 857 flatten: function() { 513 858 return this.inject([], function(array, value) { 514 return array.concat( value && value.constructor == Array?859 return array.concat(Object.isArray(value) ? 515 860 value.flatten() : [value]); 516 861 &nb
