quick_script 0.11.8 → 0.11.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module QuickScript
2
- VERSION = "0.11.8"
2
+ VERSION = "0.11.9"
3
3
  end
@@ -162,10 +162,11 @@ Overlay.add = (vm, tmp, opts) ->
162
162
  if opts.stretch == true
163
163
  $("#overlay-#{id} .modal-body").css({'max-height' : ($(window).height() - 200)})
164
164
  $('#overlay-' + id).css({'margin-top' : ($(window).height() - 100)/ -2})
165
- $('#overlay-' + id).modal('show')
166
165
  $('#overlay-' + id).on 'hidden', ->
167
166
  $('#overlay-' + id).koClean()
168
167
  $('#overlay-' + id).remove()
168
+ $('#overlay-' + id).on 'shown', opts.shown if opts.shown?
169
+ $('#overlay-' + id).modal('show')
169
170
  , 100
170
171
  #Overlay.instance.zindex = Overlay.instance.zindex + 10
171
172
 
@@ -207,10 +208,16 @@ Overlay.confirm = (msg, opts) ->
207
208
  $('#overlay-confirm').slideDown 'fast'
208
209
 
209
210
  Overlay.remove = (id) ->
210
- $('#overlay-' + id).modal('hide')
211
- $('#popover-' + id).koClean().remove()
212
- $('#backdrop-' + id).remove()
213
- $('#overlay-' + id).remove() if (id == 'confirm')
211
+ Overlay.removeModal(id)
212
+ Overlay.removePopover(id)
213
+
214
+ Overlay.removeModal = (id) ->
215
+ $('#overlay-' + id).modal('hide')
216
+ $('#backdrop-' + id).remove()
217
+ $('#overlay-' + id).remove() if (id == 'confirm')
218
+
219
+ Overlay.removePopover = (id) ->
220
+ $('#popover-' + id).koClean().remove()
214
221
 
215
222
  Overlay.removePopovers = ->
216
223
  $('.popover').remove()
@@ -221,7 +228,7 @@ Overlay.isVisible = (id) ->
221
228
  Overlay.popover = (el, vm, tmp, opts)->
222
229
  id = vm.name
223
230
  opts.placement = opts.placement || 'bottom'
224
- $po = $("<div id='popover-#{id}' class='popover fade'><div class='arrow'></div><div class='popover-inner'><h3 class='popover-title'>#{opts.title}</h3><div class='popover-content' data-bind=\"template : '#{tmp}'\"></div></div></div>")
231
+ $po = $("<div id='popover-#{id}' class='popover fade'><div class='arrow'></div><div class='popover-inner'><button class='close' data-bind='click : hidePopover'>x</button><h3 class='popover-title'>#{opts.title}</h3><div class='popover-content' data-bind=\"template : '#{tmp}'\"></div></div></div>")
225
232
 
226
233
  setTimeout ->
227
234
  $po.remove().css({ top: 0, left: 0, display: 'block', width: 'auto' }).prependTo(document.body)
@@ -555,6 +555,7 @@ class @Model
555
555
  error : =>
556
556
  console.log("Delete error encountered")
557
557
  @model_state(ko.modelStates.READY)
558
+ callback({meta : 500, data : {errors : ['An error occurred']}}) if callback?
558
559
  @model_state(ko.modelStates.SAVING)
559
560
  removeFromCollection : =>
560
561
  @collection.removeItemById(@id()) if @collection?
@@ -947,6 +948,8 @@ class @View
947
948
  Overlay.popover(el, this, tmp, opts)
948
949
  hideOverlay : =>
949
950
  Overlay.remove(@name)
951
+ hidePopover : =>
952
+ Overlay.removePopover(@name)
950
953
  overlayVisible : =>
951
954
  Overlay.isVisible(@name)
952
955
 
@@ -981,12 +984,9 @@ class @ModelAdapter
981
984
  send : (opts)->
982
985
  ModelAdapter.send(@host, opts)
983
986
  delete : (opts)->
984
- $.ajax
985
- type : 'DELETE'
986
- url : @host + @save_url
987
- data : opts.data
988
- success : opts.success
989
- error : opts.error
987
+ opts.type = 'DELETE'
988
+ opts.url = @save_url
989
+ @send opts
990
990
  add_method : (fn_name, fn)->
991
991
  @[fn_name] = fn.bind(this)
992
992
  ModelAdapter.send = (host, opts)->
@@ -1056,13 +1056,9 @@ class @AccountAdapter
1056
1056
  send : (opts)->
1057
1057
  ModelAdapter.send(@host, opts)
1058
1058
  delete : (opts)->
1059
- $.ajax_qs
1060
- type : 'DELETE'
1061
- url : @host + opts.url
1062
- data : opts.data
1063
- progress : opts.progress
1064
- success : opts.success
1065
- error : opts.error
1059
+ opts.type = 'DELETE'
1060
+ opts.url = @save_url
1061
+ @send opts
1066
1062
  add_method : (fn_name, fn)->
1067
1063
  @[fn_name] = fn.bind(this)
1068
1064
 
@@ -1,86 +1,3577 @@
1
- // Knockout JavaScript library v2.1.0
1
+ // Knockout JavaScript library v2.2.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(window,document,navigator,undefined){
6
- function m(w){throw w;}var n=void 0,p=!0,s=null,t=!1;function A(w){return function(){return w}};function E(w){function B(b,c,d){d&&c!==a.k.r(b)&&a.k.S(b,c);c!==a.k.r(b)&&a.a.va(b,"change")}var a="undefined"!==typeof w?w:{};a.b=function(b,c){for(var d=b.split("."),f=a,g=0;g<d.length-1;g++)f=f[d[g]];f[d[d.length-1]]=c};a.B=function(a,c,d){a[c]=d};a.version="2.1.0";a.b("version",a.version);a.a=new function(){function b(b,c){if("input"!==a.a.o(b)||!b.type||"click"!=c.toLowerCase())return t;var e=b.type;return"checkbox"==e||"radio"==e}var c=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,d={},f={};d[/Firefox\/2/i.test(navigator.userAgent)?
7
- "KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];d.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");for(var g in d){var e=d[g];if(e.length)for(var h=0,j=e.length;h<j;h++)f[e[h]]=g}var k={propertychange:p},i=function(){for(var a=3,b=document.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="<\!--[if gt IE "+ ++a+"]><i></i><![endif]--\>",c[0];);return 4<a?a:n}();return{Ca:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],
8
- v:function(a,b){for(var c=0,e=a.length;c<e;c++)b(a[c])},j:function(a,b){if("function"==typeof Array.prototype.indexOf)return Array.prototype.indexOf.call(a,b);for(var c=0,e=a.length;c<e;c++)if(a[c]===b)return c;return-1},ab:function(a,b,c){for(var e=0,f=a.length;e<f;e++)if(b.call(c,a[e]))return a[e];return s},ba:function(b,c){var e=a.a.j(b,c);0<=e&&b.splice(e,1)},za:function(b){for(var b=b||[],c=[],e=0,f=b.length;e<f;e++)0>a.a.j(c,b[e])&&c.push(b[e]);return c},T:function(a,b){for(var a=a||[],c=[],
9
- e=0,f=a.length;e<f;e++)c.push(b(a[e]));return c},aa:function(a,b){for(var a=a||[],c=[],e=0,f=a.length;e<f;e++)b(a[e])&&c.push(a[e]);return c},N:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,e=b.length;c<e;c++)a.push(b[c]);return a},extend:function(a,b){if(b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},ga:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Ab:function(b){for(var b=a.a.L(b),c=document.createElement("div"),e=0,f=b.length;e<f;e++)a.F(b[e]),
10
- c.appendChild(b[e]);return c},X:function(b,c){a.a.ga(b);if(c)for(var e=0,f=c.length;e<f;e++)b.appendChild(c[e])},Na:function(b,c){var e=b.nodeType?[b]:b;if(0<e.length){for(var f=e[0],d=f.parentNode,g=0,h=c.length;g<h;g++)d.insertBefore(c[g],f);g=0;for(h=e.length;g<h;g++)a.removeNode(e[g])}},Pa:function(a,b){0<=navigator.userAgent.indexOf("MSIE 6")?a.setAttribute("selected",b):a.selected=b},w:function(a){return(a||"").replace(c,"")},Ib:function(b,c){for(var e=[],f=(b||"").split(c),g=0,d=f.length;g<
11
- d;g++){var h=a.a.w(f[g]);""!==h&&e.push(h)}return e},Hb:function(a,b){a=a||"";return b.length>a.length?t:a.substring(0,b.length)===b},eb:function(a,b){for(var c="return ("+a+")",e=0;e<b;e++)c="with(sc["+e+"]) { "+c+" } ";return new Function("sc",c)},kb:function(a,b){if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a!=s;){if(a==b)return p;a=a.parentNode}return t},fa:function(b){return a.a.kb(b,b.ownerDocument)},o:function(a){return a&&a.tagName&&a.tagName.toLowerCase()},
12
- n:function(a,c,e){var f=i&&k[c];if(!f&&"undefined"!=typeof jQuery){if(b(a,c))var g=e,e=function(a,b){var c=this.checked;b&&(this.checked=b.fb!==p);g.call(this,a);this.checked=c};jQuery(a).bind(c,e)}else!f&&"function"==typeof a.addEventListener?a.addEventListener(c,e,t):"undefined"!=typeof a.attachEvent?a.attachEvent("on"+c,function(b){e.call(a,b)}):m(Error("Browser doesn't support addEventListener or attachEvent"))},va:function(a,c){(!a||!a.nodeType)&&m(Error("element must be a DOM node when calling triggerEvent"));
13
- if("undefined"!=typeof jQuery){var e=[];b(a,c)&&e.push({fb:a.checked});jQuery(a).trigger(c,e)}else"function"==typeof document.createEvent?"function"==typeof a.dispatchEvent?(e=document.createEvent(f[c]||"HTMLEvents"),e.initEvent(c,p,p,window,0,0,0,0,0,t,t,t,t,0,a),a.dispatchEvent(e)):m(Error("The supplied element doesn't support dispatchEvent")):"undefined"!=typeof a.fireEvent?(b(a,c)&&(a.checked=a.checked!==p),a.fireEvent("on"+c)):m(Error("Browser doesn't support triggering events"))},d:function(b){return a.la(b)?
14
- b():b},Ua:function(b,c,e){var f=(b.className||"").split(/\s+/),g=0<=a.a.j(f,c);if(e&&!g)b.className+=(f[0]?" ":"")+c;else if(g&&!e){e="";for(g=0;g<f.length;g++)f[g]!=c&&(e+=f[g]+" ");b.className=a.a.w(e)}},Qa:function(b,c){var e=a.a.d(c);if(e===s||e===n)e="";"innerText"in b?b.innerText=e:b.textContent=e;9<=i&&(b.style.display=b.style.display)},lb:function(a){if(9<=i){var b=a.style.width;a.style.width=0;a.style.width=b}},Eb:function(b,e){for(var b=a.a.d(b),e=a.a.d(e),c=[],f=b;f<=e;f++)c.push(f);return c},
15
- L:function(a){for(var b=[],e=0,c=a.length;e<c;e++)b.push(a[e]);return b},tb:6===i,ub:7===i,ja:i,Da:function(b,e){for(var c=a.a.L(b.getElementsByTagName("input")).concat(a.a.L(b.getElementsByTagName("textarea"))),f="string"==typeof e?function(a){return a.name===e}:function(a){return e.test(a.name)},g=[],d=c.length-1;0<=d;d--)f(c[d])&&g.push(c[d]);return g},Bb:function(b){return"string"==typeof b&&(b=a.a.w(b))?window.JSON&&window.JSON.parse?window.JSON.parse(b):(new Function("return "+b))():s},sa:function(b,
16
- e,c){("undefined"==typeof JSON||"undefined"==typeof JSON.stringify)&&m(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"));return JSON.stringify(a.a.d(b),e,c)},Cb:function(b,e,c){var c=c||{},f=c.params||{},g=c.includeFields||this.Ca,d=b;if("object"==typeof b&&"form"===a.a.o(b))for(var d=b.action,h=g.length-1;0<=h;h--)for(var k=a.a.Da(b,g[h]),
17
- j=k.length-1;0<=j;j--)f[k[j].name]=k[j].value;var e=a.a.d(e),i=document.createElement("form");i.style.display="none";i.action=d;i.method="post";for(var z in e)b=document.createElement("input"),b.name=z,b.value=a.a.sa(a.a.d(e[z])),i.appendChild(b);for(z in f)b=document.createElement("input"),b.name=z,b.value=f[z],i.appendChild(b);document.body.appendChild(i);c.submitter?c.submitter(i):i.submit();setTimeout(function(){i.parentNode.removeChild(i)},0)}}};a.b("utils",a.a);a.b("utils.arrayForEach",a.a.v);
18
- a.b("utils.arrayFirst",a.a.ab);a.b("utils.arrayFilter",a.a.aa);a.b("utils.arrayGetDistinctValues",a.a.za);a.b("utils.arrayIndexOf",a.a.j);a.b("utils.arrayMap",a.a.T);a.b("utils.arrayPushAll",a.a.N);a.b("utils.arrayRemoveItem",a.a.ba);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.Ca);a.b("utils.getFormFields",a.a.Da);a.b("utils.postJson",a.a.Cb);a.b("utils.parseJson",a.a.Bb);a.b("utils.registerEventHandler",a.a.n);a.b("utils.stringifyJson",a.a.sa);a.b("utils.range",a.a.Eb);
19
- a.b("utils.toggleDomNodeCssClass",a.a.Ua);a.b("utils.triggerEvent",a.a.va);a.b("utils.unwrapObservable",a.a.d);Function.prototype.bind||(Function.prototype.bind=function(a){var c=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(){var b=0,c="__ko__"+(new Date).getTime(),d={};return{get:function(b,c){var e=a.a.f.getAll(b,t);return e===n?n:e[c]},set:function(b,c,e){e===n&&a.a.f.getAll(b,
20
- t)===n||(a.a.f.getAll(b,p)[c]=e)},getAll:function(a,g){var e=a[c];if(!(e&&"null"!==e)){if(!g)return;e=a[c]="ko"+b++;d[e]={}}return d[e]},clear:function(a){var b=a[c];b&&(delete d[b],a[c]=s)}}};a.b("utils.domData",a.a.f);a.b("utils.domData.clear",a.a.f.clear);a.a.G=new function(){function b(b,c){var f=a.a.f.get(b,d);f===n&&c&&(f=[],a.a.f.set(b,d,f));return f}function c(e){var f=b(e,t);if(f)for(var f=f.slice(0),d=0;d<f.length;d++)f[d](e);a.a.f.clear(e);"function"==typeof jQuery&&"function"==typeof jQuery.cleanData&&
21
- jQuery.cleanData([e]);if(g[e.nodeType])for(f=e.firstChild;e=f;)f=e.nextSibling,8===e.nodeType&&c(e)}var d="__ko_domNodeDisposal__"+(new Date).getTime(),f={1:p,8:p,9:p},g={1:p,9:p};return{wa:function(a,c){"function"!=typeof c&&m(Error("Callback must be a function"));b(a,p).push(c)},Ma:function(c,f){var g=b(c,t);g&&(a.a.ba(g,f),0==g.length&&a.a.f.set(c,d,n))},F:function(b){if(f[b.nodeType]&&(c(b),g[b.nodeType])){var d=[];a.a.N(d,b.getElementsByTagName("*"));for(var b=0,j=d.length;b<j;b++)c(d[b])}},
22
- removeNode:function(b){a.F(b);b.parentNode&&b.parentNode.removeChild(b)}}};a.F=a.a.G.F;a.removeNode=a.a.G.removeNode;a.b("cleanNode",a.F);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.G);a.b("utils.domNodeDisposal.addDisposeCallback",a.a.G.wa);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.G.Ma);(function(){a.a.pa=function(b){var c;if("undefined"!=typeof jQuery){if((c=jQuery.clean([b]))&&c[0]){for(b=c[0];b.parentNode&&11!==b.parentNode.nodeType;)b=b.parentNode;b.parentNode&&
23
- b.parentNode.removeChild(b)}}else{var d=a.a.w(b).toLowerCase();c=document.createElement("div");d=d.match(/^<(thead|tbody|tfoot)/)&&[1,"<table>","</table>"]||!d.indexOf("<tr")&&[2,"<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 window.innerShiv?c.appendChild(window.innerShiv(b)):c.innerHTML=b;d[0]--;)c=c.lastChild;c=a.a.L(c.lastChild.childNodes)}return c};
24
- a.a.Y=function(b,c){a.a.ga(b);if(c!==s&&c!==n)if("string"!=typeof c&&(c=c.toString()),"undefined"!=typeof jQuery)jQuery(b).html(c);else for(var d=a.a.pa(c),f=0;f<d.length;f++)b.appendChild(d[f])}})();a.b("utils.parseHtmlFragment",a.a.pa);a.b("utils.setHtml",a.a.Y);a.s=function(){function b(){return(4294967296*(1+Math.random())|0).toString(16).substring(1)}function c(b,g){if(b)if(8==b.nodeType){var e=a.s.Ja(b.nodeValue);e!=s&&g.push({jb:b,yb:e})}else if(1==b.nodeType)for(var e=0,d=b.childNodes,j=d.length;e<
25
- j;e++)c(d[e],g)}var d={};return{na:function(a){"function"!=typeof a&&m(Error("You can only pass a function to ko.memoization.memoize()"));var c=b()+b();d[c]=a;return"<\!--[ko_memo:"+c+"]--\>"},Va:function(a,b){var c=d[a];c===n&&m(Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized."));try{return c.apply(s,b||[]),p}finally{delete d[a]}},Wa:function(b,d){var e=[];c(b,e);for(var h=0,j=e.length;h<j;h++){var k=e[h].jb,i=[k];d&&a.a.N(i,d);a.s.Va(e[h].yb,i);k.nodeValue="";k.parentNode&&
26
- k.parentNode.removeChild(k)}},Ja:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:s}}}();a.b("memoization",a.s);a.b("memoization.memoize",a.s.na);a.b("memoization.unmemoize",a.s.Va);a.b("memoization.parseMemoText",a.s.Ja);a.b("memoization.unmemoizeDomNodeAndDescendants",a.s.Wa);a.Ba={throttle:function(b,c){b.throttleEvaluation=c;var d=s;return a.h({read:b,write:function(a){clearTimeout(d);d=setTimeout(function(){b(a)},c)}})},notify:function(b,c){b.equalityComparer="always"==c?A(t):a.m.fn.equalityComparer;
27
- return b}};a.b("extenders",a.Ba);a.Sa=function(b,c,d){this.target=b;this.ca=c;this.ib=d;a.B(this,"dispose",this.A)};a.Sa.prototype.A=function(){this.sb=p;this.ib()};a.R=function(){this.u={};a.a.extend(this,a.R.fn);a.B(this,"subscribe",this.ta);a.B(this,"extend",this.extend);a.B(this,"getSubscriptionsCount",this.ob)};a.R.fn={ta:function(b,c,d){var d=d||"change",b=c?b.bind(c):b,f=new a.Sa(this,b,function(){a.a.ba(this.u[d],f)}.bind(this));this.u[d]||(this.u[d]=[]);this.u[d].push(f);return f},notifySubscribers:function(b,
28
- c){c=c||"change";this.u[c]&&a.a.v(this.u[c].slice(0),function(a){a&&a.sb!==p&&a.ca(b)})},ob:function(){var a=0,c;for(c in this.u)this.u.hasOwnProperty(c)&&(a+=this.u[c].length);return a},extend:function(b){var c=this;if(b)for(var d in b){var f=a.Ba[d];"function"==typeof f&&(c=f(c,b[d]))}return c}};a.Ga=function(a){return"function"==typeof a.ta&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.R);a.b("isSubscribable",a.Ga);a.U=function(){var b=[];return{bb:function(a){b.push({ca:a,Aa:[]})},
29
- end:function(){b.pop()},La:function(c){a.Ga(c)||m(Error("Only subscribable things can act as dependencies"));if(0<b.length){var d=b[b.length-1];0<=a.a.j(d.Aa,c)||(d.Aa.push(c),d.ca(c))}}}}();var G={undefined:p,"boolean":p,number:p,string:p};a.m=function(b){function c(){if(0<arguments.length){if(!c.equalityComparer||!c.equalityComparer(d,arguments[0]))c.I(),d=arguments[0],c.H();return this}a.U.La(c);return d}var d=b;a.R.call(c);c.H=function(){c.notifySubscribers(d)};c.I=function(){c.notifySubscribers(d,
30
- "beforeChange")};a.a.extend(c,a.m.fn);a.B(c,"valueHasMutated",c.H);a.B(c,"valueWillMutate",c.I);return c};a.m.fn={equalityComparer:function(a,c){return a===s||typeof a in G?a===c:t}};var x=a.m.Db="__ko_proto__";a.m.fn[x]=a.m;a.ia=function(b,c){return b===s||b===n||b[x]===n?t:b[x]===c?p:a.ia(b[x],c)};a.la=function(b){return a.ia(b,a.m)};a.Ha=function(b){return"function"==typeof b&&b[x]===a.m||"function"==typeof b&&b[x]===a.h&&b.pb?p:t};a.b("observable",a.m);a.b("isObservable",a.la);a.b("isWriteableObservable",
31
- a.Ha);a.Q=function(b){0==arguments.length&&(b=[]);b!==s&&(b!==n&&!("length"in b))&&m(Error("The argument passed when initializing an observable array must be an array, or null, or undefined."));var c=a.m(b);a.a.extend(c,a.Q.fn);return c};a.Q.fn={remove:function(a){for(var c=this(),d=[],f="function"==typeof a?a:function(c){return c===a},g=0;g<c.length;g++){var e=c[g];f(e)&&(0===d.length&&this.I(),d.push(e),c.splice(g,1),g--)}d.length&&this.H();return d},removeAll:function(b){if(b===n){var c=this(),
32
- d=c.slice(0);this.I();c.splice(0,c.length);this.H();return d}return!b?[]:this.remove(function(c){return 0<=a.a.j(b,c)})},destroy:function(a){var c=this(),d="function"==typeof a?a:function(c){return c===a};this.I();for(var f=c.length-1;0<=f;f--)d(c[f])&&(c[f]._destroy=p);this.H()},destroyAll:function(b){return b===n?this.destroy(A(p)):!b?[]:this.destroy(function(c){return 0<=a.a.j(b,c)})},indexOf:function(b){var c=this();return a.a.j(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.I(),
33
- this()[d]=c,this.H())}};a.a.v("pop push reverse shift sort splice unshift".split(" "),function(b){a.Q.fn[b]=function(){var a=this();this.I();a=a[b].apply(a,arguments);this.H();return a}});a.a.v(["slice"],function(b){a.Q.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.b("observableArray",a.Q);a.h=function(b,c,d){function f(){a.a.v(v,function(a){a.A()});v=[]}function g(){var a=h.throttleEvaluation;a&&0<=a?(clearTimeout(x),x=setTimeout(e,a)):e()}function e(){if(!l)if(i&&w())u();else{l=
34
- p;try{var b=a.a.T(v,function(a){return a.target});a.U.bb(function(c){var e;0<=(e=a.a.j(b,c))?b[e]=n:v.push(c.ta(g))});for(var e=q.call(c),f=b.length-1;0<=f;f--)b[f]&&v.splice(f,1)[0].A();i=p;h.notifySubscribers(k,"beforeChange");k=e}finally{a.U.end()}h.notifySubscribers(k);l=t}}function h(){if(0<arguments.length)j.apply(h,arguments);else return i||e(),a.U.La(h),k}function j(){"function"===typeof o?o.apply(c,arguments):m(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."))}
35
- var k,i=t,l=t,q=b;q&&"object"==typeof q?(d=q,q=d.read):(d=d||{},q||(q=d.read));"function"!=typeof q&&m(Error("Pass a function that returns the value of the ko.computed"));var o=d.write;c||(c=d.owner);var v=[],u=f,r="object"==typeof d.disposeWhenNodeIsRemoved?d.disposeWhenNodeIsRemoved:s,w=d.disposeWhen||A(t);if(r){u=function(){a.a.G.Ma(r,arguments.callee);f()};a.a.G.wa(r,u);var y=w,w=function(){return!a.a.fa(r)||y()}}var x=s;h.nb=function(){return v.length};h.pb="function"===typeof d.write;h.A=function(){u()};
36
- a.R.call(h);a.a.extend(h,a.h.fn);d.deferEvaluation!==p&&e();a.B(h,"dispose",h.A);a.B(h,"getDependenciesCount",h.nb);return h};a.rb=function(b){return a.ia(b,a.h)};w=a.m.Db;a.h[w]=a.m;a.h.fn={};a.h.fn[w]=a.h;a.b("dependentObservable",a.h);a.b("computed",a.h);a.b("isComputed",a.rb);(function(){function b(a,g,e){e=e||new d;a=g(a);if(!("object"==typeof a&&a!==s&&a!==n&&!(a instanceof Date)))return a;var h=a instanceof Array?[]:{};e.save(a,h);c(a,function(c){var d=g(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":h[c]=
37
- d;break;case "object":case "undefined":var i=e.get(d);h[c]=i!==n?i:b(d,g,e)}});return h}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(){var b=[],c=[];this.save=function(e,d){var j=a.a.j(b,e);0<=j?c[j]=d:(b.push(e),c.push(d))};this.get=function(e){e=a.a.j(b,e);return 0<=e?c[e]:n}}a.Ta=function(c){0==arguments.length&&m(Error("When calling ko.toJS, pass the object you want to convert."));return b(c,function(b){for(var c=
38
- 0;a.la(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,e){b=a.Ta(b);return a.a.sa(b,c,e)}})();a.b("toJS",a.Ta);a.b("toJSON",a.toJSON);(function(){a.k={r:function(b){switch(a.a.o(b)){case "option":return b.__ko__hasDomDataOptionValue__===p?a.a.f.get(b,a.c.options.oa):b.getAttribute("value");case "select":return 0<=b.selectedIndex?a.k.r(b.options[b.selectedIndex]):n;default:return b.value}},S:function(b,c){switch(a.a.o(b)){case "option":switch(typeof c){case "string":a.a.f.set(b,a.c.options.oa,
39
- n);"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__;b.value=c;break;default:a.a.f.set(b,a.c.options.oa,c),b.__ko__hasDomDataOptionValue__=p,b.value="number"===typeof c?c:""}break;case "select":for(var d=b.options.length-1;0<=d;d--)if(a.k.r(b.options[d])==c){b.selectedIndex=d;break}break;default:if(c===s||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.k);a.b("selectExtensions.readValue",a.k.r);a.b("selectExtensions.writeValue",a.k.S);a.g=function(){function b(a,b){for(var d=
40
- s;a!=d;)d=a,a=a.replace(c,function(a,c){return b[c]});return a}var c=/\@ko_token_(\d+)\@/g,d=/^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$/i,f=["true","false"];return{D:[],W:function(c){var e=a.a.w(c);if(3>e.length)return[];"{"===e.charAt(0)&&(e=e.substring(1,e.length-1));for(var c=[],d=s,f,k=0;k<e.length;k++){var i=e.charAt(k);if(d===s)switch(i){case '"':case "'":case "/":d=k,f=i}else if(i==f&&"\\"!==e.charAt(k-1)){i=e.substring(d,k+1);c.push(i);var l="@ko_token_"+(c.length-
41
- 1)+"@",e=e.substring(0,d)+l+e.substring(k+1),k=k-(i.length-l.length),d=s}}f=d=s;for(var q=0,o=s,k=0;k<e.length;k++){i=e.charAt(k);if(d===s)switch(i){case "{":d=k;o=i;f="}";break;case "(":d=k;o=i;f=")";break;case "[":d=k,o=i,f="]"}i===o?q++:i===f&&(q--,0===q&&(i=e.substring(d,k+1),c.push(i),l="@ko_token_"+(c.length-1)+"@",e=e.substring(0,d)+l+e.substring(k+1),k-=i.length-l.length,d=s))}f=[];e=e.split(",");d=0;for(k=e.length;d<k;d++)q=e[d],o=q.indexOf(":"),0<o&&o<q.length-1?(i=q.substring(o+1),f.push({key:b(q.substring(0,
42
- o),c),value:b(i,c)})):f.push({unknown:b(q,c)});return f},ka:function(b){for(var c="string"===typeof b?a.g.W(b):b,h=[],b=[],j,k=0;j=c[k];k++)if(0<h.length&&h.push(","),j.key){var i;a:{i=j.key;var l=a.a.w(i);switch(l.length&&l.charAt(0)){case "'":case '"':break a;default:i="'"+l+"'"}}j=j.value;h.push(i);h.push(":");h.push(j);l=a.a.w(j);if(0<=a.a.j(f,a.a.w(l).toLowerCase())?0:l.match(d)!==s)0<b.length&&b.push(", "),b.push(i+" : function(__ko_value) { "+j+" = __ko_value; }")}else j.unknown&&h.push(j.unknown);
43
- c=h.join("");0<b.length&&(c=c+", '_ko_property_writers' : { "+b.join("")+" } ");return c},wb:function(b,c){for(var d=0;d<b.length;d++)if(a.a.w(b[d].key)==c)return p;return t},$:function(b,c,d,f,k){if(!b||!a.Ha(b)){if((b=c()._ko_property_writers)&&b[d])b[d](f)}else(!k||b()!==f)&&b(f)}}}();a.b("jsonExpressionRewriting",a.g);a.b("jsonExpressionRewriting.bindingRewriteValidators",a.g.D);a.b("jsonExpressionRewriting.parseObjectLiteral",a.g.W);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",
44
- a.g.ka);(function(){function b(a){return 8==a.nodeType&&(g?a.text:a.nodeValue).match(e)}function c(a){return 8==a.nodeType&&(g?a.text:a.nodeValue).match(h)}function d(a,e){for(var d=a,f=1,g=[];d=d.nextSibling;){if(c(d)&&(f--,0===f))return g;g.push(d);b(d)&&f++}e||m(Error("Cannot find closing comment tag to match: "+a.nodeValue));return s}function f(a,b){var c=d(a,b);return c?0<c.length?c[c.length-1].nextSibling:a.nextSibling:s}var g="<\!--test--\>"===document.createComment("test").text,e=g?/^<\!--\s*ko\s+(.*\:.*)\s*--\>$/:
45
- /^\s*ko\s+(.*\:.*)\s*$/,h=g?/^<\!--\s*\/ko\s*--\>$/:/^\s*\/ko\s*$/,j={ul:p,ol:p};a.e={C:{},childNodes:function(a){return b(a)?d(a):a.childNodes},ha:function(c){if(b(c))for(var c=a.e.childNodes(c),e=0,d=c.length;e<d;e++)a.removeNode(c[e]);else a.a.ga(c)},X:function(c,e){if(b(c)){a.e.ha(c);for(var d=c.nextSibling,f=0,g=e.length;f<g;f++)d.parentNode.insertBefore(e[f],d)}else a.a.X(c,e)},Ka:function(a,c){b(a)?a.parentNode.insertBefore(c,a.nextSibling):a.firstChild?a.insertBefore(c,a.firstChild):a.appendChild(c)},
46
- Fa:function(a,c,e){b(a)?a.parentNode.insertBefore(c,e.nextSibling):e.nextSibling?a.insertBefore(c,e.nextSibling):a.appendChild(c)},firstChild:function(a){return!b(a)?a.firstChild:!a.nextSibling||c(a.nextSibling)?s:a.nextSibling},nextSibling:function(a){b(a)&&(a=f(a));return a.nextSibling&&c(a.nextSibling)?s:a.nextSibling},Xa:function(a){return(a=b(a))?a[1]:s},Ia:function(e){if(j[a.a.o(e)]){var d=e.firstChild;if(d){do if(1===d.nodeType){var g;g=d.firstChild;var h=s;if(g){do if(h)h.push(g);else if(b(g)){var o=
47
- f(g,p);o?g=o:h=[g]}else c(g)&&(h=[g]);while(g=g.nextSibling)}if(g=h){h=d.nextSibling;for(o=0;o<g.length;o++)h?e.insertBefore(g[o],h):e.appendChild(g[o])}}while(d=d.nextSibling)}}}}})();a.b("virtualElements",a.e);a.b("virtualElements.allowedBindings",a.e.C);a.b("virtualElements.emptyNode",a.e.ha);a.b("virtualElements.insertAfter",a.e.Fa);a.b("virtualElements.prepend",a.e.Ka);a.b("virtualElements.setDomNodeChildren",a.e.X);(function(){a.J=function(){this.cb={}};a.a.extend(a.J.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind")!=
48
- s;case 8:return a.e.Xa(b)!=s;default:return t}},getBindings:function(a,c){var d=this.getBindingsString(a,c);return d?this.parseBindingsString(d,c):s},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.e.Xa(b);default:return s}},parseBindingsString:function(b,c){try{var d=c.$data,d="object"==typeof d&&d!=s?[d,c]:[c],f=d.length,g=this.cb,e=f+"_"+b,h;if(!(h=g[e])){var j=" { "+a.g.ka(b)+" } ";h=g[e]=a.a.eb(j,f)}return h(d)}catch(k){m(Error("Unable to parse bindings.\nMessage: "+
49
- k+";\nBindings value: "+b))}}});a.J.instance=new a.J})();a.b("bindingProvider",a.J);(function(){function b(b,d,e){for(var h=a.e.firstChild(d);d=h;)h=a.e.nextSibling(d),c(b,d,e)}function c(c,g,e){var h=p,j=1===g.nodeType;j&&a.e.Ia(g);if(j&&e||a.J.instance.nodeHasBindings(g))h=d(g,s,c,e).Gb;h&&b(c,g,!j)}function d(b,c,e,d){function j(a){return function(){return l[a]}}function k(){return l}var i=0,l,q;a.h(function(){var o=e&&e instanceof a.z?e:new a.z(a.a.d(e)),v=o.$data;d&&a.Ra(b,o);if(l=("function"==
50
- typeof c?c():c)||a.J.instance.getBindings(b,o)){if(0===i){i=1;for(var u in l){var r=a.c[u];r&&8===b.nodeType&&!a.e.C[u]&&m(Error("The binding '"+u+"' cannot be used with virtual elements"));if(r&&"function"==typeof r.init&&(r=(0,r.init)(b,j(u),k,v,o))&&r.controlsDescendantBindings)q!==n&&m(Error("Multiple bindings ("+q+" and "+u+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.")),q=u}i=2}if(2===i)for(u in l)(r=a.c[u])&&"function"==
51
- typeof r.update&&(0,r.update)(b,j(u),k,v,o)}},s,{disposeWhenNodeIsRemoved:b});return{Gb:q===n}}a.c={};a.z=function(b,c){c?(a.a.extend(this,c),this.$parentContext=c,this.$parent=c.$data,this.$parents=(c.$parents||[]).slice(0),this.$parents.unshift(this.$parent)):(this.$parents=[],this.$root=b);this.$data=b};a.z.prototype.createChildContext=function(b){return new a.z(b,this)};a.z.prototype.extend=function(b){var c=a.a.extend(new a.z,this);return a.a.extend(c,b)};a.Ra=function(b,c){if(2==arguments.length)a.a.f.set(b,
52
- "__ko_bindingContext__",c);else return a.a.f.get(b,"__ko_bindingContext__")};a.ya=function(b,c,e){1===b.nodeType&&a.e.Ia(b);return d(b,c,e,p)};a.Ya=function(a,c){(1===c.nodeType||8===c.nodeType)&&b(a,c,p)};a.xa=function(a,b){b&&(1!==b.nodeType&&8!==b.nodeType)&&m(Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node"));b=b||window.document.body;c(a,b,p)};a.ea=function(b){switch(b.nodeType){case 1:case 8:var c=a.Ra(b);if(c)return c;if(b.parentNode)return a.ea(b.parentNode)}};
53
- a.hb=function(b){return(b=a.ea(b))?b.$data:n};a.b("bindingHandlers",a.c);a.b("applyBindings",a.xa);a.b("applyBindingsToDescendants",a.Ya);a.b("applyBindingsToNode",a.ya);a.b("contextFor",a.ea);a.b("dataFor",a.hb)})();a.a.v(["click"],function(b){a.c[b]={init:function(c,d,f,g){return a.c.event.init.call(this,c,function(){var a={};a[b]=d();return a},f,g)}}});a.c.event={init:function(b,c,d,f){var g=c()||{},e;for(e in g)(function(){var g=e;"string"==typeof g&&a.a.n(b,g,function(b){var e,i=c()[g];if(i){var l=
54
- d();try{var q=a.a.L(arguments);q.unshift(f);e=i.apply(f,q)}finally{e!==p&&(b.preventDefault?b.preventDefault():b.returnValue=t)}l[g+"Bubble"]===t&&(b.cancelBubble=p,b.stopPropagation&&b.stopPropagation())}})})()}};a.c.submit={init:function(b,c,d,f){"function"!=typeof c()&&m(Error("The value for a submit binding must be a function"));a.a.n(b,"submit",function(a){var e,d=c();try{e=d.call(f,b)}finally{e!==p&&(a.preventDefault?a.preventDefault():a.returnValue=t)}})}};a.c.visible={update:function(b,c){var d=
55
- a.a.d(c()),f="none"!=b.style.display;d&&!f?b.style.display="":!d&&f&&(b.style.display="none")}};a.c.enable={update:function(b,c){var d=a.a.d(c());d&&b.disabled?b.removeAttribute("disabled"):!d&&!b.disabled&&(b.disabled=p)}};a.c.disable={update:function(b,c){a.c.enable.update(b,function(){return!a.a.d(c())})}};a.c.value={init:function(b,c,d){function f(){var e=c(),f=a.k.r(b);a.g.$(e,d,"value",f,p)}var g=["change"],e=d().valueUpdate;e&&("string"==typeof e&&(e=[e]),a.a.N(g,e),g=a.a.za(g));if(a.a.ja&&
56
- ("input"==b.tagName.toLowerCase()&&"text"==b.type&&"off"!=b.autocomplete&&(!b.form||"off"!=b.form.autocomplete))&&-1==a.a.j(g,"propertychange")){var h=t;a.a.n(b,"propertychange",function(){h=p});a.a.n(b,"blur",function(){if(h){h=t;f()}})}a.a.v(g,function(c){var e=f;if(a.a.Hb(c,"after")){e=function(){setTimeout(f,0)};c=c.substring(5)}a.a.n(b,c,e)})},update:function(b,c){var d="select"===a.a.o(b),f=a.a.d(c()),g=a.k.r(b),e=f!=g;0===f&&(0!==g&&"0"!==g)&&(e=p);e&&(g=function(){a.k.S(b,f)},g(),d&&setTimeout(g,
57
- 0));d&&0<b.length&&B(b,f,t)}};a.c.options={update:function(b,c,d){"select"!==a.a.o(b)&&m(Error("options binding applies only to SELECT elements"));for(var f=0==b.length,g=a.a.T(a.a.aa(b.childNodes,function(b){return b.tagName&&"option"===a.a.o(b)&&b.selected}),function(b){return a.k.r(b)||b.innerText||b.textContent}),e=b.scrollTop,h=a.a.d(c());0<b.length;)a.F(b.options[0]),b.remove(0);if(h){d=d();"number"!=typeof h.length&&(h=[h]);if(d.optionsCaption){var j=document.createElement("option");a.a.Y(j,
58
- d.optionsCaption);a.k.S(j,n);b.appendChild(j)}for(var c=0,k=h.length;c<k;c++){var j=document.createElement("option"),i="string"==typeof d.optionsValue?h[c][d.optionsValue]:h[c],i=a.a.d(i);a.k.S(j,i);var l=d.optionsText,i="function"==typeof l?l(h[c]):"string"==typeof l?h[c][l]:i;if(i===s||i===n)i="";a.a.Qa(j,i);b.appendChild(j)}h=b.getElementsByTagName("option");c=j=0;for(k=h.length;c<k;c++)0<=a.a.j(g,a.k.r(h[c]))&&(a.a.Pa(h[c],p),j++);b.scrollTop=e;f&&"value"in d&&B(b,a.a.d(d.value),p);a.a.lb(b)}}};
59
- a.c.options.oa="__ko.optionValueDomData__";a.c.selectedOptions={Ea:function(b){for(var c=[],b=b.childNodes,d=0,f=b.length;d<f;d++){var g=b[d],e=a.a.o(g);"option"==e&&g.selected?c.push(a.k.r(g)):"optgroup"==e&&(g=a.c.selectedOptions.Ea(g),Array.prototype.splice.apply(c,[c.length,0].concat(g)))}return c},init:function(b,c,d){a.a.n(b,"change",function(){var b=c(),g=a.c.selectedOptions.Ea(this);a.g.$(b,d,"value",g)})},update:function(b,c){"select"!=a.a.o(b)&&m(Error("values binding applies only to SELECT elements"));
60
- var d=a.a.d(c());if(d&&"number"==typeof d.length)for(var f=b.childNodes,g=0,e=f.length;g<e;g++){var h=f[g];"option"===a.a.o(h)&&a.a.Pa(h,0<=a.a.j(d,a.k.r(h)))}}};a.c.text={update:function(b,c){a.a.Qa(b,c())}};a.c.html={init:function(){return{controlsDescendantBindings:p}},update:function(b,c){var d=a.a.d(c());a.a.Y(b,d)}};a.c.css={update:function(b,c){var d=a.a.d(c()||{}),f;for(f in d)if("string"==typeof f){var g=a.a.d(d[f]);a.a.Ua(b,f,g)}}};a.c.style={update:function(b,c){var d=a.a.d(c()||{}),f;
61
- for(f in d)if("string"==typeof f){var g=a.a.d(d[f]);b.style[f]=g||""}}};a.c.uniqueName={init:function(b,c){c()&&(b.name="ko_unique_"+ ++a.c.uniqueName.gb,(a.a.tb||a.a.ub)&&b.mergeAttributes(document.createElement("<input name='"+b.name+"'/>"),t))}};a.c.uniqueName.gb=0;a.c.checked={init:function(b,c,d){a.a.n(b,"click",function(){var f;if("checkbox"==b.type)f=b.checked;else if("radio"==b.type&&b.checked)f=b.value;else return;var g=c();"checkbox"==b.type&&a.a.d(g)instanceof Array?(f=a.a.j(a.a.d(g),b.value),
62
- b.checked&&0>f?g.push(b.value):!b.checked&&0<=f&&g.splice(f,1)):a.g.$(g,d,"checked",f,p)});"radio"==b.type&&!b.name&&a.c.uniqueName.init(b,A(p))},update:function(b,c){var d=a.a.d(c());"checkbox"==b.type?b.checked=d instanceof Array?0<=a.a.j(d,b.value):d:"radio"==b.type&&(b.checked=b.value==d)}};var F={"class":"className","for":"htmlFor"};a.c.attr={update:function(b,c){var d=a.a.d(c())||{},f;for(f in d)if("string"==typeof f){var g=a.a.d(d[f]),e=g===t||g===s||g===n;e&&b.removeAttribute(f);8>=a.a.ja&&
63
- f in F?(f=F[f],e?b.removeAttribute(f):b[f]=g):e||b.setAttribute(f,g.toString())}}};a.c.hasfocus={init:function(b,c,d){function f(b){var e=c();a.g.$(e,d,"hasfocus",b,p)}a.a.n(b,"focus",function(){f(p)});a.a.n(b,"focusin",function(){f(p)});a.a.n(b,"blur",function(){f(t)});a.a.n(b,"focusout",function(){f(t)})},update:function(b,c){var d=a.a.d(c());d?b.focus():b.blur();a.a.va(b,d?"focusin":"focusout")}};a.c["with"]={p:function(b){return function(){var c=b();return{"if":c,data:c,templateEngine:a.q.K}}},
64
- init:function(b,c){return a.c.template.init(b,a.c["with"].p(c))},update:function(b,c,d,f,g){return a.c.template.update(b,a.c["with"].p(c),d,f,g)}};a.g.D["with"]=t;a.e.C["with"]=p;a.c["if"]={p:function(b){return function(){return{"if":b(),templateEngine:a.q.K}}},init:function(b,c){return a.c.template.init(b,a.c["if"].p(c))},update:function(b,c,d,f,g){return a.c.template.update(b,a.c["if"].p(c),d,f,g)}};a.g.D["if"]=t;a.e.C["if"]=p;a.c.ifnot={p:function(b){return function(){return{ifnot:b(),templateEngine:a.q.K}}},
65
- init:function(b,c){return a.c.template.init(b,a.c.ifnot.p(c))},update:function(b,c,d,f,g){return a.c.template.update(b,a.c.ifnot.p(c),d,f,g)}};a.g.D.ifnot=t;a.e.C.ifnot=p;a.c.foreach={p:function(b){return function(){var c=a.a.d(b());return!c||"number"==typeof c.length?{foreach:c,templateEngine:a.q.K}:{foreach:c.data,includeDestroyed:c.includeDestroyed,afterAdd:c.afterAdd,beforeRemove:c.beforeRemove,afterRender:c.afterRender,templateEngine:a.q.K}}},init:function(b,c){return a.c.template.init(b,a.c.foreach.p(c))},
66
- update:function(b,c,d,f,g){return a.c.template.update(b,a.c.foreach.p(c),d,f,g)}};a.g.D.foreach=t;a.e.C.foreach=p;a.t=function(){};a.t.prototype.renderTemplateSource=function(){m(Error("Override renderTemplateSource"))};a.t.prototype.createJavaScriptEvaluatorBlock=function(){m(Error("Override createJavaScriptEvaluatorBlock"))};a.t.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){var c=c||document,d=c.getElementById(b);d||m(Error("Cannot find template with ID "+b));return new a.l.i(d)}if(1==
67
- b.nodeType||8==b.nodeType)return new a.l.M(b);m(Error("Unknown template type: "+b))};a.t.prototype.renderTemplate=function(a,c,d,f){return this.renderTemplateSource(this.makeTemplateSource(a,f),c,d)};a.t.prototype.isTemplateRewritten=function(a,c){return this.allowTemplateRewriting===t||!(c&&c!=document)&&this.V&&this.V[a]?p:this.makeTemplateSource(a,c).data("isRewritten")};a.t.prototype.rewriteTemplate=function(a,c,d){var f=this.makeTemplateSource(a,d),c=c(f.text());f.text(c);f.data("isRewritten",
68
- p);!(d&&d!=document)&&"string"==typeof a&&(this.V=this.V||{},this.V[a]=p)};a.b("templateEngine",a.t);a.Z=function(){function b(b,c,e){for(var b=a.g.W(b),d=a.g.D,j=0;j<b.length;j++){var k=b[j].key;if(d.hasOwnProperty(k)){var i=d[k];"function"===typeof i?(k=i(b[j].value))&&m(Error(k)):i||m(Error("This template engine does not support the '"+k+"' binding within its templates"))}}b="ko.templateRewriting.applyMemoizedBindingsToNextSibling(function() { return (function() { return { "+a.g.ka(b)+
69
- " } })() })";return e.createJavaScriptEvaluatorBlock(b)+c}var c=/(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi,d=/<\!--\s*ko\b\s*([\s\S]*?)\s*--\>/g;return{mb:function(b,c,e){c.isTemplateRewritten(b,e)||c.rewriteTemplate(b,function(b){return a.Z.zb(b,c)},e)},zb:function(a,g){return a.replace(c,function(a,c,d,f,i,l,q){return b(q,c,g)}).replace(d,function(a,c){return b(c,"<\!-- ko --\>",g)})},Za:function(b){return a.s.na(function(c,
70
- e){c.nextSibling&&a.ya(c.nextSibling,b,e)})}}}();a.b("templateRewriting",a.Z);a.b("templateRewriting.applyMemoizedBindingsToNextSibling",a.Z.Za);(function(){a.l={};a.l.i=function(a){this.i=a};a.l.i.prototype.text=function(){var b=a.a.o(this.i),b="script"===b?"text":"textarea"===b?"value":"innerHTML";if(0==arguments.length)return this.i[b];var c=arguments[0];"innerHTML"===b?a.a.Y(this.i,c):this.i[b]=c};a.l.i.prototype.data=function(b){if(1===arguments.length)return a.a.f.get(this.i,"templateSourceData_"+
71
- b);a.a.f.set(this.i,"templateSourceData_"+b,arguments[1])};a.l.M=function(a){this.i=a};a.l.M.prototype=new a.l.i;a.l.M.prototype.text=function(){if(0==arguments.length){var b=a.a.f.get(this.i,"__ko_anon_template__")||{};b.ua===n&&b.da&&(b.ua=b.da.innerHTML);return b.ua}a.a.f.set(this.i,"__ko_anon_template__",{ua:arguments[0]})};a.l.i.prototype.nodes=function(){if(0==arguments.length)return(a.a.f.get(this.i,"__ko_anon_template__")||{}).da;a.a.f.set(this.i,"__ko_anon_template__",{da:arguments[0]})};
72
- a.b("templateSources",a.l);a.b("templateSources.domElement",a.l.i);a.b("templateSources.anonymousTemplate",a.l.M)})();(function(){function b(b,c,d){for(var f,c=a.e.nextSibling(c);b&&(f=b)!==c;)b=a.e.nextSibling(f),(1===f.nodeType||8===f.nodeType)&&d(f)}function c(c,d){if(c.length){var f=c[0],g=c[c.length-1];b(f,g,function(b){a.xa(d,b)});b(f,g,function(b){a.s.Wa(b,[d])})}}function d(a){return a.nodeType?a:0<a.length?a[0]:s}function f(b,f,j,k,i){var i=i||{},l=b&&d(b),l=l&&l.ownerDocument,q=i.templateEngine||
73
- g;a.Z.mb(j,q,l);j=q.renderTemplate(j,k,i,l);("number"!=typeof j.length||0<j.length&&"number"!=typeof j[0].nodeType)&&m(Error("Template engine must return an array of DOM nodes"));l=t;switch(f){case "replaceChildren":a.e.X(b,j);l=p;break;case "replaceNode":a.a.Na(b,j);l=p;break;case "ignoreTargetNode":break;default:m(Error("Unknown renderMode: "+f))}l&&(c(j,k),i.afterRender&&i.afterRender(j,k.$data));return j}var g;a.ra=function(b){b!=n&&!(b instanceof a.t)&&m(Error("templateEngine must inherit from ko.templateEngine"));
74
- g=b};a.qa=function(b,c,j,k,i){j=j||{};(j.templateEngine||g)==n&&m(Error("Set a template engine before calling renderTemplate"));i=i||"replaceChildren";if(k){var l=d(k);return a.h(function(){var g=c&&c instanceof a.z?c:new a.z(a.a.d(c)),o="function"==typeof b?b(g.$data):b,g=f(k,i,o,g,j);"replaceNode"==i&&(k=g,l=d(k))},s,{disposeWhen:function(){return!l||!a.a.fa(l)},disposeWhenNodeIsRemoved:l&&"replaceNode"==i?l.parentNode:l})}return a.s.na(function(d){a.qa(b,c,j,d,"replaceNode")})};a.Fb=function(b,
75
- d,g,k,i){function l(a,b){c(b,o);g.afterRender&&g.afterRender(b,a)}function q(c,d){var h="function"==typeof b?b(c):b;o=i.createChildContext(a.a.d(c));o.$index=d;return f(s,"ignoreTargetNode",h,o,g)}var o;return a.h(function(){var b=a.a.d(d)||[];"undefined"==typeof b.length&&(b=[b]);b=a.a.aa(b,function(b){return g.includeDestroyed||b===n||b===s||!a.a.d(b._destroy)});a.a.Oa(k,b,q,g,l)},s,{disposeWhenNodeIsRemoved:k})};a.c.template={init:function(b,c){var d=a.a.d(c());if("string"!=typeof d&&!d.name&&
76
- (1==b.nodeType||8==b.nodeType))d=1==b.nodeType?b.childNodes:a.e.childNodes(b),d=a.a.Ab(d),(new a.l.M(b)).nodes(d);return{controlsDescendantBindings:p}},update:function(b,c,d,f,g){c=a.a.d(c());f=p;"string"==typeof c?d=c:(d=c.name,"if"in c&&(f=f&&a.a.d(c["if"])),"ifnot"in c&&(f=f&&!a.a.d(c.ifnot)));var l=s;"object"===typeof c&&"foreach"in c?l=a.Fb(d||b,f&&c.foreach||[],c,b,g):f?(g="object"==typeof c&&"data"in c?g.createChildContext(a.a.d(c.data)):g,l=a.qa(d||b,g,c,b)):a.e.ha(b);g=l;(c=a.a.f.get(b,"__ko__templateSubscriptionDomDataKey__"))&&
77
- "function"==typeof c.A&&c.A();a.a.f.set(b,"__ko__templateSubscriptionDomDataKey__",g)}};a.g.D.template=function(b){b=a.g.W(b);return 1==b.length&&b[0].unknown||a.g.wb(b,"name")?s:"This template engine does not support anonymous templates nested within its templates"};a.e.C.template=p})();a.b("setTemplateEngine",a.ra);a.b("renderTemplate",a.qa);(function(){a.a.O=function(b,c,d){if(d===n)return a.a.O(b,c,1)||a.a.O(b,c,10)||a.a.O(b,c,Number.MAX_VALUE);for(var b=b||[],c=c||[],f=b,g=c,e=[],h=0;h<=g.length;h++)e[h]=
78
- [];for(var h=0,j=Math.min(f.length,d);h<=j;h++)e[0][h]=h;h=1;for(j=Math.min(g.length,d);h<=j;h++)e[h][0]=h;for(var j=f.length,k,i=g.length,h=1;h<=j;h++){k=Math.max(1,h-d);for(var l=Math.min(i,h+d);k<=l;k++)e[k][h]=f[h-1]===g[k-1]?e[k-1][h-1]:Math.min(e[k-1][h]===n?Number.MAX_VALUE:e[k-1][h]+1,e[k][h-1]===n?Number.MAX_VALUE:e[k][h-1]+1)}d=b.length;f=c.length;g=[];h=e[f][d];if(h===n)e=s;else{for(;0<d||0<f;){j=e[f][d];i=0<f?e[f-1][d]:h+1;l=0<d?e[f][d-1]:h+1;k=0<f&&0<d?e[f-1][d-1]:h+1;if(i===n||i<j-1)i=
79
- h+1;if(l===n||l<j-1)l=h+1;k<j-1&&(k=h+1);i<=l&&i<k?(g.push({status:"added",value:c[f-1]}),f--):(l<i&&l<k?g.push({status:"deleted",value:b[d-1]}):(g.push({status:"retained",value:b[d-1]}),f--),d--)}e=g.reverse()}return e}})();a.b("utils.compareArrays",a.a.O);(function(){function b(a){if(2<a.length){for(var b=a[0],c=a[a.length-1],e=[b];b!==c;){b=b.nextSibling;if(!b)return;e.push(b)}Array.prototype.splice.apply(a,[0,a.length].concat(e))}}function c(c,f,g,e,h){var j=[],c=a.h(function(){var c=f(g,h)||
80
- [];0<j.length&&(b(j),a.a.Na(j,c),e&&e(g,c));j.splice(0,j.length);a.a.N(j,c)},s,{disposeWhenNodeIsRemoved:c,disposeWhen:function(){return 0==j.length||!a.a.fa(j[0])}});return{xb:j,h:c}}a.a.Oa=function(d,f,g,e,h){for(var f=f||[],e=e||{},j=a.a.f.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")===n,k=a.a.f.get(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult")||[],i=a.a.T(k,function(a){return a.$a}),l=a.a.O(i,f),f=[],q=0,o=[],v=0,i=[],u=s,r=0,w=l.length;r<w;r++)switch(l[r].status){case "retained":var y=
81
- k[q];y.qb(v);v=f.push(y);0<y.P.length&&(u=y.P[y.P.length-1]);q++;break;case "deleted":k[q].h.A();b(k[q].P);a.a.v(k[q].P,function(a){o.push({element:a,index:r,value:l[r].value});u=a});q++;break;case "added":for(var y=l[r].value,x=a.m(v),v=c(d,g,y,h,x),C=v.xb,v=f.push({$a:l[r].value,P:C,h:v.h,qb:x}),z=0,B=C.length;z<B;z++){var D=C[z];i.push({element:D,index:r,value:l[r].value});u==s?a.e.Ka(d,D):a.e.Fa(d,D,u);u=D}h&&h(y,C,x)}a.a.v(o,function(b){a.F(b.element)});g=t;if(!j){if(e.afterAdd)for(r=0;r<i.length;r++)e.afterAdd(i[r].element,
82
- i[r].index,i[r].value);if(e.beforeRemove){for(r=0;r<o.length;r++)e.beforeRemove(o[r].element,o[r].index,o[r].value);g=p}}if(!g&&o.length)for(r=0;r<o.length;r++)e=o[r].element,e.parentNode&&e.parentNode.removeChild(e);a.a.f.set(d,"setDomNodeChildrenFromArrayMapping_lastMappingResult",f)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.Oa);a.q=function(){this.allowTemplateRewriting=t};a.q.prototype=new a.t;a.q.prototype.renderTemplateSource=function(b){var c=!(9>a.a.ja)&&b.nodes?b.nodes():s;
83
- if(c)return a.a.L(c.cloneNode(p).childNodes);b=b.text();return a.a.pa(b)};a.q.K=new a.q;a.ra(a.q.K);a.b("nativeTemplateEngine",a.q);(function(){a.ma=function(){var a=this.vb=function(){if("undefined"==typeof jQuery||!jQuery.tmpl)return 0;try{if(0<=jQuery.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();this.renderTemplateSource=function(b,f,g){g=g||{};2>a&&m(Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later."));var e=b.data("precompiled");
84
- e||(e=b.text()||"",e=jQuery.template(s,"{{ko_with $item.koBindingContext}}"+e+"{{/ko_with}}"),b.data("precompiled",e));b=[f.$data];f=jQuery.extend({koBindingContext:f},g.templateOptions);f=jQuery.tmpl(e,b,f);f.appendTo(document.createElement("div"));jQuery.fragments={};return f};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+a+" })()) }}"};this.addTemplate=function(a,b){document.write("<script type='text/html' id='"+a+"'>"+b+"<\/script>")};0<a&&(jQuery.tmpl.tag.ko_code=
85
- {open:"__.push($1 || '');"},jQuery.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.ma.prototype=new a.t;var b=new a.ma;0<b.vb&&a.ra(b);a.b("jqueryTmplTemplateEngine",a.ma)})()}"function"===typeof require&&"object"===typeof exports&&"object"===typeof module?E(module.exports||exports):"function"===typeof define&&define.amd?define(["exports"],E):E(window.ko={});p;
86
- })(window,document,navigator);
5
+ (function(){
6
+ var DEBUG=true;
7
+ (function(window,document,navigator,jQuery,undefined){
8
+ !function(factory) {
9
+ // Support three module loading scenarios
10
+ if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') {
11
+ // [1] CommonJS/Node.js
12
+ var target = module['exports'] || exports; // module.exports is for Node.js
13
+ factory(target);
14
+ } else if (typeof define === 'function' && define['amd']) {
15
+ // [2] AMD anonymous module
16
+ define(['exports'], factory);
17
+ } else {
18
+ // [3] No module loader (plain <script> tag) - put directly in global namespace
19
+ factory(window['ko'] = {});
20
+ }
21
+ }(function(koExports){
22
+ // Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
23
+ // In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
24
+ var ko = typeof koExports !== 'undefined' ? koExports : {};
25
+ // Google Closure Compiler helpers (used only to make the minified file smaller)
26
+ ko.exportSymbol = function(koPath, object) {
27
+ var tokens = koPath.split(".");
28
+
29
+ // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
30
+ // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
31
+ var target = ko;
32
+
33
+ for (var i = 0; i < tokens.length - 1; i++)
34
+ target = target[tokens[i]];
35
+ target[tokens[tokens.length - 1]] = object;
36
+ };
37
+ ko.exportProperty = function(owner, publicName, object) {
38
+ owner[publicName] = object;
39
+ };
40
+ ko.version = "2.2.0";
41
+
42
+ ko.exportSymbol('version', ko.version);
43
+ ko.utils = new (function () {
44
+ var stringTrimRegex = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
45
+
46
+ // 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)
47
+ var knownEvents = {}, knownEventTypesByEventName = {};
48
+ var keyEventTypeName = /Firefox\/2/i.test(navigator.userAgent) ? 'KeyboardEvent' : 'UIEvents';
49
+ knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
50
+ knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
51
+ for (var eventType in knownEvents) {
52
+ var knownEventsForType = knownEvents[eventType];
53
+ if (knownEventsForType.length) {
54
+ for (var i = 0, j = knownEventsForType.length; i < j; i++)
55
+ knownEventTypesByEventName[knownEventsForType[i]] = eventType;
56
+ }
57
+ }
58
+ var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406
59
+
60
+ // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
61
+ // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
62
+ // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
63
+ // If there is a future need to detect specific versions of IE10+, we will amend this.
64
+ var ieVersion = (function() {
65
+ var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');
66
+
67
+ // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
68
+ while (
69
+ div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
70
+ iElems[0]
71
+ );
72
+ return version > 4 ? version : undefined;
73
+ }());
74
+ var isIe6 = ieVersion === 6,
75
+ isIe7 = ieVersion === 7;
76
+
77
+ function isClickOnCheckableElement(element, eventType) {
78
+ if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
79
+ if (eventType.toLowerCase() != "click") return false;
80
+ var inputType = element.type;
81
+ return (inputType == "checkbox") || (inputType == "radio");
82
+ }
83
+
84
+ return {
85
+ fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],
86
+
87
+ arrayForEach: function (array, action) {
88
+ for (var i = 0, j = array.length; i < j; i++)
89
+ action(array[i]);
90
+ },
91
+
92
+ arrayIndexOf: function (array, item) {
93
+ if (typeof Array.prototype.indexOf == "function")
94
+ return Array.prototype.indexOf.call(array, item);
95
+ for (var i = 0, j = array.length; i < j; i++)
96
+ if (array[i] === item)
97
+ return i;
98
+ return -1;
99
+ },
100
+
101
+ arrayFirst: function (array, predicate, predicateOwner) {
102
+ for (var i = 0, j = array.length; i < j; i++)
103
+ if (predicate.call(predicateOwner, array[i]))
104
+ return array[i];
105
+ return null;
106
+ },
107
+
108
+ arrayRemoveItem: function (array, itemToRemove) {
109
+ var index = ko.utils.arrayIndexOf(array, itemToRemove);
110
+ if (index >= 0)
111
+ array.splice(index, 1);
112
+ },
113
+
114
+ arrayGetDistinctValues: function (array) {
115
+ array = array || [];
116
+ var result = [];
117
+ for (var i = 0, j = array.length; i < j; i++) {
118
+ if (ko.utils.arrayIndexOf(result, array[i]) < 0)
119
+ result.push(array[i]);
120
+ }
121
+ return result;
122
+ },
123
+
124
+ arrayMap: function (array, mapping) {
125
+ array = array || [];
126
+ var result = [];
127
+ for (var i = 0, j = array.length; i < j; i++)
128
+ result.push(mapping(array[i]));
129
+ return result;
130
+ },
131
+
132
+ arrayFilter: function (array, predicate) {
133
+ array = array || [];
134
+ var result = [];
135
+ for (var i = 0, j = array.length; i < j; i++)
136
+ if (predicate(array[i]))
137
+ result.push(array[i]);
138
+ return result;
139
+ },
140
+
141
+ arrayPushAll: function (array, valuesToPush) {
142
+ if (valuesToPush instanceof Array)
143
+ array.push.apply(array, valuesToPush);
144
+ else
145
+ for (var i = 0, j = valuesToPush.length; i < j; i++)
146
+ array.push(valuesToPush[i]);
147
+ return array;
148
+ },
149
+
150
+ extend: function (target, source) {
151
+ if (source) {
152
+ for(var prop in source) {
153
+ if(source.hasOwnProperty(prop)) {
154
+ target[prop] = source[prop];
155
+ }
156
+ }
157
+ }
158
+ return target;
159
+ },
160
+
161
+ emptyDomNode: function (domNode) {
162
+ while (domNode.firstChild) {
163
+ ko.removeNode(domNode.firstChild);
164
+ }
165
+ },
166
+
167
+ moveCleanedNodesToContainerElement: function(nodes) {
168
+ // Ensure it's a real array, as we're about to reparent the nodes and
169
+ // we don't want the underlying collection to change while we're doing that.
170
+ var nodesArray = ko.utils.makeArray(nodes);
171
+
172
+ var container = document.createElement('div');
173
+ for (var i = 0, j = nodesArray.length; i < j; i++) {
174
+ container.appendChild(ko.cleanNode(nodesArray[i]));
175
+ }
176
+ return container;
177
+ },
178
+
179
+ cloneNodes: function (nodesArray, shouldCleanNodes) {
180
+ for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
181
+ var clonedNode = nodesArray[i].cloneNode(true);
182
+ newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
183
+ }
184
+ return newNodesArray;
185
+ },
186
+
187
+ setDomNodeChildren: function (domNode, childNodes) {
188
+ ko.utils.emptyDomNode(domNode);
189
+ if (childNodes) {
190
+ for (var i = 0, j = childNodes.length; i < j; i++)
191
+ domNode.appendChild(childNodes[i]);
192
+ }
193
+ },
194
+
195
+ replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
196
+ var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
197
+ if (nodesToReplaceArray.length > 0) {
198
+ var insertionPoint = nodesToReplaceArray[0];
199
+ var parent = insertionPoint.parentNode;
200
+ for (var i = 0, j = newNodesArray.length; i < j; i++)
201
+ parent.insertBefore(newNodesArray[i], insertionPoint);
202
+ for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
203
+ ko.removeNode(nodesToReplaceArray[i]);
204
+ }
205
+ }
206
+ },
207
+
208
+ setOptionNodeSelectionState: function (optionNode, isSelected) {
209
+ // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
210
+ if (ieVersion < 7)
211
+ optionNode.setAttribute("selected", isSelected);
212
+ else
213
+ optionNode.selected = isSelected;
214
+ },
215
+
216
+ stringTrim: function (string) {
217
+ return (string || "").replace(stringTrimRegex, "");
218
+ },
219
+
220
+ stringTokenize: function (string, delimiter) {
221
+ var result = [];
222
+ var tokens = (string || "").split(delimiter);
223
+ for (var i = 0, j = tokens.length; i < j; i++) {
224
+ var trimmed = ko.utils.stringTrim(tokens[i]);
225
+ if (trimmed !== "")
226
+ result.push(trimmed);
227
+ }
228
+ return result;
229
+ },
230
+
231
+ stringStartsWith: function (string, startsWith) {
232
+ string = string || "";
233
+ if (startsWith.length > string.length)
234
+ return false;
235
+ return string.substring(0, startsWith.length) === startsWith;
236
+ },
237
+
238
+ domNodeIsContainedBy: function (node, containedByNode) {
239
+ if (containedByNode.compareDocumentPosition)
240
+ return (containedByNode.compareDocumentPosition(node) & 16) == 16;
241
+ while (node != null) {
242
+ if (node == containedByNode)
243
+ return true;
244
+ node = node.parentNode;
245
+ }
246
+ return false;
247
+ },
248
+
249
+ domNodeIsAttachedToDocument: function (node) {
250
+ return ko.utils.domNodeIsContainedBy(node, node.ownerDocument);
251
+ },
252
+
253
+ tagNameLower: function(element) {
254
+ // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
255
+ // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
256
+ // we don't need to do the .toLowerCase() as it will always be lower case anyway.
257
+ return element && element.tagName && element.tagName.toLowerCase();
258
+ },
259
+
260
+ registerEventHandler: function (element, eventType, handler) {
261
+ var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
262
+ if (!mustUseAttachEvent && typeof jQuery != "undefined") {
263
+ if (isClickOnCheckableElement(element, eventType)) {
264
+ // For click events on checkboxes, jQuery interferes with the event handling in an awkward way:
265
+ // it toggles the element checked state *after* the click event handlers run, whereas native
266
+ // click events toggle the checked state *before* the event handler.
267
+ // Fix this by intecepting the handler and applying the correct checkedness before it runs.
268
+ var originalHandler = handler;
269
+ handler = function(event, eventData) {
270
+ var jQuerySuppliedCheckedState = this.checked;
271
+ if (eventData)
272
+ this.checked = eventData.checkedStateBeforeEvent !== true;
273
+ originalHandler.call(this, event);
274
+ this.checked = jQuerySuppliedCheckedState; // Restore the state jQuery applied
275
+ };
276
+ }
277
+ jQuery(element)['bind'](eventType, handler);
278
+ } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
279
+ element.addEventListener(eventType, handler, false);
280
+ else if (typeof element.attachEvent != "undefined")
281
+ element.attachEvent("on" + eventType, function (event) {
282
+ handler.call(element, event);
283
+ });
284
+ else
285
+ throw new Error("Browser doesn't support addEventListener or attachEvent");
286
+ },
287
+
288
+ triggerEvent: function (element, eventType) {
289
+ if (!(element && element.nodeType))
290
+ throw new Error("element must be a DOM node when calling triggerEvent");
291
+
292
+ if (typeof jQuery != "undefined") {
293
+ var eventData = [];
294
+ if (isClickOnCheckableElement(element, eventType)) {
295
+ // Work around the jQuery "click events on checkboxes" issue described above by storing the original checked state before triggering the handler
296
+ eventData.push({ checkedStateBeforeEvent: element.checked });
297
+ }
298
+ jQuery(element)['trigger'](eventType, eventData);
299
+ } else if (typeof document.createEvent == "function") {
300
+ if (typeof element.dispatchEvent == "function") {
301
+ var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
302
+ var event = document.createEvent(eventCategory);
303
+ event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
304
+ element.dispatchEvent(event);
305
+ }
306
+ else
307
+ throw new Error("The supplied element doesn't support dispatchEvent");
308
+ } else if (typeof element.fireEvent != "undefined") {
309
+ // Unlike other browsers, IE doesn't change the checked state of checkboxes/radiobuttons when you trigger their "click" event
310
+ // so to make it consistent, we'll do it manually here
311
+ if (isClickOnCheckableElement(element, eventType))
312
+ element.checked = element.checked !== true;
313
+ element.fireEvent("on" + eventType);
314
+ }
315
+ else
316
+ throw new Error("Browser doesn't support triggering events");
317
+ },
318
+
319
+ unwrapObservable: function (value) {
320
+ return ko.isObservable(value) ? value() : value;
321
+ },
322
+
323
+ peekObservable: function (value) {
324
+ return ko.isObservable(value) ? value.peek() : value;
325
+ },
326
+
327
+ toggleDomNodeCssClass: function (node, classNames, shouldHaveClass) {
328
+ if (classNames) {
329
+ var cssClassNameRegex = /[\w-]+/g,
330
+ currentClassNames = node.className.match(cssClassNameRegex) || [];
331
+ ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
332
+ var indexOfClass = ko.utils.arrayIndexOf(currentClassNames, className);
333
+ if (indexOfClass >= 0) {
334
+ if (!shouldHaveClass)
335
+ currentClassNames.splice(indexOfClass, 1);
336
+ } else {
337
+ if (shouldHaveClass)
338
+ currentClassNames.push(className);
339
+ }
340
+ });
341
+ node.className = currentClassNames.join(" ");
342
+ }
343
+ },
344
+
345
+ setTextContent: function(element, textContent) {
346
+ var value = ko.utils.unwrapObservable(textContent);
347
+ if ((value === null) || (value === undefined))
348
+ value = "";
349
+
350
+ if (element.nodeType === 3) {
351
+ element.data = value;
352
+ } else {
353
+ // We need there to be exactly one child: a text node.
354
+ // If there are no children, more than one, or if it's not a text node,
355
+ // we'll clear everything and create a single text node.
356
+ var innerTextNode = ko.virtualElements.firstChild(element);
357
+ if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
358
+ ko.virtualElements.setDomNodeChildren(element, [document.createTextNode(value)]);
359
+ } else {
360
+ innerTextNode.data = value;
361
+ }
362
+
363
+ ko.utils.forceRefresh(element);
364
+ }
365
+ },
366
+
367
+ setElementName: function(element, name) {
368
+ element.name = name;
369
+
370
+ // Workaround IE 6/7 issue
371
+ // - https://github.com/SteveSanderson/knockout/issues/197
372
+ // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
373
+ if (ieVersion <= 7) {
374
+ try {
375
+ element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
376
+ }
377
+ catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
378
+ }
379
+ },
380
+
381
+ forceRefresh: function(node) {
382
+ // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
383
+ if (ieVersion >= 9) {
384
+ // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
385
+ var elem = node.nodeType == 1 ? node : node.parentNode;
386
+ if (elem.style)
387
+ elem.style.zoom = elem.style.zoom;
388
+ }
389
+ },
390
+
391
+ ensureSelectElementIsRenderedCorrectly: function(selectElement) {
392
+ // 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.
393
+ // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
394
+ if (ieVersion >= 9) {
395
+ var originalWidth = selectElement.style.width;
396
+ selectElement.style.width = 0;
397
+ selectElement.style.width = originalWidth;
398
+ }
399
+ },
400
+
401
+ range: function (min, max) {
402
+ min = ko.utils.unwrapObservable(min);
403
+ max = ko.utils.unwrapObservable(max);
404
+ var result = [];
405
+ for (var i = min; i <= max; i++)
406
+ result.push(i);
407
+ return result;
408
+ },
409
+
410
+ makeArray: function(arrayLikeObject) {
411
+ var result = [];
412
+ for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
413
+ result.push(arrayLikeObject[i]);
414
+ };
415
+ return result;
416
+ },
417
+
418
+ isIe6 : isIe6,
419
+ isIe7 : isIe7,
420
+ ieVersion : ieVersion,
421
+
422
+ getFormFields: function(form, fieldName) {
423
+ var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
424
+ var isMatchingField = (typeof fieldName == 'string')
425
+ ? function(field) { return field.name === fieldName }
426
+ : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
427
+ var matches = [];
428
+ for (var i = fields.length - 1; i >= 0; i--) {
429
+ if (isMatchingField(fields[i]))
430
+ matches.push(fields[i]);
431
+ };
432
+ return matches;
433
+ },
434
+
435
+ parseJson: function (jsonString) {
436
+ if (typeof jsonString == "string") {
437
+ jsonString = ko.utils.stringTrim(jsonString);
438
+ if (jsonString) {
439
+ if (window.JSON && window.JSON.parse) // Use native parsing where available
440
+ return window.JSON.parse(jsonString);
441
+ return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
442
+ }
443
+ }
444
+ return null;
445
+ },
446
+
447
+ stringifyJson: function (data, replacer, space) { // replacer and space are optional
448
+ if ((typeof JSON == "undefined") || (typeof JSON.stringify == "undefined"))
449
+ 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");
450
+ return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
451
+ },
452
+
453
+ postJson: function (urlOrForm, data, options) {
454
+ options = options || {};
455
+ var params = options['params'] || {};
456
+ var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
457
+ var url = urlOrForm;
458
+
459
+ // If we were given a form, use its 'action' URL and pick out any requested field values
460
+ if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
461
+ var originalForm = urlOrForm;
462
+ url = originalForm.action;
463
+ for (var i = includeFields.length - 1; i >= 0; i--) {
464
+ var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
465
+ for (var j = fields.length - 1; j >= 0; j--)
466
+ params[fields[j].name] = fields[j].value;
467
+ }
468
+ }
469
+
470
+ data = ko.utils.unwrapObservable(data);
471
+ var form = document.createElement("form");
472
+ form.style.display = "none";
473
+ form.action = url;
474
+ form.method = "post";
475
+ for (var key in data) {
476
+ var input = document.createElement("input");
477
+ input.name = key;
478
+ input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
479
+ form.appendChild(input);
480
+ }
481
+ for (var key in params) {
482
+ var input = document.createElement("input");
483
+ input.name = key;
484
+ input.value = params[key];
485
+ form.appendChild(input);
486
+ }
487
+ document.body.appendChild(form);
488
+ options['submitter'] ? options['submitter'](form) : form.submit();
489
+ setTimeout(function () { form.parentNode.removeChild(form); }, 0);
490
+ }
491
+ }
492
+ })();
493
+
494
+ ko.exportSymbol('utils', ko.utils);
495
+ ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
496
+ ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
497
+ ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
498
+ ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
499
+ ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
500
+ ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
501
+ ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
502
+ ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
503
+ ko.exportSymbol('utils.extend', ko.utils.extend);
504
+ ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
505
+ ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
506
+ ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
507
+ ko.exportSymbol('utils.postJson', ko.utils.postJson);
508
+ ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
509
+ ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
510
+ ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
511
+ ko.exportSymbol('utils.range', ko.utils.range);
512
+ ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
513
+ ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
514
+ ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
515
+
516
+ if (!Function.prototype['bind']) {
517
+ // 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)
518
+ // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
519
+ Function.prototype['bind'] = function (object) {
520
+ var originalFunction = this, args = Array.prototype.slice.call(arguments), object = args.shift();
521
+ return function () {
522
+ return originalFunction.apply(object, args.concat(Array.prototype.slice.call(arguments)));
523
+ };
524
+ };
525
+ }
526
+
527
+ ko.utils.domData = new (function () {
528
+ var uniqueId = 0;
529
+ var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
530
+ var dataStore = {};
531
+ return {
532
+ get: function (node, key) {
533
+ var allDataForNode = ko.utils.domData.getAll(node, false);
534
+ return allDataForNode === undefined ? undefined : allDataForNode[key];
535
+ },
536
+ set: function (node, key, value) {
537
+ if (value === undefined) {
538
+ // Make sure we don't actually create a new domData key if we are actually deleting a value
539
+ if (ko.utils.domData.getAll(node, false) === undefined)
540
+ return;
541
+ }
542
+ var allDataForNode = ko.utils.domData.getAll(node, true);
543
+ allDataForNode[key] = value;
544
+ },
545
+ getAll: function (node, createIfNotFound) {
546
+ var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
547
+ var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
548
+ if (!hasExistingDataStore) {
549
+ if (!createIfNotFound)
550
+ return undefined;
551
+ dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
552
+ dataStore[dataStoreKey] = {};
553
+ }
554
+ return dataStore[dataStoreKey];
555
+ },
556
+ clear: function (node) {
557
+ var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
558
+ if (dataStoreKey) {
559
+ delete dataStore[dataStoreKey];
560
+ node[dataStoreKeyExpandoPropertyName] = null;
561
+ return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
562
+ }
563
+ return false;
564
+ }
565
+ }
566
+ })();
567
+
568
+ ko.exportSymbol('utils.domData', ko.utils.domData);
569
+ ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully
570
+
571
+ ko.utils.domNodeDisposal = new (function () {
572
+ var domDataKey = "__ko_domNodeDisposal__" + (new Date).getTime();
573
+ var cleanableNodeTypes = { 1: true, 8: true, 9: true }; // Element, Comment, Document
574
+ var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document
575
+
576
+ function getDisposeCallbacksCollection(node, createIfNotFound) {
577
+ var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
578
+ if ((allDisposeCallbacks === undefined) && createIfNotFound) {
579
+ allDisposeCallbacks = [];
580
+ ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
581
+ }
582
+ return allDisposeCallbacks;
583
+ }
584
+ function destroyCallbacksCollection(node) {
585
+ ko.utils.domData.set(node, domDataKey, undefined);
586
+ }
587
+
588
+ function cleanSingleNode(node) {
589
+ // Run all the dispose callbacks
590
+ var callbacks = getDisposeCallbacksCollection(node, false);
591
+ if (callbacks) {
592
+ callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
593
+ for (var i = 0; i < callbacks.length; i++)
594
+ callbacks[i](node);
595
+ }
596
+
597
+ // Also erase the DOM data
598
+ ko.utils.domData.clear(node);
599
+
600
+ // Special support for jQuery here because it's so commonly used.
601
+ // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
602
+ // so notify it to tear down any resources associated with the node & descendants here.
603
+ if ((typeof jQuery == "function") && (typeof jQuery['cleanData'] == "function"))
604
+ jQuery['cleanData']([node]);
605
+
606
+ // Also clear any immediate-child comment nodes, as these wouldn't have been found by
607
+ // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
608
+ if (cleanableNodeTypesWithDescendants[node.nodeType])
609
+ cleanImmediateCommentTypeChildren(node);
610
+ }
611
+
612
+ function cleanImmediateCommentTypeChildren(nodeWithChildren) {
613
+ var child, nextChild = nodeWithChildren.firstChild;
614
+ while (child = nextChild) {
615
+ nextChild = child.nextSibling;
616
+ if (child.nodeType === 8)
617
+ cleanSingleNode(child);
618
+ }
619
+ }
620
+
621
+ return {
622
+ addDisposeCallback : function(node, callback) {
623
+ if (typeof callback != "function")
624
+ throw new Error("Callback must be a function");
625
+ getDisposeCallbacksCollection(node, true).push(callback);
626
+ },
627
+
628
+ removeDisposeCallback : function(node, callback) {
629
+ var callbacksCollection = getDisposeCallbacksCollection(node, false);
630
+ if (callbacksCollection) {
631
+ ko.utils.arrayRemoveItem(callbacksCollection, callback);
632
+ if (callbacksCollection.length == 0)
633
+ destroyCallbacksCollection(node);
634
+ }
635
+ },
636
+
637
+ cleanNode : function(node) {
638
+ // First clean this node, where applicable
639
+ if (cleanableNodeTypes[node.nodeType]) {
640
+ cleanSingleNode(node);
641
+
642
+ // ... then its descendants, where applicable
643
+ if (cleanableNodeTypesWithDescendants[node.nodeType]) {
644
+ // Clone the descendants list in case it changes during iteration
645
+ var descendants = [];
646
+ ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
647
+ for (var i = 0, j = descendants.length; i < j; i++)
648
+ cleanSingleNode(descendants[i]);
649
+ }
650
+ }
651
+ return node;
652
+ },
653
+
654
+ removeNode : function(node) {
655
+ ko.cleanNode(node);
656
+ if (node.parentNode)
657
+ node.parentNode.removeChild(node);
658
+ }
659
+ }
660
+ })();
661
+ ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
662
+ ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
663
+ ko.exportSymbol('cleanNode', ko.cleanNode);
664
+ ko.exportSymbol('removeNode', ko.removeNode);
665
+ ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
666
+ ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
667
+ ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
668
+ (function () {
669
+ var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
670
+
671
+ function simpleHtmlParse(html) {
672
+ // Based on jQuery's "clean" function, but only accounting for table-related elements.
673
+ // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
674
+
675
+ // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
676
+ // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
677
+ // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
678
+ // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
679
+
680
+ // Trim whitespace, otherwise indexOf won't work as expected
681
+ var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
682
+
683
+ // Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
684
+ var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
685
+ !tags.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] ||
686
+ (!tags.indexOf("<td") || !tags.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
687
+ /* anything else */ [0, "", ""];
688
+
689
+ // Go to html and back, then peel off extra wrappers
690
+ // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
691
+ var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
692
+ if (typeof window['innerShiv'] == "function") {
693
+ div.appendChild(window['innerShiv'](markup));
694
+ } else {
695
+ div.innerHTML = markup;
696
+ }
697
+
698
+ // Move to the right depth
699
+ while (wrap[0]--)
700
+ div = div.lastChild;
701
+
702
+ return ko.utils.makeArray(div.lastChild.childNodes);
703
+ }
704
+
705
+ function jQueryHtmlParse(html) {
706
+ var elems = jQuery['clean']([html]);
707
+
708
+ // 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.
709
+ // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
710
+ // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
711
+ if (elems && elems[0]) {
712
+ // Find the top-most parent element that's a direct child of a document fragment
713
+ var elem = elems[0];
714
+ while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
715
+ elem = elem.parentNode;
716
+ // ... then detach it
717
+ if (elem.parentNode)
718
+ elem.parentNode.removeChild(elem);
719
+ }
720
+
721
+ return elems;
722
+ }
723
+
724
+ ko.utils.parseHtmlFragment = function(html) {
725
+ return typeof jQuery != 'undefined' ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
726
+ : simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
727
+ };
728
+
729
+ ko.utils.setHtml = function(node, html) {
730
+ ko.utils.emptyDomNode(node);
731
+
732
+ // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
733
+ html = ko.utils.unwrapObservable(html);
734
+
735
+ if ((html !== null) && (html !== undefined)) {
736
+ if (typeof html != 'string')
737
+ html = html.toString();
738
+
739
+ // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
740
+ // for example <tr> elements which are not normally allowed to exist on their own.
741
+ // If you've referenced jQuery we'll use that rather than duplicating its code.
742
+ if (typeof jQuery != 'undefined') {
743
+ jQuery(node)['html'](html);
744
+ } else {
745
+ // ... otherwise, use KO's own parsing logic.
746
+ var parsedNodes = ko.utils.parseHtmlFragment(html);
747
+ for (var i = 0; i < parsedNodes.length; i++)
748
+ node.appendChild(parsedNodes[i]);
749
+ }
750
+ }
751
+ };
752
+ })();
753
+
754
+ ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
755
+ ko.exportSymbol('utils.setHtml', ko.utils.setHtml);
756
+
757
+ ko.memoization = (function () {
758
+ var memos = {};
759
+
760
+ function randomMax8HexChars() {
761
+ return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
762
+ }
763
+ function generateRandomId() {
764
+ return randomMax8HexChars() + randomMax8HexChars();
765
+ }
766
+ function findMemoNodes(rootNode, appendToArray) {
767
+ if (!rootNode)
768
+ return;
769
+ if (rootNode.nodeType == 8) {
770
+ var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
771
+ if (memoId != null)
772
+ appendToArray.push({ domNode: rootNode, memoId: memoId });
773
+ } else if (rootNode.nodeType == 1) {
774
+ for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
775
+ findMemoNodes(childNodes[i], appendToArray);
776
+ }
777
+ }
778
+
779
+ return {
780
+ memoize: function (callback) {
781
+ if (typeof callback != "function")
782
+ throw new Error("You can only pass a function to ko.memoization.memoize()");
783
+ var memoId = generateRandomId();
784
+ memos[memoId] = callback;
785
+ return "<!--[ko_memo:" + memoId + "]-->";
786
+ },
787
+
788
+ unmemoize: function (memoId, callbackParams) {
789
+ var callback = memos[memoId];
790
+ if (callback === undefined)
791
+ throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
792
+ try {
793
+ callback.apply(null, callbackParams || []);
794
+ return true;
795
+ }
796
+ finally { delete memos[memoId]; }
797
+ },
798
+
799
+ unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
800
+ var memos = [];
801
+ findMemoNodes(domNode, memos);
802
+ for (var i = 0, j = memos.length; i < j; i++) {
803
+ var node = memos[i].domNode;
804
+ var combinedParams = [node];
805
+ if (extraCallbackParamsArray)
806
+ ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
807
+ ko.memoization.unmemoize(memos[i].memoId, combinedParams);
808
+ node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
809
+ if (node.parentNode)
810
+ 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)
811
+ }
812
+ },
813
+
814
+ parseMemoText: function (memoText) {
815
+ var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
816
+ return match ? match[1] : null;
817
+ }
818
+ };
819
+ })();
820
+
821
+ ko.exportSymbol('memoization', ko.memoization);
822
+ ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
823
+ ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
824
+ ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
825
+ ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
826
+ ko.extenders = {
827
+ 'throttle': function(target, timeout) {
828
+ // Throttling means two things:
829
+
830
+ // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
831
+ // notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
832
+ target['throttleEvaluation'] = timeout;
833
+
834
+ // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
835
+ // so the target cannot change value synchronously or faster than a certain rate
836
+ var writeTimeoutInstance = null;
837
+ return ko.dependentObservable({
838
+ 'read': target,
839
+ 'write': function(value) {
840
+ clearTimeout(writeTimeoutInstance);
841
+ writeTimeoutInstance = setTimeout(function() {
842
+ target(value);
843
+ }, timeout);
844
+ }
845
+ });
846
+ },
847
+
848
+ 'notify': function(target, notifyWhen) {
849
+ target["equalityComparer"] = notifyWhen == "always"
850
+ ? function() { return false } // Treat all values as not equal
851
+ : ko.observable["fn"]["equalityComparer"];
852
+ return target;
853
+ }
854
+ };
855
+
856
+ function applyExtenders(requestedExtenders) {
857
+ var target = this;
858
+ if (requestedExtenders) {
859
+ for (var key in requestedExtenders) {
860
+ var extenderHandler = ko.extenders[key];
861
+ if (typeof extenderHandler == 'function') {
862
+ target = extenderHandler(target, requestedExtenders[key]);
863
+ }
864
+ }
865
+ }
866
+ return target;
867
+ }
868
+
869
+ ko.exportSymbol('extenders', ko.extenders);
870
+
871
+ ko.subscription = function (target, callback, disposeCallback) {
872
+ this.target = target;
873
+ this.callback = callback;
874
+ this.disposeCallback = disposeCallback;
875
+ ko.exportProperty(this, 'dispose', this.dispose);
876
+ };
877
+ ko.subscription.prototype.dispose = function () {
878
+ this.isDisposed = true;
879
+ this.disposeCallback();
880
+ };
881
+
882
+ ko.subscribable = function () {
883
+ this._subscriptions = {};
884
+
885
+ ko.utils.extend(this, ko.subscribable['fn']);
886
+ ko.exportProperty(this, 'subscribe', this.subscribe);
887
+ ko.exportProperty(this, 'extend', this.extend);
888
+ ko.exportProperty(this, 'getSubscriptionsCount', this.getSubscriptionsCount);
889
+ }
890
+
891
+ var defaultEvent = "change";
892
+
893
+ ko.subscribable['fn'] = {
894
+ subscribe: function (callback, callbackTarget, event) {
895
+ event = event || defaultEvent;
896
+ var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
897
+
898
+ var subscription = new ko.subscription(this, boundCallback, function () {
899
+ ko.utils.arrayRemoveItem(this._subscriptions[event], subscription);
900
+ }.bind(this));
901
+
902
+ if (!this._subscriptions[event])
903
+ this._subscriptions[event] = [];
904
+ this._subscriptions[event].push(subscription);
905
+ return subscription;
906
+ },
907
+
908
+ "notifySubscribers": function (valueToNotify, event) {
909
+ event = event || defaultEvent;
910
+ if (this._subscriptions[event]) {
911
+ ko.dependencyDetection.ignore(function() {
912
+ ko.utils.arrayForEach(this._subscriptions[event].slice(0), function (subscription) {
913
+ // In case a subscription was disposed during the arrayForEach cycle, check
914
+ // for isDisposed on each subscription before invoking its callback
915
+ if (subscription && (subscription.isDisposed !== true))
916
+ subscription.callback(valueToNotify);
917
+ });
918
+ }, this);
919
+ }
920
+ },
921
+
922
+ getSubscriptionsCount: function () {
923
+ var total = 0;
924
+ for (var eventName in this._subscriptions) {
925
+ if (this._subscriptions.hasOwnProperty(eventName))
926
+ total += this._subscriptions[eventName].length;
927
+ }
928
+ return total;
929
+ },
930
+
931
+ extend: applyExtenders
932
+ };
933
+
934
+
935
+ ko.isSubscribable = function (instance) {
936
+ return typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
937
+ };
938
+
939
+ ko.exportSymbol('subscribable', ko.subscribable);
940
+ ko.exportSymbol('isSubscribable', ko.isSubscribable);
941
+
942
+ ko.dependencyDetection = (function () {
943
+ var _frames = [];
944
+
945
+ return {
946
+ begin: function (callback) {
947
+ _frames.push({ callback: callback, distinctDependencies:[] });
948
+ },
949
+
950
+ end: function () {
951
+ _frames.pop();
952
+ },
953
+
954
+ registerDependency: function (subscribable) {
955
+ if (!ko.isSubscribable(subscribable))
956
+ throw new Error("Only subscribable things can act as dependencies");
957
+ if (_frames.length > 0) {
958
+ var topFrame = _frames[_frames.length - 1];
959
+ if (!topFrame || ko.utils.arrayIndexOf(topFrame.distinctDependencies, subscribable) >= 0)
960
+ return;
961
+ topFrame.distinctDependencies.push(subscribable);
962
+ topFrame.callback(subscribable);
963
+ }
964
+ },
965
+
966
+ ignore: function(callback, callbackTarget, callbackArgs) {
967
+ try {
968
+ _frames.push(null);
969
+ return callback.apply(callbackTarget, callbackArgs || []);
970
+ } finally {
971
+ _frames.pop();
972
+ }
973
+ }
974
+ };
975
+ })();
976
+ var primitiveTypes = { 'undefined':true, 'boolean':true, 'number':true, 'string':true };
977
+
978
+ ko.observable = function (initialValue) {
979
+ var _latestValue = initialValue;
980
+
981
+ function observable() {
982
+ if (arguments.length > 0) {
983
+ // Write
984
+
985
+ // Ignore writes if the value hasn't changed
986
+ if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {
987
+ observable.valueWillMutate();
988
+ _latestValue = arguments[0];
989
+ if (DEBUG) observable._latestValue = _latestValue;
990
+ observable.valueHasMutated();
991
+ }
992
+ return this; // Permits chained assignments
993
+ }
994
+ else {
995
+ // Read
996
+ ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
997
+ return _latestValue;
998
+ }
999
+ }
1000
+ if (DEBUG) observable._latestValue = _latestValue;
1001
+ ko.subscribable.call(observable);
1002
+ observable.peek = function() { return _latestValue };
1003
+ observable.valueHasMutated = function () { observable["notifySubscribers"](_latestValue); }
1004
+ observable.valueWillMutate = function () { observable["notifySubscribers"](_latestValue, "beforeChange"); }
1005
+ ko.utils.extend(observable, ko.observable['fn']);
1006
+
1007
+ ko.exportProperty(observable, 'peek', observable.peek);
1008
+ ko.exportProperty(observable, "valueHasMutated", observable.valueHasMutated);
1009
+ ko.exportProperty(observable, "valueWillMutate", observable.valueWillMutate);
1010
+
1011
+ return observable;
1012
+ }
1013
+
1014
+ ko.observable['fn'] = {
1015
+ "equalityComparer": function valuesArePrimitiveAndEqual(a, b) {
1016
+ var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
1017
+ return oldValueIsPrimitive ? (a === b) : false;
1018
+ }
1019
+ };
1020
+
1021
+ var protoProperty = ko.observable.protoProperty = "__ko_proto__";
1022
+ ko.observable['fn'][protoProperty] = ko.observable;
1023
+
1024
+ ko.hasPrototype = function(instance, prototype) {
1025
+ if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
1026
+ if (instance[protoProperty] === prototype) return true;
1027
+ return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
1028
+ };
1029
+
1030
+ ko.isObservable = function (instance) {
1031
+ return ko.hasPrototype(instance, ko.observable);
1032
+ }
1033
+ ko.isWriteableObservable = function (instance) {
1034
+ // Observable
1035
+ if ((typeof instance == "function") && instance[protoProperty] === ko.observable)
1036
+ return true;
1037
+ // Writeable dependent observable
1038
+ if ((typeof instance == "function") && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
1039
+ return true;
1040
+ // Anything else
1041
+ return false;
1042
+ }
1043
+
1044
+
1045
+ ko.exportSymbol('observable', ko.observable);
1046
+ ko.exportSymbol('isObservable', ko.isObservable);
1047
+ ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
1048
+ ko.observableArray = function (initialValues) {
1049
+ if (arguments.length == 0) {
1050
+ // Zero-parameter constructor initializes to empty array
1051
+ initialValues = [];
1052
+ }
1053
+ if ((initialValues !== null) && (initialValues !== undefined) && !('length' in initialValues))
1054
+ throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");
1055
+
1056
+ var result = ko.observable(initialValues);
1057
+ ko.utils.extend(result, ko.observableArray['fn']);
1058
+ return result;
1059
+ }
1060
+
1061
+ ko.observableArray['fn'] = {
1062
+ 'remove': function (valueOrPredicate) {
1063
+ var underlyingArray = this.peek();
1064
+ var removedValues = [];
1065
+ var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
1066
+ for (var i = 0; i < underlyingArray.length; i++) {
1067
+ var value = underlyingArray[i];
1068
+ if (predicate(value)) {
1069
+ if (removedValues.length === 0) {
1070
+ this.valueWillMutate();
1071
+ }
1072
+ removedValues.push(value);
1073
+ underlyingArray.splice(i, 1);
1074
+ i--;
1075
+ }
1076
+ }
1077
+ if (removedValues.length) {
1078
+ this.valueHasMutated();
1079
+ }
1080
+ return removedValues;
1081
+ },
1082
+
1083
+ 'removeAll': function (arrayOfValues) {
1084
+ // If you passed zero args, we remove everything
1085
+ if (arrayOfValues === undefined) {
1086
+ var underlyingArray = this.peek();
1087
+ var allValues = underlyingArray.slice(0);
1088
+ this.valueWillMutate();
1089
+ underlyingArray.splice(0, underlyingArray.length);
1090
+ this.valueHasMutated();
1091
+ return allValues;
1092
+ }
1093
+ // If you passed an arg, we interpret it as an array of entries to remove
1094
+ if (!arrayOfValues)
1095
+ return [];
1096
+ return this['remove'](function (value) {
1097
+ return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
1098
+ });
1099
+ },
1100
+
1101
+ 'destroy': function (valueOrPredicate) {
1102
+ var underlyingArray = this.peek();
1103
+ var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
1104
+ this.valueWillMutate();
1105
+ for (var i = underlyingArray.length - 1; i >= 0; i--) {
1106
+ var value = underlyingArray[i];
1107
+ if (predicate(value))
1108
+ underlyingArray[i]["_destroy"] = true;
1109
+ }
1110
+ this.valueHasMutated();
1111
+ },
1112
+
1113
+ 'destroyAll': function (arrayOfValues) {
1114
+ // If you passed zero args, we destroy everything
1115
+ if (arrayOfValues === undefined)
1116
+ return this['destroy'](function() { return true });
1117
+
1118
+ // If you passed an arg, we interpret it as an array of entries to destroy
1119
+ if (!arrayOfValues)
1120
+ return [];
1121
+ return this['destroy'](function (value) {
1122
+ return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
1123
+ });
1124
+ },
1125
+
1126
+ 'indexOf': function (item) {
1127
+ var underlyingArray = this();
1128
+ return ko.utils.arrayIndexOf(underlyingArray, item);
1129
+ },
1130
+
1131
+ 'replace': function(oldItem, newItem) {
1132
+ var index = this['indexOf'](oldItem);
1133
+ if (index >= 0) {
1134
+ this.valueWillMutate();
1135
+ this.peek()[index] = newItem;
1136
+ this.valueHasMutated();
1137
+ }
1138
+ }
1139
+ }
1140
+
1141
+ // Populate ko.observableArray.fn with read/write functions from native arrays
1142
+ // Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
1143
+ // because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
1144
+ ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
1145
+ ko.observableArray['fn'][methodName] = function () {
1146
+ // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
1147
+ // (for consistency with mutating regular observables)
1148
+ var underlyingArray = this.peek();
1149
+ this.valueWillMutate();
1150
+ var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
1151
+ this.valueHasMutated();
1152
+ return methodCallResult;
1153
+ };
1154
+ });
1155
+
1156
+ // Populate ko.observableArray.fn with read-only functions from native arrays
1157
+ ko.utils.arrayForEach(["slice"], function (methodName) {
1158
+ ko.observableArray['fn'][methodName] = function () {
1159
+ var underlyingArray = this();
1160
+ return underlyingArray[methodName].apply(underlyingArray, arguments);
1161
+ };
1162
+ });
1163
+
1164
+ ko.exportSymbol('observableArray', ko.observableArray);
1165
+ ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
1166
+ var _latestValue,
1167
+ _hasBeenEvaluated = false,
1168
+ _isBeingEvaluated = false,
1169
+ readFunction = evaluatorFunctionOrOptions;
1170
+
1171
+ if (readFunction && typeof readFunction == "object") {
1172
+ // Single-parameter syntax - everything is on this "options" param
1173
+ options = readFunction;
1174
+ readFunction = options["read"];
1175
+ } else {
1176
+ // Multi-parameter syntax - construct the options according to the params passed
1177
+ options = options || {};
1178
+ if (!readFunction)
1179
+ readFunction = options["read"];
1180
+ }
1181
+ if (typeof readFunction != "function")
1182
+ throw new Error("Pass a function that returns the value of the ko.computed");
1183
+
1184
+ function addSubscriptionToDependency(subscribable) {
1185
+ _subscriptionsToDependencies.push(subscribable.subscribe(evaluatePossiblyAsync));
1186
+ }
1187
+
1188
+ function disposeAllSubscriptionsToDependencies() {
1189
+ ko.utils.arrayForEach(_subscriptionsToDependencies, function (subscription) {
1190
+ subscription.dispose();
1191
+ });
1192
+ _subscriptionsToDependencies = [];
1193
+ }
1194
+
1195
+ function evaluatePossiblyAsync() {
1196
+ var throttleEvaluationTimeout = dependentObservable['throttleEvaluation'];
1197
+ if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
1198
+ clearTimeout(evaluationTimeoutInstance);
1199
+ evaluationTimeoutInstance = setTimeout(evaluateImmediate, throttleEvaluationTimeout);
1200
+ } else
1201
+ evaluateImmediate();
1202
+ }
1203
+
1204
+ function evaluateImmediate() {
1205
+ if (_isBeingEvaluated) {
1206
+ // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
1207
+ // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
1208
+ // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
1209
+ // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
1210
+ return;
1211
+ }
1212
+
1213
+ // Don't dispose on first evaluation, because the "disposeWhen" callback might
1214
+ // e.g., dispose when the associated DOM element isn't in the doc, and it's not
1215
+ // going to be in the doc until *after* the first evaluation
1216
+ if (_hasBeenEvaluated && disposeWhen()) {
1217
+ dispose();
1218
+ return;
1219
+ }
1220
+
1221
+ _isBeingEvaluated = true;
1222
+ try {
1223
+ // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
1224
+ // Then, during evaluation, we cross off any that are in fact still being used.
1225
+ var disposalCandidates = ko.utils.arrayMap(_subscriptionsToDependencies, function(item) {return item.target;});
1226
+
1227
+ ko.dependencyDetection.begin(function(subscribable) {
1228
+ var inOld;
1229
+ if ((inOld = ko.utils.arrayIndexOf(disposalCandidates, subscribable)) >= 0)
1230
+ disposalCandidates[inOld] = undefined; // Don't want to dispose this subscription, as it's still being used
1231
+ else
1232
+ addSubscriptionToDependency(subscribable); // Brand new subscription - add it
1233
+ });
1234
+
1235
+ var newValue = readFunction.call(evaluatorFunctionTarget);
1236
+
1237
+ // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
1238
+ for (var i = disposalCandidates.length - 1; i >= 0; i--) {
1239
+ if (disposalCandidates[i])
1240
+ _subscriptionsToDependencies.splice(i, 1)[0].dispose();
1241
+ }
1242
+ _hasBeenEvaluated = true;
1243
+
1244
+ dependentObservable["notifySubscribers"](_latestValue, "beforeChange");
1245
+ _latestValue = newValue;
1246
+ if (DEBUG) dependentObservable._latestValue = _latestValue;
1247
+ } finally {
1248
+ ko.dependencyDetection.end();
1249
+ }
1250
+
1251
+ dependentObservable["notifySubscribers"](_latestValue);
1252
+ _isBeingEvaluated = false;
1253
+ if (!_subscriptionsToDependencies.length)
1254
+ dispose();
1255
+ }
1256
+
1257
+ function dependentObservable() {
1258
+ if (arguments.length > 0) {
1259
+ if (typeof writeFunction === "function") {
1260
+ // Writing a value
1261
+ writeFunction.apply(evaluatorFunctionTarget, arguments);
1262
+ } else {
1263
+ 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.");
1264
+ }
1265
+ return this; // Permits chained assignments
1266
+ } else {
1267
+ // Reading the value
1268
+ if (!_hasBeenEvaluated)
1269
+ evaluateImmediate();
1270
+ ko.dependencyDetection.registerDependency(dependentObservable);
1271
+ return _latestValue;
1272
+ }
1273
+ }
1274
+
1275
+ function peek() {
1276
+ if (!_hasBeenEvaluated)
1277
+ evaluateImmediate();
1278
+ return _latestValue;
1279
+ }
1280
+
1281
+ function isActive() {
1282
+ return !_hasBeenEvaluated || _subscriptionsToDependencies.length > 0;
1283
+ }
1284
+
1285
+ // By here, "options" is always non-null
1286
+ var writeFunction = options["write"],
1287
+ disposeWhenNodeIsRemoved = options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
1288
+ disposeWhen = options["disposeWhen"] || options.disposeWhen || function() { return false; },
1289
+ dispose = disposeAllSubscriptionsToDependencies,
1290
+ _subscriptionsToDependencies = [],
1291
+ evaluationTimeoutInstance = null;
1292
+
1293
+ if (!evaluatorFunctionTarget)
1294
+ evaluatorFunctionTarget = options["owner"];
1295
+
1296
+ dependentObservable.peek = peek;
1297
+ dependentObservable.getDependenciesCount = function () { return _subscriptionsToDependencies.length; };
1298
+ dependentObservable.hasWriteFunction = typeof options["write"] === "function";
1299
+ dependentObservable.dispose = function () { dispose(); };
1300
+ dependentObservable.isActive = isActive;
1301
+
1302
+ ko.subscribable.call(dependentObservable);
1303
+ ko.utils.extend(dependentObservable, ko.dependentObservable['fn']);
1304
+
1305
+ ko.exportProperty(dependentObservable, 'peek', dependentObservable.peek);
1306
+ ko.exportProperty(dependentObservable, 'dispose', dependentObservable.dispose);
1307
+ ko.exportProperty(dependentObservable, 'isActive', dependentObservable.isActive);
1308
+ ko.exportProperty(dependentObservable, 'getDependenciesCount', dependentObservable.getDependenciesCount);
1309
+
1310
+ // Evaluate, unless deferEvaluation is true
1311
+ if (options['deferEvaluation'] !== true)
1312
+ evaluateImmediate();
1313
+
1314
+ // Build "disposeWhenNodeIsRemoved" and "disposeWhenNodeIsRemovedCallback" option values.
1315
+ // But skip if isActive is false (there will never be any dependencies to dispose).
1316
+ // (Note: "disposeWhenNodeIsRemoved" option both proactively disposes as soon as the node is removed using ko.removeNode(),
1317
+ // plus adds a "disposeWhen" callback that, on each evaluation, disposes if the node was removed by some other means.)
1318
+ if (disposeWhenNodeIsRemoved && isActive()) {
1319
+ dispose = function() {
1320
+ ko.utils.domNodeDisposal.removeDisposeCallback(disposeWhenNodeIsRemoved, arguments.callee);
1321
+ disposeAllSubscriptionsToDependencies();
1322
+ };
1323
+ ko.utils.domNodeDisposal.addDisposeCallback(disposeWhenNodeIsRemoved, dispose);
1324
+ var existingDisposeWhenFunction = disposeWhen;
1325
+ disposeWhen = function () {
1326
+ return !ko.utils.domNodeIsAttachedToDocument(disposeWhenNodeIsRemoved) || existingDisposeWhenFunction();
1327
+ }
1328
+ }
1329
+
1330
+ return dependentObservable;
1331
+ };
1332
+
1333
+ ko.isComputed = function(instance) {
1334
+ return ko.hasPrototype(instance, ko.dependentObservable);
1335
+ };
1336
+
1337
+ var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
1338
+ ko.dependentObservable[protoProp] = ko.observable;
1339
+
1340
+ ko.dependentObservable['fn'] = {};
1341
+ ko.dependentObservable['fn'][protoProp] = ko.dependentObservable;
1342
+
1343
+ ko.exportSymbol('dependentObservable', ko.dependentObservable);
1344
+ ko.exportSymbol('computed', ko.dependentObservable); // Make "ko.computed" an alias for "ko.dependentObservable"
1345
+ ko.exportSymbol('isComputed', ko.isComputed);
1346
+
1347
+ (function() {
1348
+ var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)
1349
+
1350
+ ko.toJS = function(rootObject) {
1351
+ if (arguments.length == 0)
1352
+ throw new Error("When calling ko.toJS, pass the object you want to convert.");
1353
+
1354
+ // We just unwrap everything at every level in the object graph
1355
+ return mapJsObjectGraph(rootObject, function(valueToMap) {
1356
+ // Loop because an observable's value might in turn be another observable wrapper
1357
+ for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
1358
+ valueToMap = valueToMap();
1359
+ return valueToMap;
1360
+ });
1361
+ };
1362
+
1363
+ ko.toJSON = function(rootObject, replacer, space) { // replacer and space are optional
1364
+ var plainJavaScriptObject = ko.toJS(rootObject);
1365
+ return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
1366
+ };
1367
+
1368
+ function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
1369
+ visitedObjects = visitedObjects || new objectLookup();
1370
+
1371
+ rootObject = mapInputCallback(rootObject);
1372
+ var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof Date));
1373
+ if (!canHaveProperties)
1374
+ return rootObject;
1375
+
1376
+ var outputProperties = rootObject instanceof Array ? [] : {};
1377
+ visitedObjects.save(rootObject, outputProperties);
1378
+
1379
+ visitPropertiesOrArrayEntries(rootObject, function(indexer) {
1380
+ var propertyValue = mapInputCallback(rootObject[indexer]);
1381
+
1382
+ switch (typeof propertyValue) {
1383
+ case "boolean":
1384
+ case "number":
1385
+ case "string":
1386
+ case "function":
1387
+ outputProperties[indexer] = propertyValue;
1388
+ break;
1389
+ case "object":
1390
+ case "undefined":
1391
+ var previouslyMappedValue = visitedObjects.get(propertyValue);
1392
+ outputProperties[indexer] = (previouslyMappedValue !== undefined)
1393
+ ? previouslyMappedValue
1394
+ : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
1395
+ break;
1396
+ }
1397
+ });
1398
+
1399
+ return outputProperties;
1400
+ }
1401
+
1402
+ function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
1403
+ if (rootObject instanceof Array) {
1404
+ for (var i = 0; i < rootObject.length; i++)
1405
+ visitorCallback(i);
1406
+
1407
+ // For arrays, also respect toJSON property for custom mappings (fixes #278)
1408
+ if (typeof rootObject['toJSON'] == 'function')
1409
+ visitorCallback('toJSON');
1410
+ } else {
1411
+ for (var propertyName in rootObject)
1412
+ visitorCallback(propertyName);
1413
+ }
1414
+ };
1415
+
1416
+ function objectLookup() {
1417
+ var keys = [];
1418
+ var values = [];
1419
+ this.save = function(key, value) {
1420
+ var existingIndex = ko.utils.arrayIndexOf(keys, key);
1421
+ if (existingIndex >= 0)
1422
+ values[existingIndex] = value;
1423
+ else {
1424
+ keys.push(key);
1425
+ values.push(value);
1426
+ }
1427
+ };
1428
+ this.get = function(key) {
1429
+ var existingIndex = ko.utils.arrayIndexOf(keys, key);
1430
+ return (existingIndex >= 0) ? values[existingIndex] : undefined;
1431
+ };
1432
+ };
1433
+ })();
1434
+
1435
+ ko.exportSymbol('toJS', ko.toJS);
1436
+ ko.exportSymbol('toJSON', ko.toJSON);
1437
+ (function () {
1438
+ var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';
1439
+
1440
+ // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
1441
+ // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
1442
+ // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
1443
+ ko.selectExtensions = {
1444
+ readValue : function(element) {
1445
+ switch (ko.utils.tagNameLower(element)) {
1446
+ case 'option':
1447
+ if (element[hasDomDataExpandoProperty] === true)
1448
+ return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
1449
+ return ko.utils.ieVersion <= 7
1450
+ ? (element.getAttributeNode('value').specified ? element.value : element.text)
1451
+ : element.value;
1452
+ case 'select':
1453
+ return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
1454
+ default:
1455
+ return element.value;
1456
+ }
1457
+ },
1458
+
1459
+ writeValue: function(element, value) {
1460
+ switch (ko.utils.tagNameLower(element)) {
1461
+ case 'option':
1462
+ switch(typeof value) {
1463
+ case "string":
1464
+ ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
1465
+ if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
1466
+ delete element[hasDomDataExpandoProperty];
1467
+ }
1468
+ element.value = value;
1469
+ break;
1470
+ default:
1471
+ // Store arbitrary object using DomData
1472
+ ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
1473
+ element[hasDomDataExpandoProperty] = true;
1474
+
1475
+ // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
1476
+ element.value = typeof value === "number" ? value : "";
1477
+ break;
1478
+ }
1479
+ break;
1480
+ case 'select':
1481
+ for (var i = element.options.length - 1; i >= 0; i--) {
1482
+ if (ko.selectExtensions.readValue(element.options[i]) == value) {
1483
+ element.selectedIndex = i;
1484
+ break;
1485
+ }
1486
+ }
1487
+ break;
1488
+ default:
1489
+ if ((value === null) || (value === undefined))
1490
+ value = "";
1491
+ element.value = value;
1492
+ break;
1493
+ }
1494
+ }
1495
+ };
1496
+ })();
1497
+
1498
+ ko.exportSymbol('selectExtensions', ko.selectExtensions);
1499
+ ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
1500
+ ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
1501
+ ko.expressionRewriting = (function () {
1502
+ var restoreCapturedTokensRegex = /\@ko_token_(\d+)\@/g;
1503
+ var javaScriptReservedWords = ["true", "false"];
1504
+
1505
+ // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
1506
+ // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
1507
+ var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;
1508
+
1509
+ function restoreTokens(string, tokens) {
1510
+ var prevValue = null;
1511
+ while (string != prevValue) { // Keep restoring tokens until it no longer makes a difference (they may be nested)
1512
+ prevValue = string;
1513
+ string = string.replace(restoreCapturedTokensRegex, function (match, tokenIndex) {
1514
+ return tokens[tokenIndex];
1515
+ });
1516
+ }
1517
+ return string;
1518
+ }
1519
+
1520
+ function getWriteableValue(expression) {
1521
+ if (ko.utils.arrayIndexOf(javaScriptReservedWords, ko.utils.stringTrim(expression).toLowerCase()) >= 0)
1522
+ return false;
1523
+ var match = expression.match(javaScriptAssignmentTarget);
1524
+ return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
1525
+ }
1526
+
1527
+ function ensureQuoted(key) {
1528
+ var trimmedKey = ko.utils.stringTrim(key);
1529
+ switch (trimmedKey.length && trimmedKey.charAt(0)) {
1530
+ case "'":
1531
+ case '"':
1532
+ return key;
1533
+ default:
1534
+ return "'" + trimmedKey + "'";
1535
+ }
1536
+ }
1537
+
1538
+ return {
1539
+ bindingRewriteValidators: [],
1540
+
1541
+ parseObjectLiteral: function(objectLiteralString) {
1542
+ // A full tokeniser+lexer would add too much weight to this library, so here's a simple parser
1543
+ // that is sufficient just to split an object literal string into a set of top-level key-value pairs
1544
+
1545
+ var str = ko.utils.stringTrim(objectLiteralString);
1546
+ if (str.length < 3)
1547
+ return [];
1548
+ if (str.charAt(0) === "{")// Ignore any braces surrounding the whole object literal
1549
+ str = str.substring(1, str.length - 1);
1550
+
1551
+ // Pull out any string literals and regex literals
1552
+ var tokens = [];
1553
+ var tokenStart = null, tokenEndChar;
1554
+ for (var position = 0; position < str.length; position++) {
1555
+ var c = str.charAt(position);
1556
+ if (tokenStart === null) {
1557
+ switch (c) {
1558
+ case '"':
1559
+ case "'":
1560
+ case "/":
1561
+ tokenStart = position;
1562
+ tokenEndChar = c;
1563
+ break;
1564
+ }
1565
+ } else if ((c == tokenEndChar) && (str.charAt(position - 1) !== "\\")) {
1566
+ var token = str.substring(tokenStart, position + 1);
1567
+ tokens.push(token);
1568
+ var replacement = "@ko_token_" + (tokens.length - 1) + "@";
1569
+ str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
1570
+ position -= (token.length - replacement.length);
1571
+ tokenStart = null;
1572
+ }
1573
+ }
1574
+
1575
+ // Next pull out balanced paren, brace, and bracket blocks
1576
+ tokenStart = null;
1577
+ tokenEndChar = null;
1578
+ var tokenDepth = 0, tokenStartChar = null;
1579
+ for (var position = 0; position < str.length; position++) {
1580
+ var c = str.charAt(position);
1581
+ if (tokenStart === null) {
1582
+ switch (c) {
1583
+ case "{": tokenStart = position; tokenStartChar = c;
1584
+ tokenEndChar = "}";
1585
+ break;
1586
+ case "(": tokenStart = position; tokenStartChar = c;
1587
+ tokenEndChar = ")";
1588
+ break;
1589
+ case "[": tokenStart = position; tokenStartChar = c;
1590
+ tokenEndChar = "]";
1591
+ break;
1592
+ }
1593
+ }
1594
+
1595
+ if (c === tokenStartChar)
1596
+ tokenDepth++;
1597
+ else if (c === tokenEndChar) {
1598
+ tokenDepth--;
1599
+ if (tokenDepth === 0) {
1600
+ var token = str.substring(tokenStart, position + 1);
1601
+ tokens.push(token);
1602
+ var replacement = "@ko_token_" + (tokens.length - 1) + "@";
1603
+ str = str.substring(0, tokenStart) + replacement + str.substring(position + 1);
1604
+ position -= (token.length - replacement.length);
1605
+ tokenStart = null;
1606
+ }
1607
+ }
1608
+ }
1609
+
1610
+ // Now we can safely split on commas to get the key/value pairs
1611
+ var result = [];
1612
+ var keyValuePairs = str.split(",");
1613
+ for (var i = 0, j = keyValuePairs.length; i < j; i++) {
1614
+ var pair = keyValuePairs[i];
1615
+ var colonPos = pair.indexOf(":");
1616
+ if ((colonPos > 0) && (colonPos < pair.length - 1)) {
1617
+ var key = pair.substring(0, colonPos);
1618
+ var value = pair.substring(colonPos + 1);
1619
+ result.push({ 'key': restoreTokens(key, tokens), 'value': restoreTokens(value, tokens) });
1620
+ } else {
1621
+ result.push({ 'unknown': restoreTokens(pair, tokens) });
1622
+ }
1623
+ }
1624
+ return result;
1625
+ },
1626
+
1627
+ preProcessBindings: function (objectLiteralStringOrKeyValueArray) {
1628
+ var keyValueArray = typeof objectLiteralStringOrKeyValueArray === "string"
1629
+ ? ko.expressionRewriting.parseObjectLiteral(objectLiteralStringOrKeyValueArray)
1630
+ : objectLiteralStringOrKeyValueArray;
1631
+ var resultStrings = [], propertyAccessorResultStrings = [];
1632
+
1633
+ var keyValueEntry;
1634
+ for (var i = 0; keyValueEntry = keyValueArray[i]; i++) {
1635
+ if (resultStrings.length > 0)
1636
+ resultStrings.push(",");
1637
+
1638
+ if (keyValueEntry['key']) {
1639
+ var quotedKey = ensureQuoted(keyValueEntry['key']), val = keyValueEntry['value'];
1640
+ resultStrings.push(quotedKey);
1641
+ resultStrings.push(":");
1642
+ resultStrings.push(val);
1643
+
1644
+ if (val = getWriteableValue(ko.utils.stringTrim(val))) {
1645
+ if (propertyAccessorResultStrings.length > 0)
1646
+ propertyAccessorResultStrings.push(", ");
1647
+ propertyAccessorResultStrings.push(quotedKey + " : function(__ko_value) { " + val + " = __ko_value; }");
1648
+ }
1649
+ } else if (keyValueEntry['unknown']) {
1650
+ resultStrings.push(keyValueEntry['unknown']);
1651
+ }
1652
+ }
1653
+
1654
+ var combinedResult = resultStrings.join("");
1655
+ if (propertyAccessorResultStrings.length > 0) {
1656
+ var allPropertyAccessors = propertyAccessorResultStrings.join("");
1657
+ combinedResult = combinedResult + ", '_ko_property_writers' : { " + allPropertyAccessors + " } ";
1658
+ }
1659
+
1660
+ return combinedResult;
1661
+ },
1662
+
1663
+ keyValueArrayContainsKey: function(keyValueArray, key) {
1664
+ for (var i = 0; i < keyValueArray.length; i++)
1665
+ if (ko.utils.stringTrim(keyValueArray[i]['key']) == key)
1666
+ return true;
1667
+ return false;
1668
+ },
1669
+
1670
+ // Internal, private KO utility for updating model properties from within bindings
1671
+ // property: If the property being updated is (or might be) an observable, pass it here
1672
+ // If it turns out to be a writable observable, it will be written to directly
1673
+ // allBindingsAccessor: All bindings in the current execution context.
1674
+ // This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
1675
+ // key: The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
1676
+ // value: The value to be written
1677
+ // checkIfDifferent: If true, and if the property being written is a writable observable, the value will only be written if
1678
+ // it is !== existing value on that writable observable
1679
+ writeValueToProperty: function(property, allBindingsAccessor, key, value, checkIfDifferent) {
1680
+ if (!property || !ko.isWriteableObservable(property)) {
1681
+ var propWriters = allBindingsAccessor()['_ko_property_writers'];
1682
+ if (propWriters && propWriters[key])
1683
+ propWriters[key](value);
1684
+ } else if (!checkIfDifferent || property.peek() !== value) {
1685
+ property(value);
1686
+ }
1687
+ }
1688
+ };
1689
+ })();
1690
+
1691
+ ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
1692
+ ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
1693
+ ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
1694
+ ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);
1695
+
1696
+ // For backward compatibility, define the following aliases. (Previously, these function names were misleading because
1697
+ // they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
1698
+ ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
1699
+ ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);(function() {
1700
+ // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
1701
+ // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
1702
+ // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
1703
+ // of that virtual hierarchy
1704
+ //
1705
+ // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
1706
+ // without having to scatter special cases all over the binding and templating code.
1707
+
1708
+ // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
1709
+ // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
1710
+ // So, use node.text where available, and node.nodeValue elsewhere
1711
+ var commentNodesHaveTextProperty = document.createComment("test").text === "<!--test-->";
1712
+
1713
+ var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*-->$/ : /^\s*ko(?:\s+(.+\s*\:[\s\S]*))?\s*$/;
1714
+ var endCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
1715
+ var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };
1716
+
1717
+ function isStartComment(node) {
1718
+ return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
1719
+ }
1720
+
1721
+ function isEndComment(node) {
1722
+ return (node.nodeType == 8) && (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(endCommentRegex);
1723
+ }
1724
+
1725
+ function getVirtualChildren(startComment, allowUnbalanced) {
1726
+ var currentNode = startComment;
1727
+ var depth = 1;
1728
+ var children = [];
1729
+ while (currentNode = currentNode.nextSibling) {
1730
+ if (isEndComment(currentNode)) {
1731
+ depth--;
1732
+ if (depth === 0)
1733
+ return children;
1734
+ }
1735
+
1736
+ children.push(currentNode);
1737
+
1738
+ if (isStartComment(currentNode))
1739
+ depth++;
1740
+ }
1741
+ if (!allowUnbalanced)
1742
+ throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
1743
+ return null;
1744
+ }
1745
+
1746
+ function getMatchingEndComment(startComment, allowUnbalanced) {
1747
+ var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
1748
+ if (allVirtualChildren) {
1749
+ if (allVirtualChildren.length > 0)
1750
+ return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
1751
+ return startComment.nextSibling;
1752
+ } else
1753
+ return null; // Must have no matching end comment, and allowUnbalanced is true
1754
+ }
1755
+
1756
+ function getUnbalancedChildTags(node) {
1757
+ // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
1758
+ // from <div>OK</div><!-- /ko --><!-- /ko -->, returns: <!-- /ko --><!-- /ko -->
1759
+ var childNode = node.firstChild, captureRemaining = null;
1760
+ if (childNode) {
1761
+ do {
1762
+ if (captureRemaining) // We already hit an unbalanced node and are now just scooping up all subsequent nodes
1763
+ captureRemaining.push(childNode);
1764
+ else if (isStartComment(childNode)) {
1765
+ var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
1766
+ if (matchingEndComment) // It's a balanced tag, so skip immediately to the end of this virtual set
1767
+ childNode = matchingEndComment;
1768
+ else
1769
+ captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
1770
+ } else if (isEndComment(childNode)) {
1771
+ captureRemaining = [childNode]; // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
1772
+ }
1773
+ } while (childNode = childNode.nextSibling);
1774
+ }
1775
+ return captureRemaining;
1776
+ }
1777
+
1778
+ ko.virtualElements = {
1779
+ allowedBindings: {},
1780
+
1781
+ childNodes: function(node) {
1782
+ return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
1783
+ },
1784
+
1785
+ emptyNode: function(node) {
1786
+ if (!isStartComment(node))
1787
+ ko.utils.emptyDomNode(node);
1788
+ else {
1789
+ var virtualChildren = ko.virtualElements.childNodes(node);
1790
+ for (var i = 0, j = virtualChildren.length; i < j; i++)
1791
+ ko.removeNode(virtualChildren[i]);
1792
+ }
1793
+ },
1794
+
1795
+ setDomNodeChildren: function(node, childNodes) {
1796
+ if (!isStartComment(node))
1797
+ ko.utils.setDomNodeChildren(node, childNodes);
1798
+ else {
1799
+ ko.virtualElements.emptyNode(node);
1800
+ var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
1801
+ for (var i = 0, j = childNodes.length; i < j; i++)
1802
+ endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
1803
+ }
1804
+ },
1805
+
1806
+ prepend: function(containerNode, nodeToPrepend) {
1807
+ if (!isStartComment(containerNode)) {
1808
+ if (containerNode.firstChild)
1809
+ containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
1810
+ else
1811
+ containerNode.appendChild(nodeToPrepend);
1812
+ } else {
1813
+ // Start comments must always have a parent and at least one following sibling (the end comment)
1814
+ containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
1815
+ }
1816
+ },
1817
+
1818
+ insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
1819
+ if (!insertAfterNode) {
1820
+ ko.virtualElements.prepend(containerNode, nodeToInsert);
1821
+ } else if (!isStartComment(containerNode)) {
1822
+ // Insert after insertion point
1823
+ if (insertAfterNode.nextSibling)
1824
+ containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
1825
+ else
1826
+ containerNode.appendChild(nodeToInsert);
1827
+ } else {
1828
+ // Children of start comments must always have a parent and at least one following sibling (the end comment)
1829
+ containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
1830
+ }
1831
+ },
1832
+
1833
+ firstChild: function(node) {
1834
+ if (!isStartComment(node))
1835
+ return node.firstChild;
1836
+ if (!node.nextSibling || isEndComment(node.nextSibling))
1837
+ return null;
1838
+ return node.nextSibling;
1839
+ },
1840
+
1841
+ nextSibling: function(node) {
1842
+ if (isStartComment(node))
1843
+ node = getMatchingEndComment(node);
1844
+ if (node.nextSibling && isEndComment(node.nextSibling))
1845
+ return null;
1846
+ return node.nextSibling;
1847
+ },
1848
+
1849
+ virtualNodeBindingValue: function(node) {
1850
+ var regexMatch = isStartComment(node);
1851
+ return regexMatch ? regexMatch[1] : null;
1852
+ },
1853
+
1854
+ normaliseVirtualElementDomStructure: function(elementVerified) {
1855
+ // Workaround for https://github.com/SteveSanderson/knockout/issues/155
1856
+ // (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
1857
+ // that are direct descendants of <ul> into the preceding <li>)
1858
+ if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
1859
+ return;
1860
+
1861
+ // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
1862
+ // must be intended to appear *after* that child, so move them there.
1863
+ var childNode = elementVerified.firstChild;
1864
+ if (childNode) {
1865
+ do {
1866
+ if (childNode.nodeType === 1) {
1867
+ var unbalancedTags = getUnbalancedChildTags(childNode);
1868
+ if (unbalancedTags) {
1869
+ // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
1870
+ var nodeToInsertBefore = childNode.nextSibling;
1871
+ for (var i = 0; i < unbalancedTags.length; i++) {
1872
+ if (nodeToInsertBefore)
1873
+ elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
1874
+ else
1875
+ elementVerified.appendChild(unbalancedTags[i]);
1876
+ }
1877
+ }
1878
+ }
1879
+ } while (childNode = childNode.nextSibling);
1880
+ }
1881
+ }
1882
+ };
1883
+ })();
1884
+ ko.exportSymbol('virtualElements', ko.virtualElements);
1885
+ ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
1886
+ ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
1887
+ //ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild); // firstChild is not minified
1888
+ ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
1889
+ //ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling); // nextSibling is not minified
1890
+ ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
1891
+ ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
1892
+ (function() {
1893
+ var defaultBindingAttributeName = "data-bind";
1894
+
1895
+ ko.bindingProvider = function() {
1896
+ this.bindingCache = {};
1897
+ };
1898
+
1899
+ ko.utils.extend(ko.bindingProvider.prototype, {
1900
+ 'nodeHasBindings': function(node) {
1901
+ switch (node.nodeType) {
1902
+ case 1: return node.getAttribute(defaultBindingAttributeName) != null; // Element
1903
+ case 8: return ko.virtualElements.virtualNodeBindingValue(node) != null; // Comment node
1904
+ default: return false;
1905
+ }
1906
+ },
1907
+
1908
+ 'getBindings': function(node, bindingContext) {
1909
+ var bindingsString = this['getBindingsString'](node, bindingContext);
1910
+ return bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
1911
+ },
1912
+
1913
+ // The following function is only used internally by this default provider.
1914
+ // It's not part of the interface definition for a general binding provider.
1915
+ 'getBindingsString': function(node, bindingContext) {
1916
+ switch (node.nodeType) {
1917
+ case 1: return node.getAttribute(defaultBindingAttributeName); // Element
1918
+ case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
1919
+ default: return null;
1920
+ }
1921
+ },
1922
+
1923
+ // The following function is only used internally by this default provider.
1924
+ // It's not part of the interface definition for a general binding provider.
1925
+ 'parseBindingsString': function(bindingsString, bindingContext, node) {
1926
+ try {
1927
+ var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache);
1928
+ return bindingFunction(bindingContext, node);
1929
+ } catch (ex) {
1930
+ throw new Error("Unable to parse bindings.\nMessage: " + ex + ";\nBindings value: " + bindingsString);
1931
+ }
1932
+ }
1933
+ });
1934
+
1935
+ ko.bindingProvider['instance'] = new ko.bindingProvider();
1936
+
1937
+ function createBindingsStringEvaluatorViaCache(bindingsString, cache) {
1938
+ var cacheKey = bindingsString;
1939
+ return cache[cacheKey]
1940
+ || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString));
1941
+ }
1942
+
1943
+ function createBindingsStringEvaluator(bindingsString) {
1944
+ // Build the source for a function that evaluates "expression"
1945
+ // For each scope variable, add an extra level of "with" nesting
1946
+ // Example result: with(sc1) { with(sc0) { return (expression) } }
1947
+ var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString),
1948
+ functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
1949
+ return new Function("$context", "$element", functionBody);
1950
+ }
1951
+ })();
1952
+
1953
+ ko.exportSymbol('bindingProvider', ko.bindingProvider);
1954
+ (function () {
1955
+ ko.bindingHandlers = {};
1956
+
1957
+ ko.bindingContext = function(dataItem, parentBindingContext, dataItemAlias) {
1958
+ if (parentBindingContext) {
1959
+ ko.utils.extend(this, parentBindingContext); // Inherit $root and any custom properties
1960
+ this['$parentContext'] = parentBindingContext;
1961
+ this['$parent'] = parentBindingContext['$data'];
1962
+ this['$parents'] = (parentBindingContext['$parents'] || []).slice(0);
1963
+ this['$parents'].unshift(this['$parent']);
1964
+ } else {
1965
+ this['$parents'] = [];
1966
+ this['$root'] = dataItem;
1967
+ // Export 'ko' in the binding context so it will be available in bindings and templates
1968
+ // even if 'ko' isn't exported as a global, such as when using an AMD loader.
1969
+ // See https://github.com/SteveSanderson/knockout/issues/490
1970
+ this['ko'] = ko;
1971
+ }
1972
+ this['$data'] = dataItem;
1973
+ if (dataItemAlias)
1974
+ this[dataItemAlias] = dataItem;
1975
+ }
1976
+ ko.bindingContext.prototype['createChildContext'] = function (dataItem, dataItemAlias) {
1977
+ return new ko.bindingContext(dataItem, this, dataItemAlias);
1978
+ };
1979
+ ko.bindingContext.prototype['extend'] = function(properties) {
1980
+ var clone = ko.utils.extend(new ko.bindingContext(), this);
1981
+ return ko.utils.extend(clone, properties);
1982
+ };
1983
+
1984
+ function validateThatBindingIsAllowedForVirtualElements(bindingName) {
1985
+ var validator = ko.virtualElements.allowedBindings[bindingName];
1986
+ if (!validator)
1987
+ throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
1988
+ }
1989
+
1990
+ function applyBindingsToDescendantsInternal (viewModel, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
1991
+ var currentChild, nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
1992
+ while (currentChild = nextInQueue) {
1993
+ // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
1994
+ nextInQueue = ko.virtualElements.nextSibling(currentChild);
1995
+ applyBindingsToNodeAndDescendantsInternal(viewModel, currentChild, bindingContextsMayDifferFromDomParentElement);
1996
+ }
1997
+ }
1998
+
1999
+ function applyBindingsToNodeAndDescendantsInternal (viewModel, nodeVerified, bindingContextMayDifferFromDomParentElement) {
2000
+ var shouldBindDescendants = true;
2001
+
2002
+ // Perf optimisation: Apply bindings only if...
2003
+ // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
2004
+ // Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
2005
+ // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
2006
+ var isElement = (nodeVerified.nodeType === 1);
2007
+ if (isElement) // Workaround IE <= 8 HTML parsing weirdness
2008
+ ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
2009
+
2010
+ var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement) // Case (1)
2011
+ || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified); // Case (2)
2012
+ if (shouldApplyBindings)
2013
+ shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, viewModel, bindingContextMayDifferFromDomParentElement).shouldBindDescendants;
2014
+
2015
+ if (shouldBindDescendants) {
2016
+ // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
2017
+ // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
2018
+ // hence bindingContextsMayDifferFromDomParentElement is false
2019
+ // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
2020
+ // skip over any number of intermediate virtual elements, any of which might define a custom binding context,
2021
+ // hence bindingContextsMayDifferFromDomParentElement is true
2022
+ applyBindingsToDescendantsInternal(viewModel, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
2023
+ }
2024
+ }
2025
+
2026
+ function applyBindingsToNodeInternal (node, bindings, viewModelOrBindingContext, bindingContextMayDifferFromDomParentElement) {
2027
+ // Need to be sure that inits are only run once, and updates never run until all the inits have been run
2028
+ var initPhase = 0; // 0 = before all inits, 1 = during inits, 2 = after all inits
2029
+
2030
+ // Each time the dependentObservable is evaluated (after data changes),
2031
+ // the binding attribute is reparsed so that it can pick out the correct
2032
+ // model properties in the context of the changed data.
2033
+ // DOM event callbacks need to be able to access this changed data,
2034
+ // so we need a single parsedBindings variable (shared by all callbacks
2035
+ // associated with this node's bindings) that all the closures can access.
2036
+ var parsedBindings;
2037
+ function makeValueAccessor(bindingKey) {
2038
+ return function () { return parsedBindings[bindingKey] }
2039
+ }
2040
+ function parsedBindingsAccessor() {
2041
+ return parsedBindings;
2042
+ }
2043
+
2044
+ var bindingHandlerThatControlsDescendantBindings;
2045
+ ko.dependentObservable(
2046
+ function () {
2047
+ // Ensure we have a nonnull binding context to work with
2048
+ var bindingContextInstance = viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
2049
+ ? viewModelOrBindingContext
2050
+ : new ko.bindingContext(ko.utils.unwrapObservable(viewModelOrBindingContext));
2051
+ var viewModel = bindingContextInstance['$data'];
2052
+
2053
+ // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
2054
+ // we can easily recover it just by scanning up the node's ancestors in the DOM
2055
+ // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
2056
+ if (bindingContextMayDifferFromDomParentElement)
2057
+ ko.storedBindingContextForNode(node, bindingContextInstance);
2058
+
2059
+ // Use evaluatedBindings if given, otherwise fall back on asking the bindings provider to give us some bindings
2060
+ var evaluatedBindings = (typeof bindings == "function") ? bindings(bindingContextInstance, node) : bindings;
2061
+ parsedBindings = evaluatedBindings || ko.bindingProvider['instance']['getBindings'](node, bindingContextInstance);
2062
+
2063
+ if (parsedBindings) {
2064
+ // First run all the inits, so bindings can register for notification on changes
2065
+ if (initPhase === 0) {
2066
+ initPhase = 1;
2067
+ for (var bindingKey in parsedBindings) {
2068
+ var binding = ko.bindingHandlers[bindingKey];
2069
+ if (binding && node.nodeType === 8)
2070
+ validateThatBindingIsAllowedForVirtualElements(bindingKey);
2071
+
2072
+ if (binding && typeof binding["init"] == "function") {
2073
+ var handlerInitFn = binding["init"];
2074
+ var initResult = handlerInitFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
2075
+
2076
+ // If this binding handler claims to control descendant bindings, make a note of this
2077
+ if (initResult && initResult['controlsDescendantBindings']) {
2078
+ if (bindingHandlerThatControlsDescendantBindings !== undefined)
2079
+ 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.");
2080
+ bindingHandlerThatControlsDescendantBindings = bindingKey;
2081
+ }
2082
+ }
2083
+ }
2084
+ initPhase = 2;
2085
+ }
2086
+
2087
+ // ... then run all the updates, which might trigger changes even on the first evaluation
2088
+ if (initPhase === 2) {
2089
+ for (var bindingKey in parsedBindings) {
2090
+ var binding = ko.bindingHandlers[bindingKey];
2091
+ if (binding && typeof binding["update"] == "function") {
2092
+ var handlerUpdateFn = binding["update"];
2093
+ handlerUpdateFn(node, makeValueAccessor(bindingKey), parsedBindingsAccessor, viewModel, bindingContextInstance);
2094
+ }
2095
+ }
2096
+ }
2097
+ }
2098
+ },
2099
+ null,
2100
+ { disposeWhenNodeIsRemoved : node }
2101
+ );
2102
+
2103
+ return {
2104
+ shouldBindDescendants: bindingHandlerThatControlsDescendantBindings === undefined
2105
+ };
2106
+ };
2107
+
2108
+ var storedBindingContextDomDataKey = "__ko_bindingContext__";
2109
+ ko.storedBindingContextForNode = function (node, bindingContext) {
2110
+ if (arguments.length == 2)
2111
+ ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
2112
+ else
2113
+ return ko.utils.domData.get(node, storedBindingContextDomDataKey);
2114
+ }
2115
+
2116
+ ko.applyBindingsToNode = function (node, bindings, viewModel) {
2117
+ if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
2118
+ ko.virtualElements.normaliseVirtualElementDomStructure(node);
2119
+ return applyBindingsToNodeInternal(node, bindings, viewModel, true);
2120
+ };
2121
+
2122
+ ko.applyBindingsToDescendants = function(viewModel, rootNode) {
2123
+ if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
2124
+ applyBindingsToDescendantsInternal(viewModel, rootNode, true);
2125
+ };
2126
+
2127
+ ko.applyBindings = function (viewModel, rootNode) {
2128
+ if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
2129
+ throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
2130
+ rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
2131
+
2132
+ applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
2133
+ };
2134
+
2135
+ // Retrieving binding context from arbitrary nodes
2136
+ ko.contextFor = function(node) {
2137
+ // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
2138
+ switch (node.nodeType) {
2139
+ case 1:
2140
+ case 8:
2141
+ var context = ko.storedBindingContextForNode(node);
2142
+ if (context) return context;
2143
+ if (node.parentNode) return ko.contextFor(node.parentNode);
2144
+ break;
2145
+ }
2146
+ return undefined;
2147
+ };
2148
+ ko.dataFor = function(node) {
2149
+ var context = ko.contextFor(node);
2150
+ return context ? context['$data'] : undefined;
2151
+ };
2152
+
2153
+ ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
2154
+ ko.exportSymbol('applyBindings', ko.applyBindings);
2155
+ ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
2156
+ ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
2157
+ ko.exportSymbol('contextFor', ko.contextFor);
2158
+ ko.exportSymbol('dataFor', ko.dataFor);
2159
+ })();
2160
+ var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
2161
+ ko.bindingHandlers['attr'] = {
2162
+ 'update': function(element, valueAccessor, allBindingsAccessor) {
2163
+ var value = ko.utils.unwrapObservable(valueAccessor()) || {};
2164
+ for (var attrName in value) {
2165
+ if (typeof attrName == "string") {
2166
+ var attrValue = ko.utils.unwrapObservable(value[attrName]);
2167
+
2168
+ // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
2169
+ // when someProp is a "no value"-like value (strictly null, false, or undefined)
2170
+ // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
2171
+ var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
2172
+ if (toRemove)
2173
+ element.removeAttribute(attrName);
2174
+
2175
+ // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
2176
+ // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
2177
+ // but instead of figuring out the mode, we'll just set the attribute through the Javascript
2178
+ // property for IE <= 8.
2179
+ if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
2180
+ attrName = attrHtmlToJavascriptMap[attrName];
2181
+ if (toRemove)
2182
+ element.removeAttribute(attrName);
2183
+ else
2184
+ element[attrName] = attrValue;
2185
+ } else if (!toRemove) {
2186
+ element.setAttribute(attrName, attrValue.toString());
2187
+ }
2188
+
2189
+ // Treat "name" specially - although you can think of it as an attribute, it also needs
2190
+ // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
2191
+ // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
2192
+ // entirely, and there's no strong reason to allow for such casing in HTML.
2193
+ if (attrName === "name") {
2194
+ ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
2195
+ }
2196
+ }
2197
+ }
2198
+ }
2199
+ };
2200
+ ko.bindingHandlers['checked'] = {
2201
+ 'init': function (element, valueAccessor, allBindingsAccessor) {
2202
+ var updateHandler = function() {
2203
+ var valueToWrite;
2204
+ if (element.type == "checkbox") {
2205
+ valueToWrite = element.checked;
2206
+ } else if ((element.type == "radio") && (element.checked)) {
2207
+ valueToWrite = element.value;
2208
+ } else {
2209
+ return; // "checked" binding only responds to checkboxes and selected radio buttons
2210
+ }
2211
+
2212
+ var modelValue = valueAccessor(), unwrappedValue = ko.utils.unwrapObservable(modelValue);
2213
+ if ((element.type == "checkbox") && (unwrappedValue instanceof Array)) {
2214
+ // For checkboxes bound to an array, we add/remove the checkbox value to that array
2215
+ // This works for both observable and non-observable arrays
2216
+ var existingEntryIndex = ko.utils.arrayIndexOf(unwrappedValue, element.value);
2217
+ if (element.checked && (existingEntryIndex < 0))
2218
+ modelValue.push(element.value);
2219
+ else if ((!element.checked) && (existingEntryIndex >= 0))
2220
+ modelValue.splice(existingEntryIndex, 1);
2221
+ } else {
2222
+ ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'checked', valueToWrite, true);
2223
+ }
2224
+ };
2225
+ ko.utils.registerEventHandler(element, "click", updateHandler);
2226
+
2227
+ // IE 6 won't allow radio buttons to be selected unless they have a name
2228
+ if ((element.type == "radio") && !element.name)
2229
+ ko.bindingHandlers['uniqueName']['init'](element, function() { return true });
2230
+ },
2231
+ 'update': function (element, valueAccessor) {
2232
+ var value = ko.utils.unwrapObservable(valueAccessor());
2233
+
2234
+ if (element.type == "checkbox") {
2235
+ if (value instanceof Array) {
2236
+ // When bound to an array, the checkbox being checked represents its value being present in that array
2237
+ element.checked = ko.utils.arrayIndexOf(value, element.value) >= 0;
2238
+ } else {
2239
+ // When bound to anything other value (not an array), the checkbox being checked represents the value being trueish
2240
+ element.checked = value;
2241
+ }
2242
+ } else if (element.type == "radio") {
2243
+ element.checked = (element.value == value);
2244
+ }
2245
+ }
2246
+ };
2247
+ var classesWrittenByBindingKey = '__ko__cssValue';
2248
+ ko.bindingHandlers['css'] = {
2249
+ 'update': function (element, valueAccessor) {
2250
+ var value = ko.utils.unwrapObservable(valueAccessor());
2251
+ if (typeof value == "object") {
2252
+ for (var className in value) {
2253
+ var shouldHaveClass = ko.utils.unwrapObservable(value[className]);
2254
+ ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
2255
+ }
2256
+ } else {
2257
+ value = String(value || ''); // Make sure we don't try to store or set a non-string value
2258
+ ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
2259
+ element[classesWrittenByBindingKey] = value;
2260
+ ko.utils.toggleDomNodeCssClass(element, value, true);
2261
+ }
2262
+ }
2263
+ };
2264
+ ko.bindingHandlers['enable'] = {
2265
+ 'update': function (element, valueAccessor) {
2266
+ var value = ko.utils.unwrapObservable(valueAccessor());
2267
+ if (value && element.disabled)
2268
+ element.removeAttribute("disabled");
2269
+ else if ((!value) && (!element.disabled))
2270
+ element.disabled = true;
2271
+ }
2272
+ };
2273
+
2274
+ ko.bindingHandlers['disable'] = {
2275
+ 'update': function (element, valueAccessor) {
2276
+ ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
2277
+ }
2278
+ };
2279
+ // For certain common events (currently just 'click'), allow a simplified data-binding syntax
2280
+ // e.g. click:handler instead of the usual full-length event:{click:handler}
2281
+ function makeEventHandlerShortcut(eventName) {
2282
+ ko.bindingHandlers[eventName] = {
2283
+ 'init': function(element, valueAccessor, allBindingsAccessor, viewModel) {
2284
+ var newValueAccessor = function () {
2285
+ var result = {};
2286
+ result[eventName] = valueAccessor();
2287
+ return result;
2288
+ };
2289
+ return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindingsAccessor, viewModel);
2290
+ }
2291
+ }
2292
+ }
2293
+
2294
+ ko.bindingHandlers['event'] = {
2295
+ 'init' : function (element, valueAccessor, allBindingsAccessor, viewModel) {
2296
+ var eventsToHandle = valueAccessor() || {};
2297
+ for(var eventNameOutsideClosure in eventsToHandle) {
2298
+ (function() {
2299
+ var eventName = eventNameOutsideClosure; // Separate variable to be captured by event handler closure
2300
+ if (typeof eventName == "string") {
2301
+ ko.utils.registerEventHandler(element, eventName, function (event) {
2302
+ var handlerReturnValue;
2303
+ var handlerFunction = valueAccessor()[eventName];
2304
+ if (!handlerFunction)
2305
+ return;
2306
+ var allBindings = allBindingsAccessor();
2307
+
2308
+ try {
2309
+ // Take all the event args, and prefix with the viewmodel
2310
+ var argsForHandler = ko.utils.makeArray(arguments);
2311
+ argsForHandler.unshift(viewModel);
2312
+ handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
2313
+ } finally {
2314
+ if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
2315
+ if (event.preventDefault)
2316
+ event.preventDefault();
2317
+ else
2318
+ event.returnValue = false;
2319
+ }
2320
+ }
2321
+
2322
+ var bubble = allBindings[eventName + 'Bubble'] !== false;
2323
+ if (!bubble) {
2324
+ event.cancelBubble = true;
2325
+ if (event.stopPropagation)
2326
+ event.stopPropagation();
2327
+ }
2328
+ });
2329
+ }
2330
+ })();
2331
+ }
2332
+ }
2333
+ };
2334
+ // "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
2335
+ // "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
2336
+ ko.bindingHandlers['foreach'] = {
2337
+ makeTemplateValueAccessor: function(valueAccessor) {
2338
+ return function() {
2339
+ var modelValue = valueAccessor(),
2340
+ unwrappedValue = ko.utils.peekObservable(modelValue); // Unwrap without setting a dependency here
2341
+
2342
+ // If unwrappedValue is the array, pass in the wrapped value on its own
2343
+ // The value will be unwrapped and tracked within the template binding
2344
+ // (See https://github.com/SteveSanderson/knockout/issues/523)
2345
+ if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
2346
+ return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };
2347
+
2348
+ // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
2349
+ ko.utils.unwrapObservable(modelValue);
2350
+ return {
2351
+ 'foreach': unwrappedValue['data'],
2352
+ 'as': unwrappedValue['as'],
2353
+ 'includeDestroyed': unwrappedValue['includeDestroyed'],
2354
+ 'afterAdd': unwrappedValue['afterAdd'],
2355
+ 'beforeRemove': unwrappedValue['beforeRemove'],
2356
+ 'afterRender': unwrappedValue['afterRender'],
2357
+ 'beforeMove': unwrappedValue['beforeMove'],
2358
+ 'afterMove': unwrappedValue['afterMove'],
2359
+ 'templateEngine': ko.nativeTemplateEngine.instance
2360
+ };
2361
+ };
2362
+ },
2363
+ 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
2364
+ return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
2365
+ },
2366
+ 'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
2367
+ return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindingsAccessor, viewModel, bindingContext);
2368
+ }
2369
+ };
2370
+ ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
2371
+ ko.virtualElements.allowedBindings['foreach'] = true;
2372
+ var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
2373
+ ko.bindingHandlers['hasfocus'] = {
2374
+ 'init': function(element, valueAccessor, allBindingsAccessor) {
2375
+ var handleElementFocusChange = function(isFocused) {
2376
+ // Where possible, ignore which event was raised and determine focus state using activeElement,
2377
+ // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
2378
+ // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
2379
+ // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
2380
+ // from calling 'blur()' on the element when it loses focus.
2381
+ // Discussion at https://github.com/SteveSanderson/knockout/pull/352
2382
+ element[hasfocusUpdatingProperty] = true;
2383
+ var ownerDoc = element.ownerDocument;
2384
+ if ("activeElement" in ownerDoc) {
2385
+ isFocused = (ownerDoc.activeElement === element);
2386
+ }
2387
+ var modelValue = valueAccessor();
2388
+ ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'hasfocus', isFocused, true);
2389
+ element[hasfocusUpdatingProperty] = false;
2390
+ };
2391
+ var handleElementFocusIn = handleElementFocusChange.bind(null, true);
2392
+ var handleElementFocusOut = handleElementFocusChange.bind(null, false);
2393
+
2394
+ ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
2395
+ ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
2396
+ ko.utils.registerEventHandler(element, "blur", handleElementFocusOut);
2397
+ ko.utils.registerEventHandler(element, "focusout", handleElementFocusOut); // For IE
2398
+ },
2399
+ 'update': function(element, valueAccessor) {
2400
+ var value = ko.utils.unwrapObservable(valueAccessor());
2401
+ if (!element[hasfocusUpdatingProperty]) {
2402
+ value ? element.focus() : element.blur();
2403
+ ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]); // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
2404
+ }
2405
+ }
2406
+ };
2407
+ ko.bindingHandlers['html'] = {
2408
+ 'init': function() {
2409
+ // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
2410
+ return { 'controlsDescendantBindings': true };
2411
+ },
2412
+ 'update': function (element, valueAccessor) {
2413
+ // setHtml will unwrap the value if needed
2414
+ ko.utils.setHtml(element, valueAccessor());
2415
+ }
2416
+ };
2417
+ var withIfDomDataKey = '__ko_withIfBindingData';
2418
+ // Makes a binding like with or if
2419
+ function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
2420
+ ko.bindingHandlers[bindingKey] = {
2421
+ 'init': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
2422
+ ko.utils.domData.set(element, withIfDomDataKey, {});
2423
+ return { 'controlsDescendantBindings': true };
2424
+ },
2425
+ 'update': function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
2426
+ var withIfData = ko.utils.domData.get(element, withIfDomDataKey),
2427
+ dataValue = ko.utils.unwrapObservable(valueAccessor()),
2428
+ shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
2429
+ isFirstRender = !withIfData.savedNodes,
2430
+ needsRefresh = isFirstRender || isWith || (shouldDisplay !== withIfData.didDisplayOnLastUpdate);
2431
+
2432
+ if (needsRefresh) {
2433
+ if (isFirstRender) {
2434
+ withIfData.savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
2435
+ }
2436
+
2437
+ if (shouldDisplay) {
2438
+ if (!isFirstRender) {
2439
+ ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(withIfData.savedNodes));
2440
+ }
2441
+ ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
2442
+ } else {
2443
+ ko.virtualElements.emptyNode(element);
2444
+ }
2445
+
2446
+ withIfData.didDisplayOnLastUpdate = shouldDisplay;
2447
+ }
2448
+ }
2449
+ };
2450
+ ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
2451
+ ko.virtualElements.allowedBindings[bindingKey] = true;
2452
+ }
2453
+
2454
+ // Construct the actual binding handlers
2455
+ makeWithIfBinding('if');
2456
+ makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
2457
+ makeWithIfBinding('with', true /* isWith */, false /* isNot */,
2458
+ function(bindingContext, dataValue) {
2459
+ return bindingContext['createChildContext'](dataValue);
2460
+ }
2461
+ );
2462
+ function ensureDropdownSelectionIsConsistentWithModelValue(element, modelValue, preferModelValue) {
2463
+ if (preferModelValue) {
2464
+ if (modelValue !== ko.selectExtensions.readValue(element))
2465
+ ko.selectExtensions.writeValue(element, modelValue);
2466
+ }
2467
+
2468
+ // No matter which direction we're syncing in, we want the end result to be equality between dropdown value and model value.
2469
+ // If they aren't equal, either we prefer the dropdown value, or the model value couldn't be represented, so either way,
2470
+ // change the model value to match the dropdown.
2471
+ if (modelValue !== ko.selectExtensions.readValue(element))
2472
+ ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
2473
+ };
2474
+
2475
+ ko.bindingHandlers['options'] = {
2476
+ 'update': function (element, valueAccessor, allBindingsAccessor) {
2477
+ if (ko.utils.tagNameLower(element) !== "select")
2478
+ throw new Error("options binding applies only to SELECT elements");
2479
+
2480
+ var selectWasPreviouslyEmpty = element.length == 0;
2481
+ var previousSelectedValues = ko.utils.arrayMap(ko.utils.arrayFilter(element.childNodes, function (node) {
2482
+ return node.tagName && (ko.utils.tagNameLower(node) === "option") && node.selected;
2483
+ }), function (node) {
2484
+ return ko.selectExtensions.readValue(node) || node.innerText || node.textContent;
2485
+ });
2486
+ var previousScrollTop = element.scrollTop;
2487
+
2488
+ var value = ko.utils.unwrapObservable(valueAccessor());
2489
+ var selectedValue = element.value;
2490
+
2491
+ // Remove all existing <option>s.
2492
+ // Need to use .remove() rather than .removeChild() for <option>s otherwise IE behaves oddly (https://github.com/SteveSanderson/knockout/issues/134)
2493
+ while (element.length > 0) {
2494
+ ko.cleanNode(element.options[0]);
2495
+ element.remove(0);
2496
+ }
2497
+
2498
+ if (value) {
2499
+ var allBindings = allBindingsAccessor(),
2500
+ includeDestroyed = allBindings['optionsIncludeDestroyed'];
2501
+
2502
+ if (typeof value.length != "number")
2503
+ value = [value];
2504
+ if (allBindings['optionsCaption']) {
2505
+ var option = document.createElement("option");
2506
+ ko.utils.setHtml(option, allBindings['optionsCaption']);
2507
+ ko.selectExtensions.writeValue(option, undefined);
2508
+ element.appendChild(option);
2509
+ }
2510
+
2511
+ for (var i = 0, j = value.length; i < j; i++) {
2512
+ // Skip destroyed items
2513
+ var arrayEntry = value[i];
2514
+ if (arrayEntry && arrayEntry['_destroy'] && !includeDestroyed)
2515
+ continue;
2516
+
2517
+ var option = document.createElement("option");
2518
+
2519
+ function applyToObject(object, predicate, defaultValue) {
2520
+ var predicateType = typeof predicate;
2521
+ if (predicateType == "function") // Given a function; run it against the data value
2522
+ return predicate(object);
2523
+ else if (predicateType == "string") // Given a string; treat it as a property name on the data value
2524
+ return object[predicate];
2525
+ else // Given no optionsText arg; use the data value itself
2526
+ return defaultValue;
2527
+ }
2528
+
2529
+ // Apply a value to the option element
2530
+ var optionValue = applyToObject(arrayEntry, allBindings['optionsValue'], arrayEntry);
2531
+ ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));
2532
+
2533
+ // Apply some text to the option element
2534
+ var optionText = applyToObject(arrayEntry, allBindings['optionsText'], optionValue);
2535
+ ko.utils.setTextContent(option, optionText);
2536
+
2537
+ element.appendChild(option);
2538
+ }
2539
+
2540
+ // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
2541
+ // That's why we first added them without selection. Now it's time to set the selection.
2542
+ var newOptions = element.getElementsByTagName("option");
2543
+ var countSelectionsRetained = 0;
2544
+ for (var i = 0, j = newOptions.length; i < j; i++) {
2545
+ if (ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[i])) >= 0) {
2546
+ ko.utils.setOptionNodeSelectionState(newOptions[i], true);
2547
+ countSelectionsRetained++;
2548
+ }
2549
+ }
2550
+
2551
+ element.scrollTop = previousScrollTop;
2552
+
2553
+ if (selectWasPreviouslyEmpty && ('value' in allBindings)) {
2554
+ // Ensure consistency between model value and selected option.
2555
+ // If the dropdown is being populated for the first time here (or was otherwise previously empty),
2556
+ // the dropdown selection state is meaningless, so we preserve the model value.
2557
+ ensureDropdownSelectionIsConsistentWithModelValue(element, ko.utils.peekObservable(allBindings['value']), /* preferModelValue */ true);
2558
+ }
2559
+
2560
+ // Workaround for IE9 bug
2561
+ ko.utils.ensureSelectElementIsRenderedCorrectly(element);
2562
+ }
2563
+ }
2564
+ };
2565
+ ko.bindingHandlers['options'].optionValueDomDataKey = '__ko.optionValueDomData__';
2566
+ ko.bindingHandlers['selectedOptions'] = {
2567
+ 'init': function (element, valueAccessor, allBindingsAccessor) {
2568
+ ko.utils.registerEventHandler(element, "change", function () {
2569
+ var value = valueAccessor(), valueToWrite = [];
2570
+ ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
2571
+ if (node.selected)
2572
+ valueToWrite.push(ko.selectExtensions.readValue(node));
2573
+ });
2574
+ ko.expressionRewriting.writeValueToProperty(value, allBindingsAccessor, 'value', valueToWrite);
2575
+ });
2576
+ },
2577
+ 'update': function (element, valueAccessor) {
2578
+ if (ko.utils.tagNameLower(element) != "select")
2579
+ throw new Error("values binding applies only to SELECT elements");
2580
+
2581
+ var newValue = ko.utils.unwrapObservable(valueAccessor());
2582
+ if (newValue && typeof newValue.length == "number") {
2583
+ ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
2584
+ var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
2585
+ ko.utils.setOptionNodeSelectionState(node, isSelected);
2586
+ });
2587
+ }
2588
+ }
2589
+ };
2590
+ ko.bindingHandlers['style'] = {
2591
+ 'update': function (element, valueAccessor) {
2592
+ var value = ko.utils.unwrapObservable(valueAccessor() || {});
2593
+ for (var styleName in value) {
2594
+ if (typeof styleName == "string") {
2595
+ var styleValue = ko.utils.unwrapObservable(value[styleName]);
2596
+ element.style[styleName] = styleValue || ""; // Empty string removes the value, whereas null/undefined have no effect
2597
+ }
2598
+ }
2599
+ }
2600
+ };
2601
+ ko.bindingHandlers['submit'] = {
2602
+ 'init': function (element, valueAccessor, allBindingsAccessor, viewModel) {
2603
+ if (typeof valueAccessor() != "function")
2604
+ throw new Error("The value for a submit binding must be a function");
2605
+ ko.utils.registerEventHandler(element, "submit", function (event) {
2606
+ var handlerReturnValue;
2607
+ var value = valueAccessor();
2608
+ try { handlerReturnValue = value.call(viewModel, element); }
2609
+ finally {
2610
+ if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
2611
+ if (event.preventDefault)
2612
+ event.preventDefault();
2613
+ else
2614
+ event.returnValue = false;
2615
+ }
2616
+ }
2617
+ });
2618
+ }
2619
+ };
2620
+ ko.bindingHandlers['text'] = {
2621
+ 'update': function (element, valueAccessor) {
2622
+ ko.utils.setTextContent(element, valueAccessor());
2623
+ }
2624
+ };
2625
+ ko.virtualElements.allowedBindings['text'] = true;
2626
+ ko.bindingHandlers['uniqueName'] = {
2627
+ 'init': function (element, valueAccessor) {
2628
+ if (valueAccessor()) {
2629
+ var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
2630
+ ko.utils.setElementName(element, name);
2631
+ }
2632
+ }
2633
+ };
2634
+ ko.bindingHandlers['uniqueName'].currentIndex = 0;
2635
+ ko.bindingHandlers['value'] = {
2636
+ 'init': function (element, valueAccessor, allBindingsAccessor) {
2637
+ // Always catch "change" event; possibly other events too if asked
2638
+ var eventsToCatch = ["change"];
2639
+ var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
2640
+ var propertyChangedFired = false;
2641
+ if (requestedEventsToCatch) {
2642
+ if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
2643
+ requestedEventsToCatch = [requestedEventsToCatch];
2644
+ ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
2645
+ eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
2646
+ }
2647
+
2648
+ var valueUpdateHandler = function() {
2649
+ propertyChangedFired = false;
2650
+ var modelValue = valueAccessor();
2651
+ var elementValue = ko.selectExtensions.readValue(element);
2652
+ ko.expressionRewriting.writeValueToProperty(modelValue, allBindingsAccessor, 'value', elementValue);
2653
+ }
2654
+
2655
+ // Workaround for https://github.com/SteveSanderson/knockout/issues/122
2656
+ // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
2657
+ var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
2658
+ && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
2659
+ if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
2660
+ ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
2661
+ ko.utils.registerEventHandler(element, "blur", function() {
2662
+ if (propertyChangedFired) {
2663
+ valueUpdateHandler();
2664
+ }
2665
+ });
2666
+ }
2667
+
2668
+ ko.utils.arrayForEach(eventsToCatch, function(eventName) {
2669
+ // The syntax "after<eventname>" means "run the handler asynchronously after the event"
2670
+ // This is useful, for example, to catch "keydown" events after the browser has updated the control
2671
+ // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
2672
+ var handler = valueUpdateHandler;
2673
+ if (ko.utils.stringStartsWith(eventName, "after")) {
2674
+ handler = function() { setTimeout(valueUpdateHandler, 0) };
2675
+ eventName = eventName.substring("after".length);
2676
+ }
2677
+ ko.utils.registerEventHandler(element, eventName, handler);
2678
+ });
2679
+ },
2680
+ 'update': function (element, valueAccessor) {
2681
+ var valueIsSelectOption = ko.utils.tagNameLower(element) === "select";
2682
+ var newValue = ko.utils.unwrapObservable(valueAccessor());
2683
+ var elementValue = ko.selectExtensions.readValue(element);
2684
+ var valueHasChanged = (newValue != elementValue);
2685
+
2686
+ // JavaScript's 0 == "" behavious is unfortunate here as it prevents writing 0 to an empty text box (loose equality suggests the values are the same).
2687
+ // We don't want to do a strict equality comparison as that is more confusing for developers in certain cases, so we specifically special case 0 != "" here.
2688
+ if ((newValue === 0) && (elementValue !== 0) && (elementValue !== "0"))
2689
+ valueHasChanged = true;
2690
+
2691
+ if (valueHasChanged) {
2692
+ var applyValueAction = function () { ko.selectExtensions.writeValue(element, newValue); };
2693
+ applyValueAction();
2694
+
2695
+ // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
2696
+ // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
2697
+ // to apply the value as well.
2698
+ var alsoApplyAsynchronously = valueIsSelectOption;
2699
+ if (alsoApplyAsynchronously)
2700
+ setTimeout(applyValueAction, 0);
2701
+ }
2702
+
2703
+ // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
2704
+ // because you're not allowed to have a model value that disagrees with a visible UI selection.
2705
+ if (valueIsSelectOption && (element.length > 0))
2706
+ ensureDropdownSelectionIsConsistentWithModelValue(element, newValue, /* preferModelValue */ false);
2707
+ }
2708
+ };
2709
+ ko.bindingHandlers['visible'] = {
2710
+ 'update': function (element, valueAccessor) {
2711
+ var value = ko.utils.unwrapObservable(valueAccessor());
2712
+ var isCurrentlyVisible = !(element.style.display == "none");
2713
+ if (value && !isCurrentlyVisible)
2714
+ element.style.display = "";
2715
+ else if ((!value) && isCurrentlyVisible)
2716
+ element.style.display = "none";
2717
+ }
2718
+ };
2719
+ // 'click' is just a shorthand for the usual full-length event:{click:handler}
2720
+ makeEventHandlerShortcut('click');
2721
+ // If you want to make a custom template engine,
2722
+ //
2723
+ // [1] Inherit from this class (like ko.nativeTemplateEngine does)
2724
+ // [2] Override 'renderTemplateSource', supplying a function with this signature:
2725
+ //
2726
+ // function (templateSource, bindingContext, options) {
2727
+ // // - templateSource.text() is the text of the template you should render
2728
+ // // - bindingContext.$data is the data you should pass into the template
2729
+ // // - you might also want to make bindingContext.$parent, bindingContext.$parents,
2730
+ // // and bindingContext.$root available in the template too
2731
+ // // - options gives you access to any other properties set on "data-bind: { template: options }"
2732
+ // //
2733
+ // // Return value: an array of DOM nodes
2734
+ // }
2735
+ //
2736
+ // [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
2737
+ //
2738
+ // function (script) {
2739
+ // // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
2740
+ // // For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
2741
+ // }
2742
+ //
2743
+ // This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
2744
+ // If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
2745
+ // and then you don't need to override 'createJavaScriptEvaluatorBlock'.
2746
+
2747
+ ko.templateEngine = function () { };
2748
+
2749
+ ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
2750
+ throw new Error("Override renderTemplateSource");
2751
+ };
2752
+
2753
+ ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
2754
+ throw new Error("Override createJavaScriptEvaluatorBlock");
2755
+ };
2756
+
2757
+ ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
2758
+ // Named template
2759
+ if (typeof template == "string") {
2760
+ templateDocument = templateDocument || document;
2761
+ var elem = templateDocument.getElementById(template);
2762
+ if (!elem)
2763
+ throw new Error("Cannot find template with ID " + template);
2764
+ return new ko.templateSources.domElement(elem);
2765
+ } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
2766
+ // Anonymous template
2767
+ return new ko.templateSources.anonymousTemplate(template);
2768
+ } else
2769
+ throw new Error("Unknown template type: " + template);
2770
+ };
2771
+
2772
+ ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
2773
+ var templateSource = this['makeTemplateSource'](template, templateDocument);
2774
+ return this['renderTemplateSource'](templateSource, bindingContext, options);
2775
+ };
2776
+
2777
+ ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
2778
+ // Skip rewriting if requested
2779
+ if (this['allowTemplateRewriting'] === false)
2780
+ return true;
2781
+ return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
2782
+ };
2783
+
2784
+ ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
2785
+ var templateSource = this['makeTemplateSource'](template, templateDocument);
2786
+ var rewritten = rewriterCallback(templateSource['text']());
2787
+ templateSource['text'](rewritten);
2788
+ templateSource['data']("isRewritten", true);
2789
+ };
2790
+
2791
+ ko.exportSymbol('templateEngine', ko.templateEngine);
2792
+
2793
+ ko.templateRewriting = (function () {
2794
+ var memoizeDataBindingAttributeSyntaxRegex = /(<[a-z]+\d*(\s+(?!data-bind=)[a-z0-9\-]+(=(\"[^\"]*\"|\'[^\']*\'))?)*\s+)data-bind=(["'])([\s\S]*?)\5/gi;
2795
+ var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;
2796
+
2797
+ function validateDataBindValuesForRewriting(keyValueArray) {
2798
+ var allValidators = ko.expressionRewriting.bindingRewriteValidators;
2799
+ for (var i = 0; i < keyValueArray.length; i++) {
2800
+ var key = keyValueArray[i]['key'];
2801
+ if (allValidators.hasOwnProperty(key)) {
2802
+ var validator = allValidators[key];
2803
+
2804
+ if (typeof validator === "function") {
2805
+ var possibleErrorMessage = validator(keyValueArray[i]['value']);
2806
+ if (possibleErrorMessage)
2807
+ throw new Error(possibleErrorMessage);
2808
+ } else if (!validator) {
2809
+ throw new Error("This template engine does not support the '" + key + "' binding within its templates");
2810
+ }
2811
+ }
2812
+ }
2813
+ }
2814
+
2815
+ function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, templateEngine) {
2816
+ var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
2817
+ validateDataBindValuesForRewriting(dataBindKeyValueArray);
2818
+ var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray);
2819
+
2820
+ // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
2821
+ // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
2822
+ // extra indirection.
2823
+ var applyBindingsToNextSiblingScript =
2824
+ "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()})";
2825
+ return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
2826
+ }
2827
+
2828
+ return {
2829
+ ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
2830
+ if (!templateEngine['isTemplateRewritten'](template, templateDocument))
2831
+ templateEngine['rewriteTemplate'](template, function (htmlString) {
2832
+ return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
2833
+ }, templateDocument);
2834
+ },
2835
+
2836
+ memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
2837
+ return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
2838
+ return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[6], /* tagToRetain: */ arguments[1], templateEngine);
2839
+ }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
2840
+ return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", templateEngine);
2841
+ });
2842
+ },
2843
+
2844
+ applyMemoizedBindingsToNextSibling: function (bindings) {
2845
+ return ko.memoization.memoize(function (domNode, bindingContext) {
2846
+ if (domNode.nextSibling)
2847
+ ko.applyBindingsToNode(domNode.nextSibling, bindings, bindingContext);
2848
+ });
2849
+ }
2850
+ }
2851
+ })();
2852
+
2853
+
2854
+ // Exported only because it has to be referenced by string lookup from within rewritten template
2855
+ ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
2856
+ (function() {
2857
+ // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
2858
+ // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
2859
+ //
2860
+ // Two are provided by default:
2861
+ // 1. ko.templateSources.domElement - reads/writes the text content of an arbitrary DOM element
2862
+ // 2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
2863
+ // without reading/writing the actual element text content, since it will be overwritten
2864
+ // with the rendered template output.
2865
+ // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
2866
+ // Template sources need to have the following functions:
2867
+ // text() - returns the template text from your storage location
2868
+ // text(value) - writes the supplied template text to your storage location
2869
+ // data(key) - reads values stored using data(key, value) - see below
2870
+ // data(key, value) - associates "value" with this template and the key "key". Is used to store information like "isRewritten".
2871
+ //
2872
+ // Optionally, template sources can also have the following functions:
2873
+ // nodes() - returns a DOM element containing the nodes of this template, where available
2874
+ // nodes(value) - writes the given DOM element to your storage location
2875
+ // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
2876
+ // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
2877
+ //
2878
+ // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
2879
+ // using and overriding "makeTemplateSource" to return an instance of your custom template source.
2880
+
2881
+ ko.templateSources = {};
2882
+
2883
+ // ---- ko.templateSources.domElement -----
2884
+
2885
+ ko.templateSources.domElement = function(element) {
2886
+ this.domElement = element;
2887
+ }
2888
+
2889
+ ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
2890
+ var tagNameLower = ko.utils.tagNameLower(this.domElement),
2891
+ elemContentsProperty = tagNameLower === "script" ? "text"
2892
+ : tagNameLower === "textarea" ? "value"
2893
+ : "innerHTML";
2894
+
2895
+ if (arguments.length == 0) {
2896
+ return this.domElement[elemContentsProperty];
2897
+ } else {
2898
+ var valueToWrite = arguments[0];
2899
+ if (elemContentsProperty === "innerHTML")
2900
+ ko.utils.setHtml(this.domElement, valueToWrite);
2901
+ else
2902
+ this.domElement[elemContentsProperty] = valueToWrite;
2903
+ }
2904
+ };
2905
+
2906
+ ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
2907
+ if (arguments.length === 1) {
2908
+ return ko.utils.domData.get(this.domElement, "templateSourceData_" + key);
2909
+ } else {
2910
+ ko.utils.domData.set(this.domElement, "templateSourceData_" + key, arguments[1]);
2911
+ }
2912
+ };
2913
+
2914
+ // ---- ko.templateSources.anonymousTemplate -----
2915
+ // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
2916
+ // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
2917
+ // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.
2918
+
2919
+ var anonymousTemplatesDomDataKey = "__ko_anon_template__";
2920
+ ko.templateSources.anonymousTemplate = function(element) {
2921
+ this.domElement = element;
2922
+ }
2923
+ ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
2924
+ ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
2925
+ if (arguments.length == 0) {
2926
+ var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
2927
+ if (templateData.textData === undefined && templateData.containerData)
2928
+ templateData.textData = templateData.containerData.innerHTML;
2929
+ return templateData.textData;
2930
+ } else {
2931
+ var valueToWrite = arguments[0];
2932
+ ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {textData: valueToWrite});
2933
+ }
2934
+ };
2935
+ ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
2936
+ if (arguments.length == 0) {
2937
+ var templateData = ko.utils.domData.get(this.domElement, anonymousTemplatesDomDataKey) || {};
2938
+ return templateData.containerData;
2939
+ } else {
2940
+ var valueToWrite = arguments[0];
2941
+ ko.utils.domData.set(this.domElement, anonymousTemplatesDomDataKey, {containerData: valueToWrite});
2942
+ }
2943
+ };
2944
+
2945
+ ko.exportSymbol('templateSources', ko.templateSources);
2946
+ ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
2947
+ ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
2948
+ })();
2949
+ (function () {
2950
+ var _templateEngine;
2951
+ ko.setTemplateEngine = function (templateEngine) {
2952
+ if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
2953
+ throw new Error("templateEngine must inherit from ko.templateEngine");
2954
+ _templateEngine = templateEngine;
2955
+ }
2956
+
2957
+ function invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, action) {
2958
+ var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
2959
+ while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
2960
+ nextInQueue = ko.virtualElements.nextSibling(node);
2961
+ if (node.nodeType === 1 || node.nodeType === 8)
2962
+ action(node);
2963
+ }
2964
+ }
2965
+
2966
+ function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
2967
+ // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
2968
+ // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
2969
+ // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
2970
+ // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
2971
+ // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)
2972
+
2973
+ if (continuousNodeArray.length) {
2974
+ var firstNode = continuousNodeArray[0], lastNode = continuousNodeArray[continuousNodeArray.length - 1];
2975
+
2976
+ // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
2977
+ // whereas a regular applyBindings won't introduce new memoized nodes
2978
+ invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
2979
+ ko.applyBindings(bindingContext, node);
2980
+ });
2981
+ invokeForEachNodeOrCommentInContinuousRange(firstNode, lastNode, function(node) {
2982
+ ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
2983
+ });
2984
+ }
2985
+ }
2986
+
2987
+ function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
2988
+ return nodeOrNodeArray.nodeType ? nodeOrNodeArray
2989
+ : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
2990
+ : null;
2991
+ }
2992
+
2993
+ function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
2994
+ options = options || {};
2995
+ var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
2996
+ var templateDocument = firstTargetNode && firstTargetNode.ownerDocument;
2997
+ var templateEngineToUse = (options['templateEngine'] || _templateEngine);
2998
+ ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
2999
+ var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);
3000
+
3001
+ // Loosely check result is an array of DOM nodes
3002
+ if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
3003
+ throw new Error("Template engine must return an array of DOM nodes");
3004
+
3005
+ var haveAddedNodesToParent = false;
3006
+ switch (renderMode) {
3007
+ case "replaceChildren":
3008
+ ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
3009
+ haveAddedNodesToParent = true;
3010
+ break;
3011
+ case "replaceNode":
3012
+ ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
3013
+ haveAddedNodesToParent = true;
3014
+ break;
3015
+ case "ignoreTargetNode": break;
3016
+ default:
3017
+ throw new Error("Unknown renderMode: " + renderMode);
3018
+ }
3019
+
3020
+ if (haveAddedNodesToParent) {
3021
+ activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
3022
+ if (options['afterRender'])
3023
+ ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
3024
+ }
3025
+
3026
+ return renderedNodesArray;
3027
+ }
3028
+
3029
+ ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
3030
+ options = options || {};
3031
+ if ((options['templateEngine'] || _templateEngine) == undefined)
3032
+ throw new Error("Set a template engine before calling renderTemplate");
3033
+ renderMode = renderMode || "replaceChildren";
3034
+
3035
+ if (targetNodeOrNodeArray) {
3036
+ var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
3037
+
3038
+ var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
3039
+ var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;
3040
+
3041
+ return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
3042
+ function () {
3043
+ // Ensure we've got a proper binding context to work with
3044
+ var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
3045
+ ? dataOrBindingContext
3046
+ : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));
3047
+
3048
+ // Support selecting template as a function of the data being rendered
3049
+ var templateName = typeof(template) == 'function' ? template(bindingContext['$data'], bindingContext) : template;
3050
+
3051
+ var renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);
3052
+ if (renderMode == "replaceNode") {
3053
+ targetNodeOrNodeArray = renderedNodesArray;
3054
+ firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
3055
+ }
3056
+ },
3057
+ null,
3058
+ { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
3059
+ );
3060
+ } else {
3061
+ // 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
3062
+ return ko.memoization.memoize(function (domNode) {
3063
+ ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
3064
+ });
3065
+ }
3066
+ };
3067
+
3068
+ ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
3069
+ // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
3070
+ // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
3071
+ var arrayItemContext;
3072
+
3073
+ // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
3074
+ var executeTemplateForArrayItem = function (arrayValue, index) {
3075
+ // Support selecting template as a function of the data being rendered
3076
+ arrayItemContext = parentBindingContext['createChildContext'](ko.utils.unwrapObservable(arrayValue), options['as']);
3077
+ arrayItemContext['$index'] = index;
3078
+ var templateName = typeof(template) == 'function' ? template(arrayValue, arrayItemContext) : template;
3079
+ return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
3080
+ }
3081
+
3082
+ // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
3083
+ var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
3084
+ activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
3085
+ if (options['afterRender'])
3086
+ options['afterRender'](addedNodesArray, arrayValue);
3087
+ };
3088
+
3089
+ return ko.dependentObservable(function () {
3090
+ var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
3091
+ if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
3092
+ unwrappedArray = [unwrappedArray];
3093
+
3094
+ // Filter out any entries marked as destroyed
3095
+ var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
3096
+ return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
3097
+ });
3098
+
3099
+ // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
3100
+ // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
3101
+ ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);
3102
+
3103
+ }, null, { disposeWhenNodeIsRemoved: targetNode });
3104
+ };
3105
+
3106
+ var templateComputedDomDataKey = '__ko__templateComputedDomDataKey__';
3107
+ function disposeOldComputedAndStoreNewOne(element, newComputed) {
3108
+ var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
3109
+ if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
3110
+ oldComputed.dispose();
3111
+ ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
3112
+ }
3113
+
3114
+ ko.bindingHandlers['template'] = {
3115
+ 'init': function(element, valueAccessor) {
3116
+ // Support anonymous templates
3117
+ var bindingValue = ko.utils.unwrapObservable(valueAccessor());
3118
+ if ((typeof bindingValue != "string") && (!bindingValue['name']) && (element.nodeType == 1 || element.nodeType == 8)) {
3119
+ // It's an anonymous template - store the element contents, then clear the element
3120
+ var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
3121
+ container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
3122
+ new ko.templateSources.anonymousTemplate(element)['nodes'](container);
3123
+ }
3124
+ return { 'controlsDescendantBindings': true };
3125
+ },
3126
+ 'update': function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
3127
+ var templateName = ko.utils.unwrapObservable(valueAccessor()),
3128
+ options = {},
3129
+ shouldDisplay = true,
3130
+ dataValue,
3131
+ templateComputed = null;
3132
+
3133
+ if (typeof templateName != "string") {
3134
+ options = templateName;
3135
+ templateName = options['name'];
3136
+
3137
+ // Support "if"/"ifnot" conditions
3138
+ if ('if' in options)
3139
+ shouldDisplay = ko.utils.unwrapObservable(options['if']);
3140
+ if (shouldDisplay && 'ifnot' in options)
3141
+ shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);
3142
+
3143
+ dataValue = ko.utils.unwrapObservable(options['data']);
3144
+ }
3145
+
3146
+ if ('foreach' in options) {
3147
+ // Render once for each data point (treating data set as empty if shouldDisplay==false)
3148
+ var dataArray = (shouldDisplay && options['foreach']) || [];
3149
+ templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
3150
+ } else if (!shouldDisplay) {
3151
+ ko.virtualElements.emptyNode(element);
3152
+ } else {
3153
+ // Render once for this single data point (or use the viewModel if no data was provided)
3154
+ var innerBindingContext = ('data' in options) ?
3155
+ bindingContext['createChildContext'](dataValue, options['as']) : // Given an explitit 'data' value, we create a child binding context for it
3156
+ bindingContext; // Given no explicit 'data' value, we retain the same binding context
3157
+ templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
3158
+ }
3159
+
3160
+ // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
3161
+ disposeOldComputedAndStoreNewOne(element, templateComputed);
3162
+ }
3163
+ };
3164
+
3165
+ // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
3166
+ ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
3167
+ var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);
3168
+
3169
+ if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
3170
+ return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)
3171
+
3172
+ if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
3173
+ return null; // Named templates can be rewritten, so return "no error"
3174
+ return "This template engine does not support anonymous templates nested within its templates";
3175
+ };
3176
+
3177
+ ko.virtualElements.allowedBindings['template'] = true;
3178
+ })();
3179
+
3180
+ ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
3181
+ ko.exportSymbol('renderTemplate', ko.renderTemplate);
3182
+
3183
+ ko.utils.compareArrays = (function () {
3184
+ var statusNotInOld = 'added', statusNotInNew = 'deleted';
3185
+
3186
+ // Simple calculation based on Levenshtein distance.
3187
+ function compareArrays(oldArray, newArray, dontLimitMoves) {
3188
+ oldArray = oldArray || [];
3189
+ newArray = newArray || [];
3190
+
3191
+ if (oldArray.length <= newArray.length)
3192
+ return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, dontLimitMoves);
3193
+ else
3194
+ return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, dontLimitMoves);
3195
+ }
3196
+
3197
+ function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, dontLimitMoves) {
3198
+ var myMin = Math.min,
3199
+ myMax = Math.max,
3200
+ editDistanceMatrix = [],
3201
+ smlIndex, smlIndexMax = smlArray.length,
3202
+ bigIndex, bigIndexMax = bigArray.length,
3203
+ compareRange = (bigIndexMax - smlIndexMax) || 1,
3204
+ maxDistance = smlIndexMax + bigIndexMax + 1,
3205
+ thisRow, lastRow,
3206
+ bigIndexMaxForRow, bigIndexMinForRow;
3207
+
3208
+ for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
3209
+ lastRow = thisRow;
3210
+ editDistanceMatrix.push(thisRow = []);
3211
+ bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
3212
+ bigIndexMinForRow = myMax(0, smlIndex - 1);
3213
+ for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
3214
+ if (!bigIndex)
3215
+ thisRow[bigIndex] = smlIndex + 1;
3216
+ else if (!smlIndex) // Top row - transform empty array into new array via additions
3217
+ thisRow[bigIndex] = bigIndex + 1;
3218
+ else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
3219
+ thisRow[bigIndex] = lastRow[bigIndex - 1]; // copy value (no edit)
3220
+ else {
3221
+ var northDistance = lastRow[bigIndex] || maxDistance; // not in big (deletion)
3222
+ var westDistance = thisRow[bigIndex - 1] || maxDistance; // not in small (addition)
3223
+ thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
3224
+ }
3225
+ }
3226
+ }
3227
+
3228
+ var editScript = [], meMinusOne, notInSml = [], notInBig = [];
3229
+ for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
3230
+ meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
3231
+ if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
3232
+ notInSml.push(editScript[editScript.length] = { // added
3233
+ 'status': statusNotInSml,
3234
+ 'value': bigArray[--bigIndex],
3235
+ 'index': bigIndex });
3236
+ } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
3237
+ notInBig.push(editScript[editScript.length] = { // deleted
3238
+ 'status': statusNotInBig,
3239
+ 'value': smlArray[--smlIndex],
3240
+ 'index': smlIndex });
3241
+ } else {
3242
+ editScript.push({
3243
+ 'status': "retained",
3244
+ 'value': bigArray[--bigIndex] });
3245
+ --smlIndex;
3246
+ }
3247
+ }
3248
+
3249
+ if (notInSml.length && notInBig.length) {
3250
+ // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
3251
+ // smlIndexMax keeps the time complexity of this algorithm linear.
3252
+ var limitFailedCompares = smlIndexMax * 10, failedCompares,
3253
+ a, d, notInSmlItem, notInBigItem;
3254
+ // Go through the items that have been added and deleted and try to find matches between them.
3255
+ for (failedCompares = a = 0; (dontLimitMoves || failedCompares < limitFailedCompares) && (notInSmlItem = notInSml[a]); a++) {
3256
+ for (d = 0; notInBigItem = notInBig[d]; d++) {
3257
+ if (notInSmlItem['value'] === notInBigItem['value']) {
3258
+ notInSmlItem['moved'] = notInBigItem['index'];
3259
+ notInBigItem['moved'] = notInSmlItem['index'];
3260
+ notInBig.splice(d,1); // This item is marked as moved; so remove it from notInBig list
3261
+ failedCompares = d = 0; // Reset failed compares count because we're checking for consecutive failures
3262
+ break;
3263
+ }
3264
+ }
3265
+ failedCompares += d;
3266
+ }
3267
+ }
3268
+ return editScript.reverse();
3269
+ }
3270
+
3271
+ return compareArrays;
3272
+ })();
3273
+
3274
+ ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
3275
+
3276
+ (function () {
3277
+ // Objective:
3278
+ // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
3279
+ // map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
3280
+ // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
3281
+ // 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
3282
+ // previously mapped - retain those nodes, and just insert/delete other ones
3283
+
3284
+ // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
3285
+ // You can use this, for example, to activate bindings on those nodes.
3286
+
3287
+ function fixUpNodesToBeMovedOrRemoved(contiguousNodeArray) {
3288
+ // Before moving, deleting, or replacing a set of nodes that were previously outputted by the "map" function, we have to reconcile
3289
+ // them against what is in the DOM right now. It may be that some of the nodes have already been removed from the document,
3290
+ // or that new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
3291
+ // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
3292
+ // So, this function translates the old "map" output array into its best guess of what set of current DOM nodes should be removed.
3293
+ //
3294
+ // Rules:
3295
+ // [A] Any leading nodes that aren't in the document any more should be ignored
3296
+ // These most likely correspond to memoization nodes that were already removed during binding
3297
+ // See https://github.com/SteveSanderson/knockout/pull/440
3298
+ // [B] We want to output a contiguous series of nodes that are still in the document. So, ignore any nodes that
3299
+ // have already been removed, and include any nodes that have been inserted among the previous collection
3300
+
3301
+ // Rule [A]
3302
+ while (contiguousNodeArray.length && !ko.utils.domNodeIsAttachedToDocument(contiguousNodeArray[0]))
3303
+ contiguousNodeArray.splice(0, 1);
3304
+
3305
+ // Rule [B]
3306
+ if (contiguousNodeArray.length > 1) {
3307
+ // Build up the actual new contiguous node set
3308
+ var current = contiguousNodeArray[0], last = contiguousNodeArray[contiguousNodeArray.length - 1], newContiguousSet = [current];
3309
+ while (current !== last) {
3310
+ current = current.nextSibling;
3311
+ if (!current) // Won't happen, except if the developer has manually removed some DOM elements (then we're in an undefined scenario)
3312
+ return;
3313
+ newContiguousSet.push(current);
3314
+ }
3315
+
3316
+ // ... then mutate the input array to match this.
3317
+ // (The following line replaces the contents of contiguousNodeArray with newContiguousSet)
3318
+ Array.prototype.splice.apply(contiguousNodeArray, [0, contiguousNodeArray.length].concat(newContiguousSet));
3319
+ }
3320
+ return contiguousNodeArray;
3321
+ }
3322
+
3323
+ function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
3324
+ // Map this array value inside a dependentObservable so we re-map when any dependency changes
3325
+ var mappedNodes = [];
3326
+ var dependentObservable = ko.dependentObservable(function() {
3327
+ var newMappedNodes = mapping(valueToMap, index) || [];
3328
+
3329
+ // On subsequent evaluations, just replace the previously-inserted DOM nodes
3330
+ if (mappedNodes.length > 0) {
3331
+ ko.utils.replaceDomNodes(fixUpNodesToBeMovedOrRemoved(mappedNodes), newMappedNodes);
3332
+ if (callbackAfterAddingNodes)
3333
+ ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
3334
+ }
3335
+
3336
+ // Replace the contents of the mappedNodes array, thereby updating the record
3337
+ // of which nodes would be deleted if valueToMap was itself later removed
3338
+ mappedNodes.splice(0, mappedNodes.length);
3339
+ ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
3340
+ }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return (mappedNodes.length == 0) || !ko.utils.domNodeIsAttachedToDocument(mappedNodes[0]) } });
3341
+ return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
3342
+ }
3343
+
3344
+ var lastMappingResultDomDataKey = "setDomNodeChildrenFromArrayMapping_lastMappingResult";
3345
+
3346
+ ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
3347
+ // Compare the provided array against the previous one
3348
+ array = array || [];
3349
+ options = options || {};
3350
+ var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
3351
+ var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
3352
+ var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
3353
+ var editScript = ko.utils.compareArrays(lastArray, array);
3354
+
3355
+ // Build the new mapping result
3356
+ var newMappingResult = [];
3357
+ var lastMappingResultIndex = 0;
3358
+ var newMappingResultIndex = 0;
3359
+
3360
+ var nodesToDelete = [];
3361
+ var itemsToProcess = [];
3362
+ var itemsForBeforeRemoveCallbacks = [];
3363
+ var itemsForMoveCallbacks = [];
3364
+ var itemsForAfterAddCallbacks = [];
3365
+ var mapData;
3366
+
3367
+ function itemMovedOrRetained(editScriptIndex, oldPosition) {
3368
+ mapData = lastMappingResult[oldPosition];
3369
+ if (newMappingResultIndex !== oldPosition)
3370
+ itemsForMoveCallbacks[editScriptIndex] = mapData;
3371
+ // Since updating the index might change the nodes, do so before calling fixUpNodesToBeMovedOrRemoved
3372
+ mapData.indexObservable(newMappingResultIndex++);
3373
+ fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes);
3374
+ newMappingResult.push(mapData);
3375
+ itemsToProcess.push(mapData);
3376
+ }
3377
+
3378
+ function callCallback(callback, items) {
3379
+ if (callback) {
3380
+ for (var i = 0, n = items.length; i < n; i++) {
3381
+ if (items[i]) {
3382
+ ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
3383
+ callback(node, i, items[i].arrayEntry);
3384
+ });
3385
+ }
3386
+ }
3387
+ }
3388
+ }
3389
+
3390
+ for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
3391
+ movedIndex = editScriptItem['moved'];
3392
+ switch (editScriptItem['status']) {
3393
+ case "deleted":
3394
+ if (movedIndex === undefined) {
3395
+ mapData = lastMappingResult[lastMappingResultIndex];
3396
+
3397
+ // Stop tracking changes to the mapping for these nodes
3398
+ if (mapData.dependentObservable)
3399
+ mapData.dependentObservable.dispose();
3400
+
3401
+ // Queue these nodes for later removal
3402
+ nodesToDelete.push.apply(nodesToDelete, fixUpNodesToBeMovedOrRemoved(mapData.mappedNodes));
3403
+ if (options['beforeRemove']) {
3404
+ itemsForBeforeRemoveCallbacks[i] = mapData;
3405
+ itemsToProcess.push(mapData);
3406
+ }
3407
+ }
3408
+ lastMappingResultIndex++;
3409
+ break;
3410
+
3411
+ case "retained":
3412
+ itemMovedOrRetained(i, lastMappingResultIndex++);
3413
+ break;
3414
+
3415
+ case "added":
3416
+ if (movedIndex !== undefined) {
3417
+ itemMovedOrRetained(i, movedIndex);
3418
+ } else {
3419
+ mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
3420
+ newMappingResult.push(mapData);
3421
+ itemsToProcess.push(mapData);
3422
+ if (!isFirstExecution)
3423
+ itemsForAfterAddCallbacks[i] = mapData;
3424
+ }
3425
+ break;
3426
+ }
3427
+ }
3428
+
3429
+ // Call beforeMove first before any changes have been made to the DOM
3430
+ callCallback(options['beforeMove'], itemsForMoveCallbacks);
3431
+
3432
+ // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
3433
+ ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);
3434
+
3435
+ // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
3436
+ for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
3437
+ // Get nodes for newly added items
3438
+ if (!mapData.mappedNodes)
3439
+ ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));
3440
+
3441
+ // Put nodes in the right place if they aren't there already
3442
+ for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
3443
+ if (node !== nextNode)
3444
+ ko.virtualElements.insertAfter(domNode, node, lastNode);
3445
+ }
3446
+
3447
+ // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
3448
+ if (!mapData.initialized && callbackAfterAddingNodes) {
3449
+ callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
3450
+ mapData.initialized = true;
3451
+ }
3452
+ }
3453
+
3454
+ // If there's a beforeRemove callback, call it after reordering.
3455
+ // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
3456
+ // some sort of animation, which is why we first reorder the nodes that will be removed. If the
3457
+ // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
3458
+ // Perhaps we'll make that change in the future if this scenario becomes more common.
3459
+ callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);
3460
+
3461
+ // Finally call afterMove and afterAdd callbacks
3462
+ callCallback(options['afterMove'], itemsForMoveCallbacks);
3463
+ callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
3464
+
3465
+ // Store a copy of the array items we just considered so we can difference it next time
3466
+ ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);
3467
+ }
3468
+ })();
3469
+
3470
+ ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
3471
+ ko.nativeTemplateEngine = function () {
3472
+ this['allowTemplateRewriting'] = false;
3473
+ }
3474
+
3475
+ ko.nativeTemplateEngine.prototype = new ko.templateEngine();
3476
+ ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options) {
3477
+ var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
3478
+ templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
3479
+ templateNodes = templateNodesFunc ? templateSource['nodes']() : null;
3480
+
3481
+ if (templateNodes) {
3482
+ return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
3483
+ } else {
3484
+ var templateText = templateSource['text']();
3485
+ return ko.utils.parseHtmlFragment(templateText);
3486
+ }
3487
+ };
3488
+
3489
+ ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
3490
+ ko.setTemplateEngine(ko.nativeTemplateEngine.instance);
3491
+
3492
+ ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
3493
+ (function() {
3494
+ ko.jqueryTmplTemplateEngine = function () {
3495
+ // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
3496
+ // doesn't expose a version number, so we have to infer it.
3497
+ // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
3498
+ // which KO internally refers to as version "2", so older versions are no longer detected.
3499
+ var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
3500
+ if ((typeof(jQuery) == "undefined") || !(jQuery['tmpl']))
3501
+ return 0;
3502
+ // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
3503
+ try {
3504
+ if (jQuery['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
3505
+ // Since 1.0.0pre, custom tags should append markup to an array called "__"
3506
+ return 2; // Final version of jquery.tmpl
3507
+ }
3508
+ } catch(ex) { /* Apparently not the version we were looking for */ }
3509
+
3510
+ return 1; // Any older version that we don't support
3511
+ })();
3512
+
3513
+ function ensureHasReferencedJQueryTemplates() {
3514
+ if (jQueryTmplVersion < 2)
3515
+ throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
3516
+ }
3517
+
3518
+ function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
3519
+ return jQuery['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
3520
+ }
3521
+
3522
+ this['renderTemplateSource'] = function(templateSource, bindingContext, options) {
3523
+ options = options || {};
3524
+ ensureHasReferencedJQueryTemplates();
3525
+
3526
+ // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
3527
+ var precompiled = templateSource['data']('precompiled');
3528
+ if (!precompiled) {
3529
+ var templateText = templateSource['text']() || "";
3530
+ // Wrap in "with($whatever.koBindingContext) { ... }"
3531
+ templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";
3532
+
3533
+ precompiled = jQuery['template'](null, templateText);
3534
+ templateSource['data']('precompiled', precompiled);
3535
+ }
3536
+
3537
+ var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
3538
+ var jQueryTemplateOptions = jQuery['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);
3539
+
3540
+ var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
3541
+ resultNodes['appendTo'](document.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work
3542
+
3543
+ jQuery['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
3544
+ return resultNodes;
3545
+ };
3546
+
3547
+ this['createJavaScriptEvaluatorBlock'] = function(script) {
3548
+ return "{{ko_code ((function() { return " + script + " })()) }}";
3549
+ };
3550
+
3551
+ this['addTemplate'] = function(templateName, templateMarkup) {
3552
+ document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "</script>");
3553
+ };
3554
+
3555
+ if (jQueryTmplVersion > 0) {
3556
+ jQuery['tmpl']['tag']['ko_code'] = {
3557
+ open: "__.push($1 || '');"
3558
+ };
3559
+ jQuery['tmpl']['tag']['ko_with'] = {
3560
+ open: "with($1) {",
3561
+ close: "} "
3562
+ };
3563
+ }
3564
+ };
3565
+
3566
+ ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
3567
+
3568
+ // Use this one by default *only if jquery.tmpl is referenced*
3569
+ var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
3570
+ if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
3571
+ ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);
3572
+
3573
+ ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
3574
+ })();
3575
+ });
3576
+ })(window,document,navigator,window["jQuery"]);
3577
+ })();