You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
7.1 KiB
JavaScript
250 lines
7.1 KiB
JavaScript
8 years ago
|
/* global _ */
|
||
|
(function () {
|
||
|
'use strict';
|
||
|
|
||
|
/* jshint ignore:start */
|
||
|
// Underscore's Template Module
|
||
|
// Courtesy of underscorejs.org
|
||
|
var _ = (function (_) {
|
||
|
_.defaults = function (object) {
|
||
|
if (!object) {
|
||
|
return object;
|
||
|
}
|
||
|
for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
|
||
|
var iterable = arguments[argsIndex];
|
||
|
if (iterable) {
|
||
|
for (var key in iterable) {
|
||
|
if (object[key] == null) {
|
||
|
object[key] = iterable[key];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return object;
|
||
|
}
|
||
|
|
||
|
// By default, Underscore uses ERB-style template delimiters, change the
|
||
|
// following template settings to use alternative delimiters.
|
||
|
_.templateSettings = {
|
||
|
evaluate : /<%([\s\S]+?)%>/g,
|
||
|
interpolate : /<%=([\s\S]+?)%>/g,
|
||
|
escape : /<%-([\s\S]+?)%>/g
|
||
|
};
|
||
|
|
||
|
// When customizing `templateSettings`, if you don't want to define an
|
||
|
// interpolation, evaluation or escaping regex, we need one that is
|
||
|
// guaranteed not to match.
|
||
|
var noMatch = /(.)^/;
|
||
|
|
||
|
// Certain characters need to be escaped so that they can be put into a
|
||
|
// string literal.
|
||
|
var escapes = {
|
||
|
"'": "'",
|
||
|
'\\': '\\',
|
||
|
'\r': 'r',
|
||
|
'\n': 'n',
|
||
|
'\t': 't',
|
||
|
'\u2028': 'u2028',
|
||
|
'\u2029': 'u2029'
|
||
|
};
|
||
|
|
||
|
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
|
||
|
|
||
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
||
|
// Underscore templating handles arbitrary delimiters, preserves whitespace,
|
||
|
// and correctly escapes quotes within interpolated code.
|
||
|
_.template = function(text, data, settings) {
|
||
|
var render;
|
||
|
settings = _.defaults({}, settings, _.templateSettings);
|
||
|
|
||
|
// Combine delimiters into one regular expression via alternation.
|
||
|
var matcher = new RegExp([
|
||
|
(settings.escape || noMatch).source,
|
||
|
(settings.interpolate || noMatch).source,
|
||
|
(settings.evaluate || noMatch).source
|
||
|
].join('|') + '|$', 'g');
|
||
|
|
||
|
// Compile the template source, escaping string literals appropriately.
|
||
|
var index = 0;
|
||
|
var source = "__p+='";
|
||
|
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
|
||
|
source += text.slice(index, offset)
|
||
|
.replace(escaper, function(match) { return '\\' + escapes[match]; });
|
||
|
|
||
|
if (escape) {
|
||
|
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
|
||
|
}
|
||
|
if (interpolate) {
|
||
|
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
|
||
|
}
|
||
|
if (evaluate) {
|
||
|
source += "';\n" + evaluate + "\n__p+='";
|
||
|
}
|
||
|
index = offset + match.length;
|
||
|
return match;
|
||
|
});
|
||
|
source += "';\n";
|
||
|
|
||
|
// If a variable is not specified, place data values in local scope.
|
||
|
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
|
||
|
|
||
|
source = "var __t,__p='',__j=Array.prototype.join," +
|
||
|
"print=function(){__p+=__j.call(arguments,'');};\n" +
|
||
|
source + "return __p;\n";
|
||
|
|
||
|
try {
|
||
|
render = new Function(settings.variable || 'obj', '_', source);
|
||
|
} catch (e) {
|
||
|
e.source = source;
|
||
|
throw e;
|
||
|
}
|
||
|
|
||
|
if (data) return render(data, _);
|
||
|
var template = function(data) {
|
||
|
return render.call(this, data, _);
|
||
|
};
|
||
|
|
||
|
// Provide the compiled function source as a convenience for precompilation.
|
||
|
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
|
||
|
|
||
|
return template;
|
||
|
};
|
||
|
|
||
|
return _;
|
||
|
})({});
|
||
|
|
||
|
if (location.hostname === 'todomvc.com') {
|
||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||
|
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||
|
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||
|
ga('create', 'UA-31081062-1', 'auto');
|
||
|
ga('send', 'pageview');
|
||
|
}
|
||
|
/* jshint ignore:end */
|
||
|
|
||
|
function redirect() {
|
||
|
if (location.hostname === 'tastejs.github.io') {
|
||
|
location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function findRoot() {
|
||
|
var base = location.href.indexOf('examples/');
|
||
|
return location.href.substr(0, base);
|
||
|
}
|
||
|
|
||
|
function getFile(file, callback) {
|
||
|
if (!location.host) {
|
||
|
return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
|
||
|
}
|
||
|
|
||
|
var xhr = new XMLHttpRequest();
|
||
|
|
||
|
xhr.open('GET', findRoot() + file, true);
|
||
|
xhr.send();
|
||
|
|
||
|
xhr.onload = function () {
|
||
|
if (xhr.status === 200 && callback) {
|
||
|
callback(xhr.responseText);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function Learn(learnJSON, config) {
|
||
|
if (!(this instanceof Learn)) {
|
||
|
return new Learn(learnJSON, config);
|
||
|
}
|
||
|
|
||
|
var template, framework;
|
||
|
|
||
|
if (typeof learnJSON !== 'object') {
|
||
|
try {
|
||
|
learnJSON = JSON.parse(learnJSON);
|
||
|
} catch (e) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (config) {
|
||
|
template = config.template;
|
||
|
framework = config.framework;
|
||
|
}
|
||
|
|
||
|
if (!template && learnJSON.templates) {
|
||
|
template = learnJSON.templates.todomvc;
|
||
|
}
|
||
|
|
||
|
if (!framework && document.querySelector('[data-framework]')) {
|
||
|
framework = document.querySelector('[data-framework]').dataset.framework;
|
||
|
}
|
||
|
|
||
|
this.template = template;
|
||
|
|
||
|
if (learnJSON.backend) {
|
||
|
this.frameworkJSON = learnJSON.backend;
|
||
|
this.frameworkJSON.issueLabel = framework;
|
||
|
this.append({
|
||
|
backend: true
|
||
|
});
|
||
|
} else if (learnJSON[framework]) {
|
||
|
this.frameworkJSON = learnJSON[framework];
|
||
|
this.frameworkJSON.issueLabel = framework;
|
||
|
this.append();
|
||
|
}
|
||
|
|
||
|
this.fetchIssueCount();
|
||
|
}
|
||
|
|
||
|
Learn.prototype.append = function (opts) {
|
||
|
var aside = document.createElement('aside');
|
||
|
aside.innerHTML = _.template(this.template, this.frameworkJSON);
|
||
|
aside.className = 'learn';
|
||
|
|
||
|
if (opts && opts.backend) {
|
||
|
// Remove demo link
|
||
|
var sourceLinks = aside.querySelector('.source-links');
|
||
|
var heading = sourceLinks.firstElementChild;
|
||
|
var sourceLink = sourceLinks.lastElementChild;
|
||
|
// Correct link path
|
||
|
var href = sourceLink.getAttribute('href');
|
||
|
sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
|
||
|
sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
|
||
|
} else {
|
||
|
// Localize demo links
|
||
|
var demoLinks = aside.querySelectorAll('.demo-link');
|
||
|
Array.prototype.forEach.call(demoLinks, function (demoLink) {
|
||
|
if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
|
||
|
demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
document.body.className = (document.body.className + ' learn-bar').trim();
|
||
|
document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
|
||
|
};
|
||
|
|
||
|
Learn.prototype.fetchIssueCount = function () {
|
||
|
var issueLink = document.getElementById('issue-count-link');
|
||
|
if (issueLink) {
|
||
|
var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
|
||
|
var xhr = new XMLHttpRequest();
|
||
|
xhr.open('GET', url, true);
|
||
|
xhr.onload = function (e) {
|
||
|
var parsedResponse = JSON.parse(e.target.responseText);
|
||
|
if (parsedResponse instanceof Array) {
|
||
|
var count = parsedResponse.length;
|
||
|
if (count !== 0) {
|
||
|
issueLink.innerHTML = 'This app has ' + count + ' open issues';
|
||
|
document.getElementById('issue-count').style.display = 'inline';
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
xhr.send();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
redirect();
|
||
|
getFile('learn.json', Learn);
|
||
|
})();
|