knockoutjs-rails 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  module Knockoutjs
2
2
  module Rails
3
- VERSION = "3.0.0"
3
+ VERSION = "3.1.0"
4
4
  end
5
5
  end
@@ -1,94 +1,4469 @@
1
- // Knockout JavaScript library v3.0.0
1
+ // Knockout JavaScript library v3.1.0
2
2
  // (c) Steven Sanderson - http://knockoutjs.com/
3
3
  // License: MIT (http://www.opensource.org/licenses/mit-license.php)
4
4
 
5
- (function() {(function(q){var y=this||(0,eval)("this"),w=y.document,K=y.navigator,u=y.jQuery,B=y.JSON;(function(q){"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?q(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],q):q(y.ko={})})(function(F){function G(a,c){return null===a||typeof a in N?a===c:!1}function H(b,c,d,e){a.d[b]={init:function(b){a.a.f.set(b,L,{});return{controlsDescendantBindings:!0}},update:function(b,h,k,m,f){k=a.a.f.get(b,L);h=a.a.c(h());
6
- m=!d!==!h;var p=!k.ob;if(p||c||m!==k.Db)p&&(k.ob=a.a.Ya(a.e.childNodes(b),!0)),m?(p||a.e.S(b,a.a.Ya(k.ob)),a.Ta(e?e(f,h):f,b)):a.e.Z(b),k.Db=m}};a.g.Y[b]=!1;a.e.P[b]=!0}var a="undefined"!==typeof F?F:{};a.b=function(b,c){for(var d=b.split("."),e=a,g=0;g<d.length-1;g++)e=e[d[g]];e[d[d.length-1]]=c};a.s=function(a,c,d){a[c]=d};a.version="3.0.0";a.b("version",a.version);a.a=function(){function b(a,b){for(var f in a)a.hasOwnProperty(f)&&b(f,a[f])}function c(k,b){if("input"!==a.a.v(k)||!k.type||"click"!=
7
- b.toLowerCase())return!1;var f=k.type;return"checkbox"==f||"radio"==f}var d={},e={};d[K&&/Firefox\/2/i.test(K.userAgent)?"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(d,function(a,b){if(b.length)for(var f=0,c=b.length;f<c;f++)e[b[f]]=a});var g={propertychange:!0},h=w&&function(){for(var a=3,b=w.createElement("div"),f=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+
8
- ++a+"]><i></i><![endif]--\x3e",f[0];);return 4<a?a:q}();return{$a:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],n:function(a,b){for(var f=0,c=a.length;f<c;f++)b(a[f])},l:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var f=0,c=a.length;f<c;f++)if(a[f]===b)return f;return-1},Ua:function(a,b,f){for(var c=0,d=a.length;c<d;c++)if(b.call(f,a[c]))return a[c];return null},ia:function(b,c){var f=a.a.l(b,c);0<=f&&b.splice(f,1)},Va:function(b){b=
9
- b||[];for(var c=[],f=0,d=b.length;f<d;f++)0>a.a.l(c,b[f])&&c.push(b[f]);return c},ha:function(a,b){a=a||[];for(var f=[],c=0,d=a.length;c<d;c++)f.push(b(a[c]));return f},ga:function(a,b){a=a||[];for(var f=[],c=0,d=a.length;c<d;c++)b(a[c])&&f.push(a[c]);return f},X:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var f=0,c=b.length;f<c;f++)a.push(b[f]);return a},V:function(b,c,f){var d=a.a.l(a.a.Ha(b),c);0>d?f&&b.push(c):f||b.splice(d,1)},extend:function(a,b){if(b)for(var f in b)b.hasOwnProperty(f)&&
10
- (a[f]=b[f]);return a},K:b,Da:function(a,b){if(!a)return a;var f={},c;for(c in a)a.hasOwnProperty(c)&&(f[c]=b(a[c],c,a));return f},wa:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Vb:function(b){b=a.a.Q(b);for(var c=w.createElement("div"),f=0,d=b.length;f<d;f++)c.appendChild(a.L(b[f]));return c},Ya:function(b,c){for(var f=0,d=b.length,e=[];f<d;f++){var g=b[f].cloneNode(!0);e.push(c?a.L(g):g)}return e},S:function(b,c){a.a.wa(b);if(c)for(var f=0,d=c.length;f<d;f++)b.appendChild(c[f])},nb:function(b,
11
- c){var f=b.nodeType?[b]:b;if(0<f.length){for(var d=f[0],e=d.parentNode,g=0,n=c.length;g<n;g++)e.insertBefore(c[g],d);g=0;for(n=f.length;g<n;g++)a.removeNode(f[g])}},$:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);if(1<a.length){var f=a[0],c=a[a.length-1];for(a.length=0;f!==c;)if(a.push(f),f=f.nextSibling,!f)return;a.push(c)}}return a},qb:function(a,b){7>h?a.setAttribute("selected",b):a.selected=b},la:function(a){return null===a||a===
12
- q?"":a.trim?a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},ec:function(b,c){for(var f=[],d=(b||"").split(c),e=0,g=d.length;e<g;e++){var n=a.a.la(d[e]);""!==n&&f.push(n)}return f},ac:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},Gb:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(3===a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;
13
- return!!a},va:function(b){return a.a.Gb(b,b.ownerDocument.documentElement)},Ra:function(b){return!!a.a.Ua(b,a.a.va)},v:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},r:function(b,d,f){var e=h&&g[d];if(e||"undefined"==typeof u)if(e||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var s=function(a){f.call(b,a)},l="on"+d;b.attachEvent(l,s);a.a.C.ea(b,function(){b.detachEvent(l,s)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(d,
14
- f,!1);else{if(c(b,d)){var n=f;f=function(a,b){var f=this.checked;b&&(this.checked=!0!==b.Ab);n.call(this,a);this.checked=f}}u(b).bind(d,f)}},da:function(a,b){if(!a||!a.nodeType)throw Error("element must be a DOM node when calling triggerEvent");if("undefined"!=typeof u){var f=[];c(a,b)&&f.push({Ab:a.checked});u(a).trigger(b,f)}else if("function"==typeof w.createEvent)if("function"==typeof a.dispatchEvent)f=w.createEvent(e[b]||"HTMLEvents"),f.initEvent(b,!0,!0,y,0,0,0,0,0,!1,!1,!1,!1,0,a),a.dispatchEvent(f);
15
- else throw Error("The supplied element doesn't support dispatchEvent");else if("undefined"!=typeof a.fireEvent)c(a,b)&&(a.checked=!0!==a.checked),a.fireEvent("on"+b);else throw Error("Browser doesn't support triggering events");},c:function(b){return a.M(b)?b():b},Ha:function(b){return a.M(b)?b.t():b},ma:function(b,c,f){if(c){var d=/\S+/g,e=b.className.match(d)||[];a.a.n(c.match(d),function(b){a.a.V(e,b,f)});b.className=e.join(" ")}},Ma:function(b,c){var f=a.a.c(c);if(null===f||f===q)f="";var d=a.e.firstChild(b);
16
- !d||3!=d.nodeType||a.e.nextSibling(d)?a.e.S(b,[w.createTextNode(f)]):d.data=f;a.a.Jb(b)},pb:function(a,b){a.name=b;if(7>=h)try{a.mergeAttributes(w.createElement("<input name='"+a.name+"'/>"),!1)}catch(f){}},Jb:function(a){9<=h&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},Hb:function(a){if(h){var b=a.style.width;a.style.width=0;a.style.width=b}},Zb:function(b,c){b=a.a.c(b);c=a.a.c(c);for(var f=[],d=b;d<=c;d++)f.push(d);return f},Q:function(a){for(var b=[],c=0,d=a.length;c<
17
- d;c++)b.push(a[c]);return b},cc:6===h,dc:7===h,ja:h,ab:function(b,c){for(var f=a.a.Q(b.getElementsByTagName("input")).concat(a.a.Q(b.getElementsByTagName("textarea"))),d="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},e=[],g=f.length-1;0<=g;g--)d(f[g])&&e.push(f[g]);return e},Wb:function(b){return"string"==typeof b&&(b=a.a.la(b))?B&&B.parse?B.parse(b):(new Function("return "+b))():null},Na:function(b,c,f){if(!B||!B.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
18
- return B.stringify(a.a.c(b),c,f)},Xb:function(c,d,f){f=f||{};var e=f.params||{},g=f.includeFields||this.$a,h=c;if("object"==typeof c&&"form"===a.a.v(c))for(var h=c.action,n=g.length-1;0<=n;n--)for(var r=a.a.ab(c,g[n]),v=r.length-1;0<=v;v--)e[r[v].name]=r[v].value;d=a.a.c(d);var t=w.createElement("form");t.style.display="none";t.action=h;t.method="post";for(var E in d)c=w.createElement("input"),c.name=E,c.value=a.a.Na(a.a.c(d[E])),t.appendChild(c);b(e,function(a,b){var c=w.createElement("input");c.name=
19
- a;c.value=b;t.appendChild(c)});w.body.appendChild(t);f.submitter?f.submitter(t):t.submit();setTimeout(function(){t.parentNode.removeChild(t)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.n);a.b("utils.arrayFirst",a.a.Ua);a.b("utils.arrayFilter",a.a.ga);a.b("utils.arrayGetDistinctValues",a.a.Va);a.b("utils.arrayIndexOf",a.a.l);a.b("utils.arrayMap",a.a.ha);a.b("utils.arrayPushAll",a.a.X);a.b("utils.arrayRemoveItem",a.a.ia);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",
20
- a.a.$a);a.b("utils.getFormFields",a.a.ab);a.b("utils.peekObservable",a.a.Ha);a.b("utils.postJson",a.a.Xb);a.b("utils.parseJson",a.a.Wb);a.b("utils.registerEventHandler",a.a.r);a.b("utils.stringifyJson",a.a.Na);a.b("utils.range",a.a.Zb);a.b("utils.toggleDomNodeCssClass",a.a.ma);a.b("utils.triggerEvent",a.a.da);a.b("utils.unwrapObservable",a.a.c);a.b("utils.objectForEach",a.a.K);a.b("utils.addOrRemoveItem",a.a.V);a.b("unwrap",a.a.c);Function.prototype.bind||(Function.prototype.bind=function(a){var c=
21
- this,d=Array.prototype.slice.call(arguments);a=d.shift();return function(){return c.apply(a,d.concat(Array.prototype.slice.call(arguments)))}});a.a.f=new function(){function a(b,h){var k=b[d];if(!k||"null"===k||!e[k]){if(!h)return q;k=b[d]="ko"+c++;e[k]={}}return e[k]}var c=0,d="__ko__"+(new Date).getTime(),e={};return{get:function(c,d){var e=a(c,!1);return e===q?q:e[d]},set:function(c,d,e){if(e!==q||a(c,!1)!==q)a(c,!0)[d]=e},clear:function(a){var b=a[d];return b?(delete e[b],a[d]=null,!0):!1},D:function(){return c++ +
22
- d}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.C=new function(){function b(b,c){var e=a.a.f.get(b,d);e===q&&c&&(e=[],a.a.f.set(b,d,e));return e}function c(d){var e=b(d,!1);if(e)for(var e=e.slice(0),m=0;m<e.length;m++)e[m](d);a.a.f.clear(d);"function"==typeof u&&"function"==typeof u.cleanData&&u.cleanData([d]);if(g[d.nodeType])for(e=d.firstChild;d=e;)e=d.nextSibling,8===d.nodeType&&c(d)}var d=a.a.f.D(),e={1:!0,8:!0,9:!0},g={1:!0,9:!0};return{ea:function(a,c){if("function"!=
23
- typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},mb:function(c,e){var g=b(c,!1);g&&(a.a.ia(g,e),0==g.length&&a.a.f.set(c,d,q))},L:function(b){if(e[b.nodeType]&&(c(b),g[b.nodeType])){var d=[];a.a.X(d,b.getElementsByTagName("*"));for(var m=0,f=d.length;m<f;m++)c(d[m])}return b},removeNode:function(b){a.L(b);b.parentNode&&b.parentNode.removeChild(b)}}};a.L=a.a.C.L;a.removeNode=a.a.C.removeNode;a.b("cleanNode",a.L);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.C);
24
- a.b("utils.domNodeDisposal.addDisposeCallback",a.a.C.ea);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.C.mb);(function(){a.a.Fa=function(b){var c;if("undefined"!=typeof u)if(u.parseHTML)c=u.parseHTML(b)||[];else{if((c=u.clean([b]))&&c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&b.parentNode.removeChild(b)}}else{var d=a.a.la(b).toLowerCase();c=w.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,
25
- "<table><tbody>","</tbody></table>"]||(!d.indexOf("<td")||!d.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||[0,"",""];b="ignored<div>"+d[1]+b+d[2]+"</div>";for("function"==typeof y.innerShiv?c.appendChild(y.innerShiv(b)):c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.Q(c.lastChild.childNodes)}return c};a.a.Ka=function(b,c){a.a.wa(b);c=a.a.c(c);if(null!==c&&c!==q)if("string"!=typeof c&&(c=c.toString()),"undefined"!=typeof u)u(b).html(c);else for(var d=a.a.Fa(c),e=0;e<d.length;e++)b.appendChild(d[e])}})();
26
- a.b("utils.parseHtmlFragment",a.a.Fa);a.b("utils.setHtml",a.a.Ka);a.u=function(){function b(c,e){if(c)if(8==c.nodeType){var g=a.u.jb(c.nodeValue);null!=g&&e.push({Fb:c,Tb:g})}else if(1==c.nodeType)for(var g=0,h=c.childNodes,k=h.length;g<k;g++)b(h[g],e)}var c={};return{Ca:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);
27
- c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},ub:function(a,b){var g=c[a];if(g===q)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return g.apply(null,b||[]),!0}finally{delete c[a]}},vb:function(c,e){var g=[];b(c,g);for(var h=0,k=g.length;h<k;h++){var m=g[h].Fb,f=[m];e&&a.a.X(f,e);a.u.ub(g[h].Tb,f);m.nodeValue="";m.parentNode&&m.parentNode.removeChild(m)}},jb:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.u);a.b("memoization.memoize",
28
- a.u.Ca);a.b("memoization.unmemoize",a.u.ub);a.b("memoization.parseMemoText",a.u.jb);a.b("memoization.unmemoizeDomNodeAndDescendants",a.u.vb);a.xa={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.h({read:b,write:function(a){clearTimeout(d);d=setTimeout(function(){b(a)},c)}})},notify:function(a,c){a.equalityComparer="always"==c?null:G}};var N={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.xa);a.sb=function(b,c,d){this.target=b;this.qa=c;this.Eb=d;a.s(this,"dispose",
29
- this.B)};a.sb.prototype.B=function(){this.Qb=!0;this.Eb()};a.ca=function(){this.F={};a.a.extend(this,a.ca.fn);a.s(this,"subscribe",this.T);a.s(this,"extend",this.extend);a.s(this,"getSubscriptionsCount",this.Lb)};var I="change";a.ca.fn={T:function(b,c,d){d=d||I;var e=new a.sb(this,c?b.bind(c):b,function(){a.a.ia(this.F[d],e)}.bind(this));this.F[d]||(this.F[d]=[]);this.F[d].push(e);return e},notifySubscribers:function(b,c){c=c||I;if(this.cb(c))try{a.i.Wa();for(var d=this.F[c].slice(0),e=0,g;g=d[e];++e)g&&
30
- !0!==g.Qb&&g.qa(b)}finally{a.i.end()}},cb:function(a){return this.F[a]&&this.F[a].length},Lb:function(){var b=0;a.a.K(this.F,function(a,d){b+=d.length});return b},extend:function(b){var c=this;b&&a.a.K(b,function(b,e){var g=a.xa[b];"function"==typeof g&&(c=g(c,e)||c)});return c}};a.fb=function(a){return null!=a&&"function"==typeof a.T&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.ca);a.b("isSubscribable",a.fb);a.i=function(){var b=[];return{Wa:function(a){b.push(a&&{qa:a,Za:[]})},
31
- end:function(){b.pop()},lb:function(c){if(!a.fb(c))throw Error("Only subscribable things can act as dependencies");if(0<b.length){var d=b[b.length-1];!d||0<=a.a.l(d.Za,c)||(d.Za.push(c),d.qa(c))}},p:function(a,d,e){try{return b.push(null),a.apply(d,e||[])}finally{b.pop()}}}}();a.q=function(b){function c(){if(0<arguments.length)return c.equalityComparer&&c.equalityComparer(d,arguments[0])||(c.O(),d=arguments[0],c.N()),this;a.i.lb(c);return d}var d=b;a.ca.call(c);c.t=function(){return d};c.N=function(){c.notifySubscribers(d)};
32
- c.O=function(){c.notifySubscribers(d,"beforeChange")};a.a.extend(c,a.q.fn);a.s(c,"peek",c.t);a.s(c,"valueHasMutated",c.N);a.s(c,"valueWillMutate",c.O);return c};a.q.fn={equalityComparer:G};var C=a.q.Yb="__ko_proto__";a.q.fn[C]=a.q;a.ya=function(b,c){return null===b||b===q||b[C]===q?!1:b[C]===c?!0:a.ya(b[C],c)};a.M=function(b){return a.ya(b,a.q)};a.gb=function(b){return"function"==typeof b&&b[C]===a.q||"function"==typeof b&&b[C]===a.h&&b.Nb?!0:!1};a.b("observable",a.q);a.b("isObservable",a.M);a.b("isWriteableObservable",
33
- a.gb);a.ba=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.q(b);a.a.extend(b,a.ba.fn);return b.extend({trackArrayChanges:!0})};a.ba.fn={remove:function(b){for(var c=this.t(),d=[],e="function"!=typeof b||a.M(b)?function(a){return a===b}:b,g=0;g<c.length;g++){var h=c[g];e(h)&&(0===d.length&&this.O(),d.push(h),c.splice(g,1),g--)}d.length&&this.N();return d},removeAll:function(b){if(b===
34
- q){var c=this.t(),d=c.slice(0);this.O();c.splice(0,c.length);this.N();return d}return b?this.remove(function(c){return 0<=a.a.l(b,c)}):[]},destroy:function(b){var c=this.t(),d="function"!=typeof b||a.M(b)?function(a){return a===b}:b;this.O();for(var e=c.length-1;0<=e;e--)d(c[e])&&(c[e]._destroy=!0);this.N()},destroyAll:function(b){return b===q?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.l(b,c)}):[]},indexOf:function(b){var c=this();return a.a.l(c,b)},replace:function(a,
35
- c){var d=this.indexOf(a);0<=d&&(this.O(),this.t()[d]=c,this.N())}};a.a.n("pop push reverse shift sort splice unshift".split(" "),function(b){a.ba.fn[b]=function(){var a=this.t();this.O();this.Xa(a,b,arguments);a=a[b].apply(a,arguments);this.N();return a}});a.a.n(["slice"],function(b){a.ba.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.ba);var J="arrayChange";a.xa.trackArrayChanges=function(b){function c(){if(!d){d=!0;var c=b.notifySubscribers;b.notifySubscribers=
36
- function(a,b){b&&b!==I||++g;return c.apply(this,arguments)};var m=[].concat(b.t()||[]);e=null;b.T(function(c){c=[].concat(c||[]);if(b.cb(J)){var d;if(!e||1<g)e=a.a.ra(m,c,{sparse:!0});d=e;d.length&&b.notifySubscribers(d,J)}m=c;e=null;g=0})}}if(!b.Xa){var d=!1,e=null,g=0,h=b.T;b.T=b.subscribe=function(a,b,f){f===J&&c();return h.apply(this,arguments)};b.Xa=function(a,b,c){function p(a,b,c){h.push({status:a,value:b,index:c})}if(d&&!g){var h=[],l=a.length,n=c.length,r=0;switch(b){case "push":r=l;case "unshift":for(b=
37
- 0;b<n;b++)p("added",c[b],r+b);break;case "pop":r=l-1;case "shift":l&&p("deleted",a[r],r);break;case "splice":b=Math.min(Math.max(0,0>c[0]?l+c[0]:c[0]),l);for(var l=1===n?l:Math.min(b+(c[1]||0),l),n=b+n-2,r=Math.max(l,n),v=2;b<r;++b,++v)b<l&&p("deleted",a[b],b),b<n&&p("added",c[v],b);break;default:return}e=h}}}};a.h=function(b,c,d){function e(){a.a.n(z,function(a){a.B()});z=[]}function g(){var a=k.throttleEvaluation;a&&0<=a?(clearTimeout(x),x=setTimeout(h,a)):h()}function h(){if(!s){if(E&&E()){if(!l){D();
38
- p=!0;return}}else l=!1;s=!0;try{var b=a.a.ha(z,function(a){return a.target});a.i.Wa(function(c){var d;0<=(d=a.a.l(b,c))?b[d]=q:z.push(c.T(g))});for(var d=c?n.call(c):n(),e=b.length-1;0<=e;e--)b[e]&&z.splice(e,1)[0].B();p=!0;k.equalityComparer&&k.equalityComparer(f,d)||(k.notifySubscribers(f,"beforeChange"),f=d,k.notifySubscribers(f))}finally{a.i.end(),s=!1}z.length||D()}}function k(){if(0<arguments.length){if("function"===typeof r)r.apply(c,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
39
- return this}p||h();a.i.lb(k);return f}function m(){return!p||0<z.length}var f,p=!1,s=!1,l=!1,n=b;n&&"object"==typeof n?(d=n,n=d.read):(d=d||{},n||(n=d.read));if("function"!=typeof n)throw Error("Pass a function that returns the value of the ko.computed");var r=d.write,v=d.disposeWhenNodeIsRemoved||d.I||null,t=d.disposeWhen||d.ua,E=t,D=e,z=[],x=null;c||(c=d.owner);k.t=function(){p||h();return f};k.Kb=function(){return z.length};k.Nb="function"===typeof d.write;k.B=function(){D()};k.aa=m;a.ca.call(k);
40
- a.a.extend(k,a.h.fn);a.s(k,"peek",k.t);a.s(k,"dispose",k.B);a.s(k,"isActive",k.aa);a.s(k,"getDependenciesCount",k.Kb);v&&(l=!0,v.nodeType&&(E=function(){return!a.a.va(v)||t&&t()}));!0!==d.deferEvaluation&&h();v&&m()&&(D=function(){a.a.C.mb(v,D);e()},a.a.C.ea(v,D));return k};a.Pb=function(b){return a.ya(b,a.h)};F=a.q.Yb;a.h[F]=a.q;a.h.fn={equalityComparer:G};a.h.fn[F]=a.h;a.b("dependentObservable",a.h);a.b("computed",a.h);a.b("isComputed",a.Pb);(function(){function b(a,g,h){h=h||new d;a=g(a);if("object"!=
41
- typeof a||null===a||a===q||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var k=a instanceof Array?[]:{};h.save(a,k);c(a,function(c){var d=g(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":k[c]=d;break;case "object":case "undefined":var p=h.get(d);k[c]=p!==q?p:b(d,g,h)}});return k}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=
42
- [];this.Qa=[]}a.tb=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.M(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.tb(b);return a.a.Na(b,c,d)};d.prototype={save:function(b,c){var d=a.a.l(this.keys,b);0<=d?this.Qa[d]=c:(this.keys.push(b),this.Qa.push(c))},get:function(b){b=a.a.l(this.keys,b);return 0<=b?this.Qa[b]:q}}})();a.b("toJS",a.tb);a.b("toJSON",a.toJSON);(function(){a.k={o:function(b){switch(a.a.v(b)){case "option":return!0===
43
- b.__ko__hasDomDataOptionValue__?a.a.f.get(b,a.d.options.Ea):7>=a.a.ja?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.k.o(b.options[b.selectedIndex]):q;default:return b.value}},na:function(b,c){switch(a.a.v(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.d.options.Ea,q);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.d.options.Ea,c),b.__ko__hasDomDataOptionValue__=
44
- !0,b.value="number"===typeof c?c:""}break;case "select":""===c&&(c=q);if(null===c||c===q)b.selectedIndex=-1;for(var d=b.options.length-1;0<=d;d--)if(a.k.o(b.options[d])==c){b.selectedIndex=d;break}1<b.size||-1!==b.selectedIndex||(b.selectedIndex=0);break;default:if(null===c||c===q)c="";b.value=c}}}})();a.b("selectExtensions",a.k);a.b("selectExtensions.readValue",a.k.o);a.b("selectExtensions.writeValue",a.k.na);a.g=function(){function b(b){b=a.a.la(b);123===b.charCodeAt(0)&&(b=b.slice(1,-1));var c=
45
- [],d=b.match(e),k,l,n=0;if(d){d.push(",");for(var r=0,v;v=d[r];++r){var t=v.charCodeAt(0);if(44===t){if(0>=n){k&&c.push(l?{key:k,value:l.join("")}:{unknown:k});k=l=n=0;continue}}else if(58===t){if(!l)continue}else if(47===t&&r&&1<v.length)(t=d[r-1].match(g))&&!h[t[0]]&&(b=b.substr(b.indexOf(v)+1),d=b.match(e),d.push(","),r=-1,v="/");else if(40===t||123===t||91===t)++n;else if(41===t||125===t||93===t)--n;else if(!k&&!l){k=34===t||39===t?v.slice(1,-1):v;continue}l?l.push(v):l=[v]}}return c}var c=["true",
46
- "false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:[^\"\\\\]|\\\\.)*\"|'(?:[^'\\\\]|\\\\.)*'|/(?:[^/\\\\]|\\\\.)*/w*|[^\\s:,/][^,\"'{}()/:[\\]]*[^\\s,\"'{}()/:[\\]]|[^\\s]","g"),g=/[\])"'A-Za-z0-9_$]+$/,h={"in":1,"return":1,"typeof":1},k={};return{Y:[],U:k,Ga:b,ka:function(e,f){function g(b,f){var e,r=a.getBindingHandler(b);if(r&&r.preprocess?f=r.preprocess(f,b,g):1){if(r=k[b])e=f,0<=a.a.l(c,e)?e=!1:(r=e.match(d),e=null===r?!1:r[1]?"Object("+r[1]+")"+
47
- r[2]:e),r=e;r&&l.push("'"+b+"':function(_z){"+e+"=_z}");n&&(f="function(){return "+f+" }");h.push("'"+b+"':"+f)}}f=f||{};var h=[],l=[],n=f.valueAccessors,r="string"===typeof e?b(e):e;a.a.n(r,function(a){g(a.key||a.unknown,a.value)});l.length&&g("_ko_property_writers","{"+l.join(",")+"}");return h.join(",")},Sb:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},oa:function(b,c,d,e,k){if(b&&a.M(b))!a.gb(b)||k&&b.t()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();
48
- a.b("expressionRewriting",a.g);a.b("expressionRewriting.bindingRewriteValidators",a.g.Y);a.b("expressionRewriting.parseObjectLiteral",a.g.Ga);a.b("expressionRewriting.preProcessBindings",a.g.ka);a.b("expressionRewriting._twoWayBindings",a.g.U);a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.g.ka);(function(){function b(a){return 8==a.nodeType&&h.test(g?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&k.test(g?a.text:a.nodeValue)}function d(a,
49
- d){for(var e=a,k=1,n=[];e=e.nextSibling;){if(c(e)&&(k--,0===k))return n;n.push(e);b(e)&&k++}if(!d)throw Error("Cannot find closing comment tag to match: "+a.nodeValue);return null}function e(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var g=w&&"\x3c!--test--\x3e"===w.createComment("test").text,h=g?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,k=g?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,m={ul:!0,ol:!0};a.e={P:{},childNodes:function(a){return b(a)?
50
- d(a):a.childNodes},Z:function(c){if(b(c)){c=a.e.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.wa(c)},S:function(c,d){if(b(c)){a.e.Z(c);for(var e=c.nextSibling,k=0,n=d.length;k<n;k++)e.parentNode.insertBefore(d[k],e)}else a.a.S(c,d)},kb:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},eb:function(c,d,e){e?b(c)?c.parentNode.insertBefore(d,e.nextSibling):e.nextSibling?c.insertBefore(d,e.nextSibling):
51
- c.appendChild(d):a.e.kb(c,d)},firstChild:function(a){return b(a)?!a.nextSibling||c(a.nextSibling)?null:a.nextSibling:a.firstChild},nextSibling:function(a){b(a)&&(a=e(a));return a.nextSibling&&c(a.nextSibling)?null:a.nextSibling},Mb:b,bc:function(a){return(a=(g?a.text:a.nodeValue).match(h))?a[1]:null},ib:function(d){if(m[a.a.v(d)]){var k=d.firstChild;if(k){do if(1===k.nodeType){var g;g=k.firstChild;var h=null;if(g){do if(h)h.push(g);else if(b(g)){var n=e(g,!0);n?g=n:h=[g]}else c(g)&&(h=[g]);while(g=
52
- g.nextSibling)}if(g=h)for(h=k.nextSibling,n=0;n<g.length;n++)h?d.insertBefore(g[n],h):d.appendChild(g[n])}while(k=k.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.P);a.b("virtualElements.emptyNode",a.e.Z);a.b("virtualElements.insertAfter",a.e.eb);a.b("virtualElements.prepend",a.e.kb);a.b("virtualElements.setDomNodeChildren",a.e.S);(function(){a.H=function(){this.zb={}};a.a.extend(a.H.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=
53
- b.getAttribute("data-bind");case 8:return a.e.Mb(b);default:return!1}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a):null},getBindingAccessors:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c,a,{valueAccessors:!0}):null},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.e.bc(b);default:return null}},parseBindingsString:function(b,c,d,e){try{var g=this.zb,
54
- h=b+(e&&e.valueAccessors||""),k;if(!(k=g[h])){var m,f="with($context){with($data||{}){return{"+a.g.ka(b,e)+"}}}";m=new Function("$context","$element",f);k=g[h]=m}return k(c,d)}catch(p){throw p.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+p.message,p;}}});a.H.instance=new a.H})();a.b("bindingProvider",a.H);(function(){function b(a){return function(){return a}}function c(a){return a()}function d(b){return a.a.Da(a.i.p(b),function(a,c){return function(){return b()[c]}})}function e(a,
55
- b){return d(this.getBindings.bind(this,a,b))}function g(b,c,d){var f,e=a.e.firstChild(c),k=a.H.instance,g=k.preprocessNode;if(g){for(;f=e;)e=a.e.nextSibling(f),g.call(k,f);e=a.e.firstChild(c)}for(;f=e;)e=a.e.nextSibling(f),h(b,f,d)}function h(b,c,d){var f=!0,e=1===c.nodeType;e&&a.e.ib(c);if(e&&d||a.H.instance.nodeHasBindings(c))f=m(c,null,b,d).shouldBindDescendants;f&&!p[a.a.v(c)]&&g(b,c,!e)}function k(b){var c=[],d={},f=[];a.a.K(b,function D(e){if(!d[e]){var k=a.getBindingHandler(e);k&&(k.after&&
56
- (f.push(e),a.a.n(k.after,function(c){if(b[c]){if(-1!==a.a.l(f,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+f.join(", "));D(c)}}),f.pop()),c.push({key:e,bb:k}));d[e]=!0}});return c}function m(b,d,f,g){var h=a.a.f.get(b,s);if(!d){if(h)throw Error("You cannot apply bindings multiple times to the same element.");a.a.f.set(b,s,!0)}!h&&g&&a.rb(b,f);var m;if(d&&"function"!==typeof d)m=d;else{var p=a.H.instance,l=p.getBindingAccessors||e;if(d||f.A){var A=
57
- a.h(function(){(m=d?d(f,b):l.call(p,b,f))&&f.A&&f.A();return m},null,{I:b});m&&A.aa()||(A=null)}else m=a.i.p(l,p,[b,f])}var u;if(m){var w=A?function(a){return function(){return c(A()[a])}}:function(a){return m[a]},y=function(){return a.a.Da(A?A():m,c)};y.get=function(a){return m[a]&&c(w(a))};y.has=function(a){return a in m};g=k(m);a.a.n(g,function(c){var d=c.bb.init,e=c.bb.update,k=c.key;if(8===b.nodeType&&!a.e.P[k])throw Error("The binding '"+k+"' cannot be used with virtual elements");try{"function"==
58
- typeof d&&a.i.p(function(){var a=d(b,w(k),y,f.$data,f);if(a&&a.controlsDescendantBindings){if(u!==q)throw Error("Multiple bindings ("+u+" and "+k+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");u=k}}),"function"==typeof e&&a.h(function(){e(b,w(k),y,f.$data,f)},null,{I:b})}catch(g){throw g.message='Unable to process binding "'+k+": "+m[k]+'"\nMessage: '+g.message,g;}})}return{shouldBindDescendants:u===q}}function f(b){return b&&
59
- b instanceof a.G?b:new a.G(b)}a.d={};var p={script:!0};a.getBindingHandler=function(b){return a.d[b]};a.G=function(b,c,d,f){var e=this,k="function"==typeof b,g,h=a.h(function(){var g=k?b():b;c?(c.A&&c.A(),a.a.extend(e,c),h&&(e.A=h)):(e.$parents=[],e.$root=g,e.ko=a);e.$rawData=b;e.$data=g;d&&(e[d]=g);f&&f(e,c,g);return e.$data},null,{ua:function(){return g&&!a.a.Ra(g)},I:!0});h.aa()&&(e.A=h,h.equalityComparer=null,g=[],h.wb=function(b){g.push(b);a.a.C.ea(b,function(b){a.a.ia(g,b);g.length||(h.B(),
60
- e.A=h=q)})})};a.G.prototype.createChildContext=function(b,c,d){return new a.G(b,this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)})};a.G.prototype.extend=function(b){return new a.G(this.$rawData,this,null,function(c){a.a.extend(c,"function"==typeof b?b():b)})};var s=a.a.f.D(),l=a.a.f.D();a.rb=function(b,c){if(2==arguments.length)a.a.f.set(b,l,c),c.A&&c.A.wb(b);else return a.a.f.get(b,l)};a.pa=function(b,c,d){1===b.nodeType&&
61
- a.e.ib(b);return m(b,c,f(d),!0)};a.xb=function(c,e,k){k=f(k);return a.pa(c,"function"===typeof e?d(e.bind(null,k,c)):a.a.Da(e,b),k)};a.Ta=function(a,b){1!==b.nodeType&&8!==b.nodeType||g(f(a),b,!0)};a.Sa=function(a,b){if(b&&1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");b=b||y.document.body;h(f(a),b,!0)};a.ta=function(b){switch(b.nodeType){case 1:case 8:var c=a.rb(b);if(c)return c;if(b.parentNode)return a.ta(b.parentNode)}return q};
62
- a.Cb=function(b){return(b=a.ta(b))?b.$data:q};a.b("bindingHandlers",a.d);a.b("applyBindings",a.Sa);a.b("applyBindingsToDescendants",a.Ta);a.b("applyBindingAccessorsToNode",a.pa);a.b("applyBindingsToNode",a.xb);a.b("contextFor",a.ta);a.b("dataFor",a.Cb)})();var M={"class":"className","for":"htmlFor"};a.d.attr={update:function(b,c){var d=a.a.c(c())||{};a.a.K(d,function(c,d){d=a.a.c(d);var h=!1===d||null===d||d===q;h&&b.removeAttribute(c);8>=a.a.ja&&c in M?(c=M[c],h?b.removeAttribute(c):b[c]=d):h||b.setAttribute(c,
63
- d.toString());"name"===c&&a.a.pb(b,h?"":d.toString())})}};(function(){a.d.checked={after:["value","attr"],init:function(b,c,d){function e(){return d.has("checkedValue")?a.a.c(d.get("checkedValue")):b.value}function g(){var k=b.checked,g=s?e():k;if(l&&(!m||k)){var h=a.i.p(c);f?p!==g?(k&&(a.a.V(h,g,!0),a.a.V(h,p,!1)),p=g):a.a.V(h,g,k):a.g.oa(h,d,"checked",g,!0)}}function h(){var d=a.a.c(c());b.checked=f?0<=a.a.l(d,e()):k?d:e()===d}var k="checkbox"==b.type,m="radio"==b.type;if(k||m){var f=k&&a.a.c(c())instanceof
64
- Array,p=f?e():q,s=m||f,l=!1;m&&!b.name&&a.d.uniqueName.init(b,function(){return!0});a.h(g,null,{I:b});a.a.r(b,"click",g);a.h(h,null,{I:b});l=!0}}};a.g.U.checked=!0;a.d.checkedValue={update:function(b,c){b.value=a.a.c(c())}}})();a.d.css={update:function(b,c){var d=a.a.c(c());"object"==typeof d?a.a.K(d,function(c,d){d=a.a.c(d);a.a.ma(b,c,d)}):(d=String(d||""),a.a.ma(b,b.__ko__cssValue,!1),b.__ko__cssValue=d,a.a.ma(b,d,!0))}};a.d.enable={update:function(b,c){var d=a.a.c(c());d&&b.disabled?b.removeAttribute("disabled"):
65
- d||b.disabled||(b.disabled=!0)}};a.d.disable={update:function(b,c){a.d.enable.update(b,function(){return!a.a.c(c())})}};a.d.event={init:function(b,c,d,e,g){var h=c()||{};a.a.K(h,function(k){"string"==typeof k&&a.a.r(b,k,function(b){var f,h=c()[k];if(h){try{var s=a.a.Q(arguments);e=g.$data;s.unshift(e);f=h.apply(e,s)}finally{!0!==f&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}!1===d.get(k+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.d.foreach={hb:function(b){return function(){var c=
66
- b(),d=a.a.Ha(c);if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.J.Aa};a.a.c(c);return{foreach:d.data,as:d.as,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.J.Aa}}},init:function(b,c){return a.d.template.init(b,a.d.foreach.hb(c))},update:function(b,c,d,e,g){return a.d.template.update(b,a.d.foreach.hb(c),d,e,g)}};a.g.Y.foreach=!1;a.e.P.foreach=!0;a.d.hasfocus=
67
- {init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var g=b.ownerDocument;if("activeElement"in g){var f;try{f=g.activeElement}catch(h){f=g.body}e=f===b}g=c();a.g.oa(g,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var g=e.bind(null,!0),h=e.bind(null,!1);a.a.r(b,"focus",g);a.a.r(b,"focusin",g);a.a.r(b,"blur",h);a.a.r(b,"focusout",h)},update:function(b,c){var d=!!a.a.c(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===d||(d?b.focus():b.blur(),a.i.p(a.a.da,
68
- null,[b,d?"focusin":"focusout"]))}};a.g.U.hasfocus=!0;a.d.hasFocus=a.d.hasfocus;a.g.U.hasFocus=!0;a.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Ka(b,c())}};var L=a.a.f.D();H("if");H("ifnot",!1,!0);H("with",!0,!1,function(a,c){return a.createChildContext(c)});a.d.options={init:function(b){if("select"!==a.a.v(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,
69
- c,d){function e(){return a.a.ga(b.options,function(a){return a.selected})}function g(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function h(c,d){if(p.length){var f=0<=a.a.l(p,a.k.o(d[0]));a.a.qb(d[0],f);l&&!f&&a.i.p(a.a.da,null,[b,"change"])}}var k=0!=b.length&&b.multiple?b.scrollTop:null;c=a.a.c(c());var m=d.get("optionsIncludeDestroyed"),f={},p;p=b.multiple?a.a.ha(e(),a.k.o):0<=b.selectedIndex?[a.k.o(b.options[b.selectedIndex])]:[];if(c){"undefined"==typeof c.length&&(c=[c]);
70
- var s=a.a.ga(c,function(b){return m||b===q||null===b||!a.a.c(b._destroy)});d.has("optionsCaption")&&(c=a.a.c(d.get("optionsCaption")),null!==c&&c!==q&&s.unshift(f))}else c=[];var l=!1;c=h;d.has("optionsAfterRender")&&(c=function(b,c){h(0,c);a.i.p(d.get("optionsAfterRender"),null,[c[0],b!==f?b:q])});a.a.Ja(b,s,function(b,c,e){e.length&&(p=e[0].selected?[a.k.o(e[0])]:[],l=!0);c=w.createElement("option");b===f?(a.a.Ma(c,d.get("optionsCaption")),a.k.na(c,q)):(e=g(b,d.get("optionsValue"),b),a.k.na(c,a.a.c(e)),
71
- b=g(b,d.get("optionsText"),e),a.a.Ma(c,b));return[c]},null,c);(b.multiple?p.length&&e().length<p.length:p.length&&0<=b.selectedIndex?a.k.o(b.options[b.selectedIndex])!==p[0]:p.length||0<=b.selectedIndex)&&a.i.p(a.a.da,null,[b,"change"]);a.a.Hb(b);k&&20<Math.abs(k-b.scrollTop)&&(b.scrollTop=k)}};a.d.options.Ea=a.a.f.D();a.d.selectedOptions={after:["options","foreach"],init:function(b,c,d){a.a.r(b,"change",function(){var e=c(),g=[];a.a.n(b.getElementsByTagName("option"),function(b){b.selected&&g.push(a.k.o(b))});
72
- a.g.oa(e,d,"selectedOptions",g)})},update:function(b,c){if("select"!=a.a.v(b))throw Error("values binding applies only to SELECT elements");var d=a.a.c(c());d&&"number"==typeof d.length&&a.a.n(b.getElementsByTagName("option"),function(b){var c=0<=a.a.l(d,a.k.o(b));a.a.qb(b,c)})}};a.g.U.selectedOptions=!0;a.d.style={update:function(b,c){var d=a.a.c(c()||{});a.a.K(d,function(c,d){d=a.a.c(d);b.style[c]=d||""})}};a.d.submit={init:function(b,c,d,e,g){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");
73
- a.a.r(b,"submit",function(a){var d,e=c();try{d=e.call(g.$data,b)}finally{!0!==d&&(a.preventDefault?a.preventDefault():a.returnValue=!1)}})}};a.d.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Ma(b,c())}};a.e.P.text=!0;a.d.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.d.uniqueName.Bb;a.a.pb(b,d)}}};a.d.uniqueName.Bb=0;a.d.value={after:["options","foreach"],init:function(b,c,d){function e(){k=!1;var e=c(),f=a.k.o(b);a.g.oa(e,d,"value",f)}var g=
74
- ["change"],h=d.get("valueUpdate"),k=!1;h&&("string"==typeof h&&(h=[h]),a.a.X(g,h),g=a.a.Va(g));!a.a.ja||"input"!=b.tagName.toLowerCase()||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.l(g,"propertychange")||(a.a.r(b,"propertychange",function(){k=!0}),a.a.r(b,"blur",function(){k&&e()}));a.a.n(g,function(c){var d=e;a.a.ac(c,"after")&&(d=function(){setTimeout(e,0)},c=c.substring(5));a.a.r(b,c,d)})},update:function(b,c){var d="select"===a.a.v(b),e=a.a.c(c()),g=a.k.o(b);
75
- e!==g&&(g=function(){a.k.na(b,e)},g(),d&&(e!==a.k.o(b)?a.i.p(a.a.da,null,[b,"change"]):setTimeout(g,0)))}};a.g.U.value=!0;a.d.visible={update:function(b,c){var d=a.a.c(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};(function(b){a.d[b]={init:function(c,d,e,g,h){return a.d.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,g,h)}}})("click");a.w=function(){};a.w.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");
76
- };a.w.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.w.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||w;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.m.j(d)}if(1==b.nodeType||8==b.nodeType)return new a.m.W(b);throw Error("Unknown template type: "+b);};a.w.prototype.renderTemplate=function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,
77
- d)};a.w.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.w.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.w);a.Oa=function(){function b(b,c,d,k){b=a.g.Ga(b);for(var m=a.g.Y,f=0;f<b.length;f++){var p=b[f].key;if(m.hasOwnProperty(p)){var s=m[p];if("function"===typeof s){if(p=s(b[f].value))throw Error(p);}else if(!s)throw Error("This template engine does not support the '"+
78
- p+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.g.ka(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return k.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{Ib:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.Oa.Ub(b,c)},
79
- d)},Ub:function(a,g){return a.replace(c,function(a,c,d,f,e){return b(e,c,d,g)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",g)})},yb:function(b,c){return a.u.Ca(function(d,k){var m=d.nextSibling;m&&m.nodeName.toLowerCase()===c&&a.pa(m,b,k)})}}}();a.b("__tr_ambtns",a.Oa.yb);(function(){a.m={};a.m.j=function(a){this.j=a};a.m.j.prototype.text=function(){var b=a.a.v(this.j),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.j[b];var c=arguments[0];
80
- "innerHTML"===b?a.a.Ka(this.j,c):this.j[b]=c};var b=a.a.f.D()+"_";a.m.j.prototype.data=function(c){if(1===arguments.length)return a.a.f.get(this.j,b+c);a.a.f.set(this.j,b+c,arguments[1])};var c=a.a.f.D();a.m.W=function(a){this.j=a};a.m.W.prototype=new a.m.j;a.m.W.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.j,c)||{};b.Pa===q&&b.sa&&(b.Pa=b.sa.innerHTML);return b.Pa}a.a.f.set(this.j,c,{Pa:arguments[0]})};a.m.j.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.j,
81
- c)||{}).sa;a.a.f.set(this.j,c,{sa:arguments[0]})};a.b("templateSources",a.m);a.b("templateSources.domElement",a.m.j);a.b("templateSources.anonymousTemplate",a.m.W)})();(function(){function b(b,c,d){var e;for(c=a.e.nextSibling(c);b&&(e=b)!==c;)b=a.e.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var f=c[0],e=c[c.length-1],g=f.parentNode,h=a.H.instance,n=h.preprocessNode;if(n){b(f,e,function(a,b){var c=a.previousSibling,d=n.call(h,a);d&&(a===f&&(f=d[0]||b),a===e&&(e=d[d.length-1]||c))});c.length=
82
- 0;if(!f)return;f===e?c.push(f):(c.push(f,e),a.a.$(c,g))}b(f,e,function(b){1!==b.nodeType&&8!==b.nodeType||a.Sa(d,b)});b(f,e,function(b){1!==b.nodeType&&8!==b.nodeType||a.u.vb(b,[d])});a.a.$(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,f,h,s){s=s||{};var l=b&&d(b),l=l&&l.ownerDocument,n=s.templateEngine||g;a.Oa.Ib(f,n,l);f=n.renderTemplate(f,h,s,l);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");
83
- l=!1;switch(e){case "replaceChildren":a.e.S(b,f);l=!0;break;case "replaceNode":a.a.nb(b,f);l=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}l&&(c(f,h),s.afterRender&&a.i.p(s.afterRender,null,[f,h.$data]));return f}var g;a.La=function(b){if(b!=q&&!(b instanceof a.w))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.Ia=function(b,c,f,h,s){f=f||{};if((f.templateEngine||g)==q)throw Error("Set a template engine before calling renderTemplate");
84
- s=s||"replaceChildren";if(h){var l=d(h);return a.h(function(){var g=c&&c instanceof a.G?c:new a.G(a.a.c(c)),r="function"==typeof b?b(g.$data,g):b,g=e(h,s,r,g,f);"replaceNode"==s&&(h=g,l=d(h))},null,{ua:function(){return!l||!a.a.va(l)},I:l&&"replaceNode"==s?l.parentNode:l})}return a.u.Ca(function(d){a.Ia(b,c,f,d,"replaceNode")})};a.$b=function(b,d,f,g,h){function l(a,b){c(b,r);f.afterRender&&f.afterRender(b,a)}function n(a,c){r=h.createChildContext(a,f.as,function(a){a.$index=c});var d="function"==
85
- typeof b?b(a,r):b;return e(null,"ignoreTargetNode",d,r,f)}var r;return a.h(function(){var b=a.a.c(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.ga(b,function(b){return f.includeDestroyed||b===q||null===b||!a.a.c(b._destroy)});a.i.p(a.a.Ja,null,[g,b,n,f,l])},null,{I:g})};var h=a.a.f.D();a.d.template={init:function(b,c){var d=a.a.c(c());"string"==typeof d||d.name?a.e.Z(b):(d=a.e.childNodes(b),d=a.a.Vb(d),(new a.m.W(b)).nodes(d));return{controlsDescendantBindings:!0}},update:function(b,c,d,e,g){c=
86
- a.a.c(c());d={};e=!0;var l,n=null;"string"!=typeof c&&(d=c,c=a.a.c(d.name),"if"in d&&(e=a.a.c(d["if"])),e&&"ifnot"in d&&(e=!a.a.c(d.ifnot)),l=a.a.c(d.data));"foreach"in d?n=a.$b(c||b,e&&d.foreach||[],d,b,g):e?(g="data"in d?g.createChildContext(l,d.as):g,n=a.Ia(c||b,g,d,b)):a.e.Z(b);g=n;(l=a.a.f.get(b,h))&&"function"==typeof l.B&&l.B();a.a.f.set(b,h,g&&g.aa()?g:q)}};a.g.Y.template=function(b){b=a.g.Ga(b);return 1==b.length&&b[0].unknown||a.g.Sb(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};
87
- a.e.P.template=!0})();a.b("setTemplateEngine",a.La);a.b("renderTemplate",a.Ia);a.a.ra=function(){function a(b,d,e,g,h){var k=Math.min,m=Math.max,f=[],p,q=b.length,l,n=d.length,r=n-q||1,v=q+n+1,t,u,w;for(p=0;p<=q;p++)for(u=t,f.push(t=[]),w=k(n,p+r),l=m(0,p-1);l<=w;l++)t[l]=l?p?b[p-1]===d[l-1]?u[l-1]:k(u[l]||v,t[l-1]||v)+1:l+1:p+1;k=[];m=[];r=[];p=q;for(l=n;p||l;)n=f[p][l]-1,l&&n===f[p][l-1]?m.push(k[k.length]={status:e,value:d[--l],index:l}):p&&n===f[p-1][l]?r.push(k[k.length]={status:g,value:b[--p],
88
- index:p}):(--l,--p,h.sparse||k.push({status:"retained",value:d[l]}));if(m.length&&r.length){b=10*q;var z;for(d=e=0;(h.dontLimitMoves||d<b)&&(z=m[e]);e++){for(g=0;f=r[g];g++)if(z.value===f.value){z.moved=f.index;f.moved=z.index;r.splice(g,1);d=g=0;break}d+=g}}return k.reverse()}return function(c,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};c=c||[];d=d||[];return c.length<=d.length?a(c,d,"added","deleted",e):a(d,c,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.ra);(function(){function b(b,
89
- c,g,h,k){var m=[],f=a.h(function(){var f=c(g,k,a.a.$(m,b))||[];0<m.length&&(a.a.nb(m,f),h&&a.i.p(h,null,[g,f,k]));m.splice(0,m.length);a.a.X(m,f)},null,{I:b,ua:function(){return!a.a.Ra(m)}});return{R:m,h:f.aa()?f:q}}var c=a.a.f.D();a.a.Ja=function(d,e,g,h,k){function m(b,c){x=s[c];t!==c&&(z[b]=x);x.za(t++);a.a.$(x.R,d);r.push(x);w.push(x)}function f(b,c){if(b)for(var d=0,e=c.length;d<e;d++)c[d]&&a.a.n(c[d].R,function(a){b(a,d,c[d].fa)})}e=e||[];h=h||{};var p=a.a.f.get(d,c)===q,s=a.a.f.get(d,c)||[],
90
- l=a.a.ha(s,function(a){return a.fa}),n=a.a.ra(l,e,h.dontLimitMoves),r=[],v=0,t=0,u=[],w=[];e=[];for(var z=[],l=[],x,A=0,y,B;y=n[A];A++)switch(B=y.moved,y.status){case "deleted":B===q&&(x=s[v],x.h&&x.h.B(),u.push.apply(u,a.a.$(x.R,d)),h.beforeRemove&&(e[A]=x,w.push(x)));v++;break;case "retained":m(A,v++);break;case "added":B!==q?m(A,B):(x={fa:y.value,za:a.q(t++)},r.push(x),w.push(x),p||(l[A]=x))}f(h.beforeMove,z);a.a.n(u,h.beforeRemove?a.L:a.removeNode);for(var A=0,p=a.e.firstChild(d),C;x=w[A];A++){x.R||
91
- a.a.extend(x,b(d,g,x.fa,k,x.za));for(v=0;n=x.R[v];p=n.nextSibling,C=n,v++)n!==p&&a.e.eb(d,n,C);!x.Ob&&k&&(k(x.fa,x.R,x.za),x.Ob=!0)}f(h.beforeRemove,e);f(h.afterMove,z);f(h.afterAdd,l);a.a.f.set(d,c,r)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Ja);a.J=function(){this.allowTemplateRewriting=!1};a.J.prototype=new a.w;a.J.prototype.renderTemplateSource=function(b){var c=(9>a.a.ja?0:b.nodes)?b.nodes():null;if(c)return a.a.Q(c.cloneNode(!0).childNodes);b=b.text();return a.a.Fa(b)};a.J.Aa=
92
- new a.J;a.La(a.J.Aa);a.b("nativeTemplateEngine",a.J);(function(){a.Ba=function(){var a=this.Rb=function(){if("undefined"==typeof u||!u.tmpl)return 0;try{if(0<=u.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,e,g){g=g||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=u.template(null,"{{ko_with $item.koBindingContext}}"+h+
93
- "{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=u.extend({koBindingContext:e},g.templateOptions);e=u.tmpl(h,b,e);e.appendTo(w.createElement("div"));u.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){w.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(u.tmpl.tag.ko_code={open:"__.push($1 || '');"},u.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.Ba.prototype=
94
- new a.w;var b=new a.Ba;0<b.Rb&&a.La(b);a.b("jqueryTmplTemplateEngine",a.Ba)})()})})();})();
5
+ (function(){
6
+ var DEBUG=true;
7
+ (function(undefined){
8
+ // (0, eval)('this') is a robust way of getting a reference to the global object
9
+ // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023
10
+ var window = this || (0, eval)('this'),
11
+ document = window['document'],
12
+ navigator = window['navigator'],
13
+ jQuery = window["jQuery"],
14
+ JSON = window["JSON"];
15
+ (function(factory) {
16
+ // Support three module loading scenarios
17
+ if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
18
+ // [1] CommonJS/Node.js
19
+ var target = module['exports'] || exports; // module.exports is for Node.js
20
+ factory(target);
21
+ } else if (typeof define === 'function' && define['amd']) {
22
+ // [2] AMD anonymous module
23
+ define(['exports'], factory);
24
+ } else {
25
+ // [3] No module loader (plain <script> tag) - put directly in global namespace
26
+ factory(window['ko'] = {});
27
+ }
28
+ }(function(koExports){
29
+ // Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
30
+ // In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
31
+ var ko = typeof koExports !== 'undefined' ? koExports : {};
32
+ // Google Closure Compiler helpers (used only to make the minified file smaller)
33
+ ko.exportSymbol = function(koPath, object) {
34
+ var tokens = koPath.split(".");
35
+
36
+ // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
37
+ // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
38
+ var target = ko;
39
+
40
+ for (var i = 0; i < tokens.length - 1; i++)
41
+ target = target[tokens[i]];
42
+ target[tokens[tokens.length - 1]] = object;
43
+ };
44
+ ko.exportProperty = function(owner, publicName, object) {
45
+ owner[publicName] = object;
46
+ };
47
+ ko.version = "3.1.0";
48
+
49
+ ko.exportSymbol('version', ko.version);
50
+ ko.utils = (function () {
51
+ function objectForEach(obj, action) {
52
+ for (var prop in obj) {
53
+ if (obj.hasOwnProperty(prop)) {
54
+ action(prop, obj[prop]);
55
+ }
56
+ }
57
+ }
58
+
59
+ function extend(target, source) {
60
+ if (source) {
61
+ for(var prop in source) {
62
+ if(source.hasOwnProperty(prop)) {
63
+ target[prop] = source[prop];
64
+ }
65
+ }
66
+ }
67
+ return target;
68
+ }
69
+
70
+ function setPrototypeOf(obj, proto) {
71
+ obj.__proto__ = proto;
72
+ return obj;
73
+ }
74
+
75
+ var canSetPrototype = ({ __proto__: [] } instanceof Array);
76
+
77
+ // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
78
+ var knownEvents = {}, knownEventTypesByEventName = {};
79
+ var keyEventTypeName = (navigator && /Firefox\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';
80
+ knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
81
+ knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
82
+ objectForEach(knownEvents, function(eventType, knownEventsForType) {
83
+ if (knownEventsForType.length) {
84
+ for (var i = 0, j = knownEventsForType.length; i < j; i++)
85
+ knownEventTypesByEventName[knownEventsForType[i]] = eventType;
86
+ }
87
+ });
88
+ var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
89
+
90
+ // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
91
+ // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
92
+ // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
93
+ // If there is a future need to detect specific versions of IE10+, we will amend this.
94
+ var ieVersion = document && (function() {
95
+ var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
96
+
97
+ // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
98
+ while (
99
+ div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
100
+ iElems[0]
101
+ ) {}
102
+ return version > 4 ? version : undefined;
103
+ }());
104
+ var isIe6 = ieVersion === 6,
105
+ isIe7 = ieVersion === 7;
106
+
107
+ function isClickOnCheckableElement(element, eventType) {
108
+ if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
109
+ if (eventType.toLowerCase() != "click") return false;
110
+ var inputType = element.type;
111
+ return (inputType == "checkbox") || (inputType == "radio");
112
+ }
113
+
114
+ return {
115
+ fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
116
+
117
+ arrayForEach: function (array, action) {
118
+ for (var i = 0, j = array.length; i < j; i++)
119
+ action(array[i], i);
120
+ },
121
+
122
+ arrayIndexOf: function (array, item) {
123
+ if (typeof Array.prototype.indexOf == "function")
124
+ return Array.prototype.indexOf.call(array, item);
125
+ for (var i = 0, j = array.length; i < j; i++)
126
+ if (array[i] === item)
127
+ return i;
128
+ return -1;
129
+ },
130
+
131
+ arrayFirst: function (array, predicate, predicateOwner) {
132
+ for (var i = 0, j = array.length; i < j; i++)
133
+ if (predicate.call(predicateOwner, array[i], i))
134
+ return array[i];
135
+ return null;
136
+ },
137
+
138
+ arrayRemoveItem: function (array, itemToRemove) {
139
+ var index = ko.utils.arrayIndexOf(array, itemToRemove);
140
+ if (index > 0) {
141
+ array.splice(index, 1);
142
+ }
143
+ else if (index === 0) {
144
+ array.shift();
145
+ }
146
+ },
147
+
148
+ arrayGetDistinctValues: function (array) {
149
+ array = array || [];
150
+ var result = [];
151
+ for (var i = 0, j = array.length; i < j; i++) {
152
+ if (ko.utils.arrayIndexOf(result, array[i]) < 0)
153
+ result.push(array[i]);
154
+ }
155
+ return result;
156
+ },
157
+
158
+ arrayMap: function (array, mapping) {
159
+ array = array || [];
160
+ var result = [];
161
+ for (var i = 0, j = array.length; i < j; i++)
162
+ result.push(mapping(array[i], i));
163
+ return result;
164
+ },
165
+
166
+ arrayFilter: function (array, predicate) {
167
+ array = array || [];
168
+ var result = [];
169
+ for (var i = 0, j = array.length; i < j; i++)
170
+ if (predicate(array[i], i))
171
+ result.push(array[i]);
172
+ return result;
173
+ },
174
+
175
+ arrayPushAll: function (array, valuesToPush) {
176
+ if (valuesToPush instanceof Array)
177
+ array.push.apply(array, valuesToPush);
178
+ else
179
+ for (var i = 0, j = valuesToPush.length; i < j; i++)
180
+ array.push(valuesToPush[i]);
181
+ return array;
182
+ },
183
+
184
+ addOrRemoveItem: function(array, value, included) {
185
+ var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);
186
+ if (existingEntryIndex < 0) {
187
+ if (included)
188
+ array.push(value);
189
+ } else {
190
+ if (!included)
191
+ array.splice(existingEntryIndex, 1);
192
+ }
193
+ },
194
+
195
+ canSetPrototype: canSetPrototype,
196
+
197
+ extend: extend,
198
+
199
+ setPrototypeOf: setPrototypeOf,
200
+
201
+ setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,
202
+
203
+ objectForEach: objectForEach,
204
+
205
+ objectMap: function(source, mapping) {
206
+ if (!source)
207
+ return source;
208
+ var target = {};
209
+ for (var prop in source) {
210
+ if (source.hasOwnProperty(prop)) {
211
+ target[prop] = mapping(source[prop], prop, source);
212
+ }
213
+ }
214
+ return target;
215
+ },
216
+
217
+ emptyDomNode: function (domNode) {
218
+ while (domNode.firstChild) {
219
+ ko.removeNode(domNode.firstChild);
220
+ }
221
+ },
222
+
223
+ moveCleanedNodesToContainerElement: function(nodes) {
224
+ // Ensure it's a real array, as we're about to reparent the nodes and
225
+ // we don't want the underlying collection to change while we're doing that.
226
+ var nodesArray = ko.utils.makeArray(nodes);
227
+
228
+ var container = document.createElement('div');
229
+ for (var i = 0, j = nodesArray.length; i < j; i++) {
230
+ container.appendChild(ko.cleanNode(nodesArray[i]));
231
+ }
232
+ return container;
233
+ },
234
+
235
+ cloneNodes: function (nodesArray, shouldCleanNodes) {
236
+ for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
237
+ var clonedNode = nodesArray[i].cloneNode(true);
238
+ newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
239
+ }
240
+ return newNodesArray;
241
+ },
242
+
243
+ setDomNodeChildren: function (domNode, childNodes) {
244
+ ko.utils.emptyDomNode(domNode);
245
+ if (childNodes) {
246
+ for (var i = 0, j = childNodes.length; i < j; i++)
247
+ domNode.appendChild(childNodes[i]);
248
+ }
249
+ },
250
+
251
+ replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
252
+ var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
253
+ if (nodesToReplaceArray.length > 0) {
254
+ var insertionPoint = nodesToReplaceArray[0];
255
+ var parent = insertionPoint.parentNode;
256
+ for (var i = 0, j = newNodesArray.length; i < j; i++)
257
+ parent.insertBefore(newNodesArray[i], insertionPoint);
258
+ for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
259
+ ko.removeNode(nodesToReplaceArray[i]);
260
+ }
261
+ }
262
+ },
263
+
264
+ fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {
265
+ // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile
266
+ // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that
267
+ // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
268
+ // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
269
+ // So, this function translates the old "map" output array into its best guess of the set of current DOM nodes.
270
+ //
271
+ // Rules:
272
+ // [A] Any leading nodes that have been removed should be ignored
273
+ // These most likely correspond to memoization nodes that were already removed during binding
274
+ // See https://github.com/SteveSanderson/knockout/pull/440
275
+ // [B] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,
276
+ // and include any nodes that have been inserted among the previous collection
277
+
278
+ if (continuousNodeArray.length) {
279
+ // The parent node can be a virtual element; so get the real parent node
280
+ parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;
281
+
282
+ // Rule [A]
283
+ while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
284
+ continuousNodeArray.shift();
285
+
286
+ // Rule [B]
287
+ if (continuousNodeArray.length > 1) {
288
+ var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];
289
+ // Replace with the actual new continuous node set
290
+ continuousNodeArray.length = 0;
291
+ while (current !== last) {
292
+ continuousNodeArray.push(current);
293
+ current = current.nextSibling;
294
+ if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
295
+ return;
296
+ }
297
+ continuousNodeArray.push(last);
298
+ }
299
+ }
300
+ return continuousNodeArray;
301
+ },
302
+
303
+ setOptionNodeSelectionState: function (optionNode, isSelected) {
304
+ // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
305
+ if (ieVersion < 7)
306
+ optionNode.setAttribute("selected", isSelected);
307
+ else
308
+ optionNode.selected = isSelected;
309
+ },
310
+
311
+ stringTrim: function (string) {
312
+ return string === null || string === undefined ? '' :
313
+ string.trim ?
314
+ string.trim() :
315
+ string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
316
+ },
317
+
318
+ stringTokenize: function (string, delimiter) {
319
+ var result = [];
320
+ var tokens = (string || "").split(delimiter);
321
+ for (var i = 0, j = tokens.length; i < j; i++) {
322
+ var trimmed = ko.utils.stringTrim(tokens[i]);
323
+ if (trimmed !== "")
324
+ result.push(trimmed);
325
+ }
326
+ return result;
327
+ },
328
+
329
+ stringStartsWith: function (string, startsWith) {
330
+ string = string || "";
331
+ if (startsWith.length > string.length)
332
+ return false;
333
+ return string.substring(0, startsWith.length) === startsWith;
334
+ },
335
+
336
+ domNodeIsContainedBy: function (node, containedByNode) {
337
+ if (node === containedByNode)
338
+ return true;
339
+ if (node.nodeType === 11)
340
+ return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8
341
+ if (containedByNode.contains)
342
+ return containedByNode.contains(node.nodeType === 3 ? node.parentNode : node);
343
+ if (containedByNode.compareDocumentPosition)
344
+ return (containedByNode.compareDocumentPosition(node) & 16) == 16;
345
+ while (node && node != containedByNode) {
346
+ node = node.parentNode;
347
+ }
348
+ return !!node;
349
+ },
350
+
351
+ domNodeIsAttachedToDocument: function (node) {
352
+ return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);
353
+ },
354
+
355
+ anyDomNodeIsAttachedToDocument: function(nodes) {
356
+ return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);
357
+ },
358
+
359
+ tagNameLower: function(element) {
360
+ // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
361
+ // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
362
+ // we don't need to do the .toLowerCase() as it will always be lower case anyway.
363
+ return element && element.tagName && element.tagName.toLowerCase();
364
+ },
365
+
366
+ registerEventHandler: function (element, eventType, handler) {
367
+ var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
368
+ if (!mustUseAttachEvent && jQuery) {
369
+ jQuery(element)['bind'](eventType, handler);
370
+ } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
371
+ element.addEventListener(eventType, handler, false);
372
+ else if (typeof element.attachEvent != "undefined") {
373
+ var attachEventHandler = function (event) { handler.call(element, event); },
374
+ attachEventName = "on" + eventType;
375
+ element.attachEvent(attachEventName, attachEventHandler);
376
+
377
+ // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)
378
+ // so to avoid leaks, we have to remove them manually. See bug #856
379
+ ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
380
+ element.detachEvent(attachEventName, attachEventHandler);
381
+ });
382
+ } else
383
+ throw new Error("Browser doesn't support addEventListener or attachEvent");
384
+ },
385
+
386
+ triggerEvent: function (element, eventType) {
387
+ if (!(element && element.nodeType))
388
+ throw new Error("element must be a DOM node when calling triggerEvent");
389
+
390
+ // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the
391
+ // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)
392
+ // IE doesn't change the checked state when you trigger the click event using "fireEvent".
393
+ // In both cases, we'll use the click method instead.
394
+ var useClickWorkaround = isClickOnCheckableElement(element, eventType);
395
+
396
+ if (jQuery && !useClickWorkaround) {
397
+ jQuery(element)['trigger'](eventType);
398
+ } else if (typeof document.createEvent == "function") {
399
+ if (typeof element.dispatchEvent == "function") {
400
+ var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
401
+ var event = document.createEvent(eventCategory);
402
+ event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
403
+ element.dispatchEvent(event);
404
+ }
405
+ else
406
+ throw new Error("The supplied element doesn't support dispatchEvent");
407
+ } else if (useClickWorkaround && element.click) {
408
+ element.click();
409
+ } else if (typeof element.fireEvent != "undefined") {
410
+ element.fireEvent("on" + eventType);
411
+ } else {
412
+ throw new Error("Browser doesn't support triggering events");
413
+ }
414
+ },
415
+
416
+ unwrapObservable: function (value) {
417
+ return ko.isObservable(value) ? value() : value;
418
+ },
419
+
420
+ peekObservable: function (value) {
421
+ return ko.isObservable(value) ? value.peek() : value;
422
+ },
423
+
424
+ toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
425
+ if (classNames) {
426
+ var cssClassNameRegex = /\S+/g,
427
+ currentClassNames = node.className.match(cssClassNameRegex) || [];
428
+ ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
429
+ ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);
430
+ });
431
+ node.className = currentClassNames.join(" ");
432
+ }
433
+ },
434
+
435
+ setTextContent: function(element, textContent) {
436
+ var value = ko.utils.unwrapObservable(textContent);
437
+ if ((value === null) || (value === undefined))
438
+ value = "";
439
+
440
+ // We need there to be exactly one child: a text node.
441
+ // If there are no children, more than one, or if it's not a text node,
442
+ // we'll clear everything and create a single text node.
443
+ var innerTextNode = ko.virtualElements.firstChild(element);
444
+ if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
445
+ ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);
446
+ } else {
447
+ innerTextNode.data = value;
448
+ }
449
+
450
+ ko.utils.forceRefresh(element);
451
+ },
452
+
453
+ setElementName: function(element, name) {
454
+ element.name = name;
455
+
456
+ // Workaround IE 6/7 issue
457
+ // - https://github.com/SteveSanderson/knockout/issues/197
458
+ // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
459
+ if (ieVersion <= 7) {
460
+ try {
461
+ element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
462
+ }
463
+ catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
464
+ }
465
+ },
466
+
467
+ forceRefresh: function(node) {
468
+ // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
469
+ if (ieVersion >= 9) {
470
+ // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
471
+ var elem = node.nodeType == 1 ? node : node.parentNode;
472
+ if (elem.style)
473
+ elem.style.zoom = elem.style.zoom;
474
+ }
475
+ },
476
+
477
+ ensureSelectElementIsRenderedCorrectly: function(selectElement) {
478
+ // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
479
+ // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
480
+ // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)
481
+ if (ieVersion) {
482
+ var originalWidth = selectElement.style.width;
483
+ selectElement.style.width = 0;
484
+ selectElement.style.width = originalWidth;
485
+ }
486
+ },
487
+
488
+ range: function (min, max) {
489
+ min = ko.utils.unwrapObservable(min);
490
+ max = ko.utils.unwrapObservable(max);
491
+ var result = [];
492
+ for (var i = min; i <= max; i++)
493
+ result.push(i);
494
+ return result;
495
+ },
496
+
497
+ makeArray: function(arrayLikeObject) {
498
+ var result = [];
499
+ for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
500
+ result.push(arrayLikeObject[i]);
501
+ };
502
+ return result;
503
+ },
504
+
505
+ isIe6 : isIe6,
506
+ isIe7 : isIe7,
507
+ ieVersion : ieVersion,
508
+
509
+ getFormFields: function(form, fieldName) {
510
+ var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
511
+ var isMatchingField = (typeof fieldName == 'string')
512
+ ? function(field) { return field.name === fieldName }
513
+ : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
514
+ var matches = [];
515
+ for (var i = fields.length - 1; i >= 0; i--) {
516
+ if (isMatchingField(fields[i]))
517
+ matches.push(fields[i]);
518
+ };
519
+ return matches;
520
+ },
521
+
522
+ parseJson: function (jsonString) {
523
+ if (typeof jsonString == "string") {
524
+ jsonString = ko.utils.stringTrim(jsonString);
525
+ if (jsonString) {
526
+ if (JSON && JSON.parse) // Use native parsing where available
527
+ return JSON.parse(jsonString);
528
+ return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
529
+ }
530
+ }
531
+ return null;
532
+ },
533
+
534
+ stringifyJson: function (data, replacer, space) { // replacer and space are optional
535
+ if (!JSON || !JSON.stringify)
536
+ throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
537
+ return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
538
+ },
539
+
540
+ postJson: function (urlOrForm, data, options) {
541
+ options = options || {};
542
+ var params = options['params'] || {};
543
+ var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
544
+ var url = urlOrForm;
545
+
546
+ // If we were given a form, use its 'action' URL and pick out any requested field values
547
+ if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
548
+ var originalForm = urlOrForm;
549
+ url = originalForm.action;
550
+ for (var i = includeFields.length - 1; i >= 0; i--) {
551
+ var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
552
+ for (var j = fields.length - 1; j >= 0; j--)
553
+ params[fields[j].name] = fields[j].value;
554
+ }
555
+ }
556
+
557
+ data = ko.utils.unwrapObservable(data);
558
+ var form = document.createElement("form");
559
+ form.style.display = "none";
560
+ form.action = url;
561
+ form.method = "post";
562
+ for (var key in data) {
563
+ // Since 'data' this is a model object, we include all properties including those inherited from its prototype
564
+ var input = document.createElement("input");
565
+ input.name = key;
566
+ input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
567
+ form.appendChild(input);
568
+ }
569
+ objectForEach(params, function(key, value) {
570
+ var input = document.createElement("input");
571
+ input.name = key;
572
+ input.value = value;
573
+ form.appendChild(input);
574
+ });
575
+ document.body.appendChild(form);
576
+ options['submitter'] ? options['submitter'](form) : form.submit();
577
+ setTimeout(function () { form.parentNode.removeChild(form); }, 0);
578
+ }
579
+ }
580
+ }());
581
+
582
+ ko.exportSymbol('utils', ko.utils);
583
+ ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
584
+ ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
585
+ ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
586
+ ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
587
+ ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
588
+ ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
589
+ ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
590
+ ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
591
+ ko.exportSymbol('utils.extend', ko.utils.extend);
592
+ ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
593
+ ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
594
+ ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
595
+ ko.exportSymbol('utils.postJson', ko.utils.postJson);
596
+ ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
597
+ ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
598
+ ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
599
+ ko.exportSymbol('utils.range', ko.utils.range);
600
+ ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
601
+ ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
602
+ ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
603
+ ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);
604
+ ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);
605
+ ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly
606
+
607
+ if (!Function.prototype['bind']) {
608
+ // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
609
+ // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
610
+ Function.prototype['bind'] = function (object) {
611
+ var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
612
+ return function () {
613
+ return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
614
+ };
615
+ };
616
+ }
617
+
618
+ ko.utils.domData = new (function () {
619
+ var uniqueId = 0;
620
+ var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
621
+ var dataStore = {};
622
+
623
+ function getAll(node, createIfNotFound) {
624
+ var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
625
+ var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
626
+ if (!hasExistingDataStore) {
627
+ if (!createIfNotFound)
628
+ return undefined;
629
+ dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
630
+ dataStore[dataStoreKey] = {};
631
+ }
632
+ return dataStore[dataStoreKey];
633
+ }
634
+
635
+ return {
636
+ get: function (node, key) {
637
+ var allDataForNode = getAll(node, false);
638
+ return allDataForNode === undefined ? undefined : allDataForNode[key];
639
+ },
640
+ set: function (node, key, value) {
641
+ if (value === undefined) {
642
+ // Make sure we don't actually create a new domData key if we are actually deleting a value
643
+ if (getAll(node, false) === undefined)
644
+ return;
645
+ }
646
+ var allDataForNode = getAll(node, true);
647
+ allDataForNode[key] = value;
648
+ },
649
+ clear: function (node) {
650
+ var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
651
+ if (dataStoreKey) {
652
+ delete dataStore[dataStoreKey];
653
+ node[dataStoreKeyExpandoPropertyName] = null;
654
+ return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
655
+ }
656
+ return false;
657
+ },
658
+
659
+ nextKey: function () {
660
+ return (uniqueId++) + dataStoreKeyExpandoPropertyName;
661
+ }
662
+ };
663
+ })();
664
+
665
+ ko.exportSymbol('utils.domData', ko.utils.domData);
666
+ ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
667
+
668
+ ko.utils.domNodeDisposal = new (function () {
669
+ var domDataKey = ko.utils.domData.nextKey();
670
+ var cleanableNodeTypes = { 1: true, 8: true, 9: true }; // Element, Comment, Document
671
+ var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
672
+
673
+ function getDisposeCallbacksCollection(node, createIfNotFound) {
674
+ var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
675
+ if ((allDisposeCallbacks === undefined) && createIfNotFound) {
676
+ allDisposeCallbacks = [];
677
+ ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
678
+ }
679
+ return allDisposeCallbacks;
680
+ }
681
+ function destroyCallbacksCollection(node) {
682
+ ko.utils.domData.set(node, domDataKey, undefined);
683
+ }
684
+
685
+ function cleanSingleNode(node) {
686
+ // Run all the dispose callbacks
687
+ var callbacks = getDisposeCallbacksCollection(node, false);
688
+ if (callbacks) {
689
+ callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
690
+ for (var i = 0; i < callbacks.length; i++)
691
+ callbacks[i](node);
692
+ }
693
+
694
+ // Erase the DOM data
695
+ ko.utils.domData.clear(node);
696
+
697
+ // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)
698
+ ko.utils.domNodeDisposal["cleanExternalData"](node);
699
+
700
+ // Clear any immediate-child comment nodes, as these wouldn't have been found by
701
+ // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
702
+ if (cleanableNodeTypesWithDescendants[node.nodeType])
703
+ cleanImmediateCommentTypeChildren(node);
704
+ }
705
+
706
+ function cleanImmediateCommentTypeChildren(nodeWithChildren) {
707
+ var child, nextChild = nodeWithChildren.firstChild;
708
+ while (child = nextChild) {
709
+ nextChild = child.nextSibling;
710
+ if (child.nodeType === 8)
711
+ cleanSingleNode(child);
712
+ }
713
+ }
714
+
715
+ return {
716
+ addDisposeCallback : function(node, callback) {
717
+ if (typeof callback != "function")
718
+ throw new Error("Callback must be a function");
719
+ getDisposeCallbacksCollection(node, true).push(callback);
720
+ },
721
+
722
+ removeDisposeCallback : function(node, callback) {
723
+ var callbacksCollection = getDisposeCallbacksCollection(node, false);
724
+ if (callbacksCollection) {
725
+ ko.utils.arrayRemoveItem(callbacksCollection, callback);
726
+ if (callbacksCollection.length == 0)
727
+ destroyCallbacksCollection(node);
728
+ }
729
+ },
730
+
731
+ cleanNode : function(node) {
732
+ // First clean this node, where applicable
733
+ if (cleanableNodeTypes[node.nodeType]) {
734
+ cleanSingleNode(node);
735
+
736
+ // ... then its descendants, where applicable
737
+ if (cleanableNodeTypesWithDescendants[node.nodeType]) {
738
+ // Clone the descendants list in case it changes during iteration
739
+ var descendants = [];
740
+ ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
741
+ for (var i = 0, j = descendants.length; i < j; i++)
742
+ cleanSingleNode(descendants[i]);
743
+ }
744
+ }
745
+ return node;
746
+ },
747
+
748
+ removeNode : function(node) {
749
+ ko.cleanNode(node);
750
+ if (node.parentNode)
751
+ node.parentNode.removeChild(node);
752
+ },
753
+
754
+ "cleanExternalData" : function (node) {
755
+ // Special support for jQuery here because it's so commonly used.
756
+ // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
757
+ // so notify it to tear down any resources associated with the node & descendants here.
758
+ if (jQuery && (typeof jQuery['cleanData'] == "function"))
759
+ jQuery['cleanData']([node]);
760
+ }
761
+ }
762
+ })();
763
+ ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
764
+ ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
765
+ ko.exportSymbol('cleanNode', ko.cleanNode);
766
+ ko.exportSymbol('removeNode', ko.removeNode);
767
+ ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
768
+ ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
769
+ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
770
+ (function () {
771
+ var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
772
+
773
+ function simpleHtmlParse(html) {
774
+ // Based on jQuery's "clean" function, but only accounting for table-related elements.
775
+ // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
776
+
777
+ // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
778
+ // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
779
+ // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
780
+ // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
781
+
782
+ // Trim whitespace, otherwise indexOf won't work as expected
783
+ var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
784
+
785
+ // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
786
+ var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
787
+ !tags.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] ||
788
+ (!tags.indexOf("<td") || !tags.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
789
+ /* anything else */ [0, "", ""];
790
+
791
+ // Go to html and back, then peel off extra wrappers
792
+ // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
793
+ var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
794
+ if (typeof window['innerShiv'] == "function") {
795
+ div.appendChild(window['innerShiv'](markup));
796
+ } else {
797
+ div.innerHTML = markup;
798
+ }
799
+
800
+ // Move to the right depth
801
+ while (wrap[0]--)
802
+ div = div.lastChild;
803
+
804
+ return ko.utils.makeArray(div.lastChild.childNodes);
805
+ }
806
+
807
+ function jQueryHtmlParse(html) {
808
+ // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
809
+ if (jQuery['parseHTML']) {
810
+ return jQuery['parseHTML'](html) || []; // Ensure we always return an array and never null
811
+ } else {
812
+ // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
813
+ var elems = jQuery['clean']([html]);
814
+
815
+ // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
816
+ // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
817
+ // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
818
+ if (elems && elems[0]) {
819
+ // Find the top-most parent element that's a direct child of a document fragment
820
+ var elem = elems[0];
821
+ while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
822
+ elem = elem.parentNode;
823
+ // ... then detach it
824
+ if (elem.parentNode)
825
+ elem.parentNode.removeChild(elem);
826
+ }
827
+
828
+ return elems;
829
+ }
830
+ }
831
+
832
+ ko.utils.parseHtmlFragment = function(html) {
833
+ return jQuery ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
834
+ : simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
835
+ };
836
+
837
+ ko.utils.setHtml = function(node, html) {
838
+ ko.utils.emptyDomNode(node);
839
+
840
+ // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
841
+ html = ko.utils.unwrapObservable(html);
842
+
843
+ if ((html !== null) && (html !== undefined)) {
844
+ if (typeof html != 'string')
845
+ html = html.toString();
846
+
847
+ // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
848
+ // for example <tr> elements which are not normally allowed to exist on their own.
849
+ // If you've referenced jQuery we'll use that rather than duplicating its code.
850
+ if (jQuery) {
851
+ jQuery(node)['html'](html);
852
+ } else {
853
+ // ... otherwise, use KO's own parsing logic.
854
+ var parsedNodes = ko.utils.parseHtmlFragment(html);
855
+ for (var i = 0; i < parsedNodes.length; i++)
856
+ node.appendChild(parsedNodes[i]);
857
+ }
858
+ }
859
+ };
860
+ })();
861
+
862
+ ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
863
+ ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
864
+
865
+ ko.memoization = (function () {
866
+ var memos = {};
867
+
868
+ function randomMax8HexChars() {
869
+ return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
870
+ }
871
+ function generateRandomId() {
872
+ return randomMax8HexChars() + randomMax8HexChars();
873
+ }
874
+ function findMemoNodes(rootNode, appendToArray) {
875
+ if (!rootNode)
876
+ return;
877
+ if (rootNode.nodeType == 8) {
878
+ var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
879
+ if (memoId != null)
880
+ appendToArray.push({ domNode: rootNode, memoId: memoId });
881
+ } else if (rootNode.nodeType == 1) {
882
+ for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
883
+ findMemoNodes(childNodes[i], appendToArray);
884
+ }
885
+ }
886
+
887
+ return {
888
+ memoize: function (callback) {
889
+ if (typeof callback != "function")
890
+ throw new Error("You can only pass a function to ko.memoization.memoize()");
891
+ var memoId = generateRandomId();
892
+ memos[memoId] = callback;
893
+ return "<!--[ko_memo:" + memoId + "]-->";
894
+ },
895
+
896
+ unmemoize: function (memoId, callbackParams) {
897
+ var callback = memos[memoId];
898
+ if (callback === undefined)
899
+ throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
900
+ try {
901
+ callback.apply(null, callbackParams || []);
902
+ return true;
903
+ }
904
+ finally { delete memos[memoId]; }
905
+ },
906
+
907
+ unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
908
+ var memos = [];
909
+ findMemoNodes(domNode, memos);
910
+ for (var i = 0, j = memos.length; i < j; i++) {
911
+ var node = memos[i].domNode;
912
+ var combinedParams = [node];
913
+ if (extraCallbackParamsArray)
914
+ ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
915
+ ko.memoization.unmemoize(memos[i].memoId, combinedParams);
916
+ node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
917
+ if (node.parentNode)
918
+ node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
919
+ }
920
+ },
921
+
922
+ parseMemoText: function (memoText) {
923
+ var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
924
+ return match ? match[1] : null;
925
+ }
926
+ };
927
+ })();
928
+
929
+ ko.exportSymbol('memoization', ko.memoization);
930
+ ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
931
+ ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
932
+ ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
933
+ ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
934
+ ko.extenders = {
935
+ 'throttle': function(target, timeout) {
936
+ // Throttling means two things:
937
+
938
+ // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
939
+ // notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
940
+ target['throttleEvaluation'] = timeout;
941
+
942
+ // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
943
+ // so the target cannot change value synchronously or faster than a certain rate
944
+ var writeTimeoutInstance = null;
945
+ return ko.dependentObservable({
946
+ 'read': target,
947
+ 'write': function(value) {
948
+ clearTimeout(writeTimeoutInstance);
949
+ writeTimeoutInstance = setTimeout(function() {
950
+ target(value);
951
+ }, timeout);
952
+ }
953
+ });
954
+ },
955
+
956
+ 'rateLimit': function(target, options) {
957
+ var timeout, method, limitFunction;
958
+
959
+ if (typeof options == 'number') {
960
+ timeout = options;
961
+ } else {
962
+ timeout = options['timeout'];
963
+ method = options['method'];
964
+ }
965
+
966
+ limitFunction = method == 'notifyWhenChangesStop' ? debounce : throttle;
967
+ target.limit(function(callback) {
968
+ return limitFunction(callback, timeout);
969
+ });
970
+ },
971
+
972
+ 'notify': function(target, notifyWhen) {
973
+ target["equalityComparer"] = notifyWhen == "always" ?
974
+ null : // null equalityComparer means to always notify
975
+ valuesArePrimitiveAndEqual;
976
+ }
977
+ };
978
+
979
+ var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };
980
+ function valuesArePrimitiveAndEqual(a, b) {
981
+ var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
982
+ return oldValueIsPrimitive ? (a === b) : false;
983
+ }
984
+
985
+ function throttle(callback, timeout) {
986
+ var timeoutInstance;
987
+ return function () {
988
+ if (!timeoutInstance) {
989
+ timeoutInstance = setTimeout(function() {
990
+ timeoutInstance = undefined;
991
+ callback();
992
+ }, timeout);
993
+ }
994
+ };
995
+ }
996
+
997
+ function debounce(callback, timeout) {
998
+ var timeoutInstance;
999
+ return function () {
1000
+ clearTimeout(timeoutInstance);
1001
+ timeoutInstance = setTimeout(callback, timeout);
1002
+ };
1003
+ }
1004
+
1005
+ function applyExtenders(requestedExtenders) {
1006
+ var target = this;
1007
+ if (requestedExtenders) {
1008
+ ko.utils.objectForEach(requestedExtenders, function(key, value) {
1009
+ var extenderHandler = ko.extenders[key];
1010
+ if (typeof extenderHandler == 'function') {
1011
+ target = extenderHandler(target, value) || target;
1012
+ }
1013
+ });
1014
+ }
1015
+ return target;
1016
+ }
1017
+
1018
+ ko.exportSymbol('extenders', ko.extenders);
1019
+
1020
+ ko.subscription = function (target, callback, disposeCallback) {
1021
+ this.target = target;
1022
+ this.callback = callback;
1023
+ this.disposeCallback = disposeCallback;
1024
+ this.isDisposed = false;
1025
+ ko.exportProperty(this, 'dispose', this.dispose);
1026
+ };
1027
+ ko.subscription.prototype.dispose = function () {
1028
+ this.isDisposed = true;
1029
+ this.disposeCallback();
1030
+ };
1031
+
1032
+ ko.subscribable = function () {
1033
+ ko.utils.setPrototypeOfOrExtend(this, ko.subscribable['fn']);
1034
+ this._subscriptions = {};
1035
+ }
1036
+
1037
+ var defaultEvent = "change";
1038
+
1039
+ var ko_subscribable_fn = {
1040
+ subscribe: function (callback, callbackTarget, event) {
1041
+ var self = this;
1042
+
1043
+ event = event || defaultEvent;
1044
+ var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
1045
+
1046
+ var subscription = new ko.subscription(self, boundCallback, function () {
1047
+ ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);
1048
+ });
1049
+
1050
+ // This will force a computed with deferEvaluation to evaluate before any subscriptions
1051
+ // are registered.
1052
+ if (self.peek) {
1053
+ self.peek();
1054
+ }
1055
+
1056
+ if (!self._subscriptions[event])
1057
+ self._subscriptions[event] = [];
1058
+ self._subscriptions[event].push(subscription);
1059
+ return subscription;
1060
+ },
1061
+
1062
+ "notifySubscribers": function (valueToNotify, event) {
1063
+ event = event || defaultEvent;
1064
+ if (this.hasSubscriptionsForEvent(event)) {
1065
+ try {
1066
+ ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)
1067
+ for (var a = this._subscriptions[event].slice(0), i = 0, subscription; subscription = a[i]; ++i) {
1068
+ // In case a subscription was disposed during the arrayForEach cycle, check
1069
+ // for isDisposed on each subscription before invoking its callback
1070
+ if (!subscription.isDisposed)
1071
+ subscription.callback(valueToNotify);
1072
+ }
1073
+ } finally {
1074
+ ko.dependencyDetection.end(); // End suppressing dependency detection
1075
+ }
1076
+ }
1077
+ },
1078
+
1079
+ limit: function(limitFunction) {
1080
+ var self = this, selfIsObservable = ko.isObservable(self),
1081
+ isPending, previousValue, pendingValue, beforeChange = 'beforeChange';
1082
+
1083
+ if (!self._origNotifySubscribers) {
1084
+ self._origNotifySubscribers = self["notifySubscribers"];
1085
+ self["notifySubscribers"] = function(value, event) {
1086
+ if (!event || event === defaultEvent) {
1087
+ self._rateLimitedChange(value);
1088
+ } else if (event === beforeChange) {
1089
+ self._rateLimitedBeforeChange(value);
1090
+ } else {
1091
+ self._origNotifySubscribers(value, event);
1092
+ }
1093
+ };
1094
+ }
1095
+
1096
+ var finish = limitFunction(function() {
1097
+ // If an observable provided a reference to itself, access it to get the latest value.
1098
+ // This allows computed observables to delay calculating their value until needed.
1099
+ if (selfIsObservable && pendingValue === self) {
1100
+ pendingValue = self();
1101
+ }
1102
+ isPending = false;
1103
+ if (self.isDifferent(previousValue, pendingValue)) {
1104
+ self._origNotifySubscribers(previousValue = pendingValue);
1105
+ }
1106
+ });
1107
+
1108
+ self._rateLimitedChange = function(value) {
1109
+ isPending = true;
1110
+ pendingValue = value;
1111
+ finish();
1112
+ };
1113
+ self._rateLimitedBeforeChange = function(value) {
1114
+ if (!isPending) {
1115
+ previousValue = value;
1116
+ self._origNotifySubscribers(value, beforeChange);
1117
+ }
1118
+ };
1119
+ },
1120
+
1121
+ hasSubscriptionsForEvent: function(event) {
1122
+ return this._subscriptions[event] && this._subscriptions[event].length;
1123
+ },
1124
+
1125
+ getSubscriptionsCount: function () {
1126
+ var total = 0;
1127
+ ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {
1128
+ total += subscriptions.length;
1129
+ });
1130
+ return total;
1131
+ },
1132
+
1133
+ isDifferent: function(oldValue, newValue) {
1134
+ return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);
1135
+ },
1136
+
1137
+ extend: applyExtenders
1138
+ };
1139
+
1140
+ ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);
1141
+ ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);
1142
+ ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);
1143
+
1144
+ // For browsers that support proto assignment, we overwrite the prototype of each
1145
+ // observable instance. Since observables are functions, we need Function.prototype
1146
+ // to still be in the prototype chain.
1147
+ if (ko.utils.canSetPrototype) {
1148
+ ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);
1149
+ }
1150
+
1151
+ ko.subscribable['fn'] = ko_subscribable_fn;
1152
+
1153
+
1154
+ ko.isSubscribable = function (instance) {
1155
+ return instance != null && typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
1156
+ };
1157
+
1158
+ ko.exportSymbol('subscribable', ko.subscribable);
1159
+ ko.exportSymbol('isSubscribable', ko.isSubscribable);
1160
+
1161
+ ko.computedContext = ko.dependencyDetection = (function () {
1162
+ var outerFrames = [],
1163
+ currentFrame,
1164
+ lastId = 0;
1165
+
1166
+ // Return a unique ID that can be assigned to an observable for dependency tracking.
1167
+ // Theoretically, you could eventually overflow the number storage size, resulting
1168
+ // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53
1169
+ // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would
1170
+ // take over 285 years to reach that number.
1171
+ // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html
1172
+ function getId() {
1173
+ return ++lastId;
1174
+ }
1175
+
1176
+ function begin(options) {
1177
+ outerFrames.push(currentFrame);
1178
+ currentFrame = options;
1179
+ }
1180
+
1181
+ function end() {
1182
+ currentFrame = outerFrames.pop();
1183
+ }
1184
+
1185
+ return {
1186
+ begin: begin,
1187
+
1188
+ end: end,
1189
+
1190
+ registerDependency: function (subscribable) {
1191
+ if (currentFrame) {
1192
+ if (!ko.isSubscribable(subscribable))
1193
+ throw new Error("Only subscribable things can act as dependencies");
1194
+ currentFrame.callback(subscribable, subscribable._id || (subscribable._id = getId()));
1195
+ }
1196
+ },
1197
+
1198
+ ignore: function (callback, callbackTarget, callbackArgs) {
1199
+ try {
1200
+ begin();
1201
+ return callback.apply(callbackTarget, callbackArgs || []);
1202
+ } finally {
1203
+ end();
1204
+ }
1205
+ },
1206
+
1207
+ getDependenciesCount: function () {
1208
+ if (currentFrame)
1209
+ return currentFrame.computed.getDependenciesCount();
1210
+ },
1211
+
1212
+ isInitial: function() {
1213
+ if (currentFrame)
1214
+ return currentFrame.isInitial;
1215
+ }
1216
+ };
1217
+ })();
1218
+
1219
+ ko.exportSymbol('computedContext', ko.computedContext);
1220
+ ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);
1221
+ ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);
1222
+ ko.observable = function (initialValue) {
1223
+ var _latestValue = initialValue;
1224
+
1225
+ function observable() {
1226
+ if (arguments.length > 0) {
1227
+ // Write
1228
+
1229
+ // Ignore writes if the value hasn't changed
1230
+ if (observable.isDifferent(_latestValue, arguments[0])) {
1231
+ observable.valueWillMutate();
1232
+ _latestValue = arguments[0];
1233
+ if (DEBUG) observable._latestValue = _latestValue;
1234
+ observable.valueHasMutated();
1235
+ }
1236
+ return this; // Permits chained assignments
1237
+ }
1238
+ else {
1239
+ // Read
1240
+ ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
1241
+ return _latestValue;
1242
+ }
1243
+ }
1244
+ ko.subscribable.call(observable);
1245
+ ko.utils.setPrototypeOfOrExtend(observable, ko.observable['fn']);
1246
+
1247
+ if (DEBUG) observable._latestValue = _latestValue;
1248
+ observable.peek = function() { return _latestValue };
1249
+ observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
1250
+ observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
1251
+
1252
+ ko.exportProperty(observable, 'peek', observable.peek);
1253
+ ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
1254
+ ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
1255
+
1256
+ return observable;
1257
+ }
1258
+
1259
+ ko.observable['fn'] = {
1260
+ "equalityComparer": valuesArePrimitiveAndEqual
1261
+ };
1262
+
1263
+ var protoProperty = ko.observable.protoProperty = "__ko_proto__";
1264
+ ko.observable['fn'][protoProperty] = ko.observable;
1265
+
1266
+ // Note that for browsers that don't support proto assignment, the
1267
+ // inheritance chain is created manually in the ko.observable constructor
1268
+ if (ko.utils.canSetPrototype) {
1269
+ ko.utils.setPrototypeOf(ko.observable['fn'], ko.subscribable['fn']);
1270
+ }
1271
+
1272
+ ko.hasPrototype = function(instance, prototype) {
1273
+ if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
1274
+ if (instance[protoProperty] === prototype) return true;
1275
+ return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
1276
+ };
1277
+
1278
+ ko.isObservable = function (instance) {
1279
+ return ko.hasPrototype(instance, ko.observable);
1280
+ }
1281
+ ko.isWriteableObservable = function (instance) {
1282
+ // Observable
1283
+ if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
1284
+ return true;
1285
+ // Writeable dependent observable
1286
+ if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
1287
+ return true;
1288
+ // Anything else
1289
+ return false;
1290
+ }
1291
+
1292
+
1293
+ ko.exportSymbol('observable', ko.observable);
1294
+ ko.exportSymbol('isObservable', ko.isObservable);
1295
+ ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
1296
+ ko.observableArray = function (initialValues) {
1297
+ initialValues = initialValues || [];
1298
+
1299
+ if (typeof initialValues != 'object' || !('length' in initialValues))
1300
+ throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
1301
+
1302
+ var result = ko.observable(initialValues);
1303
+ ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);
1304
+ return result.extend({'trackArrayChanges':true});
1305
+ };
1306
+
1307
+ ko.observableArray['fn'] = {
1308
+ 'remove': function (valueOrPredicate) {
1309
+ var underlyingArray = this.peek();
1310
+ var removedValues = [];
1311
+ var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
1312
+ for (var i = 0; i < underlyingArray.length; i++) {
1313
+ var value = underlyingArray[i];
1314
+ if (predicate(value)) {
1315
+ if (removedValues.length === 0) {
1316
+ this.valueWillMutate();
1317
+ }
1318
+ removedValues.push(value);
1319
+ underlyingArray.splice(i, 1);
1320
+ i--;
1321
+ }
1322
+ }
1323
+ if (removedValues.length) {
1324
+ this.valueHasMutated();
1325
+ }
1326
+ return removedValues;
1327
+ },
1328
+
1329
+ 'removeAll': function (arrayOfValues) {
1330
+ // If you passed zero args, we remove everything
1331
+ if (arrayOfValues === undefined) {
1332
+ var underlyingArray = this.peek();
1333
+ var allValues = underlyingArray.slice(0);
1334
+ this.valueWillMutate();
1335
+ underlyingArray.splice(0, underlyingArray.length);
1336
+ this.valueHasMutated();
1337
+ return allValues;
1338
+ }
1339
+ // If you passed an arg, we interpret it as an array of entries to remove
1340
+ if (!arrayOfValues)
1341
+ return [];
1342
+ return this['remove'](function (value) {
1343
+ return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
1344
+ });
1345
+ },
1346
+
1347
+ 'destroy': function (valueOrPredicate) {
1348
+ var underlyingArray = this.peek();
1349
+ var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
1350
+ this.valueWillMutate();
1351
+ for (var i = underlyingArray.length - 1; i >= 0; i--) {
1352
+ var value = underlyingArray[i];
1353
+ if (predicate(value))
1354
+ underlyingArray[i]["_destroy"] = true;
1355
+ }
1356
+ this.valueHasMutated();
1357
+ },
1358
+
1359
+ 'destroyAll': function (arrayOfValues) {
1360
+ // If you passed zero args, we destroy everything
1361
+ if (arrayOfValues === undefined)
1362
+ return this['destroy'](function() { return true });
1363
+
1364
+ // If you passed an arg, we interpret it as an array of entries to destroy
1365
+ if (!arrayOfValues)
1366
+ return [];
1367
+ return this['destroy'](function (value) {
1368
+ return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
1369
+ });
1370
+ },
1371
+
1372
+ 'indexOf': function (item) {
1373
+ var underlyingArray = this();
1374
+ return ko.utils.arrayIndexOf(underlyingArray, item);
1375
+ },
1376
+
1377
+ 'replace': function(oldItem, newItem) {
1378
+ var index = this['indexOf'](oldItem);
1379
+ if (index >= 0) {
1380
+ this.valueWillMutate();
1381
+ this.peek()[index] = newItem;
1382
+ this.valueHasMutated();
1383
+ }
1384
+ }
1385
+ };
1386
+
1387
+ // Populate ko.observableArray.fn with read/write functions from native arrays
1388
+ // Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
1389
+ // because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
1390
+ ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
1391
+ ko.observableArray['fn'][methodName] = function () {
1392
+ // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
1393
+ // (for consistency with mutating regular observables)
1394
+ var underlyingArray = this.peek();
1395
+ this.valueWillMutate();
1396
+ this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);
1397
+ var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
1398
+ this.valueHasMutated();
1399
+ return methodCallResult;
1400
+ };
1401
+ });
1402
+
1403
+ // Populate ko.observableArray.fn with read-only functions from native arrays
1404
+ ko.utils.arrayForEach(["slice"], function (methodName) {
1405
+ ko.observableArray['fn'][methodName] = function () {
1406
+ var underlyingArray = this();
1407
+ return underlyingArray[methodName].apply(underlyingArray, arguments);
1408
+ };
1409
+ });
1410
+
1411
+ // Note that for browsers that don't support proto assignment, the
1412
+ // inheritance chain is created manually in the ko.observableArray constructor
1413
+ if (ko.utils.canSetPrototype) {
1414
+ ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);
1415
+ }
1416
+
1417
+ ko.exportSymbol('observableArray', ko.observableArray);
1418
+ var arrayChangeEventName = 'arrayChange';
1419
+ ko.extenders['trackArrayChanges'] = function(target) {
1420
+ // Only modify the target observable once
1421
+ if (target.cacheDiffForKnownOperation) {
1422
+ return;
1423
+ }
1424
+ var trackingChanges = false,
1425
+ cachedDiff = null,
1426
+ pendingNotifications = 0,
1427
+ underlyingSubscribeFunction = target.subscribe;
1428
+
1429
+ // Intercept "subscribe" calls, and for array change events, ensure change tracking is enabled
1430
+ target.subscribe = target['subscribe'] = function(callback, callbackTarget, event) {
1431
+ if (event === arrayChangeEventName) {
1432
+ trackChanges();
1433
+ }
1434
+ return underlyingSubscribeFunction.apply(this, arguments);
1435
+ };
1436
+
1437
+ function trackChanges() {
1438
+ // Calling 'trackChanges' multiple times is the same as calling it once
1439
+ if (trackingChanges) {
1440
+ return;
1441
+ }
1442
+
1443
+ trackingChanges = true;
1444
+
1445
+ // Intercept "notifySubscribers" to track how many times it was called.
1446
+ var underlyingNotifySubscribersFunction = target['notifySubscribers'];
1447
+ target['notifySubscribers'] = function(valueToNotify, event) {
1448
+ if (!event || event === defaultEvent) {
1449
+ ++pendingNotifications;
1450
+ }
1451
+ return underlyingNotifySubscribersFunction.apply(this, arguments);
1452
+ };
1453
+
1454
+ // Each time the array changes value, capture a clone so that on the next
1455
+ // change it's possible to produce a diff
1456
+ var previousContents = [].concat(target.peek() || []);
1457
+ cachedDiff = null;
1458
+ target.subscribe(function(currentContents) {
1459
+ // Make a copy of the current contents and ensure it's an array
1460
+ currentContents = [].concat(currentContents || []);
1461
+
1462
+ // Compute the diff and issue notifications, but only if someone is listening
1463
+ if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {
1464
+ var changes = getChanges(previousContents, currentContents);
1465
+ if (changes.length) {
1466
+ target['notifySubscribers'](changes, arrayChangeEventName);
1467
+ }
1468
+ }
1469
+
1470
+ // Eliminate references to the old, removed items, so they can be GCed
1471
+ previousContents = currentContents;
1472
+ cachedDiff = null;
1473
+ pendingNotifications = 0;
1474
+ });
1475
+ }
1476
+
1477
+ function getChanges(previousContents, currentContents) {
1478
+ // We try to re-use cached diffs.
1479
+ // The scenarios where pendingNotifications > 1 are when using rate-limiting or the Deferred Updates
1480
+ // plugin, which without this check would not be compatible with arrayChange notifications. Normally,
1481
+ // notifications are issued immediately so we wouldn't be queueing up more than one.
1482
+ if (!cachedDiff || pendingNotifications > 1) {
1483
+ cachedDiff = ko.utils.compareArrays(previousContents, currentContents, { 'sparse': true });
1484
+ }
1485
+
1486
+ return cachedDiff;
1487
+ }
1488
+
1489
+ target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {
1490
+ // Only run if we're currently tracking changes for this observable array
1491
+ // and there aren't any pending deferred notifications.
1492
+ if (!trackingChanges || pendingNotifications) {
1493
+ return;
1494
+ }
1495
+ var diff = [],
1496
+ arrayLength = rawArray.length,
1497
+ argsLength = args.length,
1498
+ offset = 0;
1499
+
1500
+ function pushDiff(status, value, index) {
1501
+ return diff[diff.length] = { 'status': status, 'value': value, 'index': index };
1502
+ }
1503
+ switch (operationName) {
1504
+ case 'push':
1505
+ offset = arrayLength;
1506
+ case 'unshift':
1507
+ for (var index = 0; index < argsLength; index++) {
1508
+ pushDiff('added', args[index], offset + index);
1509
+ }
1510
+ break;
1511
+
1512
+ case 'pop':
1513
+ offset = arrayLength - 1;
1514
+ case 'shift':
1515
+ if (arrayLength) {
1516
+ pushDiff('deleted', rawArray[offset], offset);
1517
+ }
1518
+ break;
1519
+
1520
+ case 'splice':
1521
+ // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].
1522
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
1523
+ var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),
1524
+ endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),
1525
+ endAddIndex = startIndex + argsLength - 2,
1526
+ endIndex = Math.max(endDeleteIndex, endAddIndex),
1527
+ additions = [], deletions = [];
1528
+ for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {
1529
+ if (index < endDeleteIndex)
1530
+ deletions.push(pushDiff('deleted', rawArray[index], index));
1531
+ if (index < endAddIndex)
1532
+ additions.push(pushDiff('added', args[argsIndex], index));
1533
+ }
1534
+ ko.utils.findMovesInArrayComparison(deletions, additions);
1535
+ break;
1536
+
1537
+ default:
1538
+ return;
1539
+ }
1540
+ cachedDiff = diff;
1541
+ };
1542
+ };
1543
+ ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
1544
+ var _latestValue,
1545
+ _needsEvaluation = true,
1546
+ _isBeingEvaluated = false,
1547
+ _suppressDisposalUntilDisposeWhenReturnsFalse = false,
1548
+ _isDisposed = false,
1549
+ readFunction = evaluatorFunctionOrOptions;
1550
+
1551
+ if (readFunction && typeof readFunction == "object") {
1552
+ // Single-parameter syntax - everything is on this "options" param
1553
+ options = readFunction;
1554
+ readFunction = options["read"];
1555
+ } else {
1556
+ // Multi-parameter syntax - construct the options according to the params passed
1557
+ options = options || {};
1558
+ if (!readFunction)
1559
+ readFunction = options["read"];
1560
+ }
1561
+ if (typeof readFunction != "function")
1562
+ throw new Error("Pass a function that returns the value of the ko.computed");
1563
+
1564
+ function addSubscriptionToDependency(subscribable, id) {
1565
+ if (!_subscriptionsToDependencies[id]) {
1566
+ _subscriptionsToDependencies[id] = subscribable.subscribe(evaluatePossiblyAsync);
1567
+ ++_dependenciesCount;
1568
+ }
1569
+ }
1570
+
1571
+ function disposeAllSubscriptionsToDependencies() {
1572
+ _isDisposed = true;
1573
+ ko.utils.objectForEach(_subscriptionsToDependencies, function (id, subscription) {
1574
+ subscription.dispose();
1575
+ });
1576
+ _subscriptionsToDependencies = {};
1577
+ _dependenciesCount = 0;
1578
+ _needsEvaluation = false;
1579
+ }
1580
+
1581
+ function evaluatePossiblyAsync() {
1582
+ var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
1583
+ if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
1584
+ clearTimeout(evaluationTimeoutInstance);
1585
+ evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
1586
+ } else if (dependentObservable._evalRateLimited) {
1587
+ dependentObservable._evalRateLimited();
1588
+ } else {
1589
+ evaluateImmediate();
1590
+ }
1591
+ }
1592
+
1593
+ function evaluateImmediate() {
1594
+ if (_isBeingEvaluated) {
1595
+ // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
1596
+ // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
1597
+ // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
1598
+ // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
1599
+ return;
1600
+ }
1601
+
1602
+ // Do not evaluate (and possibly capture new dependencies) if disposed
1603
+ if (_isDisposed) {
1604
+ return;
1605
+ }
1606
+
1607
+ if (disposeWhen && disposeWhen()) {
1608
+ // See comment below about _suppressDisposalUntilDisposeWhenReturnsFalse
1609
+ if (!_suppressDisposalUntilDisposeWhenReturnsFalse) {
1610
+ dispose();
1611
+ return;
1612
+ }
1613
+ } else {
1614
+ // It just did return false, so we can stop suppressing now
1615
+ _suppressDisposalUntilDisposeWhenReturnsFalse = false;
1616
+ }
1617
+
1618
+ _isBeingEvaluated = true;
1619
+ try {
1620
+ // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
1621
+ // Then, during evaluation, we cross off any that are in fact still being used.
1622
+ var disposalCandidates = _subscriptionsToDependencies, disposalCount = _dependenciesCount;
1623
+ ko.dependencyDetection.begin({
1624
+ callback: function(subscribable, id) {
1625
+ if (!_isDisposed) {
1626
+ if (disposalCount && disposalCandidates[id]) {
1627
+ // Don't want to dispose this subscription, as it's still being used
1628
+ _subscriptionsToDependencies[id] = disposalCandidates[id];
1629
+ ++_dependenciesCount;
1630
+ delete disposalCandidates[id];
1631
+ --disposalCount;
1632
+ } else {
1633
+ // Brand new subscription - add it
1634
+ addSubscriptionToDependency(subscribable, id);
1635
+ }
1636
+ }
1637
+ },
1638
+ computed: dependentObservable,
1639
+ isInitial: !_dependenciesCount // If we're evaluating when there are no previous dependencies, it must be the first time
1640
+ });
1641
+
1642
+ _subscriptionsToDependencies = {};
1643
+ _dependenciesCount = 0;
1644
+
1645
+ try {
1646
+ var newValue = evaluatorFunctionTarget ? readFunction.call(evaluatorFunctionTarget) : readFunction();
1647
+
1648
+ } finally {
1649
+ ko.dependencyDetection.end();
1650
+
1651
+ // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
1652
+ if (disposalCount) {
1653
+ ko.utils.objectForEach(disposalCandidates, function(id, toDispose) {
1654
+ toDispose.dispose();
1655
+ });
1656
+ }
1657
+
1658
+ _needsEvaluation = false;
1659
+ }
1660
+
1661
+ if (dependentObservable.isDifferent(_latestValue, newValue)) {
1662
+ dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
1663
+
1664
+ _latestValue = newValue;
1665
+ if (DEBUG) dependentObservable._latestValue = _latestValue;
1666
+
1667
+ // If rate-limited, the notification will happen within the limit function. Otherwise,
1668
+ // notify as soon as the value changes. Check specifically for the throttle setting since
1669
+ // it overrides rateLimit.
1670
+ if (!dependentObservable._evalRateLimited || dependentObservable['throttleEvaluation']) {
1671
+ dependentObservable["notifySubscribers"](_latestValue);
1672
+ }
1673
+ }
1674
+ } finally {
1675
+ _isBeingEvaluated = false;
1676
+ }
1677
+
1678
+ if (!_dependenciesCount)
1679
+ dispose();
1680
+ }
1681
+
1682
+ function dependentObservable() {
1683
+ if (arguments.length > 0) {
1684
+ if (typeof writeFunction === "function") {
1685
+ // Writing a value
1686
+ writeFunction.apply(evaluatorFunctionTarget, arguments);
1687
+ } else {
1688
+ throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
1689
+ }
1690
+ return this; // Permits chained assignments
1691
+ } else {
1692
+ // Reading the value
1693
+ if (_needsEvaluation)
1694
+ evaluateImmediate();
1695
+ ko.dependencyDetection.registerDependency(dependentObservable);
1696
+ return _latestValue;
1697
+ }
1698
+ }
1699
+
1700
+ function peek() {
1701
+ // Peek won't re-evaluate, except to get the initial value when "deferEvaluation" is set.
1702
+ // That's the only time that both of these conditions will be satisfied.
1703
+ if (_needsEvaluation && !_dependenciesCount)
1704
+ evaluateImmediate();
1705
+ return _latestValue;
1706
+ }
1707
+
1708
+ function isActive() {
1709
+ return _needsEvaluation || _dependenciesCount > 0;
1710
+ }
1711
+
1712
+ // By here, "options" is always non-null
1713
+ var writeFunction = options["write"],
1714
+ disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
1715
+ disposeWhenOption = options["disposeWhen"] || options.disposeWhen,
1716
+ disposeWhen = disposeWhenOption,
1717
+ dispose = disposeAllSubscriptionsToDependencies,
1718
+ _subscriptionsToDependencies = {},
1719
+ _dependenciesCount = 0,
1720
+ evaluationTimeoutInstance = null;
1721
+
1722
+ if (!evaluatorFunctionTarget)
1723
+ evaluatorFunctionTarget = options["owner"];
1724
+
1725
+ ko.subscribable.call(dependentObservable);
1726
+ ko.utils.setPrototypeOfOrExtend(dependentObservable, ko.dependentObservable['fn']);
1727
+
1728
+ dependentObservable.peek = peek;
1729
+ dependentObservable.getDependenciesCount = function () { return _dependenciesCount; };
1730
+ dependentObservable.hasWriteFunction = typeof options["write"] === "function";
1731
+ dependentObservable.dispose = function () { dispose(); };
1732
+ dependentObservable.isActive = isActive;
1733
+
1734
+ // Replace the limit function with one that delays evaluation as well.
1735
+ var originalLimit = dependentObservable.limit;
1736
+ dependentObservable.limit = function(limitFunction) {
1737
+ originalLimit.call(dependentObservable, limitFunction);
1738
+ dependentObservable._evalRateLimited = function() {
1739
+ dependentObservable._rateLimitedBeforeChange(_latestValue);
1740
+
1741
+ _needsEvaluation = true; // Mark as dirty
1742
+
1743
+ // Pass the observable to the rate-limit code, which will access it when
1744
+ // it's time to do the notification.
1745
+ dependentObservable._rateLimitedChange(dependentObservable);
1746
+ }
1747
+ };
1748
+
1749
+ ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
1750
+ ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
1751
+ ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
1752
+ ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
1753
+
1754
+ // Add a "disposeWhen" callback that, on each evaluation, disposes if the node was removed without using ko.removeNode.
1755
+ if (disposeWhenNodeIsRemoved) {
1756
+ // Since this computed is associated with a DOM node, and we don't want to dispose the computed
1757
+ // until the DOM node is *removed* from the document (as opposed to never having been in the document),
1758
+ // we'll prevent disposal until "disposeWhen" first returns false.
1759
+ _suppressDisposalUntilDisposeWhenReturnsFalse = true;
1760
+
1761
+ // Only watch for the node's disposal if the value really is a node. It might not be,
1762
+ // e.g., { disposeWhenNodeIsRemoved: true } can be used to opt into the "only dispose
1763
+ // after first false result" behaviour even if there's no specific node to watch. This
1764
+ // technique is intended for KO's internal use only and shouldn't be documented or used
1765
+ // by application code, as it's likely to change in a future version of KO.
1766
+ if (disposeWhenNodeIsRemoved.nodeType) {
1767
+ disposeWhen = function () {
1768
+ return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || (disposeWhenOption && disposeWhenOption());
1769
+ };
1770
+ }
1771
+ }
1772
+
1773
+ // Evaluate, unless deferEvaluation is true
1774
+ if (options['deferEvaluation'] !== true)
1775
+ evaluateImmediate();
1776
+
1777
+ // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is
1778
+ // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).
1779
+ if (disposeWhenNodeIsRemoved && isActive() && disposeWhenNodeIsRemoved.nodeType) {
1780
+ dispose = function() {
1781
+ ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, dispose);
1782
+ disposeAllSubscriptionsToDependencies();
1783
+ };
1784
+ ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
1785
+ }
1786
+
1787
+ return dependentObservable;
1788
+ };
1789
+
1790
+ ko.isComputed = function(instance) {
1791
+ return ko.hasPrototype(instance, ko.dependentObservable);
1792
+ };
1793
+
1794
+ var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
1795
+ ko.dependentObservable[protoProp] = ko.observable;
1796
+
1797
+ ko.dependentObservable['fn'] = {
1798
+ "equalityComparer": valuesArePrimitiveAndEqual
1799
+ };
1800
+ ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
1801
+
1802
+ // Note that for browsers that don't support proto assignment, the
1803
+ // inheritance chain is created manually in the ko.dependentObservable constructor
1804
+ if (ko.utils.canSetPrototype) {
1805
+ ko.utils.setPrototypeOf(ko.dependentObservable['fn'], ko.subscribable['fn']);
1806
+ }
1807
+
1808
+ ko.exportSymbol('dependentObservable', ko.dependentObservable);
1809
+ ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
1810
+ ko.exportSymbol('isComputed', ko.isComputed);
1811
+
1812
+ (function() {
1813
+ var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
1814
+
1815
+ ko.toJS = function(rootObject) {
1816
+ if (arguments.length == 0)
1817
+ throw new Error("When calling ko.toJS, pass the object you want to convert.");
1818
+
1819
+ // We just unwrap everything at every level in the object graph
1820
+ return mapJsObjectGraph(rootObject, function(valueToMap) {
1821
+ // Loop because an observable's value might in turn be another observable wrapper
1822
+ for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
1823
+ valueToMap = valueToMap();
1824
+ return valueToMap;
1825
+ });
1826
+ };
1827
+
1828
+ ko.toJSON = function(rootObject, replacer, space) { // replacer and space are optional
1829
+ var plainJavaScriptObject = ko.toJS(rootObject);
1830
+ return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
1831
+ };
1832
+
1833
+ function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
1834
+ visitedObjects = visitedObjects || new objectLookup();
1835
+
1836
+ rootObject = mapInputCallback(rootObject);
1837
+ var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));
1838
+ if (!canHaveProperties)
1839
+ return rootObject;
1840
+
1841
+ var outputProperties = rootObject instanceof Array ? [] : {};
1842
+ visitedObjects.save(rootObject, outputProperties);
1843
+
1844
+ visitPropertiesOrArrayEntries(rootObject, function(indexer) {
1845
+ var propertyValue = mapInputCallback(rootObject[indexer]);
1846
+
1847
+ switch (typeof propertyValue) {
1848
+ case "boolean":
1849
+ case "number":
1850
+ case "string":
1851
+ case "function":
1852
+ outputProperties[indexer] = propertyValue;
1853
+ break;
1854
+ case "object":
1855
+ case "undefined":
1856
+ var previouslyMappedValue = visitedObjects.get(propertyValue);
1857
+ outputProperties[indexer] = (previouslyMappedValue !== undefined)
1858
+ ? previouslyMappedValue
1859
+ : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
1860
+ break;
1861
+ }
1862
+ });
1863
+
1864
+ return outputProperties;
1865
+ }
1866
+
1867
+ function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
1868
+ if (rootObject instanceof Array) {
1869
+ for (var i = 0; i < rootObject.length; i++)
1870
+ visitorCallback(i);
1871
+
1872
+ // For arrays, also respect toJSON property for custom mappings (fixes #278)
1873
+ if (typeof rootObject['toJSON'] == 'function')
1874
+ visitorCallback('toJSON');
1875
+ } else {
1876
+ for (var propertyName in rootObject) {
1877
+ visitorCallback(propertyName);
1878
+ }
1879
+ }
1880
+ };
1881
+
1882
+ function objectLookup() {
1883
+ this.keys = [];
1884
+ this.values = [];
1885
+ };
1886
+
1887
+ objectLookup.prototype = {
1888
+ constructor: objectLookup,
1889
+ save: function(key, value) {
1890
+ var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
1891
+ if (existingIndex >= 0)
1892
+ this.values[existingIndex] = value;
1893
+ else {
1894
+ this.keys.push(key);
1895
+ this.values.push(value);
1896
+ }
1897
+ },
1898
+ get: function(key) {
1899
+ var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
1900
+ return (existingIndex >= 0) ? this.values[existingIndex] : undefined;
1901
+ }
1902
+ };
1903
+ })();
1904
+
1905
+ ko.exportSymbol('toJS', ko.toJS);
1906
+ ko.exportSymbol('toJSON', ko.toJSON);
1907
+ (function () {
1908
+ var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
1909
+
1910
+ // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
1911
+ // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
1912
+ // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
1913
+ ko.selectExtensions = {
1914
+ readValue : function(element) {
1915
+ switch (ko.utils.tagNameLower(element)) {
1916
+ case 'option':
1917
+ if (element[hasDomDataExpandoProperty] === true)
1918
+ return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
1919
+ return ko.utils.ieVersion <= 7
1920
+ ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
1921
+ : element.value;
1922
+ case 'select':
1923
+ return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
1924
+ default:
1925
+ return element.value;
1926
+ }
1927
+ },
1928
+
1929
+ writeValue: function(element, value, allowUnset) {
1930
+ switch (ko.utils.tagNameLower(element)) {
1931
+ case 'option':
1932
+ switch(typeof value) {
1933
+ case "string":
1934
+ ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
1935
+ if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
1936
+ delete element[hasDomDataExpandoProperty];
1937
+ }
1938
+ element.value = value;
1939
+ break;
1940
+ default:
1941
+ // Store arbitrary object using DomData
1942
+ ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
1943
+ element[hasDomDataExpandoProperty] = true;
1944
+
1945
+ // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
1946
+ element.value = typeof value === "number" ? value : "";
1947
+ break;
1948
+ }
1949
+ break;
1950
+ case 'select':
1951
+ if (value === "" || value === null) // A blank string or null value will select the caption
1952
+ value = undefined;
1953
+ var selection = -1;
1954
+ for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {
1955
+ optionValue = ko.selectExtensions.readValue(element.options[i]);
1956
+ // Include special check to handle selecting a caption with a blank string value
1957
+ if (optionValue == value || (optionValue == "" && value === undefined)) {
1958
+ selection = i;
1959
+ break;
1960
+ }
1961
+ }
1962
+ if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {
1963
+ element.selectedIndex = selection;
1964
+ }
1965
+ break;
1966
+ default:
1967
+ if ((value === null) || (value === undefined))
1968
+ value = "";
1969
+ element.value = value;
1970
+ break;
1971
+ }
1972
+ }
1973
+ };
1974
+ })();
1975
+
1976
+ ko.exportSymbol('selectExtensions', ko.selectExtensions);
1977
+ ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
1978
+ ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
1979
+ ko.expressionRewriting = (function () {
1980
+ var javaScriptReservedWords = ["true", "false", "null", "undefined"];
1981
+
1982
+ // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
1983
+ // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
1984
+ // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).
1985
+ var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
1986
+
1987
+ function getWriteableValue(expression) {
1988
+ if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)
1989
+ return false;
1990
+ var match = expression.match(javaScriptAssignmentTarget);
1991
+ return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
1992
+ }
1993
+
1994
+ // The following regular expressions will be used to split an object-literal string into tokens
1995
+
1996
+ // These two match strings, either with double quotes or single quotes
1997
+ var stringDouble = '"(?:[^"\\\\]|\\\\.)*"',
1998
+ stringSingle = "'(?:[^'\\\\]|\\\\.)*'",
1999
+ // Matches a regular expression (text enclosed by slashes), but will also match sets of divisions
2000
+ // as a regular expression (this is handled by the parsing loop below).
2001
+ stringRegexp = '/(?:[^/\\\\]|\\\\.)*/\w*',
2002
+ // These characters have special meaning to the parser and must not appear in the middle of a
2003
+ // token, except as part of a string.
2004
+ specials = ',"\'{}()/:[\\]',
2005
+ // Match text (at least two characters) that does not contain any of the above special characters,
2006
+ // although some of the special characters are allowed to start it (all but the colon and comma).
2007
+ // The text can contain spaces, but leading or trailing spaces are skipped.
2008
+ everyThingElse = '[^\\s:,/][^' + specials + ']*[^\\s' + specials + ']',
2009
+ // Match any non-space character not matched already. This will match colons and commas, since they're
2010
+ // not matched by "everyThingElse", but will also match any other single character that wasn't already
2011
+ // matched (for example: in "a: 1, b: 2", each of the non-space characters will be matched by oneNotSpace).
2012
+ oneNotSpace = '[^\\s]',
2013
+
2014
+ // Create the actual regular expression by or-ing the above strings. The order is important.
2015
+ bindingToken = RegExp(stringDouble + '|' + stringSingle + '|' + stringRegexp + '|' + everyThingElse + '|' + oneNotSpace, 'g'),
2016
+
2017
+ // Match end of previous token to determine whether a slash is a division or regex.
2018
+ divisionLookBehind = /[\])"'A-Za-z0-9_$]+$/,
2019
+ keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};
2020
+
2021
+ function parseObjectLiteral(objectLiteralString) {
2022
+ // Trim leading and trailing spaces from the string
2023
+ var str = ko.utils.stringTrim(objectLiteralString);
2024
+
2025
+ // Trim braces '{' surrounding the whole object literal
2026
+ if (str.charCodeAt(0) === 123) str = str.slice(1, -1);
2027
+
2028
+ // Split into tokens
2029
+ var result = [], toks = str.match(bindingToken), key, values, depth = 0;
2030
+
2031
+ if (toks) {
2032
+ // Append a comma so that we don't need a separate code block to deal with the last item
2033
+ toks.push(',');
2034
+
2035
+ for (var i = 0, tok; tok = toks[i]; ++i) {
2036
+ var c = tok.charCodeAt(0);
2037
+ // A comma signals the end of a key/value pair if depth is zero
2038
+ if (c === 44) { // ","
2039
+ if (depth <= 0) {
2040
+ if (key)
2041
+ result.push(values ? {key: key, value: values.join('')} : {'unknown': key});
2042
+ key = values = depth = 0;
2043
+ continue;
2044
+ }
2045
+ // Simply skip the colon that separates the name and value
2046
+ } else if (c === 58) { // ":"
2047
+ if (!values)
2048
+ continue;
2049
+ // A set of slashes is initially matched as a regular expression, but could be division
2050
+ } else if (c === 47 && i && tok.length > 1) { // "/"
2051
+ // Look at the end of the previous token to determine if the slash is actually division
2052
+ var match = toks[i-1].match(divisionLookBehind);
2053
+ if (match && !keywordRegexLookBehind[match[0]]) {
2054
+ // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)
2055
+ str = str.substr(str.indexOf(tok) + 1);
2056
+ toks = str.match(bindingToken);
2057
+ toks.push(',');
2058
+ i = -1;
2059
+ // Continue with just the slash
2060
+ tok = '/';
2061
+ }
2062
+ // Increment depth for parentheses, braces, and brackets so that interior commas are ignored
2063
+ } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['
2064
+ ++depth;
2065
+ } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'
2066
+ --depth;
2067
+ // The key must be a single token; if it's a string, trim the quotes
2068
+ } else if (!key && !values) {
2069
+ key = (c === 34 || c === 39) /* '"', "'" */ ? tok.slice(1, -1) : tok;
2070
+ continue;
2071
+ }
2072
+ if (values)
2073
+ values.push(tok);
2074
+ else
2075
+ values = [tok];
2076
+ }
2077
+ }
2078
+ return result;
2079
+ }
2080
+
2081
+ // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.
2082
+ var twoWayBindings = {};
2083
+
2084
+ function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {
2085
+ bindingOptions = bindingOptions || {};
2086
+
2087
+ function processKeyValue(key, val) {
2088
+ var writableVal;
2089
+ function callPreprocessHook(obj) {
2090
+ return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;
2091
+ }
2092
+ if (!callPreprocessHook(ko['getBindingHandler'](key)))
2093
+ return;
2094
+
2095
+ if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {
2096
+ // For two-way bindings, provide a write method in case the value
2097
+ // isn't a writable observable.
2098
+ propertyAccessorResultStrings.push("'" + key + "':function(_z){" + writableVal + "=_z}");
2099
+ }
2100
+
2101
+ // Values are wrapped in a function so that each value can be accessed independently
2102
+ if (makeValueAccessors) {
2103
+ val = 'function(){return ' + val + ' }';
2104
+ }
2105
+ resultStrings.push("'" + key + "':" + val);
2106
+ }
2107
+
2108
+ var resultStrings = [],
2109
+ propertyAccessorResultStrings = [],
2110
+ makeValueAccessors = bindingOptions['valueAccessors'],
2111
+ keyValueArray = typeof bindingsStringOrKeyValueArray === "string" ?
2112
+ parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;
2113
+
2114
+ ko.utils.arrayForEach(keyValueArray, function(keyValue) {
2115
+ processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);
2116
+ });
2117
+
2118
+ if (propertyAccessorResultStrings.length)
2119
+ processKeyValue('_ko_property_writers', "{" + propertyAccessorResultStrings.join(",") + " }");
2120
+
2121
+ return resultStrings.join(",");
2122
+ }
2123
+
2124
+ return {
2125
+ bindingRewriteValidators: [],
2126
+
2127
+ twoWayBindings: twoWayBindings,
2128
+
2129
+ parseObjectLiteral: parseObjectLiteral,
2130
+
2131
+ preProcessBindings: preProcessBindings,
2132
+
2133
+ keyValueArrayContainsKey: function(keyValueArray, key) {
2134
+ for (var i = 0; i < keyValueArray.length; i++)
2135
+ if (keyValueArray[i]['key'] == key)
2136
+ return true;
2137
+ return false;
2138
+ },
2139
+
2140
+ // Internal, private KO utility for updating model properties from within bindings
2141
+ // property: If the property being updated is (or might be) an observable, pass it here
2142
+ // If it turns out to be a writable observable, it will be written to directly
2143
+ // allBindings: An object with a get method to retrieve bindings in the current execution context.
2144
+ // This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
2145
+ // key: The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
2146
+ // value: The value to be written
2147
+ // checkIfDifferent: If true, and if the property being written is a writable observable, the value will only be written if
2148
+ // it is !== existing value on that writable observable
2149
+ writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {
2150
+ if (!property || !ko.isObservable(property)) {
2151
+ var propWriters = allBindings.get('_ko_property_writers');
2152
+ if (propWriters && propWriters[key])
2153
+ propWriters[key](value);
2154
+ } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
2155
+ property(value);
2156
+ }
2157
+ }
2158
+ };
2159
+ })();
2160
+
2161
+ ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
2162
+ ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
2163
+ ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
2164
+ ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
2165
+
2166
+ // Making bindings explicitly declare themselves as "two way" isn't ideal in the long term (it would be better if
2167
+ // all bindings could use an official 'property writer' API without needing to declare that they might). However,
2168
+ // since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable
2169
+ // as an internal implementation detail in the short term.
2170
+ // For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an
2171
+ // undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official
2172
+ // public API, and we reserve the right to remove it at any time if we create a real public property writers API.
2173
+ ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);
2174
+
2175
+ // For backward compatibility, define the following aliases. (Previously, these function names were misleading because
2176
+ // they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
2177
+ ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
2178
+ ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);
2179
+ (function() {
2180
+ // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
2181
+ // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
2182
+ // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
2183
+ // of that virtual hierarchy
2184
+ //
2185
+ // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
2186
+ // without having to scatter special cases all over the binding and templating code.
2187
+
2188
+ // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
2189
+ // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
2190
+ // So, use node.text where available, and node.nodeValue elsewhere
2191
+ var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->";
2192
+
2193
+ var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/;
2194
+ var endCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
2195
+ var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
2196
+
2197
+ function isStartComment(node) {
2198
+ return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
2199
+ }
2200
+
2201
+ function isEndComment(node) {
2202
+ return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
2203
+ }
2204
+
2205
+ function getVirtualChildren(startComment, allowUnbalanced) {
2206
+ var currentNode = startComment;
2207
+ var depth = 1;
2208
+ var children = [];
2209
+ while (currentNode = currentNode.nextSibling) {
2210
+ if (isEndComment(currentNode)) {
2211
+ depth--;
2212
+ if (depth === 0)
2213
+ return children;
2214
+ }
2215
+
2216
+ children.push(currentNode);
2217
+
2218
+ if (isStartComment(currentNode))
2219
+ depth++;
2220
+ }
2221
+ if (!allowUnbalanced)
2222
+ throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
2223
+ return null;
2224
+ }
2225
+
2226
+ function getMatchingEndComment(startComment, allowUnbalanced) {
2227
+ var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
2228
+ if (allVirtualChildren) {
2229
+ if (allVirtualChildren.length > 0)
2230
+ return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
2231
+ return startComment.nextSibling;
2232
+ } else
2233
+ return null; // Must have no matching end comment, and allowUnbalanced is true
2234
+ }
2235
+
2236
+ function getUnbalancedChildTags(node) {
2237
+ // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
2238
+ // from <div>OK</div><!-- /ko --><!-- /ko -->, returns: <!-- /ko --><!-- /ko -->
2239
+ var childNode = node.firstChild, captureRemaining = null;
2240
+ if (childNode) {
2241
+ do {
2242
+ if (captureRemaining) // We already hit an unbalanced node and are now just scooping up all subsequent nodes
2243
+ captureRemaining.push(childNode);
2244
+ else if (isStartComment(childNode)) {
2245
+ var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
2246
+ if (matchingEndComment) // It's a balanced tag, so skip immediately to the end of this virtual set
2247
+ childNode = matchingEndComment;
2248
+ else
2249
+ captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
2250
+ } else if (isEndComment(childNode)) {
2251
+ captureRemaining = [childNode]; // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
2252
+ }
2253
+ } while (childNode = childNode.nextSibling);
2254
+ }
2255
+ return captureRemaining;
2256
+ }
2257
+
2258
+ ko.virtualElements = {
2259
+ allowedBindings: {},
2260
+
2261
+ childNodes: function(node) {
2262
+ return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
2263
+ },
2264
+
2265
+ emptyNode: function(node) {
2266
+ if (!isStartComment(node))
2267
+ ko.utils.emptyDomNode(node);
2268
+ else {
2269
+ var virtualChildren = ko.virtualElements.childNodes(node);
2270
+ for (var i = 0, j = virtualChildren.length; i < j; i++)
2271
+ ko.removeNode(virtualChildren[i]);
2272
+ }
2273
+ },
2274
+
2275
+ setDomNodeChildren: function(node, childNodes) {
2276
+ if (!isStartComment(node))
2277
+ ko.utils.setDomNodeChildren(node, childNodes);
2278
+ else {
2279
+ ko.virtualElements.emptyNode(node);
2280
+ var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
2281
+ for (var i = 0, j = childNodes.length; i < j; i++)
2282
+ endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
2283
+ }
2284
+ },
2285
+
2286
+ prepend: function(containerNode, nodeToPrepend) {
2287
+ if (!isStartComment(containerNode)) {
2288
+ if (containerNode.firstChild)
2289
+ containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
2290
+ else
2291
+ containerNode.appendChild(nodeToPrepend);
2292
+ } else {
2293
+ // Start comments must always have a parent and at least one following sibling (the end comment)
2294
+ containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
2295
+ }
2296
+ },
2297
+
2298
+ insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
2299
+ if (!insertAfterNode) {
2300
+ ko.virtualElements.prepend(containerNode, nodeToInsert);
2301
+ } else if (!isStartComment(containerNode)) {
2302
+ // Insert after insertion point
2303
+ if (insertAfterNode.nextSibling)
2304
+ containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
2305
+ else
2306
+ containerNode.appendChild(nodeToInsert);
2307
+ } else {
2308
+ // Children of start comments must always have a parent and at least one following sibling (the end comment)
2309
+ containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
2310
+ }
2311
+ },
2312
+
2313
+ firstChild: function(node) {
2314
+ if (!isStartComment(node))
2315
+ return node.firstChild;
2316
+ if (!node.nextSibling || isEndComment(node.nextSibling))
2317
+ return null;
2318
+ return node.nextSibling;
2319
+ },
2320
+
2321
+ nextSibling: function(node) {
2322
+ if (isStartComment(node))
2323
+ node = getMatchingEndComment(node);
2324
+ if (node.nextSibling && isEndComment(node.nextSibling))
2325
+ return null;
2326
+ return node.nextSibling;
2327
+ },
2328
+
2329
+ hasBindingValue: isStartComment,
2330
+
2331
+ virtualNodeBindingValue: function(node) {
2332
+ var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
2333
+ return regexMatch ? regexMatch[1] : null;
2334
+ },
2335
+
2336
+ normaliseVirtualElementDomStructure: function(elementVerified) {
2337
+ // Workaround for https://github.com/SteveSanderson/knockout/issues/155
2338
+ // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
2339
+ // that are direct descendants of <ul> into the preceding <li>)
2340
+ if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
2341
+ return;
2342
+
2343
+ // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
2344
+ // must be intended to appear *after* that child, so move them there.
2345
+ var childNode = elementVerified.firstChild;
2346
+ if (childNode) {
2347
+ do {
2348
+ if (childNode.nodeType === 1) {
2349
+ var unbalancedTags = getUnbalancedChildTags(childNode);
2350
+ if (unbalancedTags) {
2351
+ // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
2352
+ var nodeToInsertBefore = childNode.nextSibling;
2353
+ for (var i = 0; i < unbalancedTags.length; i++) {
2354
+ if (nodeToInsertBefore)
2355
+ elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
2356
+ else
2357
+ elementVerified.appendChild(unbalancedTags[i]);
2358
+ }
2359
+ }
2360
+ }
2361
+ } while (childNode = childNode.nextSibling);
2362
+ }
2363
+ }
2364
+ };
2365
+ })();
2366
+ ko.exportSymbol('virtualElements', ko.virtualElements);
2367
+ ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
2368
+ ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
2369
+ //ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild); // firstChild is not minified
2370
+ ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
2371
+ //ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling); // nextSibling is not minified
2372
+ ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
2373
+ ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
2374
+ (function() {
2375
+ var defaultBindingAttributeName = "data-bind";
2376
+
2377
+ ko.bindingProvider = function() {
2378
+ this.bindingCache = {};
2379
+ };
2380
+
2381
+ ko.utils.extend(ko.bindingProvider.prototype, {
2382
+ 'nodeHasBindings': function(node) {
2383
+ switch (node.nodeType) {
2384
+ case 1: return node.getAttribute(defaultBindingAttributeName) != null; // Element
2385
+ case 8: return ko.virtualElements.hasBindingValue(node); // Comment node
2386
+ default: return false;
2387
+ }
2388
+ },
2389
+
2390
+ 'getBindings': function(node, bindingContext) {
2391
+ var bindingsString = this['getBindingsString'](node, bindingContext);
2392
+ return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
2393
+ },
2394
+
2395
+ 'getBindingAccessors': function(node, bindingContext) {
2396
+ var bindingsString = this['getBindingsString'](node, bindingContext);
2397
+ return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, {'valueAccessors':true}) : null;
2398
+ },
2399
+
2400
+ // The following function is only used internally by this default provider.
2401
+ // It's not part of the interface definition for a general binding provider.
2402
+ 'getBindingsString': function(node, bindingContext) {
2403
+ switch (node.nodeType) {
2404
+ case 1: return node.getAttribute(defaultBindingAttributeName); // Element
2405
+ case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
2406
+ default: return null;
2407
+ }
2408
+ },
2409
+
2410
+ // The following function is only used internally by this default provider.
2411
+ // It's not part of the interface definition for a general binding provider.
2412
+ 'parseBindingsString': function(bindingsString, bindingContext, node, options) {
2413
+ try {
2414
+ var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);
2415
+ return bindingFunction(bindingContext, node);
2416
+ } catch (ex) {
2417
+ ex.message = "Unable to parse bindings.\nBindings value: " + bindingsString + "\nMessage: " + ex.message;
2418
+ throw ex;
2419
+ }
2420
+ }
2421
+ });
2422
+
2423
+ ko.bindingProvider['instance'] = new ko.bindingProvider();
2424
+
2425
+ function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {
2426
+ var cacheKey = bindingsString + (options && options['valueAccessors'] || '');
2427
+ return cache[cacheKey]
2428
+ || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));
2429
+ }
2430
+
2431
+ function createBindingsStringEvaluator(bindingsString, options) {
2432
+ // Build the source for a function that evaluates "expression"
2433
+ // For each scope variable, add an extra level of "with" nesting
2434
+ // Example result: with(sc1) { with(sc0) { return (expression) } }
2435
+ var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),
2436
+ functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
2437
+ return new Function("$context", "$element", functionBody);
2438
+ }
2439
+ })();
2440
+
2441
+ ko.exportSymbol('bindingProvider', ko.bindingProvider);
2442
+ (function () {
2443
+ ko.bindingHandlers = {};
2444
+
2445
+ // The following element types will not be recursed into during binding. In the future, we
2446
+ // may consider adding <template> to this list, because such elements' contents are always
2447
+ // intended to be bound in a different context from where they appear in the document.
2448
+ var bindingDoesNotRecurseIntoElementTypes = {
2449
+ // Don't want bindings that operate on text nodes to mutate <script> contents,
2450
+ // because it's unexpected and a potential XSS issue
2451
+ 'script': true
2452
+ };
2453
+
2454
+ // Use an overridable method for retrieving binding handlers so that a plugins may support dynamically created handlers
2455
+ ko['getBindingHandler'] = function(bindingKey) {
2456
+ return ko.bindingHandlers[bindingKey];
2457
+ };
2458
+
2459
+ // The ko.bindingContext constructor is only called directly to create the root context. For child
2460
+ // contexts, use bindingContext.createChildContext or bindingContext.extend.
2461
+ ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback) {
2462
+
2463
+ // The binding context object includes static properties for the current, parent, and root view models.
2464
+ // If a view model is actually stored in an observable, the corresponding binding context object, and
2465
+ // any child contexts, must be updated when the view model is changed.
2466
+ function updateContext() {
2467
+ // Most of the time, the context will directly get a view model object, but if a function is given,
2468
+ // we call the function to retrieve the view model. If the function accesses any obsevables or returns
2469
+ // an observable, the dependency is tracked, and those observables can later cause the binding
2470
+ // context to be updated.
2471
+ var dataItemOrObservable = isFunc ? dataItemOrAccessor() : dataItemOrAccessor,
2472
+ dataItem = ko.utils.unwrapObservable(dataItemOrObservable);
2473
+
2474
+ if (parentContext) {
2475
+ // When a "parent" context is given, register a dependency on the parent context. Thus whenever the
2476
+ // parent context is updated, this context will also be updated.
2477
+ if (parentContext._subscribable)
2478
+ parentContext._subscribable();
2479
+
2480
+ // Copy $root and any custom properties from the parent context
2481
+ ko.utils.extend(self, parentContext);
2482
+
2483
+ // Because the above copy overwrites our own properties, we need to reset them.
2484
+ // During the first execution, "subscribable" isn't set, so don't bother doing the update then.
2485
+ if (subscribable) {
2486
+ self._subscribable = subscribable;
2487
+ }
2488
+ } else {
2489
+ self['$parents'] = [];
2490
+ self['$root'] = dataItem;
2491
+
2492
+ // Export 'ko' in the binding context so it will be available in bindings and templates
2493
+ // even if 'ko' isn't exported as a global, such as when using an AMD loader.
2494
+ // See https://github.com/SteveSanderson/knockout/issues/490
2495
+ self['ko'] = ko;
2496
+ }
2497
+ self['$rawData'] = dataItemOrObservable;
2498
+ self['$data'] = dataItem;
2499
+ if (dataItemAlias)
2500
+ self[dataItemAlias] = dataItem;
2501
+
2502
+ // The extendCallback function is provided when creating a child context or extending a context.
2503
+ // It handles the specific actions needed to finish setting up the binding context. Actions in this
2504
+ // function could also add dependencies to this binding context.
2505
+ if (extendCallback)
2506
+ extendCallback(self, parentContext, dataItem);
2507
+
2508
+ return self['$data'];
2509
+ }
2510
+ function disposeWhen() {
2511
+ return nodes && !ko.utils.anyDomNodeIsAttachedToDocument(nodes);
2512
+ }
2513
+
2514
+ var self = this,
2515
+ isFunc = typeof(dataItemOrAccessor) == "function" && !ko.isObservable(dataItemOrAccessor),
2516
+ nodes,
2517
+ subscribable = ko.dependentObservable(updateContext, null, { disposeWhen: disposeWhen, disposeWhenNodeIsRemoved: true });
2518
+
2519
+ // At this point, the binding context has been initialized, and the "subscribable" computed observable is
2520
+ // subscribed to any observables that were accessed in the process. If there is nothing to track, the
2521
+ // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in
2522
+ // the context object.
2523
+ if (subscribable.isActive()) {
2524
+ self._subscribable = subscribable;
2525
+
2526
+ // Always notify because even if the model ($data) hasn't changed, other context properties might have changed
2527
+ subscribable['equalityComparer'] = null;
2528
+
2529
+ // We need to be able to dispose of this computed observable when it's no longer needed. This would be
2530
+ // easy if we had a single node to watch, but binding contexts can be used by many different nodes, and
2531
+ // we cannot assume that those nodes have any relation to each other. So instead we track any node that
2532
+ // the context is attached to, and dispose the computed when all of those nodes have been cleaned.
2533
+
2534
+ // Add properties to *subscribable* instead of *self* because any properties added to *self* may be overwritten on updates
2535
+ nodes = [];
2536
+ subscribable._addNode = function(node) {
2537
+ nodes.push(node);
2538
+ ko.utils.domNodeDisposal.addDisposeCallback(node, function(node) {
2539
+ ko.utils.arrayRemoveItem(nodes, node);
2540
+ if (!nodes.length) {
2541
+ subscribable.dispose();
2542
+ self._subscribable = subscribable = undefined;
2543
+ }
2544
+ });
2545
+ };
2546
+ }
2547
+ }
2548
+
2549
+ // Extend the binding context hierarchy with a new view model object. If the parent context is watching
2550
+ // any obsevables, the new child context will automatically get a dependency on the parent context.
2551
+ // But this does not mean that the $data value of the child context will also get updated. If the child
2552
+ // view model also depends on the parent view model, you must provide a function that returns the correct
2553
+ // view model on each update.
2554
+ ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback) {
2555
+ return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function(self, parentContext) {
2556
+ // Extend the context hierarchy by setting the appropriate pointers
2557
+ self['$parentContext'] = parentContext;
2558
+ self['$parent'] = parentContext['$data'];
2559
+ self['$parents'] = (parentContext['$parents'] || []).slice(0);
2560
+ self['$parents'].unshift(self['$parent']);
2561
+ if (extendCallback)
2562
+ extendCallback(self);
2563
+ });
2564
+ };
2565
+
2566
+ // Extend the binding context with new custom properties. This doesn't change the context hierarchy.
2567
+ // Similarly to "child" contexts, provide a function here to make sure that the correct values are set
2568
+ // when an observable view model is updated.
2569
+ ko.bindingContext.prototype['extend'] = function(properties) {
2570
+ // If the parent context references an observable view model, "_subscribable" will always be the
2571
+ // latest view model object. If not, "_subscribable" isn't set, and we can use the static "$data" value.
2572
+ return new ko.bindingContext(this._subscribable || this['$data'], this, null, function(self, parentContext) {
2573
+ // This "child" context doesn't directly track a parent observable view model,
2574
+ // so we need to manually set the $rawData value to match the parent.
2575
+ self['$rawData'] = parentContext['$rawData'];
2576
+ ko.utils.extend(self, typeof(properties) == "function" ? properties() : properties);
2577
+ });
2578
+ };
2579
+
2580
+ // Returns the valueAccesor function for a binding value
2581
+ function makeValueAccessor(value) {
2582
+ return function() {
2583
+ return value;
2584
+ };
2585
+ }
2586
+
2587
+ // Returns the value of a valueAccessor function
2588
+ function evaluateValueAccessor(valueAccessor) {
2589
+ return valueAccessor();
2590
+ }
2591
+
2592
+ // Given a function that returns bindings, create and return a new object that contains
2593
+ // binding value-accessors functions. Each accessor function calls the original function
2594
+ // so that it always gets the latest value and all dependencies are captured. This is used
2595
+ // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.
2596
+ function makeAccessorsFromFunction(callback) {
2597
+ return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {
2598
+ return function() {
2599
+ return callback()[key];
2600
+ };
2601
+ });
2602
+ }
2603
+
2604
+ // Given a bindings function or object, create and return a new object that contains
2605
+ // binding value-accessors functions. This is used by ko.applyBindingsToNode.
2606
+ function makeBindingAccessors(bindings, context, node) {
2607
+ if (typeof bindings === 'function') {
2608
+ return makeAccessorsFromFunction(bindings.bind(null, context, node));
2609
+ } else {
2610
+ return ko.utils.objectMap(bindings, makeValueAccessor);
2611
+ }
2612
+ }
2613
+
2614
+ // This function is used if the binding provider doesn't include a getBindingAccessors function.
2615
+ // It must be called with 'this' set to the provider instance.
2616
+ function getBindingsAndMakeAccessors(node, context) {
2617
+ return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));
2618
+ }
2619
+
2620
+ function validateThatBindingIsAllowedForVirtualElements(bindingName) {
2621
+ var validator = ko.virtualElements.allowedBindings[bindingName];
2622
+ if (!validator)
2623
+ throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
2624
+ }
2625
+
2626
+ function applyBindingsToDescendantsInternal (bindingContext, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
2627
+ var currentChild,
2628
+ nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement),
2629
+ provider = ko.bindingProvider['instance'],
2630
+ preprocessNode = provider['preprocessNode'];
2631
+
2632
+ // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's
2633
+ // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to
2634
+ // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that
2635
+ // trigger insertion of <template> contents at that point in the document.
2636
+ if (preprocessNode) {
2637
+ while (currentChild = nextInQueue) {
2638
+ nextInQueue = ko.virtualElements.nextSibling(currentChild);
2639
+ preprocessNode.call(provider, currentChild);
2640
+ }
2641
+ // Reset nextInQueue for the next loop
2642
+ nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
2643
+ }
2644
+
2645
+ while (currentChild = nextInQueue) {
2646
+ // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
2647
+ nextInQueue = ko.virtualElements.nextSibling(currentChild);
2648
+ applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild, bindingContextsMayDifferFromDomParentElement);
2649
+ }
2650
+ }
2651
+
2652
+ function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {
2653
+ var shouldBindDescendants = true;
2654
+
2655
+ // Perf optimisation: Apply bindings only if...
2656
+ // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
2657
+ // Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
2658
+ // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
2659
+ var isElement = (nodeVerified.nodeType === 1);
2660
+ if (isElement) // Workaround IE <= 8 HTML parsing weirdness
2661
+ ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
2662
+
2663
+ var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement) // Case (1)
2664
+ || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified); // Case (2)
2665
+ if (shouldApplyBindings)
2666
+ shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];
2667
+
2668
+ if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {
2669
+ // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
2670
+ // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
2671
+ // hence bindingContextsMayDifferFromDomParentElement is false
2672
+ // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
2673
+ // skip over any number of intermediate virtual elements, any of which might define a custom binding context,
2674
+ // hence bindingContextsMayDifferFromDomParentElement is true
2675
+ applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
2676
+ }
2677
+ }
2678
+
2679
+ var boundElementDomDataKey = ko.utils.domData.nextKey();
2680
+
2681
+
2682
+ function topologicalSortBindings(bindings) {
2683
+ // Depth-first sort
2684
+ var result = [], // The list of key/handler pairs that we will return
2685
+ bindingsConsidered = {}, // A temporary record of which bindings are already in 'result'
2686
+ cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
2687
+ ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
2688
+ if (!bindingsConsidered[bindingKey]) {
2689
+ var binding = ko['getBindingHandler'](bindingKey);
2690
+ if (binding) {
2691
+ // First add dependencies (if any) of the current binding
2692
+ if (binding['after']) {
2693
+ cyclicDependencyStack.push(bindingKey);
2694
+ ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {
2695
+ if (bindings[bindingDependencyKey]) {
2696
+ if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {
2697
+ throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
2698
+ } else {
2699
+ pushBinding(bindingDependencyKey);
2700
+ }
2701
+ }
2702
+ });
2703
+ cyclicDependencyStack.length--;
2704
+ }
2705
+ // Next add the current binding
2706
+ result.push({ key: bindingKey, handler: binding });
2707
+ }
2708
+ bindingsConsidered[bindingKey] = true;
2709
+ }
2710
+ });
2711
+
2712
+ return result;
2713
+ }
2714
+
2715
+ function applyBindingsToNodeInternal(node, sourceBindings, bindingContext, bindingContextMayDifferFromDomParentElement) {
2716
+ // Prevent multiple applyBindings calls for the same node, except when a binding value is specified
2717
+ var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey);
2718
+ if (!sourceBindings) {
2719
+ if (alreadyBound) {
2720
+ throw Error("You cannot apply bindings multiple times to the same element.");
2721
+ }
2722
+ ko.utils.domData.set(node, boundElementDomDataKey, true);
2723
+ }
2724
+
2725
+ // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
2726
+ // we can easily recover it just by scanning up the node's ancestors in the DOM
2727
+ // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
2728
+ if (!alreadyBound && bindingContextMayDifferFromDomParentElement)
2729
+ ko.storedBindingContextForNode(node, bindingContext);
2730
+
2731
+ // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings
2732
+ var bindings;
2733
+ if (sourceBindings && typeof sourceBindings !== 'function') {
2734
+ bindings = sourceBindings;
2735
+ } else {
2736
+ var provider = ko.bindingProvider['instance'],
2737
+ getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;
2738
+
2739
+ // Get the binding from the provider within a computed observable so that we can update the bindings whenever
2740
+ // the binding context is updated or if the binding provider accesses observables.
2741
+ var bindingsUpdater = ko.dependentObservable(
2742
+ function() {
2743
+ bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);
2744
+ // Register a dependency on the binding context to support obsevable view models.
2745
+ if (bindings && bindingContext._subscribable)
2746
+ bindingContext._subscribable();
2747
+ return bindings;
2748
+ },
2749
+ null, { disposeWhenNodeIsRemoved: node }
2750
+ );
2751
+
2752
+ if (!bindings || !bindingsUpdater.isActive())
2753
+ bindingsUpdater = null;
2754
+ }
2755
+
2756
+ var bindingHandlerThatControlsDescendantBindings;
2757
+ if (bindings) {
2758
+ // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding
2759
+ // context update), just return the value accessor from the binding. Otherwise, return a function that always gets
2760
+ // the latest binding value and registers a dependency on the binding updater.
2761
+ var getValueAccessor = bindingsUpdater
2762
+ ? function(bindingKey) {
2763
+ return function() {
2764
+ return evaluateValueAccessor(bindingsUpdater()[bindingKey]);
2765
+ };
2766
+ } : function(bindingKey) {
2767
+ return bindings[bindingKey];
2768
+ };
2769
+
2770
+ // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated
2771
+ function allBindings() {
2772
+ return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);
2773
+ }
2774
+ // The following is the 3.x allBindings API
2775
+ allBindings['get'] = function(key) {
2776
+ return bindings[key] && evaluateValueAccessor(getValueAccessor(key));
2777
+ };
2778
+ allBindings['has'] = function(key) {
2779
+ return key in bindings;
2780
+ };
2781
+
2782
+ // First put the bindings into the right order
2783
+ var orderedBindings = topologicalSortBindings(bindings);
2784
+
2785
+ // Go through the sorted bindings, calling init and update for each
2786
+ ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {
2787
+ // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,
2788
+ // so bindingKeyAndHandler.handler will always be nonnull.
2789
+ var handlerInitFn = bindingKeyAndHandler.handler["init"],
2790
+ handlerUpdateFn = bindingKeyAndHandler.handler["update"],
2791
+ bindingKey = bindingKeyAndHandler.key;
2792
+
2793
+ if (node.nodeType === 8) {
2794
+ validateThatBindingIsAllowedForVirtualElements(bindingKey);
2795
+ }
2796
+
2797
+ try {
2798
+ // Run init, ignoring any dependencies
2799
+ if (typeof handlerInitFn == "function") {
2800
+ ko.dependencyDetection.ignore(function() {
2801
+ var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
2802
+
2803
+ // If this binding handler claims to control descendant bindings, make a note of this
2804
+ if (initResult && initResult['controlsDescendantBindings']) {
2805
+ if (bindingHandlerThatControlsDescendantBindings !== undefined)
2806
+ throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
2807
+ bindingHandlerThatControlsDescendantBindings = bindingKey;
2808
+ }
2809
+ });
2810
+ }
2811
+
2812
+ // Run update in its own computed wrapper
2813
+ if (typeof handlerUpdateFn == "function") {
2814
+ ko.dependentObservable(
2815
+ function() {
2816
+ handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
2817
+ },
2818
+ null,
2819
+ { disposeWhenNodeIsRemoved: node }
2820
+ );
2821
+ }
2822
+ } catch (ex) {
2823
+ ex.message = "Unable to process binding \"" + bindingKey + ": " + bindings[bindingKey] + "\"\nMessage: " + ex.message;
2824
+ throw ex;
2825
+ }
2826
+ });
2827
+ }
2828
+
2829
+ return {
2830
+ 'shouldBindDescendants': bindingHandlerThatControlsDescendantBindings === undefined
2831
+ };
2832
+ };
2833
+
2834
+ var storedBindingContextDomDataKey = ko.utils.domData.nextKey();
2835
+ ko.storedBindingContextForNode = function (node, bindingContext) {
2836
+ if (arguments.length == 2) {
2837
+ ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
2838
+ if (bindingContext._subscribable)
2839
+ bindingContext._subscribable._addNode(node);
2840
+ } else {
2841
+ return ko.utils.domData.get(node, storedBindingContextDomDataKey);
2842
+ }
2843
+ }
2844
+
2845
+ function getBindingContext(viewModelOrBindingContext) {
2846
+ return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
2847
+ ? viewModelOrBindingContext
2848
+ : new ko.bindingContext(viewModelOrBindingContext);
2849
+ }
2850
+
2851
+ ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {
2852
+ if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
2853
+ ko.virtualElements.normaliseVirtualElementDomStructure(node);
2854
+ return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext), true);
2855
+ };
2856
+
2857
+ ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {
2858
+ var context = getBindingContext(viewModelOrBindingContext);
2859
+ return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);
2860
+ };
2861
+
2862
+ ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {
2863
+ if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
2864
+ applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
2865
+ };
2866
+
2867
+ ko.applyBindings = function (viewModelOrBindingContext, rootNode) {
2868
+ // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.
2869
+ if (!jQuery && window['jQuery']) {
2870
+ jQuery = window['jQuery'];
2871
+ }
2872
+
2873
+ if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
2874
+ throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
2875
+ rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
2876
+
2877
+ applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
2878
+ };
2879
+
2880
+ // Retrieving binding context from arbitrary nodes
2881
+ ko.contextFor = function(node) {
2882
+ // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
2883
+ switch (node.nodeType) {
2884
+ case 1:
2885
+ case 8:
2886
+ var context = ko.storedBindingContextForNode(node);
2887
+ if (context) return context;
2888
+ if (node.parentNode) return ko.contextFor(node.parentNode);
2889
+ break;
2890
+ }
2891
+ return undefined;
2892
+ };
2893
+ ko.dataFor = function(node) {
2894
+ var context = ko.contextFor(node);
2895
+ return context ? context['$data'] : undefined;
2896
+ };
2897
+
2898
+ ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
2899
+ ko.exportSymbol('applyBindings', ko.applyBindings);
2900
+ ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
2901
+ ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);
2902
+ ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
2903
+ ko.exportSymbol('contextFor', ko.contextFor);
2904
+ ko.exportSymbol('dataFor', ko.dataFor);
2905
+ })();
2906
+ var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
2907
+ ko.bindingHandlers['attr'] = {
2908
+ 'update': function(element, valueAccessor, allBindings) {
2909
+ var value = ko.utils.unwrapObservable(valueAccessor()) || {};
2910
+ ko.utils.objectForEach(value, function(attrName, attrValue) {
2911
+ attrValue = ko.utils.unwrapObservable(attrValue);
2912
+
2913
+ // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
2914
+ // when someProp is a "no value"-like value (strictly null, false, or undefined)
2915
+ // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
2916
+ var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
2917
+ if (toRemove)
2918
+ element.removeAttribute(attrName);
2919
+
2920
+ // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
2921
+ // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
2922
+ // but instead of figuring out the mode, we'll just set the attribute through the Javascript
2923
+ // property for IE <= 8.
2924
+ if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
2925
+ attrName = attrHtmlToJavascriptMap[attrName];
2926
+ if (toRemove)
2927
+ element.removeAttribute(attrName);
2928
+ else
2929
+ element[attrName] = attrValue;
2930
+ } else if (!toRemove) {
2931
+ element.setAttribute(attrName, attrValue.toString());
2932
+ }
2933
+
2934
+ // Treat "name" specially - although you can think of it as an attribute, it also needs
2935
+ // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
2936
+ // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
2937
+ // entirely, and there's no strong reason to allow for such casing in HTML.
2938
+ if (attrName === "name") {
2939
+ ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
2940
+ }
2941
+ });
2942
+ }
2943
+ };
2944
+ (function() {
2945
+
2946
+ ko.bindingHandlers['checked'] = {
2947
+ 'after': ['value', 'attr'],
2948
+ 'init': function (element, valueAccessor, allBindings) {
2949
+ function checkedValue() {
2950
+ return allBindings['has']('checkedValue')
2951
+ ? ko.utils.unwrapObservable(allBindings.get('checkedValue'))
2952
+ : element.value;
2953
+ }
2954
+
2955
+ function updateModel() {
2956
+ // This updates the model value from the view value.
2957
+ // It runs in response to DOM events (click) and changes in checkedValue.
2958
+ var isChecked = element.checked,
2959
+ elemValue = useCheckedValue ? checkedValue() : isChecked;
2960
+
2961
+ // When we're first setting up this computed, don't change any model state.
2962
+ if (ko.computedContext.isInitial()) {
2963
+ return;
2964
+ }
2965
+
2966
+ // We can ignore unchecked radio buttons, because some other radio
2967
+ // button will be getting checked, and that one can take care of updating state.
2968
+ if (isRadio && !isChecked) {
2969
+ return;
2970
+ }
2971
+
2972
+ var modelValue = ko.dependencyDetection.ignore(valueAccessor);
2973
+ if (isValueArray) {
2974
+ if (oldElemValue !== elemValue) {
2975
+ // When we're responding to the checkedValue changing, and the element is
2976
+ // currently checked, replace the old elem value with the new elem value
2977
+ // in the model array.
2978
+ if (isChecked) {
2979
+ ko.utils.addOrRemoveItem(modelValue, elemValue, true);
2980
+ ko.utils.addOrRemoveItem(modelValue, oldElemValue, false);
2981
+ }
2982
+
2983
+ oldElemValue = elemValue;
2984
+ } else {
2985
+ // When we're responding to the user having checked/unchecked a checkbox,
2986
+ // add/remove the element value to the model array.
2987
+ ko.utils.addOrRemoveItem(modelValue, elemValue, isChecked);
2988
+ }
2989
+ } else {
2990
+ ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);
2991
+ }
2992
+ };
2993
+
2994
+ function updateView() {
2995
+ // This updates the view value from the model value.
2996
+ // It runs in response to changes in the bound (checked) value.
2997
+ var modelValue = ko.utils.unwrapObservable(valueAccessor());
2998
+
2999
+ if (isValueArray) {
3000
+ // When a checkbox is bound to an array, being checked represents its value being present in that array
3001
+ element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;
3002
+ } else if (isCheckbox) {
3003
+ // When a checkbox is bound to any other value (not an array), being checked represents the value being trueish
3004
+ element.checked = modelValue;
3005
+ } else {
3006
+ // For radio buttons, being checked means that the radio button's value corresponds to the model value
3007
+ element.checked = (checkedValue() === modelValue);
3008
+ }
3009
+ };
3010
+
3011
+ var isCheckbox = element.type == "checkbox",
3012
+ isRadio = element.type == "radio";
3013
+
3014
+ // Only bind to check boxes and radio buttons
3015
+ if (!isCheckbox && !isRadio) {
3016
+ return;
3017
+ }
3018
+
3019
+ var isValueArray = isCheckbox && (ko.utils.unwrapObservable(valueAccessor()) instanceof Array),
3020
+ oldElemValue = isValueArray ? checkedValue() : undefined,
3021
+ useCheckedValue = isRadio || isValueArray;
3022
+
3023
+ // IE 6 won't allow radio buttons to be selected unless they have a name
3024
+ if (isRadio && !element.name)
3025
+ ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
3026
+
3027
+ // Set up two computeds to update the binding:
3028
+
3029
+ // The first responds to changes in the checkedValue value and to element clicks
3030
+ ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });
3031
+ ko.utils.registerEventHandler(element, "click", updateModel);
3032
+
3033
+ // The second responds to changes in the model value (the one associated with the checked binding)
3034
+ ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
3035
+ }
3036
+ };
3037
+ ko.expressionRewriting.twoWayBindings['checked'] = true;
3038
+
3039
+ ko.bindingHandlers['checkedValue'] = {
3040
+ 'update': function (element, valueAccessor) {
3041
+ element.value = ko.utils.unwrapObservable(valueAccessor());
3042
+ }
3043
+ };
3044
+
3045
+ })();var classesWrittenByBindingKey = '__ko__cssValue';
3046
+ ko.bindingHandlers['css'] = {
3047
+ 'update': function (element, valueAccessor) {
3048
+ var value = ko.utils.unwrapObservable(valueAccessor());
3049
+ if (typeof value == "object") {
3050
+ ko.utils.objectForEach(value, function(className, shouldHaveClass) {
3051
+ shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
3052
+ ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
3053
+ });
3054
+ } else {
3055
+ value = String(value || ''); // Make sure we don't try to store or set a non-string value
3056
+ ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
3057
+ element[classesWrittenByBindingKey] = value;
3058
+ ko.utils.toggleDomNodeCssClass(element, value, true);
3059
+ }
3060
+ }
3061
+ };
3062
+ ko.bindingHandlers['enable'] = {
3063
+ 'update': function (element, valueAccessor) {
3064
+ var value = ko.utils.unwrapObservable(valueAccessor());
3065
+ if (value && element.disabled)
3066
+ element.removeAttribute("disabled");
3067
+ else if ((!value) && (!element.disabled))
3068
+ element.disabled = true;
3069
+ }
3070
+ };
3071
+
3072
+ ko.bindingHandlers['disable'] = {
3073
+ 'update': function (element, valueAccessor) {
3074
+ ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
3075
+ }
3076
+ };
3077
+ // For certain common events (currently just 'click'), allow a simplified data-binding syntax
3078
+ // e.g. click:handler instead of the usual full-length event:{click:handler}
3079
+ function makeEventHandlerShortcut(eventName) {
3080
+ ko.bindingHandlers[eventName] = {
3081
+ 'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3082
+ var newValueAccessor = function () {
3083
+ var result = {};
3084
+ result[eventName] = valueAccessor();
3085
+ return result;
3086
+ };
3087
+ return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
3088
+ }
3089
+ }
3090
+ }
3091
+
3092
+ ko.bindingHandlers['event'] = {
3093
+ 'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {
3094
+ var eventsToHandle = valueAccessor() || {};
3095
+ ko.utils.objectForEach(eventsToHandle, function(eventName) {
3096
+ if (typeof eventName == "string") {
3097
+ ko.utils.registerEventHandler(element, eventName, function (event) {
3098
+ var handlerReturnValue;
3099
+ var handlerFunction = valueAccessor()[eventName];
3100
+ if (!handlerFunction)
3101
+ return;
3102
+
3103
+ try {
3104
+ // Take all the event args, and prefix with the viewmodel
3105
+ var argsForHandler = ko.utils.makeArray(arguments);
3106
+ viewModel = bindingContext['$data'];
3107
+ argsForHandler.unshift(viewModel);
3108
+ handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
3109
+ } finally {
3110
+ if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
3111
+ if (event.preventDefault)
3112
+ event.preventDefault();
3113
+ else
3114
+ event.returnValue = false;
3115
+ }
3116
+ }
3117
+
3118
+ var bubble = allBindings.get(eventName + 'Bubble') !== false;
3119
+ if (!bubble) {
3120
+ event.cancelBubble = true;
3121
+ if (event.stopPropagation)
3122
+ event.stopPropagation();
3123
+ }
3124
+ });
3125
+ }
3126
+ });
3127
+ }
3128
+ };
3129
+ // "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
3130
+ // "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
3131
+ ko.bindingHandlers['foreach'] = {
3132
+ makeTemplateValueAccessor: function(valueAccessor) {
3133
+ return function() {
3134
+ var modelValue = valueAccessor(),
3135
+ unwrappedValue = ko.utils.peekObservable(modelValue); // Unwrap without setting a dependency here
3136
+
3137
+ // If unwrappedValue is the array, pass in the wrapped value on its own
3138
+ // The value will be unwrapped and tracked within the template binding
3139
+ // (See https://github.com/SteveSanderson/knockout/issues/523)
3140
+ if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
3141
+ return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
3142
+
3143
+ // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
3144
+ ko.utils.unwrapObservable(modelValue);
3145
+ return {
3146
+ 'foreach': unwrappedValue['data'],
3147
+ 'as': unwrappedValue['as'],
3148
+ 'includeDestroyed': unwrappedValue['includeDestroyed'],
3149
+ 'afterAdd': unwrappedValue['afterAdd'],
3150
+ 'beforeRemove': unwrappedValue['beforeRemove'],
3151
+ 'afterRender': unwrappedValue['afterRender'],
3152
+ 'beforeMove': unwrappedValue['beforeMove'],
3153
+ 'afterMove': unwrappedValue['afterMove'],
3154
+ 'templateEngine': ko.nativeTemplateEngine.instance
3155
+ };
3156
+ };
3157
+ },
3158
+ 'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3159
+ return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
3160
+ },
3161
+ 'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3162
+ return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);
3163
+ }
3164
+ };
3165
+ ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
3166
+ ko.virtualElements.allowedBindings['foreach'] = true;
3167
+ var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
3168
+ var hasfocusLastValue = '__ko_hasfocusLastValue';
3169
+ ko.bindingHandlers['hasfocus'] = {
3170
+ 'init': function(element, valueAccessor, allBindings) {
3171
+ var handleElementFocusChange = function(isFocused) {
3172
+ // Where possible, ignore which event was raised and determine focus state using activeElement,
3173
+ // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
3174
+ // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
3175
+ // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
3176
+ // from calling 'blur()' on the element when it loses focus.
3177
+ // Discussion at https://github.com/SteveSanderson/knockout/pull/352
3178
+ element[hasfocusUpdatingProperty] = true;
3179
+ var ownerDoc = element.ownerDocument;
3180
+ if ("activeElement" in ownerDoc) {
3181
+ var active;
3182
+ try {
3183
+ active = ownerDoc.activeElement;
3184
+ } catch(e) {
3185
+ // IE9 throws if you access activeElement during page load (see issue #703)
3186
+ active = ownerDoc.body;
3187
+ }
3188
+ isFocused = (active === element);
3189
+ }
3190
+ var modelValue = valueAccessor();
3191
+ ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);
3192
+
3193
+ //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function
3194
+ element[hasfocusLastValue] = isFocused;
3195
+ element[hasfocusUpdatingProperty] = false;
3196
+ };
3197
+ var handleElementFocusIn = handleElementFocusChange.bind(null, true);
3198
+ var handleElementFocusOut = handleElementFocusChange.bind(null, false);
3199
+
3200
+ ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
3201
+ ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
3202
+ ko.utils.registerEventHandler(element, "blur", handleElementFocusOut);
3203
+ ko.utils.registerEventHandler(element, "focusout", handleElementFocusOut); // For IE
3204
+ },
3205
+ 'update': function(element, valueAccessor) {
3206
+ var value = !!ko.utils.unwrapObservable(valueAccessor()); //force boolean to compare with last value
3207
+ if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {
3208
+ value ? element.focus() : element.blur();
3209
+ ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
3210
+ }
3211
+ }
3212
+ };
3213
+ ko.expressionRewriting.twoWayBindings['hasfocus'] = true;
3214
+
3215
+ ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make "hasFocus" an alias
3216
+ ko.expressionRewriting.twoWayBindings['hasFocus'] = true;
3217
+ ko.bindingHandlers['html'] = {
3218
+ 'init': function() {
3219
+ // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
3220
+ return { 'controlsDescendantBindings': true };
3221
+ },
3222
+ 'update': function (element, valueAccessor) {
3223
+ // setHtml will unwrap the value if needed
3224
+ ko.utils.setHtml(element, valueAccessor());
3225
+ }
3226
+ };
3227
+ // Makes a binding like with or if
3228
+ function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
3229
+ ko.bindingHandlers[bindingKey] = {
3230
+ 'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
3231
+ var didDisplayOnLastUpdate,
3232
+ savedNodes;
3233
+ ko.computed(function() {
3234
+ var dataValue = ko.utils.unwrapObservable(valueAccessor()),
3235
+ shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
3236
+ isFirstRender = !savedNodes,
3237
+ needsRefresh = isFirstRender || isWith || (shouldDisplay !== didDisplayOnLastUpdate);
3238
+
3239
+ if (needsRefresh) {
3240
+ // Save a copy of the inner nodes on the initial update, but only if we have dependencies.
3241
+ if (isFirstRender && ko.computedContext.getDependenciesCount()) {
3242
+ savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
3243
+ }
3244
+
3245
+ if (shouldDisplay) {
3246
+ if (!isFirstRender) {
3247
+ ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));
3248
+ }
3249
+ ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
3250
+ } else {
3251
+ ko.virtualElements.emptyNode(element);
3252
+ }
3253
+
3254
+ didDisplayOnLastUpdate = shouldDisplay;
3255
+ }
3256
+ }, null, { disposeWhenNodeIsRemoved: element });
3257
+ return { 'controlsDescendantBindings': true };
3258
+ }
3259
+ };
3260
+ ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
3261
+ ko.virtualElements.allowedBindings[bindingKey] = true;
3262
+ }
3263
+
3264
+ // Construct the actual binding handlers
3265
+ makeWithIfBinding('if');
3266
+ makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
3267
+ makeWithIfBinding('with', true /* isWith */, false /* isNot */,
3268
+ function(bindingContext, dataValue) {
3269
+ return bindingContext['createChildContext'](dataValue);
3270
+ }
3271
+ );
3272
+ var captionPlaceholder = {};
3273
+ ko.bindingHandlers['options'] = {
3274
+ 'init': function(element) {
3275
+ if (ko.utils.tagNameLower(element) !== "select")
3276
+ throw new Error("options binding applies only to SELECT elements");
3277
+
3278
+ // Remove all existing <option>s.
3279
+ while (element.length > 0) {
3280
+ element.remove(0);
3281
+ }
3282
+
3283
+ // Ensures that the binding processor doesn't try to bind the options
3284
+ return { 'controlsDescendantBindings': true };
3285
+ },
3286
+ 'update': function (element, valueAccessor, allBindings) {
3287
+ function selectedOptions() {
3288
+ return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });
3289
+ }
3290
+
3291
+ var selectWasPreviouslyEmpty = element.length == 0;
3292
+ var previousScrollTop = (!selectWasPreviouslyEmpty && element.multiple) ? element.scrollTop : null;
3293
+ var unwrappedArray = ko.utils.unwrapObservable(valueAccessor());
3294
+ var includeDestroyed = allBindings.get('optionsIncludeDestroyed');
3295
+ var arrayToDomNodeChildrenOptions = {};
3296
+ var captionValue;
3297
+ var filteredArray;
3298
+ var previousSelectedValues;
3299
+
3300
+ if (element.multiple) {
3301
+ previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);
3302
+ } else {
3303
+ previousSelectedValues = element.selectedIndex >= 0 ? [ ko.selectExtensions.readValue(element.options[element.selectedIndex]) ] : [];
3304
+ }
3305
+
3306
+ if (unwrappedArray) {
3307
+ if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
3308
+ unwrappedArray = [unwrappedArray];
3309
+
3310
+ // Filter out any entries marked as destroyed
3311
+ filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
3312
+ return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
3313
+ });
3314
+
3315
+ // If caption is included, add it to the array
3316
+ if (allBindings['has']('optionsCaption')) {
3317
+ captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));
3318
+ // If caption value is null or undefined, don't show a caption
3319
+ if (captionValue !== null && captionValue !== undefined) {
3320
+ filteredArray.unshift(captionPlaceholder);
3321
+ }
3322
+ }
3323
+ } else {
3324
+ // If a falsy value is provided (e.g. null), we'll simply empty the select element
3325
+ }
3326
+
3327
+ function applyToObject(object, predicate, defaultValue) {
3328
+ var predicateType = typeof predicate;
3329
+ if (predicateType == "function") // Given a function; run it against the data value
3330
+ return predicate(object);
3331
+ else if (predicateType == "string") // Given a string; treat it as a property name on the data value
3332
+ return object[predicate];
3333
+ else // Given no optionsText arg; use the data value itself
3334
+ return defaultValue;
3335
+ }
3336
+
3337
+ // The following functions can run at two different times:
3338
+ // The first is when the whole array is being updated directly from this binding handler.
3339
+ // The second is when an observable value for a specific array entry is updated.
3340
+ // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.
3341
+ var itemUpdate = false;
3342
+ function optionForArrayItem(arrayEntry, index, oldOptions) {
3343
+ if (oldOptions.length) {
3344
+ previousSelectedValues = oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
3345
+ itemUpdate = true;
3346
+ }
3347
+ var option = element.ownerDocument.createElement("option");
3348
+ if (arrayEntry === captionPlaceholder) {
3349
+ ko.utils.setTextContent(option, allBindings.get('optionsCaption'));
3350
+ ko.selectExtensions.writeValue(option, undefined);
3351
+ } else {
3352
+ // Apply a value to the option element
3353
+ var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);
3354
+ ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
3355
+
3356
+ // Apply some text to the option element
3357
+ var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);
3358
+ ko.utils.setTextContent(option, optionText);
3359
+ }
3360
+ return [option];
3361
+ }
3362
+
3363
+ // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection
3364
+ // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208
3365
+ arrayToDomNodeChildrenOptions['beforeRemove'] =
3366
+ function (option) {
3367
+ element.removeChild(option);
3368
+ };
3369
+
3370
+ function setSelectionCallback(arrayEntry, newOptions) {
3371
+ // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
3372
+ // That's why we first added them without selection. Now it's time to set the selection.
3373
+ if (previousSelectedValues.length) {
3374
+ var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;
3375
+ ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);
3376
+
3377
+ // If this option was changed from being selected during a single-item update, notify the change
3378
+ if (itemUpdate && !isSelected)
3379
+ ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
3380
+ }
3381
+ }
3382
+
3383
+ var callback = setSelectionCallback;
3384
+ if (allBindings['has']('optionsAfterRender')) {
3385
+ callback = function(arrayEntry, newOptions) {
3386
+ setSelectionCallback(arrayEntry, newOptions);
3387
+ ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
3388
+ }
3389
+ }
3390
+
3391
+ ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);
3392
+
3393
+ ko.dependencyDetection.ignore(function () {
3394
+ if (allBindings.get('valueAllowUnset') && allBindings['has']('value')) {
3395
+ // The model value is authoritative, so make sure its value is the one selected
3396
+ ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
3397
+ } else {
3398
+ // Determine if the selection has changed as a result of updating the options list
3399
+ var selectionChanged;
3400
+ if (element.multiple) {
3401
+ // For a multiple-select box, compare the new selection count to the previous one
3402
+ // But if nothing was selected before, the selection can't have changed
3403
+ selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
3404
+ } else {
3405
+ // For a single-select box, compare the current value to the previous value
3406
+ // But if nothing was selected before or nothing is selected now, just look for a change in selection
3407
+ selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)
3408
+ ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])
3409
+ : (previousSelectedValues.length || element.selectedIndex >= 0);
3410
+ }
3411
+
3412
+ // Ensure consistency between model value and selected option.
3413
+ // If the dropdown was changed so that selection is no longer the same,
3414
+ // notify the value or selectedOptions binding.
3415
+ if (selectionChanged) {
3416
+ ko.utils.triggerEvent(element, "change");
3417
+ }
3418
+ }
3419
+ });
3420
+
3421
+ // Workaround for IE bug
3422
+ ko.utils.ensureSelectElementIsRenderedCorrectly(element);
3423
+
3424
+ if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)
3425
+ element.scrollTop = previousScrollTop;
3426
+ }
3427
+ };
3428
+ ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();
3429
+ ko.bindingHandlers['selectedOptions'] = {
3430
+ 'after': ['options', 'foreach'],
3431
+ 'init': function (element, valueAccessor, allBindings) {
3432
+ ko.utils.registerEventHandler(element, "change", function () {
3433
+ var value = valueAccessor(), valueToWrite = [];
3434
+ ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
3435
+ if (node.selected)
3436
+ valueToWrite.push(ko.selectExtensions.readValue(node));
3437
+ });
3438
+ ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);
3439
+ });
3440
+ },
3441
+ 'update': function (element, valueAccessor) {
3442
+ if (ko.utils.tagNameLower(element) != "select")
3443
+ throw new Error("values binding applies only to SELECT elements");
3444
+
3445
+ var newValue = ko.utils.unwrapObservable(valueAccessor());
3446
+ if (newValue && typeof newValue.length == "number") {
3447
+ ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
3448
+ var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
3449
+ ko.utils.setOptionNodeSelectionState(node, isSelected);
3450
+ });
3451
+ }
3452
+ }
3453
+ };
3454
+ ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;
3455
+ ko.bindingHandlers['style'] = {
3456
+ 'update': function (element, valueAccessor) {
3457
+ var value = ko.utils.unwrapObservable(valueAccessor() || {});
3458
+ ko.utils.objectForEach(value, function(styleName, styleValue) {
3459
+ styleValue = ko.utils.unwrapObservable(styleValue);
3460
+ element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
3461
+ });
3462
+ }
3463
+ };
3464
+ ko.bindingHandlers['submit'] = {
3465
+ 'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
3466
+ if (typeof valueAccessor() != "function")
3467
+ throw new Error("The value for a submit binding must be a function");
3468
+ ko.utils.registerEventHandler(element, "submit", function (event) {
3469
+ var handlerReturnValue;
3470
+ var value = valueAccessor();
3471
+ try { handlerReturnValue = value.call(bindingContext['$data'], element); }
3472
+ finally {
3473
+ if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
3474
+ if (event.preventDefault)
3475
+ event.preventDefault();
3476
+ else
3477
+ event.returnValue = false;
3478
+ }
3479
+ }
3480
+ });
3481
+ }
3482
+ };
3483
+ ko.bindingHandlers['text'] = {
3484
+ 'init': function() {
3485
+ // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
3486
+ // It should also make things faster, as we no longer have to consider whether the text node might be bindable.
3487
+ return { 'controlsDescendantBindings': true };
3488
+ },
3489
+ 'update': function (element, valueAccessor) {
3490
+ ko.utils.setTextContent(element, valueAccessor());
3491
+ }
3492
+ };
3493
+ ko.virtualElements.allowedBindings['text'] = true;
3494
+ ko.bindingHandlers['uniqueName'] = {
3495
+ 'init': function (element, valueAccessor) {
3496
+ if (valueAccessor()) {
3497
+ var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
3498
+ ko.utils.setElementName(element, name);
3499
+ }
3500
+ }
3501
+ };
3502
+ ko.bindingHandlers['uniqueName'].currentIndex = 0;
3503
+ ko.bindingHandlers['value'] = {
3504
+ 'after': ['options', 'foreach'],
3505
+ 'init': function (element, valueAccessor, allBindings) {
3506
+ // Always catch "change" event; possibly other events too if asked
3507
+ var eventsToCatch = ["change"];
3508
+ var requestedEventsToCatch = allBindings.get("valueUpdate");
3509
+ var propertyChangedFired = false;
3510
+ if (requestedEventsToCatch) {
3511
+ if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
3512
+ requestedEventsToCatch = [requestedEventsToCatch];
3513
+ ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
3514
+ eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
3515
+ }
3516
+
3517
+ var valueUpdateHandler = function() {
3518
+ propertyChangedFired = false;
3519
+ var modelValue = valueAccessor();
3520
+ var elementValue = ko.selectExtensions.readValue(element);
3521
+ ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);
3522
+ }
3523
+
3524
+ // Workaround for https://github.com/SteveSanderson/knockout/issues/122
3525
+ // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
3526
+ var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
3527
+ && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
3528
+ if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
3529
+ ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
3530
+ ko.utils.registerEventHandler(element, "focus", function () { propertyChangedFired = false });
3531
+ ko.utils.registerEventHandler(element, "blur", function() {
3532
+ if (propertyChangedFired) {
3533
+ valueUpdateHandler();
3534
+ }
3535
+ });
3536
+ }
3537
+
3538
+ ko.utils.arrayForEach(eventsToCatch, function(eventName) {
3539
+ // The syntax "after<eventname>" means "run the handler asynchronously after the event"
3540
+ // This is useful, for example, to catch "keydown" events after the browser has updated the control
3541
+ // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
3542
+ var handler = valueUpdateHandler;
3543
+ if (ko.utils.stringStartsWith(eventName, "after")) {
3544
+ handler = function() { setTimeout(valueUpdateHandler, 0) };
3545
+ eventName = eventName.substring("after".length);
3546
+ }
3547
+ ko.utils.registerEventHandler(element, eventName, handler);
3548
+ });
3549
+ },
3550
+ 'update': function (element, valueAccessor, allBindings) {
3551
+ var newValue = ko.utils.unwrapObservable(valueAccessor());
3552
+ var elementValue = ko.selectExtensions.readValue(element);
3553
+ var valueHasChanged = (newValue !== elementValue);
3554
+
3555
+ if (valueHasChanged) {
3556
+ if (ko.utils.tagNameLower(element) === "select") {
3557
+ var allowUnset = allBindings.get('valueAllowUnset');
3558
+ var applyValueAction = function () {
3559
+ ko.selectExtensions.writeValue(element, newValue, allowUnset);
3560
+ };
3561
+ applyValueAction();
3562
+
3563
+ if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {
3564
+ // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
3565
+ // because you're not allowed to have a model value that disagrees with a visible UI selection.
3566
+ ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
3567
+ } else {
3568
+ // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
3569
+ // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
3570
+ // to apply the value as well.
3571
+ setTimeout(applyValueAction, 0);
3572
+ }
3573
+ } else {
3574
+ ko.selectExtensions.writeValue(element, newValue);
3575
+ }
3576
+ }
3577
+ }
3578
+ };
3579
+ ko.expressionRewriting.twoWayBindings['value'] = true;
3580
+ ko.bindingHandlers['visible'] = {
3581
+ 'update': function (element, valueAccessor) {
3582
+ var value = ko.utils.unwrapObservable(valueAccessor());
3583
+ var isCurrentlyVisible = !(element.style.display == "none");
3584
+ if (value && !isCurrentlyVisible)
3585
+ element.style.display = "";
3586
+ else if ((!value) && isCurrentlyVisible)
3587
+ element.style.display = "none";
3588
+ }
3589
+ };
3590
+ // 'click' is just a shorthand for the usual full-length event:{click:handler}
3591
+ makeEventHandlerShortcut('click');
3592
+ // If you want to make a custom template engine,
3593
+ //
3594
+ // [1] Inherit from this class (like ko.nativeTemplateEngine does)
3595
+ // [2] Override 'renderTemplateSource', supplying a function with this signature:
3596
+ //
3597
+ // function (templateSource, bindingContext, options) {
3598
+ // // - templateSource.text() is the text of the template you should render
3599
+ // // - bindingContext.$data is the data you should pass into the template
3600
+ // // - you might also want to make bindingContext.$parent, bindingContext.$parents,
3601
+ // // and bindingContext.$root available in the template too
3602
+ // // - options gives you access to any other properties set on "data-bind: { template: options }"
3603
+ // //
3604
+ // // Return value: an array of DOM nodes
3605
+ // }
3606
+ //
3607
+ // [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
3608
+ //
3609
+ // function (script) {
3610
+ // // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
3611
+ // // For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
3612
+ // }
3613
+ //
3614
+ // This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
3615
+ // If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
3616
+ // and then you don't need to override 'createJavaScriptEvaluatorBlock'.
3617
+
3618
+ ko.templateEngine = function () { };
3619
+
3620
+ ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
3621
+ throw new Error("Override renderTemplateSource");
3622
+ };
3623
+
3624
+ ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
3625
+ throw new Error("Override createJavaScriptEvaluatorBlock");
3626
+ };
3627
+
3628
+ ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
3629
+ // Named template
3630
+ if (typeof template == "string") {
3631
+ templateDocument = templateDocument || document;
3632
+ var elem = templateDocument.getElementById(template);
3633
+ if (!elem)
3634
+ throw new Error("Cannot find template with ID " + template);
3635
+ return new ko.templateSources.domElement(elem);
3636
+ } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
3637
+ // Anonymous template
3638
+ return new ko.templateSources.anonymousTemplate(template);
3639
+ } else
3640
+ throw new Error("Unknown template type: " + template);
3641
+ };
3642
+
3643
+ ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
3644
+ var templateSource = this['makeTemplateSource'](template, templateDocument);
3645
+ return this['renderTemplateSource'](templateSource, bindingContext, options);
3646
+ };
3647
+
3648
+ ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
3649
+ // Skip rewriting if requested
3650
+ if (this['allowTemplateRewriting'] === false)
3651
+ return true;
3652
+ return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
3653
+ };
3654
+
3655
+ ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
3656
+ var templateSource = this['makeTemplateSource'](template, templateDocument);
3657
+ var rewritten = rewriterCallback(templateSource['text']());
3658
+ templateSource['text'](rewritten);
3659
+ templateSource['data']("isRewritten", true);
3660
+ };
3661
+
3662
+ ko.exportSymbol('templateEngine', ko.templateEngine);
3663
+
3664
+ ko.templateRewriting = (function () {
3665
+ var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
3666
+ var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
3667
+
3668
+ function validateDataBindValuesForRewriting(keyValueArray) {
3669
+ var allValidators = ko.expressionRewriting.bindingRewriteValidators;
3670
+ for (var i = 0; i < keyValueArray.length; i++) {
3671
+ var key = keyValueArray[i]['key'];
3672
+ if (allValidators.hasOwnProperty(key)) {
3673
+ var validator = allValidators[key];
3674
+
3675
+ if (typeof validator === "function") {
3676
+ var possibleErrorMessage = validator(keyValueArray[i]['value']);
3677
+ if (possibleErrorMessage)
3678
+ throw new Error(possibleErrorMessage);
3679
+ } else if (!validator) {
3680
+ throw new Error("This template engine does not support the '" + key + "' binding within its templates");
3681
+ }
3682
+ }
3683
+ }
3684
+ }
3685
+
3686
+ function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {
3687
+ var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
3688
+ validateDataBindValuesForRewriting(dataBindKeyValueArray);
3689
+ var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});
3690
+
3691
+ // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
3692
+ // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
3693
+ // extra indirection.
3694
+ var applyBindingsToNextSiblingScript =
3695
+ "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()},'" + nodeName.toLowerCase() + "')";
3696
+ return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
3697
+ }
3698
+
3699
+ return {
3700
+ ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
3701
+ if (!templateEngine['isTemplateRewritten'](template, templateDocument))
3702
+ templateEngine['rewriteTemplate'](template, function (htmlString) {
3703
+ return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
3704
+ }, templateDocument);
3705
+ },
3706
+
3707
+ memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
3708
+ return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
3709
+ return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);
3710
+ }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
3711
+ return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", /* nodeName: */ "#comment", templateEngine);
3712
+ });
3713
+ },
3714
+
3715
+ applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {
3716
+ return ko.memoization.memoize(function (domNode, bindingContext) {
3717
+ var nodeToBind = domNode.nextSibling;
3718
+ if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
3719
+ ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
3720
+ }
3721
+ });
3722
+ }
3723
+ }
3724
+ })();
3725
+
3726
+
3727
+ // Exported only because it has to be referenced by string lookup from within rewritten template
3728
+ ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
3729
+ (function() {
3730
+ // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
3731
+ // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
3732
+ //
3733
+ // Two are provided by default:
3734
+ // 1. ko.templateSources.domElement - reads/writes the text content of an arbitrary DOM element
3735
+ // 2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
3736
+ // without reading/writing the actual element text content, since it will be overwritten
3737
+ // with the rendered template output.
3738
+ // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
3739
+ // Template sources need to have the following functions:
3740
+ // text() - returns the template text from your storage location
3741
+ // text(value) - writes the supplied template text to your storage location
3742
+ // data(key) - reads values stored using data(key, value) - see below
3743
+ // data(key, value) - associates "value" with this template and the key "key". Is used to store information like "isRewritten".
3744
+ //
3745
+ // Optionally, template sources can also have the following functions:
3746
+ // nodes() - returns a DOM element containing the nodes of this template, where available
3747
+ // nodes(value) - writes the given DOM element to your storage location
3748
+ // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
3749
+ // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
3750
+ //
3751
+ // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
3752
+ // using and overriding "makeTemplateSource" to return an instance of your custom template source.
3753
+
3754
+ ko.templateSources = {};
3755
+
3756
+ // ---- ko.templateSources.domElement -----
3757
+
3758
+ ko.templateSources.domElement = function(element) {
3759
+ this.domElement = element;
3760
+ }
3761
+
3762
+ ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
3763
+ var tagNameLower = ko.utils.tagNameLower(this.domElement),
3764
+ elemContentsProperty = tagNameLower === "script" ? "text"
3765
+ : tagNameLower === "textarea" ? "value"
3766
+ : "innerHTML";
3767
+
3768
+ if (arguments.length == 0) {
3769
+ return this.domElement[elemContentsProperty];
3770
+ } else {
3771
+ var valueToWrite = arguments[0];
3772
+ if (elemContentsProperty === "innerHTML")
3773
+ ko.utils.setHtml(this.domElement, valueToWrite);
3774
+ else
3775
+ this.domElement[elemContentsProperty] = valueToWrite;
3776
+ }
3777
+ };
3778
+
3779
+ var dataDomDataPrefix = ko.utils.domData.nextKey() + "_";
3780
+ ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
3781
+ if (arguments.length === 1) {
3782
+ return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);
3783
+ } else {
3784
+ ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
3785
+ }
3786
+ };
3787
+
3788
+ // ---- ko.templateSources.anonymousTemplate -----
3789
+ // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
3790
+ // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
3791
+ // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
3792
+
3793
+ var anonymousTemplatesDomDataKey = ko.utils.domData.nextKey();
3794
+ ko.templateSources.anonymousTemplate = function(element) {
3795
+ this.domElement = element;
3796
+ }
3797
+ ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
3798
+ ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;
3799
+ ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
3800
+ if (arguments.length == 0) {
3801
+ var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
3802
+ if (templateData.textData === undefined && templateData.containerData)
3803
+ templateData.textData = templateData.containerData.innerHTML;
3804
+ return templateData.textData;
3805
+ } else {
3806
+ var valueToWrite = arguments[0];
3807
+ ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
3808
+ }
3809
+ };
3810
+ ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
3811
+ if (arguments.length == 0) {
3812
+ var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
3813
+ return templateData.containerData;
3814
+ } else {
3815
+ var valueToWrite = arguments[0];
3816
+ ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
3817
+ }
3818
+ };
3819
+
3820
+ ko.exportSymbol('templateSources', ko.templateSources);
3821
+ ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
3822
+ ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
3823
+ })();
3824
+ (function () {
3825
+ var _templateEngine;
3826
+ ko.setTemplateEngine = function (templateEngine) {
3827
+ if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
3828
+ throw new Error("templateEngine must inherit from ko.templateEngine");
3829
+ _templateEngine = templateEngine;
3830
+ }
3831
+
3832
+ function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
3833
+ var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
3834
+ while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
3835
+ nextInQueue = ko.virtualElements.nextSibling(node);
3836
+ action(node, nextInQueue);
3837
+ }
3838
+ }
3839
+
3840
+ function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
3841
+ // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
3842
+ // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
3843
+ // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
3844
+ // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
3845
+ // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
3846
+
3847
+ if (continuousNodeArray.length) {
3848
+ var firstNode = continuousNodeArray[0],
3849
+ lastNode = continuousNodeArray[continuousNodeArray.length - 1],
3850
+ parentNode = firstNode.parentNode,
3851
+ provider = ko.bindingProvider['instance'],
3852
+ preprocessNode = provider['preprocessNode'];
3853
+
3854
+ if (preprocessNode) {
3855
+ invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {
3856
+ var nodePreviousSibling = node.previousSibling;
3857
+ var newNodes = preprocessNode.call(provider, node);
3858
+ if (newNodes) {
3859
+ if (node === firstNode)
3860
+ firstNode = newNodes[0] || nextNodeInRange;
3861
+ if (node === lastNode)
3862
+ lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;
3863
+ }
3864
+ });
3865
+
3866
+ // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.
3867
+ // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real
3868
+ // first node needs to be in the array).
3869
+ continuousNodeArray.length = 0;
3870
+ if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do
3871
+ return;
3872
+ }
3873
+ if (firstNode === lastNode) {
3874
+ continuousNodeArray.push(firstNode);
3875
+ } else {
3876
+ continuousNodeArray.push(firstNode, lastNode);
3877
+ ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
3878
+ }
3879
+ }
3880
+
3881
+ // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
3882
+ // whereas a regular applyBindings won't introduce new memoized nodes
3883
+ invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
3884
+ if (node.nodeType === 1 || node.nodeType === 8)
3885
+ ko.applyBindings(bindingContext, node);
3886
+ });
3887
+ invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
3888
+ if (node.nodeType === 1 || node.nodeType === 8)
3889
+ ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
3890
+ });
3891
+
3892
+ // Make sure any changes done by applyBindings or unmemoize are reflected in the array
3893
+ ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
3894
+ }
3895
+ }
3896
+
3897
+ function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
3898
+ return nodeOrNodeArray.nodeType ? nodeOrNodeArray
3899
+ : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
3900
+ : null;
3901
+ }
3902
+
3903
+ function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
3904
+ options = options || {};
3905
+ var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
3906
+ var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
3907
+ var templateEngineToUse = (options['templateEngine'] || _templateEngine);
3908
+ ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
3909
+ var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
3910
+
3911
+ // Loosely check result is an array of DOM nodes
3912
+ if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
3913
+ throw new Error("Template engine must return an array of DOM nodes");
3914
+
3915
+ var haveAddedNodesToParent = false;
3916
+ switch (renderMode) {
3917
+ case "replaceChildren":
3918
+ ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
3919
+ haveAddedNodesToParent = true;
3920
+ break;
3921
+ case "replaceNode":
3922
+ ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
3923
+ haveAddedNodesToParent = true;
3924
+ break;
3925
+ case "ignoreTargetNode": break;
3926
+ default:
3927
+ throw new Error("Unknown renderMode: " + renderMode);
3928
+ }
3929
+
3930
+ if (haveAddedNodesToParent) {
3931
+ activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
3932
+ if (options['afterRender'])
3933
+ ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
3934
+ }
3935
+
3936
+ return renderedNodesArray;
3937
+ }
3938
+
3939
+ ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
3940
+ options = options || {};
3941
+ if ((options['templateEngine'] || _templateEngine) == undefined)
3942
+ throw new Error("Set a template engine before calling renderTemplate");
3943
+ renderMode = renderMode || "replaceChildren";
3944
+
3945
+ if (targetNodeOrNodeArray) {
3946
+ var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
3947
+
3948
+ var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
3949
+ var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
3950
+
3951
+ return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
3952
+ function () {
3953
+ // Ensure we've got a proper binding context to work with
3954
+ var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
3955
+ ? dataOrBindingContext
3956
+ : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
3957
+
3958
+ // Support selecting template as a function of the data being rendered
3959
+ var templateName = ko.isObservable(template) ? template()
3960
+ : typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
3961
+
3962
+ var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
3963
+ if (renderMode == "replaceNode") {
3964
+ targetNodeOrNodeArray = renderedNodesArray;
3965
+ firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
3966
+ }
3967
+ },
3968
+ null,
3969
+ { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
3970
+ );
3971
+ } else {
3972
+ // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
3973
+ return ko.memoization.memoize(function (domNode) {
3974
+ ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
3975
+ });
3976
+ }
3977
+ };
3978
+
3979
+ ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
3980
+ // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
3981
+ // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
3982
+ var arrayItemContext;
3983
+
3984
+ // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
3985
+ var executeTemplateForArrayItem = function (arrayValue, index) {
3986
+ // Support selecting template as a function of the data being rendered
3987
+ arrayItemContext = parentBindingContext['createChildContext'](arrayValue, options['as'], function(context) {
3988
+ context['$index'] = index;
3989
+ });
3990
+ var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
3991
+ return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
3992
+ }
3993
+
3994
+ // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
3995
+ var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
3996
+ activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
3997
+ if (options['afterRender'])
3998
+ options['afterRender'](addedNodesArray, arrayValue);
3999
+ };
4000
+
4001
+ return ko.dependentObservable(function () {
4002
+ var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
4003
+ if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
4004
+ unwrappedArray = [unwrappedArray];
4005
+
4006
+ // Filter out any entries marked as destroyed
4007
+ var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
4008
+ return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
4009
+ });
4010
+
4011
+ // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
4012
+ // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
4013
+ ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
4014
+
4015
+ }, null, { disposeWhenNodeIsRemoved: targetNode });
4016
+ };
4017
+
4018
+ var templateComputedDomDataKey = ko.utils.domData.nextKey();
4019
+ function disposeOldComputedAndStoreNewOne(element, newComputed) {
4020
+ var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
4021
+ if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
4022
+ oldComputed.dispose();
4023
+ ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
4024
+ }
4025
+
4026
+ ko.bindingHandlers['template'] = {
4027
+ 'init': function(element, valueAccessor) {
4028
+ // Support anonymous templates
4029
+ var bindingValue = ko.utils.unwrapObservable(valueAccessor());
4030
+ if (typeof bindingValue == "string" || bindingValue['name']) {
4031
+ // It's a named template - clear the element
4032
+ ko.virtualElements.emptyNode(element);
4033
+ } else {
4034
+ // It's an anonymous template - store the element contents, then clear the element
4035
+ var templateNodes = ko.virtualElements.childNodes(element),
4036
+ container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
4037
+ new ko.templateSources.anonymousTemplate(element)['nodes'](container);
4038
+ }
4039
+ return { 'controlsDescendantBindings': true };
4040
+ },
4041
+ 'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
4042
+ var value = valueAccessor(),
4043
+ dataValue,
4044
+ options = ko.utils.unwrapObservable(value),
4045
+ shouldDisplay = true,
4046
+ templateComputed = null,
4047
+ templateName;
4048
+
4049
+ if (typeof options == "string") {
4050
+ templateName = value;
4051
+ options = {};
4052
+ } else {
4053
+ templateName = options['name'];
4054
+
4055
+ // Support "if"/"ifnot" conditions
4056
+ if ('if' in options)
4057
+ shouldDisplay = ko.utils.unwrapObservable(options['if']);
4058
+ if (shouldDisplay && 'ifnot' in options)
4059
+ shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
4060
+
4061
+ dataValue = ko.utils.unwrapObservable(options['data']);
4062
+ }
4063
+
4064
+ if ('foreach' in options) {
4065
+ // Render once for each data point (treating data set as empty if shouldDisplay==false)
4066
+ var dataArray = (shouldDisplay && options['foreach']) || [];
4067
+ templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
4068
+ } else if (!shouldDisplay) {
4069
+ ko.virtualElements.emptyNode(element);
4070
+ } else {
4071
+ // Render once for this single data point (or use the viewModel if no data was provided)
4072
+ var innerBindingContext = ('data' in options) ?
4073
+ bindingContext['createChildContext'](dataValue, options['as']) : // Given an explitit 'data' value, we create a child binding context for it
4074
+ bindingContext; // Given no explicit 'data' value, we retain the same binding context
4075
+ templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
4076
+ }
4077
+
4078
+ // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
4079
+ disposeOldComputedAndStoreNewOne(element, templateComputed);
4080
+ }
4081
+ };
4082
+
4083
+ // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
4084
+ ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
4085
+ var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
4086
+
4087
+ if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
4088
+ return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
4089
+
4090
+ if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
4091
+ return null; // Named templates can be rewritten, so return "no error"
4092
+ return "This template engine does not support anonymous templates nested within its templates";
4093
+ };
4094
+
4095
+ ko.virtualElements.allowedBindings['template'] = true;
4096
+ })();
4097
+
4098
+ ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
4099
+ ko.exportSymbol('renderTemplate', ko.renderTemplate);
4100
+ // Go through the items that have been added and deleted and try to find matches between them.
4101
+ ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {
4102
+ if (left.length && right.length) {
4103
+ var failedCompares, l, r, leftItem, rightItem;
4104
+ for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {
4105
+ for (r = 0; rightItem = right[r]; ++r) {
4106
+ if (leftItem['value'] === rightItem['value']) {
4107
+ leftItem['moved'] = rightItem['index'];
4108
+ rightItem['moved'] = leftItem['index'];
4109
+ right.splice(r, 1); // This item is marked as moved; so remove it from right list
4110
+ failedCompares = r = 0; // Reset failed compares count because we're checking for consecutive failures
4111
+ break;
4112
+ }
4113
+ }
4114
+ failedCompares += r;
4115
+ }
4116
+ }
4117
+ };
4118
+
4119
+ ko.utils.compareArrays = (function () {
4120
+ var statusNotInOld = 'added', statusNotInNew = 'deleted';
4121
+
4122
+ // Simple calculation based on Levenshtein distance.
4123
+ function compareArrays(oldArray, newArray, options) {
4124
+ // For backward compatibility, if the third arg is actually a bool, interpret
4125
+ // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.
4126
+ options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});
4127
+ oldArray = oldArray || [];
4128
+ newArray = newArray || [];
4129
+
4130
+ if (oldArray.length <= newArray.length)
4131
+ return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);
4132
+ else
4133
+ return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);
4134
+ }
4135
+
4136
+ function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {
4137
+ var myMin = Math.min,
4138
+ myMax = Math.max,
4139
+ editDistanceMatrix = [],
4140
+ smlIndex, smlIndexMax = smlArray.length,
4141
+ bigIndex, bigIndexMax = bigArray.length,
4142
+ compareRange = (bigIndexMax - smlIndexMax) || 1,
4143
+ maxDistance = smlIndexMax + bigIndexMax + 1,
4144
+ thisRow, lastRow,
4145
+ bigIndexMaxForRow, bigIndexMinForRow;
4146
+
4147
+ for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
4148
+ lastRow = thisRow;
4149
+ editDistanceMatrix.push(thisRow = []);
4150
+ bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
4151
+ bigIndexMinForRow = myMax(0, smlIndex - 1);
4152
+ for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
4153
+ if (!bigIndex)
4154
+ thisRow[bigIndex] = smlIndex + 1;
4155
+ else if (!smlIndex) // Top row - transform empty array into new array via additions
4156
+ thisRow[bigIndex] = bigIndex + 1;
4157
+ else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
4158
+ thisRow[bigIndex] = lastRow[bigIndex - 1]; // copy value (no edit)
4159
+ else {
4160
+ var northDistance = lastRow[bigIndex] || maxDistance; // not in big (deletion)
4161
+ var westDistance = thisRow[bigIndex - 1] || maxDistance; // not in small (addition)
4162
+ thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
4163
+ }
4164
+ }
4165
+ }
4166
+
4167
+ var editScript = [], meMinusOne, notInSml = [], notInBig = [];
4168
+ for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
4169
+ meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
4170
+ if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
4171
+ notInSml.push(editScript[editScript.length] = { // added
4172
+ 'status': statusNotInSml,
4173
+ 'value': bigArray[--bigIndex],
4174
+ 'index': bigIndex });
4175
+ } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
4176
+ notInBig.push(editScript[editScript.length] = { // deleted
4177
+ 'status': statusNotInBig,
4178
+ 'value': smlArray[--smlIndex],
4179
+ 'index': smlIndex });
4180
+ } else {
4181
+ --bigIndex;
4182
+ --smlIndex;
4183
+ if (!options['sparse']) {
4184
+ editScript.push({
4185
+ 'status': "retained",
4186
+ 'value': bigArray[bigIndex] });
4187
+ }
4188
+ }
4189
+ }
4190
+
4191
+ // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
4192
+ // smlIndexMax keeps the time complexity of this algorithm linear.
4193
+ ko.utils.findMovesInArrayComparison(notInSml, notInBig, smlIndexMax * 10);
4194
+
4195
+ return editScript.reverse();
4196
+ }
4197
+
4198
+ return compareArrays;
4199
+ })();
4200
+
4201
+ ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
4202
+ (function () {
4203
+ // Objective:
4204
+ // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
4205
+ // map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
4206
+ // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
4207
+ // so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
4208
+ // previously mapped - retain those nodes, and just insert/delete other ones
4209
+
4210
+ // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
4211
+ // You can use this, for example, to activate bindings on those nodes.
4212
+
4213
+ function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
4214
+ // Map this array value inside a dependentObservable so we re-map when any dependency changes
4215
+ var mappedNodes = [];
4216
+ var dependentObservable = ko.dependentObservable(function() {
4217
+ var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];
4218
+
4219
+ // On subsequent evaluations, just replace the previously-inserted DOM nodes
4220
+ if (mappedNodes.length > 0) {
4221
+ ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);
4222
+ if (callbackAfterAddingNodes)
4223
+ ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
4224
+ }
4225
+
4226
+ // Replace the contents of the mappedNodes array, thereby updating the record
4227
+ // of which nodes would be deleted if valueToMap was itself later removed
4228
+ mappedNodes.length = 0;
4229
+ ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
4230
+ }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });
4231
+ return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
4232
+ }
4233
+
4234
+ var lastMappingResultDomDataKey = ko.utils.domData.nextKey();
4235
+
4236
+ ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
4237
+ // Compare the provided array against the previous one
4238
+ array = array || [];
4239
+ options = options || {};
4240
+ var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
4241
+ var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
4242
+ var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
4243
+ var editScript = ko.utils.compareArrays(lastArray, array, options['dontLimitMoves']);
4244
+
4245
+ // Build the new mapping result
4246
+ var newMappingResult = [];
4247
+ var lastMappingResultIndex = 0;
4248
+ var newMappingResultIndex = 0;
4249
+
4250
+ var nodesToDelete = [];
4251
+ var itemsToProcess = [];
4252
+ var itemsForBeforeRemoveCallbacks = [];
4253
+ var itemsForMoveCallbacks = [];
4254
+ var itemsForAfterAddCallbacks = [];
4255
+ var mapData;
4256
+
4257
+ function itemMovedOrRetained(editScriptIndex, oldPosition) {
4258
+ mapData = lastMappingResult[oldPosition];
4259
+ if (newMappingResultIndex !== oldPosition)
4260
+ itemsForMoveCallbacks[editScriptIndex] = mapData;
4261
+ // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
4262
+ mapData.indexObservable(newMappingResultIndex++);
4263
+ ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
4264
+ newMappingResult.push(mapData);
4265
+ itemsToProcess.push(mapData);
4266
+ }
4267
+
4268
+ function callCallback(callback, items) {
4269
+ if (callback) {
4270
+ for (var i = 0, n = items.length; i < n; i++) {
4271
+ if (items[i]) {
4272
+ ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
4273
+ callback(node, i, items[i].arrayEntry);
4274
+ });
4275
+ }
4276
+ }
4277
+ }
4278
+ }
4279
+
4280
+ for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
4281
+ movedIndex = editScriptItem['moved'];
4282
+ switch (editScriptItem['status']) {
4283
+ case "deleted":
4284
+ if (movedIndex === undefined) {
4285
+ mapData = lastMappingResult[lastMappingResultIndex];
4286
+
4287
+ // Stop tracking changes to the mapping for these nodes
4288
+ if (mapData.dependentObservable)
4289
+ mapData.dependentObservable.dispose();
4290
+
4291
+ // Queue these nodes for later removal
4292
+ nodesToDelete.push.apply(nodesToDelete, ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode));
4293
+ if (options['beforeRemove']) {
4294
+ itemsForBeforeRemoveCallbacks[i] = mapData;
4295
+ itemsToProcess.push(mapData);
4296
+ }
4297
+ }
4298
+ lastMappingResultIndex++;
4299
+ break;
4300
+
4301
+ case "retained":
4302
+ itemMovedOrRetained(i, lastMappingResultIndex++);
4303
+ break;
4304
+
4305
+ case "added":
4306
+ if (movedIndex !== undefined) {
4307
+ itemMovedOrRetained(i, movedIndex);
4308
+ } else {
4309
+ mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
4310
+ newMappingResult.push(mapData);
4311
+ itemsToProcess.push(mapData);
4312
+ if (!isFirstExecution)
4313
+ itemsForAfterAddCallbacks[i] = mapData;
4314
+ }
4315
+ break;
4316
+ }
4317
+ }
4318
+
4319
+ // Call beforeMove first before any changes have been made to the DOM
4320
+ callCallback(options['beforeMove'], itemsForMoveCallbacks);
4321
+
4322
+ // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
4323
+ ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
4324
+
4325
+ // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
4326
+ for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
4327
+ // Get nodes for newly added items
4328
+ if (!mapData.mappedNodes)
4329
+ ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
4330
+
4331
+ // Put nodes in the right place if they aren't there already
4332
+ for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
4333
+ if (node !== nextNode)
4334
+ ko.virtualElements.insertAfter(domNode, node, lastNode);
4335
+ }
4336
+
4337
+ // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
4338
+ if (!mapData.initialized && callbackAfterAddingNodes) {
4339
+ callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
4340
+ mapData.initialized = true;
4341
+ }
4342
+ }
4343
+
4344
+ // If there's a beforeRemove callback, call it after reordering.
4345
+ // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
4346
+ // some sort of animation, which is why we first reorder the nodes that will be removed. If the
4347
+ // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
4348
+ // Perhaps we'll make that change in the future if this scenario becomes more common.
4349
+ callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
4350
+
4351
+ // Finally call afterMove and afterAdd callbacks
4352
+ callCallback(options['afterMove'], itemsForMoveCallbacks);
4353
+ callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
4354
+
4355
+ // Store a copy of the array items we just considered so we can difference it next time
4356
+ ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
4357
+ }
4358
+ })();
4359
+
4360
+ ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
4361
+ ko.nativeTemplateEngine = function () {
4362
+ this['allowTemplateRewriting'] = false;
4363
+ }
4364
+
4365
+ ko.nativeTemplateEngine.prototype = new ko.templateEngine();
4366
+ ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;
4367
+ ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
4368
+ var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
4369
+ templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
4370
+ templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
4371
+
4372
+ if (templateNodes) {
4373
+ return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
4374
+ } else {
4375
+ var templateText = templateSource['text']();
4376
+ return ko.utils.parseHtmlFragment(templateText);
4377
+ }
4378
+ };
4379
+
4380
+ ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
4381
+ ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
4382
+
4383
+ ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
4384
+ (function() {
4385
+ ko.jqueryTmplTemplateEngine = function () {
4386
+ // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
4387
+ // doesn't expose a version number, so we have to infer it.
4388
+ // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
4389
+ // which KO internally refers to as version "2", so older versions are no longer detected.
4390
+ var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
4391
+ if (!jQuery || !(jQuery['tmpl']))
4392
+ return 0;
4393
+ // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
4394
+ try {
4395
+ if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
4396
+ // Since 1.0.0pre, custom tags should append markup to an array called "__"
4397
+ return 2; // Final version of jquery.tmpl
4398
+ }
4399
+ } catch(ex) { /* Apparently not the version we were looking for */ }
4400
+
4401
+ return 1; // Any older version that we don't support
4402
+ })();
4403
+
4404
+ function ensureHasReferencedJQueryTemplates() {
4405
+ if (jQueryTmplVersion < 2)
4406
+ throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
4407
+ }
4408
+
4409
+ function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
4410
+ return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
4411
+ }
4412
+
4413
+ this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
4414
+ options = options || {};
4415
+ ensureHasReferencedJQueryTemplates();
4416
+
4417
+ // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
4418
+ var precompiled = templateSource['data']('precompiled');
4419
+ if (!precompiled) {
4420
+ var templateText = templateSource['text']() || "";
4421
+ // Wrap in "with($whatever.koBindingContext) { ... }"
4422
+ templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
4423
+
4424
+ precompiled = jQuery['template'](null, templateText);
4425
+ templateSource['data']('precompiled', precompiled);
4426
+ }
4427
+
4428
+ var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
4429
+ var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
4430
+
4431
+ var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
4432
+ resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
4433
+
4434
+ jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
4435
+ return resultNodes;
4436
+ };
4437
+
4438
+ this['createJavaScriptEvaluatorBlock'] = function(script) {
4439
+ return "{{ko_code ((function() { return " + script + " })()) }}";
4440
+ };
4441
+
4442
+ this['addTemplate'] = function(templateName, templateMarkup) {
4443
+ document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
4444
+ };
4445
+
4446
+ if (jQueryTmplVersion > 0) {
4447
+ jQuery['tmpl']['tag']['ko_code'] = {
4448
+ open: "__.push($1 || '');"
4449
+ };
4450
+ jQuery['tmpl']['tag']['ko_with'] = {
4451
+ open: "with($1) {",
4452
+ close: "} "
4453
+ };
4454
+ }
4455
+ };
4456
+
4457
+ ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
4458
+ ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;
4459
+
4460
+ // Use this one by default *only if jquery.tmpl is referenced*
4461
+ var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
4462
+ if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
4463
+ ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
4464
+
4465
+ ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
4466
+ })();
4467
+ }));
4468
+ }());
4469
+ })();