prototype/src/base.js

272 lines
6.9 KiB
JavaScript
Raw Normal View History

/* Based on Alex Arnell's inheritance implementation. */
2007-01-18 22:24:27 +00:00
var Class = {
create: function(parent, methods) {
if (arguments.length == 1 && !Object.isFunction(parent))
methods = parent, parent = null;
var method = function() {
if (!Class.extending) this.initialize.apply(this, arguments);
};
method.superclass = parent;
method.subclasses = [];
if (Object.isFunction(parent)) {
Class.extending = true;
method.prototype = new parent();
method.prototype.constructor = method;
parent.subclasses.push(method);
delete Class.extending;
}
if (methods) Class.extend(method, methods);
return method;
},
extend: function(destination, source) {
for (var name in source) Class.inherit(destination, source, name);
return destination;
},
inherit: function(destination, source, name) {
var prototype = destination.prototype, ancestor = prototype[name],
descendant = source[name];
if (ancestor && Object.isFunction(descendant) &&
descendant.argumentNames().first() == "$super") {
var method = descendant, descendant = ancestor.wrap(method);
Object.extend(descendant, {
valueOf: function() { return method },
toString: function() { return method.toString() }
});
}
prototype[name] = descendant;
if (destination.subclasses && destination.subclasses.length > 0) {
for (var i = 0, subclass; subclass = destination.subclasses[i]; i++) {
Class.extending = true;
Object.extend(subclass.prototype, new destination());
subclass.prototype.constructor = subclass;
delete Class.extending;
Class.inherit(subclass, destination.prototype, name);
}
2007-01-18 22:24:27 +00:00
}
},
mixin: function(destination, source) {
return Object.extend(destination, source);
2007-01-18 22:24:27 +00:00
}
};
2007-01-18 22:24:27 +00:00
var Abstract = { };
2007-01-18 22:24:27 +00:00
Object.extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
return destination;
};
2007-01-18 22:24:27 +00:00
Object.extend(Object, {
inspect: function(object) {
try {
if (object === undefined) return 'undefined';
if (object === null) return 'null';
return object.inspect ? object.inspect() : object.toString();
} catch (e) {
if (e instanceof RangeError) return '...';
throw e;
}
},
toJSON: function(object) {
var type = typeof object;
switch (type) {
case 'undefined':
case 'function':
case 'unknown': return;
case 'boolean': return object.toString();
}
if (object === null) return 'null';
if (object.toJSON) return object.toJSON();
if (Object.isElement(object)) return;
var results = [];
for (var property in object) {
var value = Object.toJSON(object[property]);
if (value !== undefined)
results.push(property.toJSON() + ': ' + value);
}
return '{' + results.join(', ') + '}';
},
toHTML: function(object) {
return object && object.toHTML ? object.toHTML() : String.interpret(object);
},
2007-01-18 22:24:27 +00:00
keys: function(object) {
var keys = [];
for (var property in object)
keys.push(property);
return keys;
},
values: function(object) {
var values = [];
for (var property in object)
values.push(object[property]);
return values;
},
clone: function(object) {
return Object.extend({ }, object);
},
isElement: function(object) {
return object && object.nodeType == 1;
},
isArray: function(object) {
return object && object.constructor === Array;
},
isFunction: function(object) {
return typeof object == "function";
},
isString: function(object) {
return typeof object == "string";
},
isNumber: function(object) {
return typeof object == "number";
},
isUndefined: function(object) {
return typeof object == "undefined";
2007-01-18 22:24:27 +00:00
}
});
Object.extend(Function.prototype, {
argumentNames: function() {
var names = this.toString().match(/^[\s\(]*function\s*\((.*?)\)/)[1].split(",").invoke("strip");
return names.length == 1 && !names[0] ? [] : names;
},
bind: function() {
if (arguments.length < 2 && arguments[0] === undefined) return this;
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));
}
},
curry: function() {
if (!arguments.length) return this;
var __method = this, args = $A(arguments);
return function() {
return __method.apply(this, args.concat($A(arguments)));
}
},
2007-01-18 22:24:27 +00:00
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)));
}
},
methodize: function() {
if (this._methodized) return this._methodized;
var __method = this;
return this._methodized = function() {
return __method.apply(null, [this].concat($A(arguments)));
};
2007-01-18 22:24:27 +00:00
}
});
Function.prototype.defer = Function.prototype.delay.curry(0.01);
2007-01-18 22:24:27 +00:00
Date.prototype.toJSON = function() {
return '"' + this.getFullYear() + '-' +
(this.getMonth() + 1).toPaddedString(2) + '-' +
this.getDate().toPaddedString(2) + 'T' +
this.getHours().toPaddedString(2) + ':' +
this.getMinutes().toPaddedString(2) + ':' +
this.getSeconds().toPaddedString(2) + '"';
};
2007-01-18 22:24:27 +00:00
var Try = {
these: function() {
var returnValue;
for (var i = 0, length = arguments.length; i < length; i++) {
var lambda = arguments[i];
try {
returnValue = lambda();
break;
} catch (e) { }
2007-01-18 22:24:27 +00:00
}
return returnValue;
}
};
2007-01-18 22:24:27 +00:00
RegExp.prototype.match = RegExp.prototype.test;
RegExp.escape = function(str) {
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
2007-01-18 22:24:27 +00:00
/*--------------------------------------------------------------------------*/
var PeriodicalExecuter = Class.create({
2007-01-18 22:24:27 +00:00
initialize: function(callback, frequency) {
this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
stop: function() {
if (!this.timer) return;
clearInterval(this.timer);
this.timer = null;
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.callback(this);
} finally {
this.currentlyExecuting = false;
}
}
}
});