├── .gitignore ├── BRAINSTORM.md ├── Hom.js ├── LICENSE ├── README.md ├── Setup.hs ├── hom-lib.cabal ├── index.html ├── lib ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE-MIT ├── README.md ├── bundle.js ├── index.html ├── lib │ └── hom-lib.js ├── package.json └── test │ └── lib_test.js └── src ├── Hom ├── Animate.hs ├── App.hs └── DOM.hs └── Main.hs /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | cabal-dev 3 | *.o 4 | *.hi 5 | *.chi 6 | *.chs.h 7 | 8 | src/**/*.js 9 | .virtualenv 10 | .hsenv 11 | .cabal-sandbox/ 12 | cabal.sandbox.config 13 | cabal.config 14 | main 15 | hom-lib-* 16 | ./*.js 17 | -------------------------------------------------------------------------------- /BRAINSTORM.md: -------------------------------------------------------------------------------- 1 | # This file is my brainstorm file where I'm going to write down my thought stream. 2 | 3 | 4 | basically we want something like https://github.com/Matt-Esch/virtual-dom 5 | 6 | https://gist.github.com/Raynos/8414846 is a gist that lead to virtual-dom. with good explanations about the arch. 7 | 8 | 9 | We will have two threads: 10 | 11 | * an event dispatch thread on which we dispatch async events that will modify our State MVar. 12 | 13 | * a render thread which blocks on the State MVar until it sees a change. the MVar is a state-change witness here. So we know that that our state has changed if and only if we can take from the MVar. 14 | 15 | We then render a virtual dom with this new state and diff it against our old one. We retreive a list of 'patches' that instruct how 16 | we must modify the real DOM to execute this diff most efficiently. diffing tree is an O(n^3) problem but which can be approximated using 17 | heuristics pretty well. I'm just gonna re-use virtual-dom for this because although really interesting to write such an algorithm in haskell, 18 | it's way out of my current abilities. 19 | 20 | 21 | 22 | we want the virtual dom to be a "pure" function. so event handlers are just simple functions from state to state. 23 | how they are actually handeld and dispatched is upto the event dispatch thread. we as render thread ignore the fact that 24 | they are async or anything. it's not our responsibility. 25 | 26 | 27 | type EventCB state = EventData -> state -> state 28 | 29 | a := b = (a,b) 30 | type Prop = (JSString, JSString) 31 | type CB a= (JSString, EventCB a) 32 | 33 | -- creates a virtual domNode 34 | vnode :: JSString -> [Prop] -> [CB state] -> [VNode] -> VNode 35 | 36 | -- a simple counter widget might look like this: 37 | 38 | counterWidget count = 39 | vnode "div" [] [] 40 | [ vnode "div" ["class":="boldText"] [] [ vtext . show $ count ] 41 | , vnode "button" [] [["onClick" := const (+1)] [ vtext "increase!"] 42 | ] 43 | 44 | 45 | 46 | ... to becontinued. 47 | 48 | 49 | what I need to do is interpret the DOM in the event-dispatch-thread as well to change these "pure state transitions" to effects on the state MVar. That way the render-thread witnesses a state-change and will update the DOM by diffing. 50 | 51 | 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 arianvp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Hom 2 | === 3 | 4 | Hom - React.JS for Haskell! 5 | 6 | 7 | currently we're doing something similar at: 8 | 9 | http://github.com/ghcjs/ghcjs-vdom 10 | 11 | https://github.com/purescript-contrib/purescript-virtual-dom 12 | -------------------------------------------------------------------------------- /Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /hom-lib.cabal: -------------------------------------------------------------------------------- 1 | -- Initial hom-lib.cabal generated by cabal init. For further 2 | -- documentation, see http://haskell.org/cabal/users-guide/ 3 | 4 | name: hom-lib 5 | version: 0.1.0.0 6 | -- synopsis: 7 | -- description: 8 | license: GPL-3 9 | license-file: LICENSE 10 | author: Arian van Putten 11 | maintainer: aeroboy94@gmail.com 12 | -- copyright: 13 | category: Web 14 | build-type: Simple 15 | -- extra-source-files: 16 | cabal-version: >=1.10 17 | 18 | library 19 | exposed-modules: Hom.DOM 20 | -- other-modules: 21 | -- other-extensions: 22 | build-depends: base >=4.6 && <4.7, 23 | haste-lib ==0.3, transformers >=0.3 24 | ghc-options: "--with-js=./lib/bundle.js" 25 | hs-source-dirs: src 26 | default-language: Haskell2010 27 | 28 | executable lol 29 | Main-Is: Main.hs 30 | hs-source-dirs: src 31 | ghc-options: "--with-js=./lib/bundle.js" 32 | build-depends: base >=4.6 && <4.7, haste-lib >=0.3, transformers >=0.3 33 | other-modules: Hom.DOM 34 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /lib/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": "nofunc", 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true 14 | } 15 | -------------------------------------------------------------------------------- /lib/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | - '0.10' 5 | before_script: 6 | - npm install -g grunt-cli 7 | -------------------------------------------------------------------------------- /lib/Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(grunt) { 4 | 5 | // Project configuration. 6 | grunt.initConfig({ 7 | // nodeunit: { 8 | // files: ['test/**/*_test.js'], 9 | // }, 10 | jshint: { 11 | options: { 12 | jshintrc: '.jshintrc' 13 | }, 14 | gruntfile: { 15 | src: 'Gruntfile.js' 16 | }, 17 | lib: { 18 | src: ['lib/**/*.js'] 19 | }, 20 | // test: { 21 | //j src: ['test/**/*.js'] 22 | // }, 23 | }, 24 | browserify: { 25 | all: { 26 | src: 'lib/**/*.js', 27 | dest: 'bundle.js' 28 | } 29 | }, 30 | watch: { 31 | gruntfile: { 32 | files: '<%= jshint.gruntfile.src %>', 33 | tasks: ['jshint:gruntfile'] 34 | }, 35 | lib: { 36 | files: '<%= jshint.lib.src %>', 37 | tasks: ['jshint:lib', 'nodeunit'] 38 | }, 39 | test: { 40 | files: '<%= jshint.test.src %>', 41 | tasks: ['jshint:test', 'nodeunit'] 42 | }, 43 | }, 44 | }); 45 | 46 | // These plugins provide necessary tasks. 47 | grunt.loadNpmTasks('grunt-contrib-nodeunit'); 48 | grunt.loadNpmTasks('grunt-contrib-jshint'); 49 | grunt.loadNpmTasks('grunt-contrib-watch'); 50 | grunt.loadNpmTasks('grunt-browserify'); 51 | grunt.loadNpmTasks('grunt-file-append'); 52 | // Default task. 53 | grunt.registerTask('default', ['jshint', 'browserify', ]); 54 | 55 | }; 56 | -------------------------------------------------------------------------------- /lib/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Arian van Putten 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | # lib [![Build Status](https://secure.travis-ci.org/arian/lib.png?branch=master)](http://travis-ci.org/arian/lib) 2 | 3 | The best project ever. 4 | 5 | ## Getting Started 6 | Install the module with: `npm install lib` 7 | 8 | ```javascript 9 | var lib = require('lib'); 10 | lib.awesome(); // "awesome" 11 | ``` 12 | 13 | ## Documentation 14 | _(Coming soon)_ 15 | 16 | ## Examples 17 | _(Coming soon)_ 18 | 19 | ## Contributing 20 | In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). 21 | 22 | ## Release History 23 | _(Nothing yet)_ 24 | 25 | ## License 26 | Copyright (c) 2014 Arian van Putten 27 | Licensed under the MIT license. 28 | -------------------------------------------------------------------------------- /lib/bundle.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { 68 | var fn = queue.shift(); 69 | fn(); 70 | } 71 | } 72 | }, true); 73 | 74 | return function nextTick(fn) { 75 | queue.push(fn); 76 | window.postMessage('process-tick', '*'); 77 | }; 78 | } 79 | 80 | return function nextTick(fn) { 81 | setTimeout(fn, 0); 82 | }; 83 | })(); 84 | 85 | process.title = 'browser'; 86 | process.browser = true; 87 | process.env = {}; 88 | process.argv = []; 89 | 90 | function noop() {} 91 | 92 | process.on = noop; 93 | process.addListener = noop; 94 | process.once = noop; 95 | process.off = noop; 96 | process.removeListener = noop; 97 | process.removeAllListeners = noop; 98 | process.emit = noop; 99 | 100 | process.binding = function (name) { 101 | throw new Error('process.binding is not supported'); 102 | } 103 | 104 | // TODO(shtylman) 105 | process.cwd = function () { return '/' }; 106 | process.chdir = function (dir) { 107 | throw new Error('process.chdir is not supported'); 108 | }; 109 | 110 | },{}],4:[function(require,module,exports){ 111 | var raf = require("raf") 112 | var vtreeDiff = require("vtree/diff") 113 | var vdomCreate = require("vdom/create-element") 114 | var vdomPatch = require("vdom/patch") 115 | var TypedError = require("error/typed") 116 | 117 | var InvalidUpdateInRender = TypedError({ 118 | type: "main-loop.invalid.update.in-render", 119 | message: "main-loop: Unexpected update occurred in loop.\n" + 120 | "We are currently rendering a view, " + 121 | "you can't change state right now.\n" + 122 | "The diff is: {stringDiff}.\n" + 123 | "SUGGESTED FIX: find the state mutation in your view " + 124 | "or rendering function and remove it.\n" + 125 | "The view should not have any side effects.\n", 126 | diff: null, 127 | stringDiff: null 128 | }) 129 | 130 | module.exports = main 131 | 132 | function main(initialState, view, opts) { 133 | opts = opts || {} 134 | 135 | var currentState = initialState 136 | var create = opts.create || vdomCreate 137 | var diff = opts.diff || vtreeDiff 138 | var patch = opts.patch || vdomPatch 139 | var redrawScheduled = false 140 | 141 | var tree = opts.initialTree || view(currentState) 142 | var target = opts.target || create(tree, opts) 143 | var inRenderingTransaction = false 144 | 145 | currentState = null 146 | 147 | return { 148 | target: target, 149 | update: update 150 | } 151 | 152 | function update(state) { 153 | if (inRenderingTransaction) { 154 | throw InvalidUpdateInRender({ 155 | diff: state._diff, 156 | stringDiff: JSON.stringify(state._diff) 157 | }) 158 | } 159 | 160 | if (currentState === null && !redrawScheduled) { 161 | redrawScheduled = true 162 | raf(redraw) 163 | } 164 | 165 | currentState = state 166 | } 167 | 168 | function redraw() { 169 | redrawScheduled = false; 170 | if (currentState === null) { 171 | return 172 | } 173 | 174 | inRenderingTransaction = true 175 | var newTree = view(currentState) 176 | 177 | if (opts.createOnly) { 178 | create(newTree, opts) 179 | } else { 180 | var patches = diff(tree, newTree, opts) 181 | target = patch(target, patches, opts) 182 | } 183 | 184 | inRenderingTransaction = false 185 | tree = newTree 186 | currentState = null 187 | } 188 | } 189 | 190 | },{"error/typed":17,"raf":144,"vdom/create-element":19,"vdom/patch":25,"vtree/diff":27}],5:[function(require,module,exports){ 191 | // http://wiki.commonjs.org/wiki/Unit_Testing/1.0 192 | // 193 | // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! 194 | // 195 | // Originally from narwhal.js (http://narwhaljs.org) 196 | // Copyright (c) 2009 Thomas Robinson <280north.com> 197 | // 198 | // Permission is hereby granted, free of charge, to any person obtaining a copy 199 | // of this software and associated documentation files (the 'Software'), to 200 | // deal in the Software without restriction, including without limitation the 201 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 202 | // sell copies of the Software, and to permit persons to whom the Software is 203 | // furnished to do so, subject to the following conditions: 204 | // 205 | // The above copyright notice and this permission notice shall be included in 206 | // all copies or substantial portions of the Software. 207 | // 208 | // THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 209 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 210 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 211 | // AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 212 | // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 213 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 214 | 215 | // when used in node, this will actually load the util module we depend on 216 | // versus loading the builtin util module as happens otherwise 217 | // this is a bug in node module loading as far as I am concerned 218 | var util = require('util/'); 219 | 220 | var pSlice = Array.prototype.slice; 221 | var hasOwn = Object.prototype.hasOwnProperty; 222 | 223 | // 1. The assert module provides functions that throw 224 | // AssertionError's when particular conditions are not met. The 225 | // assert module must conform to the following interface. 226 | 227 | var assert = module.exports = ok; 228 | 229 | // 2. The AssertionError is defined in assert. 230 | // new assert.AssertionError({ message: message, 231 | // actual: actual, 232 | // expected: expected }) 233 | 234 | assert.AssertionError = function AssertionError(options) { 235 | this.name = 'AssertionError'; 236 | this.actual = options.actual; 237 | this.expected = options.expected; 238 | this.operator = options.operator; 239 | if (options.message) { 240 | this.message = options.message; 241 | this.generatedMessage = false; 242 | } else { 243 | this.message = getMessage(this); 244 | this.generatedMessage = true; 245 | } 246 | var stackStartFunction = options.stackStartFunction || fail; 247 | 248 | if (Error.captureStackTrace) { 249 | Error.captureStackTrace(this, stackStartFunction); 250 | } 251 | else { 252 | // non v8 browsers so we can have a stacktrace 253 | var err = new Error(); 254 | if (err.stack) { 255 | var out = err.stack; 256 | 257 | // try to strip useless frames 258 | var fn_name = stackStartFunction.name; 259 | var idx = out.indexOf('\n' + fn_name); 260 | if (idx >= 0) { 261 | // once we have located the function frame 262 | // we need to strip out everything before it (and its line) 263 | var next_line = out.indexOf('\n', idx + 1); 264 | out = out.substring(next_line + 1); 265 | } 266 | 267 | this.stack = out; 268 | } 269 | } 270 | }; 271 | 272 | // assert.AssertionError instanceof Error 273 | util.inherits(assert.AssertionError, Error); 274 | 275 | function replacer(key, value) { 276 | if (util.isUndefined(value)) { 277 | return '' + value; 278 | } 279 | if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) { 280 | return value.toString(); 281 | } 282 | if (util.isFunction(value) || util.isRegExp(value)) { 283 | return value.toString(); 284 | } 285 | return value; 286 | } 287 | 288 | function truncate(s, n) { 289 | if (util.isString(s)) { 290 | return s.length < n ? s : s.slice(0, n); 291 | } else { 292 | return s; 293 | } 294 | } 295 | 296 | function getMessage(self) { 297 | return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + 298 | self.operator + ' ' + 299 | truncate(JSON.stringify(self.expected, replacer), 128); 300 | } 301 | 302 | // At present only the three keys mentioned above are used and 303 | // understood by the spec. Implementations or sub modules can pass 304 | // other keys to the AssertionError's constructor - they will be 305 | // ignored. 306 | 307 | // 3. All of the following functions must throw an AssertionError 308 | // when a corresponding condition is not met, with a message that 309 | // may be undefined if not provided. All assertion methods provide 310 | // both the actual and expected values to the assertion error for 311 | // display purposes. 312 | 313 | function fail(actual, expected, message, operator, stackStartFunction) { 314 | throw new assert.AssertionError({ 315 | message: message, 316 | actual: actual, 317 | expected: expected, 318 | operator: operator, 319 | stackStartFunction: stackStartFunction 320 | }); 321 | } 322 | 323 | // EXTENSION! allows for well behaved errors defined elsewhere. 324 | assert.fail = fail; 325 | 326 | // 4. Pure assertion tests whether a value is truthy, as determined 327 | // by !!guard. 328 | // assert.ok(guard, message_opt); 329 | // This statement is equivalent to assert.equal(true, !!guard, 330 | // message_opt);. To test strictly for the value true, use 331 | // assert.strictEqual(true, guard, message_opt);. 332 | 333 | function ok(value, message) { 334 | if (!value) fail(value, true, message, '==', assert.ok); 335 | } 336 | assert.ok = ok; 337 | 338 | // 5. The equality assertion tests shallow, coercive equality with 339 | // ==. 340 | // assert.equal(actual, expected, message_opt); 341 | 342 | assert.equal = function equal(actual, expected, message) { 343 | if (actual != expected) fail(actual, expected, message, '==', assert.equal); 344 | }; 345 | 346 | // 6. The non-equality assertion tests for whether two objects are not equal 347 | // with != assert.notEqual(actual, expected, message_opt); 348 | 349 | assert.notEqual = function notEqual(actual, expected, message) { 350 | if (actual == expected) { 351 | fail(actual, expected, message, '!=', assert.notEqual); 352 | } 353 | }; 354 | 355 | // 7. The equivalence assertion tests a deep equality relation. 356 | // assert.deepEqual(actual, expected, message_opt); 357 | 358 | assert.deepEqual = function deepEqual(actual, expected, message) { 359 | if (!_deepEqual(actual, expected)) { 360 | fail(actual, expected, message, 'deepEqual', assert.deepEqual); 361 | } 362 | }; 363 | 364 | function _deepEqual(actual, expected) { 365 | // 7.1. All identical values are equivalent, as determined by ===. 366 | if (actual === expected) { 367 | return true; 368 | 369 | } else if (util.isBuffer(actual) && util.isBuffer(expected)) { 370 | if (actual.length != expected.length) return false; 371 | 372 | for (var i = 0; i < actual.length; i++) { 373 | if (actual[i] !== expected[i]) return false; 374 | } 375 | 376 | return true; 377 | 378 | // 7.2. If the expected value is a Date object, the actual value is 379 | // equivalent if it is also a Date object that refers to the same time. 380 | } else if (util.isDate(actual) && util.isDate(expected)) { 381 | return actual.getTime() === expected.getTime(); 382 | 383 | // 7.3 If the expected value is a RegExp object, the actual value is 384 | // equivalent if it is also a RegExp object with the same source and 385 | // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). 386 | } else if (util.isRegExp(actual) && util.isRegExp(expected)) { 387 | return actual.source === expected.source && 388 | actual.global === expected.global && 389 | actual.multiline === expected.multiline && 390 | actual.lastIndex === expected.lastIndex && 391 | actual.ignoreCase === expected.ignoreCase; 392 | 393 | // 7.4. Other pairs that do not both pass typeof value == 'object', 394 | // equivalence is determined by ==. 395 | } else if (!util.isObject(actual) && !util.isObject(expected)) { 396 | return actual == expected; 397 | 398 | // 7.5 For all other Object pairs, including Array objects, equivalence is 399 | // determined by having the same number of owned properties (as verified 400 | // with Object.prototype.hasOwnProperty.call), the same set of keys 401 | // (although not necessarily the same order), equivalent values for every 402 | // corresponding key, and an identical 'prototype' property. Note: this 403 | // accounts for both named and indexed properties on Arrays. 404 | } else { 405 | return objEquiv(actual, expected); 406 | } 407 | } 408 | 409 | function isArguments(object) { 410 | return Object.prototype.toString.call(object) == '[object Arguments]'; 411 | } 412 | 413 | function objEquiv(a, b) { 414 | if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) 415 | return false; 416 | // an identical 'prototype' property. 417 | if (a.prototype !== b.prototype) return false; 418 | //~~~I've managed to break Object.keys through screwy arguments passing. 419 | // Converting to array solves the problem. 420 | if (isArguments(a)) { 421 | if (!isArguments(b)) { 422 | return false; 423 | } 424 | a = pSlice.call(a); 425 | b = pSlice.call(b); 426 | return _deepEqual(a, b); 427 | } 428 | try { 429 | var ka = objectKeys(a), 430 | kb = objectKeys(b), 431 | key, i; 432 | } catch (e) {//happens when one is a string literal and the other isn't 433 | return false; 434 | } 435 | // having the same number of owned properties (keys incorporates 436 | // hasOwnProperty) 437 | if (ka.length != kb.length) 438 | return false; 439 | //the same set of keys (although not necessarily the same order), 440 | ka.sort(); 441 | kb.sort(); 442 | //~~~cheap key test 443 | for (i = ka.length - 1; i >= 0; i--) { 444 | if (ka[i] != kb[i]) 445 | return false; 446 | } 447 | //equivalent values for every corresponding key, and 448 | //~~~possibly expensive deep test 449 | for (i = ka.length - 1; i >= 0; i--) { 450 | key = ka[i]; 451 | if (!_deepEqual(a[key], b[key])) return false; 452 | } 453 | return true; 454 | } 455 | 456 | // 8. The non-equivalence assertion tests for any deep inequality. 457 | // assert.notDeepEqual(actual, expected, message_opt); 458 | 459 | assert.notDeepEqual = function notDeepEqual(actual, expected, message) { 460 | if (_deepEqual(actual, expected)) { 461 | fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); 462 | } 463 | }; 464 | 465 | // 9. The strict equality assertion tests strict equality, as determined by ===. 466 | // assert.strictEqual(actual, expected, message_opt); 467 | 468 | assert.strictEqual = function strictEqual(actual, expected, message) { 469 | if (actual !== expected) { 470 | fail(actual, expected, message, '===', assert.strictEqual); 471 | } 472 | }; 473 | 474 | // 10. The strict non-equality assertion tests for strict inequality, as 475 | // determined by !==. assert.notStrictEqual(actual, expected, message_opt); 476 | 477 | assert.notStrictEqual = function notStrictEqual(actual, expected, message) { 478 | if (actual === expected) { 479 | fail(actual, expected, message, '!==', assert.notStrictEqual); 480 | } 481 | }; 482 | 483 | function expectedException(actual, expected) { 484 | if (!actual || !expected) { 485 | return false; 486 | } 487 | 488 | if (Object.prototype.toString.call(expected) == '[object RegExp]') { 489 | return expected.test(actual); 490 | } else if (actual instanceof expected) { 491 | return true; 492 | } else if (expected.call({}, actual) === true) { 493 | return true; 494 | } 495 | 496 | return false; 497 | } 498 | 499 | function _throws(shouldThrow, block, expected, message) { 500 | var actual; 501 | 502 | if (util.isString(expected)) { 503 | message = expected; 504 | expected = null; 505 | } 506 | 507 | try { 508 | block(); 509 | } catch (e) { 510 | actual = e; 511 | } 512 | 513 | message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + 514 | (message ? ' ' + message : '.'); 515 | 516 | if (shouldThrow && !actual) { 517 | fail(actual, expected, 'Missing expected exception' + message); 518 | } 519 | 520 | if (!shouldThrow && expectedException(actual, expected)) { 521 | fail(actual, expected, 'Got unwanted exception' + message); 522 | } 523 | 524 | if ((shouldThrow && actual && expected && 525 | !expectedException(actual, expected)) || (!shouldThrow && actual)) { 526 | throw actual; 527 | } 528 | } 529 | 530 | // 11. Expected to throw an error: 531 | // assert.throws(block, Error_opt, message_opt); 532 | 533 | assert.throws = function(block, /*optional*/error, /*optional*/message) { 534 | _throws.apply(this, [true].concat(pSlice.call(arguments))); 535 | }; 536 | 537 | // EXTENSION! This is annoying to write outside this module. 538 | assert.doesNotThrow = function(block, /*optional*/message) { 539 | _throws.apply(this, [false].concat(pSlice.call(arguments))); 540 | }; 541 | 542 | assert.ifError = function(err) { if (err) {throw err;}}; 543 | 544 | var objectKeys = Object.keys || function (obj) { 545 | var keys = []; 546 | for (var key in obj) { 547 | if (hasOwn.call(obj, key)) keys.push(key); 548 | } 549 | return keys; 550 | }; 551 | 552 | },{"util/":8}],6:[function(require,module,exports){ 553 | if (typeof Object.create === 'function') { 554 | // implementation from standard node.js 'util' module 555 | module.exports = function inherits(ctor, superCtor) { 556 | ctor.super_ = superCtor 557 | ctor.prototype = Object.create(superCtor.prototype, { 558 | constructor: { 559 | value: ctor, 560 | enumerable: false, 561 | writable: true, 562 | configurable: true 563 | } 564 | }); 565 | }; 566 | } else { 567 | // old school shim for old browsers 568 | module.exports = function inherits(ctor, superCtor) { 569 | ctor.super_ = superCtor 570 | var TempCtor = function () {} 571 | TempCtor.prototype = superCtor.prototype 572 | ctor.prototype = new TempCtor() 573 | ctor.prototype.constructor = ctor 574 | } 575 | } 576 | 577 | },{}],7:[function(require,module,exports){ 578 | module.exports = function isBuffer(arg) { 579 | return arg && typeof arg === 'object' 580 | && typeof arg.copy === 'function' 581 | && typeof arg.fill === 'function' 582 | && typeof arg.readUInt8 === 'function'; 583 | } 584 | },{}],8:[function(require,module,exports){ 585 | (function (process,global){ 586 | // Copyright Joyent, Inc. and other Node contributors. 587 | // 588 | // Permission is hereby granted, free of charge, to any person obtaining a 589 | // copy of this software and associated documentation files (the 590 | // "Software"), to deal in the Software without restriction, including 591 | // without limitation the rights to use, copy, modify, merge, publish, 592 | // distribute, sublicense, and/or sell copies of the Software, and to permit 593 | // persons to whom the Software is furnished to do so, subject to the 594 | // following conditions: 595 | // 596 | // The above copyright notice and this permission notice shall be included 597 | // in all copies or substantial portions of the Software. 598 | // 599 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 600 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 601 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 602 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 603 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 604 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 605 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 606 | 607 | var formatRegExp = /%[sdj%]/g; 608 | exports.format = function(f) { 609 | if (!isString(f)) { 610 | var objects = []; 611 | for (var i = 0; i < arguments.length; i++) { 612 | objects.push(inspect(arguments[i])); 613 | } 614 | return objects.join(' '); 615 | } 616 | 617 | var i = 1; 618 | var args = arguments; 619 | var len = args.length; 620 | var str = String(f).replace(formatRegExp, function(x) { 621 | if (x === '%%') return '%'; 622 | if (i >= len) return x; 623 | switch (x) { 624 | case '%s': return String(args[i++]); 625 | case '%d': return Number(args[i++]); 626 | case '%j': 627 | try { 628 | return JSON.stringify(args[i++]); 629 | } catch (_) { 630 | return '[Circular]'; 631 | } 632 | default: 633 | return x; 634 | } 635 | }); 636 | for (var x = args[i]; i < len; x = args[++i]) { 637 | if (isNull(x) || !isObject(x)) { 638 | str += ' ' + x; 639 | } else { 640 | str += ' ' + inspect(x); 641 | } 642 | } 643 | return str; 644 | }; 645 | 646 | 647 | // Mark that a method should not be used. 648 | // Returns a modified function which warns once by default. 649 | // If --no-deprecation is set, then it is a no-op. 650 | exports.deprecate = function(fn, msg) { 651 | // Allow for deprecating things in the process of starting up. 652 | if (isUndefined(global.process)) { 653 | return function() { 654 | return exports.deprecate(fn, msg).apply(this, arguments); 655 | }; 656 | } 657 | 658 | if (process.noDeprecation === true) { 659 | return fn; 660 | } 661 | 662 | var warned = false; 663 | function deprecated() { 664 | if (!warned) { 665 | if (process.throwDeprecation) { 666 | throw new Error(msg); 667 | } else if (process.traceDeprecation) { 668 | console.trace(msg); 669 | } else { 670 | console.error(msg); 671 | } 672 | warned = true; 673 | } 674 | return fn.apply(this, arguments); 675 | } 676 | 677 | return deprecated; 678 | }; 679 | 680 | 681 | var debugs = {}; 682 | var debugEnviron; 683 | exports.debuglog = function(set) { 684 | if (isUndefined(debugEnviron)) 685 | debugEnviron = process.env.NODE_DEBUG || ''; 686 | set = set.toUpperCase(); 687 | if (!debugs[set]) { 688 | if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { 689 | var pid = process.pid; 690 | debugs[set] = function() { 691 | var msg = exports.format.apply(exports, arguments); 692 | console.error('%s %d: %s', set, pid, msg); 693 | }; 694 | } else { 695 | debugs[set] = function() {}; 696 | } 697 | } 698 | return debugs[set]; 699 | }; 700 | 701 | 702 | /** 703 | * Echos the value of a value. Trys to print the value out 704 | * in the best way possible given the different types. 705 | * 706 | * @param {Object} obj The object to print out. 707 | * @param {Object} opts Optional options object that alters the output. 708 | */ 709 | /* legacy: obj, showHidden, depth, colors*/ 710 | function inspect(obj, opts) { 711 | // default options 712 | var ctx = { 713 | seen: [], 714 | stylize: stylizeNoColor 715 | }; 716 | // legacy... 717 | if (arguments.length >= 3) ctx.depth = arguments[2]; 718 | if (arguments.length >= 4) ctx.colors = arguments[3]; 719 | if (isBoolean(opts)) { 720 | // legacy... 721 | ctx.showHidden = opts; 722 | } else if (opts) { 723 | // got an "options" object 724 | exports._extend(ctx, opts); 725 | } 726 | // set default options 727 | if (isUndefined(ctx.showHidden)) ctx.showHidden = false; 728 | if (isUndefined(ctx.depth)) ctx.depth = 2; 729 | if (isUndefined(ctx.colors)) ctx.colors = false; 730 | if (isUndefined(ctx.customInspect)) ctx.customInspect = true; 731 | if (ctx.colors) ctx.stylize = stylizeWithColor; 732 | return formatValue(ctx, obj, ctx.depth); 733 | } 734 | exports.inspect = inspect; 735 | 736 | 737 | // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics 738 | inspect.colors = { 739 | 'bold' : [1, 22], 740 | 'italic' : [3, 23], 741 | 'underline' : [4, 24], 742 | 'inverse' : [7, 27], 743 | 'white' : [37, 39], 744 | 'grey' : [90, 39], 745 | 'black' : [30, 39], 746 | 'blue' : [34, 39], 747 | 'cyan' : [36, 39], 748 | 'green' : [32, 39], 749 | 'magenta' : [35, 39], 750 | 'red' : [31, 39], 751 | 'yellow' : [33, 39] 752 | }; 753 | 754 | // Don't use 'blue' not visible on cmd.exe 755 | inspect.styles = { 756 | 'special': 'cyan', 757 | 'number': 'yellow', 758 | 'boolean': 'yellow', 759 | 'undefined': 'grey', 760 | 'null': 'bold', 761 | 'string': 'green', 762 | 'date': 'magenta', 763 | // "name": intentionally not styling 764 | 'regexp': 'red' 765 | }; 766 | 767 | 768 | function stylizeWithColor(str, styleType) { 769 | var style = inspect.styles[styleType]; 770 | 771 | if (style) { 772 | return '\u001b[' + inspect.colors[style][0] + 'm' + str + 773 | '\u001b[' + inspect.colors[style][1] + 'm'; 774 | } else { 775 | return str; 776 | } 777 | } 778 | 779 | 780 | function stylizeNoColor(str, styleType) { 781 | return str; 782 | } 783 | 784 | 785 | function arrayToHash(array) { 786 | var hash = {}; 787 | 788 | array.forEach(function(val, idx) { 789 | hash[val] = true; 790 | }); 791 | 792 | return hash; 793 | } 794 | 795 | 796 | function formatValue(ctx, value, recurseTimes) { 797 | // Provide a hook for user-specified inspect functions. 798 | // Check that value is an object with an inspect function on it 799 | if (ctx.customInspect && 800 | value && 801 | isFunction(value.inspect) && 802 | // Filter out the util module, it's inspect function is special 803 | value.inspect !== exports.inspect && 804 | // Also filter out any prototype objects using the circular check. 805 | !(value.constructor && value.constructor.prototype === value)) { 806 | var ret = value.inspect(recurseTimes, ctx); 807 | if (!isString(ret)) { 808 | ret = formatValue(ctx, ret, recurseTimes); 809 | } 810 | return ret; 811 | } 812 | 813 | // Primitive types cannot have properties 814 | var primitive = formatPrimitive(ctx, value); 815 | if (primitive) { 816 | return primitive; 817 | } 818 | 819 | // Look up the keys of the object. 820 | var keys = Object.keys(value); 821 | var visibleKeys = arrayToHash(keys); 822 | 823 | if (ctx.showHidden) { 824 | keys = Object.getOwnPropertyNames(value); 825 | } 826 | 827 | // IE doesn't make error fields non-enumerable 828 | // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx 829 | if (isError(value) 830 | && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { 831 | return formatError(value); 832 | } 833 | 834 | // Some type of object without properties can be shortcutted. 835 | if (keys.length === 0) { 836 | if (isFunction(value)) { 837 | var name = value.name ? ': ' + value.name : ''; 838 | return ctx.stylize('[Function' + name + ']', 'special'); 839 | } 840 | if (isRegExp(value)) { 841 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 842 | } 843 | if (isDate(value)) { 844 | return ctx.stylize(Date.prototype.toString.call(value), 'date'); 845 | } 846 | if (isError(value)) { 847 | return formatError(value); 848 | } 849 | } 850 | 851 | var base = '', array = false, braces = ['{', '}']; 852 | 853 | // Make Array say that they are Array 854 | if (isArray(value)) { 855 | array = true; 856 | braces = ['[', ']']; 857 | } 858 | 859 | // Make functions say that they are functions 860 | if (isFunction(value)) { 861 | var n = value.name ? ': ' + value.name : ''; 862 | base = ' [Function' + n + ']'; 863 | } 864 | 865 | // Make RegExps say that they are RegExps 866 | if (isRegExp(value)) { 867 | base = ' ' + RegExp.prototype.toString.call(value); 868 | } 869 | 870 | // Make dates with properties first say the date 871 | if (isDate(value)) { 872 | base = ' ' + Date.prototype.toUTCString.call(value); 873 | } 874 | 875 | // Make error with message first say the error 876 | if (isError(value)) { 877 | base = ' ' + formatError(value); 878 | } 879 | 880 | if (keys.length === 0 && (!array || value.length == 0)) { 881 | return braces[0] + base + braces[1]; 882 | } 883 | 884 | if (recurseTimes < 0) { 885 | if (isRegExp(value)) { 886 | return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); 887 | } else { 888 | return ctx.stylize('[Object]', 'special'); 889 | } 890 | } 891 | 892 | ctx.seen.push(value); 893 | 894 | var output; 895 | if (array) { 896 | output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); 897 | } else { 898 | output = keys.map(function(key) { 899 | return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); 900 | }); 901 | } 902 | 903 | ctx.seen.pop(); 904 | 905 | return reduceToSingleString(output, base, braces); 906 | } 907 | 908 | 909 | function formatPrimitive(ctx, value) { 910 | if (isUndefined(value)) 911 | return ctx.stylize('undefined', 'undefined'); 912 | if (isString(value)) { 913 | var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') 914 | .replace(/'/g, "\\'") 915 | .replace(/\\"/g, '"') + '\''; 916 | return ctx.stylize(simple, 'string'); 917 | } 918 | if (isNumber(value)) 919 | return ctx.stylize('' + value, 'number'); 920 | if (isBoolean(value)) 921 | return ctx.stylize('' + value, 'boolean'); 922 | // For some reason typeof null is "object", so special case here. 923 | if (isNull(value)) 924 | return ctx.stylize('null', 'null'); 925 | } 926 | 927 | 928 | function formatError(value) { 929 | return '[' + Error.prototype.toString.call(value) + ']'; 930 | } 931 | 932 | 933 | function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { 934 | var output = []; 935 | for (var i = 0, l = value.length; i < l; ++i) { 936 | if (hasOwnProperty(value, String(i))) { 937 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 938 | String(i), true)); 939 | } else { 940 | output.push(''); 941 | } 942 | } 943 | keys.forEach(function(key) { 944 | if (!key.match(/^\d+$/)) { 945 | output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, 946 | key, true)); 947 | } 948 | }); 949 | return output; 950 | } 951 | 952 | 953 | function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { 954 | var name, str, desc; 955 | desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; 956 | if (desc.get) { 957 | if (desc.set) { 958 | str = ctx.stylize('[Getter/Setter]', 'special'); 959 | } else { 960 | str = ctx.stylize('[Getter]', 'special'); 961 | } 962 | } else { 963 | if (desc.set) { 964 | str = ctx.stylize('[Setter]', 'special'); 965 | } 966 | } 967 | if (!hasOwnProperty(visibleKeys, key)) { 968 | name = '[' + key + ']'; 969 | } 970 | if (!str) { 971 | if (ctx.seen.indexOf(desc.value) < 0) { 972 | if (isNull(recurseTimes)) { 973 | str = formatValue(ctx, desc.value, null); 974 | } else { 975 | str = formatValue(ctx, desc.value, recurseTimes - 1); 976 | } 977 | if (str.indexOf('\n') > -1) { 978 | if (array) { 979 | str = str.split('\n').map(function(line) { 980 | return ' ' + line; 981 | }).join('\n').substr(2); 982 | } else { 983 | str = '\n' + str.split('\n').map(function(line) { 984 | return ' ' + line; 985 | }).join('\n'); 986 | } 987 | } 988 | } else { 989 | str = ctx.stylize('[Circular]', 'special'); 990 | } 991 | } 992 | if (isUndefined(name)) { 993 | if (array && key.match(/^\d+$/)) { 994 | return str; 995 | } 996 | name = JSON.stringify('' + key); 997 | if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { 998 | name = name.substr(1, name.length - 2); 999 | name = ctx.stylize(name, 'name'); 1000 | } else { 1001 | name = name.replace(/'/g, "\\'") 1002 | .replace(/\\"/g, '"') 1003 | .replace(/(^"|"$)/g, "'"); 1004 | name = ctx.stylize(name, 'string'); 1005 | } 1006 | } 1007 | 1008 | return name + ': ' + str; 1009 | } 1010 | 1011 | 1012 | function reduceToSingleString(output, base, braces) { 1013 | var numLinesEst = 0; 1014 | var length = output.reduce(function(prev, cur) { 1015 | numLinesEst++; 1016 | if (cur.indexOf('\n') >= 0) numLinesEst++; 1017 | return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; 1018 | }, 0); 1019 | 1020 | if (length > 60) { 1021 | return braces[0] + 1022 | (base === '' ? '' : base + '\n ') + 1023 | ' ' + 1024 | output.join(',\n ') + 1025 | ' ' + 1026 | braces[1]; 1027 | } 1028 | 1029 | return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; 1030 | } 1031 | 1032 | 1033 | // NOTE: These type checking functions intentionally don't use `instanceof` 1034 | // because it is fragile and can be easily faked with `Object.create()`. 1035 | function isArray(ar) { 1036 | return Array.isArray(ar); 1037 | } 1038 | exports.isArray = isArray; 1039 | 1040 | function isBoolean(arg) { 1041 | return typeof arg === 'boolean'; 1042 | } 1043 | exports.isBoolean = isBoolean; 1044 | 1045 | function isNull(arg) { 1046 | return arg === null; 1047 | } 1048 | exports.isNull = isNull; 1049 | 1050 | function isNullOrUndefined(arg) { 1051 | return arg == null; 1052 | } 1053 | exports.isNullOrUndefined = isNullOrUndefined; 1054 | 1055 | function isNumber(arg) { 1056 | return typeof arg === 'number'; 1057 | } 1058 | exports.isNumber = isNumber; 1059 | 1060 | function isString(arg) { 1061 | return typeof arg === 'string'; 1062 | } 1063 | exports.isString = isString; 1064 | 1065 | function isSymbol(arg) { 1066 | return typeof arg === 'symbol'; 1067 | } 1068 | exports.isSymbol = isSymbol; 1069 | 1070 | function isUndefined(arg) { 1071 | return arg === void 0; 1072 | } 1073 | exports.isUndefined = isUndefined; 1074 | 1075 | function isRegExp(re) { 1076 | return isObject(re) && objectToString(re) === '[object RegExp]'; 1077 | } 1078 | exports.isRegExp = isRegExp; 1079 | 1080 | function isObject(arg) { 1081 | return typeof arg === 'object' && arg !== null; 1082 | } 1083 | exports.isObject = isObject; 1084 | 1085 | function isDate(d) { 1086 | return isObject(d) && objectToString(d) === '[object Date]'; 1087 | } 1088 | exports.isDate = isDate; 1089 | 1090 | function isError(e) { 1091 | return isObject(e) && 1092 | (objectToString(e) === '[object Error]' || e instanceof Error); 1093 | } 1094 | exports.isError = isError; 1095 | 1096 | function isFunction(arg) { 1097 | return typeof arg === 'function'; 1098 | } 1099 | exports.isFunction = isFunction; 1100 | 1101 | function isPrimitive(arg) { 1102 | return arg === null || 1103 | typeof arg === 'boolean' || 1104 | typeof arg === 'number' || 1105 | typeof arg === 'string' || 1106 | typeof arg === 'symbol' || // ES6 symbol 1107 | typeof arg === 'undefined'; 1108 | } 1109 | exports.isPrimitive = isPrimitive; 1110 | 1111 | exports.isBuffer = require('./support/isBuffer'); 1112 | 1113 | function objectToString(o) { 1114 | return Object.prototype.toString.call(o); 1115 | } 1116 | 1117 | 1118 | function pad(n) { 1119 | return n < 10 ? '0' + n.toString(10) : n.toString(10); 1120 | } 1121 | 1122 | 1123 | var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 1124 | 'Oct', 'Nov', 'Dec']; 1125 | 1126 | // 26 Feb 16:19:34 1127 | function timestamp() { 1128 | var d = new Date(); 1129 | var time = [pad(d.getHours()), 1130 | pad(d.getMinutes()), 1131 | pad(d.getSeconds())].join(':'); 1132 | return [d.getDate(), months[d.getMonth()], time].join(' '); 1133 | } 1134 | 1135 | 1136 | // log is just a thin wrapper to console.log that prepends a timestamp 1137 | exports.log = function() { 1138 | console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); 1139 | }; 1140 | 1141 | 1142 | /** 1143 | * Inherit the prototype methods from one constructor into another. 1144 | * 1145 | * The Function.prototype.inherits from lang.js rewritten as a standalone 1146 | * function (not on Function.prototype). NOTE: If this file is to be loaded 1147 | * during bootstrapping this function needs to be rewritten using some native 1148 | * functions as prototype setup using normal JavaScript does not work as 1149 | * expected during bootstrapping (see mirror.js in r114903). 1150 | * 1151 | * @param {function} ctor Constructor function which needs to inherit the 1152 | * prototype. 1153 | * @param {function} superCtor Constructor function to inherit prototype from. 1154 | */ 1155 | exports.inherits = require('inherits'); 1156 | 1157 | exports._extend = function(origin, add) { 1158 | // Don't do anything if add isn't an object 1159 | if (!add || !isObject(add)) return origin; 1160 | 1161 | var keys = Object.keys(add); 1162 | var i = keys.length; 1163 | while (i--) { 1164 | origin[keys[i]] = add[keys[i]]; 1165 | } 1166 | return origin; 1167 | }; 1168 | 1169 | function hasOwnProperty(obj, prop) { 1170 | return Object.prototype.hasOwnProperty.call(obj, prop); 1171 | } 1172 | 1173 | }).call(this,require("JkpR2F"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 1174 | },{"./support/isBuffer":7,"JkpR2F":3,"inherits":6}],9:[function(require,module,exports){ 1175 | module.exports = function(obj) { 1176 | if (typeof obj === 'string') return camelCase(obj); 1177 | return walk(obj); 1178 | }; 1179 | 1180 | function walk (obj) { 1181 | if (!obj || typeof obj !== 'object') return obj; 1182 | if (isArray(obj)) return map(obj, walk); 1183 | return reduce(objectKeys(obj), function (acc, key) { 1184 | var camel = camelCase(key); 1185 | acc[camel] = walk(obj[key]); 1186 | return acc; 1187 | }, {}); 1188 | } 1189 | 1190 | function camelCase(str) { 1191 | return str.replace(/[_.-](\w|$)/g, function (_,x) { 1192 | return x.toUpperCase() 1193 | }); 1194 | } 1195 | 1196 | var isArray = Array.isArray || function (obj) { 1197 | return Object.prototype.toString.call(obj) === '[object Array]'; 1198 | }; 1199 | 1200 | var has = Object.prototype.hasOwnProperty; 1201 | var objectKeys = Object.keys || function (obj) { 1202 | var keys = []; 1203 | for (var key in obj) { 1204 | if (has.call(obj, key)) keys.push(key); 1205 | } 1206 | return keys; 1207 | }; 1208 | 1209 | function map (xs, f) { 1210 | if (xs.map) return xs.map(f); 1211 | var res = []; 1212 | for (var i = 0; i < xs.length; i++) { 1213 | res.push(f(xs[i], i)); 1214 | } 1215 | return res; 1216 | } 1217 | 1218 | function reduce (xs, f, acc) { 1219 | if (xs.reduce) return xs.reduce(f, acc); 1220 | for (var i = 0; i < xs.length; i++) { 1221 | acc = f(acc, xs[i], i); 1222 | } 1223 | return acc; 1224 | } 1225 | 1226 | },{}],10:[function(require,module,exports){ 1227 | var nargs = /\{([0-9a-zA-Z]+)\}/g 1228 | var slice = Array.prototype.slice 1229 | 1230 | module.exports = template 1231 | 1232 | function template(string) { 1233 | var args 1234 | 1235 | if (arguments.length === 2 && typeof arguments[1] === "object") { 1236 | args = arguments[1] 1237 | } else { 1238 | args = slice.call(arguments, 1) 1239 | } 1240 | 1241 | if (!args || !args.hasOwnProperty) { 1242 | args = {} 1243 | } 1244 | 1245 | return string.replace(nargs, function replaceArg(match, i, index) { 1246 | var result 1247 | 1248 | if (string[index - 1] === "{" && 1249 | string[index + match.length] === "}") { 1250 | return i 1251 | } else { 1252 | result = args.hasOwnProperty(i) ? args[i] : null 1253 | if (result === null || result === undefined) { 1254 | return "" 1255 | } 1256 | 1257 | return result 1258 | } 1259 | }) 1260 | } 1261 | },{}],11:[function(require,module,exports){ 1262 | module.exports = hasKeys 1263 | 1264 | function hasKeys(source) { 1265 | return source !== null && 1266 | (typeof source === "object" || 1267 | typeof source === "function") 1268 | } 1269 | 1270 | },{}],12:[function(require,module,exports){ 1271 | var Keys = require("object-keys") 1272 | var hasKeys = require("./has-keys") 1273 | 1274 | module.exports = extend 1275 | 1276 | function extend(target) { 1277 | var sources = [].slice.call(arguments, 1) 1278 | 1279 | for (var i = 0; i < sources.length; i++) { 1280 | var source = sources[i] 1281 | 1282 | if (!hasKeys(source)) { 1283 | continue 1284 | } 1285 | 1286 | var keys = Keys(source) 1287 | 1288 | for (var j = 0; j < keys.length; j++) { 1289 | var name = keys[j] 1290 | target[name] = source[name] 1291 | } 1292 | } 1293 | 1294 | return target 1295 | } 1296 | 1297 | },{"./has-keys":11,"object-keys":14}],13:[function(require,module,exports){ 1298 | var hasOwn = Object.prototype.hasOwnProperty; 1299 | var toString = Object.prototype.toString; 1300 | 1301 | var isFunction = function (fn) { 1302 | var isFunc = (typeof fn === 'function' && !(fn instanceof RegExp)) || toString.call(fn) === '[object Function]'; 1303 | if (!isFunc && typeof window !== 'undefined') { 1304 | isFunc = fn === window.setTimeout || fn === window.alert || fn === window.confirm || fn === window.prompt; 1305 | } 1306 | return isFunc; 1307 | }; 1308 | 1309 | module.exports = function forEach(obj, fn) { 1310 | if (!isFunction(fn)) { 1311 | throw new TypeError('iterator must be a function'); 1312 | } 1313 | var i, k, 1314 | isString = typeof obj === 'string', 1315 | l = obj.length, 1316 | context = arguments.length > 2 ? arguments[2] : null; 1317 | if (l === +l) { 1318 | for (i = 0; i < l; i++) { 1319 | if (context === null) { 1320 | fn(isString ? obj.charAt(i) : obj[i], i, obj); 1321 | } else { 1322 | fn.call(context, isString ? obj.charAt(i) : obj[i], i, obj); 1323 | } 1324 | } 1325 | } else { 1326 | for (k in obj) { 1327 | if (hasOwn.call(obj, k)) { 1328 | if (context === null) { 1329 | fn(obj[k], k, obj); 1330 | } else { 1331 | fn.call(context, obj[k], k, obj); 1332 | } 1333 | } 1334 | } 1335 | } 1336 | }; 1337 | 1338 | 1339 | },{}],14:[function(require,module,exports){ 1340 | module.exports = Object.keys || require('./shim'); 1341 | 1342 | 1343 | },{"./shim":16}],15:[function(require,module,exports){ 1344 | var toString = Object.prototype.toString; 1345 | 1346 | module.exports = function isArguments(value) { 1347 | var str = toString.call(value); 1348 | var isArguments = str === '[object Arguments]'; 1349 | if (!isArguments) { 1350 | isArguments = str !== '[object Array]' 1351 | && value !== null 1352 | && typeof value === 'object' 1353 | && typeof value.length === 'number' 1354 | && value.length >= 0 1355 | && toString.call(value.callee) === '[object Function]'; 1356 | } 1357 | return isArguments; 1358 | }; 1359 | 1360 | 1361 | },{}],16:[function(require,module,exports){ 1362 | (function () { 1363 | "use strict"; 1364 | 1365 | // modified from https://github.com/kriskowal/es5-shim 1366 | var has = Object.prototype.hasOwnProperty, 1367 | toString = Object.prototype.toString, 1368 | forEach = require('./foreach'), 1369 | isArgs = require('./isArguments'), 1370 | hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'), 1371 | hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'), 1372 | dontEnums = [ 1373 | "toString", 1374 | "toLocaleString", 1375 | "valueOf", 1376 | "hasOwnProperty", 1377 | "isPrototypeOf", 1378 | "propertyIsEnumerable", 1379 | "constructor" 1380 | ], 1381 | keysShim; 1382 | 1383 | keysShim = function keys(object) { 1384 | var isObject = object !== null && typeof object === 'object', 1385 | isFunction = toString.call(object) === '[object Function]', 1386 | isArguments = isArgs(object), 1387 | theKeys = []; 1388 | 1389 | if (!isObject && !isFunction && !isArguments) { 1390 | throw new TypeError("Object.keys called on a non-object"); 1391 | } 1392 | 1393 | if (isArguments) { 1394 | forEach(object, function (value) { 1395 | theKeys.push(value); 1396 | }); 1397 | } else { 1398 | var name, 1399 | skipProto = hasProtoEnumBug && isFunction; 1400 | 1401 | for (name in object) { 1402 | if (!(skipProto && name === 'prototype') && has.call(object, name)) { 1403 | theKeys.push(name); 1404 | } 1405 | } 1406 | } 1407 | 1408 | if (hasDontEnumBug) { 1409 | var ctor = object.constructor, 1410 | skipConstructor = ctor && ctor.prototype === object; 1411 | 1412 | forEach(dontEnums, function (dontEnum) { 1413 | if (!(skipConstructor && dontEnum === 'constructor') && has.call(object, dontEnum)) { 1414 | theKeys.push(dontEnum); 1415 | } 1416 | }); 1417 | } 1418 | return theKeys; 1419 | }; 1420 | 1421 | module.exports = keysShim; 1422 | }()); 1423 | 1424 | 1425 | },{"./foreach":13,"./isArguments":15}],17:[function(require,module,exports){ 1426 | var assert = require("assert/") 1427 | var camelize = require("camelize") 1428 | var template = require("string-template") 1429 | var extend = require("xtend/mutable") 1430 | 1431 | module.exports = TypedError 1432 | 1433 | function TypedError(args) { 1434 | assert(args, "args is required"); 1435 | assert(args.type, "args.type is required") 1436 | assert(args.message, "args.message is required") 1437 | 1438 | var message = args.message 1439 | 1440 | if (args.type && !args.name) { 1441 | var errorName = camelize(args.type) + "Error" 1442 | args.name = errorName[0].toUpperCase() + errorName.substr(1) 1443 | } 1444 | 1445 | createError.type = args.type; 1446 | createError._name = args.name; 1447 | 1448 | return createError; 1449 | 1450 | function createError(opts) { 1451 | var result = new Error() 1452 | 1453 | Object.defineProperty(result, "type", { 1454 | value: result.type, 1455 | enumerable: true, 1456 | writable: true, 1457 | configurable: true 1458 | }) 1459 | 1460 | var options = extend({}, args, opts) 1461 | 1462 | extend(result, options) 1463 | result.message = template(message, options) 1464 | 1465 | return result 1466 | } 1467 | } 1468 | 1469 | 1470 | },{"assert/":5,"camelize":9,"string-template":10,"xtend/mutable":12}],18:[function(require,module,exports){ 1471 | var isObject = require("is-object") 1472 | var isHook = require("vtree/is-vhook") 1473 | 1474 | module.exports = applyProperties 1475 | 1476 | function applyProperties(node, props, previous) { 1477 | for (var propName in props) { 1478 | var propValue = props[propName] 1479 | 1480 | if (propValue === undefined) { 1481 | removeProperty(node, props, previous, propName); 1482 | } else if (isHook(propValue)) { 1483 | propValue.hook(node, 1484 | propName, 1485 | previous ? previous[propName] : undefined) 1486 | } else { 1487 | if (isObject(propValue)) { 1488 | patchObject(node, props, previous, propName, propValue); 1489 | } else if (propValue !== undefined) { 1490 | node[propName] = propValue 1491 | } 1492 | } 1493 | } 1494 | } 1495 | 1496 | function removeProperty(node, props, previous, propName) { 1497 | if (previous) { 1498 | var previousValue = previous[propName] 1499 | 1500 | if (!isHook(previousValue)) { 1501 | if (propName === "style") { 1502 | for (var i in previousValue) { 1503 | node.style[i] = "" 1504 | } 1505 | } else if (typeof previousValue === "string") { 1506 | node[propName] = "" 1507 | } else { 1508 | node[propName] = null 1509 | } 1510 | } 1511 | } 1512 | } 1513 | 1514 | function patchObject(node, props, previous, propName, propValue) { 1515 | if(previous && isObject(previous[propName]) && 1516 | getPrototype(previous[propName]) !== getPrototype(propValue)) { 1517 | node[propName] = previousValue 1518 | return 1519 | } 1520 | 1521 | if (!isObject(node[propName])) { 1522 | node[propName] = {} 1523 | } 1524 | 1525 | var replacer = propName === "style" ? "" : undefined 1526 | 1527 | for (var k in propValue) { 1528 | var value = propValue[k] 1529 | node[propName][k] = (value === undefined) ? replacer : value 1530 | } 1531 | } 1532 | 1533 | function getPrototype(value) { 1534 | if (Object.getPrototypeOf) { 1535 | return Object.getPrototypeOf(value) 1536 | } else if (value.__proto__) { 1537 | return value.__proto__ 1538 | } else if (value.constructor) { 1539 | return value.constructor.prototype 1540 | } 1541 | } 1542 | 1543 | },{"is-object":22,"vtree/is-vhook":30}],19:[function(require,module,exports){ 1544 | var document = require("global/document") 1545 | 1546 | var applyProperties = require("./apply-properties") 1547 | 1548 | var isVNode = require("vtree/is-vnode") 1549 | var isVText = require("vtree/is-vtext") 1550 | var isWidget = require("vtree/is-widget") 1551 | var handleThunk = require("vtree/handle-thunk") 1552 | 1553 | module.exports = createElement 1554 | 1555 | function createElement(vnode, opts) { 1556 | var doc = opts ? opts.document || document : document 1557 | var warn = opts ? opts.warn : null 1558 | 1559 | vnode = handleThunk(vnode).a 1560 | 1561 | if (isWidget(vnode)) { 1562 | return vnode.init() 1563 | } else if (isVText(vnode)) { 1564 | return doc.createTextNode(vnode.text) 1565 | } else if (!isVNode(vnode)) { 1566 | if (warn) { 1567 | warn("Item is not a valid virtual dom node", vnode) 1568 | } 1569 | return null 1570 | } 1571 | 1572 | var node = (vnode.namespace === null) ? 1573 | doc.createElement(vnode.tagName) : 1574 | doc.createElementNS(vnode.namespace, vnode.tagName) 1575 | 1576 | var props = vnode.properties 1577 | applyProperties(node, props) 1578 | 1579 | var children = vnode.children 1580 | 1581 | for (var i = 0; i < children.length; i++) { 1582 | var childNode = createElement(children[i], opts) 1583 | if (childNode) { 1584 | node.appendChild(childNode) 1585 | } 1586 | } 1587 | 1588 | return node 1589 | } 1590 | 1591 | },{"./apply-properties":18,"global/document":21,"vtree/handle-thunk":28,"vtree/is-vnode":31,"vtree/is-vtext":32,"vtree/is-widget":33}],20:[function(require,module,exports){ 1592 | // Maps a virtual DOM tree onto a real DOM tree in an efficient manner. 1593 | // We don't want to read all of the DOM nodes in the tree so we use 1594 | // the in-order tree indexing to eliminate recursion down certain branches. 1595 | // We only recurse into a DOM node if we know that it contains a child of 1596 | // interest. 1597 | 1598 | var noChild = {} 1599 | 1600 | module.exports = domIndex 1601 | 1602 | function domIndex(rootNode, tree, indices, nodes) { 1603 | if (!indices || indices.length === 0) { 1604 | return {} 1605 | } else { 1606 | indices.sort(ascending) 1607 | return recurse(rootNode, tree, indices, nodes, 0) 1608 | } 1609 | } 1610 | 1611 | function recurse(rootNode, tree, indices, nodes, rootIndex) { 1612 | nodes = nodes || {} 1613 | 1614 | 1615 | if (rootNode) { 1616 | if (indexInRange(indices, rootIndex, rootIndex)) { 1617 | nodes[rootIndex] = rootNode 1618 | } 1619 | 1620 | var vChildren = tree.children 1621 | 1622 | if (vChildren) { 1623 | 1624 | var childNodes = rootNode.childNodes 1625 | 1626 | for (var i = 0; i < tree.children.length; i++) { 1627 | rootIndex += 1 1628 | 1629 | var vChild = vChildren[i] || noChild 1630 | var nextIndex = rootIndex + (vChild.count || 0) 1631 | 1632 | // skip recursion down the tree if there are no nodes down here 1633 | if (indexInRange(indices, rootIndex, nextIndex)) { 1634 | recurse(childNodes[i], vChild, indices, nodes, rootIndex) 1635 | } 1636 | 1637 | rootIndex = nextIndex 1638 | } 1639 | } 1640 | } 1641 | 1642 | return nodes 1643 | } 1644 | 1645 | // Binary search for an index in the interval [left, right] 1646 | function indexInRange(indices, left, right) { 1647 | if (indices.length === 0) { 1648 | return false 1649 | } 1650 | 1651 | var minIndex = 0 1652 | var maxIndex = indices.length - 1 1653 | var currentIndex 1654 | var currentItem 1655 | 1656 | while (minIndex <= maxIndex) { 1657 | currentIndex = ((maxIndex + minIndex) / 2) >> 0 1658 | currentItem = indices[currentIndex] 1659 | 1660 | if (minIndex === maxIndex) { 1661 | return currentItem >= left && currentItem <= right 1662 | } else if (currentItem < left) { 1663 | minIndex = currentIndex + 1 1664 | } else if (currentItem > right) { 1665 | maxIndex = currentIndex - 1 1666 | } else { 1667 | return true 1668 | } 1669 | } 1670 | 1671 | return false; 1672 | } 1673 | 1674 | function ascending(a, b) { 1675 | return a > b ? 1 : -1 1676 | } 1677 | 1678 | },{}],21:[function(require,module,exports){ 1679 | (function (global){ 1680 | var topLevel = typeof global !== 'undefined' ? global : 1681 | typeof window !== 'undefined' ? window : {} 1682 | var minDoc = require('min-document'); 1683 | 1684 | if (typeof document !== 'undefined') { 1685 | module.exports = document; 1686 | } else { 1687 | var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4']; 1688 | 1689 | if (!doccy) { 1690 | doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc; 1691 | } 1692 | 1693 | module.exports = doccy; 1694 | } 1695 | 1696 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 1697 | },{"min-document":2}],22:[function(require,module,exports){ 1698 | module.exports = isObject 1699 | 1700 | function isObject(x) { 1701 | return typeof x === "object" && x !== null 1702 | } 1703 | 1704 | },{}],23:[function(require,module,exports){ 1705 | var nativeIsArray = Array.isArray 1706 | var toString = Object.prototype.toString 1707 | 1708 | module.exports = nativeIsArray || isArray 1709 | 1710 | function isArray(obj) { 1711 | return toString.call(obj) === "[object Array]" 1712 | } 1713 | 1714 | },{}],24:[function(require,module,exports){ 1715 | var applyProperties = require("./apply-properties") 1716 | 1717 | var isWidget = require("vtree/is-widget") 1718 | var VPatch = require("vtree/vpatch") 1719 | 1720 | var render = require("./create-element") 1721 | var updateWidget = require("./update-widget") 1722 | 1723 | module.exports = applyPatch 1724 | 1725 | function applyPatch(vpatch, domNode, renderOptions) { 1726 | var type = vpatch.type 1727 | var vNode = vpatch.vNode 1728 | var patch = vpatch.patch 1729 | 1730 | switch (type) { 1731 | case VPatch.REMOVE: 1732 | return removeNode(domNode, vNode) 1733 | case VPatch.INSERT: 1734 | return insertNode(domNode, patch, renderOptions) 1735 | case VPatch.VTEXT: 1736 | return stringPatch(domNode, vNode, patch, renderOptions) 1737 | case VPatch.WIDGET: 1738 | return widgetPatch(domNode, vNode, patch, renderOptions) 1739 | case VPatch.VNODE: 1740 | return vNodePatch(domNode, vNode, patch, renderOptions) 1741 | case VPatch.ORDER: 1742 | reorderChildren(domNode, patch) 1743 | return domNode 1744 | case VPatch.PROPS: 1745 | applyProperties(domNode, patch, vNode.properties) 1746 | return domNode 1747 | case VPatch.THUNK: 1748 | return replaceRoot(domNode, 1749 | renderOptions.patch(domNode, patch, renderOptions)) 1750 | default: 1751 | return domNode 1752 | } 1753 | } 1754 | 1755 | function removeNode(domNode, vNode) { 1756 | var parentNode = domNode.parentNode 1757 | 1758 | if (parentNode) { 1759 | parentNode.removeChild(domNode) 1760 | } 1761 | 1762 | destroyWidget(domNode, vNode); 1763 | 1764 | return null 1765 | } 1766 | 1767 | function insertNode(parentNode, vNode, renderOptions) { 1768 | var newNode = render(vNode, renderOptions) 1769 | 1770 | if (parentNode) { 1771 | parentNode.appendChild(newNode) 1772 | } 1773 | 1774 | return parentNode 1775 | } 1776 | 1777 | function stringPatch(domNode, leftVNode, vText, renderOptions) { 1778 | var newNode 1779 | 1780 | if (domNode.nodeType === 3) { 1781 | domNode.replaceData(0, domNode.length, vText.text) 1782 | newNode = domNode 1783 | } else { 1784 | var parentNode = domNode.parentNode 1785 | newNode = render(vText, renderOptions) 1786 | 1787 | if (parentNode) { 1788 | parentNode.replaceChild(newNode, domNode) 1789 | } 1790 | } 1791 | 1792 | destroyWidget(domNode, leftVNode) 1793 | 1794 | return newNode 1795 | } 1796 | 1797 | function widgetPatch(domNode, leftVNode, widget, renderOptions) { 1798 | if (updateWidget(leftVNode, widget)) { 1799 | return widget.update(leftVNode, domNode) || domNode 1800 | } 1801 | 1802 | var parentNode = domNode.parentNode 1803 | var newWidget = render(widget, renderOptions) 1804 | 1805 | if (parentNode) { 1806 | parentNode.replaceChild(newWidget, domNode) 1807 | } 1808 | 1809 | destroyWidget(domNode, leftVNode) 1810 | 1811 | return newWidget 1812 | } 1813 | 1814 | function vNodePatch(domNode, leftVNode, vNode, renderOptions) { 1815 | var parentNode = domNode.parentNode 1816 | var newNode = render(vNode, renderOptions) 1817 | 1818 | if (parentNode) { 1819 | parentNode.replaceChild(newNode, domNode) 1820 | } 1821 | 1822 | destroyWidget(domNode, leftVNode) 1823 | 1824 | return newNode 1825 | } 1826 | 1827 | function destroyWidget(domNode, w) { 1828 | if (typeof w.destroy === "function" && isWidget(w)) { 1829 | w.destroy(domNode) 1830 | } 1831 | } 1832 | 1833 | function reorderChildren(domNode, bIndex) { 1834 | var children = [] 1835 | var childNodes = domNode.childNodes 1836 | var len = childNodes.length 1837 | var i 1838 | var reverseIndex = bIndex.reverse 1839 | 1840 | for (i = 0; i < len; i++) { 1841 | children.push(domNode.childNodes[i]) 1842 | } 1843 | 1844 | var insertOffset = 0 1845 | var move 1846 | var node 1847 | var insertNode 1848 | for (i = 0; i < len; i++) { 1849 | move = bIndex[i] 1850 | if (move !== undefined && move !== i) { 1851 | // the element currently at this index will be moved later so increase the insert offset 1852 | if (reverseIndex[i] > i) { 1853 | insertOffset++ 1854 | } 1855 | 1856 | node = children[move] 1857 | insertNode = childNodes[i + insertOffset] 1858 | if (node !== insertNode) { 1859 | domNode.insertBefore(node, insertNode) 1860 | } 1861 | 1862 | // the moved element came from the front of the array so reduce the insert offset 1863 | if (move < i) { 1864 | insertOffset-- 1865 | } 1866 | } 1867 | 1868 | // element at this index is scheduled to be removed so increase insert offset 1869 | if (i in bIndex.removes) { 1870 | insertOffset++ 1871 | } 1872 | } 1873 | } 1874 | 1875 | function replaceRoot(oldRoot, newRoot) { 1876 | if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) { 1877 | console.log(oldRoot) 1878 | oldRoot.parentNode.replaceChild(newRoot, oldRoot) 1879 | } 1880 | 1881 | return newRoot; 1882 | } 1883 | 1884 | },{"./apply-properties":18,"./create-element":19,"./update-widget":26,"vtree/is-widget":33,"vtree/vpatch":37}],25:[function(require,module,exports){ 1885 | var document = require("global/document") 1886 | var isArray = require("x-is-array") 1887 | 1888 | var domIndex = require("./dom-index") 1889 | var patchOp = require("./patch-op") 1890 | module.exports = patch 1891 | 1892 | function patch(rootNode, patches) { 1893 | return patchRecursive(rootNode, patches) 1894 | } 1895 | 1896 | function patchRecursive(rootNode, patches, renderOptions) { 1897 | var indices = patchIndices(patches) 1898 | 1899 | if (indices.length === 0) { 1900 | return rootNode 1901 | } 1902 | 1903 | var index = domIndex(rootNode, patches.a, indices) 1904 | var ownerDocument = rootNode.ownerDocument 1905 | 1906 | if (!renderOptions) { 1907 | renderOptions = { patch: patchRecursive } 1908 | if (ownerDocument !== document) { 1909 | renderOptions.document = ownerDocument 1910 | } 1911 | } 1912 | 1913 | for (var i = 0; i < indices.length; i++) { 1914 | var nodeIndex = indices[i] 1915 | rootNode = applyPatch(rootNode, 1916 | index[nodeIndex], 1917 | patches[nodeIndex], 1918 | renderOptions) 1919 | } 1920 | 1921 | return rootNode 1922 | } 1923 | 1924 | function applyPatch(rootNode, domNode, patchList, renderOptions) { 1925 | if (!domNode) { 1926 | return rootNode 1927 | } 1928 | 1929 | var newNode 1930 | 1931 | if (isArray(patchList)) { 1932 | for (var i = 0; i < patchList.length; i++) { 1933 | newNode = patchOp(patchList[i], domNode, renderOptions) 1934 | 1935 | if (domNode === rootNode) { 1936 | rootNode = newNode 1937 | } 1938 | } 1939 | } else { 1940 | newNode = patchOp(patchList, domNode, renderOptions) 1941 | 1942 | if (domNode === rootNode) { 1943 | rootNode = newNode 1944 | } 1945 | } 1946 | 1947 | return rootNode 1948 | } 1949 | 1950 | function patchIndices(patches) { 1951 | var indices = [] 1952 | 1953 | for (var key in patches) { 1954 | if (key !== "a") { 1955 | indices.push(Number(key)) 1956 | } 1957 | } 1958 | 1959 | return indices 1960 | } 1961 | 1962 | },{"./dom-index":20,"./patch-op":24,"global/document":21,"x-is-array":23}],26:[function(require,module,exports){ 1963 | var isWidget = require("vtree/is-widget") 1964 | 1965 | module.exports = updateWidget 1966 | 1967 | function updateWidget(a, b) { 1968 | if (isWidget(a) && isWidget(b)) { 1969 | if ("name" in a && "name" in b) { 1970 | return a.id === b.id 1971 | } else { 1972 | return a.init === b.init 1973 | } 1974 | } 1975 | 1976 | return false 1977 | } 1978 | 1979 | },{"vtree/is-widget":33}],27:[function(require,module,exports){ 1980 | var isArray = require("x-is-array") 1981 | var isObject = require("is-object") 1982 | 1983 | var VPatch = require("./vpatch") 1984 | var isVNode = require("./is-vnode") 1985 | var isVText = require("./is-vtext") 1986 | var isWidget = require("./is-widget") 1987 | var isThunk = require("./is-thunk") 1988 | var handleThunk = require("./handle-thunk") 1989 | 1990 | module.exports = diff 1991 | 1992 | function diff(a, b) { 1993 | var patch = { a: a } 1994 | walk(a, b, patch, 0) 1995 | return patch 1996 | } 1997 | 1998 | function walk(a, b, patch, index) { 1999 | if (a === b) { 2000 | if (isThunk(a) || isThunk(b)) { 2001 | thunks(a, b, patch, index) 2002 | } else { 2003 | hooks(b, patch, index) 2004 | } 2005 | return 2006 | } 2007 | 2008 | var apply = patch[index] 2009 | 2010 | if (b == null) { 2011 | apply = appendPatch(apply, new VPatch(VPatch.REMOVE, a, b)) 2012 | destroyWidgets(a, patch, index) 2013 | } else if (isThunk(a) || isThunk(b)) { 2014 | thunks(a, b, patch, index) 2015 | } else if (isVNode(b)) { 2016 | if (isVNode(a)) { 2017 | if (a.tagName === b.tagName && 2018 | a.namespace === b.namespace && 2019 | a.key === b.key) { 2020 | var propsPatch = diffProps(a.properties, b.properties, b.hooks) 2021 | if (propsPatch) { 2022 | apply = appendPatch(apply, 2023 | new VPatch(VPatch.PROPS, a, propsPatch)) 2024 | } 2025 | } else { 2026 | apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) 2027 | destroyWidgets(a, patch, index) 2028 | } 2029 | 2030 | apply = diffChildren(a, b, patch, apply, index) 2031 | } else { 2032 | apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b)) 2033 | destroyWidgets(a, patch, index) 2034 | } 2035 | } else if (isVText(b)) { 2036 | if (!isVText(a)) { 2037 | apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) 2038 | destroyWidgets(a, patch, index) 2039 | } else if (a.text !== b.text) { 2040 | apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b)) 2041 | } 2042 | } else if (isWidget(b)) { 2043 | apply = appendPatch(apply, new VPatch(VPatch.WIDGET, a, b)) 2044 | 2045 | if (!isWidget(a)) { 2046 | destroyWidgets(a, patch, index) 2047 | } 2048 | } 2049 | 2050 | if (apply) { 2051 | patch[index] = apply 2052 | } 2053 | } 2054 | 2055 | function diffProps(a, b, hooks) { 2056 | var diff 2057 | 2058 | for (var aKey in a) { 2059 | if (!(aKey in b)) { 2060 | diff = diff || {} 2061 | diff[aKey] = undefined 2062 | } 2063 | 2064 | var aValue = a[aKey] 2065 | var bValue = b[aKey] 2066 | 2067 | if (hooks && aKey in hooks) { 2068 | diff = diff || {} 2069 | diff[aKey] = bValue 2070 | } else { 2071 | if (isObject(aValue) && isObject(bValue)) { 2072 | if (getPrototype(bValue) !== getPrototype(aValue)) { 2073 | diff = diff || {} 2074 | diff[aKey] = bValue 2075 | } else { 2076 | var objectDiff = diffProps(aValue, bValue) 2077 | if (objectDiff) { 2078 | diff = diff || {} 2079 | diff[aKey] = objectDiff 2080 | } 2081 | } 2082 | } else if (aValue !== bValue) { 2083 | diff = diff || {} 2084 | diff[aKey] = bValue 2085 | } 2086 | } 2087 | } 2088 | 2089 | for (var bKey in b) { 2090 | if (!(bKey in a)) { 2091 | diff = diff || {} 2092 | diff[bKey] = b[bKey] 2093 | } 2094 | } 2095 | 2096 | return diff 2097 | } 2098 | 2099 | function getPrototype(value) { 2100 | if (Object.getPrototypeOf) { 2101 | return Object.getPrototypeOf(value) 2102 | } else if (value.__proto__) { 2103 | return value.__proto__ 2104 | } else if (value.constructor) { 2105 | return value.constructor.prototype 2106 | } 2107 | } 2108 | 2109 | function diffChildren(a, b, patch, apply, index) { 2110 | var aChildren = a.children 2111 | var bChildren = reorder(aChildren, b.children) 2112 | 2113 | var aLen = aChildren.length 2114 | var bLen = bChildren.length 2115 | var len = aLen > bLen ? aLen : bLen 2116 | 2117 | for (var i = 0; i < len; i++) { 2118 | var leftNode = aChildren[i] 2119 | var rightNode = bChildren[i] 2120 | index += 1 2121 | 2122 | if (!leftNode) { 2123 | if (rightNode) { 2124 | // Excess nodes in b need to be added 2125 | apply = appendPatch(apply, 2126 | new VPatch(VPatch.INSERT, null, rightNode)) 2127 | } 2128 | } else if (!rightNode) { 2129 | if (leftNode) { 2130 | // Excess nodes in a need to be removed 2131 | patch[index] = new VPatch(VPatch.REMOVE, leftNode, null) 2132 | destroyWidgets(leftNode, patch, index) 2133 | } 2134 | } else { 2135 | walk(leftNode, rightNode, patch, index) 2136 | } 2137 | 2138 | if (isVNode(leftNode) && leftNode.count) { 2139 | index += leftNode.count 2140 | } 2141 | } 2142 | 2143 | if (bChildren.moves) { 2144 | // Reorder nodes last 2145 | apply = appendPatch(apply, new VPatch(VPatch.ORDER, a, bChildren.moves)) 2146 | } 2147 | 2148 | return apply 2149 | } 2150 | 2151 | // Patch records for all destroyed widgets must be added because we need 2152 | // a DOM node reference for the destroy function 2153 | function destroyWidgets(vNode, patch, index) { 2154 | if (isWidget(vNode)) { 2155 | if (typeof vNode.destroy === "function") { 2156 | patch[index] = new VPatch(VPatch.REMOVE, vNode, null) 2157 | } 2158 | } else if (isVNode(vNode) && vNode.hasWidgets) { 2159 | var children = vNode.children 2160 | var len = children.length 2161 | for (var i = 0; i < len; i++) { 2162 | var child = children[i] 2163 | index += 1 2164 | 2165 | destroyWidgets(child, patch, index) 2166 | 2167 | if (isVNode(child) && child.count) { 2168 | index += child.count 2169 | } 2170 | } 2171 | } 2172 | } 2173 | 2174 | // Create a sub-patch for thunks 2175 | function thunks(a, b, patch, index) { 2176 | var nodes = handleThunk(a, b); 2177 | var thunkPatch = diff(nodes.a, nodes.b) 2178 | if (hasPatches(thunkPatch)) { 2179 | patch[index] = new VPatch(VPatch.THUNK, null, thunkPatch) 2180 | } 2181 | } 2182 | 2183 | function hasPatches(patch) { 2184 | for (var index in patch) { 2185 | if (index !== "a") { 2186 | return true; 2187 | } 2188 | } 2189 | 2190 | return false; 2191 | } 2192 | 2193 | // Execute hooks when two nodes are identical 2194 | function hooks(vNode, patch, index) { 2195 | if (isVNode(vNode)) { 2196 | if (vNode.hooks) { 2197 | patch[index] = new VPatch(VPatch.PROPS, vNode.hooks, vNode.hooks) 2198 | } 2199 | 2200 | if (vNode.descendantHooks) { 2201 | var children = vNode.children 2202 | var len = children.length 2203 | for (var i = 0; i < len; i++) { 2204 | var child = children[i] 2205 | index += 1 2206 | 2207 | hooks(child, patch, index) 2208 | 2209 | if (isVNode(child) && child.count) { 2210 | index += child.count 2211 | } 2212 | } 2213 | } 2214 | } 2215 | } 2216 | 2217 | // List diff, naive left to right reordering 2218 | function reorder(aChildren, bChildren) { 2219 | 2220 | var bKeys = keyIndex(bChildren) 2221 | 2222 | if (!bKeys) { 2223 | return bChildren 2224 | } 2225 | 2226 | var aKeys = keyIndex(aChildren) 2227 | 2228 | if (!aKeys) { 2229 | return bChildren 2230 | } 2231 | 2232 | var bMatch = {}, aMatch = {} 2233 | 2234 | for (var key in bKeys) { 2235 | bMatch[bKeys[key]] = aKeys[key] 2236 | } 2237 | 2238 | for (var key in aKeys) { 2239 | aMatch[aKeys[key]] = bKeys[key] 2240 | } 2241 | 2242 | var aLen = aChildren.length 2243 | var bLen = bChildren.length 2244 | var len = aLen > bLen ? aLen : bLen 2245 | var shuffle = [] 2246 | var freeIndex = 0 2247 | var i = 0 2248 | var moveIndex = 0 2249 | var moves = {} 2250 | var removes = moves.removes = {} 2251 | var reverse = moves.reverse = {} 2252 | var hasMoves = false 2253 | 2254 | while (freeIndex < len) { 2255 | var move = aMatch[i] 2256 | if (move !== undefined) { 2257 | shuffle[i] = bChildren[move] 2258 | if (move !== moveIndex) { 2259 | moves[move] = moveIndex 2260 | reverse[moveIndex] = move 2261 | hasMoves = true 2262 | } 2263 | moveIndex++ 2264 | } else if (i in aMatch) { 2265 | shuffle[i] = undefined 2266 | removes[i] = moveIndex++ 2267 | hasMoves = true 2268 | } else { 2269 | while (bMatch[freeIndex] !== undefined) { 2270 | freeIndex++ 2271 | } 2272 | 2273 | if (freeIndex < len) { 2274 | var freeChild = bChildren[freeIndex] 2275 | if (freeChild) { 2276 | shuffle[i] = freeChild 2277 | if (freeIndex !== moveIndex) { 2278 | hasMoves = true 2279 | moves[freeIndex] = moveIndex 2280 | reverse[moveIndex] = freeIndex 2281 | } 2282 | moveIndex++ 2283 | } 2284 | freeIndex++ 2285 | } 2286 | } 2287 | i++ 2288 | } 2289 | 2290 | if (hasMoves) { 2291 | shuffle.moves = moves 2292 | } 2293 | 2294 | return shuffle 2295 | } 2296 | 2297 | function keyIndex(children) { 2298 | var i, keys 2299 | 2300 | for (i = 0; i < children.length; i++) { 2301 | var child = children[i] 2302 | 2303 | if (child.key !== undefined) { 2304 | keys = keys || {} 2305 | keys[child.key] = i 2306 | } 2307 | } 2308 | 2309 | return keys 2310 | } 2311 | 2312 | function appendPatch(apply, patch) { 2313 | if (apply) { 2314 | if (isArray(apply)) { 2315 | apply.push(patch) 2316 | } else { 2317 | apply = [apply, patch] 2318 | } 2319 | 2320 | return apply 2321 | } else { 2322 | return patch 2323 | } 2324 | } 2325 | 2326 | },{"./handle-thunk":28,"./is-thunk":29,"./is-vnode":31,"./is-vtext":32,"./is-widget":33,"./vpatch":37,"is-object":34,"x-is-array":35}],28:[function(require,module,exports){ 2327 | var isVNode = require("./is-vnode") 2328 | var isVText = require("./is-vtext") 2329 | var isWidget = require("./is-widget") 2330 | var isThunk = require("./is-thunk") 2331 | 2332 | module.exports = handleThunk 2333 | 2334 | function handleThunk(a, b) { 2335 | var renderedA = a 2336 | var renderedB = b 2337 | 2338 | if (isThunk(b)) { 2339 | renderedB = renderThunk(b, a) 2340 | } 2341 | 2342 | if (isThunk(a)) { 2343 | renderedA = renderThunk(a, null) 2344 | } 2345 | 2346 | return { 2347 | a: renderedA, 2348 | b: renderedB 2349 | } 2350 | } 2351 | 2352 | function renderThunk(thunk, previous) { 2353 | var renderedThunk = thunk.vnode 2354 | 2355 | if (!renderedThunk) { 2356 | renderedThunk = thunk.vnode = thunk.render(previous) 2357 | } 2358 | 2359 | if (!(isVNode(renderedThunk) || 2360 | isVText(renderedThunk) || 2361 | isWidget(renderedThunk))) { 2362 | throw new Error("thunk did not return a valid node"); 2363 | } 2364 | 2365 | return renderedThunk 2366 | } 2367 | 2368 | },{"./is-thunk":29,"./is-vnode":31,"./is-vtext":32,"./is-widget":33}],29:[function(require,module,exports){ 2369 | module.exports = isThunk 2370 | 2371 | function isThunk(t) { 2372 | return t && t.type === "Thunk" 2373 | } 2374 | 2375 | },{}],30:[function(require,module,exports){ 2376 | module.exports = isHook 2377 | 2378 | function isHook(hook) { 2379 | return hook && typeof hook.hook === "function" && 2380 | !hook.hasOwnProperty("hook") 2381 | } 2382 | 2383 | },{}],31:[function(require,module,exports){ 2384 | var version = require("./version") 2385 | 2386 | module.exports = isVirtualNode 2387 | 2388 | function isVirtualNode(x) { 2389 | return x && x.type === "VirtualNode" && x.version === version 2390 | } 2391 | 2392 | },{"./version":36}],32:[function(require,module,exports){ 2393 | var version = require("./version") 2394 | 2395 | module.exports = isVirtualText 2396 | 2397 | function isVirtualText(x) { 2398 | return x && x.type === "VirtualText" && x.version === version 2399 | } 2400 | 2401 | },{"./version":36}],33:[function(require,module,exports){ 2402 | module.exports = isWidget 2403 | 2404 | function isWidget(w) { 2405 | return w && w.type === "Widget" 2406 | } 2407 | 2408 | },{}],34:[function(require,module,exports){ 2409 | module.exports=require(22) 2410 | },{}],35:[function(require,module,exports){ 2411 | module.exports=require(23) 2412 | },{}],36:[function(require,module,exports){ 2413 | module.exports = "1" 2414 | 2415 | },{}],37:[function(require,module,exports){ 2416 | var version = require("./version") 2417 | 2418 | VirtualPatch.NONE = 0 2419 | VirtualPatch.VTEXT = 1 2420 | VirtualPatch.VNODE = 2 2421 | VirtualPatch.WIDGET = 3 2422 | VirtualPatch.PROPS = 4 2423 | VirtualPatch.ORDER = 5 2424 | VirtualPatch.INSERT = 6 2425 | VirtualPatch.REMOVE = 7 2426 | VirtualPatch.THUNK = 8 2427 | 2428 | module.exports = VirtualPatch 2429 | 2430 | function VirtualPatch(type, vNode, patch) { 2431 | this.type = Number(type) 2432 | this.vNode = vNode 2433 | this.patch = patch 2434 | } 2435 | 2436 | VirtualPatch.prototype.version = version 2437 | VirtualPatch.prototype.type = "VirtualPatch" 2438 | 2439 | },{"./version":36}],38:[function(require,module,exports){ 2440 | var SingleEvent = require("geval/single") 2441 | var MultipleEvent = require("geval/multiple") 2442 | 2443 | /* 2444 | Pro tip: Don't require `mercury` itself. 2445 | require and depend on all these modules directly! 2446 | */ 2447 | var mercury = module.exports = { 2448 | // Entry 2449 | main: require("main-loop"), 2450 | app: app, 2451 | 2452 | // Input 2453 | Delegator: require("dom-delegator"), 2454 | input: input, 2455 | event: require("value-event/event"), 2456 | valueEvent: require("value-event/value"), 2457 | submitEvent: require("value-event/submit"), 2458 | changeEvent: require("value-event/change"), 2459 | keyEvent: require("value-event/key"), 2460 | 2461 | // State 2462 | array: require("observ-array"), 2463 | struct: require("observ-struct"), 2464 | // alias struct as hash for back compat 2465 | hash: require("observ-struct"), 2466 | varhash: require("observ-varhash"), 2467 | value: require("observ"), 2468 | 2469 | // Render 2470 | diff: require("vtree/diff"), 2471 | patch: require("vdom/patch"), 2472 | partial: require("vdom-thunk"), 2473 | create: require("vdom/create-element"), 2474 | h: require("virtual-hyperscript"), 2475 | svg: require("virtual-hyperscript/svg"), 2476 | 2477 | // Utilities 2478 | computed: require("observ/computed"), 2479 | watch: require("observ/watch") 2480 | } 2481 | 2482 | function input(names) { 2483 | if (!names) { 2484 | return SingleEvent() 2485 | } 2486 | 2487 | return MultipleEvent(names) 2488 | } 2489 | 2490 | function app(elem, observ, render, opts) { 2491 | mercury.Delegator(opts); 2492 | var loop = mercury.main(observ(), render, opts) 2493 | if (elem) { 2494 | elem.appendChild(loop.target) 2495 | } 2496 | return observ(loop.update) 2497 | } 2498 | 2499 | },{"dom-delegator":41,"geval/multiple":53,"geval/single":54,"main-loop":55,"observ":81,"observ-array":73,"observ-struct":76,"observ-varhash":78,"observ/computed":80,"observ/watch":82,"value-event/change":83,"value-event/event":84,"value-event/key":85,"value-event/submit":91,"value-event/value":92,"vdom-thunk":94,"vdom/create-element":98,"vdom/patch":104,"virtual-hyperscript":110,"virtual-hyperscript/svg":130,"vtree/diff":131}],39:[function(require,module,exports){ 2500 | var DataSet = require("data-set") 2501 | 2502 | module.exports = addEvent 2503 | 2504 | function addEvent(target, type, handler) { 2505 | var ds = DataSet(target) 2506 | var events = ds[type] 2507 | 2508 | if (!events) { 2509 | ds[type] = handler 2510 | } else if (Array.isArray(events)) { 2511 | if (events.indexOf(handler) === -1) { 2512 | events.push(handler) 2513 | } 2514 | } else if (events !== handler) { 2515 | ds[type] = [events, handler] 2516 | } 2517 | } 2518 | 2519 | },{"data-set":44}],40:[function(require,module,exports){ 2520 | var globalDocument = require("global/document") 2521 | var DataSet = require("data-set") 2522 | 2523 | var addEvent = require("./add-event.js") 2524 | var removeEvent = require("./remove-event.js") 2525 | var ProxyEvent = require("./proxy-event.js") 2526 | 2527 | module.exports = DOMDelegator 2528 | 2529 | function DOMDelegator(document) { 2530 | document = document || globalDocument 2531 | 2532 | this.target = document.documentElement 2533 | this.events = {} 2534 | this.rawEventListeners = {} 2535 | this.globalListeners = {} 2536 | } 2537 | 2538 | DOMDelegator.prototype.addEventListener = addEvent 2539 | DOMDelegator.prototype.removeEventListener = removeEvent 2540 | 2541 | DOMDelegator.prototype.addGlobalEventListener = 2542 | function addGlobalEventListener(eventName, fn) { 2543 | var listeners = this.globalListeners[eventName] 2544 | if (!listeners) { 2545 | listeners = this.globalListeners[eventName] = [] 2546 | } 2547 | 2548 | if (listeners.indexOf(fn) === -1) { 2549 | listeners.push(fn) 2550 | } 2551 | } 2552 | 2553 | DOMDelegator.prototype.removeGlobalEventListener = 2554 | function removeGlobalEventListener(eventName, fn) { 2555 | var listeners = this.globalListeners[eventName] 2556 | if (!listeners) { 2557 | return 2558 | } 2559 | 2560 | var index = listeners.indexOf(fn) 2561 | if (index !== -1) { 2562 | listeners.splice(index, 1) 2563 | } 2564 | } 2565 | 2566 | DOMDelegator.prototype.listenTo = function listenTo(eventName) { 2567 | if (this.events[eventName]) { 2568 | return 2569 | } 2570 | 2571 | this.events[eventName] = true 2572 | listen(this, eventName) 2573 | } 2574 | 2575 | DOMDelegator.prototype.unlistenTo = function unlistenTo(eventName) { 2576 | if (!this.events[eventName]) { 2577 | return 2578 | } 2579 | 2580 | this.events[eventName] = false 2581 | unlisten(this, eventName) 2582 | } 2583 | 2584 | function listen(delegator, eventName) { 2585 | var listener = delegator.rawEventListeners[eventName] 2586 | 2587 | if (!listener) { 2588 | listener = delegator.rawEventListeners[eventName] = 2589 | createHandler(eventName, delegator.globalListeners) 2590 | } 2591 | 2592 | delegator.target.addEventListener(eventName, listener, true) 2593 | } 2594 | 2595 | function unlisten(delegator, eventName) { 2596 | var listener = delegator.rawEventListeners[eventName] 2597 | 2598 | if (!listener) { 2599 | throw new Error("dom-delegator#unlistenTo: cannot " + 2600 | "unlisten to " + eventName) 2601 | } 2602 | 2603 | delegator.target.removeEventListener(eventName, listener, true) 2604 | } 2605 | 2606 | function createHandler(eventName, globalListeners) { 2607 | return handler 2608 | 2609 | function handler(ev) { 2610 | var globalHandlers = globalListeners[eventName] || [] 2611 | var listener = getListener(ev.target, eventName) 2612 | 2613 | var handlers = globalHandlers 2614 | .concat(listener ? listener.handlers : []) 2615 | if (handlers.length === 0) { 2616 | return 2617 | } 2618 | 2619 | var arg = new ProxyEvent(ev, listener) 2620 | 2621 | handlers.forEach(function (handler) { 2622 | typeof handler === "function" ? 2623 | handler(arg) : handler.handleEvent(arg) 2624 | }) 2625 | } 2626 | } 2627 | 2628 | function getListener(target, type) { 2629 | // terminate recursion if parent is `null` 2630 | if (target === null) { 2631 | return null 2632 | } 2633 | 2634 | var ds = DataSet(target) 2635 | // fetch list of handler fns for this event 2636 | var handler = ds[type] 2637 | var allHandler = ds.event 2638 | 2639 | if (!handler && !allHandler) { 2640 | return getListener(target.parentNode, type) 2641 | } 2642 | 2643 | var handlers = [].concat(handler || [], allHandler || []) 2644 | return new Listener(target, handlers) 2645 | } 2646 | 2647 | function Listener(target, handlers) { 2648 | this.currentTarget = target 2649 | this.handlers = handlers 2650 | } 2651 | 2652 | },{"./add-event.js":39,"./proxy-event.js":50,"./remove-event.js":51,"data-set":44,"global/document":47}],41:[function(require,module,exports){ 2653 | var Individual = require("individual") 2654 | var cuid = require("cuid") 2655 | var globalDocument = require("global/document") 2656 | 2657 | var DOMDelegator = require("./dom-delegator.js") 2658 | 2659 | var delegatorCache = Individual("__DOM_DELEGATOR_CACHE@9", { 2660 | delegators: {} 2661 | }) 2662 | var commonEvents = [ 2663 | "blur", "change", "click", "contextmenu", "dblclick", 2664 | "error","focus", "focusin", "focusout", "input", "keydown", 2665 | "keypress", "keyup", "load", "mousedown", "mouseup", 2666 | "resize", "scroll", "select", "submit", "unload" 2667 | ] 2668 | 2669 | /* Delegator is a thin wrapper around a singleton `DOMDelegator` 2670 | instance. 2671 | 2672 | Only one DOMDelegator should exist because we do not want 2673 | duplicate event listeners bound to the DOM. 2674 | 2675 | `Delegator` will also `listenTo()` all events unless 2676 | every caller opts out of it 2677 | */ 2678 | module.exports = Delegator 2679 | 2680 | function Delegator(opts) { 2681 | opts = opts || {} 2682 | var document = opts.document || globalDocument 2683 | 2684 | var cacheKey = document["__DOM_DELEGATOR_CACHE_TOKEN@9"] 2685 | 2686 | if (!cacheKey) { 2687 | cacheKey = 2688 | document["__DOM_DELEGATOR_CACHE_TOKEN@9"] = cuid() 2689 | } 2690 | 2691 | var delegator = delegatorCache.delegators[cacheKey] 2692 | 2693 | if (!delegator) { 2694 | delegator = delegatorCache.delegators[cacheKey] = 2695 | new DOMDelegator(document) 2696 | } 2697 | 2698 | if (opts.defaultEvents !== false) { 2699 | for (var i = 0; i < commonEvents.length; i++) { 2700 | delegator.listenTo(commonEvents[i]) 2701 | } 2702 | } 2703 | 2704 | return delegator 2705 | } 2706 | 2707 | 2708 | 2709 | },{"./dom-delegator.js":40,"cuid":42,"global/document":47,"individual":48}],42:[function(require,module,exports){ 2710 | /** 2711 | * cuid.js 2712 | * Collision-resistant UID generator for browsers and node. 2713 | * Sequential for fast db lookups and recency sorting. 2714 | * Safe for element IDs and server-side lookups. 2715 | * 2716 | * Extracted from CLCTR 2717 | * 2718 | * Copyright (c) Eric Elliott 2012 2719 | * MIT License 2720 | */ 2721 | 2722 | /*global window, navigator, document, require, process, module */ 2723 | (function (app) { 2724 | 'use strict'; 2725 | var namespace = 'cuid', 2726 | c = 0, 2727 | blockSize = 4, 2728 | base = 36, 2729 | discreteValues = Math.pow(base, blockSize), 2730 | 2731 | pad = function pad(num, size) { 2732 | var s = "000000000" + num; 2733 | return s.substr(s.length-size); 2734 | }, 2735 | 2736 | randomBlock = function randomBlock() { 2737 | return pad((Math.random() * 2738 | discreteValues << 0) 2739 | .toString(base), blockSize); 2740 | }, 2741 | 2742 | safeCounter = function () { 2743 | c = (c < discreteValues) ? c : 0; 2744 | c++; // this is not subliminal 2745 | return c - 1; 2746 | }, 2747 | 2748 | api = function cuid() { 2749 | // Starting with a lowercase letter makes 2750 | // it HTML element ID friendly. 2751 | var letter = 'c', // hard-coded allows for sequential access 2752 | 2753 | // timestamp 2754 | // warning: this exposes the exact date and time 2755 | // that the uid was created. 2756 | timestamp = (new Date().getTime()).toString(base), 2757 | 2758 | // Prevent same-machine collisions. 2759 | counter, 2760 | 2761 | // A few chars to generate distinct ids for different 2762 | // clients (so different computers are far less 2763 | // likely to generate the same id) 2764 | fingerprint = api.fingerprint(), 2765 | 2766 | // Grab some more chars from Math.random() 2767 | random = randomBlock() + randomBlock(); 2768 | 2769 | counter = pad(safeCounter().toString(base), blockSize); 2770 | 2771 | return (letter + timestamp + counter + fingerprint + random); 2772 | }; 2773 | 2774 | api.slug = function slug() { 2775 | var date = new Date().getTime().toString(36), 2776 | counter, 2777 | print = api.fingerprint().slice(0,1) + 2778 | api.fingerprint().slice(-1), 2779 | random = randomBlock().slice(-2); 2780 | 2781 | counter = safeCounter().toString(36).slice(-4); 2782 | 2783 | return date.slice(-2) + 2784 | counter + print + random; 2785 | }; 2786 | 2787 | api.globalCount = function globalCount() { 2788 | // We want to cache the results of this 2789 | var cache = (function calc() { 2790 | var i, 2791 | count = 0; 2792 | 2793 | for (i in window) { 2794 | count++; 2795 | } 2796 | 2797 | return count; 2798 | }()); 2799 | 2800 | api.globalCount = function () { return cache; }; 2801 | return cache; 2802 | }; 2803 | 2804 | api.fingerprint = function browserPrint() { 2805 | return pad((navigator.mimeTypes.length + 2806 | navigator.userAgent.length).toString(36) + 2807 | api.globalCount().toString(36), 4); 2808 | }; 2809 | 2810 | // don't change anything from here down. 2811 | if (app.register) { 2812 | app.register(namespace, api); 2813 | } else if (typeof module !== 'undefined') { 2814 | module.exports = api; 2815 | } else { 2816 | app[namespace] = api; 2817 | } 2818 | 2819 | }(this.applitude || this)); 2820 | 2821 | },{}],43:[function(require,module,exports){ 2822 | module.exports = createHash 2823 | 2824 | function createHash(elem) { 2825 | var attributes = elem.attributes 2826 | var hash = {} 2827 | 2828 | if (attributes === null || attributes === undefined) { 2829 | return hash 2830 | } 2831 | 2832 | for (var i = 0; i < attributes.length; i++) { 2833 | var attr = attributes[i] 2834 | 2835 | if (attr.name.substr(0,5) !== "data-") { 2836 | continue 2837 | } 2838 | 2839 | hash[attr.name.substr(5)] = attr.value 2840 | } 2841 | 2842 | return hash 2843 | } 2844 | 2845 | },{}],44:[function(require,module,exports){ 2846 | var createStore = require("weakmap-shim/create-store") 2847 | var Individual = require("individual") 2848 | 2849 | var createHash = require("./create-hash.js") 2850 | 2851 | var hashStore = Individual("__DATA_SET_WEAKMAP@3", createStore()) 2852 | 2853 | module.exports = DataSet 2854 | 2855 | function DataSet(elem) { 2856 | var store = hashStore(elem) 2857 | 2858 | if (!store.hash) { 2859 | store.hash = createHash(elem) 2860 | } 2861 | 2862 | return store.hash 2863 | } 2864 | 2865 | },{"./create-hash.js":43,"individual":48,"weakmap-shim/create-store":45}],45:[function(require,module,exports){ 2866 | var hiddenStore = require('./hidden-store.js'); 2867 | 2868 | module.exports = createStore; 2869 | 2870 | function createStore() { 2871 | var key = {}; 2872 | 2873 | return function (obj) { 2874 | if (typeof obj !== 'object' || obj === null) { 2875 | throw new Error('Weakmap-shim: Key must be object') 2876 | } 2877 | 2878 | var store = obj.valueOf(key); 2879 | return store && store.identity === key ? 2880 | store : hiddenStore(obj, key); 2881 | }; 2882 | } 2883 | 2884 | },{"./hidden-store.js":46}],46:[function(require,module,exports){ 2885 | module.exports = hiddenStore; 2886 | 2887 | function hiddenStore(obj, key) { 2888 | var store = { identity: key }; 2889 | var valueOf = obj.valueOf; 2890 | 2891 | Object.defineProperty(obj, "valueOf", { 2892 | value: function (value) { 2893 | return value !== key ? 2894 | valueOf.apply(this, arguments) : store; 2895 | }, 2896 | writable: true 2897 | }); 2898 | 2899 | return store; 2900 | } 2901 | 2902 | },{}],47:[function(require,module,exports){ 2903 | module.exports=require(21) 2904 | },{"min-document":2}],48:[function(require,module,exports){ 2905 | (function (global){ 2906 | var root = typeof window !== 'undefined' ? 2907 | window : typeof global !== 'undefined' ? 2908 | global : {}; 2909 | 2910 | module.exports = Individual 2911 | 2912 | function Individual(key, value) { 2913 | if (root[key]) { 2914 | return root[key] 2915 | } 2916 | 2917 | Object.defineProperty(root, key, { 2918 | value: value 2919 | , configurable: true 2920 | }) 2921 | 2922 | return value 2923 | } 2924 | 2925 | }).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 2926 | },{}],49:[function(require,module,exports){ 2927 | module.exports=require(6) 2928 | },{}],50:[function(require,module,exports){ 2929 | var inherits = require("inherits") 2930 | 2931 | var ALL_PROPS = [ 2932 | "altKey", "bubbles", "cancelable", "ctrlKey", 2933 | "eventPhase", "metaKey", "relatedTarget", "shiftKey", 2934 | "target", "timeStamp", "type", "view", "which" 2935 | ] 2936 | var KEY_PROPS = ["char", "charCode", "key", "keyCode"] 2937 | var MOUSE_PROPS = [ 2938 | "button", "buttons", "clientX", "clientY", "layerX", 2939 | "layerY", "offsetX", "offsetY", "pageX", "pageY", 2940 | "screenX", "screenY", "toElement" 2941 | ] 2942 | 2943 | var rkeyEvent = /^key|input/ 2944 | var rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/ 2945 | 2946 | module.exports = ProxyEvent 2947 | 2948 | function ProxyEvent(ev, listener) { 2949 | if (!(this instanceof ProxyEvent)) { 2950 | return new ProxyEvent(ev, listener) 2951 | } 2952 | 2953 | if (rkeyEvent.test(ev.type)) { 2954 | return new KeyEvent(ev, listener) 2955 | } else if (rmouseEvent.test(ev.type)) { 2956 | return new MouseEvent(ev, listener) 2957 | } 2958 | 2959 | for (var i = 0; i < ALL_PROPS.length; i++) { 2960 | var propKey = ALL_PROPS[i] 2961 | this[propKey] = ev[propKey] 2962 | } 2963 | 2964 | this._rawEvent = ev 2965 | this.currentTarget = listener ? listener.currentTarget : null 2966 | } 2967 | 2968 | ProxyEvent.prototype.preventDefault = function () { 2969 | this._rawEvent.preventDefault() 2970 | } 2971 | 2972 | function MouseEvent(ev, listener) { 2973 | for (var i = 0; i < ALL_PROPS.length; i++) { 2974 | var propKey = ALL_PROPS[i] 2975 | this[propKey] = ev[propKey] 2976 | } 2977 | 2978 | for (var j = 0; j < MOUSE_PROPS.length; j++) { 2979 | var mousePropKey = MOUSE_PROPS[j] 2980 | this[mousePropKey] = ev[mousePropKey] 2981 | } 2982 | 2983 | this._rawEvent = ev 2984 | this.currentTarget = listener ? listener.currentTarget : null 2985 | } 2986 | 2987 | inherits(MouseEvent, ProxyEvent) 2988 | 2989 | function KeyEvent(ev, listener) { 2990 | for (var i = 0; i < ALL_PROPS.length; i++) { 2991 | var propKey = ALL_PROPS[i] 2992 | this[propKey] = ev[propKey] 2993 | } 2994 | 2995 | for (var j = 0; j < KEY_PROPS.length; j++) { 2996 | var keyPropKey = KEY_PROPS[j] 2997 | this[keyPropKey] = ev[keyPropKey] 2998 | } 2999 | 3000 | this._rawEvent = ev 3001 | this.currentTarget = listener ? listener.currentTarget : null 3002 | } 3003 | 3004 | inherits(KeyEvent, ProxyEvent) 3005 | 3006 | },{"inherits":49}],51:[function(require,module,exports){ 3007 | var DataSet = require("data-set") 3008 | 3009 | module.exports = removeEvent 3010 | 3011 | function removeEvent(target, type, handler) { 3012 | var ds = DataSet(target) 3013 | var events = ds[type] 3014 | 3015 | if (!events) { 3016 | return 3017 | } else if (Array.isArray(events)) { 3018 | var index = events.indexOf(handler) 3019 | if (index !== -1) { 3020 | events.splice(index, 1) 3021 | } 3022 | } else if (events === handler) { 3023 | ds[type] = null 3024 | } 3025 | } 3026 | 3027 | },{"data-set":44}],52:[function(require,module,exports){ 3028 | module.exports = Event 3029 | 3030 | function Event() { 3031 | var listeners = [] 3032 | 3033 | return { broadcast: broadcast, listen: event } 3034 | 3035 | function broadcast(value) { 3036 | for (var i = 0; i < listeners.length; i++) { 3037 | listeners[i](value) 3038 | } 3039 | } 3040 | 3041 | function event(listener) { 3042 | listeners.push(listener) 3043 | 3044 | return removeListener 3045 | 3046 | function removeListener() { 3047 | var index = listeners.indexOf(listener) 3048 | if (index !== -1) { 3049 | listeners.splice(index, 1) 3050 | } 3051 | } 3052 | } 3053 | } 3054 | 3055 | },{}],53:[function(require,module,exports){ 3056 | var event = require("./single.js") 3057 | 3058 | module.exports = multiple 3059 | 3060 | function multiple(names) { 3061 | return names.reduce(function (acc, name) { 3062 | acc[name] = event() 3063 | return acc 3064 | }, {}) 3065 | } 3066 | 3067 | },{"./single.js":54}],54:[function(require,module,exports){ 3068 | var Event = require('./event.js') 3069 | 3070 | module.exports = Single 3071 | 3072 | function Single() { 3073 | var tuple = Event() 3074 | 3075 | return function event(value) { 3076 | if (typeof value === "function") { 3077 | return tuple.listen(value) 3078 | } else { 3079 | return tuple.broadcast(value) 3080 | } 3081 | } 3082 | } 3083 | 3084 | },{"./event.js":52}],55:[function(require,module,exports){ 3085 | module.exports=require(4) 3086 | },{"error/typed":68,"raf":69,"vdom/create-element":98,"vdom/patch":104,"vtree/diff":131}],56:[function(require,module,exports){ 3087 | module.exports=require(5) 3088 | },{"util/":59}],57:[function(require,module,exports){ 3089 | module.exports=require(6) 3090 | },{}],58:[function(require,module,exports){ 3091 | module.exports=require(7) 3092 | },{}],59:[function(require,module,exports){ 3093 | module.exports=require(8) 3094 | },{"./support/isBuffer":58,"JkpR2F":3,"inherits":57}],60:[function(require,module,exports){ 3095 | module.exports=require(9) 3096 | },{}],61:[function(require,module,exports){ 3097 | module.exports=require(10) 3098 | },{}],62:[function(require,module,exports){ 3099 | module.exports=require(11) 3100 | },{}],63:[function(require,module,exports){ 3101 | module.exports=require(12) 3102 | },{"./has-keys":62,"object-keys":65}],64:[function(require,module,exports){ 3103 | module.exports=require(13) 3104 | },{}],65:[function(require,module,exports){ 3105 | module.exports=require(14) 3106 | },{"./shim":67}],66:[function(require,module,exports){ 3107 | module.exports=require(15) 3108 | },{}],67:[function(require,module,exports){ 3109 | module.exports=require(16) 3110 | },{"./foreach":64,"./isArguments":66}],68:[function(require,module,exports){ 3111 | module.exports=require(17) 3112 | },{"assert/":56,"camelize":60,"string-template":61,"xtend/mutable":63}],69:[function(require,module,exports){ 3113 | var now = require('performance-now') 3114 | , global = typeof window === 'undefined' ? {} : window 3115 | , vendors = ['moz', 'webkit'] 3116 | , suffix = 'AnimationFrame' 3117 | , raf = global['request' + suffix] 3118 | , caf = global['cancel' + suffix] || global['cancelRequest' + suffix] 3119 | 3120 | for(var i = 0; i < vendors.length && !raf; i++) { 3121 | raf = global[vendors[i] + 'Request' + suffix] 3122 | caf = global[vendors[i] + 'Cancel' + suffix] 3123 | || global[vendors[i] + 'CancelRequest' + suffix] 3124 | } 3125 | 3126 | // Some versions of FF have rAF but not cAF 3127 | if(!raf || !caf) { 3128 | var last = 0 3129 | , id = 0 3130 | , queue = [] 3131 | , frameDuration = 1000 / 60 3132 | 3133 | raf = function(callback) { 3134 | if(queue.length === 0) { 3135 | var _now = now() 3136 | , next = Math.max(0, frameDuration - (_now - last)) 3137 | last = next + _now 3138 | setTimeout(function() { 3139 | var cp = queue.slice(0) 3140 | // Clear queue here to prevent 3141 | // callbacks from appending listeners 3142 | // to the current frame's queue 3143 | queue.length = 0 3144 | for (var i = 0; i < cp.length; i++) { 3145 | if (!cp[i].cancelled) { 3146 | cp[i].callback(last) 3147 | } 3148 | } 3149 | }, next) 3150 | } 3151 | queue.push({ 3152 | handle: ++id, 3153 | callback: callback, 3154 | cancelled: false 3155 | }) 3156 | return id 3157 | } 3158 | 3159 | caf = function(handle) { 3160 | for(var i = 0; i < queue.length; i++) { 3161 | if(queue[i].handle === handle) { 3162 | queue[i].cancelled = true 3163 | } 3164 | } 3165 | } 3166 | } 3167 | 3168 | module.exports = function() { 3169 | // Wrap in a new function to prevent 3170 | // `cancel` potentially being assigned 3171 | // to the native rAF function 3172 | return raf.apply(global, arguments) 3173 | } 3174 | module.exports.cancel = function() { 3175 | caf.apply(global, arguments) 3176 | } 3177 | 3178 | },{"performance-now":70}],70:[function(require,module,exports){ 3179 | (function (process){ 3180 | // Generated by CoffeeScript 1.6.3 3181 | (function() { 3182 | var getNanoSeconds, hrtime, loadTime; 3183 | 3184 | if ((typeof performance !== "undefined" && performance !== null) && performance.now) { 3185 | module.exports = function() { 3186 | return performance.now(); 3187 | }; 3188 | } else if ((typeof process !== "undefined" && process !== null) && process.hrtime) { 3189 | module.exports = function() { 3190 | return (getNanoSeconds() - loadTime) / 1e6; 3191 | }; 3192 | hrtime = process.hrtime; 3193 | getNanoSeconds = function() { 3194 | var hr; 3195 | hr = hrtime(); 3196 | return hr[0] * 1e9 + hr[1]; 3197 | }; 3198 | loadTime = getNanoSeconds(); 3199 | } else if (Date.now) { 3200 | module.exports = function() { 3201 | return Date.now() - loadTime; 3202 | }; 3203 | loadTime = Date.now(); 3204 | } else { 3205 | module.exports = function() { 3206 | return new Date().getTime() - loadTime; 3207 | }; 3208 | loadTime = new Date().getTime(); 3209 | } 3210 | 3211 | }).call(this); 3212 | 3213 | /* 3214 | //@ sourceMappingURL=performance-now.map 3215 | */ 3216 | 3217 | }).call(this,require("JkpR2F")) 3218 | },{"JkpR2F":3}],71:[function(require,module,exports){ 3219 | var setNonEnumerable = require("./lib/set-non-enumerable.js"); 3220 | 3221 | module.exports = addListener 3222 | 3223 | function addListener(observArray, observ) { 3224 | var list = observArray._list 3225 | 3226 | return observ(function (value) { 3227 | var valueList = observArray().slice() 3228 | var index = list.indexOf(observ) 3229 | 3230 | // This code path should never hit. If this happens 3231 | // there's a bug in the cleanup code 3232 | if (index === -1) { 3233 | var message = "observ-array: Unremoved observ listener" 3234 | var err = new Error(message) 3235 | err.list = list 3236 | err.index = index 3237 | err.observ = observ 3238 | throw err 3239 | } 3240 | 3241 | valueList.splice(index, 1, value) 3242 | setNonEnumerable(valueList, "_diff", [index, 1, value]) 3243 | 3244 | observArray.set(valueList) 3245 | }) 3246 | } 3247 | 3248 | },{"./lib/set-non-enumerable.js":74}],72:[function(require,module,exports){ 3249 | var ObservArray = require("./index.js") 3250 | 3251 | var slice = Array.prototype.slice 3252 | 3253 | var ARRAY_METHODS = [ 3254 | "concat", "slice", "every", "filter", "forEach", "indexOf", 3255 | "join", "lastIndexOf", "map", "reduce", "reduceRight", 3256 | "some", "toString", "toLocaleString" 3257 | ] 3258 | 3259 | var methods = ARRAY_METHODS.map(function (name) { 3260 | return [name, function () { 3261 | var res = this._list[name].apply(this._list, arguments) 3262 | 3263 | if (res && Array.isArray(res)) { 3264 | res = ObservArray(res) 3265 | } 3266 | 3267 | return res 3268 | }] 3269 | }) 3270 | 3271 | module.exports = ArrayMethods 3272 | 3273 | function ArrayMethods(obs) { 3274 | obs.push = observArrayPush 3275 | obs.pop = observArrayPop 3276 | obs.shift = observArrayShift 3277 | obs.unshift = observArrayUnshift 3278 | obs.reverse = notImplemented 3279 | obs.sort = notImplemented 3280 | 3281 | methods.forEach(function (tuple) { 3282 | obs[tuple[0]] = tuple[1] 3283 | }) 3284 | return obs 3285 | } 3286 | 3287 | 3288 | 3289 | function observArrayPush() { 3290 | var args = slice.call(arguments) 3291 | args.unshift(this._list.length, 0) 3292 | this.splice.apply(this, args) 3293 | 3294 | return this._list.length 3295 | } 3296 | function observArrayPop() { 3297 | return this.splice(this._list.length - 1, 1)[0] 3298 | } 3299 | function observArrayShift() { 3300 | return this.splice(0, 1)[0] 3301 | } 3302 | function observArrayUnshift() { 3303 | var args = slice.call(arguments) 3304 | args.unshift(0, 0) 3305 | this.splice.apply(this, args) 3306 | 3307 | return this._list.length 3308 | } 3309 | 3310 | 3311 | function notImplemented() { 3312 | throw new Error("Pull request welcome") 3313 | } 3314 | 3315 | },{"./index.js":73}],73:[function(require,module,exports){ 3316 | var Observ = require("observ") 3317 | 3318 | // circular dep between ArrayMethods & this file 3319 | module.exports = ObservArray 3320 | 3321 | var splice = require("./splice.js") 3322 | var ArrayMethods = require("./array-methods.js") 3323 | var addListener = require("./add-listener.js") 3324 | 3325 | /* ObservArray := (Array) => Observ< 3326 | Array & { _diff: Array } 3327 | > & { 3328 | splice: (index: Number, amount: Number, rest...: T) => 3329 | Array, 3330 | push: (values...: T) => Number, 3331 | filter: (lambda: Function, thisValue: Any) => Array, 3332 | indexOf: (item: T, fromIndex: Number) => Number 3333 | } 3334 | 3335 | Fix to make it more like ObservHash. 3336 | 3337 | I.e. you write observables into it. 3338 | reading methods take plain JS objects to read 3339 | and the value of the array is always an array of plain 3340 | objsect. 3341 | 3342 | The observ array instance itself would have indexed 3343 | properties that are the observables 3344 | */ 3345 | function ObservArray(initialList) { 3346 | // list is the internal mutable list observ instances that 3347 | // all methods on `obs` dispatch to. 3348 | var list = initialList 3349 | var initialState = [] 3350 | 3351 | // copy state out of initialList into initialState 3352 | list.forEach(function (observ, index) { 3353 | initialState[index] = typeof observ === "function" ? 3354 | observ() : observ 3355 | }) 3356 | 3357 | var obs = Observ(initialState) 3358 | obs.splice = splice 3359 | 3360 | obs.get = get 3361 | obs.getLength = getLength 3362 | obs.put = put 3363 | 3364 | // you better not mutate this list directly 3365 | // this is the list of observs instances 3366 | obs._list = list 3367 | 3368 | var removeListeners = list.map(function (observ) { 3369 | return typeof observ === "function" ? 3370 | addListener(obs, observ) : 3371 | null 3372 | }); 3373 | // this is a list of removal functions that must be called 3374 | // when observ instances are removed from `obs.list` 3375 | // not calling this means we do not GC our observ change 3376 | // listeners. Which causes rage bugs 3377 | obs._removeListeners = removeListeners 3378 | 3379 | return ArrayMethods(obs, list) 3380 | } 3381 | 3382 | function get(index) { 3383 | return this._list[index] 3384 | } 3385 | 3386 | function put(index, value) { 3387 | this.splice(index, 1, value) 3388 | } 3389 | 3390 | function getLength() { 3391 | return this._list.length 3392 | } 3393 | 3394 | },{"./add-listener.js":71,"./array-methods.js":72,"./splice.js":75,"observ":81}],74:[function(require,module,exports){ 3395 | module.exports = setNonEnumerable; 3396 | 3397 | function setNonEnumerable(object, key, value) { 3398 | Object.defineProperty(object, key, { 3399 | value: value, 3400 | writable: true, 3401 | configurable: true, 3402 | enumerable: false 3403 | }); 3404 | } 3405 | 3406 | },{}],75:[function(require,module,exports){ 3407 | var slice = Array.prototype.slice 3408 | 3409 | var addListener = require("./add-listener.js") 3410 | var setNonEnumerable = require("./lib/set-non-enumerable.js"); 3411 | 3412 | module.exports = splice 3413 | 3414 | // `obs.splice` is a mutable implementation of `splice()` 3415 | // that mutates both `list` and the internal `valueList` that 3416 | // is the current value of `obs` itself 3417 | function splice(index, amount) { 3418 | var obs = this 3419 | var args = slice.call(arguments, 0) 3420 | var valueList = obs().slice() 3421 | 3422 | // generate a list of args to mutate the internal 3423 | // list of only obs 3424 | var valueArgs = args.map(function (value, index) { 3425 | if (index === 0 || index === 1) { 3426 | return value 3427 | } 3428 | 3429 | // must unpack observables that we are adding 3430 | return typeof value === "function" ? value() : value 3431 | }) 3432 | 3433 | valueList.splice.apply(valueList, valueArgs) 3434 | // we remove the observs that we remove 3435 | var removed = obs._list.splice.apply(obs._list, args) 3436 | 3437 | var extraRemoveListeners = args.slice(2).map(function (observ) { 3438 | return typeof observ === "function" ? 3439 | addListener(obs, observ) : 3440 | null 3441 | }) 3442 | extraRemoveListeners.unshift(args[0], args[1]) 3443 | var removedListeners = obs._removeListeners.splice 3444 | .apply(obs._removeListeners, extraRemoveListeners) 3445 | 3446 | removedListeners.forEach(function (removeObservListener) { 3447 | if (removeObservListener) { 3448 | removeObservListener() 3449 | } 3450 | }) 3451 | 3452 | setNonEnumerable(valueList, "_diff", valueArgs) 3453 | 3454 | obs.set(valueList) 3455 | return removed 3456 | } 3457 | 3458 | },{"./add-listener.js":71,"./lib/set-non-enumerable.js":74}],76:[function(require,module,exports){ 3459 | var Observ = require("observ") 3460 | var extend = require("xtend") 3461 | 3462 | var blackList = ["name", "_diff", "_type", "_version"] 3463 | var blackListReasons = { 3464 | "name": "Clashes with `Function.prototype.name`.\n", 3465 | "_diff": "_diff is reserved key of observ-struct.\n", 3466 | "_type": "_type is reserved key of observ-struct.\n", 3467 | "_version": "_version is reserved key of observ-struct.\n" 3468 | } 3469 | var NO_TRANSACTION = {} 3470 | 3471 | /* ObservStruct := (Object>) => 3472 | Object> & 3473 | Observ & { 3474 | _diff: Object 3475 | }> 3476 | 3477 | */ 3478 | module.exports = ObservStruct 3479 | 3480 | function ObservStruct(struct) { 3481 | var keys = Object.keys(struct) 3482 | 3483 | var initialState = {} 3484 | var currentTransaction = NO_TRANSACTION 3485 | var nestedTransaction = NO_TRANSACTION 3486 | 3487 | keys.forEach(function (key) { 3488 | if (blackList.indexOf(key) !== -1) { 3489 | throw new Error("cannot create an observ-struct " + 3490 | "with a key named '" + key + "'.\n" + 3491 | blackListReasons[key]); 3492 | } 3493 | 3494 | var observ = struct[key] 3495 | initialState[key] = typeof observ === "function" ? 3496 | observ() : observ 3497 | }) 3498 | 3499 | var obs = Observ(initialState) 3500 | keys.forEach(function (key) { 3501 | var observ = struct[key] 3502 | obs[key] = observ 3503 | 3504 | if (typeof observ === "function") { 3505 | observ(function (value) { 3506 | if (nestedTransaction === value) { 3507 | return 3508 | } 3509 | 3510 | var state = extend(obs()) 3511 | state[key] = value 3512 | var diff = {} 3513 | diff[key] = value && value._diff ? 3514 | value._diff : value 3515 | state._diff = diff 3516 | currentTransaction = state 3517 | obs.set(state) 3518 | currentTransaction = NO_TRANSACTION 3519 | }) 3520 | } 3521 | }) 3522 | var _set = obs.set 3523 | obs.set = function trackDiff(value) { 3524 | if (currentTransaction === value) { 3525 | return _set(value) 3526 | } 3527 | 3528 | var newState = extend(value) 3529 | newState._diff = value 3530 | _set(newState) 3531 | } 3532 | 3533 | obs(function (newState) { 3534 | if (currentTransaction === newState) { 3535 | return 3536 | } 3537 | 3538 | keys.forEach(function (key) { 3539 | var observ = struct[key] 3540 | var newObservValue = newState[key] 3541 | 3542 | if (typeof observ === "function" && 3543 | observ() !== newObservValue 3544 | ) { 3545 | nestedTransaction = newObservValue 3546 | observ.set(newState[key]) 3547 | nestedTransaction = NO_TRANSACTION 3548 | } 3549 | }) 3550 | }) 3551 | 3552 | obs._type = "observ-struct" 3553 | obs._version = "4" 3554 | 3555 | return obs 3556 | } 3557 | 3558 | },{"observ":81,"xtend":77}],77:[function(require,module,exports){ 3559 | module.exports = extend 3560 | 3561 | function extend() { 3562 | var target = {} 3563 | 3564 | for (var i = 0; i < arguments.length; i++) { 3565 | var source = arguments[i] 3566 | 3567 | for (var key in source) { 3568 | if (source.hasOwnProperty(key)) { 3569 | target[key] = source[key] 3570 | } 3571 | } 3572 | } 3573 | 3574 | return target 3575 | } 3576 | 3577 | },{}],78:[function(require,module,exports){ 3578 | var Observ = require('observ') 3579 | var extend = require('xtend') 3580 | 3581 | var NO_TRANSACTION = {} 3582 | 3583 | ObservVarhash.Tombstone = new Tombstone() 3584 | 3585 | module.exports = ObservVarhash 3586 | 3587 | function ObservVarhash (hash, createValue) { 3588 | createValue = createValue || function (obj) { return obj } 3589 | 3590 | var initialState = {} 3591 | var currentTransaction = NO_TRANSACTION 3592 | 3593 | for (var key in hash) { 3594 | var observ = hash[key] 3595 | checkKey(key) 3596 | initialState[key] = isFunc(observ) ? observ() : observ 3597 | } 3598 | 3599 | var obs = Observ(initialState) 3600 | obs._removeListeners = {} 3601 | 3602 | var actions = methods(createValue) 3603 | for (var k in actions) { 3604 | obs[k] = actions[k] 3605 | } 3606 | 3607 | for (key in hash) { 3608 | obs[key] = createValue(hash[key], key) 3609 | 3610 | if (isFunc(obs[key])) { 3611 | obs._removeListeners[key] = obs[key](watch(obs, key, currentTransaction)) 3612 | } 3613 | } 3614 | 3615 | obs(function (newState) { 3616 | if (currentTransaction === newState) { 3617 | return 3618 | } 3619 | 3620 | for (var key in hash) { 3621 | var observ = hash[key] 3622 | 3623 | if (isFunc(observ) && observ() !== newState[key]) { 3624 | observ.set(newState[key]) 3625 | } 3626 | } 3627 | }) 3628 | 3629 | return obs 3630 | } 3631 | 3632 | function methods (createValue) { 3633 | return { 3634 | get: function (key) { 3635 | return this[key] 3636 | }, 3637 | 3638 | put: function (key, val) { 3639 | checkKey(key) 3640 | 3641 | var observ = createValue(val, key) 3642 | var state = extend(this()) 3643 | 3644 | state[key] = isFunc(observ) ? observ() : observ 3645 | 3646 | if (isFunc(this._removeListeners[key])) { 3647 | this._removeListeners[key]() 3648 | } 3649 | 3650 | this._removeListeners[key] = isFunc(observ) ? 3651 | observ(watch(this, key)) : null 3652 | 3653 | state._diff = diff(key, state[key]) 3654 | 3655 | this.set(state) 3656 | this[key] = observ 3657 | 3658 | return this 3659 | }, 3660 | 3661 | 'delete': function (key) { 3662 | var state = extend(this()) 3663 | if (isFunc(this._removeListeners[key])) { 3664 | this._removeListeners[key]() 3665 | } 3666 | 3667 | delete this._removeListeners[key] 3668 | delete state[key] 3669 | 3670 | state._diff = diff(key, ObservVarhash.Tombstone) 3671 | 3672 | this.set(state) 3673 | 3674 | return this 3675 | } 3676 | } 3677 | } 3678 | 3679 | function watch (obs, key, currentTransaction) { 3680 | return function (value) { 3681 | var state = extend(obs()) 3682 | state[key] = value 3683 | state._diff = diff(key, value) 3684 | currentTransaction = state 3685 | obs.set(state) 3686 | currentTransaction = NO_TRANSACTION 3687 | } 3688 | } 3689 | 3690 | function diff (key, value) { 3691 | var obj = {} 3692 | obj[key] = value && value._diff ? value._diff : value 3693 | return obj 3694 | } 3695 | 3696 | function checkKey (key) { 3697 | var msg = getKeyError(key) 3698 | 3699 | if (msg) { 3700 | throw new Error(msg) 3701 | } 3702 | } 3703 | 3704 | function getKeyError (key) { 3705 | switch (key) { 3706 | case 'name': { 3707 | return formatError(key, 'Clashes with `Function.prototype.name`.') 3708 | } 3709 | case 'get': 3710 | case 'put': 3711 | case 'delete': 3712 | case '_diff': 3713 | case '_removeListeners': { 3714 | return formatError(key, 'Clashes with observ-varhash method') 3715 | } 3716 | default: { 3717 | return '' 3718 | } 3719 | } 3720 | } 3721 | 3722 | function formatError (key, reason) { 3723 | return 'cannot create an observ-varhash with key `' + key + '`, ' + reason 3724 | } 3725 | 3726 | function isFunc (obj) { 3727 | return typeof obj === 'function' 3728 | } 3729 | 3730 | // identify deletes 3731 | function Tombstone () {} 3732 | 3733 | Tombstone.prototype.toJSON = nameTombstone 3734 | Tombstone.prototype.inspect = nameTombstone 3735 | Tombstone.prototype.toString = nameTombstone 3736 | 3737 | function nameTombstone () { 3738 | return '[object Tombstone]' 3739 | } 3740 | 3741 | },{"observ":81,"xtend":79}],79:[function(require,module,exports){ 3742 | module.exports=require(77) 3743 | },{}],80:[function(require,module,exports){ 3744 | var Observable = require("./index.js") 3745 | 3746 | module.exports = computed 3747 | 3748 | function computed(observables, lambda) { 3749 | var values = observables.map(function (o) { 3750 | return o() 3751 | }) 3752 | var result = Observable(lambda.apply(null, values)) 3753 | 3754 | observables.forEach(function (o, index) { 3755 | o(function (newValue) { 3756 | values[index] = newValue 3757 | result.set(lambda.apply(null, values)) 3758 | }) 3759 | }) 3760 | 3761 | return result 3762 | } 3763 | 3764 | },{"./index.js":81}],81:[function(require,module,exports){ 3765 | module.exports = Observable 3766 | 3767 | function Observable(value) { 3768 | var listeners = [] 3769 | value = value === undefined ? null : value 3770 | 3771 | observable.set = function (v) { 3772 | value = v 3773 | listeners.forEach(function (f) { 3774 | f(v) 3775 | }) 3776 | } 3777 | 3778 | return observable 3779 | 3780 | function observable(listener) { 3781 | if (!listener) { 3782 | return value 3783 | } 3784 | 3785 | listeners.push(listener) 3786 | 3787 | return function remove() { 3788 | listeners.splice(listeners.indexOf(listener), 1) 3789 | } 3790 | } 3791 | } 3792 | 3793 | },{}],82:[function(require,module,exports){ 3794 | module.exports = watch 3795 | 3796 | function watch(observable, listener) { 3797 | var remove = observable(listener) 3798 | listener(observable()) 3799 | return remove 3800 | } 3801 | 3802 | },{}],83:[function(require,module,exports){ 3803 | var extend = require('xtend') 3804 | var getFormData = require('form-data-set/element') 3805 | 3806 | var VALID_CHANGE = ['checkbox', 'file']; 3807 | var VALID_INPUT = ['color', 'date', 'datetime', 'datetime-local', 'email', 3808 | 'month', 'number', 'password', 'range', 'search', 'tel', 'text', 'time', 3809 | 'url', 'week']; 3810 | 3811 | module.exports = ChangeSinkHandler 3812 | 3813 | function ChangeSinkHandler(sink, data) { 3814 | if (!(this instanceof ChangeSinkHandler)) { 3815 | return new ChangeSinkHandler(sink, data) 3816 | } 3817 | 3818 | this.sink = sink 3819 | this.data = data 3820 | this.type = 'change' 3821 | this.id = sink.id 3822 | 3823 | if (this.data && typeof this.data === 'object' && 3824 | 'preventDefault' in this.data 3825 | ) { 3826 | this.preventDefault = this.data.preventDefault; 3827 | delete this.data.preventDefault; 3828 | } else { 3829 | this.preventDefault = true; 3830 | } 3831 | } 3832 | 3833 | ChangeSinkHandler.prototype.handleEvent = handleEvent 3834 | 3835 | function handleEvent(ev) { 3836 | var target = ev.target 3837 | 3838 | var isValid = 3839 | (ev.type === 'input' && VALID_INPUT.indexOf(target.type) !== -1) || 3840 | (ev.type === 'change' && VALID_CHANGE.indexOf(target.type) !== -1); 3841 | 3842 | if (!isValid) { 3843 | return 3844 | } 3845 | 3846 | var value = getFormData(ev.currentTarget) 3847 | var data = extend(value, this.data) 3848 | 3849 | if (typeof this.sink === 'function') { 3850 | this.sink(data) 3851 | } else { 3852 | this.sink.write(data) 3853 | } 3854 | 3855 | if (this.preventDefault && ev.preventDefault) { 3856 | ev.preventDefault() 3857 | } 3858 | } 3859 | 3860 | },{"form-data-set/element":87,"xtend":90}],84:[function(require,module,exports){ 3861 | module.exports = SinkEventHandler 3862 | 3863 | function SinkEventHandler(sink, data) { 3864 | if (!(this instanceof SinkEventHandler)) { 3865 | return new SinkEventHandler(sink, data) 3866 | } 3867 | 3868 | this.sink = sink 3869 | this.id = sink.id 3870 | this.data = data 3871 | 3872 | if (this.data && typeof this.data === 'object' && 3873 | 'preventDefault' in this.data 3874 | ) { 3875 | this.preventDefault = this.data.preventDefault; 3876 | delete this.data.preventDefault; 3877 | } else { 3878 | this.preventDefault = true; 3879 | } 3880 | } 3881 | 3882 | SinkEventHandler.prototype.handleEvent = handleEvent 3883 | 3884 | function handleEvent(ev) { 3885 | if (typeof this.sink === 'function') { 3886 | this.sink(this.data) 3887 | } else { 3888 | this.sink.write(this.data) 3889 | } 3890 | 3891 | if (this.preventDefault && ev.preventDefault) { 3892 | ev.preventDefault() 3893 | } 3894 | } 3895 | 3896 | },{}],85:[function(require,module,exports){ 3897 | module.exports = KeyEventHandler 3898 | 3899 | function KeyEventHandler(fn, key, data) { 3900 | if (!(this instanceof KeyEventHandler)) { 3901 | return new KeyEventHandler(fn, key, data) 3902 | } 3903 | 3904 | this.fn = fn 3905 | this.data = data 3906 | this.key = key 3907 | 3908 | if (this.data && typeof this.data === 'object' && 3909 | 'preventDefault' in this.data 3910 | ) { 3911 | this.preventDefault = this.data.preventDefault; 3912 | delete this.data.preventDefault; 3913 | } else { 3914 | this.preventDefault = true; 3915 | } 3916 | } 3917 | 3918 | KeyEventHandler.prototype.handleEvent = handleEvent 3919 | 3920 | function handleEvent(ev) { 3921 | if (ev.keyCode === this.key) { 3922 | this.fn(this.data) 3923 | } 3924 | 3925 | if (this.preventDefault && ev.preventDefault) { 3926 | ev.preventDefault() 3927 | } 3928 | } 3929 | 3930 | },{}],86:[function(require,module,exports){ 3931 | var slice = Array.prototype.slice 3932 | 3933 | module.exports = iterativelyWalk 3934 | 3935 | function iterativelyWalk(nodes, cb) { 3936 | if (!('length' in nodes)) { 3937 | nodes = [nodes] 3938 | } 3939 | 3940 | nodes = slice.call(nodes) 3941 | 3942 | while(nodes.length) { 3943 | var node = nodes.shift(), 3944 | ret = cb(node) 3945 | 3946 | if (ret) { 3947 | return ret 3948 | } 3949 | 3950 | if (node.childNodes && node.childNodes.length) { 3951 | nodes = slice.call(node.childNodes).concat(nodes) 3952 | } 3953 | } 3954 | } 3955 | 3956 | },{}],87:[function(require,module,exports){ 3957 | var walk = require('dom-walk') 3958 | 3959 | var FormData = require('./index.js') 3960 | 3961 | module.exports = getFormData 3962 | 3963 | function buildElems(rootElem) { 3964 | var hash = {} 3965 | 3966 | walk(rootElem, function (child) { 3967 | if (child.name) { 3968 | hash[child.name] = child 3969 | } 3970 | }) 3971 | 3972 | 3973 | return hash 3974 | } 3975 | 3976 | function getFormData(rootElem) { 3977 | var elements = buildElems(rootElem) 3978 | 3979 | return FormData(elements) 3980 | } 3981 | 3982 | },{"./index.js":88,"dom-walk":86}],88:[function(require,module,exports){ 3983 | /*jshint maxcomplexity: 10*/ 3984 | 3985 | module.exports = FormData 3986 | 3987 | //TODO: Massive spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#constructing-form-data-set 3988 | function FormData(elements) { 3989 | return Object.keys(elements).reduce(function (acc, key) { 3990 | var elem = elements[key] 3991 | 3992 | acc[key] = valueOfElement(elem) 3993 | 3994 | return acc 3995 | }, {}) 3996 | } 3997 | 3998 | function valueOfElement(elem) { 3999 | if (typeof elem === "function") { 4000 | return elem() 4001 | } else if (containsRadio(elem)) { 4002 | var elems = toList(elem) 4003 | var checked = elems.filter(function (elem) { 4004 | return elem.checked 4005 | })[0] || null 4006 | 4007 | return checked ? checked.value : null 4008 | } else if (Array.isArray(elem)) { 4009 | return elem.map(valueOfElement).filter(filterNull) 4010 | } else if (elem.tagName === undefined && elem.nodeType === undefined) { 4011 | return FormData(elem) 4012 | } else if (elem.tagName === "INPUT" && isChecked(elem)) { 4013 | if (elem.hasAttribute("value")) { 4014 | return elem.checked ? elem.value : null 4015 | } else { 4016 | return elem.checked 4017 | } 4018 | } else if (elem.tagName === "INPUT") { 4019 | return elem.value 4020 | } else if (elem.tagName === "TEXTAREA") { 4021 | return elem.value 4022 | } else if (elem.tagName === "SELECT") { 4023 | return elem.value 4024 | } 4025 | } 4026 | 4027 | function isChecked(elem) { 4028 | return elem.type === "checkbox" || elem.type === "radio" 4029 | } 4030 | 4031 | function containsRadio(value) { 4032 | if (value.tagName || value.nodeType) { 4033 | return false 4034 | } 4035 | 4036 | var elems = toList(value) 4037 | 4038 | return elems.some(function (elem) { 4039 | return elem.tagName === "INPUT" && elem.type === "radio" 4040 | }) 4041 | } 4042 | 4043 | function toList(value) { 4044 | if (Array.isArray(value)) { 4045 | return value 4046 | } 4047 | 4048 | return Object.keys(value).map(prop, value) 4049 | } 4050 | 4051 | function prop(x) { 4052 | return this[x] 4053 | } 4054 | 4055 | function filterNull(val) { 4056 | return val !== null 4057 | } 4058 | 4059 | },{}],89:[function(require,module,exports){ 4060 | module.exports=require(11) 4061 | },{}],90:[function(require,module,exports){ 4062 | var hasKeys = require("./has-keys") 4063 | 4064 | module.exports = extend 4065 | 4066 | function extend() { 4067 | var target = {} 4068 | 4069 | for (var i = 0; i < arguments.length; i++) { 4070 | var source = arguments[i] 4071 | 4072 | if (!hasKeys(source)) { 4073 | continue 4074 | } 4075 | 4076 | for (var key in source) { 4077 | if (source.hasOwnProperty(key)) { 4078 | target[key] = source[key] 4079 | } 4080 | } 4081 | } 4082 | 4083 | return target 4084 | } 4085 | 4086 | },{"./has-keys":89}],91:[function(require,module,exports){ 4087 | var extend = require('xtend') 4088 | var getFormData = require('form-data-set/element') 4089 | 4090 | var ENTER = 13 4091 | 4092 | module.exports = SubmitSinkHandler 4093 | 4094 | function SubmitSinkHandler(sink, data) { 4095 | if (!(this instanceof SubmitSinkHandler)) { 4096 | return new SubmitSinkHandler(sink, data) 4097 | } 4098 | 4099 | this.sink = sink 4100 | this.data = data 4101 | this.id = sink.id 4102 | this.type = 'submit' 4103 | 4104 | if (this.data && typeof this.data === 'object' && 4105 | 'preventDefault' in this.data 4106 | ) { 4107 | this.preventDefault = this.data.preventDefault; 4108 | delete this.data.preventDefault; 4109 | } else { 4110 | this.preventDefault = true; 4111 | } 4112 | } 4113 | 4114 | SubmitSinkHandler.prototype.handleEvent = handleEvent 4115 | 4116 | function handleEvent(ev) { 4117 | var target = ev.target 4118 | 4119 | var isValid = 4120 | (ev.type === 'click' && target.tagName === 'BUTTON') || 4121 | (ev.type === 'click' && target.type === 'submit') || 4122 | ( 4123 | (target.type === 'text') && 4124 | (ev.keyCode === ENTER && ev.type === 'keydown') 4125 | ) 4126 | 4127 | // prevent forms form refreshing page 4128 | if (ev.type === 'submit') { 4129 | ev.preventDefualt(); 4130 | } 4131 | 4132 | if (!isValid) { 4133 | return 4134 | } 4135 | 4136 | var value = getFormData(ev.currentTarget) 4137 | var data = extend(value, this.data) 4138 | 4139 | if (typeof this.sink === 'function') { 4140 | this.sink(data) 4141 | } else { 4142 | this.sink.write(data) 4143 | } 4144 | 4145 | if (this.preventDefault && ev.preventDefault) { 4146 | ev.preventDefault() 4147 | } 4148 | } 4149 | 4150 | },{"form-data-set/element":87,"xtend":90}],92:[function(require,module,exports){ 4151 | var extend = require('xtend') 4152 | var getFormData = require('form-data-set/element') 4153 | 4154 | module.exports = ValueEventHandler 4155 | 4156 | function ValueEventHandler(sink, data) { 4157 | if (!(this instanceof ValueEventHandler)) { 4158 | return new ValueEventHandler(sink, data) 4159 | } 4160 | 4161 | this.sink = sink 4162 | this.data = data 4163 | this.id = sink.id 4164 | 4165 | if (this.data && typeof this.data === 'object' && 4166 | 'preventDefault' in this.data 4167 | ) { 4168 | this.preventDefault = this.data.preventDefault; 4169 | delete this.data.preventDefault; 4170 | } else { 4171 | this.preventDefault = true; 4172 | } 4173 | } 4174 | 4175 | ValueEventHandler.prototype.handleEvent = handleEvent 4176 | 4177 | function handleEvent(ev) { 4178 | var value = getFormData(ev.currentTarget) 4179 | var data = extend(value, this.data) 4180 | 4181 | if (ev.type === 'submit') { 4182 | ev.preventDefault(); 4183 | } 4184 | 4185 | if (typeof this.sink === 'function') { 4186 | this.sink(data) 4187 | } else { 4188 | this.sink.write(data) 4189 | } 4190 | 4191 | if (this.preventDefault && ev.preventDefault) { 4192 | ev.preventDefault() 4193 | } 4194 | } 4195 | 4196 | },{"form-data-set/element":87,"xtend":90}],93:[function(require,module,exports){ 4197 | function Thunk(fn, args, key, eqArgs) { 4198 | this.fn = fn; 4199 | this.args = args; 4200 | this.key = key; 4201 | this.eqArgs = eqArgs; 4202 | } 4203 | 4204 | Thunk.prototype.type = 'Thunk'; 4205 | Thunk.prototype.render = render; 4206 | module.exports = Thunk; 4207 | 4208 | function shouldUpdate(current, previous) { 4209 | if (!current || !previous || current.fn !== previous.fn) { 4210 | return true; 4211 | } 4212 | 4213 | var cargs = current.args; 4214 | var pargs = previous.args; 4215 | 4216 | return !current.eqArgs(cargs, pargs); 4217 | } 4218 | 4219 | function render(previous) { 4220 | if (shouldUpdate(this, previous)) { 4221 | return this.fn.apply(null, this.args); 4222 | } else { 4223 | return previous.vnode; 4224 | } 4225 | } 4226 | 4227 | },{}],94:[function(require,module,exports){ 4228 | var Partial = require('./partial'); 4229 | 4230 | module.exports = Partial(); 4231 | 4232 | },{"./partial":95}],95:[function(require,module,exports){ 4233 | var shallowEq = require('./shallow-eq'); 4234 | var Thunk = require('./immutable-thunk'); 4235 | 4236 | module.exports = createPartial; 4237 | 4238 | function createPartial(eq) { 4239 | return function partial(fn) { 4240 | var args = copyOver(arguments, 1); 4241 | var firstArg = args[0]; 4242 | var key; 4243 | 4244 | var eqArgs = eq || shallowEq; 4245 | 4246 | if (typeof firstArg === 'object' && firstArg !== null) { 4247 | if ('key' in firstArg) { 4248 | key = firstArg.key; 4249 | } else if ('id' in firstArg) { 4250 | key = firstArg.id; 4251 | } 4252 | } 4253 | 4254 | return new Thunk(fn, args, key, eqArgs); 4255 | }; 4256 | } 4257 | 4258 | function copyOver(list, offset) { 4259 | var newList = []; 4260 | for (var i = list.length - 1; i >= offset; i--) { 4261 | newList[i - offset] = list[i]; 4262 | } 4263 | return newList; 4264 | } 4265 | 4266 | },{"./immutable-thunk":93,"./shallow-eq":96}],96:[function(require,module,exports){ 4267 | module.exports = shallowEq; 4268 | 4269 | function shallowEq(currentArgs, previousArgs) { 4270 | if (currentArgs.length === 0 && previousArgs.length === 0) { 4271 | return true; 4272 | } 4273 | 4274 | if (currentArgs.length !== previousArgs.length) { 4275 | return false; 4276 | } 4277 | 4278 | var len = currentArgs.length; 4279 | 4280 | for (var i = 0; i < len; i++) { 4281 | if (currentArgs[i] !== previousArgs[i]) { 4282 | return false; 4283 | } 4284 | } 4285 | 4286 | return true; 4287 | } 4288 | 4289 | },{}],97:[function(require,module,exports){ 4290 | module.exports=require(18) 4291 | },{"is-object":101,"vtree/is-vhook":134}],98:[function(require,module,exports){ 4292 | module.exports=require(19) 4293 | },{"./apply-properties":97,"global/document":100,"vtree/handle-thunk":132,"vtree/is-vnode":135,"vtree/is-vtext":136,"vtree/is-widget":137}],99:[function(require,module,exports){ 4294 | module.exports=require(20) 4295 | },{}],100:[function(require,module,exports){ 4296 | module.exports=require(21) 4297 | },{"min-document":2}],101:[function(require,module,exports){ 4298 | module.exports=require(22) 4299 | },{}],102:[function(require,module,exports){ 4300 | module.exports=require(23) 4301 | },{}],103:[function(require,module,exports){ 4302 | module.exports=require(24) 4303 | },{"./apply-properties":97,"./create-element":98,"./update-widget":105,"vtree/is-widget":137,"vtree/vpatch":142}],104:[function(require,module,exports){ 4304 | module.exports=require(25) 4305 | },{"./dom-index":99,"./patch-op":103,"global/document":100,"x-is-array":102}],105:[function(require,module,exports){ 4306 | module.exports=require(26) 4307 | },{"vtree/is-widget":137}],106:[function(require,module,exports){ 4308 | module.exports = AttributeHook; 4309 | 4310 | function AttributeHook(value) { 4311 | if (!(this instanceof AttributeHook)) { 4312 | return new AttributeHook(value); 4313 | } 4314 | 4315 | this.value = value; 4316 | } 4317 | 4318 | AttributeHook.prototype.hook = function (node, prop, prev) { 4319 | if (prev && prev.value === this.value) { 4320 | return; 4321 | } 4322 | 4323 | node.setAttributeNS(null, prop, this.value) 4324 | } 4325 | 4326 | },{}],107:[function(require,module,exports){ 4327 | var DataSet = require("data-set") 4328 | 4329 | module.exports = DataSetHook; 4330 | 4331 | function DataSetHook(value) { 4332 | if (!(this instanceof DataSetHook)) { 4333 | return new DataSetHook(value); 4334 | } 4335 | 4336 | this.value = value; 4337 | } 4338 | 4339 | DataSetHook.prototype.hook = function (node, propertyName) { 4340 | var ds = DataSet(node) 4341 | var propName = propertyName.substr(5) 4342 | 4343 | ds[propName] = this.value; 4344 | }; 4345 | 4346 | },{"data-set":112}],108:[function(require,module,exports){ 4347 | var DataSet = require("data-set") 4348 | 4349 | module.exports = DataSetHook; 4350 | 4351 | function DataSetHook(value) { 4352 | if (!(this instanceof DataSetHook)) { 4353 | return new DataSetHook(value); 4354 | } 4355 | 4356 | this.value = value; 4357 | } 4358 | 4359 | DataSetHook.prototype.hook = function (node, propertyName) { 4360 | var ds = DataSet(node) 4361 | var propName = propertyName.substr(3) 4362 | 4363 | ds[propName] = this.value; 4364 | }; 4365 | 4366 | },{"data-set":112}],109:[function(require,module,exports){ 4367 | module.exports = SoftSetHook; 4368 | 4369 | function SoftSetHook(value) { 4370 | if (!(this instanceof SoftSetHook)) { 4371 | return new SoftSetHook(value); 4372 | } 4373 | 4374 | this.value = value; 4375 | } 4376 | 4377 | SoftSetHook.prototype.hook = function (node, propertyName) { 4378 | if (node[propertyName] !== this.value) { 4379 | node[propertyName] = this.value; 4380 | } 4381 | }; 4382 | 4383 | },{}],110:[function(require,module,exports){ 4384 | var VNode = require("vtree/vnode.js") 4385 | var VText = require("vtree/vtext.js") 4386 | var isVNode = require("vtree/is-vnode") 4387 | var isVText = require("vtree/is-vtext") 4388 | var isWidget = require("vtree/is-widget") 4389 | var isHook = require("vtree/is-vhook") 4390 | var isVThunk = require("vtree/is-thunk") 4391 | var TypedError = require("error/typed") 4392 | 4393 | var parseTag = require("./parse-tag.js") 4394 | var softSetHook = require("./hooks/soft-set-hook.js") 4395 | var dataSetHook = require("./hooks/data-set-hook.js") 4396 | var evHook = require("./hooks/ev-hook.js") 4397 | 4398 | var UnexpectedVirtualElement = TypedError({ 4399 | type: "virtual-hyperscript.unexpected.virtual-element", 4400 | message: "Unexpected virtual child passed to h().\n" + 4401 | "Expected a VNode / Vthunk / VWidget / string but:\n" + 4402 | "got a {foreignObjectStr}.\n" + 4403 | "The parent vnode is {parentVnodeStr}.\n" + 4404 | "Suggested fix: change your `h(..., [ ... ])` callsite.", 4405 | foreignObjectStr: null, 4406 | parentVnodeStr: null, 4407 | foreignObject: null, 4408 | parentVnode: null 4409 | }) 4410 | 4411 | module.exports = h 4412 | 4413 | function h(tagName, properties, children) { 4414 | var childNodes = [] 4415 | var tag, props, key, namespace 4416 | 4417 | if (!children && isChildren(properties)) { 4418 | children = properties 4419 | props = {} 4420 | } 4421 | 4422 | props = props || properties || {} 4423 | tag = parseTag(tagName, props) 4424 | 4425 | // support keys 4426 | if ("key" in props) { 4427 | key = props.key 4428 | props.key = undefined 4429 | } 4430 | 4431 | // support namespace 4432 | if ("namespace" in props) { 4433 | namespace = props.namespace 4434 | props.namespace = undefined 4435 | } 4436 | 4437 | // fix cursor bug 4438 | if (tag === "input" && 4439 | "value" in props && 4440 | props.value !== undefined && 4441 | !isHook(props.value) 4442 | ) { 4443 | props.value = softSetHook(props.value) 4444 | } 4445 | 4446 | var keys = Object.keys(props) 4447 | var propName, value 4448 | for (var j = 0; j < keys.length; j++) { 4449 | propName = keys[j] 4450 | value = props[propName] 4451 | if (isHook(value)) { 4452 | continue 4453 | } 4454 | 4455 | // add data-foo support 4456 | if (propName.substr(0, 5) === "data-") { 4457 | props[propName] = dataSetHook(value) 4458 | } 4459 | 4460 | // add ev-foo support 4461 | if (propName.substr(0, 3) === "ev-") { 4462 | props[propName] = evHook(value) 4463 | } 4464 | } 4465 | 4466 | if (children !== undefined && children !== null) { 4467 | addChild(children, childNodes, tag, props) 4468 | } 4469 | 4470 | 4471 | var node = new VNode(tag, props, childNodes, key, namespace) 4472 | 4473 | return node 4474 | } 4475 | 4476 | function addChild(c, childNodes, tag, props) { 4477 | if (typeof c === "string") { 4478 | childNodes.push(new VText(c)) 4479 | } else if (isChild(c)) { 4480 | childNodes.push(c) 4481 | } else if (Array.isArray(c)) { 4482 | for (var i = 0; i < c.length; i++) { 4483 | addChild(c[i], childNodes, tag, props) 4484 | } 4485 | } else if (c === null || c === undefined) { 4486 | return 4487 | } else { 4488 | throw UnexpectedVirtualElement({ 4489 | foreignObjectStr: JSON.stringify(c), 4490 | foreignObject: c, 4491 | parentVnodeStr: JSON.stringify({ 4492 | tagName: tag, 4493 | properties: props 4494 | }), 4495 | parentVnode: { 4496 | tagName: tag, 4497 | properties: props 4498 | } 4499 | }) 4500 | } 4501 | } 4502 | 4503 | function isChild(x) { 4504 | return isVNode(x) || isVText(x) || isWidget(x) || isVThunk(x) 4505 | } 4506 | 4507 | function isChildren(x) { 4508 | return typeof x === "string" || Array.isArray(x) || isChild(x) 4509 | } 4510 | 4511 | },{"./hooks/data-set-hook.js":107,"./hooks/ev-hook.js":108,"./hooks/soft-set-hook.js":109,"./parse-tag.js":129,"error/typed":128,"vtree/is-thunk":133,"vtree/is-vhook":134,"vtree/is-vnode":135,"vtree/is-vtext":136,"vtree/is-widget":137,"vtree/vnode.js":141,"vtree/vtext.js":143}],111:[function(require,module,exports){ 4512 | module.exports=require(43) 4513 | },{}],112:[function(require,module,exports){ 4514 | module.exports=require(44) 4515 | },{"./create-hash.js":111,"individual":113,"weakmap-shim/create-store":114}],113:[function(require,module,exports){ 4516 | module.exports=require(48) 4517 | },{}],114:[function(require,module,exports){ 4518 | module.exports=require(45) 4519 | },{"./hidden-store.js":115}],115:[function(require,module,exports){ 4520 | module.exports=require(46) 4521 | },{}],116:[function(require,module,exports){ 4522 | module.exports=require(5) 4523 | },{"util/":119}],117:[function(require,module,exports){ 4524 | module.exports=require(6) 4525 | },{}],118:[function(require,module,exports){ 4526 | module.exports=require(7) 4527 | },{}],119:[function(require,module,exports){ 4528 | module.exports=require(8) 4529 | },{"./support/isBuffer":118,"JkpR2F":3,"inherits":117}],120:[function(require,module,exports){ 4530 | module.exports=require(9) 4531 | },{}],121:[function(require,module,exports){ 4532 | module.exports=require(10) 4533 | },{}],122:[function(require,module,exports){ 4534 | module.exports=require(11) 4535 | },{}],123:[function(require,module,exports){ 4536 | module.exports=require(12) 4537 | },{"./has-keys":122,"object-keys":125}],124:[function(require,module,exports){ 4538 | module.exports=require(13) 4539 | },{}],125:[function(require,module,exports){ 4540 | module.exports=require(14) 4541 | },{"./shim":127}],126:[function(require,module,exports){ 4542 | module.exports=require(15) 4543 | },{}],127:[function(require,module,exports){ 4544 | module.exports=require(16) 4545 | },{"./foreach":124,"./isArguments":126}],128:[function(require,module,exports){ 4546 | module.exports=require(17) 4547 | },{"assert/":116,"camelize":120,"string-template":121,"xtend/mutable":123}],129:[function(require,module,exports){ 4548 | var classIdSplit = /([\.#]?[a-zA-Z0-9_:-]+)/ 4549 | var notClassId = /^\.|#/ 4550 | 4551 | module.exports = parseTag 4552 | 4553 | function parseTag(tag, props) { 4554 | if (!tag) { 4555 | return "div" 4556 | } 4557 | 4558 | var noId = !("id" in props) 4559 | 4560 | var tagParts = tag.split(classIdSplit) 4561 | var tagName = null 4562 | 4563 | if (notClassId.test(tagParts[1])) { 4564 | tagName = "div" 4565 | } 4566 | 4567 | var classes, part, type, i 4568 | for (i = 0; i < tagParts.length; i++) { 4569 | part = tagParts[i] 4570 | 4571 | if (!part) { 4572 | continue 4573 | } 4574 | 4575 | type = part.charAt(0) 4576 | 4577 | if (!tagName) { 4578 | tagName = part 4579 | } else if (type === ".") { 4580 | classes = classes || [] 4581 | classes.push(part.substring(1, part.length)) 4582 | } else if (type === "#" && noId) { 4583 | props.id = part.substring(1, part.length) 4584 | } 4585 | } 4586 | 4587 | if (classes) { 4588 | if (props.className) { 4589 | classes.push(props.className) 4590 | } 4591 | 4592 | props.className = classes.join(" ") 4593 | } 4594 | 4595 | return tagName ? tagName.toLowerCase() : "div" 4596 | } 4597 | 4598 | },{}],130:[function(require,module,exports){ 4599 | var attributeHook = require("./hooks/attribute-hook.js") 4600 | var h = require("./index.js") 4601 | 4602 | var BLACKLISTED_KEYS = { 4603 | "style": true, 4604 | "namespace": true, 4605 | "key": true 4606 | } 4607 | var SVG_NAMESPACE = "http://www.w3.org/2000/svg" 4608 | 4609 | module.exports = svg 4610 | 4611 | function svg(tagName, properties, children) { 4612 | if (!children && isChildren(properties)) { 4613 | children = properties 4614 | properties = {} 4615 | } 4616 | 4617 | properties = properties || {} 4618 | 4619 | // set namespace for svg 4620 | properties.namespace = SVG_NAMESPACE 4621 | 4622 | // for each key, if attribute & string, bool or number then 4623 | // convert it into a setAttribute hook 4624 | for (var key in properties) { 4625 | if (!properties.hasOwnProperty(key)) { 4626 | continue 4627 | } 4628 | 4629 | if (BLACKLISTED_KEYS[key]) { 4630 | continue 4631 | } 4632 | 4633 | var value = properties[key] 4634 | if (typeof value !== "string" && 4635 | typeof value !== "number" && 4636 | typeof value !== "boolean" 4637 | ) { 4638 | continue 4639 | } 4640 | 4641 | properties[key] = attributeHook(value) 4642 | } 4643 | 4644 | return h(tagName, properties, children) 4645 | } 4646 | 4647 | function isChildren(x) { 4648 | return typeof x === "string" || Array.isArray(x) 4649 | } 4650 | 4651 | },{"./hooks/attribute-hook.js":106,"./index.js":110}],131:[function(require,module,exports){ 4652 | module.exports=require(27) 4653 | },{"./handle-thunk":132,"./is-thunk":133,"./is-vnode":135,"./is-vtext":136,"./is-widget":137,"./vpatch":142,"is-object":138,"x-is-array":139}],132:[function(require,module,exports){ 4654 | module.exports=require(28) 4655 | },{"./is-thunk":133,"./is-vnode":135,"./is-vtext":136,"./is-widget":137}],133:[function(require,module,exports){ 4656 | module.exports=require(29) 4657 | },{}],134:[function(require,module,exports){ 4658 | module.exports=require(30) 4659 | },{}],135:[function(require,module,exports){ 4660 | module.exports=require(31) 4661 | },{"./version":140}],136:[function(require,module,exports){ 4662 | module.exports=require(32) 4663 | },{"./version":140}],137:[function(require,module,exports){ 4664 | module.exports=require(33) 4665 | },{}],138:[function(require,module,exports){ 4666 | module.exports=require(22) 4667 | },{}],139:[function(require,module,exports){ 4668 | module.exports=require(23) 4669 | },{}],140:[function(require,module,exports){ 4670 | module.exports=require(36) 4671 | },{}],141:[function(require,module,exports){ 4672 | var version = require("./version") 4673 | var isVNode = require("./is-vnode") 4674 | var isWidget = require("./is-widget") 4675 | var isVHook = require("./is-vhook") 4676 | 4677 | module.exports = VirtualNode 4678 | 4679 | var noProperties = {} 4680 | var noChildren = [] 4681 | 4682 | function VirtualNode(tagName, properties, children, key, namespace) { 4683 | this.tagName = tagName 4684 | this.properties = properties || noProperties 4685 | this.children = children || noChildren 4686 | this.key = key != null ? String(key) : undefined 4687 | this.namespace = (typeof namespace === "string") ? namespace : null 4688 | 4689 | var count = (children && children.length) || 0 4690 | var descendants = 0 4691 | var hasWidgets = false 4692 | var descendantHooks = false 4693 | var hooks 4694 | 4695 | for (var propName in properties) { 4696 | if (properties.hasOwnProperty(propName)) { 4697 | var property = properties[propName] 4698 | if (isVHook(property)) { 4699 | if (!hooks) { 4700 | hooks = {} 4701 | } 4702 | 4703 | hooks[propName] = property 4704 | } 4705 | } 4706 | } 4707 | 4708 | for (var i = 0; i < count; i++) { 4709 | var child = children[i] 4710 | if (isVNode(child)) { 4711 | descendants += child.count || 0 4712 | 4713 | if (!hasWidgets && child.hasWidgets) { 4714 | hasWidgets = true 4715 | } 4716 | 4717 | if (!descendantHooks && (child.hooks || child.descendantHooks)) { 4718 | descendantHooks = true 4719 | } 4720 | } else if (!hasWidgets && isWidget(child)) { 4721 | if (typeof child.destroy === "function") { 4722 | hasWidgets = true 4723 | } 4724 | } 4725 | } 4726 | 4727 | this.count = count + descendants 4728 | this.hasWidgets = hasWidgets 4729 | this.hooks = hooks 4730 | this.descendantHooks = descendantHooks 4731 | } 4732 | 4733 | VirtualNode.prototype.version = version 4734 | VirtualNode.prototype.type = "VirtualNode" 4735 | 4736 | },{"./is-vhook":134,"./is-vnode":135,"./is-widget":137,"./version":140}],142:[function(require,module,exports){ 4737 | module.exports=require(37) 4738 | },{"./version":140}],143:[function(require,module,exports){ 4739 | var version = require("./version") 4740 | 4741 | module.exports = VirtualText 4742 | 4743 | function VirtualText(text) { 4744 | this.text = String(text) 4745 | } 4746 | 4747 | VirtualText.prototype.version = version 4748 | VirtualText.prototype.type = "VirtualText" 4749 | 4750 | },{"./version":140}],144:[function(require,module,exports){ 4751 | module.exports=require(69) 4752 | },{"performance-now":145}],145:[function(require,module,exports){ 4753 | module.exports=require(70) 4754 | },{"JkpR2F":3}]},{},[1]); -------------------------------------------------------------------------------- /lib/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/lib/hom-lib.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var mercury = require('mercury'); 5 | var main = require('main-loop'); 6 | // just re-exporting mercurcy for now. until we are gonna do more fancy stuff 7 | module.exports = mercury; 8 | 9 | 10 | // export to globals to we can access them with FFI. 11 | global.jsCreateElement = mercury.create; 12 | global.jsNode = mercury.h; 13 | global.jsDiff = mercury.diff; 14 | global.jsPatch = function (patches, el) { mercury.patch(el,patches);}; 15 | global.jsText = String; 16 | global.jsEmpty = function () {return [];}; 17 | global.jsCons = function (a,b) { return [a].concat(b); }; 18 | global.jsConcat = function (a,b) { return a.concat(b); }; 19 | 20 | global.jsRaf = requestAnimationFrame; 21 | 22 | global.jsMainLoop = function (state, render) { 23 | var loop = main(state,render); 24 | return loop; 25 | }; 26 | 27 | global.jsUpdate = function (state, loop) { 28 | return loop.update(state); 29 | }; 30 | global.jsTarget = function (loop) { 31 | return loop.target; 32 | }; 33 | 34 | 35 | global.jsTestArrays = function (xs) { console.log(xs);}; 36 | 37 | global.test = function (a) { return a + 1; }; 38 | 39 | -------------------------------------------------------------------------------- /lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lib", 3 | "description": "The best project ever.", 4 | "version": "0.1.0", 5 | "homepage": "https://github.com/arian/lib", 6 | "author": { 7 | "name": "Arian van Putten", 8 | "email": "aeroboy94@gmail.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/arian/lib.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/arian/lib/issues" 16 | }, 17 | "licenses": [ 18 | { 19 | "type": "MIT", 20 | "url": "https://github.com/arian/lib/blob/master/LICENSE-MIT" 21 | } 22 | ], 23 | "main": "lib/lib", 24 | "engines": { 25 | "node": ">= 0.8.0" 26 | }, 27 | "scripts": { 28 | "test": "grunt nodeunit" 29 | }, 30 | "devDependencies": { 31 | "grunt": "~0.4.5", 32 | "grunt-browserify": "^2.1.4", 33 | "grunt-contrib-jshint": "~0.6.4", 34 | "grunt-contrib-nodeunit": "~0.2.0", 35 | "grunt-contrib-watch": "~0.5.3", 36 | "grunt-file-append": "0.0.4" 37 | }, 38 | "keywords": [], 39 | "dependencies": { 40 | "main-loop": "^2.3.0", 41 | "mercury": "^6.0.1", 42 | "raf": "^2.0.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/test/lib_test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var lib = require('../lib/hom-lib.js'); 4 | 5 | /* 6 | ======== A Handy Little Nodeunit Reference ======== 7 | https://github.com/caolan/nodeunit 8 | 9 | Test methods: 10 | test.expect(numAssertions) 11 | test.done() 12 | Test assertions: 13 | test.ok(value, [message]) 14 | test.equal(actual, expected, [message]) 15 | test.notEqual(actual, expected, [message]) 16 | test.deepEqual(actual, expected, [message]) 17 | test.notDeepEqual(actual, expected, [message]) 18 | test.strictEqual(actual, expected, [message]) 19 | test.notStrictEqual(actual, expected, [message]) 20 | test.throws(block, [error], [message]) 21 | test.doesNotThrow(block, [error], [message]) 22 | test.ifError(value) 23 | */ 24 | 25 | exports['awesome'] = { 26 | setUp: function(done) { 27 | // setup here 28 | done(); 29 | }, 30 | 'no args': function(test) { 31 | test.expect(1); 32 | // tests here 33 | test.equal(lib.awesome(), 'awesome', 'should be awesome.'); 34 | test.done(); 35 | }, 36 | }; 37 | -------------------------------------------------------------------------------- /src/Hom/Animate.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | module Hom.Animate 3 | ( requestAnimationFrame 4 | , waitForAnimationFrame 5 | ) 6 | where 7 | 8 | import Control.Monad.IO.Class 9 | import Haste.Prim 10 | import Haste.Concurrent 11 | 12 | newtype JSFun a = JSFun (Ptr a) 13 | 14 | foreign import ccall jsRaf :: JSFun a -> IO () 15 | 16 | mkCallback :: a -> JSFun a 17 | mkCallback = JSFun . toPtr 18 | 19 | 20 | requestAnimationFrame :: MonadIO m => IO () -> m () 21 | requestAnimationFrame cb = liftIO $ jsRaf (mkCallback $! cb) 22 | 23 | requestAnimationFrame' :: MonadIO m => CIO () -> m () 24 | requestAnimationFrame' cb = 25 | liftIO $ jsRaf (mkCallback $! concurrent cb) 26 | 27 | 28 | waitForAnimationFrame :: CIO () 29 | waitForAnimationFrame = do 30 | v <- newEmptyMVar 31 | liftIO $ requestAnimationFrame' $ putMVar v () 32 | takeMVar v 33 | 34 | -------------------------------------------------------------------------------- /src/Hom/App.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ForeignFunctionInterface #-} 2 | 3 | module Hom.App 4 | ( 5 | app 6 | ) 7 | where 8 | 9 | import Hom.DOM 10 | import Haste.DOM 11 | import Haste.Concurrent 12 | import Haste.Prim 13 | import Hom.Animate 14 | import Control.Monad.IO.Class 15 | 16 | 17 | app initialState render root update = concurrent . withElem root $ \rootEl -> do 18 | stateMVar <- newEmptyMVar 19 | let currentDOM = render initialState 20 | forkIO $ update initialState stateMVar 21 | let go = do 22 | state <- takeMVar stateMVar 23 | let nextDOM = render state 24 | let patches = diff currentDOM nextDOM 25 | patch patches rootEl 26 | go 27 | go -------------------------------------------------------------------------------- /src/Hom/DOM.hs: -------------------------------------------------------------------------------- 1 | {-#LANGUAGE ForeignFunctionInterface, GeneralizedNewtypeDeriving #-} 2 | module Hom.DOM 3 | ( createElement 4 | , diff 5 | , patch 6 | , text 7 | , node 8 | , Node 9 | , Elem 10 | , (=:) 11 | ) 12 | where 13 | 14 | import Haste.DOM 15 | import Haste.Foreign 16 | import Haste.App 17 | import Haste.Serialize 18 | import Haste.JSON 19 | import Haste.Prim 20 | 21 | 22 | a =: b = (a,b) 23 | newtype Patches = Patches JSAny deriving (Pack, Unpack) 24 | newtype Node = Node JSAny deriving (Pack, Unpack) 25 | newtype Nodes = Nodes JSAny deriving (Pack, Unpack) 26 | newtype Properties = Properties JSAny deriving (Pack, Unpack) 27 | newtype Children = Children JSAny deriving (Pack, Unpack) 28 | 29 | foreign import ccall "jsEmpty" jsNodesEmpty :: Nodes 30 | foreign import ccall "jsConcat" jsNodesConcat :: Nodes -> Nodes -> Nodes 31 | foreign import ccall "jsCons" jsNodesCons :: Node -> Nodes -> Nodes 32 | 33 | 34 | foreign import ccall jsCreateElement :: Node -> IO Elem 35 | foreign import ccall jsDiff :: Node -> Node -> Patches 36 | foreign import ccall jsPatch :: Patches -> Elem -> IO () 37 | foreign import ccall jsText :: JSString -> Node 38 | foreign import ccall jsNode :: JSString -> Properties -> Nodes -> Node 39 | foreign import ccall lst2arr :: Ptr ([Node]) -> Nodes 40 | 41 | createElement :: MonadIO m => Node -> m Elem 42 | createElement n = liftIO $ jsCreateElement n 43 | 44 | diff :: Node -> Node -> Patches 45 | diff = jsDiff 46 | 47 | patch :: MonadIO m => Patches -> Elem -> m () 48 | patch p e= liftIO $ jsPatch p e 49 | 50 | text :: JSString -> Node 51 | text = jsText 52 | 53 | 54 | toNodes :: [Node] -> Nodes 55 | toNodes = foldr jsNodesCons jsNodesEmpty 56 | 57 | 58 | 59 | node :: JSString -> [(JSString, JSString)] -> [Node] -> Node 60 | node selector properties children = jsNode selector (Properties $ properties') (toNodes children) 61 | where properties' = toObject . Dict $ map (\(a,b)->(a, Str b)) properties 62 | --node name attrs children = let attrs' = toJSON: . toObject $ attrs -------------------------------------------------------------------------------- /src/Main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | import Haste.Prim 4 | import Haste.Concurrent 5 | import Hom.DOM 6 | import Hom.App 7 | 8 | count :: Int -> Node 9 | count c = node "div" ["style"=:"color:red;"] [ text . toJSStr . show $ c] 10 | 11 | counter startval ctr = 12 | go startval 13 | where 14 | go n = do 15 | putMVar ctr n 16 | wait 1000 17 | go $ n+1 18 | 19 | main = app 0 count "root" counter --------------------------------------------------------------------------------