├── README.md └── Source ├── CSS └── MediaQuery.js ├── Elements └── Elements.Dataset.js ├── Geolocation └── Locator.js ├── IndexedDB └── Database.js └── WebWorker └── Thread.js /README.md: -------------------------------------------------------------------------------- 1 | 2 | MooTools HTMLX 3 | 4 | This repository is for MooTools *contributors* that are not afraid to make new things. All users should download MooTools HTMLX from MooTools.net, but since it isn't offered there yet, you'll have to get it here - we know, that blows. 5 | 6 | See the documentation files included in this repo. We don't have anything on the MooTools Wiki for you, because they rest of the group says HTMLX isn't *official* yet. 7 | 8 | 9 | -------------------------------------------------------------------------------- /Source/CSS/MediaQuery.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: MediaQuery 5 | 6 | description: A JavaScript API for testing and interacting with CSS Media Queries 7 | 8 | license: MIT-style license. 9 | 10 | copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). 11 | 12 | authors: Daniel Buchner 13 | 14 | inspiration: 15 | - Programming Motherfucker, as it is the only thing that matters 16 | 17 | provides: MediaQuery 18 | 19 | ... 20 | */ 21 | 22 | var MediaQuery = new Class({ 23 | 24 | Implements: [Options, Events], 25 | 26 | options: { 27 | queries: {} 28 | }, 29 | 30 | initialize: function(options){ 31 | this.setOptions(options); 32 | 33 | this.results = {}; 34 | this.sheet = document.id('media_query_element') || new Element('style', { 35 | id: 'media_query_element', 36 | text: '#media_query_element{ z-index: 0; }' 37 | }).inject(document.head); 38 | 39 | Object.each(this.options.queries, function(v, k){ 40 | this.test(k, v); 41 | }, this); 42 | }, 43 | 44 | test: function(expression, fn){ 45 | this.sheet.set('media', expression); 46 | var result = this.results[expression] = this.sheet.getStyle('z-index') == 0; 47 | this.sheet.set('media', ''); 48 | 49 | if(fn && result) fn(expression); 50 | 51 | return this.results[expression]; 52 | } 53 | 54 | }); -------------------------------------------------------------------------------- /Source/Elements/Elements.Dataset.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var hasData = (function(){ 4 | var node = document.createElement('div'); 5 | node.setAttribute('data-id', '1'); 6 | return node.dataset && node.dataset.id && node.dataset.id == '1'; 7 | }()); 8 | 9 | [Element, Document, Window].invoke('implement', { 10 | 11 | setData: (hasData ? function(key, val){ 12 | this.dataset[key.camelCase()] = val; 13 | return this; 14 | } : function(key, val){ 15 | return this.setProperty('data-' + key.hyphenate(), val); 16 | }).overloadSetter(), 17 | 18 | getData: (hasData ? function(key){ 19 | return this.dataset[key.camelCase()] 20 | } : function(key){ 21 | return this.getProperty('data-' + key.hyphenate()); 22 | }).overloadGetter(), 23 | 24 | getDataset: hasData ? function(){ 25 | return Object.clone(this.dataset); 26 | } : function(){ 27 | var attributes = item.attributes, 28 | i = attributes.length, 29 | collection = {}; 30 | 31 | while(i--){ 32 | var attribute = attributes[ i ], 33 | key = attribute.attributeName; 34 | 35 | if (!key.test(/^data-/)) continue; 36 | 37 | key = camelKey(key.replace(/^data-/)); 38 | collection[ key ] = attribute.value; 39 | } 40 | 41 | return collection; 42 | }, 43 | 44 | eraseData: function(key){ 45 | return this.removeProperty('data-' + key.hyphenate()); 46 | } 47 | 48 | }); 49 | 50 | }()); 51 | -------------------------------------------------------------------------------- /Source/Geolocation/Locator.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Locator 5 | 6 | description: An augmented version of the Web Worker API. 7 | 8 | license: MIT-style license. 9 | 10 | copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). 11 | 12 | authors: Daniel Buchner 13 | 14 | inspiration: 15 | - Programming Motherfucker, as it is the only thing that matters 16 | 17 | provides: Locator 18 | 19 | ... 20 | */ 21 | 22 | var Locator = new Class({ 23 | 24 | Implements: [Options, Events], 25 | 26 | Binds: ['update', 'error'], 27 | 28 | options: { 29 | watch: false, 30 | autostart: false, 31 | position: { 32 | enableHighAccuracy: false, 33 | timeout: 30000, 34 | maximumAge: 120000 35 | } 36 | }, 37 | 38 | initialize: function(options){ 39 | this.setOptions(options); 40 | this.geo = navigator.geolocation; 41 | this.errors = { 0: 'error', 1: 'denied', 2: 'unavailable', 3: 'timeout' }; 42 | this.location = {}; 43 | if(this.options.autostart) this[(this.options.watch) ? 'watch' : 'getPosition'](); 44 | }, 45 | 46 | getPosition: function(){ 47 | this.geo.getCurrentPosition(this.update, this.error, this.options.position); 48 | return this; 49 | }, 50 | 51 | watch: function(){ 52 | this.watchID = this.geo.watchPosition(this.update, this.error, this.options.position); 53 | return this; 54 | }, 55 | 56 | update: function(position){ 57 | this.location = position; 58 | this.fireEvent('change', position); 59 | return this 60 | }, 61 | 62 | error: function(error){ 63 | this.fireEvent(this.errors[error.code], error); 64 | return this; 65 | }, 66 | 67 | clear: function(){ 68 | if(this.watchID || this.watchID == 0) this.geo.clearWatch(this.watchID); 69 | return this; 70 | } 71 | 72 | }); -------------------------------------------------------------------------------- /Source/IndexedDB/Database.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Database 5 | 6 | description: An augmented version of the IndexedDB API. 7 | 8 | license: MIT-style license. 9 | 10 | copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). 11 | 12 | authors: Daniel Buchner 13 | 14 | inspiration: 15 | - Programming Motherfucker, as it is the only thing that matters 16 | 17 | provides: Database 18 | 19 | ... 20 | */ 21 | 22 | (function(){ 23 | 24 | var errorTypes = { 25 | 1: 'unknown', 26 | 2: 'nonTransient', 27 | 3: 'notFound', 28 | 4: 'constraint', 29 | 5: 'data', 30 | 6: 'notAllowed', 31 | 7: 'transactionInactive', 32 | 8: 'abort', 33 | 9: 'readonly', 34 | 10: 'recoverable', 35 | 11: 'serial', 36 | 12: 'timeout' 37 | }, 38 | IDBMethods = { 39 | store: function(data){ 40 | this.put((typeof data == 'function') ? data.call(this) : data); 41 | return this; 42 | }, 43 | 44 | retrieve: function(key, fn){ 45 | var self = this; 46 | this.get(key).onsuccess = function(event){ 47 | fn.call(self, event, event.target.result); 48 | self.callChain(); 49 | }; 50 | return this; 51 | }, 52 | 53 | each: function(fn, bind, range, relay){ 54 | var self = this, 55 | returned = [], 56 | bind = (typeof bind === 'undefined') ? this : bind; 57 | 58 | this.openCursor(range).onsuccess = function(e) { 59 | var data = e.target.result; 60 | if(data) { 61 | returned.push(fn.call(bind, data.value, data.key, data)); 62 | data.continue(); 63 | } 64 | else{ 65 | if(relay) relay.call(bind, returned); 66 | self.callChain(); 67 | } 68 | }; 69 | 70 | return this; 71 | }, 72 | 73 | getRange: function(start, end, fn, bind){ 74 | var range = {}; 75 | this.each(function(v, k){ 76 | range[k] = v; 77 | }, this, IDBKeyRange.bound(start, end, false, false), fn.bind(bind, range)); 78 | return this; 79 | }, 80 | 81 | getKeys: function(fn){ 82 | this.each(function(value, key){ 83 | return key; 84 | }, this, null, fn); 85 | return this; 86 | }, 87 | 88 | getValues: function(fn){ 89 | this.each(function(value){ 90 | return value; 91 | }, this, null, fn); 92 | return this; 93 | }, 94 | 95 | getIndex: function(name){ 96 | var index = this.index(name); 97 | index.instance = this.instance; 98 | return index; 99 | } 100 | }, 101 | revive = function(object){ 102 | var revived = (object.objectStore) ? object.instance.getObject(object.objectStore.name).getIndex(object.name) : object.instance.getObject(object.name); 103 | revived.$chain = object.$chain; 104 | return object = revived; 105 | }; 106 | 107 | [ 108 | { type: 'IDBObjectStore', methods: IDBMethods }, 109 | { type: 'IDBIndex', methods: Object.subset(IDBMethods, ['retrieve', 'each', 'getRange', 'getKeys', 'getValues']) } 110 | ].each(function(object){ 111 | var global = window[object.type]; 112 | global.extend = Object.extend; 113 | new Type(object.type, global); 114 | global.implement(new Chain).implement(Object.map(object.methods, function(method){ 115 | return function(){ 116 | return method.apply(((this.objectStore || this).inactive) ? revive(this) : this, arguments); 117 | } 118 | })); 119 | }); 120 | 121 | Database = new Class({ 122 | 123 | Implements: [Options, Events, Chain], 124 | 125 | options: { 126 | version: '0.1', 127 | schema: [ // This schema is an example and should be removed before release 128 | { 129 | name: 'users', 130 | options: { 131 | keyPath: 'id' 132 | }, 133 | indexes: { 134 | 'UsersByName': { 135 | keyPath: 'username', 136 | options: { 137 | 'unique': true 138 | } 139 | } 140 | } 141 | }, 142 | { 143 | name: 'projects', 144 | options: { 145 | keyPath: 'id' 146 | }, 147 | indexes: { 148 | 'ProjectsByType': { 149 | keyPath: 'type' 150 | } 151 | } 152 | } 153 | ] 154 | }, 155 | 156 | initialize: function(name, options){ 157 | this.setOptions(options); 158 | this.name = name; 159 | this.open(); 160 | }, 161 | 162 | open: function(restart){ 163 | var self = this, 164 | options = this.options, 165 | request = (mozIndexedDB || webkitIndexedDB).open(this.name); 166 | 167 | request.onerror = function(error) { 168 | self.fireEvent('openFailure', error); 169 | }; 170 | 171 | request.onblocked = function(){ 172 | console.log('***BLOCKED***'); // remove console before release 173 | }; 174 | 175 | request.onsuccess = function(event) { 176 | var db = request.result; 177 | db.instance = self; 178 | self.db = db; 179 | 180 | db.onversionchange = function(e){ 181 | if(db.version != self.previousVersion) self.fireEvent('versionChange', e); 182 | self.close(); 183 | self.open(true); 184 | }; 185 | 186 | db.onerror = function(e) { 187 | self.fireEvent(errorTypes[e.target.errorCode], [e, request]); 188 | }; 189 | 190 | if(options.schema && !restart) { 191 | self.setVersion(options.version || db.version, function(){ 192 | options.schema.each(function(e){ 193 | if(!db.objectStoreNames.contains(e.name)) { 194 | var object = self.create(e.name, e.options); 195 | if(e.indexes){ 196 | Object.each(e.indexes, function(args, index){ 197 | object.createIndex(index, args.keyPath, args.options || {}); 198 | }); 199 | } 200 | } 201 | }); 202 | }); 203 | } 204 | 205 | self.fireEvent('open', event); 206 | }; 207 | }, 208 | 209 | setVersion: function(version, fn) { 210 | this.previousVersion = this.db.version; 211 | this.db.setVersion(version || this.db.version).onsuccess = (fn || function(){}).bind(this); 212 | return this; 213 | }, 214 | 215 | create: function(name, options){ 216 | return(!this.db.objectStoreNames.contains(name)) ? this.db.createObjectStore(name, options || {}) : this.getObject(name); 217 | }, 218 | 219 | getObject: function(name){ 220 | var object = this.db.transaction([name], IDBTransaction.READ_WRITE, 0).objectStore(name); 221 | object.instance = this; 222 | object.transaction.oncomplete = function(){ 223 | object.inactive = true; 224 | }; 225 | return object; 226 | }, 227 | 228 | close: function(){ 229 | this.fireEvent('close'); 230 | this.db.close(); 231 | } 232 | 233 | }); 234 | 235 | })(); -------------------------------------------------------------------------------- /Source/WebWorker/Thread.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | 4 | name: Thread 5 | 6 | description: An augmented version of the Web Worker API. 7 | 8 | license: MIT-style license. 9 | 10 | copyright: Copyright (c) 2006-2010 [Valerio Proietti](http://mad4milk.net/). 11 | 12 | authors: Daniel Buchner 13 | 14 | inspiration: 15 | - Programming Motherfucker, as it is the only thing that matters 16 | 17 | provides: Thread 18 | 19 | ... 20 | */ 21 | 22 | (function(){ 23 | var isWorker; 24 | try{ window } 25 | catch(e){ isWorker = true; } 26 | 27 | if(!isWorker) { 28 | 29 | this.Thread = new Class({ 30 | 31 | Implements: [Options, Events, Chain], 32 | 33 | options: { 34 | file: 'Thread', 35 | require: null 36 | }, 37 | 38 | initialize: function(options){ 39 | this.setOptions(options); 40 | this.setUrl(); 41 | this.worker = new Worker(this.url); 42 | this.require = Array.from(this.options.require); 43 | this.attach(); 44 | }, 45 | 46 | setUrl: function(){ 47 | var self = this, sources = $$('script').get('src').clean(); 48 | this.url = sources.each(function(e, i, a){ 49 | if(e.split('.js')[0].split('/').getLast() == self.options.file) a[0] = sources[i]; 50 | })[0]; 51 | return this; 52 | }, 53 | 54 | attach: function(){ 55 | var self = this; 56 | this.worker.onerror = function(){ 57 | self.fireEvent('error', arguments) 58 | }; 59 | this.worker.onmessage = function(msg){ 60 | var data = msg.data; 61 | self.fireEvent(data.id, data.response) 62 | .fireEvent('complete', data.response) 63 | .removeEvents(data.id); 64 | }; 65 | return this; 66 | }, 67 | 68 | send: function(work){ 69 | work.fn = work.fn.toString().replace(/\n/g, ''); 70 | work.arguments = Array.from(work.arguments); 71 | work.require = this.require; 72 | work.id = String.uniqueID(); 73 | 74 | if(work.onComplete) { 75 | this.addEvent(work.id, work.onComplete); 76 | delete work.onComplete; 77 | } 78 | 79 | this.worker.postMessage(work); 80 | 81 | return this; 82 | }, 83 | 84 | cancel: function(){ 85 | this.worker.terminate(); 86 | return this; 87 | } 88 | 89 | }); 90 | 91 | Function.implement('thread', function(options){ 92 | var self = this, thread = new Thread(options); 93 | 94 | return function(){ 95 | thread.send({ 96 | fn: self, 97 | arguments: arguments 98 | }); 99 | }; 100 | }); 101 | 102 | } 103 | else { 104 | onerror = function(event){ throw event.data }; 105 | onmessage = function(msg){ 106 | var work = msg.data, 107 | fn = work.fn, 108 | args = fn.split('(')[1].split(')')[0].replace(/\s/g,'').split(',') || []; 109 | 110 | args.push(fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}'))); 111 | 112 | if(work.require.length) importScripts.apply(this, work.require); 113 | 114 | postMessage({ 115 | id: work.id, 116 | response: Function.apply(null, args).apply(this, work.arguments) 117 | }); 118 | } 119 | } 120 | 121 | })(); --------------------------------------------------------------------------------