Created
July 6, 2010 23:42
-
-
Save cpojer/466097 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CAFE | |
0010 | |
0007 | |
7100 | |
8AFF | |
CA15 | |
11A1 | |
C011 | |
91FF | |
0000 | |
1234 | |
2341 | |
3412 | |
4123 | |
1111 | |
1111 | |
1111 | |
1111 | |
1111 | |
0001 | |
0001 | |
0000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
JavaScript Implementation of the TOY CPU which we used in the | |
lecture RECHNERNETZE UND -ORGANISATION (Computer Networks and Organization) | |
More Information: http://www.cs.princeton.edu/introcs/52toy/ | |
Instruction Set: http://www.cs.princeton.edu/introcs/53isa/ | |
This implementation comes with a built-in boot loader. | |
It expects files in the following format: | |
line 1: CAFE | |
line 2: Memory Address on where to store the program | |
line 3: Amount of Instructions | |
line 4 .. n: Instructions, terminated by 0000 | |
line n+1 .. EOF: stdin data | |
Run: | |
node Toy.js test1.in // Expected output: 0001 | |
Notes: | |
This hasn't been thoroughly tested and was done just for the fun of it. | |
SHR likely does not work correctly. | |
(c) [Christoph Pojer](http://cpojer.net) | |
*/ | |
require('./MooTools').apply(GLOBAL); | |
var sys = require('sys'), | |
puts = sys.puts, | |
print = sys.print; | |
String.implement({ | |
repeat: function(times){ | |
var s = ''; | |
while (times--) s += this; | |
return s; | |
}, | |
pad: function(length, left){ | |
if (!left) left = '0'; | |
if (this.length < length) return (left).repeat(length - this.length) + this; | |
return this; | |
}, | |
toAddress: function(){ | |
return parseInt(this, 16).toAddress(); | |
}, | |
toWord: function(){ | |
return this.pad(4); | |
} | |
}); | |
Number.implement({ | |
toAddress: function(){ | |
return (this & 0xFF).toString(16).toUpperCase().pad(2); | |
}, | |
toWord: function(){ | |
return (this & 0xFFFF).toString(16).toUpperCase().pad(4); | |
} | |
}); | |
var Register = new Class({ | |
value: 0, | |
read: function(){ | |
return this.value.toWord(); | |
}, | |
write: function(value){ | |
this.value = value.toWord(); | |
}, | |
raw: function(){ | |
return parseInt(this.read(), 16) & 0xFFFF; | |
} | |
}); | |
var Register0 = new Class({ | |
Extends: Register, | |
write: function(){} | |
}); | |
var Memory = Register; | |
var IO = new Class({ | |
Extends: Memory, | |
initialize: function(stdin, stdout){ | |
this.stdin = stdin; | |
this.stdout = stdout; | |
}, | |
read: function(){ | |
return (this.stdin.shift() || '0').toWord(); | |
}, | |
write: function(value){ | |
this.stdout.push(value.toWord()); | |
} | |
}); | |
var Toy = new Class({ | |
pc: 0x10, | |
registers: {}, | |
memory: {}, | |
stdout: [], | |
initialize: function(stdin){ | |
var i; | |
this.registers[0] = new Register0; | |
for (i = 1; i <= 15; i++) | |
this.registers[i.toString(16).toUpperCase()] = new Register; | |
for (i = 0; i <= 254; i++) | |
this.memory[i.toAddress()] = new Memory; | |
this.memory.FF = new IO(stdin, this.stdout); | |
// Bootloader | |
this.memory['00'].write('CAFE'); // A DW 0xCAFE | |
this.memory['10'].write('FFE0'); // jl RF, start | |
this.memory['E0'].write('7101'); // start lda R1, 0x1 // load constant 1 | |
this.memory['E1'].write('8200'); // ld R2, A // load CAFE | |
this.memory['E2'].write('83FF'); // ld R3, 0xFF // read | |
this.memory['E3'].write('2332'); // sub R3, R3, R2 // check for CAFE | |
this.memory['E4'].write('C3E6'); // bz R3, go | |
this.memory['E5'].write('0000'); // hlt // halt, no exe-file | |
this.memory['E6'].write('84FF'); // go ld R4, 0xFF // start addr in R4 | |
this.memory['E7'].write('1540'); // add R5, R4, R0 // temp copy of start addr | |
this.memory['E8'].write('86FF'); // ld R6, 0xFF // amount of words | |
this.memory['E9'].write('C6EF'); // loop bz R6, exit // goto exit if finished | |
this.memory['EA'].write('2661'); // sub R6, R6, R1 // decrement R6 | |
this.memory['EB'].write('87FF'); // ld R7, 0xFF // read a word | |
this.memory['EC'].write('B705'); // st R7, R5 | |
this.memory['ED'].write('1551'); // add R5, R5, R1 // increment code address | |
this.memory['EE'].write('FFE9'); // jl RF, loop | |
this.memory['EF'].write('E400'); // exit jr R4 // jump to program's start addr | |
this.memory['F0'].write('0000'); // hlt // this line should not be reached | |
}, | |
execute: function(){ | |
while (true){ | |
var pc = this.getPC(), | |
instruction = this.memory[pc].read(); | |
this.pc++; | |
puts('PC: 0x' + pc + '\tInst: 0x' + instruction); | |
if (!instruction.test(/^[0-9A-F]{4}$/)){ | |
puts(' Abort! Instruction mismatch'); | |
return this; | |
} | |
var opcode = instruction.charAt(0), | |
d = this.registers[instruction.charAt(1)], | |
s = this.registers[instruction.charAt(2)], | |
t = this.registers[instruction.charAt(3)], | |
addr = parseInt(instruction.charAt(2) + instruction.charAt(3), 16); | |
switch (opcode){ | |
case '0': return this; | |
case '1': d.write(s.raw() + t.raw()); break; | |
case '2': d.write(s.raw() - t.raw()); break; | |
case '3': d.write(s.raw() & t.raw()); break; | |
case '4': d.write(s.raw() ^ t.raw()); break; | |
case '5': d.write(s.raw() << t.raw()); break; | |
case '6': d.write(s.raw() >> t.raw()); break; | |
case '7': d.write(addr); break; | |
case '8': d.write(this.memory[addr.toAddress()].read()); break; | |
case '9': this.memory[addr.toAddress()].write(d.read()); break; | |
case 'A': d.write(this.memory[t.read().toAddress()].read()); break; | |
case 'B': this.memory[t.read().toAddress()].write(d.read()); break; | |
case 'C': if (!d.raw()) this.pc = addr; break; | |
case 'D': if (d.raw()) this.pc = addr; break; | |
case 'E': this.pc = (d.raw() & 0xFF); break; | |
case 'F': d.write(this.pc); this.pc = addr; break; | |
} | |
} | |
return this; | |
}, | |
getPC: function(){ | |
return (this.pc & 0xFF).toAddress(); | |
}, | |
dump: function(){ | |
var key; | |
puts('------------'); | |
puts('## Registers'); | |
for (key in this.registers) | |
puts('0x' + key + ': ' + this.registers[key].read()); | |
puts('------------'); | |
puts('## Memory Dump'); | |
for (var i = 0; i <= 255; i++){ | |
key = i.toAddress(); | |
print('0x' + key + ': ' + this.memory[key].read() + '\t'); | |
} | |
print('\n'); | |
puts('------------'); | |
puts('## Stdout'); | |
this.stdout.forEach(function(value){ | |
puts(value); | |
}); | |
return this; | |
} | |
}); | |
if (!process.argv[2]){ | |
puts('Please specify a test to run.'); | |
return; | |
} | |
var file = process.argv[2]; | |
require('fs').readFile(file, function(err, data){ | |
if (err) return; | |
var stdin = data.toString().split('\n'); | |
puts('## Stdin (' + file + ')'); | |
stdin.forEach(function(value){ | |
puts(value); | |
}); | |
puts('------------'); | |
(new Toy(stdin)).execute().dump(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
--- | |
name: Prefix | |
description: Loads MooTools as a CommonJS Module. | |
license: MIT-style license. | |
copyright: Copyright (c) 2010 [Christoph Pojer](http://cpojer.net/). | |
authors: Christoph Pojer | |
provides: [Prefix] | |
... | |
*/ | |
var GLOBAL_ITEMS = function(){ | |
var items = []; | |
for (var key in this) | |
items.push(key); | |
return items; | |
}(); | |
/* | |
--- | |
name: Core | |
description: The heart of MooTools. | |
license: MIT-style license. | |
copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). | |
authors: The MooTools production team (http://mootools.net/developers/) | |
inspiration: | |
- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php) | |
- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php) | |
provides: [Core, MooTools, Type, typeOf, instanceOf] | |
... | |
*/ | |
(function(){ | |
this.MooTools = { | |
version: '1.3dev', | |
build: 'd29f41a0e1d9fcf80cdd6894317d393e2885bab5' | |
}; | |
// typeOf, instanceOf | |
var typeOf = this.typeOf = function(item){ | |
if (item == null) return 'null'; | |
if (item.$family) return item.$family(); | |
if (item.nodeName){ | |
if (item.nodeType == 1) return 'element'; | |
if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace'; | |
} else if (typeof item.length == 'number'){ | |
if (item.callee) return 'arguments'; | |
if ('item' in item) return 'collection'; | |
} | |
return typeof item; | |
}; | |
var instanceOf = this.instanceOf = function(item, object){ | |
if (item == null) return false; | |
var constructor = item.$constructor || item.constructor; | |
while (constructor){ | |
if (constructor === object) return true; | |
constructor = constructor.parent; | |
} | |
return item instanceof object; | |
}; | |
// Function overloading | |
var Function = this.Function; | |
var enumerables = true; | |
for (var i in {toString: 1}) enumerables = null; | |
if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; | |
Function.prototype.overloadSetter = function(usePlural){ | |
var self = this; | |
return function(a, b){ | |
if (a == null) return this; | |
if (usePlural || typeof a != 'string'){ | |
for (var k in a) self.call(this, k, a[k]); | |
if (enumerables) for (var i = enumerables.length; i--;){ | |
k = enumerables[i]; | |
if (a.hasOwnProperty(k)) self.call(this, k, a[k]); | |
} | |
} else { | |
self.call(this, a, b); | |
} | |
return this; | |
}; | |
}; | |
Function.prototype.overloadGetter = function(usePlural){ | |
var self = this; | |
return function(a){ | |
var args, result; | |
if (usePlural || typeof a != 'string') args = a; | |
else if (arguments.length > 1) args = arguments; | |
if (args){ | |
result = {}; | |
for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]); | |
} else { | |
result = self.call(this, a); | |
} | |
return result; | |
}; | |
}; | |
Function.prototype.extend = function(key, value){ | |
this[key] = value; | |
}.overloadSetter(); | |
Function.prototype.implement = function(key, value){ | |
this.prototype[key] = value; | |
}.overloadSetter(); | |
// From | |
Function.from = function(item){ | |
return (typeOf(item) == 'function') ? item : function(){ | |
return item; | |
}; | |
}; | |
Array.from = function(item){ | |
if (item == null) return []; | |
return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : Array.prototype.slice.call(item) : [item]; | |
}; | |
Number.from = function(item){ | |
var number = parseFloat(item); | |
return isFinite(number) ? number : null; | |
}; | |
String.from = function(item){ | |
return item + ''; | |
}; | |
// hide, protect | |
Function.implement({ | |
hide: function(){ | |
this.$hidden = true; | |
return this; | |
}, | |
protect: function(){ | |
this.$protected = true; | |
return this; | |
} | |
}); | |
// Type | |
var Type = this.Type = function(name, object){ | |
if (name){ | |
var lower = name.toLowerCase(); | |
var typeCheck = function(item){ | |
return (typeOf(item) == lower); | |
}; | |
Type['is' + name] = typeCheck; | |
if (object != null){ | |
object.prototype.$family = (function(){ | |
return lower; | |
}).hide(); | |
} | |
} | |
if (object == null) return null; | |
object.extend(this); | |
object.$constructor = Type; | |
object.prototype.$constructor = object; | |
return object; | |
}; | |
var toString = Object.prototype.toString; | |
Type.isEnumerable = function(item){ | |
return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' ); | |
}; | |
var hooks = {}; | |
var hooksOf = function(object){ | |
var type = typeOf(object.prototype); | |
return hooks[type] || (hooks[type] = []); | |
}; | |
var implement = function(name, method){ | |
if (method && method.$hidden) return this; | |
var hooks = hooksOf(this); | |
for (var i = 0; i < hooks.length; i++){ | |
var hook = hooks[i]; | |
if (typeOf(hook) == 'type') implement.call(hook, name, method); | |
else hook.call(this, name, method); | |
} | |
var previous = this.prototype[name]; | |
if (previous == null || !previous.$protected) this.prototype[name] = method; | |
if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){ | |
return method.apply(item, Array.prototype.slice.call(arguments, 1)); | |
}); | |
return this; | |
}; | |
var extend = function(name, method){ | |
if (method && method.$hidden) return this; | |
var previous = this[name]; | |
if (previous == null || !previous.$protected) this[name] = method; | |
return this; | |
}; | |
Type.implement({ | |
implement: implement.overloadSetter(), | |
extend: extend.overloadSetter(), | |
alias: function(name, existing){ | |
implement.call(this, name, this.prototype[existing]); | |
}.overloadSetter(), | |
mirror: function(hook){ | |
hooksOf(this).push(hook); | |
return this; | |
} | |
}); | |
new Type('Type', Type); | |
// Default Types | |
var force = function(name, type, methods){ | |
var object = new Type(name, type), | |
prototype = object.prototype; | |
for (var i = 0, l = methods.length; i < l; i++){ | |
var key = methods[i], | |
generic = object[key], | |
proto = prototype[key]; | |
if (generic) generic.protect(); | |
if (proto){ | |
delete prototype[key]; | |
prototype[key] = proto.protect(); | |
} | |
} | |
object.implement(object.prototype); | |
return force; | |
}; | |
force('String', String, [ | |
'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search', | |
'slice', 'split', 'substr', 'substring', 'toLowerCase', 'toUpperCase' | |
])('Array', Array, [ | |
'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice', | |
'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight' | |
])('Number', Number, [ | |
'toExponential', 'toFixed', 'toLocaleString', 'toPrecision' | |
])('Function', Function, [ | |
'apply', 'call' | |
])('RegExp', RegExp, ['exec', 'test'])('Date', Date, ['now']); | |
Date.extend('now', function(){ | |
return +(new Date); | |
}); | |
new Type('Boolean', Boolean); | |
// fixes NaN returning as Number | |
Number.prototype.$family = function(){ | |
return isFinite(this) ? 'number' : 'null'; | |
}.hide(); | |
// Number.random | |
Number.extend('random', function(min, max){ | |
return Math.floor(Math.random() * (max - min + 1) + min); | |
}); | |
// forEach, each | |
Object.extend('forEach', function(object, fn, bind){ | |
for (var key in object){ | |
if (object.hasOwnProperty(key)) fn.call(bind, object[key], key, object); | |
} | |
}); | |
Object.each = Object.forEach; | |
Array.implement({ | |
forEach: function(fn, bind){ | |
for (var i = 0, l = this.length; i < l; i++){ | |
if (i in this) fn.call(bind, this[i], i, this); | |
} | |
}, | |
each: function(fn, bind){ | |
Array.forEach(this, fn, bind); | |
return this; | |
} | |
}); | |
// Array & Object cloning, Object merging and appending | |
var cloneOf = function(item){ | |
switch (typeOf(item)){ | |
case 'array': return item.clone(); | |
case 'object': return Object.clone(item); | |
default: return item; | |
} | |
}; | |
Array.implement('clone', function(){ | |
var i = this.length, clone = new Array(i); | |
while (i--) clone[i] = cloneOf(this[i]); | |
return clone; | |
}); | |
var mergeOne = function(source, key, current){ | |
switch (typeOf(current)){ | |
case 'object': | |
if (typeOf(source[key]) == 'object') Object.merge(source[key], current); | |
else source[key] = Object.clone(current); | |
break; | |
case 'array': source[key] = current.clone(); break; | |
default: source[key] = current; | |
} | |
return source; | |
}; | |
Object.extend({ | |
merge: function(source, k, v){ | |
if (typeOf(k) == 'string') return mergeOne(source, k, v); | |
for (var i = 1, l = arguments.length; i < l; i++){ | |
var object = arguments[i]; | |
for (var key in object) mergeOne(source, key, object[key]); | |
} | |
return source; | |
}, | |
clone: function(object){ | |
var clone = {}; | |
for (var key in object) clone[key] = cloneOf(object[key]); | |
return clone; | |
}, | |
append: function(original){ | |
for (var i = 1, l = arguments.length; i < l; i++){ | |
var extended = arguments[i] || {}; | |
for (var key in extended) original[key] = extended[key]; | |
} | |
return original; | |
} | |
}); | |
// Object-less types | |
['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){ | |
new Type(name); | |
}); | |
})(); | |
/* | |
--- | |
name: Array | |
description: Contains Array Prototypes like each, contains, and erase. | |
license: MIT-style license. | |
requires: Type | |
provides: Array | |
... | |
*/ | |
Array.implement({ | |
invoke: function(methodName){ | |
var args = Array.slice(arguments, 1); | |
return this.map(function(item){ | |
return item[methodName].apply(item, args); | |
}); | |
}, | |
every: function(fn, bind){ | |
for (var i = 0, l = this.length; i < l; i++){ | |
if ((i in this) && !fn.call(bind, this[i], i, this)) return false; | |
} | |
return true; | |
}, | |
filter: function(fn, bind){ | |
var results = []; | |
for (var i = 0, l = this.length; i < l; i++){ | |
if ((i in this) && fn.call(bind, this[i], i, this)) results.push(this[i]); | |
} | |
return results; | |
}, | |
clean: function(){ | |
return this.filter(function(item){ | |
return item != null; | |
}); | |
}, | |
indexOf: function(item, from){ | |
var len = this.length; | |
for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){ | |
if (this[i] === item) return i; | |
} | |
return -1; | |
}, | |
map: function(fn, bind){ | |
var results = []; | |
for (var i = 0, l = this.length; i < l; i++){ | |
if (i in this) results[i] = fn.call(bind, this[i], i, this); | |
} | |
return results; | |
}, | |
some: function(fn, bind){ | |
for (var i = 0, l = this.length; i < l; i++){ | |
if ((i in this) && fn.call(bind, this[i], i, this)) return true; | |
} | |
return false; | |
}, | |
associate: function(keys){ | |
var obj = {}, length = Math.min(this.length, keys.length); | |
for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; | |
return obj; | |
}, | |
link: function(object){ | |
var result = {}; | |
for (var i = 0, l = this.length; i < l; i++){ | |
for (var key in object){ | |
if (object[key](this[i])){ | |
result[key] = this[i]; | |
delete object[key]; | |
break; | |
} | |
} | |
} | |
return result; | |
}, | |
contains: function(item, from){ | |
return this.indexOf(item, from) != -1; | |
}, | |
append: function(array){ | |
this.push.apply(this, array); | |
return this; | |
}, | |
getLast: function(){ | |
return (this.length) ? this[this.length - 1] : null; | |
}, | |
getRandom: function(){ | |
return (this.length) ? this[Number.random(0, this.length - 1)] : null; | |
}, | |
include: function(item){ | |
if (!this.contains(item)) this.push(item); | |
return this; | |
}, | |
combine: function(array){ | |
for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); | |
return this; | |
}, | |
erase: function(item){ | |
for (var i = this.length; i--;){ | |
if (this[i] === item) this.splice(i, 1); | |
} | |
return this; | |
}, | |
empty: function(){ | |
this.length = 0; | |
return this; | |
}, | |
flatten: function(){ | |
var array = []; | |
for (var i = 0, l = this.length; i < l; i++){ | |
var type = typeOf(this[i]); | |
if (type == 'null') continue; | |
array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]); | |
} | |
return array; | |
}, | |
pick: function(){ | |
for (var i = 0, l = this.length; i < l; i++){ | |
if (this[i] != null) return this[i]; | |
} | |
return null; | |
}, | |
hexToRgb: function(array){ | |
if (this.length != 3) return null; | |
var rgb = this.map(function(value){ | |
if (value.length == 1) value += value; | |
return value.toInt(16); | |
}); | |
return (array) ? rgb : 'rgb(' + rgb + ')'; | |
}, | |
rgbToHex: function(array){ | |
if (this.length < 3) return null; | |
if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; | |
var hex = []; | |
for (var i = 0; i < 3; i++){ | |
var bit = (this[i] - 0).toString(16); | |
hex.push((bit.length == 1) ? '0' + bit : bit); | |
} | |
return (array) ? hex : '#' + hex.join(''); | |
} | |
}); | |
/* | |
--- | |
name: String | |
description: Contains String Prototypes like camelCase, capitalize, test, and toInt. | |
license: MIT-style license. | |
requires: Type | |
provides: String | |
... | |
*/ | |
String.implement({ | |
test: function(regex, params){ | |
return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this); | |
}, | |
contains: function(string, separator){ | |
return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1; | |
}, | |
trim: function(){ | |
return this.replace(/^\s+|\s+$/g, ''); | |
}, | |
clean: function(){ | |
return this.replace(/\s+/g, ' ').trim(); | |
}, | |
camelCase: function(){ | |
return this.replace(/-\D/g, function(match){ | |
return match.charAt(1).toUpperCase(); | |
}); | |
}, | |
hyphenate: function(){ | |
return this.replace(/[A-Z]/g, function(match){ | |
return ('-' + match.charAt(0).toLowerCase()); | |
}); | |
}, | |
capitalize: function(){ | |
return this.replace(/\b[a-z]/g, function(match){ | |
return match.toUpperCase(); | |
}); | |
}, | |
escapeRegExp: function(){ | |
return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); | |
}, | |
toInt: function(base){ | |
return parseInt(this, base || 10); | |
}, | |
toFloat: function(){ | |
return parseFloat(this); | |
}, | |
hexToRgb: function(array){ | |
var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); | |
return (hex) ? hex.slice(1).hexToRgb(array) : null; | |
}, | |
rgbToHex: function(array){ | |
var rgb = this.match(/\d{1,3}/g); | |
return (rgb) ? rgb.rgbToHex(array) : null; | |
}, | |
substitute: function(object, regexp){ | |
return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){ | |
if (match.charAt(0) == '\\') return match.slice(1); | |
return (object[name] != undefined) ? object[name] : ''; | |
}); | |
} | |
}); | |
/* | |
--- | |
name: Function | |
description: Contains Function Prototypes like create, bind, pass, and delay. | |
license: MIT-style license. | |
requires: Type | |
provides: Function | |
... | |
*/ | |
Function.extend({ | |
attempt: function(){ | |
for (var i = 0, l = arguments.length; i < l; i++){ | |
try { | |
return arguments[i](); | |
} catch (e){} | |
} | |
return null; | |
} | |
}); | |
Function.implement({ | |
attempt: function(args, bind){ | |
try { | |
return this.apply(bind, Array.from(args)); | |
} catch (e){ | |
return null; | |
} | |
}, | |
bind: function(bind, args){ | |
var self = this; | |
if (args != null) args = Array.from(args); | |
return function(){ | |
return self.apply(bind, args || arguments); | |
}; | |
}, | |
delay: function(delay, bind, args){ | |
return setTimeout(this.bind(bind, args || []), delay); | |
}, | |
pass: function(args, bind){ | |
return this.bind(bind, args); | |
}, | |
periodical: function(periodical, bind, args){ | |
return setInterval(this.bind(bind, args || []), periodical); | |
}, | |
run: function(args, bind){ | |
return this.apply(bind, Array.from(args)); | |
} | |
}); | |
/* | |
--- | |
name: Number | |
description: Contains Number Prototypes like limit, round, times, and ceil. | |
license: MIT-style license. | |
requires: Type | |
provides: Number | |
... | |
*/ | |
Number.implement({ | |
limit: function(min, max){ | |
return Math.min(max, Math.max(min, this)); | |
}, | |
round: function(precision){ | |
precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0); | |
return Math.round(this * precision) / precision; | |
}, | |
times: function(fn, bind){ | |
for (var i = 0; i < this; i++) fn.call(bind, i, this); | |
}, | |
toFloat: function(){ | |
return parseFloat(this); | |
}, | |
toInt: function(base){ | |
return parseInt(this, base || 10); | |
} | |
}); | |
Number.alias('each', 'times'); | |
(function(math){ | |
var methods = {}; | |
math.each(function(name){ | |
if (!Number[name]) methods[name] = function(){ | |
return Math[name].apply(null, [this].concat(Array.from(arguments))); | |
}; | |
}); | |
Number.implement(methods); | |
})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); | |
/* | |
--- | |
name: Class | |
description: Contains the Class Function for easily creating, extending, and implementing reusable Classes. | |
license: MIT-style license. | |
requires: [Array, String, Function, Number] | |
provides: Class | |
... | |
*/ | |
(function(){ | |
var Class = this.Class = new Type('Class', function(params){ | |
if (instanceOf(params, Function)) params = {'initialize': params}; | |
var newClass = function(){ | |
reset(this); | |
if (newClass.$prototyping) return this; | |
this.$caller = null; | |
var value = (this.initialize) ? this.initialize.apply(this, arguments) : this; | |
this.$caller = this.caller = null; | |
return value; | |
}.extend(this); | |
newClass.implement(params); | |
newClass.$constructor = Class; | |
newClass.prototype.$constructor = newClass; | |
newClass.prototype.parent = parent; | |
return newClass; | |
}); | |
var parent = function(){ | |
if (!this.$caller) throw new Error('The method "parent" cannot be called.'); | |
var name = this.$caller.$name, parent = this.$caller.$owner.parent; | |
var previous = (parent) ? parent.prototype[name] : null; | |
if (!previous) throw new Error('The method "' + name + '" has no parent.'); | |
return previous.apply(this, arguments); | |
}; | |
var reset = function(object){ | |
for (var key in object){ | |
var value = object[key]; | |
switch (typeOf(value)){ | |
case 'object': | |
var F = function(){}; | |
F.prototype = value; | |
var instance = new F; | |
object[key] = reset(instance); | |
break; | |
case 'array': object[key] = value.clone(); break; | |
} | |
} | |
return object; | |
}; | |
var wrap = function(self, key, method){ | |
if (method.$origin) method = method.$origin; | |
var wrapper = function(){ | |
if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.'); | |
var caller = this.caller, current = this.$caller; | |
this.caller = current; this.$caller = wrapper; | |
var result = method.apply(this, arguments); | |
this.$caller = current; this.caller = caller; | |
return result; | |
}.extend({$owner: self, $origin: method, $name: key}); | |
return wrapper; | |
}; | |
var implement = function(key, value, retain){ | |
if (Class.Mutators.hasOwnProperty(key)){ | |
value = Class.Mutators[key].call(this, value); | |
if (value == null) return this; | |
} | |
if (typeOf(value) == 'function'){ | |
if (value.$hidden) return this; | |
this.prototype[key] = (retain) ? value : wrap(this, key, value); | |
} else { | |
Object.merge(this.prototype, key, value); | |
} | |
return this; | |
}; | |
var getInstance = function(klass){ | |
klass.$prototyping = true; | |
var proto = new klass; | |
delete klass.$prototyping; | |
return proto; | |
}; | |
Class.implement('implement', implement.overloadSetter()); | |
Class.Mutators = { | |
Extends: function(parent){ | |
this.parent = parent; | |
this.prototype = getInstance(parent); | |
}, | |
Implements: function(items){ | |
Array.from(items).each(function(item){ | |
var instance = new item; | |
for (var key in instance) implement.call(this, key, instance[key], true); | |
}, this); | |
} | |
}; | |
})(); | |
/* | |
--- | |
name: Class.Extras | |
description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks. | |
license: MIT-style license. | |
requires: Class | |
provides: [Class.Extras, Chain, Events, Options] | |
... | |
*/ | |
(function(){ | |
this.Chain = new Class({ | |
$chain: [], | |
chain: function(){ | |
this.$chain.append(Array.flatten(arguments)); | |
return this; | |
}, | |
callChain: function(){ | |
return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false; | |
}, | |
clearChain: function(){ | |
this.$chain.empty(); | |
return this; | |
} | |
}); | |
var Events = this.Events = new Class({ | |
$events: {}, | |
addEvent: function(type, fn, internal){ | |
type = Events.removeOn(type); | |
if (fn){ | |
this.$events[type] = this.$events[type] || []; | |
this.$events[type].include(fn); | |
if (internal) fn.internal = true; | |
} | |
return this; | |
}, | |
addEvents: function(events){ | |
for (var type in events) this.addEvent(type, events[type]); | |
return this; | |
}, | |
fireEvent: function(type, args, delay){ | |
type = Events.removeOn(type); | |
if (!this.$events || !this.$events[type]) return this; | |
this.$events[type].each(function(fn){ | |
(delay) ? fn.delay(delay, this, args) : fn.run(args, this); | |
}, this); | |
return this; | |
}, | |
removeEvent: function(type, fn){ | |
type = Events.removeOn(type); | |
if (!this.$events[type]) return this; | |
if (!fn.internal) this.$events[type].erase(fn); | |
return this; | |
}, | |
removeEvents: function(events){ | |
var type; | |
if (typeOf(events) == 'object'){ | |
for (type in events) this.removeEvent(type, events[type]); | |
return this; | |
} | |
if (events) events = Events.removeOn(events); | |
for (type in this.$events){ | |
if (events && events != type) continue; | |
var fns = this.$events[type]; | |
for (var i = fns.length; i--;) this.removeEvent(type, fns[i]); | |
} | |
return this; | |
} | |
}); | |
Events.removeOn = function(string){ | |
return string.replace(/^on([A-Z])/, function(full, first){ | |
return first.toLowerCase(); | |
}); | |
}; | |
this.Options = new Class({ | |
setOptions: function(){ | |
var options = this.options = Object.merge.run([{}, this.options].append(arguments)); | |
if (!this.addEvent) return this; | |
for (var option in options){ | |
if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue; | |
this.addEvent(option, options[option]); | |
delete options[option]; | |
} | |
return this; | |
} | |
}); | |
})(); | |
/* | |
--- | |
name: Object | |
description: Object generic methods | |
license: MIT-style license. | |
requires: Type | |
provides: [Object, Hash] | |
... | |
*/ | |
Object.extend({ | |
subset: function(object, keys){ | |
var results = {}; | |
for (var i = 0, l = keys.length; i < l; i++){ | |
var k = keys[i]; | |
results[k] = object[k]; | |
} | |
return results; | |
}, | |
map: function(object, fn, bind){ | |
var results = {}; | |
for (var key in object){ | |
if (object.hasOwnProperty(key)) results[key] = fn.call(bind, object[key], key, object); | |
} | |
return results; | |
}, | |
filter: function(object, fn, bind){ | |
var results = {}; | |
Object.each(object, function(value, key){ | |
if (fn.call(bind, value, key, object)) results[key] = value; | |
}); | |
return results; | |
}, | |
every: function(object, fn, bind){ | |
for (var key in object){ | |
if (object.hasOwnProperty(key) && !fn.call(bind, object[key], key)) return false; | |
} | |
return true; | |
}, | |
some: function(object, fn, bind){ | |
for (var key in object){ | |
if (object.hasOwnProperty(key) && fn.call(bind, object[key], key)) return true; | |
} | |
return false; | |
}, | |
keys: function(object){ | |
var keys = []; | |
for (var key in object){ | |
if (object.hasOwnProperty(key)) keys.push(key); | |
} | |
return keys; | |
}, | |
values: function(object){ | |
var values = []; | |
for (var key in object){ | |
if (object.hasOwnProperty(key)) values.push(object[key]); | |
} | |
return values; | |
}, | |
getLength: function(object){ | |
return Object.keys(object).length; | |
}, | |
keyOf: function(object, value){ | |
for (var key in object){ | |
if (object.hasOwnProperty(key) && object[key] === value) return key; | |
} | |
return null; | |
}, | |
contains: function(object, value){ | |
return Object.keyOf(object, value) != null; | |
}, | |
toQueryString: function(object, base){ | |
var queryString = []; | |
Object.each(object, function(value, key){ | |
if (base) key = base + '[' + key + ']'; | |
var result; | |
switch (typeOf(value)){ | |
case 'object': result = Object.toQueryString(value, key); break; | |
case 'array': | |
var qs = {}; | |
value.each(function(val, i){ | |
qs[i] = val; | |
}); | |
result = Object.toQueryString(qs, key); | |
break; | |
default: result = key + '=' + encodeURIComponent(value); | |
} | |
if (value != undefined) queryString.push(result); | |
}); | |
return queryString.join('&'); | |
} | |
}); | |
/* | |
--- | |
name: Loader | |
description: Loads MooTools as a CommonJS Module. | |
license: MIT-style license. | |
copyright: Copyright (c) 2010 [Christoph Pojer](http://cpojer.net/). | |
authors: Christoph Pojer | |
requires: [Core/Core, Core/Object] | |
provides: [Loader] | |
... | |
*/ | |
if (typeof exports != 'undefined') (function(){ | |
for (var key in this) if (!GLOBAL_ITEMS.contains(key)){ | |
exports[key] = this[key]; | |
} | |
exports.apply = function(object){ | |
Object.append(object, exports); | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment