From 562e61fc8cbcb5b16f3b4da32a138df64689ee7d Mon Sep 17 00:00:00 2001 From: Sam Stephenson Date: Sun, 29 Apr 2007 05:37:07 +0000 Subject: [PATCH] prototype: Add Function#curry, Function#delay, Function#defer, and Function#wrap. Closes #8134. --- CHANGELOG | 2 ++ src/ajax.js | 9 +++----- src/array.js | 6 ++++-- src/base.js | 47 +++++++++++++++++++++++++++++++---------- src/dom.js | 8 +++---- test/unit/base.html | 51 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 23 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bd48f20..ea21ea6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Add Function#curry, Function#delay, Function#defer, and Function#wrap. Closes #8134. [Andrew Dupont, Tobie Langel, sam] + *1.5.1* (it is a mystery) *1.5.1_rc4* (April 27, 2007) diff --git a/src/ajax.js b/src/ajax.js index 179827f..e2ef898 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -107,8 +107,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), { this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); - if (this.options.asynchronous) - setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); @@ -267,8 +266,7 @@ Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { } if (this.success()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); + if (this.onComplete) this.onComplete.bind(this).defer(); } } }); @@ -307,8 +305,7 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { this.lastText = request.responseText; } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { diff --git a/src/array.js b/src/array.js index 0abf72e..e2da61c 100644 --- a/src/array.js +++ b/src/array.js @@ -1,4 +1,4 @@ -var $A = Array.from = function(iterable) { +function $A(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); @@ -11,7 +11,7 @@ var $A = Array.from = function(iterable) { } if (Prototype.Browser.WebKit) { - $A = Array.from = function(iterable) { + function $A(iterable) { if (!iterable) return []; if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && iterable.toArray) { @@ -25,6 +25,8 @@ if (Prototype.Browser.WebKit) { } } +Array.from = $A; + Object.extend(Array.prototype, Enumerable); if (!Array.prototype._reverse) diff --git a/src/base.js b/src/base.js index f005713..263ac65 100644 --- a/src/base.js +++ b/src/base.js @@ -66,19 +66,44 @@ Object.extend(Object, { } }); -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} +Object.extend(Function.prototype, { + bind: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, + + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [(event || window.event)].concat(args).concat($A(arguments))); + } + }, + + curry: function() { + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } + }, -Function.prototype.bindAsEventListener = function(object) { - var __method = this, args = $A(arguments), object = args.shift(); - return function(event) { - return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + }, + + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } } -} +}); + +Function.prototype.defer = Function.prototype.delay.curry(0.01); Object.extend(Number.prototype, { toColorPart: function() { diff --git a/src/dom.js b/src/dom.js index 4d5e897..b023ee6 100644 --- a/src/dom.js +++ b/src/dom.js @@ -105,7 +105,7 @@ Element.Methods = { update: function(element, html) { html = typeof html == 'undefined' ? '' : html.toString(); $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); + html.evalScripts.bind(html).defer(); return element; }, @@ -120,7 +120,7 @@ Element.Methods = { element.parentNode.replaceChild( range.createContextualFragment(html.stripScripts()), element); } - setTimeout(function() {html.evalScripts()}, 10); + html.evalScripts.bind(html).defer(); return element; }, @@ -504,7 +504,7 @@ else if (Prototype.Browser.IE) { } else { element.innerHTML = html.stripScripts(); } - setTimeout(function() { html.evalScripts() }, 10); + html.evalScripts.bind(html).defer(); return element; } } @@ -698,7 +698,7 @@ Abstract.Insertion.prototype = { this.insertContent([this.range.createContextualFragment(this.content)]); } - setTimeout(function() {content.evalScripts()}, 10); + content.evalScripts.bind(content).defer(); }, contentFromAnonymousTable: function() { diff --git a/test/unit/base.html b/test/unit/base.html index 363bede..597cde0 100644 --- a/test/unit/base.html +++ b/test/unit/base.html @@ -85,6 +85,57 @@ assertEqual('withBindArgsAndArgs,arg1,arg2,arg3,arg4', globalBindTest); }}, + testFunctionCurry: function() { with(this) { + var split = function(delimiter, string) { return string.split(delimiter); }; + var splitOnColons = split.curry(":"); + assertEnumEqual(split(":", "0:1:2:3:4:5"), splitOnColons("0:1:2:3:4:5")); + }}, + + testFunctionDelay: function() { with(this) { + window.delayed = undefined; + var delayedFunction = function() { window.delayed = true; }; + var delayedFunctionWithArgs = function() { window.delayedWithArgs = $A(arguments).join(' '); }; + delayedFunction.delay(0.8); + delayedFunctionWithArgs.delay(0.8, 'hello', 'world'); + assertUndefined(window.delayed); + wait(1000, function() { + assert(window.delayed); + assertEqual('hello world', window.delayedWithArgs); + }); + }}, + + testFunctionWrap: function() { with(this) { + function sayHello(){ + return 'hello world'; + }; + + assertEqual('HELLO WORLD', sayHello.wrap(function(proceed) { + return proceed().toUpperCase(); + })()); + + var temp = String.prototype.capitalize; + String.prototype.capitalize = String.prototype.capitalize.wrap(function(proceed, eachWord) { + if(eachWord && this.include(' ')) return this.split(' ').map(function(str){ + return str.capitalize(); + }).join(' '); + return proceed(); + }); + assertEqual('Hello world', 'hello world'.capitalize()); + assertEqual('Hello World', 'hello world'.capitalize(true)); + assertEqual('Hello', 'hello'.capitalize()); + String.prototype.capitalize = temp; + }}, + + testFunctionDefer: function() { with(this) { + window.deferred = undefined; + var deferredFunction = function() { window.deferred = true; }; + deferredFunction.defer(); + assertUndefined(window.deferred); + wait(50, function() { + assert(window.deferred); + }); + }}, + testObjectInspect: function() { with(this) { assertEqual('undefined', Object.inspect()); assertEqual('undefined', Object.inspect(undefined));