base.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. (function () {
  2. 'use strict';
  3. // Underscore's Template Module
  4. // Courtesy of underscorejs.org
  5. var _ = (function (_) {
  6. _.defaults = function (object) {
  7. if (!object) {
  8. return object;
  9. }
  10. for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
  11. var iterable = arguments[argsIndex];
  12. if (iterable) {
  13. for (var key in iterable) {
  14. if (object[key] == null) {
  15. object[key] = iterable[key];
  16. }
  17. }
  18. }
  19. }
  20. return object;
  21. }
  22. // By default, Underscore uses ERB-style template delimiters, change the
  23. // following template settings to use alternative delimiters.
  24. _.templateSettings = {
  25. evaluate : /<%([\s\S]+?)%>/g,
  26. interpolate : /<%=([\s\S]+?)%>/g,
  27. escape : /<%-([\s\S]+?)%>/g
  28. };
  29. // When customizing `templateSettings`, if you don't want to define an
  30. // interpolation, evaluation or escaping regex, we need one that is
  31. // guaranteed not to match.
  32. var noMatch = /(.)^/;
  33. // Certain characters need to be escaped so that they can be put into a
  34. // string literal.
  35. var escapes = {
  36. "'": "'",
  37. '\\': '\\',
  38. '\r': 'r',
  39. '\n': 'n',
  40. '\t': 't',
  41. '\u2028': 'u2028',
  42. '\u2029': 'u2029'
  43. };
  44. var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
  45. // JavaScript micro-templating, similar to John Resig's implementation.
  46. // Underscore templating handles arbitrary delimiters, preserves whitespace,
  47. // and correctly escapes quotes within interpolated code.
  48. _.template = function(text, data, settings) {
  49. var render;
  50. settings = _.defaults({}, settings, _.templateSettings);
  51. // Combine delimiters into one regular expression via alternation.
  52. var matcher = new RegExp([
  53. (settings.escape || noMatch).source,
  54. (settings.interpolate || noMatch).source,
  55. (settings.evaluate || noMatch).source
  56. ].join('|') + '|$', 'g');
  57. // Compile the template source, escaping string literals appropriately.
  58. var index = 0;
  59. var source = "__p+='";
  60. text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
  61. source += text.slice(index, offset)
  62. .replace(escaper, function(match) { return '\\' + escapes[match]; });
  63. if (escape) {
  64. source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
  65. }
  66. if (interpolate) {
  67. source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
  68. }
  69. if (evaluate) {
  70. source += "';\n" + evaluate + "\n__p+='";
  71. }
  72. index = offset + match.length;
  73. return match;
  74. });
  75. source += "';\n";
  76. // If a variable is not specified, place data values in local scope.
  77. if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
  78. source = "var __t,__p='',__j=Array.prototype.join," +
  79. "print=function(){__p+=__j.call(arguments,'');};\n" +
  80. source + "return __p;\n";
  81. try {
  82. render = new Function(settings.variable || 'obj', '_', source);
  83. } catch (e) {
  84. e.source = source;
  85. throw e;
  86. }
  87. if (data) return render(data, _);
  88. var template = function(data) {
  89. return render.call(this, data, _);
  90. };
  91. // Provide the compiled function source as a convenience for precompilation.
  92. template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
  93. return template;
  94. };
  95. return _;
  96. })({});
  97. if (location.hostname === 'todomvc.com') {
  98. window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
  99. }
  100. function redirect() {
  101. if (location.hostname === 'tastejs.github.io') {
  102. location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
  103. }
  104. }
  105. function findRoot() {
  106. var base;
  107. [/labs/, /\w*-examples/].forEach(function (href) {
  108. var match = location.href.match(href);
  109. if (!base && match) {
  110. base = location.href.indexOf(match);
  111. }
  112. });
  113. return location.href.substr(0, base);
  114. }
  115. function getFile(file, callback) {
  116. if (!location.host) {
  117. return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
  118. }
  119. var xhr = new XMLHttpRequest();
  120. xhr.open('GET', findRoot() + file, true);
  121. xhr.send();
  122. xhr.onload = function () {
  123. if (xhr.status === 200 && callback) {
  124. callback(xhr.responseText);
  125. }
  126. };
  127. }
  128. function Learn(learnJSON, config) {
  129. if (!(this instanceof Learn)) {
  130. return new Learn(learnJSON, config);
  131. }
  132. var template, framework;
  133. if (typeof learnJSON !== 'object') {
  134. try {
  135. learnJSON = JSON.parse(learnJSON);
  136. } catch (e) {
  137. return;
  138. }
  139. }
  140. if (config) {
  141. template = config.template;
  142. framework = config.framework;
  143. }
  144. if (!template && learnJSON.templates) {
  145. template = learnJSON.templates.todomvc;
  146. }
  147. if (!framework && document.querySelector('[data-framework]')) {
  148. framework = document.querySelector('[data-framework]').getAttribute('data-framework');
  149. }
  150. if (template && learnJSON[framework]) {
  151. this.frameworkJSON = learnJSON[framework];
  152. this.template = template;
  153. this.append();
  154. }
  155. }
  156. Learn.prototype.append = function () {
  157. var aside = document.createElement('aside');
  158. aside.innerHTML = _.template(this.template, this.frameworkJSON);
  159. aside.className = 'learn';
  160. // Localize demo links
  161. var demoLinks = aside.querySelectorAll('.demo-link');
  162. Array.prototype.forEach.call(demoLinks, function (demoLink) {
  163. demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
  164. });
  165. document.body.className = (document.body.className + ' learn-bar').trim();
  166. document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
  167. };
  168. redirect();
  169. getFile('learn.json', Learn);
  170. })();