knockoutjs-rails 3.0.0 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ })();