', '<%= concat.build.dest %>']
46 | }
47 | }
48 | },
49 | release: {
50 | files: ['<%= pkg.name %>.js', '<%= pkg.name %>.min.js'],
51 | src: '<%= builddir %>',
52 | dest: 'release'
53 | },
54 | jshint: {
55 | all: ['Gruntfile.js', 'src/*.js', '<%= builddir %>/<%= pkg.name %>.js'],
56 | options: {
57 | }
58 | },
59 | watch: {
60 | files: ['src/*.js', 'test/**/*.js'],
61 | tasks: ['build', 'karma:background:run']
62 | },
63 | connect: {
64 | server: {},
65 | sample: {
66 | options:{
67 | port: 5555,
68 | keepalive: true
69 | }
70 | }
71 | },
72 | karma: {
73 | options: {
74 | configFile: 'config/karma.js',
75 | singleRun: true,
76 | exclude: [],
77 | frameworks: ['jasmine'],
78 | reporters: 'dots', // 'dots' || 'progress'
79 | port: 8080,
80 | colors: true,
81 | autoWatch: false,
82 | autoWatchInterval: 0,
83 | browsers: [ grunt.option('browser') || 'PhantomJS' ]
84 | },
85 | unit: {
86 | browsers: [ grunt.option('browser') || 'PhantomJS' ]
87 | },
88 | debug: {
89 | singleRun: false,
90 | background: false,
91 | browsers: [ grunt.option('browser') || 'Chrome' ]
92 | },
93 | past: {
94 | configFile: 'config/karma-angular-1.2.28.js'
95 | },
96 | future: {
97 | configFile: 'config/karma-angular-1.4.0-beta.3.js'
98 | },
99 | background: {
100 | background: true,
101 | browsers: [ grunt.option('browser') || 'PhantomJS' ]
102 | },
103 | watch: {
104 | configFile: 'config/karma.js',
105 | singleRun: false,
106 | autoWatch: true,
107 | autoWatchInterval: 1
108 | }
109 | },
110 | changelog: {
111 | options: {
112 | dest: 'CHANGELOG.md'
113 | }
114 | }
115 | });
116 |
117 | grunt.registerTask('integrate', ['build', 'jshint', 'karma:unit', 'karma:past', 'karma:future']);
118 | grunt.registerTask('default', ['build', 'jshint', 'karma:unit']);
119 | grunt.registerTask('build', 'Perform a normal build', ['concat', 'uglify']);
120 | grunt.registerTask('dist', 'Perform a clean build', ['clean', 'build']);
121 | grunt.registerTask('release', 'Tag and perform a release', ['prepare-release', 'dist', 'perform-release']);
122 | grunt.registerTask('dev', 'Run dev server and watch for changes', ['build', 'connect:server', 'karma:background', 'watch']);
123 |
124 | grunt.registerTask('prepare-release', function () {
125 | var bower = grunt.file.readJSON('bower.json'),
126 | version = bower.version;
127 | if (version != grunt.config('pkg.version')) throw 'Version mismatch in bower.json';
128 |
129 | promising(this,
130 | ensureCleanMaster().then(function () {
131 | return exec('git tag -l \'' + version + '\'');
132 | }).then(function (result) {
133 | if (result.stdout.trim() !== '') throw 'Tag \'' + version + '\' already exists';
134 | grunt.config('buildtag', '');
135 | grunt.config('builddir', 'release');
136 | })
137 | );
138 | });
139 |
140 | grunt.registerTask('perform-release', function () {
141 | grunt.task.requires([ 'prepare-release', 'dist' ]);
142 |
143 | var version = grunt.config('pkg.version'), releasedir = grunt.config('builddir');
144 | promising(this,
145 | system('git add \'' + releasedir + '\'').then(function () {
146 | return system('git commit -m \'release ' + version + '\'');
147 | }).then(function () {
148 | return system('git tag \'' + version + '\'');
149 | })
150 | );
151 | });
152 |
153 |
154 | // Helpers for custom tasks, mainly around promises / exec
155 | var exec = require('faithful-exec'), shjs = require('shelljs');
156 |
157 | function system(cmd) {
158 | grunt.log.write('% ' + cmd + '\n');
159 | return exec(cmd).then(function (result) {
160 | grunt.log.write(result.stderr + result.stdout);
161 | }, function (error) {
162 | grunt.log.write(error.stderr + '\n');
163 | throw 'Failed to run \'' + cmd + '\'';
164 | });
165 | }
166 |
167 | function promising(task, promise) {
168 | var done = task.async();
169 | promise.then(function () {
170 | done();
171 | }, function (error) {
172 | grunt.log.write(error + '\n');
173 | done(false);
174 | });
175 | }
176 |
177 | function ensureCleanMaster() {
178 | return exec('git symbolic-ref HEAD').then(function (result) {
179 | if (result.stdout.trim() !== 'refs/heads/master') throw 'Not on master branch, aborting';
180 | return exec('git status --porcelain');
181 | }).then(function (result) {
182 | if (result.stdout.trim() !== '') throw 'Working copy is dirty, aborting';
183 | });
184 | }
185 | };
186 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2015 Tero Parviainen
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # angular-virtual-dom
2 |
3 | [](http://badge.fury.io/js/angular-virtual-dom)
4 | [](http://badge.fury.io/bo/angular-virtual-dom)
5 |
6 | angular-virtual-dom is an experimental [Virtual DOM](https://github.com/Matt-Esch/virtual-dom) based AngularJS view renderer designed to be used with immutable data structures such as [immutable-js](https://github.com/facebook/immutable-js) and [mori](http://swannodette.github.io/mori/).
7 |
8 | angular-virtual-dom lets you use regular AngularJS templates and expressions to bind data to the DOM, but uses Virtual DOM diffing behind the scenes.
9 |
10 | angular-virtual-dom supports extensibility using directives - though only with directives that are Virtual DOM aware. That means angular-virtual-dom is not a drop-in substitute for the AngularJS directive compiler, and is meant to be used in limited contexts.
11 |
12 | angular-virtual-dom works with AngularJS versions 1.2 and newer.
13 |
14 | ## Usage
15 |
16 | ```` js
17 | angular.module('myModule', ['teropa.virtualDom'])
18 | .controller('MyCtrl', function($timeout) {
19 | this.myData = Immutable.fromJS({
20 | cols: [
21 | {name: 'One', cssClass: 'one', key: 'one'},
22 | {name: 'Two', cssClass: 'two', key: 'two'}
23 | ],
24 | rows: [
25 | {one: 'A1', two: 'B1'},
26 | {one: 'A2', two: 'B2'}
27 | ]
28 | });
29 |
30 | // A new version of the immutable data structure triggers
31 | // DOM diffing later.
32 | $timeout(function() {
33 | this.myData = this.myData.updateIn(['rows'], function(rows) {
34 | return rows.push(Immutable.Map({one: 'A3', two: 'B3'}));
35 | });
36 | }.bind(this), 1000);
37 | });
38 | ````
39 |
40 | ```` html
41 |
42 |
43 |
44 |
46 | {{col.get('name')}}
47 | |
48 |
49 |
50 |
52 |
53 | {{row.get(col.get('key'))}}
54 | |
55 |
56 |
57 |
58 |
59 | ````
60 |
61 | * `v-root` establishes a Virtual DOM tree. The `table` tag and all of its descendants will be rendered using [virtual-dom](https://github.com/Matt-Esch/virtual-dom), bypassing Angular's own DOM compiler.
62 | * Virtual DOM diffing and patching occurs when `myCtrl.myData` changes. *The whole Virtual DOM tree uses a single (reference) watch*, and only when it fires does the view re-render. The idea is to attach an immutable data structure on the scope, refer to it in `v-root`, and let Virtual DOM diffing take care of updates when new versions of the data structure are produced.
63 | * The expressions within the table are normal AngularJS expressions. However, they are *not being watched*, and are only re-evaluated when diffing is triggered by the containing `v-root`.
64 | * Directives bundled with angular-virtual-dom can be used within the Virtual DOM tree. Custom directives can also be created (see below).
65 |
66 | ## Installation
67 |
68 | ### With NPM / Browserify
69 |
70 | ``` sh
71 | npm install angular-virtual-dom
72 | ```
73 |
74 | Require the module and include it in your AngularJS modules:
75 |
76 | ``` js
77 | require('angular-virtual-dom')
78 |
79 | angular.module('myModule', ['teropa.virtualDom'])
80 | ```
81 |
82 | Or just:
83 |
84 | ``` js
85 | angular.module('myModule', [
86 | require('angular-virtual-dom')
87 | ])
88 | ```
89 |
90 | ### With Bower
91 |
92 | The library is available as a Bower dependency:
93 |
94 | ``` sh
95 | bower install angular-virtual-dom --save
96 | ```
97 |
98 | After installation, add one of the following to your loaded scripts:
99 |
100 | * `angular-virtual-dom/release/angular-virtual-dom.js`
101 | * `angular-virtual-dom/release/angular-virtual-dom.min.js`
102 |
103 | Finally, include the `teropa.virtualDom` module in your AngularJS modules:
104 |
105 | ``` js
106 | angular.module('myModule', ['teropa.virtualDom'])
107 | ```
108 |
109 | ## API
110 |
111 | ### v-root
112 |
113 | Use the `v-root` directive in your Angular templates to establish a Virtual DOM. This will short-circuit Angular's normal DOM compilation and build the Virtual DOM template from the contained elements.
114 |
115 | The directive accepts an expression, and changes to that expression's value cause the Virtual DOM tree to be re-rendered:
116 |
117 | ``` html
118 |
119 |
123 |
124 | ```
125 |
126 | ### Expressions
127 |
128 | Within a `v-root`, any AngularJS expressions are evaluated whenever DOM diffing occurs:
129 |
130 | ``` html
131 |
132 |
133 | {{anotherExpression}}
134 |
135 |
136 | ```
137 |
138 | Typically, though not necessarily, the expressions will access data from the data structure referred to in `v-root`:
139 |
140 | ``` html
141 |
142 |
145 |
146 | ```
147 |
148 | ### Directives
149 |
150 | #### v-if
151 |
152 | Includes the node in the Virtual DOM only when the expression evaluates to a truthy value. Analogous with `ng-if`.
153 |
154 | ``` html
155 |
156 |
157 | {{baseData.headerText}}
158 |
159 |
160 | ```
161 |
162 | #### v-repeat
163 |
164 | Includes a collection of nodes in the Virtual DOM, for each item in a collection. Analogous with `ng-repeat`.
165 |
166 | Supports at least the following types of collections:
167 | * [immutable-js](https://github.com/facebook/immutable-js) lists, maps, stacks, ordered maps, sets, and ordered sets.
168 | * [mori](http://swannodette.github.io/mori/) lists, seqs, vectors, maps, sets, sorted sets, and queues.
169 | * JavaScript arrays an objects.
170 |
171 | Should additionally support any ES6 iterable collections.
172 |
173 | Usage with sequential data structures:
174 |
175 | ``` html
176 |
177 | -
178 | {{item}}
179 |
180 |
181 | ```
182 |
183 | Usage with associative data structures:
184 |
185 | ``` html
186 |
187 | -
188 | {{k}}: {{v}}
189 |
190 |
191 | ```
192 |
193 | Additionally makes the special variables `$index`, `$even`, and `$odd` available within the template scope.
194 |
195 | ## Writing Custom Directives
196 |
197 | *Note:* The directive API should be considered highly unstable.
198 |
199 | Virtual DOM directives are registered as normal AngularJS directives, but must define a `linkVirtual` function in the directive definition object. This should be a *pure function* that take a Virtual DOM node as an argument, and returns a modified Virtual DOM node or collection thereof.
200 |
201 | The Virtual DOM nodes used by this library always hold a `$scope` attribute, referring to the current scope. A directive may create a new scope and attach it to the `$scope` attribute of the returned node.
202 |
203 | ## Usage with Mutable Data Structures
204 |
205 | While angular-virtual-dom is designed to be used with immutable data structures, it is not a hard requirement. Regular, mutable JavaScript data structures and objects work just as well.
206 |
207 | You will, however, need to manually trigger re-renders by reassigning `v-root` to a new value unless your code does so naturally.
208 |
209 | ## Contribution
210 |
211 | Use Github issues for requests.
212 |
213 | ## Author
214 |
215 | [Tero Parviainen](http://teropa.info) ([@teropa on Twitter](https://twitter.com/teropa))
216 |
217 | Leans heavily on [virtual-dom by Matt-Esch](https://github.com/Matt-Esch/virtual-dom).
218 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-virtual-dom",
3 | "version": "0.1.1",
4 | "main": "./release/angular-virtual-dom.js",
5 | "dependencies": {
6 | "angular": ">= 1.2.0"
7 | },
8 | "ignore": [
9 | "**/.*",
10 | "node_modules",
11 | "bower_components",
12 | "component.json",
13 | "package.json",
14 | "lib",
15 | "config",
16 | "sample",
17 | "test",
18 | "tests",
19 | "ngdoc_assets",
20 | "Gruntfile.js",
21 | "files.js"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/build/angular-virtual-dom.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @version v0.0.2-dev-2015-02-09
4 | * @link https://github.com/teropa/angular-virtual-dom
5 | * @license MIT License, http://www.opensource.org/licenses/MIT
6 | *
7 | * Bundles virtual-dom by Matt-Esch
8 | * @link https://github.com/Matt-Esch/virtual-dom
9 | * @license MIT License, http://www.opensource.org/licenses/MIT
10 | */
11 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="teropa.virtualDom"),function(a,b,c){!function(b){var c;"undefined"!=typeof a?c=a:"undefined"!=typeof global?c=global:"undefined"!=typeof self&&(c=self),c.virtualDom=b()}(function(){return function b(a,c,d){function e(g,h){if(!c[g]){if(!a[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};a[g][0].call(k.exports,function(b){var c=a[g][1][b];return e(c?c:b)},k,k.exports,b,a,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>>0:f>>>0;(h=e.exec(b))&&(i=h.index+h[0].length,!(i>m&&(k.push(b.slice(m,h.index)),!d&&h.length>1&&h[0].replace(g,function(){for(var b=1;b1&&h.index=f)));)e.lastIndex===h.index&&e.lastIndex++;return m===b.length?(j||!e.test(""))&&k.push(""):k.push(b.slice(m)),k.length>f?k.slice(0,f):k}}()},{}],6:[function(a,b){"use strict";function c(a){var b=a[f];return b||(b=a[f]={}),b}var d=a("individual/one-version"),e="7";d("ev-store",e);var f="__EV_STORE_KEY@"+e;b.exports=c},{"individual/one-version":8}],7:[function(b,c){(function(b){"use strict";function d(a,b){return a in e?e[a]:(e[a]=b,b)}var e="undefined"!=typeof a?a:"undefined"!=typeof b?b:{};c.exports=d}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof a?a:{})},{}],8:[function(a,b){"use strict";function c(a,b,c){var e="__INDIVIDUAL_ONE_VERSION_"+a,f=e+"_ENFORCE_SINGLETON",g=d(f,b);if(g!==b)throw new Error("Can only have one copy of "+a+".\nYou already have version "+g+" installed.\nThis means you cannot install version "+b);return d(e,c)}var d=a("./index.js");b.exports=c},{"./index.js":7}],9:[function(b,c){(function(d){var e="undefined"!=typeof d?d:"undefined"!=typeof a?a:{},f=b("min-document");if("undefined"!=typeof document)c.exports=document;else{var g=e["__GLOBAL_DOCUMENT_CACHE@4"];g||(g=e["__GLOBAL_DOCUMENT_CACHE@4"]=f),c.exports=g}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof a?a:{})},{"min-document":35}],10:[function(a,b){"use strict";b.exports=function(a){return"object"==typeof a&&null!==a}},{}],11:[function(a,b){function c(a){return"[object Array]"===e.call(a)}var d=Array.isArray,e=Object.prototype.toString;b.exports=d||c},{}],12:[function(a,b){var c=a("./vdom/patch.js");b.exports=c},{"./vdom/patch.js":17}],13:[function(a,b){function d(a,b,d){for(var g in b){var j=b[g];j===c?e(a,g,j,d):i(j)?(e(a,g,j,d),j.hook&&j.hook(a,g,d?d[g]:c)):h(j)?f(a,b,d,g,j):a[g]=j}}function e(a,b,c,d){if(d){var e=d[b];if(i(e))e.unhook&&e.unhook(a,b,c);else if("attributes"===b)for(var f in e)a.removeAttribute(f);else if("style"===b)for(var g in e)a.style[g]="";else a[b]="string"==typeof e?"":null}}function f(a,b,d,e,f){var i=d?d[e]:c;if("attributes"!==e){if(i&&h(i)&&g(i)!==g(f))return void(a[e]=f);h(a[e])||(a[e]={});var j="style"===e?"":c;for(var k in f){var l=f[k];a[e][k]=l===c?j:l}}else for(var m in f){var n=f[m];n===c?a.removeAttribute(m):a.setAttribute(m,n)}}function g(a){return Object.getPrototypeOf?Object.getPrototypeOf(a):a.__proto__?a.__proto__:a.constructor?a.constructor.prototype:void 0}var h=a("is-object"),i=a("../vnode/is-vhook.js");b.exports=d},{"../vnode/is-vhook.js":25,"is-object":10}],14:[function(a,b){function c(a,b){var j=b?b.document||d:d,k=b?b.warn:null;if(a=i(a).a,h(a))return a.init();if(g(a))return j.createTextNode(a.text);if(!f(a))return k&&k("Item is not a valid virtual dom node",a),null;var l=null===a.namespace?j.createElement(a.tagName):j.createElementNS(a.namespace,a.tagName),m=a.properties;e(l,m);for(var n=a.children,o=0;o=f;){if(d=(g+f)/2>>0,e=a[d],f===g)return e>=b&&c>=e;if(b>e)f=d+1;else{if(!(e>c))return!0;g=d-1}}return!1}function f(a,b){return a>b?1:-1}var g={};b.exports=c},{}],16:[function(a,b){function d(a,b,c){var d=a.type,j=a.vNode,n=a.patch;switch(d){case o.REMOVE:return e(b,j);case o.INSERT:return f(b,n,c);case o.VTEXT:return g(b,j,n,c);case o.WIDGET:return h(b,j,n,c);case o.VNODE:return i(b,j,n,c);case o.ORDER:return k(b,n),b;case o.PROPS:return m(b,n,j.properties),b;case o.THUNK:return l(b,c.patch(b,n,c));default:return b}}function e(a,b){var c=a.parentNode;return c&&c.removeChild(a),j(a,b),null}function f(a,b,c){var d=p(b,c);return a&&a.appendChild(d),a}function g(a,b,c,d){var e;if(3===a.nodeType)a.replaceData(0,a.length,c.text),e=a;else{var f=a.parentNode;e=p(c,d),f&&f.replaceChild(e,a)}return e}function h(a,b,c,d){var e,f=q(b,c);e=f?c.update(b,a)||a:p(c,d);var g=a.parentNode;return g&&e!==a&&g.replaceChild(e,a),f||j(a,b),e}function i(a,b,c,d){var e=a.parentNode,f=p(c,d);return e&&e.replaceChild(f,a),f}function j(a,b){"function"==typeof b.destroy&&n(b)&&b.destroy(a)}function k(a,b){var d,e=[],f=a.childNodes,g=f.length,h=b.reverse;for(d=0;g>d;d++)e.push(a.childNodes[d]);var i,j,k,l,m,n=0;for(d=0;g>d;){if(i=b[d],l=1,i!==c&&i!==d){for(;b[d+l]===i+l;)l++;for(h[d]>d+l&&n++,j=e[i],k=f[d+n]||null,m=0;j!==k&&m++i+l&&n--}d in b.removes&&n++,d+=l}}function l(a,b){return a&&b&&a!==b&&a.parentNode&&(console.log(a),a.parentNode.replaceChild(b,a)),b}var m=a("./apply-properties"),n=a("../vnode/is-widget.js"),o=a("../vnode/vpatch.js"),p=a("./create-element"),q=a("./update-widget");b.exports=d},{"../vnode/is-widget.js":28,"../vnode/vpatch.js":31,"./apply-properties":13,"./create-element":14,"./update-widget":18}],17:[function(a,b){function c(a,b){return d(a,b)}function d(a,b,c){var h=f(b);if(0===h.length)return a;var j=i(a,b.a,h),k=a.ownerDocument;c||(c={patch:d},k!==g&&(c.document=k));for(var l=0;lu;u++){var v=d[u];f(v)?(o+=v.count||0,!p&&v.hasWidgets&&(p=!0),!q&&v.hasThunks&&(q=!0),r||!v.hooks&&!v.descendantHooks||(r=!0)):!p&&g(v)?"function"==typeof v.destroy&&(p=!0):!q&&h(v)&&(q=!0)}this.count=n+o,this.hasWidgets=p,this.hasThunks=q,this.hooks=m,this.descendantHooks=r}var e=a("./version"),f=a("./is-vnode"),g=a("./is-widget"),h=a("./is-thunk"),i=a("./is-vhook");b.exports=d;var j={},k=[];d.prototype.version=e,d.prototype.type="VirtualNode"},{"./is-thunk":24,"./is-vhook":25,"./is-vnode":26,"./is-widget":28,"./version":29}],31:[function(a,b){function c(a,b,c){this.type=Number(a),this.vNode=b,this.patch=c}var d=a("./version");c.NONE=0,c.VTEXT=1,c.VNODE=2,c.WIDGET=3,c.PROPS=4,c.ORDER=5,c.INSERT=6,c.REMOVE=7,c.THUNK=8,b.exports=c,c.prototype.version=d,c.prototype.type="VirtualPatch"},{"./version":29}],32:[function(a,b){function c(a){this.text=String(a)}var d=a("./version");b.exports=c,c.prototype.version=d,c.prototype.type="VirtualText"},{"./version":29}],33:[function(a,b){function d(a,b){var h;for(var i in a){i in b||(h=h||{},h[i]=c);var j=a[i],k=b[i];if(j!==k)if(f(j)&&f(k))if(e(k)!==e(j))h=h||{},h[i]=k;else if(g(k))h=h||{},h[i]=k;else{var l=d(j,k);l&&(h=h||{},h[i]=l)}else h=h||{},h[i]=k}for(var m in b)m in a||(h=h||{},h[m]=b[m]);return h}function e(a){return Object.getPrototypeOf?Object.getPrototypeOf(a):a.__proto__?a.__proto__:a.constructor?a.constructor.prototype:void 0}var f=a("is-object"),g=a("../vnode/is-vhook");b.exports=d},{"../vnode/is-vhook":25,"is-object":10}],34:[function(a,b){function d(a,b){var c={a:a};return e(a,b,c,0),c}function e(a,b,c,d){if(a!==b){var e=c[d],h=!1;if(u(a)||u(b))i(a,b,c,d);else if(null==b)t(a)||(g(a,c,d),e=c[d]),e=o(e,new q(q.REMOVE,a,b));else if(r(b))if(r(a))if(a.tagName===b.tagName&&a.namespace===b.namespace&&a.key===b.key){var j=w(a.properties,b.properties);j&&(e=o(e,new q(q.PROPS,a,j))),e=f(a,b,c,e,d)}else e=o(e,new q(q.VNODE,a,b)),h=!0;else e=o(e,new q(q.VNODE,a,b)),h=!0;else s(b)?s(a)?a.text!==b.text&&(e=o(e,new q(q.VTEXT,a,b))):(e=o(e,new q(q.VTEXT,a,b)),h=!0):t(b)&&(t(a)||(h=!0),e=o(e,new q(q.WIDGET,a,b)));e&&(c[d]=e),h&&g(a,c,d)}}function f(a,b,c,d,f){for(var g=a.children,h=m(g,b.children),i=g.length,j=h.length,k=i>j?i:j,l=0;k>l;l++){var n=g[l],p=h[l];f+=1,n?e(n,p,c,f):p&&(d=o(d,new q(q.INSERT,null,p))),r(n)&&n.count&&(f+=n.count)}return h.moves&&(d=o(d,new q(q.ORDER,a,h.moves))),d}function g(a,b,c){k(a,b,c),h(a,b,c)}function h(a,b,c){if(t(a))"function"==typeof a.destroy&&(b[c]=o(b[c],new q(q.REMOVE,a,null)));else if(r(a)&&(a.hasWidgets||a.hasThunks))for(var d=a.children,e=d.length,f=0;e>f;f++){var g=d[f];c+=1,h(g,b,c),r(g)&&g.count&&(c+=g.count)}else u(a)&&i(a,null,b,c)}function i(a,b,c,e){var f=v(a,b),g=d(f.a,f.b);j(g)&&(c[e]=new q(q.THUNK,null,g))}function j(a){for(var b in a)if("a"!==b)return!0;return!1}function k(a,b,c){if(r(a)){if(a.hooks&&(b[c]=o(b[c],new q(q.PROPS,a,l(a.hooks)))),a.descendantHooks||a.hasThunks)for(var d=a.children,e=d.length,f=0;e>f;f++){var g=d[f];c+=1,k(g,b,c),r(g)&&g.count&&(c+=g.count)}}else u(a)&&i(a,null,b,c)}function l(a){var b={};for(var d in a)b[d]=c;return b}function m(a,b){var d=n(b);if(!d)return b;var e=n(a);if(!e)return b;var f={},g={};for(var h in d)f[d[h]]=e[h];for(var i in e)g[e[i]]=d[i];for(var j=a.length,k=b.length,l=j>k?j:k,m=[],o=0,p=0,q=0,r={},s=r.removes={},t=r.reverse={},u=!1;l>o;){var v=g[p];if(v!==c)m[p]=b[v],v!==q&&(r[v]=q,t[q]=v,u=!0),q++;else if(p in g)m[p]=c,s[p]=q++,u=!0;else{for(;f[o]!==c;)o++;if(l>o){var w=b[o];w&&(m[p]=w,o!==q&&(u=!0,r[o]=q,t[q]=o),q++),o++}}p++}return u&&(m.moves=r),m}function n(a){var b,d;for(b=0;bc;c++)d.next();return d.next().value}}function e(a,b){a.$index=b,a.$even=b%2===0,a.$odd=!a.$even}var f="undefined"!=typeof Symbol?Symbol.iterator:"@@iterator";return{restrict:"A",priority:1e3,linkVirtual:function(g){var h=b(g,"v-repeat"),i=h.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)\s*$/),j=i[1],k=i[2];i=j.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);var l=i[3]||i[1],m=i[2],n=a(k)(g.$scope);if(Array.isArray(n))return n.map(function(a,b){var d=c(g);return d.$scope=g.$scope.$new(),d.$scope[l]=a,e(d.$scope,b),d});if(n&&n[f]){for(var o=n[f](),p=[],q=0,r=o.next();!r.done;){var s=r.value,t=c(g);t.$scope=g.$scope.$new(),m?(t.$scope[m]=d(s,0),t.$scope[l]=d(s,1)):t.$scope[l]=s,e(t.$scope,q),p.push(t),q++,r=o.next()}return p}return"object"==typeof n&&null!==n?Object.keys(n).map(function(a,b){var d=c(g);return d.$scope=g.$scope.$new(),d.$scope[m]=a,d.$scope[l]=n[a],e(d.$scope,b),d}):[]}}}]),b.module("teropa.virtualDom.vRoot",["teropa.virtualDom.virtualize","teropa.virtualDom.link"]).directive("vRoot",["$injector","$interpolate","virtualizeDom","linkVDom",function(a,c,d,e){"use strict";return{compile:function(a){var c=a[0],f=d(c);return a.empty(),function(a,c,d){function g(){if(j){var b=e(f,a),c=virtualDom.diff(h,b);i=virtualDom.patch(i,c),h=b,j=!1}}var h=e(f,a),i=virtualDom.create(h);c.replaceWith(i);var j;a.$watch(d.vRoot,function(){j=!0,a.$$postDigest(g)}),a.$on("$destroy",function(){b.element(i).remove()})}}}}]),b.module("teropa.virtualDom",["teropa.virtualDom.getAttribute","teropa.virtualDom.cloneTree","teropa.virtualDom.virtualize","teropa.virtualDom.link","teropa.virtualDom.vIf","teropa.virtualDom.vRepeat","teropa.virtualDom.vRoot"])}(window,window.angular);
--------------------------------------------------------------------------------
/config/karma-angular-1.2.28.js:
--------------------------------------------------------------------------------
1 | module.exports = function (karma) {
2 |
3 | var files = require('../files').files;
4 |
5 | karma.set({
6 | basePath: '..',
7 | files: [].concat(files.angular('1.2.28'), files.lib, files.testLib, files.src, files.test),
8 | logLevel: karma.LOG_DEBUG,
9 | browsers: [ 'PhantomJS' ]
10 | });
11 |
12 | };
13 |
--------------------------------------------------------------------------------
/config/karma-angular-1.4.0-beta.3.js:
--------------------------------------------------------------------------------
1 | module.exports = function (karma) {
2 |
3 | var files = require('../files').files;
4 |
5 | karma.set({
6 | basePath: '..',
7 | files: [].concat(files.angular('1.4.0-beta.3'), files.lib, files.testLib, files.src, files.test),
8 | logLevel: karma.LOG_DEBUG,
9 | browsers: [ 'PhantomJS' ]
10 | });
11 |
12 | };
13 |
--------------------------------------------------------------------------------
/config/karma.js:
--------------------------------------------------------------------------------
1 | module.exports = function (karma) {
2 |
3 | var files = require('../files').files;
4 |
5 | karma.set({
6 | basePath: '..',
7 | files: [].concat(files.angular('1.3.12'), files.lib, files.testLib, files.src, files.test),
8 | logLevel: karma.LOG_DEBUG,
9 | browsers: [ 'PhantomJS' ]
10 | });
11 |
12 | };
13 |
--------------------------------------------------------------------------------
/examples/hello/README.md:
--------------------------------------------------------------------------------
1 | To run this example, first run `npm install` and then open `index.html` in a browser.
2 |
--------------------------------------------------------------------------------
/examples/hello/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 | {{col.get('name')}}
10 | |
11 |
12 |
13 |
15 |
16 | {{row.get(col.get('key'))}}
17 | |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/examples/hello/index.js:
--------------------------------------------------------------------------------
1 | angular.module('myModule', ['teropa.virtualDom'])
2 | .controller('MyCtrl', function($timeout) {
3 | this.myData = Immutable.fromJS({
4 | cols: [
5 | {name: 'One', cssClass: 'one', key: 'one'},
6 | {name: 'Two', cssClsas: 'two', key: 'two'}
7 | ],
8 | rows: [
9 | {one: 'A1', two: 'B1'},
10 | {one: 'A2', two: 'B2'}
11 | ]
12 | });
13 |
14 | // A new version of the immutable data structure triggers
15 | // DOM diffing later.
16 | $timeout(function() {
17 | this.myData = this.myData.updateIn(['rows'], function(rows) {
18 | return rows.push(Immutable.Map({one: 'A3', two: 'B3'}));
19 | });
20 | }.bind(this), 1000);
21 | });
22 |
--------------------------------------------------------------------------------
/examples/hello/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-virtual-dom-hello-example",
3 | "version": "0.0.1",
4 | "description": "The Hello World Example for angular-virtual-dom",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "Tero Parviainen ",
10 | "licenses": {
11 | "type": "MIT",
12 | "url": "https://github.com/teropa/angular-virtual-dom/blob/master/LICENSE"
13 | },
14 | "dependencies": {
15 | "angular": "^1.3.12",
16 | "angular-virtual-dom": "0.0.2",
17 | "immutable": "^3.6.2"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/files.js:
--------------------------------------------------------------------------------
1 | vdomFiles = {
2 | lib: [
3 | 'lib/virtual-dom.js'
4 | ],
5 | src: [
6 | 'src/get_attribute.js',
7 | 'src/directive_normalize.js',
8 | 'src/clone_tree.js',
9 | 'src/virtualize.js',
10 | 'src/link.js',
11 | 'src/v_if_directive.js',
12 | 'src/v_repeat_directive.js',
13 | 'src/v_root_directive.js',
14 | 'src/angular-virtual-dom.js',
15 | ],
16 | testLib: [
17 | 'lib/immutable.js',
18 | 'lib/mori.js'
19 | ],
20 | test: [
21 | 'test/*spec.js'
22 | ],
23 | angular: function(version) {
24 | return [
25 | 'lib/angular-' + version + '/angular.js',
26 | 'lib/angular-' + version + '/angular-mocks.js'
27 | ];
28 | }
29 | };
30 |
31 | if (exports) {
32 | exports.files = vdomFiles;
33 | }
34 |
--------------------------------------------------------------------------------
/lib/virtual-dom.js:
--------------------------------------------------------------------------------
1 | !function(e){var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.virtualDom=e()}(function(){var define,module,exports;return (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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
41 | * Available under the MIT License
42 | * ECMAScript compliant, uniform cross-browser split method
43 | */
44 |
45 | /**
46 | * Splits a string into an array of strings using a regex or string separator. Matches of the
47 | * separator are not included in the result array. However, if `separator` is a regex that contains
48 | * capturing groups, backreferences are spliced into the result each time `separator` is matched.
49 | * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
50 | * cross-browser.
51 | * @param {String} str String to split.
52 | * @param {RegExp|String} separator Regex or string to use for separating the string.
53 | * @param {Number} [limit] Maximum number of items to include in the result array.
54 | * @returns {Array} Array of substrings.
55 | * @example
56 | *
57 | * // Basic use
58 | * split('a b c d', ' ');
59 | * // -> ['a', 'b', 'c', 'd']
60 | *
61 | * // With limit
62 | * split('a b c d', ' ', 2);
63 | * // -> ['a', 'b']
64 | *
65 | * // Backreferences in result array
66 | * split('..word1 word2..', /([a-z]+)(\d+)/i);
67 | * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
68 | */
69 | module.exports = (function split(undef) {
70 |
71 | var nativeSplit = String.prototype.split,
72 | compliantExecNpcg = /()??/.exec("")[1] === undef,
73 | // NPCG: nonparticipating capturing group
74 | self;
75 |
76 | self = function(str, separator, limit) {
77 | // If `separator` is not a regex, use `nativeSplit`
78 | if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
79 | return nativeSplit.call(str, separator, limit);
80 | }
81 | var output = [],
82 | flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6
83 | (separator.sticky ? "y" : ""),
84 | // Firefox 3+
85 | lastLastIndex = 0,
86 | // Make `global` and avoid `lastIndex` issues by working with a copy
87 | separator = new RegExp(separator.source, flags + "g"),
88 | separator2, match, lastIndex, lastLength;
89 | str += ""; // Type-convert
90 | if (!compliantExecNpcg) {
91 | // Doesn't need flags gy, but they don't hurt
92 | separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
93 | }
94 | /* Values for `limit`, per the spec:
95 | * If undefined: 4294967295 // Math.pow(2, 32) - 1
96 | * If 0, Infinity, or NaN: 0
97 | * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
98 | * If negative number: 4294967296 - Math.floor(Math.abs(limit))
99 | * If other: Type-convert, then use the above rules
100 | */
101 | limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1
102 | limit >>> 0; // ToUint32(limit)
103 | while (match = separator.exec(str)) {
104 | // `separator.lastIndex` is not reliable cross-browser
105 | lastIndex = match.index + match[0].length;
106 | if (lastIndex > lastLastIndex) {
107 | output.push(str.slice(lastLastIndex, match.index));
108 | // Fix browsers whose `exec` methods don't consistently return `undefined` for
109 | // nonparticipating capturing groups
110 | if (!compliantExecNpcg && match.length > 1) {
111 | match[0].replace(separator2, function() {
112 | for (var i = 1; i < arguments.length - 2; i++) {
113 | if (arguments[i] === undef) {
114 | match[i] = undef;
115 | }
116 | }
117 | });
118 | }
119 | if (match.length > 1 && match.index < str.length) {
120 | Array.prototype.push.apply(output, match.slice(1));
121 | }
122 | lastLength = match[0].length;
123 | lastLastIndex = lastIndex;
124 | if (output.length >= limit) {
125 | break;
126 | }
127 | }
128 | if (separator.lastIndex === match.index) {
129 | separator.lastIndex++; // Avoid an infinite loop
130 | }
131 | }
132 | if (lastLastIndex === str.length) {
133 | if (lastLength || !separator.test("")) {
134 | output.push("");
135 | }
136 | } else {
137 | output.push(str.slice(lastLastIndex));
138 | }
139 | return output.length > limit ? output.slice(0, limit) : output;
140 | };
141 |
142 | return self;
143 | })();
144 |
145 | },{}],6:[function(_dereq_,module,exports){
146 | 'use strict';
147 |
148 | var OneVersionConstraint = _dereq_('individual/one-version');
149 |
150 | var MY_VERSION = '7';
151 | OneVersionConstraint('ev-store', MY_VERSION);
152 |
153 | var hashKey = '__EV_STORE_KEY@' + MY_VERSION;
154 |
155 | module.exports = EvStore;
156 |
157 | function EvStore(elem) {
158 | var hash = elem[hashKey];
159 |
160 | if (!hash) {
161 | hash = elem[hashKey] = {};
162 | }
163 |
164 | return hash;
165 | }
166 |
167 | },{"individual/one-version":8}],7:[function(_dereq_,module,exports){
168 | (function (global){
169 | 'use strict';
170 |
171 | /*global window, global*/
172 |
173 | var root = typeof window !== 'undefined' ?
174 | window : typeof global !== 'undefined' ?
175 | global : {};
176 |
177 | module.exports = Individual;
178 |
179 | function Individual(key, value) {
180 | if (key in root) {
181 | return root[key];
182 | }
183 |
184 | root[key] = value;
185 |
186 | return value;
187 | }
188 |
189 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
190 | },{}],8:[function(_dereq_,module,exports){
191 | 'use strict';
192 |
193 | var Individual = _dereq_('./index.js');
194 |
195 | module.exports = OneVersion;
196 |
197 | function OneVersion(moduleName, version, defaultValue) {
198 | var key = '__INDIVIDUAL_ONE_VERSION_' + moduleName;
199 | var enforceKey = key + '_ENFORCE_SINGLETON';
200 |
201 | var versionValue = Individual(enforceKey, version);
202 |
203 | if (versionValue !== version) {
204 | throw new Error('Can only have one copy of ' +
205 | moduleName + '.\n' +
206 | 'You already have version ' + versionValue +
207 | ' installed.\n' +
208 | 'This means you cannot install version ' + version);
209 | }
210 |
211 | return Individual(key, defaultValue);
212 | }
213 |
214 | },{"./index.js":7}],9:[function(_dereq_,module,exports){
215 | (function (global){
216 | var topLevel = typeof global !== 'undefined' ? global :
217 | typeof window !== 'undefined' ? window : {}
218 | var minDoc = _dereq_('min-document');
219 |
220 | if (typeof document !== 'undefined') {
221 | module.exports = document;
222 | } else {
223 | var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
224 |
225 | if (!doccy) {
226 | doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
227 | }
228 |
229 | module.exports = doccy;
230 | }
231 |
232 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
233 | },{"min-document":35}],10:[function(_dereq_,module,exports){
234 | "use strict";
235 |
236 | module.exports = function isObject(x) {
237 | return typeof x === "object" && x !== null;
238 | };
239 |
240 | },{}],11:[function(_dereq_,module,exports){
241 | var nativeIsArray = Array.isArray
242 | var toString = Object.prototype.toString
243 |
244 | module.exports = nativeIsArray || isArray
245 |
246 | function isArray(obj) {
247 | return toString.call(obj) === "[object Array]"
248 | }
249 |
250 | },{}],12:[function(_dereq_,module,exports){
251 | var patch = _dereq_("./vdom/patch.js")
252 |
253 | module.exports = patch
254 |
255 | },{"./vdom/patch.js":17}],13:[function(_dereq_,module,exports){
256 | var isObject = _dereq_("is-object")
257 | var isHook = _dereq_("../vnode/is-vhook.js")
258 |
259 | module.exports = applyProperties
260 |
261 | function applyProperties(node, props, previous) {
262 | for (var propName in props) {
263 | var propValue = props[propName]
264 |
265 | if (propValue === undefined) {
266 | removeProperty(node, propName, propValue, previous);
267 | } else if (isHook(propValue)) {
268 | removeProperty(node, propName, propValue, previous)
269 | if (propValue.hook) {
270 | propValue.hook(node,
271 | propName,
272 | previous ? previous[propName] : undefined)
273 | }
274 | } else {
275 | if (isObject(propValue)) {
276 | patchObject(node, props, previous, propName, propValue);
277 | } else {
278 | node[propName] = propValue
279 | }
280 | }
281 | }
282 | }
283 |
284 | function removeProperty(node, propName, propValue, previous) {
285 | if (previous) {
286 | var previousValue = previous[propName]
287 |
288 | if (!isHook(previousValue)) {
289 | if (propName === "attributes") {
290 | for (var attrName in previousValue) {
291 | node.removeAttribute(attrName)
292 | }
293 | } else if (propName === "style") {
294 | for (var i in previousValue) {
295 | node.style[i] = ""
296 | }
297 | } else if (typeof previousValue === "string") {
298 | node[propName] = ""
299 | } else {
300 | node[propName] = null
301 | }
302 | } else if (previousValue.unhook) {
303 | previousValue.unhook(node, propName, propValue)
304 | }
305 | }
306 | }
307 |
308 | function patchObject(node, props, previous, propName, propValue) {
309 | var previousValue = previous ? previous[propName] : undefined
310 |
311 | // Set attributes
312 | if (propName === "attributes") {
313 | for (var attrName in propValue) {
314 | var attrValue = propValue[attrName]
315 |
316 | if (attrValue === undefined) {
317 | node.removeAttribute(attrName)
318 | } else {
319 | node.setAttribute(attrName, attrValue)
320 | }
321 | }
322 |
323 | return
324 | }
325 |
326 | if(previousValue && isObject(previousValue) &&
327 | getPrototype(previousValue) !== getPrototype(propValue)) {
328 | node[propName] = propValue
329 | return
330 | }
331 |
332 | if (!isObject(node[propName])) {
333 | node[propName] = {}
334 | }
335 |
336 | var replacer = propName === "style" ? "" : undefined
337 |
338 | for (var k in propValue) {
339 | var value = propValue[k]
340 | node[propName][k] = (value === undefined) ? replacer : value
341 | }
342 | }
343 |
344 | function getPrototype(value) {
345 | if (Object.getPrototypeOf) {
346 | return Object.getPrototypeOf(value)
347 | } else if (value.__proto__) {
348 | return value.__proto__
349 | } else if (value.constructor) {
350 | return value.constructor.prototype
351 | }
352 | }
353 |
354 | },{"../vnode/is-vhook.js":25,"is-object":10}],14:[function(_dereq_,module,exports){
355 | var document = _dereq_("global/document")
356 |
357 | var applyProperties = _dereq_("./apply-properties")
358 |
359 | var isVNode = _dereq_("../vnode/is-vnode.js")
360 | var isVText = _dereq_("../vnode/is-vtext.js")
361 | var isWidget = _dereq_("../vnode/is-widget.js")
362 | var handleThunk = _dereq_("../vnode/handle-thunk.js")
363 |
364 | module.exports = createElement
365 |
366 | function createElement(vnode, opts) {
367 | var doc = opts ? opts.document || document : document
368 | var warn = opts ? opts.warn : null
369 |
370 | vnode = handleThunk(vnode).a
371 |
372 | if (isWidget(vnode)) {
373 | return vnode.init()
374 | } else if (isVText(vnode)) {
375 | return doc.createTextNode(vnode.text)
376 | } else if (!isVNode(vnode)) {
377 | if (warn) {
378 | warn("Item is not a valid virtual dom node", vnode)
379 | }
380 | return null
381 | }
382 |
383 | var node = (vnode.namespace === null) ?
384 | doc.createElement(vnode.tagName) :
385 | doc.createElementNS(vnode.namespace, vnode.tagName)
386 |
387 | var props = vnode.properties
388 | applyProperties(node, props)
389 |
390 | var children = vnode.children
391 |
392 | for (var i = 0; i < children.length; i++) {
393 | var childNode = createElement(children[i], opts)
394 | if (childNode) {
395 | node.appendChild(childNode)
396 | }
397 | }
398 |
399 | return node
400 | }
401 |
402 | },{"../vnode/handle-thunk.js":23,"../vnode/is-vnode.js":26,"../vnode/is-vtext.js":27,"../vnode/is-widget.js":28,"./apply-properties":13,"global/document":9}],15:[function(_dereq_,module,exports){
403 | // Maps a virtual DOM tree onto a real DOM tree in an efficient manner.
404 | // We don't want to read all of the DOM nodes in the tree so we use
405 | // the in-order tree indexing to eliminate recursion down certain branches.
406 | // We only recurse into a DOM node if we know that it contains a child of
407 | // interest.
408 |
409 | var noChild = {}
410 |
411 | module.exports = domIndex
412 |
413 | function domIndex(rootNode, tree, indices, nodes) {
414 | if (!indices || indices.length === 0) {
415 | return {}
416 | } else {
417 | indices.sort(ascending)
418 | return recurse(rootNode, tree, indices, nodes, 0)
419 | }
420 | }
421 |
422 | function recurse(rootNode, tree, indices, nodes, rootIndex) {
423 | nodes = nodes || {}
424 |
425 |
426 | if (rootNode) {
427 | if (indexInRange(indices, rootIndex, rootIndex)) {
428 | nodes[rootIndex] = rootNode
429 | }
430 |
431 | var vChildren = tree.children
432 |
433 | if (vChildren) {
434 |
435 | var childNodes = rootNode.childNodes
436 |
437 | for (var i = 0; i < tree.children.length; i++) {
438 | rootIndex += 1
439 |
440 | var vChild = vChildren[i] || noChild
441 | var nextIndex = rootIndex + (vChild.count || 0)
442 |
443 | // skip recursion down the tree if there are no nodes down here
444 | if (indexInRange(indices, rootIndex, nextIndex)) {
445 | recurse(childNodes[i], vChild, indices, nodes, rootIndex)
446 | }
447 |
448 | rootIndex = nextIndex
449 | }
450 | }
451 | }
452 |
453 | return nodes
454 | }
455 |
456 | // Binary search for an index in the interval [left, right]
457 | function indexInRange(indices, left, right) {
458 | if (indices.length === 0) {
459 | return false
460 | }
461 |
462 | var minIndex = 0
463 | var maxIndex = indices.length - 1
464 | var currentIndex
465 | var currentItem
466 |
467 | while (minIndex <= maxIndex) {
468 | currentIndex = ((maxIndex + minIndex) / 2) >> 0
469 | currentItem = indices[currentIndex]
470 |
471 | if (minIndex === maxIndex) {
472 | return currentItem >= left && currentItem <= right
473 | } else if (currentItem < left) {
474 | minIndex = currentIndex + 1
475 | } else if (currentItem > right) {
476 | maxIndex = currentIndex - 1
477 | } else {
478 | return true
479 | }
480 | }
481 |
482 | return false;
483 | }
484 |
485 | function ascending(a, b) {
486 | return a > b ? 1 : -1
487 | }
488 |
489 | },{}],16:[function(_dereq_,module,exports){
490 | var applyProperties = _dereq_("./apply-properties")
491 |
492 | var isWidget = _dereq_("../vnode/is-widget.js")
493 | var VPatch = _dereq_("../vnode/vpatch.js")
494 |
495 | var render = _dereq_("./create-element")
496 | var updateWidget = _dereq_("./update-widget")
497 |
498 | module.exports = applyPatch
499 |
500 | function applyPatch(vpatch, domNode, renderOptions) {
501 | var type = vpatch.type
502 | var vNode = vpatch.vNode
503 | var patch = vpatch.patch
504 |
505 | switch (type) {
506 | case VPatch.REMOVE:
507 | return removeNode(domNode, vNode)
508 | case VPatch.INSERT:
509 | return insertNode(domNode, patch, renderOptions)
510 | case VPatch.VTEXT:
511 | return stringPatch(domNode, vNode, patch, renderOptions)
512 | case VPatch.WIDGET:
513 | return widgetPatch(domNode, vNode, patch, renderOptions)
514 | case VPatch.VNODE:
515 | return vNodePatch(domNode, vNode, patch, renderOptions)
516 | case VPatch.ORDER:
517 | reorderChildren(domNode, patch)
518 | return domNode
519 | case VPatch.PROPS:
520 | applyProperties(domNode, patch, vNode.properties)
521 | return domNode
522 | case VPatch.THUNK:
523 | return replaceRoot(domNode,
524 | renderOptions.patch(domNode, patch, renderOptions))
525 | default:
526 | return domNode
527 | }
528 | }
529 |
530 | function removeNode(domNode, vNode) {
531 | var parentNode = domNode.parentNode
532 |
533 | if (parentNode) {
534 | parentNode.removeChild(domNode)
535 | }
536 |
537 | destroyWidget(domNode, vNode);
538 |
539 | return null
540 | }
541 |
542 | function insertNode(parentNode, vNode, renderOptions) {
543 | var newNode = render(vNode, renderOptions)
544 |
545 | if (parentNode) {
546 | parentNode.appendChild(newNode)
547 | }
548 |
549 | return parentNode
550 | }
551 |
552 | function stringPatch(domNode, leftVNode, vText, renderOptions) {
553 | var newNode
554 |
555 | if (domNode.nodeType === 3) {
556 | domNode.replaceData(0, domNode.length, vText.text)
557 | newNode = domNode
558 | } else {
559 | var parentNode = domNode.parentNode
560 | newNode = render(vText, renderOptions)
561 |
562 | if (parentNode) {
563 | parentNode.replaceChild(newNode, domNode)
564 | }
565 | }
566 |
567 | return newNode
568 | }
569 |
570 | function widgetPatch(domNode, leftVNode, widget, renderOptions) {
571 | var updating = updateWidget(leftVNode, widget)
572 | var newNode
573 |
574 | if (updating) {
575 | newNode = widget.update(leftVNode, domNode) || domNode
576 | } else {
577 | newNode = render(widget, renderOptions)
578 | }
579 |
580 | var parentNode = domNode.parentNode
581 |
582 | if (parentNode && newNode !== domNode) {
583 | parentNode.replaceChild(newNode, domNode)
584 | }
585 |
586 | if (!updating) {
587 | destroyWidget(domNode, leftVNode)
588 | }
589 |
590 | return newNode
591 | }
592 |
593 | function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
594 | var parentNode = domNode.parentNode
595 | var newNode = render(vNode, renderOptions)
596 |
597 | if (parentNode) {
598 | parentNode.replaceChild(newNode, domNode)
599 | }
600 |
601 | return newNode
602 | }
603 |
604 | function destroyWidget(domNode, w) {
605 | if (typeof w.destroy === "function" && isWidget(w)) {
606 | w.destroy(domNode)
607 | }
608 | }
609 |
610 | function reorderChildren(domNode, bIndex) {
611 | var children = []
612 | var childNodes = domNode.childNodes
613 | var len = childNodes.length
614 | var i
615 | var reverseIndex = bIndex.reverse
616 |
617 | for (i = 0; i < len; i++) {
618 | children.push(domNode.childNodes[i])
619 | }
620 |
621 | var insertOffset = 0
622 | var move
623 | var node
624 | var insertNode
625 | var chainLength
626 | var insertedLength
627 | var nextSibling
628 | for (i = 0; i < len;) {
629 | move = bIndex[i]
630 | chainLength = 1
631 | if (move !== undefined && move !== i) {
632 | // try to bring forward as long of a chain as possible
633 | while (bIndex[i + chainLength] === move + chainLength) {
634 | chainLength++;
635 | }
636 |
637 | // the element currently at this index will be moved later so increase the insert offset
638 | if (reverseIndex[i] > i + chainLength) {
639 | insertOffset++
640 | }
641 |
642 | node = children[move]
643 | insertNode = childNodes[i + insertOffset] || null
644 | insertedLength = 0
645 | while (node !== insertNode && insertedLength++ < chainLength) {
646 | domNode.insertBefore(node, insertNode);
647 | node = children[move + insertedLength];
648 | }
649 |
650 | // the moved element came from the front of the array so reduce the insert offset
651 | if (move + chainLength < i) {
652 | insertOffset--
653 | }
654 | }
655 |
656 | // element at this index is scheduled to be removed so increase insert offset
657 | if (i in bIndex.removes) {
658 | insertOffset++
659 | }
660 |
661 | i += chainLength
662 | }
663 | }
664 |
665 | function replaceRoot(oldRoot, newRoot) {
666 | if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) {
667 | console.log(oldRoot)
668 | oldRoot.parentNode.replaceChild(newRoot, oldRoot)
669 | }
670 |
671 | return newRoot;
672 | }
673 |
674 | },{"../vnode/is-widget.js":28,"../vnode/vpatch.js":31,"./apply-properties":13,"./create-element":14,"./update-widget":18}],17:[function(_dereq_,module,exports){
675 | var document = _dereq_("global/document")
676 | var isArray = _dereq_("x-is-array")
677 |
678 | var domIndex = _dereq_("./dom-index")
679 | var patchOp = _dereq_("./patch-op")
680 | module.exports = patch
681 |
682 | function patch(rootNode, patches) {
683 | return patchRecursive(rootNode, patches)
684 | }
685 |
686 | function patchRecursive(rootNode, patches, renderOptions) {
687 | var indices = patchIndices(patches)
688 |
689 | if (indices.length === 0) {
690 | return rootNode
691 | }
692 |
693 | var index = domIndex(rootNode, patches.a, indices)
694 | var ownerDocument = rootNode.ownerDocument
695 |
696 | if (!renderOptions) {
697 | renderOptions = { patch: patchRecursive }
698 | if (ownerDocument !== document) {
699 | renderOptions.document = ownerDocument
700 | }
701 | }
702 |
703 | for (var i = 0; i < indices.length; i++) {
704 | var nodeIndex = indices[i]
705 | rootNode = applyPatch(rootNode,
706 | index[nodeIndex],
707 | patches[nodeIndex],
708 | renderOptions)
709 | }
710 |
711 | return rootNode
712 | }
713 |
714 | function applyPatch(rootNode, domNode, patchList, renderOptions) {
715 | if (!domNode) {
716 | return rootNode
717 | }
718 |
719 | var newNode
720 |
721 | if (isArray(patchList)) {
722 | for (var i = 0; i < patchList.length; i++) {
723 | newNode = patchOp(patchList[i], domNode, renderOptions)
724 |
725 | if (domNode === rootNode) {
726 | rootNode = newNode
727 | }
728 | }
729 | } else {
730 | newNode = patchOp(patchList, domNode, renderOptions)
731 |
732 | if (domNode === rootNode) {
733 | rootNode = newNode
734 | }
735 | }
736 |
737 | return rootNode
738 | }
739 |
740 | function patchIndices(patches) {
741 | var indices = []
742 |
743 | for (var key in patches) {
744 | if (key !== "a") {
745 | indices.push(Number(key))
746 | }
747 | }
748 |
749 | return indices
750 | }
751 |
752 | },{"./dom-index":15,"./patch-op":16,"global/document":9,"x-is-array":11}],18:[function(_dereq_,module,exports){
753 | var isWidget = _dereq_("../vnode/is-widget.js")
754 |
755 | module.exports = updateWidget
756 |
757 | function updateWidget(a, b) {
758 | if (isWidget(a) && isWidget(b)) {
759 | if ("name" in a && "name" in b) {
760 | return a.id === b.id
761 | } else {
762 | return a.init === b.init
763 | }
764 | }
765 |
766 | return false
767 | }
768 |
769 | },{"../vnode/is-widget.js":28}],19:[function(_dereq_,module,exports){
770 | 'use strict';
771 |
772 | var EvStore = _dereq_('ev-store');
773 |
774 | module.exports = EvHook;
775 |
776 | function EvHook(value) {
777 | if (!(this instanceof EvHook)) {
778 | return new EvHook(value);
779 | }
780 |
781 | this.value = value;
782 | }
783 |
784 | EvHook.prototype.hook = function (node, propertyName) {
785 | var es = EvStore(node);
786 | var propName = propertyName.substr(3);
787 |
788 | es[propName] = this.value;
789 | };
790 |
791 | EvHook.prototype.unhook = function(node, propertyName) {
792 | var es = EvStore(node);
793 | var propName = propertyName.substr(3);
794 |
795 | es[propName] = undefined;
796 | };
797 |
798 | },{"ev-store":6}],20:[function(_dereq_,module,exports){
799 | 'use strict';
800 |
801 | module.exports = SoftSetHook;
802 |
803 | function SoftSetHook(value) {
804 | if (!(this instanceof SoftSetHook)) {
805 | return new SoftSetHook(value);
806 | }
807 |
808 | this.value = value;
809 | }
810 |
811 | SoftSetHook.prototype.hook = function (node, propertyName) {
812 | if (node[propertyName] !== this.value) {
813 | node[propertyName] = this.value;
814 | }
815 | };
816 |
817 | },{}],21:[function(_dereq_,module,exports){
818 | 'use strict';
819 |
820 | var isArray = _dereq_('x-is-array');
821 |
822 | var VNode = _dereq_('../vnode/vnode.js');
823 | var VText = _dereq_('../vnode/vtext.js');
824 | var isVNode = _dereq_('../vnode/is-vnode');
825 | var isVText = _dereq_('../vnode/is-vtext');
826 | var isWidget = _dereq_('../vnode/is-widget');
827 | var isHook = _dereq_('../vnode/is-vhook');
828 | var isVThunk = _dereq_('../vnode/is-thunk');
829 |
830 | var parseTag = _dereq_('./parse-tag.js');
831 | var softSetHook = _dereq_('./hooks/soft-set-hook.js');
832 | var evHook = _dereq_('./hooks/ev-hook.js');
833 |
834 | module.exports = h;
835 |
836 | function h(tagName, properties, children) {
837 | var childNodes = [];
838 | var tag, props, key, namespace;
839 |
840 | if (!children && isChildren(properties)) {
841 | children = properties;
842 | props = {};
843 | }
844 |
845 | props = props || properties || {};
846 | tag = parseTag(tagName, props);
847 |
848 | // support keys
849 | if (props.hasOwnProperty('key')) {
850 | key = props.key;
851 | props.key = undefined;
852 | }
853 |
854 | // support namespace
855 | if (props.hasOwnProperty('namespace')) {
856 | namespace = props.namespace;
857 | props.namespace = undefined;
858 | }
859 |
860 | // fix cursor bug
861 | if (tag === 'INPUT' &&
862 | !namespace &&
863 | props.hasOwnProperty('value') &&
864 | props.value !== undefined &&
865 | !isHook(props.value)
866 | ) {
867 | props.value = softSetHook(props.value);
868 | }
869 |
870 | transformProperties(props);
871 |
872 | if (children !== undefined && children !== null) {
873 | addChild(children, childNodes, tag, props);
874 | }
875 |
876 |
877 | return new VNode(tag, props, childNodes, key, namespace);
878 | }
879 |
880 | function addChild(c, childNodes, tag, props) {
881 | if (typeof c === 'string') {
882 | childNodes.push(new VText(c));
883 | } else if (isChild(c)) {
884 | childNodes.push(c);
885 | } else if (isArray(c)) {
886 | for (var i = 0; i < c.length; i++) {
887 | addChild(c[i], childNodes, tag, props);
888 | }
889 | } else if (c === null || c === undefined) {
890 | return;
891 | } else {
892 | throw UnexpectedVirtualElement({
893 | foreignObject: c,
894 | parentVnode: {
895 | tagName: tag,
896 | properties: props
897 | }
898 | });
899 | }
900 | }
901 |
902 | function transformProperties(props) {
903 | for (var propName in props) {
904 | if (props.hasOwnProperty(propName)) {
905 | var value = props[propName];
906 |
907 | if (isHook(value)) {
908 | continue;
909 | }
910 |
911 | if (propName.substr(0, 3) === 'ev-') {
912 | // add ev-foo support
913 | props[propName] = evHook(value);
914 | }
915 | }
916 | }
917 | }
918 |
919 | function isChild(x) {
920 | return isVNode(x) || isVText(x) || isWidget(x) || isVThunk(x);
921 | }
922 |
923 | function isChildren(x) {
924 | return typeof x === 'string' || isArray(x) || isChild(x);
925 | }
926 |
927 | function UnexpectedVirtualElement(data) {
928 | var err = new Error();
929 |
930 | err.type = 'virtual-hyperscript.unexpected.virtual-element';
931 | err.message = 'Unexpected virtual child passed to h().\n' +
932 | 'Expected a VNode / Vthunk / VWidget / string but:\n' +
933 | 'got:\n' +
934 | errorString(data.foreignObject) +
935 | '.\n' +
936 | 'The parent vnode is:\n' +
937 | errorString(data.parentVnode)
938 | '\n' +
939 | 'Suggested fix: change your `h(..., [ ... ])` callsite.';
940 | err.foreignObject = data.foreignObject;
941 | err.parentVnode = data.parentVnode;
942 |
943 | return err;
944 | }
945 |
946 | function errorString(obj) {
947 | try {
948 | return JSON.stringify(obj, null, ' ');
949 | } catch (e) {
950 | return String(obj);
951 | }
952 | }
953 |
954 | },{"../vnode/is-thunk":24,"../vnode/is-vhook":25,"../vnode/is-vnode":26,"../vnode/is-vtext":27,"../vnode/is-widget":28,"../vnode/vnode.js":30,"../vnode/vtext.js":32,"./hooks/ev-hook.js":19,"./hooks/soft-set-hook.js":20,"./parse-tag.js":22,"x-is-array":11}],22:[function(_dereq_,module,exports){
955 | 'use strict';
956 |
957 | var split = _dereq_('browser-split');
958 |
959 | var classIdSplit = /([\.#]?[a-zA-Z0-9_:-]+)/;
960 | var notClassId = /^\.|#/;
961 |
962 | module.exports = parseTag;
963 |
964 | function parseTag(tag, props) {
965 | if (!tag) {
966 | return 'DIV';
967 | }
968 |
969 | var noId = !(props.hasOwnProperty('id'));
970 |
971 | var tagParts = split(tag, classIdSplit);
972 | var tagName = null;
973 |
974 | if (notClassId.test(tagParts[1])) {
975 | tagName = 'DIV';
976 | }
977 |
978 | var classes, part, type, i;
979 |
980 | for (i = 0; i < tagParts.length; i++) {
981 | part = tagParts[i];
982 |
983 | if (!part) {
984 | continue;
985 | }
986 |
987 | type = part.charAt(0);
988 |
989 | if (!tagName) {
990 | tagName = part;
991 | } else if (type === '.') {
992 | classes = classes || [];
993 | classes.push(part.substring(1, part.length));
994 | } else if (type === '#' && noId) {
995 | props.id = part.substring(1, part.length);
996 | }
997 | }
998 |
999 | if (classes) {
1000 | if (props.className) {
1001 | classes.push(props.className);
1002 | }
1003 |
1004 | props.className = classes.join(' ');
1005 | }
1006 |
1007 | return props.namespace ? tagName : tagName.toUpperCase();
1008 | }
1009 |
1010 | },{"browser-split":5}],23:[function(_dereq_,module,exports){
1011 | var isVNode = _dereq_("./is-vnode")
1012 | var isVText = _dereq_("./is-vtext")
1013 | var isWidget = _dereq_("./is-widget")
1014 | var isThunk = _dereq_("./is-thunk")
1015 |
1016 | module.exports = handleThunk
1017 |
1018 | function handleThunk(a, b) {
1019 | var renderedA = a
1020 | var renderedB = b
1021 |
1022 | if (isThunk(b)) {
1023 | renderedB = renderThunk(b, a)
1024 | }
1025 |
1026 | if (isThunk(a)) {
1027 | renderedA = renderThunk(a, null)
1028 | }
1029 |
1030 | return {
1031 | a: renderedA,
1032 | b: renderedB
1033 | }
1034 | }
1035 |
1036 | function renderThunk(thunk, previous) {
1037 | var renderedThunk = thunk.vnode
1038 |
1039 | if (!renderedThunk) {
1040 | renderedThunk = thunk.vnode = thunk.render(previous)
1041 | }
1042 |
1043 | if (!(isVNode(renderedThunk) ||
1044 | isVText(renderedThunk) ||
1045 | isWidget(renderedThunk))) {
1046 | throw new Error("thunk did not return a valid node");
1047 | }
1048 |
1049 | return renderedThunk
1050 | }
1051 |
1052 | },{"./is-thunk":24,"./is-vnode":26,"./is-vtext":27,"./is-widget":28}],24:[function(_dereq_,module,exports){
1053 | module.exports = isThunk
1054 |
1055 | function isThunk(t) {
1056 | return t && t.type === "Thunk"
1057 | }
1058 |
1059 | },{}],25:[function(_dereq_,module,exports){
1060 | module.exports = isHook
1061 |
1062 | function isHook(hook) {
1063 | return hook &&
1064 | (typeof hook.hook === "function" && !hook.hasOwnProperty("hook") ||
1065 | typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook"))
1066 | }
1067 |
1068 | },{}],26:[function(_dereq_,module,exports){
1069 | var version = _dereq_("./version")
1070 |
1071 | module.exports = isVirtualNode
1072 |
1073 | function isVirtualNode(x) {
1074 | return x && x.type === "VirtualNode" && x.version === version
1075 | }
1076 |
1077 | },{"./version":29}],27:[function(_dereq_,module,exports){
1078 | var version = _dereq_("./version")
1079 |
1080 | module.exports = isVirtualText
1081 |
1082 | function isVirtualText(x) {
1083 | return x && x.type === "VirtualText" && x.version === version
1084 | }
1085 |
1086 | },{"./version":29}],28:[function(_dereq_,module,exports){
1087 | module.exports = isWidget
1088 |
1089 | function isWidget(w) {
1090 | return w && w.type === "Widget"
1091 | }
1092 |
1093 | },{}],29:[function(_dereq_,module,exports){
1094 | module.exports = "1"
1095 |
1096 | },{}],30:[function(_dereq_,module,exports){
1097 | var version = _dereq_("./version")
1098 | var isVNode = _dereq_("./is-vnode")
1099 | var isWidget = _dereq_("./is-widget")
1100 | var isThunk = _dereq_("./is-thunk")
1101 | var isVHook = _dereq_("./is-vhook")
1102 |
1103 | module.exports = VirtualNode
1104 |
1105 | var noProperties = {}
1106 | var noChildren = []
1107 |
1108 | function VirtualNode(tagName, properties, children, key, namespace) {
1109 | this.tagName = tagName
1110 | this.properties = properties || noProperties
1111 | this.children = children || noChildren
1112 | this.key = key != null ? String(key) : undefined
1113 | this.namespace = (typeof namespace === "string") ? namespace : null
1114 |
1115 | var count = (children && children.length) || 0
1116 | var descendants = 0
1117 | var hasWidgets = false
1118 | var hasThunks = false
1119 | var descendantHooks = false
1120 | var hooks
1121 |
1122 | for (var propName in properties) {
1123 | if (properties.hasOwnProperty(propName)) {
1124 | var property = properties[propName]
1125 | if (isVHook(property) && property.unhook) {
1126 | if (!hooks) {
1127 | hooks = {}
1128 | }
1129 |
1130 | hooks[propName] = property
1131 | }
1132 | }
1133 | }
1134 |
1135 | for (var i = 0; i < count; i++) {
1136 | var child = children[i]
1137 | if (isVNode(child)) {
1138 | descendants += child.count || 0
1139 |
1140 | if (!hasWidgets && child.hasWidgets) {
1141 | hasWidgets = true
1142 | }
1143 |
1144 | if (!hasThunks && child.hasThunks) {
1145 | hasThunks = true
1146 | }
1147 |
1148 | if (!descendantHooks && (child.hooks || child.descendantHooks)) {
1149 | descendantHooks = true
1150 | }
1151 | } else if (!hasWidgets && isWidget(child)) {
1152 | if (typeof child.destroy === "function") {
1153 | hasWidgets = true
1154 | }
1155 | } else if (!hasThunks && isThunk(child)) {
1156 | hasThunks = true;
1157 | }
1158 | }
1159 |
1160 | this.count = count + descendants
1161 | this.hasWidgets = hasWidgets
1162 | this.hasThunks = hasThunks
1163 | this.hooks = hooks
1164 | this.descendantHooks = descendantHooks
1165 | }
1166 |
1167 | VirtualNode.prototype.version = version
1168 | VirtualNode.prototype.type = "VirtualNode"
1169 |
1170 | },{"./is-thunk":24,"./is-vhook":25,"./is-vnode":26,"./is-widget":28,"./version":29}],31:[function(_dereq_,module,exports){
1171 | var version = _dereq_("./version")
1172 |
1173 | VirtualPatch.NONE = 0
1174 | VirtualPatch.VTEXT = 1
1175 | VirtualPatch.VNODE = 2
1176 | VirtualPatch.WIDGET = 3
1177 | VirtualPatch.PROPS = 4
1178 | VirtualPatch.ORDER = 5
1179 | VirtualPatch.INSERT = 6
1180 | VirtualPatch.REMOVE = 7
1181 | VirtualPatch.THUNK = 8
1182 |
1183 | module.exports = VirtualPatch
1184 |
1185 | function VirtualPatch(type, vNode, patch) {
1186 | this.type = Number(type)
1187 | this.vNode = vNode
1188 | this.patch = patch
1189 | }
1190 |
1191 | VirtualPatch.prototype.version = version
1192 | VirtualPatch.prototype.type = "VirtualPatch"
1193 |
1194 | },{"./version":29}],32:[function(_dereq_,module,exports){
1195 | var version = _dereq_("./version")
1196 |
1197 | module.exports = VirtualText
1198 |
1199 | function VirtualText(text) {
1200 | this.text = String(text)
1201 | }
1202 |
1203 | VirtualText.prototype.version = version
1204 | VirtualText.prototype.type = "VirtualText"
1205 |
1206 | },{"./version":29}],33:[function(_dereq_,module,exports){
1207 | var isObject = _dereq_("is-object")
1208 | var isHook = _dereq_("../vnode/is-vhook")
1209 |
1210 | module.exports = diffProps
1211 |
1212 | function diffProps(a, b) {
1213 | var diff
1214 |
1215 | for (var aKey in a) {
1216 | if (!(aKey in b)) {
1217 | diff = diff || {}
1218 | diff[aKey] = undefined
1219 | }
1220 |
1221 | var aValue = a[aKey]
1222 | var bValue = b[aKey]
1223 |
1224 | if (aValue === bValue) {
1225 | continue
1226 | } else if (isObject(aValue) && isObject(bValue)) {
1227 | if (getPrototype(bValue) !== getPrototype(aValue)) {
1228 | diff = diff || {}
1229 | diff[aKey] = bValue
1230 | } else if (isHook(bValue)) {
1231 | diff = diff || {}
1232 | diff[aKey] = bValue
1233 | } else {
1234 | var objectDiff = diffProps(aValue, bValue)
1235 | if (objectDiff) {
1236 | diff = diff || {}
1237 | diff[aKey] = objectDiff
1238 | }
1239 | }
1240 | } else {
1241 | diff = diff || {}
1242 | diff[aKey] = bValue
1243 | }
1244 | }
1245 |
1246 | for (var bKey in b) {
1247 | if (!(bKey in a)) {
1248 | diff = diff || {}
1249 | diff[bKey] = b[bKey]
1250 | }
1251 | }
1252 |
1253 | return diff
1254 | }
1255 |
1256 | function getPrototype(value) {
1257 | if (Object.getPrototypeOf) {
1258 | return Object.getPrototypeOf(value)
1259 | } else if (value.__proto__) {
1260 | return value.__proto__
1261 | } else if (value.constructor) {
1262 | return value.constructor.prototype
1263 | }
1264 | }
1265 |
1266 | },{"../vnode/is-vhook":25,"is-object":10}],34:[function(_dereq_,module,exports){
1267 | var isArray = _dereq_("x-is-array")
1268 |
1269 | var VPatch = _dereq_("../vnode/vpatch")
1270 | var isVNode = _dereq_("../vnode/is-vnode")
1271 | var isVText = _dereq_("../vnode/is-vtext")
1272 | var isWidget = _dereq_("../vnode/is-widget")
1273 | var isThunk = _dereq_("../vnode/is-thunk")
1274 | var handleThunk = _dereq_("../vnode/handle-thunk")
1275 |
1276 | var diffProps = _dereq_("./diff-props")
1277 |
1278 | module.exports = diff
1279 |
1280 | function diff(a, b) {
1281 | var patch = { a: a }
1282 | walk(a, b, patch, 0)
1283 | return patch
1284 | }
1285 |
1286 | function walk(a, b, patch, index) {
1287 | if (a === b) {
1288 | return
1289 | }
1290 |
1291 | var apply = patch[index]
1292 | var applyClear = false
1293 |
1294 | if (isThunk(a) || isThunk(b)) {
1295 | thunks(a, b, patch, index)
1296 | } else if (b == null) {
1297 |
1298 | // If a is a widget we will add a remove patch for it
1299 | // Otherwise any child widgets/hooks must be destroyed.
1300 | // This prevents adding two remove patches for a widget.
1301 | if (!isWidget(a)) {
1302 | clearState(a, patch, index)
1303 | apply = patch[index]
1304 | }
1305 |
1306 | apply = appendPatch(apply, new VPatch(VPatch.REMOVE, a, b))
1307 | } else if (isVNode(b)) {
1308 | if (isVNode(a)) {
1309 | if (a.tagName === b.tagName &&
1310 | a.namespace === b.namespace &&
1311 | a.key === b.key) {
1312 | var propsPatch = diffProps(a.properties, b.properties)
1313 | if (propsPatch) {
1314 | apply = appendPatch(apply,
1315 | new VPatch(VPatch.PROPS, a, propsPatch))
1316 | }
1317 | apply = diffChildren(a, b, patch, apply, index)
1318 | } else {
1319 | apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b))
1320 | applyClear = true
1321 | }
1322 | } else {
1323 | apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b))
1324 | applyClear = true
1325 | }
1326 | } else if (isVText(b)) {
1327 | if (!isVText(a)) {
1328 | apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b))
1329 | applyClear = true
1330 | } else if (a.text !== b.text) {
1331 | apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b))
1332 | }
1333 | } else if (isWidget(b)) {
1334 | if (!isWidget(a)) {
1335 | applyClear = true;
1336 | }
1337 |
1338 | apply = appendPatch(apply, new VPatch(VPatch.WIDGET, a, b))
1339 | }
1340 |
1341 | if (apply) {
1342 | patch[index] = apply
1343 | }
1344 |
1345 | if (applyClear) {
1346 | clearState(a, patch, index)
1347 | }
1348 | }
1349 |
1350 | function diffChildren(a, b, patch, apply, index) {
1351 | var aChildren = a.children
1352 | var bChildren = reorder(aChildren, b.children)
1353 |
1354 | var aLen = aChildren.length
1355 | var bLen = bChildren.length
1356 | var len = aLen > bLen ? aLen : bLen
1357 |
1358 | for (var i = 0; i < len; i++) {
1359 | var leftNode = aChildren[i]
1360 | var rightNode = bChildren[i]
1361 | index += 1
1362 |
1363 | if (!leftNode) {
1364 | if (rightNode) {
1365 | // Excess nodes in b need to be added
1366 | apply = appendPatch(apply,
1367 | new VPatch(VPatch.INSERT, null, rightNode))
1368 | }
1369 | } else {
1370 | walk(leftNode, rightNode, patch, index)
1371 | }
1372 |
1373 | if (isVNode(leftNode) && leftNode.count) {
1374 | index += leftNode.count
1375 | }
1376 | }
1377 |
1378 | if (bChildren.moves) {
1379 | // Reorder nodes last
1380 | apply = appendPatch(apply, new VPatch(VPatch.ORDER, a, bChildren.moves))
1381 | }
1382 |
1383 | return apply
1384 | }
1385 |
1386 | function clearState(vNode, patch, index) {
1387 | // TODO: Make this a single walk, not two
1388 | unhook(vNode, patch, index)
1389 | destroyWidgets(vNode, patch, index)
1390 | }
1391 |
1392 | // Patch records for all destroyed widgets must be added because we need
1393 | // a DOM node reference for the destroy function
1394 | function destroyWidgets(vNode, patch, index) {
1395 | if (isWidget(vNode)) {
1396 | if (typeof vNode.destroy === "function") {
1397 | patch[index] = appendPatch(
1398 | patch[index],
1399 | new VPatch(VPatch.REMOVE, vNode, null)
1400 | )
1401 | }
1402 | } else if (isVNode(vNode) && (vNode.hasWidgets || vNode.hasThunks)) {
1403 | var children = vNode.children
1404 | var len = children.length
1405 | for (var i = 0; i < len; i++) {
1406 | var child = children[i]
1407 | index += 1
1408 |
1409 | destroyWidgets(child, patch, index)
1410 |
1411 | if (isVNode(child) && child.count) {
1412 | index += child.count
1413 | }
1414 | }
1415 | } else if (isThunk(vNode)) {
1416 | thunks(vNode, null, patch, index)
1417 | }
1418 | }
1419 |
1420 | // Create a sub-patch for thunks
1421 | function thunks(a, b, patch, index) {
1422 | var nodes = handleThunk(a, b);
1423 | var thunkPatch = diff(nodes.a, nodes.b)
1424 | if (hasPatches(thunkPatch)) {
1425 | patch[index] = new VPatch(VPatch.THUNK, null, thunkPatch)
1426 | }
1427 | }
1428 |
1429 | function hasPatches(patch) {
1430 | for (var index in patch) {
1431 | if (index !== "a") {
1432 | return true;
1433 | }
1434 | }
1435 |
1436 | return false;
1437 | }
1438 |
1439 | // Execute hooks when two nodes are identical
1440 | function unhook(vNode, patch, index) {
1441 | if (isVNode(vNode)) {
1442 | if (vNode.hooks) {
1443 | patch[index] = appendPatch(
1444 | patch[index],
1445 | new VPatch(
1446 | VPatch.PROPS,
1447 | vNode,
1448 | undefinedKeys(vNode.hooks)
1449 | )
1450 | )
1451 | }
1452 |
1453 | if (vNode.descendantHooks || vNode.hasThunks) {
1454 | var children = vNode.children
1455 | var len = children.length
1456 | for (var i = 0; i < len; i++) {
1457 | var child = children[i]
1458 | index += 1
1459 |
1460 | unhook(child, patch, index)
1461 |
1462 | if (isVNode(child) && child.count) {
1463 | index += child.count
1464 | }
1465 | }
1466 | }
1467 | } else if (isThunk(vNode)) {
1468 | thunks(vNode, null, patch, index)
1469 | }
1470 | }
1471 |
1472 | function undefinedKeys(obj) {
1473 | var result = {}
1474 |
1475 | for (var key in obj) {
1476 | result[key] = undefined
1477 | }
1478 |
1479 | return result
1480 | }
1481 |
1482 | // List diff, naive left to right reordering
1483 | function reorder(aChildren, bChildren) {
1484 |
1485 | var bKeys = keyIndex(bChildren)
1486 |
1487 | if (!bKeys) {
1488 | return bChildren
1489 | }
1490 |
1491 | var aKeys = keyIndex(aChildren)
1492 |
1493 | if (!aKeys) {
1494 | return bChildren
1495 | }
1496 |
1497 | var bMatch = {}, aMatch = {}
1498 |
1499 | for (var aKey in bKeys) {
1500 | bMatch[bKeys[aKey]] = aKeys[aKey]
1501 | }
1502 |
1503 | for (var bKey in aKeys) {
1504 | aMatch[aKeys[bKey]] = bKeys[bKey]
1505 | }
1506 |
1507 | var aLen = aChildren.length
1508 | var bLen = bChildren.length
1509 | var len = aLen > bLen ? aLen : bLen
1510 | var shuffle = []
1511 | var freeIndex = 0
1512 | var i = 0
1513 | var moveIndex = 0
1514 | var moves = {}
1515 | var removes = moves.removes = {}
1516 | var reverse = moves.reverse = {}
1517 | var hasMoves = false
1518 |
1519 | while (freeIndex < len) {
1520 | var move = aMatch[i]
1521 | if (move !== undefined) {
1522 | shuffle[i] = bChildren[move]
1523 | if (move !== moveIndex) {
1524 | moves[move] = moveIndex
1525 | reverse[moveIndex] = move
1526 | hasMoves = true
1527 | }
1528 | moveIndex++
1529 | } else if (i in aMatch) {
1530 | shuffle[i] = undefined
1531 | removes[i] = moveIndex++
1532 | hasMoves = true
1533 | } else {
1534 | while (bMatch[freeIndex] !== undefined) {
1535 | freeIndex++
1536 | }
1537 |
1538 | if (freeIndex < len) {
1539 | var freeChild = bChildren[freeIndex]
1540 | if (freeChild) {
1541 | shuffle[i] = freeChild
1542 | if (freeIndex !== moveIndex) {
1543 | hasMoves = true
1544 | moves[freeIndex] = moveIndex
1545 | reverse[moveIndex] = freeIndex
1546 | }
1547 | moveIndex++
1548 | }
1549 | freeIndex++
1550 | }
1551 | }
1552 | i++
1553 | }
1554 |
1555 | if (hasMoves) {
1556 | shuffle.moves = moves
1557 | }
1558 |
1559 | return shuffle
1560 | }
1561 |
1562 | function keyIndex(children) {
1563 | var i, keys
1564 |
1565 | for (i = 0; i < children.length; i++) {
1566 | var child = children[i]
1567 |
1568 | if (child.key !== undefined) {
1569 | keys = keys || {}
1570 | keys[child.key] = i
1571 | }
1572 | }
1573 |
1574 | return keys
1575 | }
1576 |
1577 | function appendPatch(apply, patch) {
1578 | if (apply) {
1579 | if (isArray(apply)) {
1580 | apply.push(patch)
1581 | } else {
1582 | apply = [apply, patch]
1583 | }
1584 |
1585 | return apply
1586 | } else {
1587 | return patch
1588 | }
1589 | }
1590 |
1591 | },{"../vnode/handle-thunk":23,"../vnode/is-thunk":24,"../vnode/is-vnode":26,"../vnode/is-vtext":27,"../vnode/is-widget":28,"../vnode/vpatch":31,"./diff-props":33,"x-is-array":11}],35:[function(_dereq_,module,exports){
1592 |
1593 | },{}]},{},[4])(4)
1594 | });
1595 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-virtual-dom",
3 | "version": "0.1.1",
4 | "homepage": "https://github.com/teropa/angular-virtual-dom",
5 | "author": "Tero Parviainen ",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/teropa/angular-virtual-dom.git"
9 | },
10 | "bugs": {
11 | "url": "https://github.com/teropa/angular-virtual-dom/issues"
12 | },
13 | "licenses": {
14 | "type": "MIT",
15 | "url": "https://github.com/teropa/angular-virtual-dom/blob/master/LICENSE"
16 | },
17 | "dependencies": {
18 | },
19 | "devDependencies": {
20 | "faithful-exec": "^0.1.0",
21 | "grunt": "^0.4.5",
22 | "grunt-contrib-clean": "^0.6.0",
23 | "grunt-contrib-concat": "^0.5.0",
24 | "grunt-contrib-connect": "^0.9.0",
25 | "grunt-contrib-jshint": "^0.11.0",
26 | "grunt-contrib-uglify": "^0.7.0",
27 | "grunt-contrib-watch": "^0.6.1",
28 | "grunt-conventional-changelog": "^1.1.0",
29 | "grunt-karma": "^0.10.1",
30 | "immutable": "=3.6.2",
31 | "jasmine-core": "^2.2.0",
32 | "karma": "^0.12.31",
33 | "karma-chrome-launcher": "^0.1.7",
34 | "karma-firefox-launcher": "^0.1.4",
35 | "karma-jasmine": "^0.3.5",
36 | "karma-phantomjs-launcher": "^0.1.4",
37 | "load-grunt-tasks": "^3.1.0",
38 | "shelljs": "^0.3.0"
39 | },
40 | "scripts": {
41 | "test": "grunt karma:unit"
42 | },
43 | "main": "release/angular-virtual-dom.js"
44 | }
45 |
--------------------------------------------------------------------------------
/release/angular-virtual-dom.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @version v0.1.1
4 | * @link https://github.com/teropa/angular-virtual-dom
5 | * @license MIT License, http://www.opensource.org/licenses/MIT
6 | *
7 | * Bundles virtual-dom by Matt-Esch
8 | * @link https://github.com/Matt-Esch/virtual-dom
9 | * @license MIT License, http://www.opensource.org/licenses/MIT
10 | */
11 |
12 | /* commonjs package manager support */
13 | if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
14 | module.exports = 'teropa.virtualDom';
15 | }
16 |
17 | (function (window, angular, undefined) {
18 | !function(e){var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.virtualDom=e()}(function(){var define,module,exports;return (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);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
58 | * Available under the MIT License
59 | * ECMAScript compliant, uniform cross-browser split method
60 | */
61 |
62 | /**
63 | * Splits a string into an array of strings using a regex or string separator. Matches of the
64 | * separator are not included in the result array. However, if `separator` is a regex that contains
65 | * capturing groups, backreferences are spliced into the result each time `separator` is matched.
66 | * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
67 | * cross-browser.
68 | * @param {String} str String to split.
69 | * @param {RegExp|String} separator Regex or string to use for separating the string.
70 | * @param {Number} [limit] Maximum number of items to include in the result array.
71 | * @returns {Array} Array of substrings.
72 | * @example
73 | *
74 | * // Basic use
75 | * split('a b c d', ' ');
76 | * // -> ['a', 'b', 'c', 'd']
77 | *
78 | * // With limit
79 | * split('a b c d', ' ', 2);
80 | * // -> ['a', 'b']
81 | *
82 | * // Backreferences in result array
83 | * split('..word1 word2..', /([a-z]+)(\d+)/i);
84 | * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
85 | */
86 | module.exports = (function split(undef) {
87 |
88 | var nativeSplit = String.prototype.split,
89 | compliantExecNpcg = /()??/.exec("")[1] === undef,
90 | // NPCG: nonparticipating capturing group
91 | self;
92 |
93 | self = function(str, separator, limit) {
94 | // If `separator` is not a regex, use `nativeSplit`
95 | if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
96 | return nativeSplit.call(str, separator, limit);
97 | }
98 | var output = [],
99 | flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6
100 | (separator.sticky ? "y" : ""),
101 | // Firefox 3+
102 | lastLastIndex = 0,
103 | // Make `global` and avoid `lastIndex` issues by working with a copy
104 | separator = new RegExp(separator.source, flags + "g"),
105 | separator2, match, lastIndex, lastLength;
106 | str += ""; // Type-convert
107 | if (!compliantExecNpcg) {
108 | // Doesn't need flags gy, but they don't hurt
109 | separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
110 | }
111 | /* Values for `limit`, per the spec:
112 | * If undefined: 4294967295 // Math.pow(2, 32) - 1
113 | * If 0, Infinity, or NaN: 0
114 | * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
115 | * If negative number: 4294967296 - Math.floor(Math.abs(limit))
116 | * If other: Type-convert, then use the above rules
117 | */
118 | limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1
119 | limit >>> 0; // ToUint32(limit)
120 | while (match = separator.exec(str)) {
121 | // `separator.lastIndex` is not reliable cross-browser
122 | lastIndex = match.index + match[0].length;
123 | if (lastIndex > lastLastIndex) {
124 | output.push(str.slice(lastLastIndex, match.index));
125 | // Fix browsers whose `exec` methods don't consistently return `undefined` for
126 | // nonparticipating capturing groups
127 | if (!compliantExecNpcg && match.length > 1) {
128 | match[0].replace(separator2, function() {
129 | for (var i = 1; i < arguments.length - 2; i++) {
130 | if (arguments[i] === undef) {
131 | match[i] = undef;
132 | }
133 | }
134 | });
135 | }
136 | if (match.length > 1 && match.index < str.length) {
137 | Array.prototype.push.apply(output, match.slice(1));
138 | }
139 | lastLength = match[0].length;
140 | lastLastIndex = lastIndex;
141 | if (output.length >= limit) {
142 | break;
143 | }
144 | }
145 | if (separator.lastIndex === match.index) {
146 | separator.lastIndex++; // Avoid an infinite loop
147 | }
148 | }
149 | if (lastLastIndex === str.length) {
150 | if (lastLength || !separator.test("")) {
151 | output.push("");
152 | }
153 | } else {
154 | output.push(str.slice(lastLastIndex));
155 | }
156 | return output.length > limit ? output.slice(0, limit) : output;
157 | };
158 |
159 | return self;
160 | })();
161 |
162 | },{}],6:[function(_dereq_,module,exports){
163 | 'use strict';
164 |
165 | var OneVersionConstraint = _dereq_('individual/one-version');
166 |
167 | var MY_VERSION = '7';
168 | OneVersionConstraint('ev-store', MY_VERSION);
169 |
170 | var hashKey = '__EV_STORE_KEY@' + MY_VERSION;
171 |
172 | module.exports = EvStore;
173 |
174 | function EvStore(elem) {
175 | var hash = elem[hashKey];
176 |
177 | if (!hash) {
178 | hash = elem[hashKey] = {};
179 | }
180 |
181 | return hash;
182 | }
183 |
184 | },{"individual/one-version":8}],7:[function(_dereq_,module,exports){
185 | (function (global){
186 | 'use strict';
187 |
188 | /*global window, global*/
189 |
190 | var root = typeof window !== 'undefined' ?
191 | window : typeof global !== 'undefined' ?
192 | global : {};
193 |
194 | module.exports = Individual;
195 |
196 | function Individual(key, value) {
197 | if (key in root) {
198 | return root[key];
199 | }
200 |
201 | root[key] = value;
202 |
203 | return value;
204 | }
205 |
206 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
207 | },{}],8:[function(_dereq_,module,exports){
208 | 'use strict';
209 |
210 | var Individual = _dereq_('./index.js');
211 |
212 | module.exports = OneVersion;
213 |
214 | function OneVersion(moduleName, version, defaultValue) {
215 | var key = '__INDIVIDUAL_ONE_VERSION_' + moduleName;
216 | var enforceKey = key + '_ENFORCE_SINGLETON';
217 |
218 | var versionValue = Individual(enforceKey, version);
219 |
220 | if (versionValue !== version) {
221 | throw new Error('Can only have one copy of ' +
222 | moduleName + '.\n' +
223 | 'You already have version ' + versionValue +
224 | ' installed.\n' +
225 | 'This means you cannot install version ' + version);
226 | }
227 |
228 | return Individual(key, defaultValue);
229 | }
230 |
231 | },{"./index.js":7}],9:[function(_dereq_,module,exports){
232 | (function (global){
233 | var topLevel = typeof global !== 'undefined' ? global :
234 | typeof window !== 'undefined' ? window : {}
235 | var minDoc = _dereq_('min-document');
236 |
237 | if (typeof document !== 'undefined') {
238 | module.exports = document;
239 | } else {
240 | var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
241 |
242 | if (!doccy) {
243 | doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
244 | }
245 |
246 | module.exports = doccy;
247 | }
248 |
249 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
250 | },{"min-document":35}],10:[function(_dereq_,module,exports){
251 | "use strict";
252 |
253 | module.exports = function isObject(x) {
254 | return typeof x === "object" && x !== null;
255 | };
256 |
257 | },{}],11:[function(_dereq_,module,exports){
258 | var nativeIsArray = Array.isArray
259 | var toString = Object.prototype.toString
260 |
261 | module.exports = nativeIsArray || isArray
262 |
263 | function isArray(obj) {
264 | return toString.call(obj) === "[object Array]"
265 | }
266 |
267 | },{}],12:[function(_dereq_,module,exports){
268 | var patch = _dereq_("./vdom/patch.js")
269 |
270 | module.exports = patch
271 |
272 | },{"./vdom/patch.js":17}],13:[function(_dereq_,module,exports){
273 | var isObject = _dereq_("is-object")
274 | var isHook = _dereq_("../vnode/is-vhook.js")
275 |
276 | module.exports = applyProperties
277 |
278 | function applyProperties(node, props, previous) {
279 | for (var propName in props) {
280 | var propValue = props[propName]
281 |
282 | if (propValue === undefined) {
283 | removeProperty(node, propName, propValue, previous);
284 | } else if (isHook(propValue)) {
285 | removeProperty(node, propName, propValue, previous)
286 | if (propValue.hook) {
287 | propValue.hook(node,
288 | propName,
289 | previous ? previous[propName] : undefined)
290 | }
291 | } else {
292 | if (isObject(propValue)) {
293 | patchObject(node, props, previous, propName, propValue);
294 | } else {
295 | node[propName] = propValue
296 | }
297 | }
298 | }
299 | }
300 |
301 | function removeProperty(node, propName, propValue, previous) {
302 | if (previous) {
303 | var previousValue = previous[propName]
304 |
305 | if (!isHook(previousValue)) {
306 | if (propName === "attributes") {
307 | for (var attrName in previousValue) {
308 | node.removeAttribute(attrName)
309 | }
310 | } else if (propName === "style") {
311 | for (var i in previousValue) {
312 | node.style[i] = ""
313 | }
314 | } else if (typeof previousValue === "string") {
315 | node[propName] = ""
316 | } else {
317 | node[propName] = null
318 | }
319 | } else if (previousValue.unhook) {
320 | previousValue.unhook(node, propName, propValue)
321 | }
322 | }
323 | }
324 |
325 | function patchObject(node, props, previous, propName, propValue) {
326 | var previousValue = previous ? previous[propName] : undefined
327 |
328 | // Set attributes
329 | if (propName === "attributes") {
330 | for (var attrName in propValue) {
331 | var attrValue = propValue[attrName]
332 |
333 | if (attrValue === undefined) {
334 | node.removeAttribute(attrName)
335 | } else {
336 | node.setAttribute(attrName, attrValue)
337 | }
338 | }
339 |
340 | return
341 | }
342 |
343 | if(previousValue && isObject(previousValue) &&
344 | getPrototype(previousValue) !== getPrototype(propValue)) {
345 | node[propName] = propValue
346 | return
347 | }
348 |
349 | if (!isObject(node[propName])) {
350 | node[propName] = {}
351 | }
352 |
353 | var replacer = propName === "style" ? "" : undefined
354 |
355 | for (var k in propValue) {
356 | var value = propValue[k]
357 | node[propName][k] = (value === undefined) ? replacer : value
358 | }
359 | }
360 |
361 | function getPrototype(value) {
362 | if (Object.getPrototypeOf) {
363 | return Object.getPrototypeOf(value)
364 | } else if (value.__proto__) {
365 | return value.__proto__
366 | } else if (value.constructor) {
367 | return value.constructor.prototype
368 | }
369 | }
370 |
371 | },{"../vnode/is-vhook.js":25,"is-object":10}],14:[function(_dereq_,module,exports){
372 | var document = _dereq_("global/document")
373 |
374 | var applyProperties = _dereq_("./apply-properties")
375 |
376 | var isVNode = _dereq_("../vnode/is-vnode.js")
377 | var isVText = _dereq_("../vnode/is-vtext.js")
378 | var isWidget = _dereq_("../vnode/is-widget.js")
379 | var handleThunk = _dereq_("../vnode/handle-thunk.js")
380 |
381 | module.exports = createElement
382 |
383 | function createElement(vnode, opts) {
384 | var doc = opts ? opts.document || document : document
385 | var warn = opts ? opts.warn : null
386 |
387 | vnode = handleThunk(vnode).a
388 |
389 | if (isWidget(vnode)) {
390 | return vnode.init()
391 | } else if (isVText(vnode)) {
392 | return doc.createTextNode(vnode.text)
393 | } else if (!isVNode(vnode)) {
394 | if (warn) {
395 | warn("Item is not a valid virtual dom node", vnode)
396 | }
397 | return null
398 | }
399 |
400 | var node = (vnode.namespace === null) ?
401 | doc.createElement(vnode.tagName) :
402 | doc.createElementNS(vnode.namespace, vnode.tagName)
403 |
404 | var props = vnode.properties
405 | applyProperties(node, props)
406 |
407 | var children = vnode.children
408 |
409 | for (var i = 0; i < children.length; i++) {
410 | var childNode = createElement(children[i], opts)
411 | if (childNode) {
412 | node.appendChild(childNode)
413 | }
414 | }
415 |
416 | return node
417 | }
418 |
419 | },{"../vnode/handle-thunk.js":23,"../vnode/is-vnode.js":26,"../vnode/is-vtext.js":27,"../vnode/is-widget.js":28,"./apply-properties":13,"global/document":9}],15:[function(_dereq_,module,exports){
420 | // Maps a virtual DOM tree onto a real DOM tree in an efficient manner.
421 | // We don't want to read all of the DOM nodes in the tree so we use
422 | // the in-order tree indexing to eliminate recursion down certain branches.
423 | // We only recurse into a DOM node if we know that it contains a child of
424 | // interest.
425 |
426 | var noChild = {}
427 |
428 | module.exports = domIndex
429 |
430 | function domIndex(rootNode, tree, indices, nodes) {
431 | if (!indices || indices.length === 0) {
432 | return {}
433 | } else {
434 | indices.sort(ascending)
435 | return recurse(rootNode, tree, indices, nodes, 0)
436 | }
437 | }
438 |
439 | function recurse(rootNode, tree, indices, nodes, rootIndex) {
440 | nodes = nodes || {}
441 |
442 |
443 | if (rootNode) {
444 | if (indexInRange(indices, rootIndex, rootIndex)) {
445 | nodes[rootIndex] = rootNode
446 | }
447 |
448 | var vChildren = tree.children
449 |
450 | if (vChildren) {
451 |
452 | var childNodes = rootNode.childNodes
453 |
454 | for (var i = 0; i < tree.children.length; i++) {
455 | rootIndex += 1
456 |
457 | var vChild = vChildren[i] || noChild
458 | var nextIndex = rootIndex + (vChild.count || 0)
459 |
460 | // skip recursion down the tree if there are no nodes down here
461 | if (indexInRange(indices, rootIndex, nextIndex)) {
462 | recurse(childNodes[i], vChild, indices, nodes, rootIndex)
463 | }
464 |
465 | rootIndex = nextIndex
466 | }
467 | }
468 | }
469 |
470 | return nodes
471 | }
472 |
473 | // Binary search for an index in the interval [left, right]
474 | function indexInRange(indices, left, right) {
475 | if (indices.length === 0) {
476 | return false
477 | }
478 |
479 | var minIndex = 0
480 | var maxIndex = indices.length - 1
481 | var currentIndex
482 | var currentItem
483 |
484 | while (minIndex <= maxIndex) {
485 | currentIndex = ((maxIndex + minIndex) / 2) >> 0
486 | currentItem = indices[currentIndex]
487 |
488 | if (minIndex === maxIndex) {
489 | return currentItem >= left && currentItem <= right
490 | } else if (currentItem < left) {
491 | minIndex = currentIndex + 1
492 | } else if (currentItem > right) {
493 | maxIndex = currentIndex - 1
494 | } else {
495 | return true
496 | }
497 | }
498 |
499 | return false;
500 | }
501 |
502 | function ascending(a, b) {
503 | return a > b ? 1 : -1
504 | }
505 |
506 | },{}],16:[function(_dereq_,module,exports){
507 | var applyProperties = _dereq_("./apply-properties")
508 |
509 | var isWidget = _dereq_("../vnode/is-widget.js")
510 | var VPatch = _dereq_("../vnode/vpatch.js")
511 |
512 | var render = _dereq_("./create-element")
513 | var updateWidget = _dereq_("./update-widget")
514 |
515 | module.exports = applyPatch
516 |
517 | function applyPatch(vpatch, domNode, renderOptions) {
518 | var type = vpatch.type
519 | var vNode = vpatch.vNode
520 | var patch = vpatch.patch
521 |
522 | switch (type) {
523 | case VPatch.REMOVE:
524 | return removeNode(domNode, vNode)
525 | case VPatch.INSERT:
526 | return insertNode(domNode, patch, renderOptions)
527 | case VPatch.VTEXT:
528 | return stringPatch(domNode, vNode, patch, renderOptions)
529 | case VPatch.WIDGET:
530 | return widgetPatch(domNode, vNode, patch, renderOptions)
531 | case VPatch.VNODE:
532 | return vNodePatch(domNode, vNode, patch, renderOptions)
533 | case VPatch.ORDER:
534 | reorderChildren(domNode, patch)
535 | return domNode
536 | case VPatch.PROPS:
537 | applyProperties(domNode, patch, vNode.properties)
538 | return domNode
539 | case VPatch.THUNK:
540 | return replaceRoot(domNode,
541 | renderOptions.patch(domNode, patch, renderOptions))
542 | default:
543 | return domNode
544 | }
545 | }
546 |
547 | function removeNode(domNode, vNode) {
548 | var parentNode = domNode.parentNode
549 |
550 | if (parentNode) {
551 | parentNode.removeChild(domNode)
552 | }
553 |
554 | destroyWidget(domNode, vNode);
555 |
556 | return null
557 | }
558 |
559 | function insertNode(parentNode, vNode, renderOptions) {
560 | var newNode = render(vNode, renderOptions)
561 |
562 | if (parentNode) {
563 | parentNode.appendChild(newNode)
564 | }
565 |
566 | return parentNode
567 | }
568 |
569 | function stringPatch(domNode, leftVNode, vText, renderOptions) {
570 | var newNode
571 |
572 | if (domNode.nodeType === 3) {
573 | domNode.replaceData(0, domNode.length, vText.text)
574 | newNode = domNode
575 | } else {
576 | var parentNode = domNode.parentNode
577 | newNode = render(vText, renderOptions)
578 |
579 | if (parentNode) {
580 | parentNode.replaceChild(newNode, domNode)
581 | }
582 | }
583 |
584 | return newNode
585 | }
586 |
587 | function widgetPatch(domNode, leftVNode, widget, renderOptions) {
588 | var updating = updateWidget(leftVNode, widget)
589 | var newNode
590 |
591 | if (updating) {
592 | newNode = widget.update(leftVNode, domNode) || domNode
593 | } else {
594 | newNode = render(widget, renderOptions)
595 | }
596 |
597 | var parentNode = domNode.parentNode
598 |
599 | if (parentNode && newNode !== domNode) {
600 | parentNode.replaceChild(newNode, domNode)
601 | }
602 |
603 | if (!updating) {
604 | destroyWidget(domNode, leftVNode)
605 | }
606 |
607 | return newNode
608 | }
609 |
610 | function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
611 | var parentNode = domNode.parentNode
612 | var newNode = render(vNode, renderOptions)
613 |
614 | if (parentNode) {
615 | parentNode.replaceChild(newNode, domNode)
616 | }
617 |
618 | return newNode
619 | }
620 |
621 | function destroyWidget(domNode, w) {
622 | if (typeof w.destroy === "function" && isWidget(w)) {
623 | w.destroy(domNode)
624 | }
625 | }
626 |
627 | function reorderChildren(domNode, bIndex) {
628 | var children = []
629 | var childNodes = domNode.childNodes
630 | var len = childNodes.length
631 | var i
632 | var reverseIndex = bIndex.reverse
633 |
634 | for (i = 0; i < len; i++) {
635 | children.push(domNode.childNodes[i])
636 | }
637 |
638 | var insertOffset = 0
639 | var move
640 | var node
641 | var insertNode
642 | var chainLength
643 | var insertedLength
644 | var nextSibling
645 | for (i = 0; i < len;) {
646 | move = bIndex[i]
647 | chainLength = 1
648 | if (move !== undefined && move !== i) {
649 | // try to bring forward as long of a chain as possible
650 | while (bIndex[i + chainLength] === move + chainLength) {
651 | chainLength++;
652 | }
653 |
654 | // the element currently at this index will be moved later so increase the insert offset
655 | if (reverseIndex[i] > i + chainLength) {
656 | insertOffset++
657 | }
658 |
659 | node = children[move]
660 | insertNode = childNodes[i + insertOffset] || null
661 | insertedLength = 0
662 | while (node !== insertNode && insertedLength++ < chainLength) {
663 | domNode.insertBefore(node, insertNode);
664 | node = children[move + insertedLength];
665 | }
666 |
667 | // the moved element came from the front of the array so reduce the insert offset
668 | if (move + chainLength < i) {
669 | insertOffset--
670 | }
671 | }
672 |
673 | // element at this index is scheduled to be removed so increase insert offset
674 | if (i in bIndex.removes) {
675 | insertOffset++
676 | }
677 |
678 | i += chainLength
679 | }
680 | }
681 |
682 | function replaceRoot(oldRoot, newRoot) {
683 | if (oldRoot && newRoot && oldRoot !== newRoot && oldRoot.parentNode) {
684 | console.log(oldRoot)
685 | oldRoot.parentNode.replaceChild(newRoot, oldRoot)
686 | }
687 |
688 | return newRoot;
689 | }
690 |
691 | },{"../vnode/is-widget.js":28,"../vnode/vpatch.js":31,"./apply-properties":13,"./create-element":14,"./update-widget":18}],17:[function(_dereq_,module,exports){
692 | var document = _dereq_("global/document")
693 | var isArray = _dereq_("x-is-array")
694 |
695 | var domIndex = _dereq_("./dom-index")
696 | var patchOp = _dereq_("./patch-op")
697 | module.exports = patch
698 |
699 | function patch(rootNode, patches) {
700 | return patchRecursive(rootNode, patches)
701 | }
702 |
703 | function patchRecursive(rootNode, patches, renderOptions) {
704 | var indices = patchIndices(patches)
705 |
706 | if (indices.length === 0) {
707 | return rootNode
708 | }
709 |
710 | var index = domIndex(rootNode, patches.a, indices)
711 | var ownerDocument = rootNode.ownerDocument
712 |
713 | if (!renderOptions) {
714 | renderOptions = { patch: patchRecursive }
715 | if (ownerDocument !== document) {
716 | renderOptions.document = ownerDocument
717 | }
718 | }
719 |
720 | for (var i = 0; i < indices.length; i++) {
721 | var nodeIndex = indices[i]
722 | rootNode = applyPatch(rootNode,
723 | index[nodeIndex],
724 | patches[nodeIndex],
725 | renderOptions)
726 | }
727 |
728 | return rootNode
729 | }
730 |
731 | function applyPatch(rootNode, domNode, patchList, renderOptions) {
732 | if (!domNode) {
733 | return rootNode
734 | }
735 |
736 | var newNode
737 |
738 | if (isArray(patchList)) {
739 | for (var i = 0; i < patchList.length; i++) {
740 | newNode = patchOp(patchList[i], domNode, renderOptions)
741 |
742 | if (domNode === rootNode) {
743 | rootNode = newNode
744 | }
745 | }
746 | } else {
747 | newNode = patchOp(patchList, domNode, renderOptions)
748 |
749 | if (domNode === rootNode) {
750 | rootNode = newNode
751 | }
752 | }
753 |
754 | return rootNode
755 | }
756 |
757 | function patchIndices(patches) {
758 | var indices = []
759 |
760 | for (var key in patches) {
761 | if (key !== "a") {
762 | indices.push(Number(key))
763 | }
764 | }
765 |
766 | return indices
767 | }
768 |
769 | },{"./dom-index":15,"./patch-op":16,"global/document":9,"x-is-array":11}],18:[function(_dereq_,module,exports){
770 | var isWidget = _dereq_("../vnode/is-widget.js")
771 |
772 | module.exports = updateWidget
773 |
774 | function updateWidget(a, b) {
775 | if (isWidget(a) && isWidget(b)) {
776 | if ("name" in a && "name" in b) {
777 | return a.id === b.id
778 | } else {
779 | return a.init === b.init
780 | }
781 | }
782 |
783 | return false
784 | }
785 |
786 | },{"../vnode/is-widget.js":28}],19:[function(_dereq_,module,exports){
787 | 'use strict';
788 |
789 | var EvStore = _dereq_('ev-store');
790 |
791 | module.exports = EvHook;
792 |
793 | function EvHook(value) {
794 | if (!(this instanceof EvHook)) {
795 | return new EvHook(value);
796 | }
797 |
798 | this.value = value;
799 | }
800 |
801 | EvHook.prototype.hook = function (node, propertyName) {
802 | var es = EvStore(node);
803 | var propName = propertyName.substr(3);
804 |
805 | es[propName] = this.value;
806 | };
807 |
808 | EvHook.prototype.unhook = function(node, propertyName) {
809 | var es = EvStore(node);
810 | var propName = propertyName.substr(3);
811 |
812 | es[propName] = undefined;
813 | };
814 |
815 | },{"ev-store":6}],20:[function(_dereq_,module,exports){
816 | 'use strict';
817 |
818 | module.exports = SoftSetHook;
819 |
820 | function SoftSetHook(value) {
821 | if (!(this instanceof SoftSetHook)) {
822 | return new SoftSetHook(value);
823 | }
824 |
825 | this.value = value;
826 | }
827 |
828 | SoftSetHook.prototype.hook = function (node, propertyName) {
829 | if (node[propertyName] !== this.value) {
830 | node[propertyName] = this.value;
831 | }
832 | };
833 |
834 | },{}],21:[function(_dereq_,module,exports){
835 | 'use strict';
836 |
837 | var isArray = _dereq_('x-is-array');
838 |
839 | var VNode = _dereq_('../vnode/vnode.js');
840 | var VText = _dereq_('../vnode/vtext.js');
841 | var isVNode = _dereq_('../vnode/is-vnode');
842 | var isVText = _dereq_('../vnode/is-vtext');
843 | var isWidget = _dereq_('../vnode/is-widget');
844 | var isHook = _dereq_('../vnode/is-vhook');
845 | var isVThunk = _dereq_('../vnode/is-thunk');
846 |
847 | var parseTag = _dereq_('./parse-tag.js');
848 | var softSetHook = _dereq_('./hooks/soft-set-hook.js');
849 | var evHook = _dereq_('./hooks/ev-hook.js');
850 |
851 | module.exports = h;
852 |
853 | function h(tagName, properties, children) {
854 | var childNodes = [];
855 | var tag, props, key, namespace;
856 |
857 | if (!children && isChildren(properties)) {
858 | children = properties;
859 | props = {};
860 | }
861 |
862 | props = props || properties || {};
863 | tag = parseTag(tagName, props);
864 |
865 | // support keys
866 | if (props.hasOwnProperty('key')) {
867 | key = props.key;
868 | props.key = undefined;
869 | }
870 |
871 | // support namespace
872 | if (props.hasOwnProperty('namespace')) {
873 | namespace = props.namespace;
874 | props.namespace = undefined;
875 | }
876 |
877 | // fix cursor bug
878 | if (tag === 'INPUT' &&
879 | !namespace &&
880 | props.hasOwnProperty('value') &&
881 | props.value !== undefined &&
882 | !isHook(props.value)
883 | ) {
884 | props.value = softSetHook(props.value);
885 | }
886 |
887 | transformProperties(props);
888 |
889 | if (children !== undefined && children !== null) {
890 | addChild(children, childNodes, tag, props);
891 | }
892 |
893 |
894 | return new VNode(tag, props, childNodes, key, namespace);
895 | }
896 |
897 | function addChild(c, childNodes, tag, props) {
898 | if (typeof c === 'string') {
899 | childNodes.push(new VText(c));
900 | } else if (isChild(c)) {
901 | childNodes.push(c);
902 | } else if (isArray(c)) {
903 | for (var i = 0; i < c.length; i++) {
904 | addChild(c[i], childNodes, tag, props);
905 | }
906 | } else if (c === null || c === undefined) {
907 | return;
908 | } else {
909 | throw UnexpectedVirtualElement({
910 | foreignObject: c,
911 | parentVnode: {
912 | tagName: tag,
913 | properties: props
914 | }
915 | });
916 | }
917 | }
918 |
919 | function transformProperties(props) {
920 | for (var propName in props) {
921 | if (props.hasOwnProperty(propName)) {
922 | var value = props[propName];
923 |
924 | if (isHook(value)) {
925 | continue;
926 | }
927 |
928 | if (propName.substr(0, 3) === 'ev-') {
929 | // add ev-foo support
930 | props[propName] = evHook(value);
931 | }
932 | }
933 | }
934 | }
935 |
936 | function isChild(x) {
937 | return isVNode(x) || isVText(x) || isWidget(x) || isVThunk(x);
938 | }
939 |
940 | function isChildren(x) {
941 | return typeof x === 'string' || isArray(x) || isChild(x);
942 | }
943 |
944 | function UnexpectedVirtualElement(data) {
945 | var err = new Error();
946 |
947 | err.type = 'virtual-hyperscript.unexpected.virtual-element';
948 | err.message = 'Unexpected virtual child passed to h().\n' +
949 | 'Expected a VNode / Vthunk / VWidget / string but:\n' +
950 | 'got:\n' +
951 | errorString(data.foreignObject) +
952 | '.\n' +
953 | 'The parent vnode is:\n' +
954 | errorString(data.parentVnode)
955 | '\n' +
956 | 'Suggested fix: change your `h(..., [ ... ])` callsite.';
957 | err.foreignObject = data.foreignObject;
958 | err.parentVnode = data.parentVnode;
959 |
960 | return err;
961 | }
962 |
963 | function errorString(obj) {
964 | try {
965 | return JSON.stringify(obj, null, ' ');
966 | } catch (e) {
967 | return String(obj);
968 | }
969 | }
970 |
971 | },{"../vnode/is-thunk":24,"../vnode/is-vhook":25,"../vnode/is-vnode":26,"../vnode/is-vtext":27,"../vnode/is-widget":28,"../vnode/vnode.js":30,"../vnode/vtext.js":32,"./hooks/ev-hook.js":19,"./hooks/soft-set-hook.js":20,"./parse-tag.js":22,"x-is-array":11}],22:[function(_dereq_,module,exports){
972 | 'use strict';
973 |
974 | var split = _dereq_('browser-split');
975 |
976 | var classIdSplit = /([\.#]?[a-zA-Z0-9_:-]+)/;
977 | var notClassId = /^\.|#/;
978 |
979 | module.exports = parseTag;
980 |
981 | function parseTag(tag, props) {
982 | if (!tag) {
983 | return 'DIV';
984 | }
985 |
986 | var noId = !(props.hasOwnProperty('id'));
987 |
988 | var tagParts = split(tag, classIdSplit);
989 | var tagName = null;
990 |
991 | if (notClassId.test(tagParts[1])) {
992 | tagName = 'DIV';
993 | }
994 |
995 | var classes, part, type, i;
996 |
997 | for (i = 0; i < tagParts.length; i++) {
998 | part = tagParts[i];
999 |
1000 | if (!part) {
1001 | continue;
1002 | }
1003 |
1004 | type = part.charAt(0);
1005 |
1006 | if (!tagName) {
1007 | tagName = part;
1008 | } else if (type === '.') {
1009 | classes = classes || [];
1010 | classes.push(part.substring(1, part.length));
1011 | } else if (type === '#' && noId) {
1012 | props.id = part.substring(1, part.length);
1013 | }
1014 | }
1015 |
1016 | if (classes) {
1017 | if (props.className) {
1018 | classes.push(props.className);
1019 | }
1020 |
1021 | props.className = classes.join(' ');
1022 | }
1023 |
1024 | return props.namespace ? tagName : tagName.toUpperCase();
1025 | }
1026 |
1027 | },{"browser-split":5}],23:[function(_dereq_,module,exports){
1028 | var isVNode = _dereq_("./is-vnode")
1029 | var isVText = _dereq_("./is-vtext")
1030 | var isWidget = _dereq_("./is-widget")
1031 | var isThunk = _dereq_("./is-thunk")
1032 |
1033 | module.exports = handleThunk
1034 |
1035 | function handleThunk(a, b) {
1036 | var renderedA = a
1037 | var renderedB = b
1038 |
1039 | if (isThunk(b)) {
1040 | renderedB = renderThunk(b, a)
1041 | }
1042 |
1043 | if (isThunk(a)) {
1044 | renderedA = renderThunk(a, null)
1045 | }
1046 |
1047 | return {
1048 | a: renderedA,
1049 | b: renderedB
1050 | }
1051 | }
1052 |
1053 | function renderThunk(thunk, previous) {
1054 | var renderedThunk = thunk.vnode
1055 |
1056 | if (!renderedThunk) {
1057 | renderedThunk = thunk.vnode = thunk.render(previous)
1058 | }
1059 |
1060 | if (!(isVNode(renderedThunk) ||
1061 | isVText(renderedThunk) ||
1062 | isWidget(renderedThunk))) {
1063 | throw new Error("thunk did not return a valid node");
1064 | }
1065 |
1066 | return renderedThunk
1067 | }
1068 |
1069 | },{"./is-thunk":24,"./is-vnode":26,"./is-vtext":27,"./is-widget":28}],24:[function(_dereq_,module,exports){
1070 | module.exports = isThunk
1071 |
1072 | function isThunk(t) {
1073 | return t && t.type === "Thunk"
1074 | }
1075 |
1076 | },{}],25:[function(_dereq_,module,exports){
1077 | module.exports = isHook
1078 |
1079 | function isHook(hook) {
1080 | return hook &&
1081 | (typeof hook.hook === "function" && !hook.hasOwnProperty("hook") ||
1082 | typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook"))
1083 | }
1084 |
1085 | },{}],26:[function(_dereq_,module,exports){
1086 | var version = _dereq_("./version")
1087 |
1088 | module.exports = isVirtualNode
1089 |
1090 | function isVirtualNode(x) {
1091 | return x && x.type === "VirtualNode" && x.version === version
1092 | }
1093 |
1094 | },{"./version":29}],27:[function(_dereq_,module,exports){
1095 | var version = _dereq_("./version")
1096 |
1097 | module.exports = isVirtualText
1098 |
1099 | function isVirtualText(x) {
1100 | return x && x.type === "VirtualText" && x.version === version
1101 | }
1102 |
1103 | },{"./version":29}],28:[function(_dereq_,module,exports){
1104 | module.exports = isWidget
1105 |
1106 | function isWidget(w) {
1107 | return w && w.type === "Widget"
1108 | }
1109 |
1110 | },{}],29:[function(_dereq_,module,exports){
1111 | module.exports = "1"
1112 |
1113 | },{}],30:[function(_dereq_,module,exports){
1114 | var version = _dereq_("./version")
1115 | var isVNode = _dereq_("./is-vnode")
1116 | var isWidget = _dereq_("./is-widget")
1117 | var isThunk = _dereq_("./is-thunk")
1118 | var isVHook = _dereq_("./is-vhook")
1119 |
1120 | module.exports = VirtualNode
1121 |
1122 | var noProperties = {}
1123 | var noChildren = []
1124 |
1125 | function VirtualNode(tagName, properties, children, key, namespace) {
1126 | this.tagName = tagName
1127 | this.properties = properties || noProperties
1128 | this.children = children || noChildren
1129 | this.key = key != null ? String(key) : undefined
1130 | this.namespace = (typeof namespace === "string") ? namespace : null
1131 |
1132 | var count = (children && children.length) || 0
1133 | var descendants = 0
1134 | var hasWidgets = false
1135 | var hasThunks = false
1136 | var descendantHooks = false
1137 | var hooks
1138 |
1139 | for (var propName in properties) {
1140 | if (properties.hasOwnProperty(propName)) {
1141 | var property = properties[propName]
1142 | if (isVHook(property) && property.unhook) {
1143 | if (!hooks) {
1144 | hooks = {}
1145 | }
1146 |
1147 | hooks[propName] = property
1148 | }
1149 | }
1150 | }
1151 |
1152 | for (var i = 0; i < count; i++) {
1153 | var child = children[i]
1154 | if (isVNode(child)) {
1155 | descendants += child.count || 0
1156 |
1157 | if (!hasWidgets && child.hasWidgets) {
1158 | hasWidgets = true
1159 | }
1160 |
1161 | if (!hasThunks && child.hasThunks) {
1162 | hasThunks = true
1163 | }
1164 |
1165 | if (!descendantHooks && (child.hooks || child.descendantHooks)) {
1166 | descendantHooks = true
1167 | }
1168 | } else if (!hasWidgets && isWidget(child)) {
1169 | if (typeof child.destroy === "function") {
1170 | hasWidgets = true
1171 | }
1172 | } else if (!hasThunks && isThunk(child)) {
1173 | hasThunks = true;
1174 | }
1175 | }
1176 |
1177 | this.count = count + descendants
1178 | this.hasWidgets = hasWidgets
1179 | this.hasThunks = hasThunks
1180 | this.hooks = hooks
1181 | this.descendantHooks = descendantHooks
1182 | }
1183 |
1184 | VirtualNode.prototype.version = version
1185 | VirtualNode.prototype.type = "VirtualNode"
1186 |
1187 | },{"./is-thunk":24,"./is-vhook":25,"./is-vnode":26,"./is-widget":28,"./version":29}],31:[function(_dereq_,module,exports){
1188 | var version = _dereq_("./version")
1189 |
1190 | VirtualPatch.NONE = 0
1191 | VirtualPatch.VTEXT = 1
1192 | VirtualPatch.VNODE = 2
1193 | VirtualPatch.WIDGET = 3
1194 | VirtualPatch.PROPS = 4
1195 | VirtualPatch.ORDER = 5
1196 | VirtualPatch.INSERT = 6
1197 | VirtualPatch.REMOVE = 7
1198 | VirtualPatch.THUNK = 8
1199 |
1200 | module.exports = VirtualPatch
1201 |
1202 | function VirtualPatch(type, vNode, patch) {
1203 | this.type = Number(type)
1204 | this.vNode = vNode
1205 | this.patch = patch
1206 | }
1207 |
1208 | VirtualPatch.prototype.version = version
1209 | VirtualPatch.prototype.type = "VirtualPatch"
1210 |
1211 | },{"./version":29}],32:[function(_dereq_,module,exports){
1212 | var version = _dereq_("./version")
1213 |
1214 | module.exports = VirtualText
1215 |
1216 | function VirtualText(text) {
1217 | this.text = String(text)
1218 | }
1219 |
1220 | VirtualText.prototype.version = version
1221 | VirtualText.prototype.type = "VirtualText"
1222 |
1223 | },{"./version":29}],33:[function(_dereq_,module,exports){
1224 | var isObject = _dereq_("is-object")
1225 | var isHook = _dereq_("../vnode/is-vhook")
1226 |
1227 | module.exports = diffProps
1228 |
1229 | function diffProps(a, b) {
1230 | var diff
1231 |
1232 | for (var aKey in a) {
1233 | if (!(aKey in b)) {
1234 | diff = diff || {}
1235 | diff[aKey] = undefined
1236 | }
1237 |
1238 | var aValue = a[aKey]
1239 | var bValue = b[aKey]
1240 |
1241 | if (aValue === bValue) {
1242 | continue
1243 | } else if (isObject(aValue) && isObject(bValue)) {
1244 | if (getPrototype(bValue) !== getPrototype(aValue)) {
1245 | diff = diff || {}
1246 | diff[aKey] = bValue
1247 | } else if (isHook(bValue)) {
1248 | diff = diff || {}
1249 | diff[aKey] = bValue
1250 | } else {
1251 | var objectDiff = diffProps(aValue, bValue)
1252 | if (objectDiff) {
1253 | diff = diff || {}
1254 | diff[aKey] = objectDiff
1255 | }
1256 | }
1257 | } else {
1258 | diff = diff || {}
1259 | diff[aKey] = bValue
1260 | }
1261 | }
1262 |
1263 | for (var bKey in b) {
1264 | if (!(bKey in a)) {
1265 | diff = diff || {}
1266 | diff[bKey] = b[bKey]
1267 | }
1268 | }
1269 |
1270 | return diff
1271 | }
1272 |
1273 | function getPrototype(value) {
1274 | if (Object.getPrototypeOf) {
1275 | return Object.getPrototypeOf(value)
1276 | } else if (value.__proto__) {
1277 | return value.__proto__
1278 | } else if (value.constructor) {
1279 | return value.constructor.prototype
1280 | }
1281 | }
1282 |
1283 | },{"../vnode/is-vhook":25,"is-object":10}],34:[function(_dereq_,module,exports){
1284 | var isArray = _dereq_("x-is-array")
1285 |
1286 | var VPatch = _dereq_("../vnode/vpatch")
1287 | var isVNode = _dereq_("../vnode/is-vnode")
1288 | var isVText = _dereq_("../vnode/is-vtext")
1289 | var isWidget = _dereq_("../vnode/is-widget")
1290 | var isThunk = _dereq_("../vnode/is-thunk")
1291 | var handleThunk = _dereq_("../vnode/handle-thunk")
1292 |
1293 | var diffProps = _dereq_("./diff-props")
1294 |
1295 | module.exports = diff
1296 |
1297 | function diff(a, b) {
1298 | var patch = { a: a }
1299 | walk(a, b, patch, 0)
1300 | return patch
1301 | }
1302 |
1303 | function walk(a, b, patch, index) {
1304 | if (a === b) {
1305 | return
1306 | }
1307 |
1308 | var apply = patch[index]
1309 | var applyClear = false
1310 |
1311 | if (isThunk(a) || isThunk(b)) {
1312 | thunks(a, b, patch, index)
1313 | } else if (b == null) {
1314 |
1315 | // If a is a widget we will add a remove patch for it
1316 | // Otherwise any child widgets/hooks must be destroyed.
1317 | // This prevents adding two remove patches for a widget.
1318 | if (!isWidget(a)) {
1319 | clearState(a, patch, index)
1320 | apply = patch[index]
1321 | }
1322 |
1323 | apply = appendPatch(apply, new VPatch(VPatch.REMOVE, a, b))
1324 | } else if (isVNode(b)) {
1325 | if (isVNode(a)) {
1326 | if (a.tagName === b.tagName &&
1327 | a.namespace === b.namespace &&
1328 | a.key === b.key) {
1329 | var propsPatch = diffProps(a.properties, b.properties)
1330 | if (propsPatch) {
1331 | apply = appendPatch(apply,
1332 | new VPatch(VPatch.PROPS, a, propsPatch))
1333 | }
1334 | apply = diffChildren(a, b, patch, apply, index)
1335 | } else {
1336 | apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b))
1337 | applyClear = true
1338 | }
1339 | } else {
1340 | apply = appendPatch(apply, new VPatch(VPatch.VNODE, a, b))
1341 | applyClear = true
1342 | }
1343 | } else if (isVText(b)) {
1344 | if (!isVText(a)) {
1345 | apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b))
1346 | applyClear = true
1347 | } else if (a.text !== b.text) {
1348 | apply = appendPatch(apply, new VPatch(VPatch.VTEXT, a, b))
1349 | }
1350 | } else if (isWidget(b)) {
1351 | if (!isWidget(a)) {
1352 | applyClear = true;
1353 | }
1354 |
1355 | apply = appendPatch(apply, new VPatch(VPatch.WIDGET, a, b))
1356 | }
1357 |
1358 | if (apply) {
1359 | patch[index] = apply
1360 | }
1361 |
1362 | if (applyClear) {
1363 | clearState(a, patch, index)
1364 | }
1365 | }
1366 |
1367 | function diffChildren(a, b, patch, apply, index) {
1368 | var aChildren = a.children
1369 | var bChildren = reorder(aChildren, b.children)
1370 |
1371 | var aLen = aChildren.length
1372 | var bLen = bChildren.length
1373 | var len = aLen > bLen ? aLen : bLen
1374 |
1375 | for (var i = 0; i < len; i++) {
1376 | var leftNode = aChildren[i]
1377 | var rightNode = bChildren[i]
1378 | index += 1
1379 |
1380 | if (!leftNode) {
1381 | if (rightNode) {
1382 | // Excess nodes in b need to be added
1383 | apply = appendPatch(apply,
1384 | new VPatch(VPatch.INSERT, null, rightNode))
1385 | }
1386 | } else {
1387 | walk(leftNode, rightNode, patch, index)
1388 | }
1389 |
1390 | if (isVNode(leftNode) && leftNode.count) {
1391 | index += leftNode.count
1392 | }
1393 | }
1394 |
1395 | if (bChildren.moves) {
1396 | // Reorder nodes last
1397 | apply = appendPatch(apply, new VPatch(VPatch.ORDER, a, bChildren.moves))
1398 | }
1399 |
1400 | return apply
1401 | }
1402 |
1403 | function clearState(vNode, patch, index) {
1404 | // TODO: Make this a single walk, not two
1405 | unhook(vNode, patch, index)
1406 | destroyWidgets(vNode, patch, index)
1407 | }
1408 |
1409 | // Patch records for all destroyed widgets must be added because we need
1410 | // a DOM node reference for the destroy function
1411 | function destroyWidgets(vNode, patch, index) {
1412 | if (isWidget(vNode)) {
1413 | if (typeof vNode.destroy === "function") {
1414 | patch[index] = appendPatch(
1415 | patch[index],
1416 | new VPatch(VPatch.REMOVE, vNode, null)
1417 | )
1418 | }
1419 | } else if (isVNode(vNode) && (vNode.hasWidgets || vNode.hasThunks)) {
1420 | var children = vNode.children
1421 | var len = children.length
1422 | for (var i = 0; i < len; i++) {
1423 | var child = children[i]
1424 | index += 1
1425 |
1426 | destroyWidgets(child, patch, index)
1427 |
1428 | if (isVNode(child) && child.count) {
1429 | index += child.count
1430 | }
1431 | }
1432 | } else if (isThunk(vNode)) {
1433 | thunks(vNode, null, patch, index)
1434 | }
1435 | }
1436 |
1437 | // Create a sub-patch for thunks
1438 | function thunks(a, b, patch, index) {
1439 | var nodes = handleThunk(a, b);
1440 | var thunkPatch = diff(nodes.a, nodes.b)
1441 | if (hasPatches(thunkPatch)) {
1442 | patch[index] = new VPatch(VPatch.THUNK, null, thunkPatch)
1443 | }
1444 | }
1445 |
1446 | function hasPatches(patch) {
1447 | for (var index in patch) {
1448 | if (index !== "a") {
1449 | return true;
1450 | }
1451 | }
1452 |
1453 | return false;
1454 | }
1455 |
1456 | // Execute hooks when two nodes are identical
1457 | function unhook(vNode, patch, index) {
1458 | if (isVNode(vNode)) {
1459 | if (vNode.hooks) {
1460 | patch[index] = appendPatch(
1461 | patch[index],
1462 | new VPatch(
1463 | VPatch.PROPS,
1464 | vNode,
1465 | undefinedKeys(vNode.hooks)
1466 | )
1467 | )
1468 | }
1469 |
1470 | if (vNode.descendantHooks || vNode.hasThunks) {
1471 | var children = vNode.children
1472 | var len = children.length
1473 | for (var i = 0; i < len; i++) {
1474 | var child = children[i]
1475 | index += 1
1476 |
1477 | unhook(child, patch, index)
1478 |
1479 | if (isVNode(child) && child.count) {
1480 | index += child.count
1481 | }
1482 | }
1483 | }
1484 | } else if (isThunk(vNode)) {
1485 | thunks(vNode, null, patch, index)
1486 | }
1487 | }
1488 |
1489 | function undefinedKeys(obj) {
1490 | var result = {}
1491 |
1492 | for (var key in obj) {
1493 | result[key] = undefined
1494 | }
1495 |
1496 | return result
1497 | }
1498 |
1499 | // List diff, naive left to right reordering
1500 | function reorder(aChildren, bChildren) {
1501 |
1502 | var bKeys = keyIndex(bChildren)
1503 |
1504 | if (!bKeys) {
1505 | return bChildren
1506 | }
1507 |
1508 | var aKeys = keyIndex(aChildren)
1509 |
1510 | if (!aKeys) {
1511 | return bChildren
1512 | }
1513 |
1514 | var bMatch = {}, aMatch = {}
1515 |
1516 | for (var aKey in bKeys) {
1517 | bMatch[bKeys[aKey]] = aKeys[aKey]
1518 | }
1519 |
1520 | for (var bKey in aKeys) {
1521 | aMatch[aKeys[bKey]] = bKeys[bKey]
1522 | }
1523 |
1524 | var aLen = aChildren.length
1525 | var bLen = bChildren.length
1526 | var len = aLen > bLen ? aLen : bLen
1527 | var shuffle = []
1528 | var freeIndex = 0
1529 | var i = 0
1530 | var moveIndex = 0
1531 | var moves = {}
1532 | var removes = moves.removes = {}
1533 | var reverse = moves.reverse = {}
1534 | var hasMoves = false
1535 |
1536 | while (freeIndex < len) {
1537 | var move = aMatch[i]
1538 | if (move !== undefined) {
1539 | shuffle[i] = bChildren[move]
1540 | if (move !== moveIndex) {
1541 | moves[move] = moveIndex
1542 | reverse[moveIndex] = move
1543 | hasMoves = true
1544 | }
1545 | moveIndex++
1546 | } else if (i in aMatch) {
1547 | shuffle[i] = undefined
1548 | removes[i] = moveIndex++
1549 | hasMoves = true
1550 | } else {
1551 | while (bMatch[freeIndex] !== undefined) {
1552 | freeIndex++
1553 | }
1554 |
1555 | if (freeIndex < len) {
1556 | var freeChild = bChildren[freeIndex]
1557 | if (freeChild) {
1558 | shuffle[i] = freeChild
1559 | if (freeIndex !== moveIndex) {
1560 | hasMoves = true
1561 | moves[freeIndex] = moveIndex
1562 | reverse[moveIndex] = freeIndex
1563 | }
1564 | moveIndex++
1565 | }
1566 | freeIndex++
1567 | }
1568 | }
1569 | i++
1570 | }
1571 |
1572 | if (hasMoves) {
1573 | shuffle.moves = moves
1574 | }
1575 |
1576 | return shuffle
1577 | }
1578 |
1579 | function keyIndex(children) {
1580 | var i, keys
1581 |
1582 | for (i = 0; i < children.length; i++) {
1583 | var child = children[i]
1584 |
1585 | if (child.key !== undefined) {
1586 | keys = keys || {}
1587 | keys[child.key] = i
1588 | }
1589 | }
1590 |
1591 | return keys
1592 | }
1593 |
1594 | function appendPatch(apply, patch) {
1595 | if (apply) {
1596 | if (isArray(apply)) {
1597 | apply.push(patch)
1598 | } else {
1599 | apply = [apply, patch]
1600 | }
1601 |
1602 | return apply
1603 | } else {
1604 | return patch
1605 | }
1606 | }
1607 |
1608 | },{"../vnode/handle-thunk":23,"../vnode/is-thunk":24,"../vnode/is-vnode":26,"../vnode/is-vtext":27,"../vnode/is-widget":28,"../vnode/vpatch":31,"./diff-props":33,"x-is-array":11}],35:[function(_dereq_,module,exports){
1609 |
1610 | },{}]},{},[4])(4)
1611 | });
1612 |
1613 | angular.module('teropa.virtualDom.getAttribute', [])
1614 | .factory('getVDomAttribute', function() {
1615 | 'use strict';
1616 | return function getVDomAttribute(node, name) {
1617 | if (node.properties && node.properties.attributes) {
1618 | return node.properties.attributes[name];
1619 | }
1620 | };
1621 | });
1622 |
1623 | angular.module('teropa.virtualDom.directiveNormalize', [])
1624 | .factory('directiveNormalize', function() {
1625 | var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
1626 | var MOZ_HACK_REGEXP = /^moz([A-Z])/;
1627 | var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
1628 |
1629 | function camelCase(name) {
1630 | return name.
1631 | replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
1632 | return offset ? letter.toUpperCase() : letter;
1633 | }).
1634 | replace(MOZ_HACK_REGEXP, 'Moz$1');
1635 | }
1636 |
1637 | return function directiveNormalize(name) {
1638 | return camelCase(name.replace(PREFIX_REGEXP, ''));
1639 | }
1640 | });
1641 |
1642 | angular.module('teropa.virtualDom.cloneTree', [])
1643 | .factory('cloneVDomTree', function() {
1644 | 'use strict';
1645 | return function cloneTree(tree) {
1646 | if (virtualDom.isVNode(tree)) {
1647 | return new virtualDom.VNode(
1648 | tree.tagName,
1649 | angular.copy(tree.properties),
1650 | tree.children.map(cloneTree)
1651 | );
1652 | } else if (virtualDom.isVText(tree)) {
1653 | return new virtualDom.VText(tree.text);
1654 | }
1655 | };
1656 | });
1657 |
1658 | angular.module('teropa.virtualDom.virtualize', [])
1659 | .factory('virtualizeDom', function() {
1660 | 'use strict';
1661 |
1662 | function virtualizeTextNode(node) {
1663 | return new virtualDom.VText(node.nodeValue);
1664 | }
1665 |
1666 | function virtualizeProperties(node) {
1667 | var attrs = {};
1668 | Array.prototype.forEach.call(node.attributes, function(attr) {
1669 | attrs[attr.name] = attr.value;
1670 | });
1671 | return {attributes: attrs};
1672 | }
1673 |
1674 | function virtualizeChildren(node) {
1675 | var children = [];
1676 | Array.prototype.forEach.call(node.childNodes, function(childNode) {
1677 | var childTree = virtualizeTree(childNode);
1678 | if (childTree) {
1679 | children.push(childTree);
1680 | }
1681 | });
1682 | return children;
1683 | }
1684 |
1685 | function virtualizeElementNode(node) {
1686 | return new virtualDom.VNode(
1687 | node.tagName.toLowerCase(),
1688 | virtualizeProperties(node),
1689 | virtualizeChildren(node)
1690 | );
1691 | }
1692 |
1693 | function virtualizeTree(node) {
1694 | if (node.nodeType === Node.TEXT_NODE) {
1695 | return virtualizeTextNode(node);
1696 | } else if (node.nodeType === Node.ELEMENT_NODE) {
1697 | return virtualizeElementNode(node);
1698 | }
1699 | }
1700 |
1701 | return virtualizeTree;
1702 |
1703 | });
1704 |
1705 | angular.module('teropa.virtualDom.link', ['teropa.virtualDom.cloneTree', 'teropa.virtualDom.directiveNormalize'])
1706 | .factory('linkVDom', ['$injector', '$interpolate', 'directiveNormalize', 'cloneVDomTree', function($injector, $interpolate, directiveNormalize, cloneVDomTree) {
1707 | 'use strict';
1708 |
1709 | function byPriority(a, b) {
1710 | var diff = b.priority - a.priority;
1711 | if (diff !== 0) {
1712 | return diff;
1713 | }
1714 | if (a.name !== b.name) {
1715 | return (a.name < b.name) ? -1 : 1;
1716 | }
1717 | return a.index - b.index;
1718 | }
1719 |
1720 | function getDirectives(node) {
1721 | var dirs = [];
1722 | if (node.properties && node.properties.attributes) {
1723 | Object.keys(node.properties.attributes).forEach(function(attrName) {
1724 | var dName = directiveNormalize(attrName) + 'Directive';
1725 | if ($injector.has(dName)) {
1726 | dirs.push.apply(dirs, $injector.get(dName));
1727 | }
1728 | });
1729 | }
1730 | return dirs.sort(byPriority);
1731 | }
1732 |
1733 | function linkVisit(node, scope) {
1734 | node.$scope = scope;
1735 | var linkedNodes;
1736 | if (virtualDom.isVNode(node)) {
1737 | var directives = getDirectives(node);
1738 | linkedNodes = directives.reduce(function(nodes, directive) {
1739 | var nextNodes = [];
1740 | nodes.forEach(function(node) {
1741 | var linked = node;
1742 | if (directive.linkVirtual) {
1743 | linked = directive.linkVirtual(node);
1744 | }
1745 | if (Array.isArray(linked)) {
1746 | nextNodes.push.apply(nextNodes, linked);
1747 | } else if (!linked) {
1748 | nextNodes.push(node);
1749 | } else {
1750 | nextNodes.push(linked);
1751 | }
1752 | });
1753 | return nextNodes;
1754 | }, [node]);
1755 |
1756 | linkedNodes.forEach(function(node) {
1757 | if (node.properties && node.properties.attributes) {
1758 | Object.keys(node.properties.attributes).forEach(function(attrName) {
1759 | var interpolateFn = $interpolate(node.properties.attributes[attrName]);
1760 | if (interpolateFn) {
1761 | node.properties.attributes[attrName] = interpolateFn(node.$scope);
1762 | }
1763 | });
1764 | }
1765 |
1766 | var linkedChildren = [];
1767 | node.children.forEach(function(childNode) {
1768 | linkedChildren.push.apply(linkedChildren, linkVisit(childNode, node.$scope));
1769 | });
1770 | node.children = linkedChildren;
1771 | });
1772 | } else {
1773 | node.text = $interpolate(node.text)(node.$scope);
1774 | linkedNodes = [node];
1775 | }
1776 | return linkedNodes;
1777 | }
1778 |
1779 | return function linkVDom(tree, scope) {
1780 | var clone = cloneVDomTree(tree);
1781 | return linkVisit(clone, scope)[0];
1782 | };
1783 |
1784 | }]);
1785 |
1786 | angular.module('teropa.virtualDom.vIf', ['teropa.virtualDom.getAttribute'])
1787 | .directive('vIf', ['$parse', 'getVDomAttribute', function($parse, getVDomAttribute) {
1788 | 'use strict';
1789 | return {
1790 | restrict: 'A',
1791 | priority: 600,
1792 | linkVirtual: function(node) {
1793 | var expr = $parse(getVDomAttribute(node, 'v-if'));
1794 | if (expr(node.$scope)) {
1795 | return node;
1796 | } else {
1797 | return [];
1798 | }
1799 | }
1800 | };
1801 | }]);
1802 |
1803 | angular.module('teropa.virtualDom.vRepeat', ['teropa.virtualDom.getAttribute', 'teropa.virtualDom.cloneTree'])
1804 | .directive('vRepeat', ['$parse', 'getVDomAttribute', 'cloneVDomTree', function($parse, getVDomAttribute, cloneVDomTree) {
1805 | 'use strict';
1806 |
1807 | var iteratorSymbol = (typeof Symbol !== 'undefined') ? Symbol.iterator : "@@iterator";
1808 |
1809 | function nth(v, n) {
1810 | if (Array.isArray(v)) {
1811 | return v[n];
1812 | } else if (v[iteratorSymbol]) {
1813 | var iterator = v[iteratorSymbol]();
1814 | var i;
1815 | for (i=0 ; i
8 | * @link https://github.com/Matt-Esch/virtual-dom
9 | * @license MIT License, http://www.opensource.org/licenses/MIT
10 | */
11 | "undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="teropa.virtualDom"),function(a,b,c){!function(b){var c;"undefined"!=typeof a?c=a:"undefined"!=typeof global?c=global:"undefined"!=typeof self&&(c=self),c.virtualDom=b()}(function(){return function b(a,c,d){function e(g,h){if(!c[g]){if(!a[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};a[g][0].call(k.exports,function(b){var c=a[g][1][b];return e(c?c:b)},k,k.exports,b,a,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g>>0:f>>>0;(h=e.exec(b))&&(i=h.index+h[0].length,!(i>m&&(k.push(b.slice(m,h.index)),!d&&h.length>1&&h[0].replace(g,function(){for(var b=1;b1&&h.index=f)));)e.lastIndex===h.index&&e.lastIndex++;return m===b.length?(j||!e.test(""))&&k.push(""):k.push(b.slice(m)),k.length>f?k.slice(0,f):k}}()},{}],6:[function(a,b){"use strict";function c(a){var b=a[f];return b||(b=a[f]={}),b}var d=a("individual/one-version"),e="7";d("ev-store",e);var f="__EV_STORE_KEY@"+e;b.exports=c},{"individual/one-version":8}],7:[function(b,c){(function(b){"use strict";function d(a,b){return a in e?e[a]:(e[a]=b,b)}var e="undefined"!=typeof a?a:"undefined"!=typeof b?b:{};c.exports=d}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof a?a:{})},{}],8:[function(a,b){"use strict";function c(a,b,c){var e="__INDIVIDUAL_ONE_VERSION_"+a,f=e+"_ENFORCE_SINGLETON",g=d(f,b);if(g!==b)throw new Error("Can only have one copy of "+a+".\nYou already have version "+g+" installed.\nThis means you cannot install version "+b);return d(e,c)}var d=a("./index.js");b.exports=c},{"./index.js":7}],9:[function(b,c){(function(d){var e="undefined"!=typeof d?d:"undefined"!=typeof a?a:{},f=b("min-document");if("undefined"!=typeof document)c.exports=document;else{var g=e["__GLOBAL_DOCUMENT_CACHE@4"];g||(g=e["__GLOBAL_DOCUMENT_CACHE@4"]=f),c.exports=g}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof a?a:{})},{"min-document":35}],10:[function(a,b){"use strict";b.exports=function(a){return"object"==typeof a&&null!==a}},{}],11:[function(a,b){function c(a){return"[object Array]"===e.call(a)}var d=Array.isArray,e=Object.prototype.toString;b.exports=d||c},{}],12:[function(a,b){var c=a("./vdom/patch.js");b.exports=c},{"./vdom/patch.js":17}],13:[function(a,b){function d(a,b,d){for(var g in b){var j=b[g];j===c?e(a,g,j,d):i(j)?(e(a,g,j,d),j.hook&&j.hook(a,g,d?d[g]:c)):h(j)?f(a,b,d,g,j):a[g]=j}}function e(a,b,c,d){if(d){var e=d[b];if(i(e))e.unhook&&e.unhook(a,b,c);else if("attributes"===b)for(var f in e)a.removeAttribute(f);else if("style"===b)for(var g in e)a.style[g]="";else a[b]="string"==typeof e?"":null}}function f(a,b,d,e,f){var i=d?d[e]:c;if("attributes"!==e){if(i&&h(i)&&g(i)!==g(f))return void(a[e]=f);h(a[e])||(a[e]={});var j="style"===e?"":c;for(var k in f){var l=f[k];a[e][k]=l===c?j:l}}else for(var m in f){var n=f[m];n===c?a.removeAttribute(m):a.setAttribute(m,n)}}function g(a){return Object.getPrototypeOf?Object.getPrototypeOf(a):a.__proto__?a.__proto__:a.constructor?a.constructor.prototype:void 0}var h=a("is-object"),i=a("../vnode/is-vhook.js");b.exports=d},{"../vnode/is-vhook.js":25,"is-object":10}],14:[function(a,b){function c(a,b){var j=b?b.document||d:d,k=b?b.warn:null;if(a=i(a).a,h(a))return a.init();if(g(a))return j.createTextNode(a.text);if(!f(a))return k&&k("Item is not a valid virtual dom node",a),null;var l=null===a.namespace?j.createElement(a.tagName):j.createElementNS(a.namespace,a.tagName),m=a.properties;e(l,m);for(var n=a.children,o=0;o=f;){if(d=(g+f)/2>>0,e=a[d],f===g)return e>=b&&c>=e;if(b>e)f=d+1;else{if(!(e>c))return!0;g=d-1}}return!1}function f(a,b){return a>b?1:-1}var g={};b.exports=c},{}],16:[function(a,b){function d(a,b,c){var d=a.type,j=a.vNode,n=a.patch;switch(d){case o.REMOVE:return e(b,j);case o.INSERT:return f(b,n,c);case o.VTEXT:return g(b,j,n,c);case o.WIDGET:return h(b,j,n,c);case o.VNODE:return i(b,j,n,c);case o.ORDER:return k(b,n),b;case o.PROPS:return m(b,n,j.properties),b;case o.THUNK:return l(b,c.patch(b,n,c));default:return b}}function e(a,b){var c=a.parentNode;return c&&c.removeChild(a),j(a,b),null}function f(a,b,c){var d=p(b,c);return a&&a.appendChild(d),a}function g(a,b,c,d){var e;if(3===a.nodeType)a.replaceData(0,a.length,c.text),e=a;else{var f=a.parentNode;e=p(c,d),f&&f.replaceChild(e,a)}return e}function h(a,b,c,d){var e,f=q(b,c);e=f?c.update(b,a)||a:p(c,d);var g=a.parentNode;return g&&e!==a&&g.replaceChild(e,a),f||j(a,b),e}function i(a,b,c,d){var e=a.parentNode,f=p(c,d);return e&&e.replaceChild(f,a),f}function j(a,b){"function"==typeof b.destroy&&n(b)&&b.destroy(a)}function k(a,b){var d,e=[],f=a.childNodes,g=f.length,h=b.reverse;for(d=0;g>d;d++)e.push(a.childNodes[d]);var i,j,k,l,m,n=0;for(d=0;g>d;){if(i=b[d],l=1,i!==c&&i!==d){for(;b[d+l]===i+l;)l++;for(h[d]>d+l&&n++,j=e[i],k=f[d+n]||null,m=0;j!==k&&m++i+l&&n--}d in b.removes&&n++,d+=l}}function l(a,b){return a&&b&&a!==b&&a.parentNode&&(console.log(a),a.parentNode.replaceChild(b,a)),b}var m=a("./apply-properties"),n=a("../vnode/is-widget.js"),o=a("../vnode/vpatch.js"),p=a("./create-element"),q=a("./update-widget");b.exports=d},{"../vnode/is-widget.js":28,"../vnode/vpatch.js":31,"./apply-properties":13,"./create-element":14,"./update-widget":18}],17:[function(a,b){function c(a,b){return d(a,b)}function d(a,b,c){var h=f(b);if(0===h.length)return a;var j=i(a,b.a,h),k=a.ownerDocument;c||(c={patch:d},k!==g&&(c.document=k));for(var l=0;lu;u++){var v=d[u];f(v)?(o+=v.count||0,!p&&v.hasWidgets&&(p=!0),!q&&v.hasThunks&&(q=!0),r||!v.hooks&&!v.descendantHooks||(r=!0)):!p&&g(v)?"function"==typeof v.destroy&&(p=!0):!q&&h(v)&&(q=!0)}this.count=n+o,this.hasWidgets=p,this.hasThunks=q,this.hooks=m,this.descendantHooks=r}var e=a("./version"),f=a("./is-vnode"),g=a("./is-widget"),h=a("./is-thunk"),i=a("./is-vhook");b.exports=d;var j={},k=[];d.prototype.version=e,d.prototype.type="VirtualNode"},{"./is-thunk":24,"./is-vhook":25,"./is-vnode":26,"./is-widget":28,"./version":29}],31:[function(a,b){function c(a,b,c){this.type=Number(a),this.vNode=b,this.patch=c}var d=a("./version");c.NONE=0,c.VTEXT=1,c.VNODE=2,c.WIDGET=3,c.PROPS=4,c.ORDER=5,c.INSERT=6,c.REMOVE=7,c.THUNK=8,b.exports=c,c.prototype.version=d,c.prototype.type="VirtualPatch"},{"./version":29}],32:[function(a,b){function c(a){this.text=String(a)}var d=a("./version");b.exports=c,c.prototype.version=d,c.prototype.type="VirtualText"},{"./version":29}],33:[function(a,b){function d(a,b){var h;for(var i in a){i in b||(h=h||{},h[i]=c);var j=a[i],k=b[i];if(j!==k)if(f(j)&&f(k))if(e(k)!==e(j))h=h||{},h[i]=k;else if(g(k))h=h||{},h[i]=k;else{var l=d(j,k);l&&(h=h||{},h[i]=l)}else h=h||{},h[i]=k}for(var m in b)m in a||(h=h||{},h[m]=b[m]);return h}function e(a){return Object.getPrototypeOf?Object.getPrototypeOf(a):a.__proto__?a.__proto__:a.constructor?a.constructor.prototype:void 0}var f=a("is-object"),g=a("../vnode/is-vhook");b.exports=d},{"../vnode/is-vhook":25,"is-object":10}],34:[function(a,b){function d(a,b){var c={a:a};return e(a,b,c,0),c}function e(a,b,c,d){if(a!==b){var e=c[d],h=!1;if(u(a)||u(b))i(a,b,c,d);else if(null==b)t(a)||(g(a,c,d),e=c[d]),e=o(e,new q(q.REMOVE,a,b));else if(r(b))if(r(a))if(a.tagName===b.tagName&&a.namespace===b.namespace&&a.key===b.key){var j=w(a.properties,b.properties);j&&(e=o(e,new q(q.PROPS,a,j))),e=f(a,b,c,e,d)}else e=o(e,new q(q.VNODE,a,b)),h=!0;else e=o(e,new q(q.VNODE,a,b)),h=!0;else s(b)?s(a)?a.text!==b.text&&(e=o(e,new q(q.VTEXT,a,b))):(e=o(e,new q(q.VTEXT,a,b)),h=!0):t(b)&&(t(a)||(h=!0),e=o(e,new q(q.WIDGET,a,b)));e&&(c[d]=e),h&&g(a,c,d)}}function f(a,b,c,d,f){for(var g=a.children,h=m(g,b.children),i=g.length,j=h.length,k=i>j?i:j,l=0;k>l;l++){var n=g[l],p=h[l];f+=1,n?e(n,p,c,f):p&&(d=o(d,new q(q.INSERT,null,p))),r(n)&&n.count&&(f+=n.count)}return h.moves&&(d=o(d,new q(q.ORDER,a,h.moves))),d}function g(a,b,c){k(a,b,c),h(a,b,c)}function h(a,b,c){if(t(a))"function"==typeof a.destroy&&(b[c]=o(b[c],new q(q.REMOVE,a,null)));else if(r(a)&&(a.hasWidgets||a.hasThunks))for(var d=a.children,e=d.length,f=0;e>f;f++){var g=d[f];c+=1,h(g,b,c),r(g)&&g.count&&(c+=g.count)}else u(a)&&i(a,null,b,c)}function i(a,b,c,e){var f=v(a,b),g=d(f.a,f.b);j(g)&&(c[e]=new q(q.THUNK,null,g))}function j(a){for(var b in a)if("a"!==b)return!0;return!1}function k(a,b,c){if(r(a)){if(a.hooks&&(b[c]=o(b[c],new q(q.PROPS,a,l(a.hooks)))),a.descendantHooks||a.hasThunks)for(var d=a.children,e=d.length,f=0;e>f;f++){var g=d[f];c+=1,k(g,b,c),r(g)&&g.count&&(c+=g.count)}}else u(a)&&i(a,null,b,c)}function l(a){var b={};for(var d in a)b[d]=c;return b}function m(a,b){var d=n(b);if(!d)return b;var e=n(a);if(!e)return b;var f={},g={};for(var h in d)f[d[h]]=e[h];for(var i in e)g[e[i]]=d[i];for(var j=a.length,k=b.length,l=j>k?j:k,m=[],o=0,p=0,q=0,r={},s=r.removes={},t=r.reverse={},u=!1;l>o;){var v=g[p];if(v!==c)m[p]=b[v],v!==q&&(r[v]=q,t[q]=v,u=!0),q++;else if(p in g)m[p]=c,s[p]=q++,u=!0;else{for(;f[o]!==c;)o++;if(l>o){var w=b[o];w&&(m[p]=w,o!==q&&(u=!0,r[o]=q,t[q]=o),q++),o++}}p++}return u&&(m.moves=r),m}function n(a){var b,d;for(b=0;bc;c++)d.next();return d.next().value}}function e(a,b){a.$index=b,a.$even=b%2===0,a.$odd=!a.$even}var f="undefined"!=typeof Symbol?Symbol.iterator:"@@iterator";return{restrict:"A",priority:1e3,linkVirtual:function(g){var h=b(g,"v-repeat"),i=h.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)\s*$/),j=i[1],k=i[2];i=j.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);var l=i[3]||i[1],m=i[2],n=a(k)(g.$scope);if(Array.isArray(n))return n.map(function(a,b){var d=c(g);return d.$scope=g.$scope.$new(),d.$scope[l]=a,e(d.$scope,b),d});if(n&&n[f]){for(var o=n[f](),p=[],q=0,r=o.next();!r.done;){var s=r.value,t=c(g);t.$scope=g.$scope.$new(),m?(t.$scope[m]=d(s,0),t.$scope[l]=d(s,1)):t.$scope[l]=s,e(t.$scope,q),p.push(t),q++,r=o.next()}return p}return"object"==typeof n&&null!==n?Object.keys(n).map(function(a,b){var d=c(g);return d.$scope=g.$scope.$new(),d.$scope[m]=a,d.$scope[l]=n[a],e(d.$scope,b),d}):[]}}}]),b.module("teropa.virtualDom.vRoot",["teropa.virtualDom.virtualize","teropa.virtualDom.link"]).directive("vRoot",["$injector","$interpolate","virtualizeDom","linkVDom",function(a,c,d,e){"use strict";return{compile:function(a){var c=a[0],f=d(c);return a.empty(),function(a,c,d){function g(){if(j){var b=e(f,a),c=virtualDom.diff(h,b);i=virtualDom.patch(i,c),h=b,j=!1}}var h=e(f,a),i=virtualDom.create(h);c.replaceWith(i);var j;a.$watch(d.vRoot,function(){j=!0,a.$$postDigest(g)}),a.$on("$destroy",function(){b.element(i).remove()})}}}}]),b.module("teropa.virtualDom",["teropa.virtualDom.getAttribute","teropa.virtualDom.cloneTree","teropa.virtualDom.virtualize","teropa.virtualDom.link","teropa.virtualDom.vIf","teropa.virtualDom.vRepeat","teropa.virtualDom.vRoot"])}(window,window.angular);
--------------------------------------------------------------------------------
/src/angular-virtual-dom.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom', [
2 | 'teropa.virtualDom.getAttribute',
3 | 'teropa.virtualDom.cloneTree',
4 | 'teropa.virtualDom.virtualize',
5 | 'teropa.virtualDom.link',
6 | 'teropa.virtualDom.vIf',
7 | 'teropa.virtualDom.vRepeat',
8 | 'teropa.virtualDom.vRoot'
9 | ]);
10 |
--------------------------------------------------------------------------------
/src/clone_tree.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom.cloneTree', [])
2 | .factory('cloneVDomTree', function() {
3 | 'use strict';
4 | return function cloneTree(tree) {
5 | if (virtualDom.isVNode(tree)) {
6 | return new virtualDom.VNode(
7 | tree.tagName,
8 | angular.copy(tree.properties),
9 | tree.children.map(cloneTree)
10 | );
11 | } else if (virtualDom.isVText(tree)) {
12 | return new virtualDom.VText(tree.text);
13 | }
14 | };
15 | });
16 |
--------------------------------------------------------------------------------
/src/directive_normalize.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom.directiveNormalize', [])
2 | .factory('directiveNormalize', function() {
3 | var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
4 | var MOZ_HACK_REGEXP = /^moz([A-Z])/;
5 | var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
6 |
7 | function camelCase(name) {
8 | return name.
9 | replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
10 | return offset ? letter.toUpperCase() : letter;
11 | }).
12 | replace(MOZ_HACK_REGEXP, 'Moz$1');
13 | }
14 |
15 | return function directiveNormalize(name) {
16 | return camelCase(name.replace(PREFIX_REGEXP, ''));
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/get_attribute.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom.getAttribute', [])
2 | .factory('getVDomAttribute', function() {
3 | 'use strict';
4 | return function getVDomAttribute(node, name) {
5 | if (node.properties && node.properties.attributes) {
6 | return node.properties.attributes[name];
7 | }
8 | };
9 | });
10 |
--------------------------------------------------------------------------------
/src/link.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom.link', ['teropa.virtualDom.cloneTree', 'teropa.virtualDom.directiveNormalize'])
2 | .factory('linkVDom', ['$injector', '$interpolate', 'directiveNormalize', 'cloneVDomTree', function($injector, $interpolate, directiveNormalize, cloneVDomTree) {
3 | 'use strict';
4 |
5 | function byPriority(a, b) {
6 | var diff = b.priority - a.priority;
7 | if (diff !== 0) {
8 | return diff;
9 | }
10 | if (a.name !== b.name) {
11 | return (a.name < b.name) ? -1 : 1;
12 | }
13 | return a.index - b.index;
14 | }
15 |
16 | function getDirectives(node) {
17 | var dirs = [];
18 | if (node.properties && node.properties.attributes) {
19 | Object.keys(node.properties.attributes).forEach(function(attrName) {
20 | var dName = directiveNormalize(attrName) + 'Directive';
21 | if ($injector.has(dName)) {
22 | dirs.push.apply(dirs, $injector.get(dName));
23 | }
24 | });
25 | }
26 | return dirs.sort(byPriority);
27 | }
28 |
29 | function linkVisit(node, scope) {
30 | node.$scope = scope;
31 | var linkedNodes;
32 | if (virtualDom.isVNode(node)) {
33 | var directives = getDirectives(node);
34 | linkedNodes = directives.reduce(function(nodes, directive) {
35 | var nextNodes = [];
36 | nodes.forEach(function(node) {
37 | var linked = node;
38 | if (directive.linkVirtual) {
39 | linked = directive.linkVirtual(node);
40 | }
41 | if (Array.isArray(linked)) {
42 | nextNodes.push.apply(nextNodes, linked);
43 | } else if (!linked) {
44 | nextNodes.push(node);
45 | } else {
46 | nextNodes.push(linked);
47 | }
48 | });
49 | return nextNodes;
50 | }, [node]);
51 |
52 | linkedNodes.forEach(function(node) {
53 | if (node.properties && node.properties.attributes) {
54 | Object.keys(node.properties.attributes).forEach(function(attrName) {
55 | var interpolateFn = $interpolate(node.properties.attributes[attrName]);
56 | if (interpolateFn) {
57 | node.properties.attributes[attrName] = interpolateFn(node.$scope);
58 | }
59 | });
60 | }
61 |
62 | var linkedChildren = [];
63 | node.children.forEach(function(childNode) {
64 | linkedChildren.push.apply(linkedChildren, linkVisit(childNode, node.$scope));
65 | });
66 | node.children = linkedChildren;
67 | });
68 | } else {
69 | node.text = $interpolate(node.text)(node.$scope);
70 | linkedNodes = [node];
71 | }
72 | return linkedNodes;
73 | }
74 |
75 | return function linkVDom(tree, scope) {
76 | var clone = cloneVDomTree(tree);
77 | return linkVisit(clone, scope)[0];
78 | };
79 |
80 | }]);
81 |
--------------------------------------------------------------------------------
/src/v_if_directive.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom.vIf', ['teropa.virtualDom.getAttribute'])
2 | .directive('vIf', ['$parse', 'getVDomAttribute', function($parse, getVDomAttribute) {
3 | 'use strict';
4 | return {
5 | restrict: 'A',
6 | priority: 600,
7 | linkVirtual: function(node) {
8 | var expr = $parse(getVDomAttribute(node, 'v-if'));
9 | if (expr(node.$scope)) {
10 | return node;
11 | } else {
12 | return [];
13 | }
14 | }
15 | };
16 | }]);
17 |
--------------------------------------------------------------------------------
/src/v_repeat_directive.js:
--------------------------------------------------------------------------------
1 | angular.module('teropa.virtualDom.vRepeat', ['teropa.virtualDom.getAttribute', 'teropa.virtualDom.cloneTree'])
2 | .directive('vRepeat', ['$parse', 'getVDomAttribute', 'cloneVDomTree', function($parse, getVDomAttribute, cloneVDomTree) {
3 | 'use strict';
4 |
5 | var iteratorSymbol = (typeof Symbol !== 'undefined') ? Symbol.iterator : "@@iterator";
6 |
7 | function nth(v, n) {
8 | if (Array.isArray(v)) {
9 | return v[n];
10 | } else if (v[iteratorSymbol]) {
11 | var iterator = v[iteratorSymbol]();
12 | var i;
13 | for (i=0 ; iStuff');
12 | $compile(element);
13 | expect(element.children().length).toBe(0);
14 | });
15 |
16 | it('renders element at link time', function() {
17 | var element = angular.element('');
18 | $compile(element)($rootScope);
19 | expect(element[0].firstChild.childNodes.length).toBe(1);
20 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Stuff');
21 | });
22 |
23 | it('uses given scope for linking', function() {
24 | var element = angular.element('');
25 | $rootScope.msg = 'Hello';
26 | $compile(element)($rootScope);
27 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Hello');
28 | });
29 |
30 | it('diffs the dom when root expression changes', function() {
31 | var element = angular.element('');
32 | $rootScope.msg = 'Hello';
33 | $compile(element)($rootScope);
34 | $rootScope.$digest();
35 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Hello');
36 |
37 | $rootScope.msg = 'World';
38 | $rootScope.$digest();
39 | expect(element[0].firstChild.firstChild.nodeValue).toBe('World');
40 | });
41 |
42 | it('does not diff the dom when root expression mutates', function() {
43 | var element = angular.element('');
44 | $rootScope.stuff = ['Hello'];
45 | $compile(element)($rootScope);
46 | $rootScope.$digest();
47 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Hello');
48 |
49 | $rootScope.stuff[0] = 'World';
50 | $rootScope.$digest();
51 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Hello');
52 | });
53 |
54 | it('does not diff the dom when inner expressions change', function() {
55 | var element = angular.element('');
56 | $rootScope.msg = 'Hello';
57 | $compile(element)($rootScope);
58 | $rootScope.$digest();
59 |
60 | $rootScope.msg = 'World';
61 | $rootScope.$digest();
62 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Hello');
63 | });
64 |
65 | it('cleans up after itself', function() {
66 | var scope = $rootScope.$new();
67 | var element = angular.element('');
68 | scope.msg = 'Hello';
69 | $compile(element)(scope);
70 | scope.$digest();
71 | expect(element[0].firstChild.firstChild.nodeValue).toBe('Hello');
72 |
73 | scope.msg = 'World';
74 | scope.$destroy();
75 | scope.$digest();
76 | expect(element[0].childNodes.length).toBe(0);
77 | });
78 |
79 | });
80 |
--------------------------------------------------------------------------------
/test/virtualize_spec.js:
--------------------------------------------------------------------------------
1 | describe('teropa.virtualDom.virtualize', function() {
2 |
3 | var virtualizeDom;
4 | beforeEach(module('teropa.virtualDom.virtualize'));
5 | beforeEach(inject(function(_virtualizeDom_) {
6 | virtualizeDom = _virtualizeDom_;
7 | }));
8 |
9 | it('virtualizes a single node', function() {
10 | var dom = angular.element('');
11 | var result = virtualizeDom(dom[0]);
12 | expect(result).toBeDefined();
13 | expect(virtualDom.isVNode(result)).toBe(true);
14 | expect(result.tagName).toBe('div');
15 | });
16 |
17 | it('virtualizes attributes', function() {
18 | var dom = angular.element('');
19 | var result = virtualizeDom(dom[0]);
20 | expect(result.properties.attributes.class).toBe('test');
21 | });
22 |
23 | it('virtualizes valueless attributes', function() {
24 | var dom = angular.element('');
25 | var result = virtualizeDom(dom[0]);
26 | expect(result.properties.attributes.readonly).toBe('');
27 | });
28 |
29 | it('virtualizes a node with nested text nodes', function() {
30 | var dom = angular.element('Hello
');
31 | var result = virtualizeDom(dom[0]);
32 | expect(result.children.length).toBe(1);
33 | expect(virtualDom.isVText(result.children[0])).toBe(true);
34 | expect(result.children[0].text).toBe('Hello');
35 | });
36 |
37 | it('virtualizes a node with nested nodes', function() {
38 | var dom = angular.element('');
39 | var result = virtualizeDom(dom[0]);
40 | expect(result.children.length).toBe(2);
41 | expect(virtualDom.isVNode(result.children[0])).toBe(true);
42 | expect(virtualDom.isVNode(result.children[1])).toBe(true);
43 | });
44 |
45 | it('strips comments', function() {
46 | var dom = angular.element('Hello again
');
47 | var result = virtualizeDom(dom[0]);
48 | expect(result.children.length).toBe(2);
49 | expect(virtualDom.isVText(result.children[0])).toBe(true);
50 | expect(result.children[0].text).toBe('Hello ');
51 | expect(virtualDom.isVText(result.children[1])).toBe(true);
52 | expect(result.children[1].text).toBe(' again');
53 | });
54 |
55 | });
56 |
--------------------------------------------------------------------------------