Bug 1356652 - Import Speedometer; rs=glandium r=glandium

From https://svn.webkit.org/repository/webkit/trunk at revision 221009.
Added without modification.

MozReview-Commit-ID: BZGxM50iev4

--HG--
extra : rebase_source : f723ec461d95d781769659b3be32335da190fe00
This commit is contained in:
Gregory Szorc 2017-08-25 10:26:28 -07:00
Родитель 8933bc1c63
Коммит 05d95e6ac2
508 изменённых файлов: 299984 добавлений и 0 удалений

170
third_party/speedometer/InteractiveRunner.html поставляемый Normal file
Просмотреть файл

@ -0,0 +1,170 @@
<!DOCTYPE html>
<html>
<head>
<title>Speedometer 2.0 Interactive Runner</title>
<script src="resources/benchmark-runner.js" defer></script>
<script src="resources/tests.js" defer></script>
<style>
iframe { border: 1px solid black; }
ol { list-style: none; margin: 0; padding: 0; }
ol ol { margin-left: 2em; list-position: outside; }
.running { text-decoration: underline; }
.ran { color: grey; }
nav { position: absolute; right: 10px; height: 600px; }
nav > ol { height: 100%; overflow-y: scroll; }
</style>
</head>
<body>
<script>
function formatTestName(suiteName, testName) {
return suiteName + (testName ? '/' + testName : '');
}
function createUIForSuites(suites, onstep, onrun) {
var control = document.createElement('nav');
var ol = document.createElement('ol');
var checkboxes = [];
for (var suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {
var suite = suites[suiteIndex];
var li = document.createElement('li');
var checkbox = document.createElement('input');
checkbox.id = suite.name;
checkbox.type = 'checkbox';
checkbox.checked = !suite.disabled;
checkbox.onchange = (function (suite, checkbox) { return function () { suite.disabled = !checkbox.checked; } })(suite, checkbox);
checkbox.onchange();
checkboxes.push(checkbox);
li.appendChild(checkbox);
var label = document.createElement('label');
label.appendChild(document.createTextNode(formatTestName(suite.name)));
li.appendChild(label);
label.htmlFor = checkbox.id;
var testList = document.createElement('ol');
for (var testIndex = 0; testIndex < suite.tests.length; testIndex++) {
var testItem = document.createElement('li');
var test = suite.tests[testIndex];
var anchor = document.createElement('a');
anchor.id = suite.name + '-' + test.name;
test.anchor = anchor;
anchor.appendChild(document.createTextNode(formatTestName(suite.name, test.name)));
testItem.appendChild(anchor);
testList.appendChild(testItem);
}
li.appendChild(testList);
ol.appendChild(li);
}
control.appendChild(ol);
var button = document.createElement('button');
button.textContent = 'Step';
button.onclick = onstep;
control.appendChild(button);
var button = document.createElement('button');
button.textContent = 'Run';
button.id = 'runSuites';
button.onclick = onrun;
control.appendChild(button);
var button = document.createElement('button');
button.textContent = 'Select all';
button.onclick = function () {
for (var suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {
suites[suiteIndex].disabled = false;
checkboxes[suiteIndex].checked = true;
}
};
control.appendChild(button);
var button = document.createElement('button');
button.textContent = 'Unselect all';
button.onclick = function () {
for (var suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {
suites[suiteIndex].disabled = true;
checkboxes[suiteIndex].checked = false;
}
};
control.appendChild(button);
return control;
}
var parseQueryString = (function (pairList) {
var pairs = {};
for (var i = 0; i < pairList.length; ++i) {
var keyValue = pairList[i].split('=', 2);
if (keyValue.length == 1)
pairs[keyValue[0]] = '';
else
pairs[keyValue[0]] = decodeURIComponent(keyValue[1].replace(/\+/g, ' '));
}
return pairs;
})(window.location.search.substr(1).split('&'));
function disableAllSuitesExcept(suiteName) {
Suites.forEach(function(element) {
if (element.name !== suiteName)
element.disabled = true;
});
}
function startTest() {
var queryParam = parseQueryString['suite'];
if (queryParam !== undefined)
disableAllSuitesExcept(queryParam);
var runner = new BenchmarkRunner(Suites, {
willRunTest: function (suite, test) {
test.anchor.classList.add('running');
},
didRunTest: function (suite, test) {
var classList = test.anchor.classList;
classList.remove('running');
classList.add('ran');
},
didRunSuites: function (measuredValues) {
var results = '';
for (var suiteName in measuredValues.tests) {
var suiteResults = measuredValues.tests[suiteName];
for (var testName in suiteResults.tests) {
var testResults = suiteResults.tests[testName];
for (var subtestName in testResults.tests) {
results += suiteName + ' : ' + testName + ' : ' + subtestName
+ ': ' + testResults.tests[subtestName] + ' ms\n';
}
}
results += suiteName + ' : ' + suiteResults.total + ' ms\n';
}
results += 'Total : ' + measuredValues.total + ' ms\n';
if (!results)
return;
var pre = document.createElement('pre');
document.body.appendChild(pre);
pre.textContent = results;
}
});
var currentState = null;
// Don't call step while step is already executing.
document.body.appendChild(createUIForSuites(Suites,
function () { runner.step(currentState).then(function (state) { currentState = state; }); },
function () { runner.runAllSteps(currentState); currentState = null; }));
if (parseQueryString['startAutomatically'] !== undefined)
document.getElementById('runSuites').click();
}
window.addEventListener('load', startTest);
</script>
</body>
</html>

100
third_party/speedometer/index.html поставляемый Normal file
Просмотреть файл

@ -0,0 +1,100 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Speedometer 1.0</title>
<link rel="stylesheet" href="resources/main.css">
<script src="resources/main.js" defer></script>
<script src="resources/benchmark-runner.js" defer></script>
<script src="resources/benchmark-report.js" defer></script>
<script src="../resources/statistics.js" defer></script>
<script src="resources/tests.js" defer></script>
</head>
<body>
<main>
<a id="logo-link" href="javascript:showHome()"><img id="logo" src="resources/logo.png"></a>
<section id="home" class="selected">
<p>
Speedometer is a browser benchmark that measures the responsiveness of Web applications.
It uses demo web applications to simulate user actions such as adding to-do items.
</p>
<p id="screen-size-warning"><strong>
Your browser window is too small. For most accurate results, please make the view port size at least 850px by 650px.<br>
It's currently <span id="screen-size"></span>.
</strong></p>
<div class="buttons">
<button onclick="startTest()">Start Test</button>
</div>
<p class="show-about"><a href="javascript:showAbout()">About Speedometer</a></p>
</section>
<section id="running">
<div id="testContainer"></div>
<div id="progress"><div id="progress-completed"></div></div>
<div id="info"></div>
</section>
<section id="summarized-results">
<h1>Runs / Minute</h1>
<div class="gauge"><div class="window"><div class="needle"></div></div></div>
<hr>
<div id="result-number"></div>
<div id="confidence-number"></div>
<div class="buttons">
<button onclick="startTest()">Test Again</button>
<button class="show-details" onclick="showResultDetails()">Details</button>
</div>
</section>
<section id="detailed-results">
<h1>Detailed Results</h1>
<table class="results-table"></table>
<table class="results-table"></table>
<div class="arithmetic-mean"><label>Arithmetic Mean:</label><span id="results-with-statistics"></span></div>
<div class="buttons">
<button onclick="startTest()">Test Again</button>
<button id="show-summary" onclick="showResultsSummary()">Summary</button>
</div>
<p class="show-about"><a href="javascript:showAbout()">About Speedometer</a></p>
</section>
<section id="about">
<h1>About Speedometer</h1>
<p>Speedometer measures simulated user interactions in web applications.</p>
<p>
The current benchmark uses TodoMVC to simulate user actions for adding, completing, and removing to-do items.
Speedometer repeats the same actions using DOM APIs &mdash;
a core set of web platform APIs used extensively in web applications &mdash;
as well as six popular JavaScript frameworks: Ember.js, Backbone.js, jQuery, AngularJS, React, and Flight.
Many of these frameworks are used on the most popular websites in the world, such as Facebook and Twitter.
The performance of these types of operations depends on the speed of the DOM APIs, the JavaScript engine,
CSS style resolution, layout, and other technologies.
</p>
<p>
Although user-driven actions like mouse movements and keyboard input cannot be accurately emulated in JavaScript,
Speedometer does its best to faithfully replay a typical workload within the demo applications.
To make the run time long enough to measure with the limited precision,
we synchronously execute a large number of the operations, such as adding one hundred to-do items.
</p>
<p>
Some browser engines use an optimization strategy of doing some work asynchronously to reduce the run time of synchronous operations.
While returning control back to JavaScript execution as soon as possible is worth pursuing,
a holistic, accurate measurement of web application performance involves measuring
when these related, asynchronous computations actually complete.
Thus, Speedometer measures the time browser spends executing those asynchronous tasks in Speedometer,
estimated as the time between when a zero-second delay timer is scheduled and when it is fired.</p>
<p class="note">
<strong>Note:</strong> Speedometer is not meant to compare the performance of different JavaScript frameworks.
The mechanism we use to simulate user actions is different for each framework,
and were forcing frameworks to do more work synchronously than needed in some cases to ensure run time can be measured.
</p>
</section>
</main>
</body>
</html>

79
third_party/speedometer/resources/benchmark-report.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,79 @@
// This file can be customized to report results as needed.
(function () {
if (!window.testRunner && location.search != '?webkit' && location.hash != '#webkit')
return;
if (window.testRunner)
testRunner.waitUntilDone();
var scriptElement = document.createElement('script');
scriptElement.src = '../resources/runner.js';
document.head.appendChild(scriptElement);
var styleElement = document.createElement('style');
styleElement.textContent = 'pre { padding-top: 600px; }';
document.head.appendChild(styleElement);
var createTest;
var valuesByIteration = new Array;
window.onload = function () {
document.body.removeChild(document.querySelector('main'));
startBenchmark();
}
window.benchmarkClient = {
iterationCount: 5, // Use 4 different instances of DRT/WTR to run 5 iterations.
willStartFirstIteration: function (iterationCount) {
createTest = function (name, aggregator, isLastTest) {
return {
customIterationCount: iterationCount,
doNotIgnoreInitialRun: true,
doNotMeasureMemoryUsage: true,
continueTesting: !isLastTest,
unit: 'ms',
name: name,
aggregator: aggregator};
}
PerfTestRunner.prepareToMeasureValuesAsync(createTest(null, 'Total'));
},
didRunSuites: function (measuredValues) {
PerfTestRunner.measureValueAsync(measuredValues.total);
valuesByIteration.push(measuredValues.tests);
},
didFinishLastIteration: function () {
document.head.removeChild(document.querySelector('style'));
var measuredValuesByFullName = {};
function addToMeasuredValue(value, fullName, aggregator) {
var values = measuredValuesByFullName[fullName] || new Array;
measuredValuesByFullName[fullName] = values;
values.push(value);
values.aggregator = aggregator;
}
valuesByIteration.forEach(function (measuredValues) {
for (var suiteName in measuredValues) {
var suite = measuredValues[suiteName];
for (var testName in suite.tests) {
var test = suite.tests[testName];
for (var subtestName in test.tests)
addToMeasuredValue(test.tests[subtestName], suiteName + '/' + testName + '/' + subtestName);
addToMeasuredValue(test.total, suiteName + '/' + testName, 'Total');
}
addToMeasuredValue(suite.total, suiteName, 'Total');
}
});
var fullNames = new Array;
for (var fullName in measuredValuesByFullName)
fullNames.push(fullName);
for (var i = 0; i < fullNames.length; i++) {
var values = measuredValuesByFullName[fullNames[i]];
PerfTestRunner.reportValues(createTest(fullNames[i], values.aggregator, i + 1 == fullNames.length), values);
}
}
};
})();

283
third_party/speedometer/resources/benchmark-runner.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,283 @@
// FIXME: Use the real promise if available.
// FIXME: Make sure this interface is compatible with the real Promise.
function SimplePromise() {
this._chainedPromise = null;
this._callback = null;
}
SimplePromise.prototype.then = function (callback) {
if (this._callback)
throw "SimplePromise doesn't support multiple calls to then";
this._callback = callback;
this._chainedPromise = new SimplePromise;
if (this._resolved)
this.resolve(this._resolvedValue);
return this._chainedPromise;
}
SimplePromise.prototype.resolve = function (value) {
if (!this._callback) {
this._resolved = true;
this._resolvedValue = value;
return;
}
var result = this._callback(value);
if (result instanceof SimplePromise) {
var chainedPromise = this._chainedPromise;
result.then(function (result) { chainedPromise.resolve(result); });
} else
this._chainedPromise.resolve(result);
}
function BenchmarkTestStep(testName, testFunction) {
this.name = testName;
this.run = testFunction;
}
function BenchmarkRunner(suites, client) {
this._suites = suites;
this._prepareReturnValue = null;
this._client = client;
}
BenchmarkRunner.prototype.waitForElement = function (selector) {
var promise = new SimplePromise;
var contentDocument = this._frame.contentDocument;
function resolveIfReady() {
var element = contentDocument.querySelector(selector);
if (element)
return promise.resolve(element);
setTimeout(resolveIfReady, 50);
}
resolveIfReady();
return promise;
}
BenchmarkRunner.prototype._removeFrame = function () {
if (this._frame) {
this._frame.parentNode.removeChild(this._frame);
this._frame = null;
}
}
BenchmarkRunner.prototype._appendFrame = function (src) {
var frame = document.createElement('iframe');
frame.style.width = '800px';
frame.style.height = '600px';
frame.style.border = '0px none';
frame.style.position = 'absolute';
frame.setAttribute('scrolling', 'no');
var marginLeft = parseInt(getComputedStyle(document.body).marginLeft);
var marginTop = parseInt(getComputedStyle(document.body).marginTop);
if (window.innerWidth > 800 + marginLeft && window.innerHeight > 600 + marginTop) {
frame.style.left = marginLeft + 'px';
frame.style.top = marginTop + 'px';
} else {
frame.style.left = '0px';
frame.style.top = '0px';
}
if (this._client && this._client.willAddTestFrame)
this._client.willAddTestFrame(frame);
document.body.insertBefore(frame, document.body.firstChild);
this._frame = frame;
return frame;
}
BenchmarkRunner.prototype._waitAndWarmUp = function () {
var startTime = Date.now();
function Fibonacci(n) {
if (Date.now() - startTime > 100)
return;
if (n <= 0)
return 0;
else if (n == 1)
return 1;
return Fibonacci(n - 2) + Fibonacci(n - 1);
}
var promise = new SimplePromise;
setTimeout(function () {
Fibonacci(100);
promise.resolve();
}, 200);
return promise;
}
BenchmarkRunner.prototype._writeMark = function(name) {
if (window.performance && window.performance.mark)
window.performance.mark(name);
}
// This function ought be as simple as possible. Don't even use SimplePromise.
BenchmarkRunner.prototype._runTest = function(suite, test, prepareReturnValue, callback)
{
var self = this;
var now = window.performance && window.performance.now ? function () { return window.performance.now(); } : Date.now;
var contentWindow = self._frame.contentWindow;
var contentDocument = self._frame.contentDocument;
self._writeMark(suite.name + '.' + test.name + '-start');
var startTime = now();
test.run(prepareReturnValue, contentWindow, contentDocument);
var endTime = now();
self._writeMark(suite.name + '.' + test.name + '-sync-end');
var syncTime = endTime - startTime;
var startTime = now();
setTimeout(function () {
// Some browsers don't immediately update the layout for paint.
// Force the layout here to ensure we're measuring the layout time.
var height = self._frame.contentDocument.body.getBoundingClientRect().height;
var endTime = now();
self._frame.contentWindow._unusedHeightValue = height; // Prevent dead code elimination.
self._writeMark(suite.name + '.' + test.name + '-async-end');
callback(syncTime, endTime - startTime, height);
}, 0);
}
function BenchmarkState(suites) {
this._suites = suites;
this._suiteIndex = -1;
this._testIndex = 0;
this.next();
}
BenchmarkState.prototype.currentSuite = function() {
return this._suites[this._suiteIndex];
}
BenchmarkState.prototype.currentTest = function () {
var suite = this.currentSuite();
return suite ? suite.tests[this._testIndex] : null;
}
BenchmarkState.prototype.next = function () {
this._testIndex++;
var suite = this._suites[this._suiteIndex];
if (suite && this._testIndex < suite.tests.length)
return this;
this._testIndex = 0;
do {
this._suiteIndex++;
} while (this._suiteIndex < this._suites.length && this._suites[this._suiteIndex].disabled);
return this;
}
BenchmarkState.prototype.isFirstTest = function () {
return !this._testIndex;
}
BenchmarkState.prototype.prepareCurrentSuite = function (runner, frame) {
var suite = this.currentSuite();
var promise = new SimplePromise;
frame.onload = function () {
suite.prepare(runner, frame.contentWindow, frame.contentDocument).then(function (result) { promise.resolve(result); });
}
frame.src = 'resources/' + suite.url;
return promise;
}
BenchmarkRunner.prototype.step = function (state) {
if (!state) {
state = new BenchmarkState(this._suites);
this._measuredValues = {tests: {}, total: 0};
}
var suite = state.currentSuite();
if (!suite) {
this._finalize();
var promise = new SimplePromise;
promise.resolve();
return promise;
}
if (state.isFirstTest()) {
this._removeFrame();
this._masuredValuesForCurrentSuite = {};
var self = this;
return state.prepareCurrentSuite(this, this._appendFrame()).then(function (prepareReturnValue) {
self._prepareReturnValue = prepareReturnValue;
return self._runTestAndRecordResults(state);
});
}
return this._runTestAndRecordResults(state);
}
BenchmarkRunner.prototype.runAllSteps = function (startingState) {
var nextCallee = this.runAllSteps.bind(this);
this.step(startingState).then(function (nextState) {
if (nextState)
nextCallee(nextState);
});
}
BenchmarkRunner.prototype.runMultipleIterations = function (iterationCount) {
var self = this;
var currentIteration = 0;
this._runNextIteration = function () {
currentIteration++;
if (currentIteration < iterationCount)
self.runAllSteps();
else if (this._client && this._client.didFinishLastIteration)
this._client.didFinishLastIteration();
}
if (this._client && this._client.willStartFirstIteration)
this._client.willStartFirstIteration(iterationCount);
self.runAllSteps();
}
BenchmarkRunner.prototype._runTestAndRecordResults = function (state) {
var promise = new SimplePromise;
var suite = state.currentSuite();
var test = state.currentTest();
if (this._client && this._client.willRunTest)
this._client.willRunTest(suite, test);
var self = this;
setTimeout(function () {
self._runTest(suite, test, self._prepareReturnValue, function (syncTime, asyncTime) {
var suiteResults = self._measuredValues.tests[suite.name] || {tests:{}, total: 0};
var total = syncTime + asyncTime;
self._measuredValues.tests[suite.name] = suiteResults;
suiteResults.tests[test.name] = {tests: {'Sync': syncTime, 'Async': asyncTime}, total: total};
suiteResults.total += total;
self._measuredValues.total += total;
if (self._client && self._client.didRunTest)
self._client.didRunTest(suite, test);
state.next();
promise.resolve(state);
});
}, 0);
return promise;
}
BenchmarkRunner.prototype._finalize = function () {
this._removeFrame();
if (this._client && this._client.didRunSuites)
this._client.didRunSuites(this._measuredValues);
if (this._runNextIteration)
this._runNextIteration();
}

Просмотреть файл

@ -0,0 +1,19 @@
Copyright (c) Twitter Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Просмотреть файл

@ -0,0 +1,5 @@
# Flight example app
[![Build Status](https://travis-ci.org/flightjs/example-app.png?branch=master)](http://travis-ci.org/flightjs/example-app)
An example Flight application.

Просмотреть файл

@ -0,0 +1,47 @@
'use strict';
define(
[
'app/component_data/mail_items',
'app/component_data/compose_box',
'app/component_data/move_to',
'app/component_ui/mail_items',
'app/component_ui/mail_controls',
'app/component_ui/compose_box',
'app/component_ui/folders',
'app/component_ui/move_to_selector'
],
function(
MailItemsData,
ComposeBoxData,
MoveToData,
MailItemsUI,
MailControlsUI,
ComposeBoxUI,
FoldersUI,
MoveToSelectorUI) {
function initialize() {
MailItemsData.attachTo(document);
ComposeBoxData.attachTo(document, {
selectedFolders: ['inbox']
});
MoveToData.attachTo(document);
MailItemsUI.attachTo('#mail_items', {
itemContainerSelector: '#mail_items_TB',
selectedFolders: ['inbox']
});
MailControlsUI.attachTo('#mail_controls');
ComposeBoxUI.attachTo('#compose_box');
FoldersUI.attachTo('#folders');
MoveToSelectorUI.attachTo('#move_to_selector', {
moveActionSelector: '#move_mail',
selectedFolders: ['inbox']
});
}
return initialize;
}
);

Просмотреть файл

@ -0,0 +1,93 @@
'use strict';
define(
[
'flight/lib/component',
'components/mustache/mustache',
'app/data',
'app/templates'
],
function(defineComponent, Mustache, dataStore, templates) {
return defineComponent(composeBox);
function composeBox() {
this.defaultAttrs({
dataStore: dataStore,
recipientHintId: 'recipient_hint',
subjectHint: 'Subject',
messageHint: 'Message',
toHint: 'To',
forwardPrefix: 'Fw',
replyPrefix: 'Re'
});
this.serveComposeBox = function(ev, data) {
this.trigger("dataComposeBoxServed", {
markup: this.renderComposeBox(data.type, data.relatedMailId),
type: data.type});
};
this.getSubject = function(type, relatedMailId) {
var relatedMail = this.attr.dataStore.mail.filter(function(each) {
return each.id == relatedMailId;
})[0];
var subject = relatedMail && relatedMail.subject;
var subjectLookup = {
newMail: this.attr.subjectHint,
forward: this.attr.forwardPrefix + ": " + subject,
reply: this.attr.replyPrefix + ": " + subject
}
return subjectLookup[type];
};
this.renderComposeBox = function(type, relatedMailId) {
var recipientId = this.getRecipientId(type, relatedMailId);
var contacts = this.attr.dataStore.contacts.map(function(contact) {
contact.recipient = (contact.id == recipientId);
return contact;
});
return Mustache.render(templates.composeBox, {
newMail: type == 'newMail',
reply: type == 'reply',
subject: this.getSubject(type, relatedMailId),
message: this.attr.messageHint,
contacts: contacts
});
};
this.getRecipientId = function(type, relatedMailId) {
var relatedMail = (type == 'reply') && this.attr.dataStore.mail.filter(function(each) {
return each.id == relatedMailId;
})[0];
return relatedMail && relatedMail.contact_id || this.attr.recipientHintId;
};
this.send = function(ev, data) {
this.attr.dataStore.mail.push({
id: String(Date.now()),
contact_id: data.to_id,
folders: ["sent"],
time: Date.now(),
subject: data.subject,
message: data.message
});
this.trigger('dataMailItemsRefreshRequested', {folder: data.currentFolder});
};
this.after("initialize", function() {
this.on("uiComposeBoxRequested", this.serveComposeBox);
this.on("uiSendRequested", this.send);
});
}
}
);

Просмотреть файл

@ -0,0 +1,68 @@
'use strict';
define(
[
'flight/lib/component',
'components/mustache/mustache',
'app/data',
'app/templates'
],
function(defineComponent, Mustache, dataStore, templates) {
return defineComponent(mailItems);
function mailItems() {
this.defaultAttrs({
folder: 'inbox',
dataStore: dataStore
});
this.serveMailItems = function(ev, data) {
var folder = (data && data.folder) || this.attr.folder;
this.trigger("dataMailItemsServed", {markup: this.renderItems(this.assembleItems(folder))})
};
this.renderItems = function(items) {
return Mustache.render(templates.mailItem, {mailItems: items});
};
this.assembleItems = function(folder) {
var items = [];
this.attr.dataStore.mail.forEach(function(each) {
if (each.folders && each.folders.indexOf(folder) > -1) {
items.push(this.getItemForView(each));
}
}, this);
return items;
};
this.getItemForView = function(itemData) {
var thisItem, thisContact, msg
thisItem = {id: itemData.id, important: itemData.important};
thisContact = this.attr.dataStore.contacts.filter(function(contact) {
return contact.id == itemData.contact_id
})[0];
thisItem.name = [thisContact.firstName, thisContact.lastName].join(' ');
var subj = itemData.subject;
thisItem.formattedSubject = subj.length > 70 ? subj.slice(0, 70) + "..." : subj;
var msg = itemData.message;
thisItem.formattedMessage = msg.length > 70 ? msg.slice(0, 70) + "..." : msg;
return thisItem;
};
this.after("initialize", function() {
this.on("uiMailItemsRequested", this.serveMailItems);
this.on("dataMailItemsRefreshRequested", this.serveMailItems);
});
}
}
);

Просмотреть файл

@ -0,0 +1,52 @@
'use strict';
define(
[
'flight/lib/component',
'components/mustache/mustache',
'app/data',
'app/templates'
],
function(defineComponent, Mustache, dataStore, templates) {
return defineComponent(moveTo);
function moveTo() {
this.defaultAttrs({
dataStore: dataStore
});
this.serveAvailableFolders = function(ev, data) {
this.trigger("dataMoveToItemsServed", {
markup: this.renderFolderSelector(this.getOtherFolders(data.folder))
})
};
this.renderFolderSelector = function(items) {
return Mustache.render(templates.moveToSelector, {moveToItems: items});
};
this.moveItems = function(ev, data) {
var itemsToMoveIds = data.itemIds
this.attr.dataStore.mail.forEach(function(item) {
if (itemsToMoveIds.indexOf(item.id) > -1) {
item.folders = [data.toFolder];
}
});
this.trigger('dataMailItemsRefreshRequested', {folder: data.fromFolder});
};
this.getOtherFolders = function(folder) {
return this.attr.dataStore.folders.filter(function(e) {return e != folder});
};
this.after("initialize", function() {
this.on("uiAvailableFoldersRequested", this.serveAvailableFolders);
this.on("uiMoveItemsRequested", this.moveItems);
});
}
}
);

Просмотреть файл

@ -0,0 +1,113 @@
'use strict';
define(
[
'flight/lib/component'
],
function(defineComponent) {
return defineComponent(composeBox);
function composeBox() {
this.defaultAttrs({
newMailType: 'newMail',
forwardMailType: 'forward',
replyMailType: 'reply',
hintClass: 'hint',
selectedFolders: [],
selectedMailItems: [],
//selectors
composeControl: '.compose',
newControlSelector: '#new_mail',
cancelSelector: '#cancel_composed',
sendSelector: '#send_composed',
toSelector: '#compose_to',
subjectSelector: '#compose_subject',
messageSelector: '#compose_message',
recipientSelector: '#recipient_select',
recipientHintSelector: '#recipient_hint',
selectedRecipientSelector: '#recipient_select :selected',
hintSelector: 'div.hint'
});
this.newMail = function() {
this.requestComposeBox(this.attr.newMailType);
};
this.forward = function() {
this.requestComposeBox(this.attr.forwardMailType, this.attr.selectedMailItems);
};
this.reply = function() {
this.requestComposeBox(this.attr.replyMailType, this.attr.selectedMailItems);
};
this.requestComposeBox = function(type, relatedMailId) {
this.trigger('uiComposeBoxRequested', {type: type, relatedMailId: relatedMailId});
};
this.launchComposeBox = function(ev, data) {
var focusSelector = (data.type == this.attr.replyMailType) ? 'messageSelector' : 'toSelector';
this.$node.html(data.markup).show();
this.select(focusSelector).focus();
};
this.cancel = function() {
this.$node.html('').hide();
};
this.requestSend = function() {
var data = {
to_id: this.select('selectedRecipientSelector').attr('id'),
subject: this.select('subjectSelector').text(),
message: this.select('messageSelector').text(),
currentFolder: this.attr.selectedFolders[0]
};
this.trigger('uiSendRequested', data);
this.$node.hide();
};
this.enableSend = function() {
this.select('recipientHintSelector').attr('disabled', 'disabled');
this.select('sendSelector').removeAttr('disabled');
};
this.removeHint = function(ev, data) {
$(ev.target).html('').removeClass(this.attr.hintClass);
};
this.updateMailItemSelections = function(ev, data) {
this.attr.selectedMailItems = data.selectedIds;
}
this.updateFolderSelections = function(ev, data) {
this.attr.selectedFolders = data.selectedIds;
}
this.after('initialize', function() {
this.on(document, 'dataComposeBoxServed', this.launchComposeBox);
this.on(document, 'uiForwardMail', this.forward);
this.on(document, 'uiReplyToMail', this.reply);
this.on(document, 'uiMailItemSelectionChanged', this.updateMailItemSelections);
this.on(document, 'uiFolderSelectionChanged', this.updateFolderSelections);
//the following bindings use delegation so that the event target is read at event time
this.on(document, "click", {
'cancelSelector': this.cancel,
'sendSelector': this.requestSend,
'newControlSelector': this.newMail
});
this.on('change', {
'recipientSelector': this.enableSend
});
this.on('keydown', {
'hintSelector': this.removeHint
});
});
}
}
);

Просмотреть файл

@ -0,0 +1,34 @@
'use strict';
define(
[
'flight/lib/component',
'./with_select'
],
function(defineComponent, withSelect) {
return defineComponent(folders, withSelect);
function folders() {
this.defaultAttrs({
selectedClass: 'selected',
selectionChangedEvent: 'uiFolderSelectionChanged',
//selectors
itemSelector: 'li.folder-item',
selectedItemSelector: 'li.folder-item.selected'
});
this.fetchMailItems = function(ev, data) {
this.trigger('uiMailItemsRequested', {folder: data.selectedIds[0]});
}
this.after('initialize', function() {
this.on('uiFolderSelectionChanged', this.fetchMailItems);
});
}
}
);

Просмотреть файл

@ -0,0 +1,67 @@
'use strict';
define(
[
'flight/lib/component'
],
function(defineComponent) {
return defineComponent(mailControls);
function mailControls() {
this.defaultAttrs({
//selectors
actionControlsSelector: 'button.mail-action',
deleteControlSelector: '#delete_mail',
moveControlSelector: '#move_mail',
forwardControlSelector: '#forward',
replyControlSelector: '#reply',
singleItemActionSelector: 'button.single-item'
});
this.disableAll = function() {
this.select('actionControlsSelector').attr('disabled', 'disabled');
};
this.restyleOnSelectionChange = function(ev, data) {
if (data.selectedIds.length > 1) {
this.select('actionControlsSelector').not('button.single-item').removeAttr('disabled');
this.select('singleItemActionSelector').attr('disabled', 'disabled');
} else if (data.selectedIds.length == 1) {
this.select('actionControlsSelector').removeAttr('disabled');
} else {
this.disableAll();
}
};
this.deleteMail = function(ev, data) {
this.trigger('uiDeleteMail');
};
this.moveMail = function(ev, data) {
this.trigger('uiMoveMail');
};
this.forwardMail = function(ev, data) {
this.trigger('uiForwardMail');
};
this.replyToMail = function(ev, data) {
this.trigger('uiReplyToMail');
};
this.after('initialize', function() {
this.on('.mail-action', 'click', {
'deleteControlSelector': this.deleteMail,
'moveControlSelector': this.moveMail,
'forwardControlSelector': this.forwardMail,
'replyControlSelector': this.replyToMail
});
this.on(document, 'uiMailItemSelectionChanged', this.restyleOnSelectionChange);
this.on(document, 'uiFolderSelectionChanged', this.disableAll);
});
}
}
);

Просмотреть файл

@ -0,0 +1,61 @@
'use strict';
define(
[
'flight/lib/component',
'./with_select'
],
function(defineComponent, withSelect) {
return defineComponent(mailItems, withSelect);
function mailItems() {
this.defaultAttrs({
deleteFolder: 'trash',
selectedClass: 'selected',
allowMultiSelect: true,
selectionChangedEvent: 'uiMailItemSelectionChanged',
selectedMailItems: [],
selectedFolders: [],
//selectors
itemSelector: 'tr.mail-item',
selectedItemSelector: 'tr.mail-item.selected'
});
this.renderItems = function(ev, data) {
this.select('itemContainerSelector').html(data.markup);
//new items, so no selections
this.trigger('uiMailItemSelectionChanged', {selectedIds: []});
}
this.updateMailItemSelections = function(ev, data) {
this.attr.selectedMailItems = data.selectedIds;
}
this.updateFolderSelections = function(ev, data) {
this.attr.selectedFolders = data.selectedIds;
}
this.requestDeletion = function() {
this.trigger('uiMoveItemsRequested', {
itemIds: this.attr.selectedMailItems,
fromFolder: this.attr.selectedFolders[0],
toFolder: this.attr.deleteFolder
});
};
this.after('initialize', function() {
this.on(document, 'dataMailItemsServed', this.renderItems);
this.on(document, 'uiDeleteMail', this.requestDeletion);
this.on('uiMailItemSelectionChanged', this.updateMailItemSelections);
this.on(document, 'uiFolderSelectionChanged', this.updateFolderSelections);
this.trigger('uiMailItemsRequested');
});
}
}
);

Просмотреть файл

@ -0,0 +1,79 @@
'use strict';
define(
[
'flight/lib/component',
'./with_select'
],
function(defineComponent, withSelect) {
return defineComponent(moveToSelector, withSelect);
function moveToSelector() {
this.defaultAttrs({
selectionChangedEvent: 'uiMoveToSelectionChanged',
selectedMailItems: [],
selectedFolders: [],
//selectors
itemSelector: 'li.move-to-item',
selectedItemSelector: 'li.move-to-item.selected'
});
this.requestSelectorWidget = function(ev, data) {
this.trigger('uiAvailableFoldersRequested', {
folder: this.attr.selectedFolders[0]
})
};
this.launchSelector = function(ev, data) {
var controlPosition = $(this.attr.moveActionSelector).offset();
this.$node.html(data.markup).show().css({
left: controlPosition.left,
top: controlPosition.top + $(this.attr.moveActionSelector).outerHeight(),
width: $(this.attr.moveActionSelector).outerWidth()
});
window.setTimeout(
(function() {
this.on(document, 'click', this.hideSelector)
}).bind(this), 0);
};
this.hideSelector = function() {
this.off(document, 'click', this.hideSelector);
this.$node.hide();
}
this.updateMailItemSelections = function(ev, data) {
this.attr.selectedMailItems = data.selectedIds;
}
this.updateFolderSelections = function(ev, data) {
this.attr.selectedFolders = data.selectedIds;
}
this.requestMoveTo = function(ev, data) {
this.trigger('uiMoveItemsRequested', {
itemIds: this.attr.selectedMailItems,
fromFolder: this.attr.selectedFolders[0],
toFolder: data.selectedIds[0]
});
this.$node.hide();
};
this.after('initialize', function() {
//show selector widget
this.on(document, 'uiMoveMail', this.requestSelectorWidget);
this.on(document, 'dataMoveToItemsServed', this.launchSelector);
//listen for other selections
this.on(document, 'uiMailItemSelectionChanged', this.updateMailItemSelections);
this.on(document, 'uiFolderSelectionChanged', this.updateFolderSelections);
//move items
this.on('uiMoveToSelectionChanged', this.requestMoveTo);
});
}
}
);

Просмотреть файл

@ -0,0 +1,64 @@
'use strict';
define(
function() {
return withSelect;
function withSelect() {
this.defaultAttrs({
selectedIds: []
});
this.initializeSelections = function() {
this.select('selectedItemSelector').toArray().forEach(function(el) {
this.attr.selectedIds.push(el.getAttribute('id'));
}, this);
};
this.getSelectedIds = function() {
return this.attr.selectedIds;
};
this.toggleItemSelect = function(ev, data) {
var $item = $(data.el), append;
if ($item.hasClass(this.attr.selectedClass)) {
this.unselectItem($item);
} else {
append = this.attr.allowMultiSelect && (ev.metaKey || ev.ctrlKey || ev.shiftKey);
this.selectItem($item, append);
}
};
this.selectItem = function($item, append) {
if (!append) {
this.select('selectedItemSelector').removeClass(this.attr.selectedClass);
this.attr.selectedIds = [];
}
$item.addClass(this.attr.selectedClass);
this.attr.selectedIds.push($item.attr('id'));
this.trigger(this.attr.selectionChangedEvent, {selectedIds: this.attr.selectedIds});
};
this.unselectItem = function($item) {
$item.removeClass(this.attr.selectedClass);
var thisIdIndex = this.attr.selectedIds.indexOf($item.attr('id'));
this.attr.selectedIds.splice(thisIdIndex, 1);
this.trigger(this.attr.selectionChangedEvent, {selectedIds: this.attr.selectedIds});
};
this.after("initialize", function() {
this.on('click', {
'itemSelector': this.toggleItemSelect
});
this.initializeSelections();
});
}
}
);

Просмотреть файл

@ -0,0 +1,102 @@
.modal.fade.in {
left: 5%;
top: 10%;
margin: auto auto auto auto;
}
table {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
td.mailContact,
span.mailSubject,
span.mailMessage {
font-size: 15px;
}
td.mailContact,
span.mailSubject {
font-weight: bold;
}
tr.mail-item.selected td,
li.folder-item.selected,
li.move-to-item.selected {
background-color: #D9EDF7;
}
tr.mail-item.selected:hover td,
li.folder-item.selected:hover,
li.move-to-item.selected:hover {
background-color: #C1E1FF;
}
li.folder-item:hover,
li.move-to-item:hover {
background-color: #EDEDED;
}
li.folder-item,
li.move-to-item {
padding: 3px 0;
margin-left: -15px;
font-size: 15px;
cursor:pointer;
}
li.move-to-item {
text-align: center;
margin-right: -15px;
}
#new_mail {
width: 100px;
}
div.compose-box {
position: absolute;
z-index: 10;
background-color: #FFFFFF;
width: 350px;
border: 1px solid;
}
div.compose-body {
padding: 0;
}
div.compose-header {
font-size: 15px;
}
#recipient_select {
width: 90%;
margin-bottom: 0;
font-weight: bold;
}
div.hint {
border: 1px solid #EAEAEA;
color:#CACACA;
}
#compose_message {
height: 180px;
}
#compose_subject,
#compose_message {
font-size: 15px;
padding: 15px;
}
#move_to_selector {
position: absolute;
z-index: 10;
background-color: #FFFFFF;
border: 1px solid;
}

Просмотреть файл

@ -0,0 +1,110 @@
'use strict';
define(
function() {
return {
folders: ["inbox", "later", "sent", "trash"],
contacts: [
{
"id": "contact_342",
"firstName": "Michael",
"lastName": "Smith",
"email": "ms@proxyweb.com"
},
{
"id": "contact_377",
"firstName": "Mary",
"lastName": "Jones",
"email": "mary@jones.net"
},
{
"id": "contact_398",
"firstName": "Billy",
"lastName": "Idiot",
"email": "william_idiot@gmail.com"
}
],
mail: [
{
"id": "mail_2139",
"contact_id": "contact_342",
"folders": ["inbox"],
"time": 1334891976104,
"subject": "Consectetur adipiscing elit",
"message": "Vestibulum vestibulum varius diam in iaculis. Praesent ultrices dui vitae nibh malesuada non iaculis ante vulputate. Suspendisse feugiat ultricies egestas. Aenean a odio libero. Quisque mollis leo et est euismod sit amet dignissim sapien venenatis. Morbi interdum adipiscing massa"
},
{
"id": "mail_2143",
"contact_id": "contact_377",
"folders": ["inbox", "later"],
"important": "true",
"time": 1334884976104,
"subject": "Neque porro quisquam velit!!",
"message": "Curabitur sollicitudin mi eget sapien posuere semper. Fusce at neque et lacus luctus vulputate vehicula ac enim"
},
{
"id": "mail_2154",
"contact_id": "contact_398",
"folders": ["inbox"],
"important": "true",
"unread": "true",
"time": 1334874976199,
"subject": "Proin egestas aliquam :)",
"message": "Aenean nec erat id ipsum faucibus tristique. Nam blandit est lacinia turpis consectetur elementum. Nulla in risus ut sapien dignissim feugiat. Proin ultrices sodales imperdiet. Vestibulum vehicula blandit tincidunt. Vivamus posuere rhoncus orci, porta commodo mauris aliquam nec"
},
{
"id": "mail_2176",
"contact_id": "contact_377",
"folders": ["inbox"],
"time": 1334884976104,
"subject": "Sed ut perspiciatis unde omnis?",
"message": "laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem."
},
{
"id": "mail_2191",
"contact_id": "contact_398",
"folders": ["inbox"],
"unread": "true",
"time": 1334874976199,
"subject": "At vero eos et accusamus!",
"message": "Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat"
},
{
"id": "mail_2203",
"contact_id": "contact_377",
"folders": ["later"],
"important": "true",
"time": 1334874576199,
"subject": "Mi netus convallis",
"message": "Egestas morbi at. Curabitur aliquet et commodo nonummy, aliquam quis arcu, sed pellentesque vitae molestie mattis magna, in eget, risus nulla vivamus vulputate"
},
{
"id": "mail_2212",
"contact_id": "contact_398",
"folders": ["sent"],
"time": 1334874579867,
"subject": "Fusce tristique pretium eros a gravida",
"message": "Proin malesuada"
},
{
"id": "mail_2021",
"contact_id": "contact_342",
"folders": ["trash"],
"time": 1134874579824,
"subject": "Phasellus vitae interdum nulla.",
"message": "Pellentesque quam eros, mollis quis vulputate eget, pellentesque nec ipsum. Cras dignissim fringilla ligula, ac ullamcorper dui convallis blandit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam id nunc ac orci hendrerit faucibus vel in ante. Mauris nec est turpis, ut fringilla mi. Suspendisse vel tortor at nulla facilisis venenatis in sit amet ligula."
},
{
"id": "mail_1976",
"contact_id": "contact_377",
"folders": ["trash"],
"time": 1034874579813,
"subject": "Fusce tristique pretium :(",
"message": "aliquam quis arcu."
}
]
};
return data;
}
);

Просмотреть файл

@ -0,0 +1,62 @@
'use strict';
define(
function() {
var mailItem =
'{{#mailItems}}\
<tr id="{{id}}" class="mail-item">\
{{#important}}\
<td class="span1"><span class="label label-important">Important</span></td>\
{{/important}}\
{{^important}}\
<td class="span1"><span>&nbsp;</span></td>\
{{/important}}\
<td class="span2 mailContact">{{name}}</td>\
<td class="span8">\
<span class="mailSubject">\
{{formattedSubject}}\
</span>\
<span class="mailMessage">\
- <a href="#">{{formattedMessage}}</a>\
</span>\
</td>\
</tr>\
{{/mailItems}}';
var composeBox =
'<div id="compose_to" class="modal-header compose-header">\
To: <select id="recipient_select">\
{{^reply}}<option id="recipient_hint" class="hint" style="color:#CACACA" >[Select Recipient]</option>{{/reply}}\
{{#contacts}}\
<option id="{{id}}"{{#recipient}} selected{{/recipient}}>{{firstName}} {{lastName}}</option>\
{{/contacts}}\
</select>\
</div>\
<div class="modal-body compose-body">\
<div id="compose_subject" class="{{#newMail}}hint{{/newMail}}{{^newMail}}compose-header{{/newMail}}" contentEditable="true">\
{{subject}}\
</div>\
<div id="compose_message" class="hint" contentEditable="true">\
{{message}}\
</div>\
</div>\
<div class="modal-footer">\
<button id="send_composed" {{^reply}}disabled="disabled"{{/reply}} class="btn btn-primary">Send</button>\
<button id="cancel_composed" class="btn">Cancel</button>\
</div>';
var moveToSelector =
'<ul class="nav nav-list">\
{{#moveToItems}}\
<li id="{{.}}" class="move-to-item">{{.}}</li>\
{{/moveToItems}}\
</ul>';
return {
mailItem: mailItem,
composeBox: composeBox,
moveToSelector: moveToSelector
}
}
);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -0,0 +1,2 @@
node_modules
.DS_Store

Просмотреть файл

@ -0,0 +1,93 @@
2.0.0
- Separate reliable shims from dubious shims (shams).
1.2.10
- Group-effort Style Cleanup
- Took a stab at fixing Object.defineProperty on IE8 without
bad side-effects. (@hax)
- Object.isExtensible no longer fakes it. (@xavierm)
- Date.prototype.toISOString no longer deals with partial
ISO dates, per spec (@kitcambridge)
- More (mostly from @bryanforbes)
1.2.9
- Corrections to toISOString by @kitcambridge
- Fixed three bugs in array methods revealed by Jasmine tests.
- Cleaned up Function.prototype.bind with more fixes and tests from
@bryanforbes.
1.2.8
- Actually fixed problems with Function.prototype.bind, and regressions
from 1.2.7 (@bryanforbes, @jdalton #36)
1.2.7 - REGRESSED
- Fixed problems with Function.prototype.bind when called as a constructor.
(@jdalton #36)
1.2.6
- Revised Date.parse to match ES 5.1 (kitcambridge)
1.2.5
- Fixed a bug for padding it Date..toISOString (tadfisher issue #33)
1.2.4
- Fixed a descriptor bug in Object.defineProperty (raynos)
1.2.3
- Cleaned up RequireJS and <script> boilerplate
1.2.2
- Changed reduce to follow the letter of the spec with regard to having and
owning properties.
- Fixed a bug where RegExps pass as Functions in some engines in reduce.
1.2.1
- Adding few fixes to make jshint happy.
- Fix for issue #12, function expressions can cause scoping issues in IE.
- NPM will minify on install or when `npm run-script install` is executed.
- Adding .gitignore to avoid publishing dev dependencies.
1.2.0
- Making script loadable as AMD module.
- Adding `indexOf` to the list of safe shims.
1.1.0
- Added support for accessor properties where possible (which is all browsers
except IE).
- Stop exposing bound function's (that are returned by
`Function.prototype.bind`) internal properties (`bound, boundTo, boundArgs`)
as in some cases (when using facade objects for example) capabilities of the
enclosed functions will be leaked.
- `Object.create` now explicitly sets `__proto__` property to guarantee
correct behavior of `Object.getPrototypeOf`'s on all objects created using
`Object.create`.
- Switched to `===` from `==` where possible as it's slightly faster on older
browsers that are target of this lib.
- Added names to all anonymous functions to have a better stack traces.
1.0.0
- fixed Date.toISODate, using UTC accessors, as in
http://code.google.com/p/v8/source/browse/trunk/src/date.js?r=6120#986
(arian)
0.0.4
- Revised Object.getPrototypeOf to work in more cases
in response to http://ejohn.org/blog/objectgetprototypeof/
[issue #2] (fschaefer)
0.0.3
- Fixed typos in Object.keys (samsonjs)
0.0.2
Per kangax's recommendations:
- faster Object.create(null)
- fixed a function-scope function declaration statement in Object.create
0.0.1
- fixed Object.create(null), in so far as that's possible
- reworked Rhino Object.freeze(Function) bug detector and patcher
0.0.0
- forked from narwhal-lib

Просмотреть файл

@ -0,0 +1,25 @@
- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License
- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal
Project)
- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA
- fschaefer Florian Schäfer Copyright (C) 2010 MIT License
- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License
- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License
- kossnocorp Sasha Koss XXX TODO License or CLA
- bryanforbes Bryan Forbes XXX TODO License or CLA
- killdream Quildreen Motta Copyright (C) 2011 MIT Licence
- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD
License
- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License
- bbqsrc Brendan Molloy (C) 2011 Creative Commons Zero (public domain)
- iwyg XXX TODO License or CLA
- DomenicDenicola Domenic Denicola Copyright (C) 2011 MIT License
- xavierm02 Montillet Xavier Copyright (C) 2011 MIT License
- Raynos Jake Verbaten Copyright (C) 2011 MIT Licence
- samsonjs Sami Samhuri Copyright (C) 2010 MIT License
- rwldrn Rick Waldron Copyright (C) 2011 MIT License
- lexer Alexey Zakharov XXX TODO License or CLA
- 280 North Inc. (Now Motorola LLC, a subsidiary of Google Inc.)
Copyright (C) 2009 MIT License

Просмотреть файл

@ -0,0 +1,19 @@
Copyright 2009, 2010 Kristopher Michael Kowal. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.

Просмотреть файл

@ -0,0 +1,161 @@
`es5-shim.js` and `es5-shim.min.js` monkey-patch a JavaScript context to
contain all EcmaScript 5 methods that can be faithfully emulated with a
legacy JavaScript engine.
`es5-sham.js` and `es5-sham.min.js` monkey-patch other ES5 methods as
closely as possible. For these methods, as closely as possible to ES5
is not very close. Many of these shams are intended only to allow code
to be written to ES5 without causing run-time errors in older engines.
In many cases, this means that these shams cause many ES5 methods to
silently fail. Decide carefully whether this is what you want.
## Tests
The tests are written with the Jasmine BDD test framework.
To run the tests, navigate to <root-folder>/tests/.
In order to run against the shim-code, the tests attempt to kill the current
implementation of the missing methods. This happens in <root-folder>/tests/helpers/h-kill.js.
So in order to run the tests against the build-in methods, invalidate that file somehow
(comment-out, delete the file, delete the script-tag, etc.).
## Shims
### Complete tests ###
* Array.prototype.every
* Array.prototype.filter
* Array.prototype.forEach
* Array.prototype.indexOf
* Array.prototype.lastIndexOf
* Array.prototype.map
* Array.prototype.some
* Array.prototype.reduce
* Array.prototype.reduceRight
* Array.isArray
* Date.now
* Date.prototype.toJSON
* Function.prototype.bind
* /!\ Caveat: the bound function's length is always 0.
* /!\ Caveat: the bound function has a prototype property.
* /!\ Caveat: bound functions do not try too hard to keep you
from manipulating their ``arguments`` and ``caller`` properties.
* /!\ Caveat: bound functions don't have checks in ``call`` and
``apply`` to avoid executing as a constructor.
* Object.keys
* String.prototype.trim
### Untested ###
* Date.parse (for ISO parsing)
* Date.prototype.toISOString
## Shams
* /?\ Object.create
For the case of simply "begetting" an object that
inherits prototypically from another, this should work
fine across legacy engines.
/!\ Object.create(null) will work only in browsers that
support prototype assignment. This creates an object
that does not have any properties inherited from
Object.prototype. It will silently fail otherwise.
/!\ The second argument is passed to
Object.defineProperties which will probably fail
silently.
* /?\ Object.getPrototypeOf
This will return "undefined" in some cases. It uses
__proto__ if it's available. Failing that, it uses
constructor.prototype, which depends on the constructor
property of the object's prototype having not been
replaced. If your object was created like this, it
won't work:
function Foo() {
}
Foo.prototype = {};
Because the prototype reassignment destroys the
constructor property.
This will work for all objects that were created using
`Object.create` implemented with this library.
* /!\ Object.getOwnPropertyNames
This method uses Object.keys, so it will not be accurate
on legacy engines.
* Object.isSealed
Returns "false" in all legacy engines for all objects,
which is conveniently guaranteed to be accurate.
* Object.isFrozen
Returns "false" in all legacy engines for all objects,
which is conveniently guaranteed to be accurate.
* Object.isExtensible
Works like a charm, by trying very hard to extend the
object then redacting the extension.
### Fail silently
* /!\ Object.getOwnPropertyDescriptor
The behavior of this shim does not conform to ES5. It
should probably not be used at this time, until its
behavior has been reviewed and been confirmed to be
useful in legacy engines.
* /!\ Object.defineProperty
This method will silently fail to set "writable",
"enumerable", and "configurable" properties.
Providing a getter or setter with "get" or "set" on a
descriptor will silently fail on engines that lack
"__defineGetter__" and "__defineSetter__", which include
all versions of IE up to version 8 so far.
IE 8 provides a version of this method but it only works
on DOM objects. Thus, the shim will not get installed
and attempts to set "value" properties will fail
silently on non-DOM objects.
https://github.com/kriskowal/es5-shim/issues#issue/5
* /!\ Object.defineProperties
This uses the Object.defineProperty shim
* Object.seal
Silently fails on all legacy engines. This should be
fine unless you are depending on the safety and security
provisions of this method, which you cannot possibly
obtain in legacy engines.
* Object.freeze
Silently fails on all legacy engines. This should be
fine unless you are depending on the safety and security
provisions of this method, which you cannot possibly
obtain in legacy engines.
* Object.preventExtensions
Silently fails on all legacy engines. This should be
fine unless you are depending on the safety and security
provisions of this method, which you cannot possibly
obtain in legacy engines.

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -0,0 +1,326 @@
// Copyright 2009-2012 by contributors, MIT License
// vim: ts=4 sts=4 sw=4 expandtab
// Module systems magic dance
(function (definition) {
// RequireJS
if (typeof define == "function") {
define(definition);
// YUI3
} else if (typeof YUI == "function") {
YUI.add("es5-sham", definition);
// CommonJS and <script>
} else {
definition();
}
})(function () {
// ES5 15.2.3.2
// http://es5.github.com/#x15.2.3.2
if (!Object.getPrototypeOf) {
// https://github.com/kriskowal/es5-shim/issues#issue/2
// http://ejohn.org/blog/objectgetprototypeof/
// recommended by fschaefer on github
Object.getPrototypeOf = function getPrototypeOf(object) {
return object.__proto__ || (
object.constructor
? object.constructor.prototype
: prototypeOfObject
);
};
}
// ES5 15.2.3.3
// http://es5.github.com/#x15.2.3.3
if (!Object.getOwnPropertyDescriptor) {
var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a non-object: ";
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
if ((typeof object != "object" && typeof object != "function") || object === null) {
throw new TypeError(ERR_NON_OBJECT + object);
}
// If object does not owns property return undefined immediately.
if (!owns(object, property)) {
return;
}
// If object has a property then it's for sure both `enumerable` and
// `configurable`.
var descriptor = { enumerable: true, configurable: true };
// If JS engine supports accessor properties then property may be a
// getter or setter.
if (supportsAccessors) {
// Unfortunately `__lookupGetter__` will return a getter even
// if object has own non getter property along with a same named
// inherited getter. To avoid misbehavior we temporary remove
// `__proto__` so that `__lookupGetter__` will return getter only
// if it's owned by an object.
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
var getter = lookupGetter(object, property);
var setter = lookupSetter(object, property);
// Once we have getter and setter we can put values back.
object.__proto__ = prototype;
if (getter || setter) {
if (getter) {
descriptor.get = getter;
}
if (setter) {
descriptor.set = setter;
}
// If it was accessor property we're done and return here
// in order to avoid adding `value` to the descriptor.
return descriptor;
}
}
// If we got this far we know that object has an own property that is
// not an accessor so we set it as a value and return descriptor.
descriptor.value = object[property];
return descriptor;
};
}
// ES5 15.2.3.4
// http://es5.github.com/#x15.2.3.4
if (!Object.getOwnPropertyNames) {
Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
return Object.keys(object);
};
}
// ES5 15.2.3.5
// http://es5.github.com/#x15.2.3.5
if (!Object.create) {
Object.create = function create(prototype, properties) {
var object;
if (prototype === null) {
object = { "__proto__": null };
} else {
if (typeof prototype != "object") {
throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
}
var Type = function () {};
Type.prototype = prototype;
object = new Type();
// IE has no built-in implementation of `Object.getPrototypeOf`
// neither `__proto__`, but this manually setting `__proto__` will
// guarantee that `Object.getPrototypeOf` will work as expected with
// objects created using `Object.create`
object.__proto__ = prototype;
}
if (properties !== void 0) {
Object.defineProperties(object, properties);
}
return object;
};
}
// ES5 15.2.3.6
// http://es5.github.com/#x15.2.3.6
// Patch for WebKit and IE8 standard mode
// Designed by hax <hax.github.com>
// related issue: https://github.com/kriskowal/es5-shim/issues#issue/5
// IE8 Reference:
// http://msdn.microsoft.com/en-us/library/dd282900.aspx
// http://msdn.microsoft.com/en-us/library/dd229916.aspx
// WebKit Bugs:
// https://bugs.webkit.org/show_bug.cgi?id=36423
function doesDefinePropertyWork(object) {
try {
Object.defineProperty(object, "sentinel", {});
return "sentinel" in object;
} catch (exception) {
// returns falsy
}
}
// check whether defineProperty works if it's given. Otherwise,
// shim partially.
if (Object.defineProperty) {
var definePropertyWorksOnObject = doesDefinePropertyWork({});
var definePropertyWorksOnDom = typeof document == "undefined" ||
doesDefinePropertyWork(document.createElement("div"));
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
var definePropertyFallback = Object.defineProperty;
}
}
if (!Object.defineProperty || definePropertyFallback) {
var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
"on this javascript engine";
Object.defineProperty = function defineProperty(object, property, descriptor) {
if ((typeof object != "object" && typeof object != "function") || object === null) {
throw new TypeError(ERR_NON_OBJECT_TARGET + object);
}
if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) {
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
}
// make a valiant attempt to use the real defineProperty
// for I8's DOM elements.
if (definePropertyFallback) {
try {
return definePropertyFallback.call(Object, object, property, descriptor);
} catch (exception) {
// try the shim if the real one doesn't work
}
}
// If it's a data property.
if (owns(descriptor, "value")) {
// fail silently if "writable", "enumerable", or "configurable"
// are requested but not supported
/*
// alternate approach:
if ( // can't implement these features; allow false but not true
!(owns(descriptor, "writable") ? descriptor.writable : true) ||
!(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||
!(owns(descriptor, "configurable") ? descriptor.configurable : true)
)
throw new RangeError(
"This implementation of Object.defineProperty does not " +
"support configurable, enumerable, or writable."
);
*/
if (supportsAccessors && (lookupGetter(object, property) ||
lookupSetter(object, property)))
{
// As accessors are supported only on engines implementing
// `__proto__` we can safely override `__proto__` while defining
// a property to make sure that we don't hit an inherited
// accessor.
var prototype = object.__proto__;
object.__proto__ = prototypeOfObject;
// Deleting a property anyway since getter / setter may be
// defined on object itself.
delete object[property];
object[property] = descriptor.value;
// Setting original `__proto__` back now.
object.__proto__ = prototype;
} else {
object[property] = descriptor.value;
}
} else {
if (!supportsAccessors) {
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
}
// If we got that far then getters and setters can be defined !!
if (owns(descriptor, "get")) {
defineGetter(object, property, descriptor.get);
}
if (owns(descriptor, "set")) {
defineSetter(object, property, descriptor.set);
}
}
return object;
};
}
// ES5 15.2.3.7
// http://es5.github.com/#x15.2.3.7
if (!Object.defineProperties) {
Object.defineProperties = function defineProperties(object, properties) {
for (var property in properties) {
if (owns(properties, property) && property != "__proto__") {
Object.defineProperty(object, property, properties[property]);
}
}
return object;
};
}
// ES5 15.2.3.8
// http://es5.github.com/#x15.2.3.8
if (!Object.seal) {
Object.seal = function seal(object) {
// this is misleading and breaks feature-detection, but
// allows "securable" code to "gracefully" degrade to working
// but insecure code.
return object;
};
}
// ES5 15.2.3.9
// http://es5.github.com/#x15.2.3.9
if (!Object.freeze) {
Object.freeze = function freeze(object) {
// this is misleading and breaks feature-detection, but
// allows "securable" code to "gracefully" degrade to working
// but insecure code.
return object;
};
}
// detect a Rhino bug and patch it
try {
Object.freeze(function () {});
} catch (exception) {
Object.freeze = (function freeze(freezeObject) {
return function freeze(object) {
if (typeof object == "function") {
return object;
} else {
return freezeObject(object);
}
};
})(Object.freeze);
}
// ES5 15.2.3.10
// http://es5.github.com/#x15.2.3.10
if (!Object.preventExtensions) {
Object.preventExtensions = function preventExtensions(object) {
// this is misleading and breaks feature-detection, but
// allows "securable" code to "gracefully" degrade to working
// but insecure code.
return object;
};
}
// ES5 15.2.3.11
// http://es5.github.com/#x15.2.3.11
if (!Object.isSealed) {
Object.isSealed = function isSealed(object) {
return false;
};
}
// ES5 15.2.3.12
// http://es5.github.com/#x15.2.3.12
if (!Object.isFrozen) {
Object.isFrozen = function isFrozen(object) {
return false;
};
}
// ES5 15.2.3.13
// http://es5.github.com/#x15.2.3.13
if (!Object.isExtensible) {
Object.isExtensible = function isExtensible(object) {
// 1. If Type(O) is not Object throw a TypeError exception.
if (Object(object) !== object) {
throw new TypeError(); // TODO message
}
// 2. Return the Boolean value of the [[Extensible]] internal property of O.
var name = '';
while (owns(object, name)) {
name += '?';
}
object[name] = true;
var returnValue = owns(object, name);
delete object[name];
return returnValue;
};
}
});

Просмотреть файл

@ -0,0 +1,6 @@
(function(d){"function"==typeof define?define(d):"function"==typeof YUI?YUI.add("es5-sham",d):d()})(function(){function d(a){try{return Object.defineProperty(a,"sentinel",{}),"sentinel"in a}catch(c){}}Object.getPrototypeOf||(Object.getPrototypeOf=function(a){return a.__proto__||(a.constructor?a.constructor.prototype:prototypeOfObject)});Object.getOwnPropertyDescriptor||(Object.getOwnPropertyDescriptor=function(a,c){if(typeof a!="object"&&typeof a!="function"||a===null)throw new TypeError("Object.getOwnPropertyDescriptor called on a non-object: "+
a);if(owns(a,c)){var b={enumerable:true,configurable:true};if(supportsAccessors){var d=a.__proto__;a.__proto__=prototypeOfObject;var f=lookupGetter(a,c),e=lookupSetter(a,c);a.__proto__=d;if(f||e){if(f)b.get=f;if(e)b.set=e;return b}}b.value=a[c];return b}});Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(a){return Object.keys(a)});Object.create||(Object.create=function(a,c){var b;if(a===null)b={__proto__:null};else{if(typeof a!="object")throw new TypeError("typeof prototype["+typeof a+
"] != 'object'");b=function(){};b.prototype=a;b=new b;b.__proto__=a}c!==void 0&&Object.defineProperties(b,c);return b});if(Object.defineProperty){var g=d({}),h="undefined"==typeof document||d(document.createElement("div"));if(!g||!h)var e=Object.defineProperty}if(!Object.defineProperty||e)Object.defineProperty=function(a,c,b){if(typeof a!="object"&&typeof a!="function"||a===null)throw new TypeError("Object.defineProperty called on non-object: "+a);if(typeof b!="object"&&typeof b!="function"||b===
null)throw new TypeError("Property description must be an object: "+b);if(e)try{return e.call(Object,a,c,b)}catch(d){}if(owns(b,"value"))if(supportsAccessors&&(lookupGetter(a,c)||lookupSetter(a,c))){var f=a.__proto__;a.__proto__=prototypeOfObject;delete a[c];a[c]=b.value;a.__proto__=f}else a[c]=b.value;else{if(!supportsAccessors)throw new TypeError("getters & setters can not be defined on this javascript engine");owns(b,"get")&&defineGetter(a,c,b.get);owns(b,"set")&&defineSetter(a,c,b.set)}return a};
Object.defineProperties||(Object.defineProperties=function(a,c){for(var b in c)owns(c,b)&&b!="__proto__"&&Object.defineProperty(a,b,c[b]);return a});Object.seal||(Object.seal=function(a){return a});Object.freeze||(Object.freeze=function(a){return a});try{Object.freeze(function(){})}catch(j){var i=Object.freeze;Object.freeze=function(a){return typeof a=="function"?a:i(a)}}Object.preventExtensions||(Object.preventExtensions=function(a){return a});Object.isSealed||(Object.isSealed=function(){return false});
Object.isFrozen||(Object.isFrozen=function(){return false});Object.isExtensible||(Object.isExtensible=function(a){if(Object(a)!==a)throw new TypeError;for(var c="";owns(a,c);)c=c+"?";a[c]=true;var b=owns(a,c);delete a[c];return b})});

Просмотреть файл

@ -0,0 +1,778 @@
// Copyright 2009-2012 by contributors, MIT License
// vim: ts=4 sts=4 sw=4 expandtab
// Module systems magic dance
(function (definition) {
// RequireJS
if (typeof define == "function") {
define(definition);
// YUI3
} else if (typeof YUI == "function") {
YUI.add("es5", definition);
// CommonJS and <script>
} else {
definition();
}
})(function () {
/**
* Brings an environment as close to ECMAScript 5 compliance
* as is possible with the facilities of erstwhile engines.
*
* Annotated ES5: http://es5.github.com/ (specific links below)
* ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
* Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
*/
//
// Function
// ========
//
// ES-5 15.3.4.5
// http://es5.github.com/#x15.3.4.5
if (!Function.prototype.bind) {
Function.prototype.bind = function bind(that) { // .length is 1
// 1. Let Target be the this value.
var target = this;
// 2. If IsCallable(Target) is false, throw a TypeError exception.
if (typeof target != "function") {
throw new TypeError("Function.prototype.bind called on incompatible " + target);
}
// 3. Let A be a new (possibly empty) internal list of all of the
// argument values provided after thisArg (arg1, arg2 etc), in order.
// XXX slicedArgs will stand in for "A" if used
var args = slice.call(arguments, 1); // for normal call
// 4. Let F be a new native ECMAScript object.
// 11. Set the [[Prototype]] internal property of F to the standard
// built-in Function prototype object as specified in 15.3.3.1.
// 12. Set the [[Call]] internal property of F as described in
// 15.3.4.5.1.
// 13. Set the [[Construct]] internal property of F as described in
// 15.3.4.5.2.
// 14. Set the [[HasInstance]] internal property of F as described in
// 15.3.4.5.3.
var bound = function () {
if (this instanceof bound) {
// 15.3.4.5.2 [[Construct]]
// When the [[Construct]] internal method of a function object,
// F that was created using the bind function is called with a
// list of arguments ExtraArgs, the following steps are taken:
// 1. Let target be the value of F's [[TargetFunction]]
// internal property.
// 2. If target has no [[Construct]] internal method, a
// TypeError exception is thrown.
// 3. Let boundArgs be the value of F's [[BoundArgs]] internal
// property.
// 4. Let args be a new list containing the same values as the
// list boundArgs in the same order followed by the same
// values as the list ExtraArgs in the same order.
// 5. Return the result of calling the [[Construct]] internal
// method of target providing args as the arguments.
var F = function(){};
F.prototype = target.prototype;
var self = new F;
var result = target.apply(
self,
args.concat(slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return self;
} else {
// 15.3.4.5.1 [[Call]]
// When the [[Call]] internal method of a function object, F,
// which was created using the bind function is called with a
// this value and a list of arguments ExtraArgs, the following
// steps are taken:
// 1. Let boundArgs be the value of F's [[BoundArgs]] internal
// property.
// 2. Let boundThis be the value of F's [[BoundThis]] internal
// property.
// 3. Let target be the value of F's [[TargetFunction]] internal
// property.
// 4. Let args be a new list containing the same values as the
// list boundArgs in the same order followed by the same
// values as the list ExtraArgs in the same order.
// 5. Return the result of calling the [[Call]] internal method
// of target providing boundThis as the this value and
// providing args as the arguments.
// equiv: target.call(this, ...boundArgs, ...args)
return target.apply(
that,
args.concat(slice.call(arguments))
);
}
};
// XXX bound.length is never writable, so don't even try
//
// 15. If the [[Class]] internal property of Target is "Function", then
// a. Let L be the length property of Target minus the length of A.
// b. Set the length own property of F to either 0 or L, whichever is
// larger.
// 16. Else set the length own property of F to 0.
// 17. Set the attributes of the length own property of F to the values
// specified in 15.3.5.1.
// TODO
// 18. Set the [[Extensible]] internal property of F to true.
// TODO
// 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
// 20. Call the [[DefineOwnProperty]] internal method of F with
// arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
// thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
// false.
// 21. Call the [[DefineOwnProperty]] internal method of F with
// arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
// [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
// and false.
// TODO
// NOTE Function objects created using Function.prototype.bind do not
// have a prototype property or the [[Code]], [[FormalParameters]], and
// [[Scope]] internal properties.
// XXX can't delete prototype in pure-js.
// 22. Return F.
return bound;
};
}
// Shortcut to an often accessed properties, in order to avoid multiple
// dereference that costs universally.
// _Please note: Shortcuts are defined after `Function.prototype.bind` as we
// us it in defining shortcuts.
var call = Function.prototype.call;
var prototypeOfArray = Array.prototype;
var prototypeOfObject = Object.prototype;
var slice = prototypeOfArray.slice;
// Having a toString local variable name breaks in Opera so use _toString.
var _toString = call.bind(prototypeOfObject.toString);
var owns = call.bind(prototypeOfObject.hasOwnProperty);
// If JS engine supports accessors creating shortcuts.
var defineGetter;
var defineSetter;
var lookupGetter;
var lookupSetter;
var supportsAccessors;
if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
defineGetter = call.bind(prototypeOfObject.__defineGetter__);
defineSetter = call.bind(prototypeOfObject.__defineSetter__);
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
}
//
// Array
// =====
//
// ES5 15.4.3.2
// http://es5.github.com/#x15.4.3.2
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
if (!Array.isArray) {
Array.isArray = function isArray(obj) {
return _toString(obj) == "[object Array]";
};
}
// The IsCallable() check in the Array functions
// has been replaced with a strict check on the
// internal class of the object to trap cases where
// the provided function was actually a regular
// expression literal, which in V8 and
// JavaScriptCore is a typeof "function". Only in
// V8 are regular expression literals permitted as
// reduce parameters, so it is desirable in the
// general case for the shim to match the more
// strict and common behavior of rejecting regular
// expressions.
// ES5 15.4.4.18
// http://es5.github.com/#x15.4.4.18
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function forEach(fun /*, thisp*/) {
var self = toObject(this),
thisp = arguments[1],
i = -1,
length = self.length >>> 0;
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(); // TODO message
}
while (++i < length) {
if (i in self) {
// Invoke the callback function with call, passing arguments:
// context, property value, property key, thisArg object context
fun.call(thisp, self[i], i, self);
}
}
};
}
// ES5 15.4.4.19
// http://es5.github.com/#x15.4.4.19
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
if (!Array.prototype.map) {
Array.prototype.map = function map(fun /*, thisp*/) {
var self = toObject(this),
length = self.length >>> 0,
result = Array(length),
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self)
result[i] = fun.call(thisp, self[i], i, self);
}
return result;
};
}
// ES5 15.4.4.20
// http://es5.github.com/#x15.4.4.20
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
if (!Array.prototype.filter) {
Array.prototype.filter = function filter(fun /*, thisp */) {
var self = toObject(this),
length = self.length >>> 0,
result = [],
value,
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self) {
value = self[i];
if (fun.call(thisp, value, i, self)) {
result.push(value);
}
}
}
return result;
};
}
// ES5 15.4.4.16
// http://es5.github.com/#x15.4.4.16
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
if (!Array.prototype.every) {
Array.prototype.every = function every(fun /*, thisp */) {
var self = toObject(this),
length = self.length >>> 0,
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self && !fun.call(thisp, self[i], i, self)) {
return false;
}
}
return true;
};
}
// ES5 15.4.4.17
// http://es5.github.com/#x15.4.4.17
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
if (!Array.prototype.some) {
Array.prototype.some = function some(fun /*, thisp */) {
var self = toObject(this),
length = self.length >>> 0,
thisp = arguments[1];
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
for (var i = 0; i < length; i++) {
if (i in self && fun.call(thisp, self[i], i, self)) {
return true;
}
}
return false;
};
}
// ES5 15.4.4.21
// http://es5.github.com/#x15.4.4.21
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
if (!Array.prototype.reduce) {
Array.prototype.reduce = function reduce(fun /*, initial*/) {
var self = toObject(this),
length = self.length >>> 0;
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
// no value to return if no initial value and an empty array
if (!length && arguments.length == 1) {
throw new TypeError('reduce of empty array with no initial value');
}
var i = 0;
var result;
if (arguments.length >= 2) {
result = arguments[1];
} else {
do {
if (i in self) {
result = self[i++];
break;
}
// if array contains no values, no initial value to return
if (++i >= length) {
throw new TypeError('reduce of empty array with no initial value');
}
} while (true);
}
for (; i < length; i++) {
if (i in self) {
result = fun.call(void 0, result, self[i], i, self);
}
}
return result;
};
}
// ES5 15.4.4.22
// http://es5.github.com/#x15.4.4.22
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
if (!Array.prototype.reduceRight) {
Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
var self = toObject(this),
length = self.length >>> 0;
// If no callback function or if callback is not a callable function
if (_toString(fun) != "[object Function]") {
throw new TypeError(fun + " is not a function");
}
// no value to return if no initial value, empty array
if (!length && arguments.length == 1) {
throw new TypeError('reduceRight of empty array with no initial value');
}
var result, i = length - 1;
if (arguments.length >= 2) {
result = arguments[1];
} else {
do {
if (i in self) {
result = self[i--];
break;
}
// if array contains no values, no initial value to return
if (--i < 0) {
throw new TypeError('reduceRight of empty array with no initial value');
}
} while (true);
}
do {
if (i in this) {
result = fun.call(void 0, result, self[i], i, self);
}
} while (i--);
return result;
};
}
// ES5 15.4.4.14
// http://es5.github.com/#x15.4.4.14
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
var self = toObject(this),
length = self.length >>> 0;
if (!length) {
return -1;
}
var i = 0;
if (arguments.length > 1) {
i = toInteger(arguments[1]);
}
// handle negative indices
i = i >= 0 ? i : Math.max(0, length + i);
for (; i < length; i++) {
if (i in self && self[i] === sought) {
return i;
}
}
return -1;
};
}
// ES5 15.4.4.15
// http://es5.github.com/#x15.4.4.15
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
var self = toObject(this),
length = self.length >>> 0;
if (!length) {
return -1;
}
var i = length - 1;
if (arguments.length > 1) {
i = Math.min(i, toInteger(arguments[1]));
}
// handle negative indices
i = i >= 0 ? i : length - Math.abs(i);
for (; i >= 0; i--) {
if (i in self && sought === self[i]) {
return i;
}
}
return -1;
};
}
//
// Object
// ======
//
// ES5 15.2.3.14
// http://es5.github.com/#x15.2.3.14
if (!Object.keys) {
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
var hasDontEnumBug = true,
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
for (var key in {"toString": null}) {
hasDontEnumBug = false;
}
Object.keys = function keys(object) {
if ((typeof object != "object" && typeof object != "function") || object === null) {
throw new TypeError("Object.keys called on a non-object");
}
var keys = [];
for (var name in object) {
if (owns(object, name)) {
keys.push(name);
}
}
if (hasDontEnumBug) {
for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
var dontEnum = dontEnums[i];
if (owns(object, dontEnum)) {
keys.push(dontEnum);
}
}
}
return keys;
};
}
//
// Date
// ====
//
// ES5 15.9.5.43
// http://es5.github.com/#x15.9.5.43
// This function returns a String value represent the instance in time
// represented by this Date object. The format of the String is the Date Time
// string format defined in 15.9.1.15. All fields are present in the String.
// The time zone is always UTC, denoted by the suffix Z. If the time value of
// this object is not a finite Number a RangeError exception is thrown.
if (!Date.prototype.toISOString || (new Date(-62198755200000).toISOString().indexOf('-000001') === -1)) {
Date.prototype.toISOString = function toISOString() {
var result, length, value, year;
if (!isFinite(this)) {
throw new RangeError("Date.prototype.toISOString called on non-finite value.");
}
// the date time string format is specified in 15.9.1.15.
result = [this.getUTCMonth() + 1, this.getUTCDate(),
this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
year = this.getUTCFullYear();
year = (year < 0 ? '-' : (year > 9999 ? '+' : '')) + ('00000' + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6);
length = result.length;
while (length--) {
value = result[length];
// pad months, days, hours, minutes, and seconds to have two digits.
if (value < 10) {
result[length] = "0" + value;
}
}
// pad milliseconds to have three digits.
return year + "-" + result.slice(0, 2).join("-") + "T" + result.slice(2).join(":") + "." +
("000" + this.getUTCMilliseconds()).slice(-3) + "Z";
}
}
// ES5 15.9.4.4
// http://es5.github.com/#x15.9.4.4
if (!Date.now) {
Date.now = function now() {
return new Date().getTime();
};
}
// ES5 15.9.5.44
// http://es5.github.com/#x15.9.5.44
// This function provides a String representation of a Date object for use by
// JSON.stringify (15.12.3).
if (!Date.prototype.toJSON) {
Date.prototype.toJSON = function toJSON(key) {
// When the toJSON method is called with argument key, the following
// steps are taken:
// 1. Let O be the result of calling ToObject, giving it the this
// value as its argument.
// 2. Let tv be ToPrimitive(O, hint Number).
// 3. If tv is a Number and is not finite, return null.
// XXX
// 4. Let toISO be the result of calling the [[Get]] internal method of
// O with argument "toISOString".
// 5. If IsCallable(toISO) is false, throw a TypeError exception.
if (typeof this.toISOString != "function") {
throw new TypeError('toISOString property is not callable');
}
// 6. Return the result of calling the [[Call]] internal method of
// toISO with O as the this value and an empty argument list.
return this.toISOString();
// NOTE 1 The argument is ignored.
// NOTE 2 The toJSON function is intentionally generic; it does not
// require that its this value be a Date object. Therefore, it can be
// transferred to other kinds of objects for use as a method. However,
// it does require that any such object have a toISOString method. An
// object is free to use the argument key to filter its
// stringification.
};
}
// ES5 15.9.4.2
// http://es5.github.com/#x15.9.4.2
// based on work shared by Daniel Friesen (dantman)
// http://gist.github.com/303249
if (!Date.parse || Date.parse("+275760-09-13T00:00:00.000Z") !== 8.64e15) {
// XXX global assignment won't work in embeddings that use
// an alternate object for the context.
Date = (function(NativeDate) {
// Date.length === 7
var Date = function Date(Y, M, D, h, m, s, ms) {
var length = arguments.length;
if (this instanceof NativeDate) {
var date = length == 1 && String(Y) === Y ? // isString(Y)
// We explicitly pass it through parse:
new NativeDate(Date.parse(Y)) :
// We have to manually make calls depending on argument
// length here
length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
length >= 5 ? new NativeDate(Y, M, D, h, m) :
length >= 4 ? new NativeDate(Y, M, D, h) :
length >= 3 ? new NativeDate(Y, M, D) :
length >= 2 ? new NativeDate(Y, M) :
length >= 1 ? new NativeDate(Y) :
new NativeDate();
// Prevent mixups with unfixed Date object
date.constructor = Date;
return date;
}
return NativeDate.apply(this, arguments);
};
// 15.9.1.15 Date Time String Format.
var isoDateExpression = new RegExp("^" +
"(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign + 6-digit extended year
"(?:-(\\d{2})" + // optional month capture
"(?:-(\\d{2})" + // optional day capture
"(?:" + // capture hours:minutes:seconds.milliseconds
"T(\\d{2})" + // hours capture
":(\\d{2})" + // minutes capture
"(?:" + // optional :seconds.milliseconds
":(\\d{2})" + // seconds capture
"(?:\\.(\\d{3}))?" + // milliseconds capture
")?" +
"(?:" + // capture UTC offset component
"Z|" + // UTC capture
"(?:" + // offset specifier +/-hours:minutes
"([-+])" + // sign capture
"(\\d{2})" + // hours offset capture
":(\\d{2})" + // minutes offset capture
")" +
")?)?)?)?" +
"$");
// Copy any custom methods a 3rd party library may have added
for (var key in NativeDate) {
Date[key] = NativeDate[key];
}
// Copy "native" methods explicitly; they may be non-enumerable
Date.now = NativeDate.now;
Date.UTC = NativeDate.UTC;
Date.prototype = NativeDate.prototype;
Date.prototype.constructor = Date;
// Upgrade Date.parse to handle simplified ISO 8601 strings
Date.parse = function parse(string) {
var match = isoDateExpression.exec(string);
if (match) {
match.shift(); // kill match[0], the full match
// parse months, days, hours, minutes, seconds, and milliseconds
for (var i = 1; i < 7; i++) {
// provide default values if necessary
match[i] = +(match[i] || (i < 3 ? 1 : 0));
// match[1] is the month. Months are 0-11 in JavaScript
// `Date` objects, but 1-12 in ISO notation, so we
// decrement.
if (i == 1) {
match[i]--;
}
}
// parse the UTC offset component
var minuteOffset = +match.pop(), hourOffset = +match.pop(), sign = match.pop();
// compute the explicit time zone offset if specified
var offset = 0;
if (sign) {
// detect invalid offsets and return early
if (hourOffset > 23 || minuteOffset > 59) {
return NaN;
}
// express the provided time zone offset in minutes. The offset is
// negative for time zones west of UTC; positive otherwise.
offset = (hourOffset * 60 + minuteOffset) * 6e4 * (sign == "+" ? -1 : 1);
}
// Date.UTC for years between 0 and 99 converts year to 1900 + year
// The Gregorian calendar has a 400-year cycle, so
// to Date.UTC(year + 400, .... ) - 12622780800000 == Date.UTC(year, ...),
// where 12622780800000 - number of milliseconds in Gregorian calendar 400 years
var year = +match[0];
if (0 <= year && year <= 99) {
match[0] = year + 400;
return NativeDate.UTC.apply(this, match) + offset - 12622780800000;
}
// compute a new UTC date value, accounting for the optional offset
return NativeDate.UTC.apply(this, match) + offset;
}
return NativeDate.parse.apply(this, arguments);
};
return Date;
})(Date);
}
//
// String
// ======
//
// ES5 15.5.4.20
// http://es5.github.com/#x15.5.4.20
var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
"\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
"\u2029\uFEFF";
if (!String.prototype.trim || ws.trim()) {
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
// http://perfectionkills.com/whitespace-deviations/
ws = "[" + ws + "]";
var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
trimEndRegexp = new RegExp(ws + ws + "*$");
String.prototype.trim = function trim() {
if (this === undefined || this === null) {
throw new TypeError("can't convert "+this+" to object");
}
return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
};
}
//
// Util
// ======
//
// ES5 9.4
// http://es5.github.com/#x9.4
// http://jsperf.com/to-integer
var toInteger = function (n) {
n = +n;
if (n !== n) { // isNaN
n = 0;
} else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
return n;
};
var prepareString = "a"[0] != "a";
// ES5 9.9
// http://es5.github.com/#x9.9
var toObject = function (o) {
if (o == null) { // this matches both null and undefined
throw new TypeError("can't convert "+o+" to object");
}
// If the implementation doesn't support by-index access of
// string characters (ex. IE < 9), split the string
if (prepareString && typeof o == "string" && o) {
return o.split("");
}
return Object(o);
};
});

Просмотреть файл

@ -0,0 +1,13 @@
(function(f){"function"==typeof define?define(f):"function"==typeof YUI?YUI.add("es5",f):f()})(function(){Function.prototype.bind||(Function.prototype.bind=function(d){var c=this;if("function"!=typeof c)throw new TypeError("Function.prototype.bind called on incompatible "+c);var a=n.call(arguments,1),b=function(){if(this instanceof b){var e=function(){};e.prototype=c.prototype;var e=new e,i=c.apply(e,a.concat(n.call(arguments)));return Object(i)===i?i:e}return c.apply(d,a.concat(n.call(arguments)))};
return b});var f=Function.prototype.call,m=Object.prototype,n=Array.prototype.slice,l=f.bind(m.toString),o=f.bind(m.hasOwnProperty);o(m,"__defineGetter__")&&(f.bind(m.__defineGetter__),f.bind(m.__defineSetter__),f.bind(m.__lookupGetter__),f.bind(m.__lookupSetter__));Array.isArray||(Array.isArray=function(d){return l(d)=="[object Array]"});Array.prototype.forEach||(Array.prototype.forEach=function(d,c){var a=j(this),b=-1,e=a.length>>>0;if(l(d)!="[object Function]")throw new TypeError;for(;++b<e;)b in
a&&d.call(c,a[b],b,a)});Array.prototype.map||(Array.prototype.map=function(d,c){var a=j(this),b=a.length>>>0,e=Array(b);if(l(d)!="[object Function]")throw new TypeError(d+" is not a function");for(var i=0;i<b;i++)i in a&&(e[i]=d.call(c,a[i],i,a));return e});Array.prototype.filter||(Array.prototype.filter=function(d,c){var a=j(this),b=a.length>>>0,e=[],i;if(l(d)!="[object Function]")throw new TypeError(d+" is not a function");for(var f=0;f<b;f++)if(f in a){i=a[f];d.call(c,i,f,a)&&e.push(i)}return e});
Array.prototype.every||(Array.prototype.every=function(d,c){var a=j(this),b=a.length>>>0;if(l(d)!="[object Function]")throw new TypeError(d+" is not a function");for(var e=0;e<b;e++)if(e in a&&!d.call(c,a[e],e,a))return false;return true});Array.prototype.some||(Array.prototype.some=function(d,c){var a=j(this),b=a.length>>>0;if(l(d)!="[object Function]")throw new TypeError(d+" is not a function");for(var e=0;e<b;e++)if(e in a&&d.call(c,a[e],e,a))return true;return false});Array.prototype.reduce||
(Array.prototype.reduce=function(d){var c=j(this),a=c.length>>>0;if(l(d)!="[object Function]")throw new TypeError(d+" is not a function");if(!a&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var b=0,e;if(arguments.length>=2)e=arguments[1];else{do{if(b in c){e=c[b++];break}if(++b>=a)throw new TypeError("reduce of empty array with no initial value");}while(1)}for(;b<a;b++)b in c&&(e=d.call(void 0,e,c[b],b,c));return e});Array.prototype.reduceRight||(Array.prototype.reduceRight=
function(d){var c=j(this),a=c.length>>>0;if(l(d)!="[object Function]")throw new TypeError(d+" is not a function");if(!a&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var b,a=a-1;if(arguments.length>=2)b=arguments[1];else{do{if(a in c){b=c[a--];break}if(--a<0)throw new TypeError("reduceRight of empty array with no initial value");}while(1)}do a in this&&(b=d.call(void 0,b,c[a],a,c));while(a--);return b});Array.prototype.indexOf||(Array.prototype.indexOf=
function(d){var c=j(this),a=c.length>>>0;if(!a)return-1;var b=0;arguments.length>1&&(b=p(arguments[1]));for(b=b>=0?b:Math.max(0,a+b);b<a;b++)if(b in c&&c[b]===d)return b;return-1});Array.prototype.lastIndexOf||(Array.prototype.lastIndexOf=function(d){var c=j(this),a=c.length>>>0;if(!a)return-1;var b=a-1;arguments.length>1&&(b=Math.min(b,p(arguments[1])));for(b=b>=0?b:a-Math.abs(b);b>=0;b--)if(b in c&&d===c[b])return b;return-1});if(!Object.keys){var q=!0,r="toString toLocaleString valueOf hasOwnProperty isPrototypeOf propertyIsEnumerable constructor".split(" "),
s=r.length,t;for(t in{toString:null})q=!1;Object.keys=function(d){if(typeof d!="object"&&typeof d!="function"||d===null)throw new TypeError("Object.keys called on a non-object");var c=[],a;for(a in d)o(d,a)&&c.push(a);if(q)for(a=0;a<s;a++){var b=r[a];o(d,b)&&c.push(b)}return c}}if(!Date.prototype.toISOString||-1===(new Date(-621987552E5)).toISOString().indexOf("-000001"))Date.prototype.toISOString=function(){var d,c,a,b;if(!isFinite(this))throw new RangeError("Date.prototype.toISOString called on non-finite value.");
d=[this.getUTCMonth()+1,this.getUTCDate(),this.getUTCHours(),this.getUTCMinutes(),this.getUTCSeconds()];b=this.getUTCFullYear();b=(b<0?"-":b>9999?"+":"")+("00000"+Math.abs(b)).slice(0<=b&&b<=9999?-4:-6);for(c=d.length;c--;){a=d[c];a<10&&(d[c]="0"+a)}return b+"-"+d.slice(0,2).join("-")+"T"+d.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"};Date.now||(Date.now=function(){return(new Date).getTime()});Date.prototype.toJSON||(Date.prototype.toJSON=function(){if(typeof this.toISOString!=
"function")throw new TypeError("toISOString property is not callable");return this.toISOString()});if(!Date.parse||864E13!==Date.parse("+275760-09-13T00:00:00.000Z")){var g=Date,f=function c(a,b,e,f,h,j,l){var k=arguments.length;if(this instanceof g){k=k==1&&String(a)===a?new g(c.parse(a)):k>=7?new g(a,b,e,f,h,j,l):k>=6?new g(a,b,e,f,h,j):k>=5?new g(a,b,e,f,h):k>=4?new g(a,b,e,f):k>=3?new g(a,b,e):k>=2?new g(a,b):k>=1?new g(a):new g;k.constructor=c;return k}return g.apply(this,arguments)},u=RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$"),
h;for(h in g)f[h]=g[h];f.now=g.now;f.UTC=g.UTC;f.prototype=g.prototype;f.prototype.constructor=f;f.parse=function(c){var a=u.exec(c);if(a){a.shift();for(var b=1;b<7;b++){a[b]=+(a[b]||(b<3?1:0));b==1&&a[b]--}var e=+a.pop(),f=+a.pop(),h=a.pop(),b=0;if(h){if(f>23||e>59)return NaN;b=(f*60+e)*6E4*(h=="+"?-1:1)}e=+a[0];if(0<=e&&e<=99){a[0]=e+400;return g.UTC.apply(this,a)+b-126227808E5}return g.UTC.apply(this,a)+b}return g.parse.apply(this,arguments)};Date=f}h="\t\n\x0B\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";
if(!String.prototype.trim||h.trim()){h="["+h+"]";var v=RegExp("^"+h+h+"*"),w=RegExp(h+h+"*$");String.prototype.trim=function(){if(this===void 0||this===null)throw new TypeError("can't convert "+this+" to object");return String(this).replace(v,"").replace(w,"")}}var p=function(c){c=+c;c!==c?c=0:c!==0&&(c!==1/0&&c!==-(1/0))&&(c=(c>0||-1)*Math.floor(Math.abs(c)));return c},x="a"!="a"[0],j=function(c){if(c==null)throw new TypeError("can't convert "+c+" to object");return x&&typeof c=="string"&&c?c.split(""):
Object(c)}});

Просмотреть файл

@ -0,0 +1,31 @@
{
"name": "es5-shim",
"version": "2.0.0",
"description": "ES5 as implementable on previous engines",
"homepage": "http://github.com/kriskowal/es5-shim/",
"contributors": [
"Kris Kowal <kris@cixar.com> (http://github.com/kriskowal/)",
"Sami Samhuri <sami.samhuri@gmail.com> (http://samhuri.net/)",
"Florian Schäfer <florian.schaefer@gmail.com> (http://github.com/fschaefer)",
"Irakli Gozalishvili <rfobic@gmail.com> (http://jeditoolkit.com)",
"Kit Cambridge <kitcambridge@gmail.com> (http://kitcambridge.github.com)"
],
"bugs": {
"mail": "kris@cixar.com",
"url": "http://github.com/kriskowal/es5-shim/issues"
},
"licenses": [
{
"type": "MIT",
"url": "http://github.com/kriskowal/es5-shim/raw/master/LICENSE"
}
],
"main": "es5-shim.js",
"repository": {
"type": "git",
"url": "http://github.com/kriskowal/es5-shim.git"
},
"engines": {
"node": ">=0.2.0"
}
}

Просмотреть файл

@ -0,0 +1,59 @@
// This methods allows the killing of built-in functions,
// so the shim can take over with that implementation
var HLP = (function() {
"use strict";
var kill;
kill = function(_class, methods) {
/*if(!Array.isArray(methods))
return;*/
if(!_class.originals)
_class.originals = {};
for (var i = 0, len = methods.length; i < len; i++) {
var obj = methods[i];
_class.originals[obj] = _class[obj];
delete _class[obj];
if (obj in _class) {
// try something more aggressive since V8 at least
// appears to ignore the delete.
_class[obj] = null;
if (_class[obj]) {
console.log("Couln't overwrite", obj, "of", _class);
}
}
}
};
return { kill: kill };
}());
HLP.kill(Function.prototype, [
'bind'
]);
HLP.kill(Array, [
'isArray'
]);
HLP.kill(String.prototype, [
"trim"
]);
HLP.kill(Object, [
'keys'
]);
HLP.kill(Date, [
'now', 'parse'
]);
HLP.kill(Date.prototype, [
"toJSON", "toISOString"
]);
HLP.kill(Array.prototype, [
'forEach', 'some', 'every',
'indexOf', 'lastIndexOf',
'map', 'filter',
'reduce', 'reduceRight'
]);

Просмотреть файл

@ -0,0 +1,34 @@
beforeEach(function() {
this.addMatchers({
toExactlyMatch: function(expected) {
var a1, a2,
l, i,
key,
actual = this.actual;
var getKeys = function(o) {
var a = [];
for(key in o) {
if(o.hasOwnProperty(key)) {
a.push(key);
}
}
return a;
}
a1 = getKeys(actual);
a2 = getKeys(expected);
l = a1.length;
if(l !== a2.length) {
return false;
}
for(i = 0; i < l; i++) {
key = a1[i];
expect(key).toEqual(a2[i]);
expect(actual[key]).toEqual(expected[key]);
}
return true;
}
})
});

Просмотреть файл

@ -0,0 +1,3 @@
function implement() {
throw 'Not implemented';
}

Просмотреть файл

@ -0,0 +1,62 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Jasmine Spec Runner</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="lib/jasmine.css">
<script type="text/javascript" src="lib/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-html.js"></script>
<script type="text/javascript" src="lib/json2.js"></script>
<!-- include helper files here... -->
<script src="helpers/h.js"></script>
<script src="helpers/h-kill.js"></script>
<script src="helpers/h-matchers.js"></script>
<!-- include source files here... -->
<script src="../es5-shim.js"></script>
<!-- include spec files here... -->
<script src="spec/s-array.js"></script>
<script src="spec/s-function.js"></script>
<script src="spec/s-string.js"></script>
<script src="spec/s-object.js"></script>
<script src="spec/s-date.js"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var trivialReporter = new jasmine.TrivialReporter();
jasmineEnv.addReporter(trivialReporter);
jasmineEnv.specFilter = function(spec) {
return trivialReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,190 @@
jasmine.TrivialReporter = function(doc) {
this.document = doc || document;
this.suiteDivs = {};
this.logRunningSpecs = false;
};
jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
var el = document.createElement(type);
for (var i = 2; i < arguments.length; i++) {
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(document.createTextNode(child));
} else {
if (child) { el.appendChild(child); }
}
}
for (var attr in attrs) {
if (attr == "className") {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
};
jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
var showPassed, showSkipped;
this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
this.createDom('div', { className: 'banner' },
this.createDom('div', { className: 'logo' },
this.createDom('span', { className: 'title' }, "Jasmine"),
this.createDom('span', { className: 'version' }, runner.env.versionString())),
this.createDom('div', { className: 'options' },
"Show ",
showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
)
),
this.runnerDiv = this.createDom('div', { className: 'runner running' },
this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
);
this.document.body.appendChild(this.outerDiv);
var suites = runner.suites();
for (var i = 0; i < suites.length; i++) {
var suite = suites[i];
var suiteDiv = this.createDom('div', { className: 'suite' },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
this.suiteDivs[suite.id] = suiteDiv;
var parentDiv = this.outerDiv;
if (suite.parentSuite) {
parentDiv = this.suiteDivs[suite.parentSuite.id];
}
parentDiv.appendChild(suiteDiv);
}
this.startedAt = new Date();
var self = this;
showPassed.onclick = function(evt) {
if (showPassed.checked) {
self.outerDiv.className += ' show-passed';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
}
};
showSkipped.onclick = function(evt) {
if (showSkipped.checked) {
self.outerDiv.className += ' show-skipped';
} else {
self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
}
};
};
jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
var results = runner.results();
var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
this.runnerDiv.setAttribute("class", className);
//do it twice for IE
this.runnerDiv.setAttribute("className", className);
var specs = runner.specs();
var specCount = 0;
for (var i = 0; i < specs.length; i++) {
if (this.specFilter(specs[i])) {
specCount++;
}
}
var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
};
jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.totalCount === 0) { // todo: change this to check results.skipped
status = 'skipped';
}
this.suiteDivs[suite.id].className += " " + status;
};
jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
if (this.logRunningSpecs) {
this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
}
};
jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
var results = spec.results();
var status = results.passed() ? 'passed' : 'failed';
if (results.skipped) {
status = 'skipped';
}
var specDiv = this.createDom('div', { className: 'spec ' + status },
this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
this.createDom('a', {
className: 'description',
href: '?spec=' + encodeURIComponent(spec.getFullName()),
title: spec.getFullName()
}, spec.description));
var resultItems = results.getItems();
var messagesDiv = this.createDom('div', { className: 'messages' });
for (var i = 0; i < resultItems.length; i++) {
var result = resultItems[i];
if (result.type == 'log') {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
} else if (result.type == 'expect' && result.passed && !result.passed()) {
messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
if (result.trace.stack) {
messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
}
}
}
if (messagesDiv.childNodes.length > 0) {
specDiv.appendChild(messagesDiv);
}
this.suiteDivs[spec.suite.id].appendChild(specDiv);
};
jasmine.TrivialReporter.prototype.log = function() {
var console = jasmine.getGlobal().console;
if (console && console.log) {
if (console.log.apply) {
console.log.apply(console, arguments);
} else {
console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
}
}
};
jasmine.TrivialReporter.prototype.getLocation = function() {
return this.document.location;
};
jasmine.TrivialReporter.prototype.specFilter = function(spec) {
var paramMap = {};
var params = this.getLocation().search.substring(1).split('&');
for (var i = 0; i < params.length; i++) {
var p = params[i].split('=');
paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
}
if (!paramMap.spec) {
return true;
}
return spec.getFullName().indexOf(paramMap.spec) === 0;
};

Просмотреть файл

@ -0,0 +1,166 @@
body {
font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
}
.jasmine_reporter a:visited, .jasmine_reporter a {
color: #303;
}
.jasmine_reporter a:hover, .jasmine_reporter a:active {
color: blue;
}
.run_spec {
float:right;
padding-right: 5px;
font-size: .8em;
text-decoration: none;
}
.jasmine_reporter {
margin: 0 5px;
}
.banner {
color: #303;
background-color: #fef;
padding: 5px;
}
.logo {
float: left;
font-size: 1.1em;
padding-left: 5px;
}
.logo .version {
font-size: .6em;
padding-left: 1em;
}
.runner.running {
background-color: yellow;
}
.options {
text-align: right;
font-size: .8em;
}
.suite {
border: 1px outset gray;
margin: 5px 0;
padding-left: 1em;
}
.suite .suite {
margin: 5px;
}
.suite.passed {
background-color: #dfd;
}
.suite.failed {
background-color: #fdd;
}
.spec {
margin: 5px;
padding-left: 1em;
clear: both;
}
.spec.failed, .spec.passed, .spec.skipped {
padding-bottom: 5px;
border: 1px solid gray;
}
.spec.failed {
background-color: #fbb;
border-color: red;
}
.spec.passed {
background-color: #bfb;
border-color: green;
}
.spec.skipped {
background-color: #bbb;
}
.messages {
border-left: 1px dashed gray;
padding-left: 1em;
padding-right: 1em;
}
.passed {
background-color: #cfc;
display: none;
}
.failed {
background-color: #fbb;
}
.skipped {
color: #777;
background-color: #eee;
display: none;
}
/*.resultMessage {*/
/*white-space: pre;*/
/*}*/
.resultMessage span.result {
display: block;
line-height: 2em;
color: black;
}
.resultMessage .mismatch {
color: black;
}
.stackTrace {
white-space: pre;
font-size: .8em;
margin-left: 10px;
max-height: 5em;
overflow: auto;
border: 1px inset red;
padding: 1em;
background: #eef;
}
.finished-at {
padding-left: 1em;
font-size: .6em;
}
.show-passed .passed,
.show-skipped .skipped {
display: block;
}
#jasmine_content {
position:fixed;
right: 100%;
}
.runner {
border: 1px solid gray;
display: block;
margin: 5px 0;
padding: 2px 0 2px 10px;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 905 B

Просмотреть файл

@ -0,0 +1,478 @@
/*
http://www.JSON.org/json2.js
2009-08-17
Public Domain.
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
See http://www.JSON.org/js.html
This file creates a global JSON object containing two methods: stringify
and parse.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
replacer an optional parameter that determines how object
values are stringified for objects. It can be a
function or an array of strings.
space an optional parameter that specifies the indentation
of nested structures. If it is omitted, the text will
be packed without extra whitespace. If it is a number,
it will specify the number of spaces to indent at each
level. If it is a string (such as '\t' or '&nbsp;'),
it contains the characters used to indent at each level.
This method produces a JSON text from a JavaScript value.
When an object value is found, if the object contains a toJSON
method, its toJSON method will be called and the result will be
stringified. A toJSON method does not serialize: it returns the
value represented by the name/value pair that should be serialized,
or undefined if nothing should be serialized. The toJSON method
will be passed the key associated with the value, and this will be
bound to the value
For example, this would serialize Dates as ISO strings.
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
return this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z';
};
You can provide an optional replacer method. It will be passed the
key and value of each member, with this bound to the containing
object. The value that is returned from your method will be
serialized. If your method returns undefined, then the member will
be excluded from the serialization.
If the replacer parameter is an array of strings, then it will be
used to select the members to be serialized. It filters the results
such that only members with keys listed in the replacer array are
stringified.
Values that do not have JSON representations, such as undefined or
functions, will not be serialized. Such values in objects will be
dropped; in arrays they will be replaced with null. You can use
a replacer function to replace those with JSON values.
JSON.stringify(undefined) returns undefined.
The optional space parameter produces a stringification of the
value that is filled with line breaks and indentation to make it
easier to read.
If the space parameter is a non-empty string, then that string will
be used for indentation. If the space parameter is a number, then
the indentation will be that many spaces.
Example:
text = JSON.stringify(['e', {pluribus: 'unum'}]);
// text is '["e",{"pluribus":"unum"}]'
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
return this[key] instanceof Date ?
'Date(' + this[key] + ')' : value;
});
// text is '["Date(---current time---)"]'
JSON.parse(text, reviver)
This method parses a JSON text to produce an object or array.
It can throw a SyntaxError exception.
The optional reviver parameter is a function that can filter and
transform the results. It receives each of the keys and values,
and its return value is used instead of the original value.
If it returns what it received, then the structure is not modified.
If it returns undefined then the member is deleted.
Example:
// Parse the text. Values that look like ISO date strings will
// be converted to Date objects.
myData = JSON.parse(text, function (key, value) {
var a;
if (typeof value === 'string') {
a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+a[5], +a[6]));
}
}
return value;
});
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
var d;
if (typeof value === 'string' &&
value.slice(0, 5) === 'Date(' &&
value.slice(-1) === ')') {
d = new Date(value.slice(5, -1));
if (d) {
return d;
}
}
return value;
});
This is a reference implementation. You are free to copy, modify, or
redistribute.
This code should be minified before deployment.
See http://javascript.crockford.com/jsmin.html
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
NOT CONTROL.
*/
/*jslint evil: true */
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
*/
"use strict";
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
if (!this.JSON) {
this.JSON = {};
}
(function () {
function f(n) {
// Format integers to have at least two digits.
return n < 10 ? '0' + n : n;
}
if (typeof Date.prototype.toJSON !== 'function') {
Date.prototype.toJSON = function (key) {
return isFinite(this.valueOf()) ?
this.getUTCFullYear() + '-' +
f(this.getUTCMonth() + 1) + '-' +
f(this.getUTCDate()) + 'T' +
f(this.getUTCHours()) + ':' +
f(this.getUTCMinutes()) + ':' +
f(this.getUTCSeconds()) + 'Z' : null;
};
String.prototype.toJSON =
Number.prototype.toJSON =
Boolean.prototype.toJSON = function (key) {
return this.valueOf();
};
}
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
gap,
indent,
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
'"' : '\\"',
'\\': '\\\\'
},
rep;
function quote(string) {
// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
escapable.lastIndex = 0;
return escapable.test(string) ?
'"' + string.replace(escapable, function (a) {
var c = meta[a];
return typeof c === 'string' ? c :
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
}) + '"' :
'"' + string + '"';
}
function str(key, holder) {
// Produce a string from holder[key].
var i, // The loop counter.
k, // The member key.
v, // The member value.
length,
mind = gap,
partial,
value = holder[key];
// If the value has a toJSON method, call it to obtain a replacement value.
if (value && typeof value === 'object' &&
typeof value.toJSON === 'function') {
value = value.toJSON(key);
}
// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
if (typeof rep === 'function') {
value = rep.call(holder, key, value);
}
// What happens next depends on the value's type.
switch (typeof value) {
case 'string':
return quote(value);
case 'number':
// JSON numbers must be finite. Encode non-finite numbers as null.
return isFinite(value) ? String(value) : 'null';
case 'boolean':
case 'null':
// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
return String(value);
// If the type is 'object', we might be dealing with an object or an array or
// null.
case 'object':
// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
if (!value) {
return 'null';
}
// Make an array to hold the partial results of stringifying this object value.
gap += indent;
partial = [];
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
length = value.length;
for (i = 0; i < length; i += 1) {
partial[i] = str(i, value) || 'null';
}
// Join all of the elements together, separated with commas, and wrap them in
// brackets.
v = partial.length === 0 ? '[]' :
gap ? '[\n' + gap +
partial.join(',\n' + gap) + '\n' +
mind + ']' :
'[' + partial.join(',') + ']';
gap = mind;
return v;
}
// If the replacer is an array, use it to select the members to be stringified.
if (rep && typeof rep === 'object') {
length = rep.length;
for (i = 0; i < length; i += 1) {
k = rep[i];
if (typeof k === 'string') {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
} else {
// Otherwise, iterate through all of the keys in the object.
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
partial.push(quote(k) + (gap ? ': ' : ':') + v);
}
}
}
}
// Join all of the member texts together, separated with commas,
// and wrap them in braces.
v = partial.length === 0 ? '{}' :
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
mind + '}' : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
}
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
JSON.stringify = function (value, replacer, space) {
// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
var i;
gap = '';
indent = '';
// If the space parameter is a number, make an indent string containing that
// many spaces.
if (typeof space === 'number') {
for (i = 0; i < space; i += 1) {
indent += ' ';
}
// If the space parameter is a string, it will be used as the indent string.
} else if (typeof space === 'string') {
indent = space;
}
// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
rep = replacer;
if (replacer && typeof replacer !== 'function' &&
(typeof replacer !== 'object' ||
typeof replacer.length !== 'number')) {
throw new Error('JSON.stringify');
}
// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
return str('', {'': value});
};
}
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
var j;
function walk(holder, key) {
// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
var k, v, value = holder[key];
if (value && typeof value === 'object') {
for (k in value) {
if (Object.hasOwnProperty.call(value, k)) {
v = walk(value, k);
if (v !== undefined) {
value[k] = v;
} else {
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}
// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
cx.lastIndex = 0;
if (cx.test(text)) {
text = text.replace(cx, function (a) {
return '\\u' +
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');
// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
return typeof reviver === 'function' ?
walk({'': j}, '') : j;
}
// If the text is not JSON parseable, then a SyntaxError is thrown.
throw new SyntaxError('JSON.parse');
};
}
}());

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,40 @@
describe('Date', function () {
describe('now', function () {
it('should be the current time', function () {
expect(Date.now() === new Date().getTime()).toBe(true);
});
});
describe("parse", function () {
// TODO: Write the rest of the test.
it('should support extended years', function () {
expect(Date.parse('0001-01-01T00:00:00Z')).toBe(-62135596800000);
expect(Date.parse('+275760-09-13T00:00:00.000Z')).toBe(8.64e15);
expect(Date.parse('+033658-09-27T01:46:40.000Z')).toBe(1e15);
expect(Date.parse('-000001-01-01T00:00:00Z')).toBe(-62198755200000);
expect(Date.parse('+002009-12-15T00:00:00Z')).toBe(1260835200000);
});
});
describe("toISOString", function () {
// TODO: write the rest of the test.
it('should support extended years', function () {
expect(new Date(-62198755200000).toISOString().indexOf('-000001-01-01')).toBe(0);
expect(new Date(8.64e15).toISOString().indexOf('+275760-09-13')).toBe(0);
});
});
describe("toJSON", function () {
it('should return the isoString when stringified', function () {
var date = new Date();
expect(JSON.stringify(date.toISOString())).toBe(JSON.stringify(date));
})
});
});

Просмотреть файл

@ -0,0 +1,137 @@
describe('Function', function() {
"use strict";
describe('bind', function() {
var actual, expected,
testSubject;
testSubject = {
push: function(o) {
this.a.push(o);
}
};
function func() {
Array.prototype.forEach.call(arguments, function(a) {
this.push(a);
}, this);
return this;
};
beforeEach(function() {
actual = [];
testSubject.a = [];
});
it('binds properly without a context', function() {
var context;
testSubject.func = function() {
context = this;
}.bind();
testSubject.func();
expect(context).toBe(function() {return this}.call());
});
it('binds properly without a context, and still supplies bound arguments', function() {
var a, context;
testSubject.func = function() {
a = Array.prototype.slice.call(arguments);
context = this;
}.bind(undefined, 1,2,3);
testSubject.func(1,2,3);
expect(a).toEqual([1,2,3,1,2,3]);
expect(context).toBe(function() {return this}.call());
});
it('binds a context properly', function() {
testSubject.func = func.bind(actual);
testSubject.func(1,2,3);
expect(actual).toEqual([1,2,3]);
expect(testSubject.a).toEqual([]);
});
it('binds a context and supplies bound arguments', function() {
testSubject.func = func.bind(actual, 1,2,3);
testSubject.func(4,5,6);
expect(actual).toEqual([1,2,3,4,5,6]);
expect(testSubject.a).toEqual([]);
});
it('returns properly without binding a context', function() {
testSubject.func = function() {
return this;
}.bind();
var context = testSubject.func();
expect(context).toBe(function() {return this}.call());
});
it('returns properly without binding a context, and still supplies bound arguments', function() {
var context;
testSubject.func = function() {
context = this;
return Array.prototype.slice.call(arguments);
}.bind(undefined, 1,2,3);
actual = testSubject.func(1,2,3);
expect(context).toBe(function() {return this}.call());
expect(actual).toEqual([1,2,3,1,2,3]);
});
it('returns properly while binding a context properly', function() {
var ret;
testSubject.func = func.bind(actual);
ret = testSubject.func(1,2,3);
expect(ret).toBe(actual);
expect(ret).not.toBe(testSubject);
});
it('returns properly while binding a context and supplies bound arguments', function() {
var ret;
testSubject.func = func.bind(actual, 1,2,3);
ret = testSubject.func(4,5,6);
expect(ret).toBe(actual);
expect(ret).not.toBe(testSubject);
});
it('passes the correct arguments as a constructor', function() {
var ret, expected = { name: "Correct" };
testSubject.func = function(arg) {
return arg;
}.bind({ name: "Incorrect" });
ret = new testSubject.func(expected);
expect(ret).toBe(expected);
});
it('returns the return value of the bound function when called as a constructor', function () {
var oracle = [1, 2, 3];
var subject = function () {
return oracle;
}.bind(null);
var result = new subject;
expect(result).toBe(oracle);
});
it('returns the correct value if constructor returns primitive', function() {
var oracle = [1, 2, 3];
var subject = function () {
return oracle;
}.bind(null);
var result = new subject;
expect(result).toBe(oracle);
oracle = {};
result = new subject;
expect(result).toBe(oracle);
oracle = function(){};
result = new subject;
expect(result).toBe(oracle);
oracle = "asdf";
result = new subject;
expect(result).not.toBe(oracle);
oracle = null;
result = new subject;
expect(result).not.toBe(oracle);
oracle = true;
result = new subject;
expect(result).not.toBe(oracle);
oracle = 1;
result = new subject;
expect(result).not.toBe(oracle);
});
});
});

Просмотреть файл

@ -0,0 +1,84 @@
describe('Object', function () {
"use strict";
describe("Object.keys", function () {
var obj = {
"str": "boz",
"obj": { },
"arr": [],
"bool": true,
"num": 42,
"null": null,
"undefined": undefined
};
var loopedValues = [];
for (var k in obj) {
loopedValues.push(k);
}
var keys = Object.keys(obj);
it('should have correct length', function () {
expect(keys.length).toBe(7);
});
it('should return an Array', function () {
expect(Array.isArray(keys)).toBe(true);
});
it('should return names which are own properties', function () {
keys.forEach(function (name) {
expect(obj.hasOwnProperty(name)).toBe(true);
});
});
it('should return names which are enumerable', function () {
keys.forEach(function (name) {
expect(loopedValues.indexOf(name)).toNotBe(-1);
})
});
it('should throw error for non object', function () {
var e = {};
expect(function () {
try {
Object.keys(42)
} catch (err) {
throw e;
}
}).toThrow(e);
});
});
describe("Object.isExtensible", function () {
var obj = { };
it('should return true if object is extensible', function () {
expect(Object.isExtensible(obj)).toBe(true);
});
it('should return false if object is not extensible', function () {
expect(Object.isExtensible(Object.preventExtensions(obj))).toBe(false);
});
it('should return false if object is seal', function () {
expect(Object.isExtensible(Object.seal(obj))).toBe(false);
});
it('should return false if object is freeze', function () {
expect(Object.isExtensible(Object.freeze(obj))).toBe(false);
});
it('should throw error for non object', function () {
var e1 = {};
expect(function () {
try {
Object.isExtensible(42)
} catch (err) {
throw e1;
}
}).toThrow(e1);
});
});
});

Просмотреть файл

@ -0,0 +1,11 @@
describe('String', function() {
"use strict";
describe("trim", function() {
var test = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFFHello, World!\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF";
it('trims all ES5 whitespace', function() {
expect(test.trim()).toEqual("Hello, World!");
expect(test.trim().length).toEqual(13);
});
});
});

Просмотреть файл

@ -0,0 +1,7 @@
language: node_js
node_js:
- 0.8
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
script: "npm install; make standalone; phantomjs test/phantom-jasmine/run_jasmine_test.coffee test/run/jasmine_test.html"

Просмотреть файл

@ -0,0 +1,69 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
"use strict";
define(
[
'./utils',
'./compose'
],
function (util, compose) {
var advice = {
around: function(base, wrapped) {
return function composedAround() {
// unpacking arguments by hand benchmarked faster
var i = 0, l = arguments.length, args = new Array(l + 1);
args[0] = base.bind(this);
for (; i < l; i++) args[i + 1] = arguments[i];
return wrapped.apply(this, args);
}
},
before: function(base, before) {
var beforeFn = (typeof before == 'function') ? before : before.obj[before.fnName];
return function composedBefore() {
beforeFn.apply(this, arguments);
return base.apply(this, arguments);
}
},
after: function(base, after) {
var afterFn = (typeof after == 'function') ? after : after.obj[after.fnName];
return function composedAfter() {
var res = (base.unbound || base).apply(this, arguments);
afterFn.apply(this, arguments);
return res;
}
},
// a mixin that allows other mixins to augment existing functions by adding additional
// code before, after or around.
withAdvice: function() {
['before', 'after', 'around'].forEach(function(m) {
this[m] = function(method, fn) {
compose.unlockProperty(this, method, function() {
if (typeof this[method] == 'function') {
return this[method] = advice[m](this[method], fn);
} else {
return this[method] = fn;
}
});
};
}, this);
}
};
return advice;
}
);

Просмотреть файл

@ -0,0 +1,308 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
"use strict";
define(
[
'./advice',
'./utils',
'./compose',
'./registry'
],
function(advice, utils, compose, registry) {
var functionNameRegEx = /function (.*?)\s?\(/;
var componentId = 0;
function teardownInstance(instanceInfo){
instanceInfo.events.slice().forEach(function(event) {
var args = [event.type];
event.element && args.unshift(event.element);
(typeof event.callback == 'function') && args.push(event.callback);
this.off.apply(this, args);
}, instanceInfo.instance);
}
function teardown() {
teardownInstance(registry.findInstanceInfo(this));
}
//teardown for all instances of this constructor
function teardownAll() {
var componentInfo = registry.findComponentInfo(this);
componentInfo && Object.keys(componentInfo.instances).forEach(function(k) {
var info = componentInfo.instances[k];
info.instance.teardown();
});
}
function checkSerializable(type, data) {
try {
window.postMessage(data, '*');
} catch(e) {
console.log('unserializable data for event',type,':',data);
throw new Error(
["The event", type, "on component", this.toString(), "was triggered with non-serializable data"].join(" ")
);
}
}
//common mixin allocates basic functionality - used by all component prototypes
//callback context is bound to component
function withBaseComponent() {
// delegate trigger, bind and unbind to an element
// if $element not supplied, use component's node
// other arguments are passed on
// event can be either a string specifying the type
// of the event, or a hash specifying both the type
// and a default function to be called.
this.trigger = function() {
var $element, type, data, event, defaultFn;
var lastIndex = arguments.length - 1, lastArg = arguments[lastIndex];
if (typeof lastArg != "string" && !(lastArg && lastArg.defaultBehavior)) {
lastIndex--;
data = lastArg;
}
if (lastIndex == 1) {
$element = $(arguments[0]);
event = arguments[1];
} else {
$element = this.$node;
event = arguments[0];
}
if (event.defaultBehavior) {
defaultFn = event.defaultBehavior;
event = $.Event(event.type);
}
type = event.type || event;
if (window.DEBUG && window.DEBUG.enabled && window.postMessage) {
checkSerializable.call(this, type, data);
}
if (typeof this.attr.eventData === 'object') {
data = $.extend(true, {}, this.attr.eventData, data);
}
$element.trigger((event || type), data);
if (defaultFn && !event.isDefaultPrevented()) {
(this[defaultFn] || defaultFn).call(this);
}
return $element;
};
this.on = function() {
var $element, type, callback, originalCb;
var lastIndex = arguments.length - 1, origin = arguments[lastIndex];
if (typeof origin == "object") {
//delegate callback
originalCb = utils.delegate(
this.resolveDelegateRules(origin)
);
} else {
originalCb = origin;
}
if (lastIndex == 2) {
$element = $(arguments[0]);
type = arguments[1];
} else {
$element = this.$node;
type = arguments[0];
}
if (typeof originalCb != 'function' && typeof originalCb != 'object') {
throw new Error("Unable to bind to '" + type + "' because the given callback is not a function or an object");
}
callback = originalCb.bind(this);
callback.target = originalCb;
// if the original callback is already branded by jQuery's guid, copy it to the context-bound version
if (originalCb.guid) {
callback.guid = originalCb.guid;
}
$element.on(type, callback);
// get jquery's guid from our bound fn, so unbinding will work
originalCb.guid = callback.guid;
return callback;
};
this.off = function() {
var $element, type, callback;
var lastIndex = arguments.length - 1;
if (typeof arguments[lastIndex] == "function") {
callback = arguments[lastIndex];
lastIndex -= 1;
}
if (lastIndex == 1) {
$element = $(arguments[0]);
type = arguments[1];
} else {
$element = this.$node;
type = arguments[0];
}
return $element.off(type, callback);
};
this.resolveDelegateRules = function(ruleInfo) {
var rules = {};
Object.keys(ruleInfo).forEach(function(r) {
if (!r in this.attr) {
throw new Error('Component "' + this.toString() + '" wants to listen on "' + r + '" but no such attribute was defined.');
}
rules[this.attr[r]] = ruleInfo[r];
}, this);
return rules;
};
this.defaultAttrs = function(defaults) {
utils.push(this.defaults, defaults, true) || (this.defaults = defaults);
};
this.select = function(attributeKey) {
return this.$node.find(this.attr[attributeKey]);
};
this.initialize = $.noop;
this.teardown = teardown;
}
function attachTo(selector/*, options args */) {
// unpacking arguments by hand benchmarked faster
var l = arguments.length;
var args = new Array(l - 1);
for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
if (!selector) {
throw new Error("Component needs to be attachTo'd a jQuery object, native node or selector string");
}
var options = utils.merge.apply(utils, args);
$(selector).each(function(i, node) {
var rawNode = node.jQuery ? node[0] : node;
var componentInfo = registry.findComponentInfo(this)
if (componentInfo && componentInfo.isAttachedTo(rawNode)) {
//already attached
return;
}
new this(node, options);
}.bind(this));
}
// define the constructor for a custom component type
// takes an unlimited number of mixin functions as arguments
// typical api call with 3 mixins: define(timeline, withTweetCapability, withScrollCapability);
function define(/*mixins*/) {
// unpacking arguments by hand benchmarked faster
var l = arguments.length;
var mixins = new Array(l);
for (var i = 0; i < l; i++) mixins[i] = arguments[i];
Component.toString = function() {
var prettyPrintMixins = mixins.map(function(mixin) {
if (mixin.name == null) {
//function name property not supported by this browser, use regex
var m = mixin.toString().match(functionNameRegEx);
return (m && m[1]) ? m[1] : "";
} else {
return (mixin.name != "withBaseComponent") ? mixin.name : "";
}
}).filter(Boolean).join(', ');
return prettyPrintMixins;
};
if (window.DEBUG && window.DEBUG.enabled) {
Component.describe = Component.toString();
}
//'options' is optional hash to be merged with 'defaults' in the component definition
function Component(node, options) {
options = options || {};
this.identity = componentId++;
if (!node) {
throw new Error("Component needs a node");
}
if (node.jquery) {
this.node = node[0];
this.$node = node;
} else {
this.node = node;
this.$node = $(node);
}
this.toString = Component.toString;
if (window.DEBUG && window.DEBUG.enabled) {
this.describe = this.toString();
}
//merge defaults with supplied options
//put options in attr.__proto__ to avoid merge overhead
var attr = Object.create(options);
for (var key in this.defaults) {
if (!options.hasOwnProperty(key)) {
attr[key] = this.defaults[key];
}
}
this.attr = attr;
Object.keys(this.defaults || {}).forEach(function(key) {
if (this.defaults[key] === null && this.attr[key] === null) {
throw new Error('Required attribute "' + key + '" not specified in attachTo for component "' + this.toString() + '".');
}
}, this);
this.initialize.call(this, options);
}
Component.attachTo = attachTo;
Component.teardownAll = teardownAll;
// prepend common mixins to supplied list, then mixin all flavors
mixins.unshift(withBaseComponent, advice.withAdvice, registry.withRegistration);
compose.mixin(Component.prototype, mixins);
return Component;
}
define.teardownAll = function() {
registry.components.slice().forEach(function(c) {
c.component.teardownAll();
});
registry.reset();
};
return define;
}
);

Просмотреть файл

@ -0,0 +1,86 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
"use strict";
define(
[
'./utils',
'../tools/debug/debug'
],
function(util, debug) {
//enumerables are shims - getOwnPropertyDescriptor shim doesn't work
var canWriteProtect = debug.enabled && !util.isEnumerable(Object, 'getOwnPropertyDescriptor');
//whitelist of unlockable property names
var dontLock = ['mixedIn'];
if (canWriteProtect) {
//IE8 getOwnPropertyDescriptor is built-in but throws exeption on non DOM objects
try {
Object.getOwnPropertyDescriptor(Object, 'keys');
} catch(e) {
canWriteProtect = false;
}
}
function setPropertyWritability(obj, isWritable) {
if (!canWriteProtect) {
return;
}
var props = Object.create(null);
Object.keys(obj).forEach(
function (key) {
if (dontLock.indexOf(key) < 0) {
var desc = Object.getOwnPropertyDescriptor(obj, key);
desc.writable = isWritable;
props[key] = desc;
}
}
);
Object.defineProperties(obj, props);
}
function unlockProperty(obj, prop, op) {
var writable;
if (!canWriteProtect || !obj.hasOwnProperty(prop)) {
op.call(obj);
return;
}
writable = Object.getOwnPropertyDescriptor(obj, prop).writable;
Object.defineProperty(obj, prop, { writable: true });
op.call(obj);
Object.defineProperty(obj, prop, { writable: writable });
}
function mixin(base, mixins) {
base.mixedIn = base.hasOwnProperty('mixedIn') ? base.mixedIn : [];
mixins.forEach(function(mixin) {
if (base.mixedIn.indexOf(mixin) == -1) {
setPropertyWritability(base, false);
mixin.call(base);
base.mixedIn.push(mixin);
}
});
setPropertyWritability(base, true);
}
return {
mixin: mixin,
unlockProperty: unlockProperty
};
}
);

Просмотреть файл

@ -0,0 +1,30 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
define(
[
'./advice',
'./component',
'./compose',
'./logger',
'./registry',
'./utils'
],
function (advice, component, compose, logger, registry, utils) {
return {
advice: advice,
component: component,
compose: compose,
logger: logger,
registry: registry,
utils: utils
};
}
);

Просмотреть файл

@ -0,0 +1,93 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
"use strict";
define(
[
'./compose',
'./utils'
],
function (compose, util) {
var actionSymbols = {
on:'<-',
trigger: '->',
off: 'x '
};
function elemToString(elem) {
var tagStr = elem.tagName ? elem.tagName.toLowerCase() : elem.toString();
var classStr = elem.className ? "." + (elem.className) : "";
var result = tagStr + classStr;
return elem.tagName ? ['\'', '\''].join(result) : result;
}
function log(action, component, eventArgs) {
var name, elem, fn, fnName, logFilter, toRegExp, actionLoggable, nameLoggable;
if (typeof eventArgs[eventArgs.length-1] == 'function') {
fn = eventArgs.pop();
fn = fn.unbound || fn; //use unbound version if any (better info)
}
if (typeof eventArgs[eventArgs.length - 1] == 'object') {
eventArgs.pop(); //trigger data arg - not logged right now
}
if (eventArgs.length == 2) {
elem = eventArgs[0];
name = eventArgs[1];
} else {
elem = component.$node[0];
name = eventArgs[0];
}
if (window.DEBUG && window.DEBUG.enabled) {
logFilter = DEBUG.events.logFilter;
// no regex for you, actions...
actionLoggable = logFilter.actions=="all" || (logFilter.actions.indexOf(action) > -1);
// event name filter allow wildcards or regex...
toRegExp = function(expr) {
return expr.test ? expr : new RegExp("^" + expr.replace(/\*/g, ".*") + "$");
};
nameLoggable =
logFilter.eventNames=="all" ||
logFilter.eventNames.some(function(e) {return toRegExp(e).test(name)});
if (actionLoggable && nameLoggable) {
console.info(
actionSymbols[action],
action,
'[' + name + ']',
elemToString(elem),
component.constructor.toString(),
fn && (fnName = fn.name || fn.displayName) && '-> ' + fnName
);
}
}
}
function withLogging() {
this.before('trigger', function() {
log('trigger', this, util.toArray(arguments));
});
this.before('on', function() {
log('on', this, util.toArray(arguments));
});
this.before('off', function(eventArgs) {
log('off', this, util.toArray(arguments));
});
}
return withLogging;
}
);

Просмотреть файл

@ -0,0 +1,220 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
"use strict";
define(
[
'./utils'
],
function (util) {
function parseEventArgs(instance, args) {
var element, type, callback;
var end = args.length;
if (typeof args[end - 1] === 'function') {
end -= 1;
callback = args[end];
}
if (typeof args[end - 1] === 'object') {
end -= 1;
}
if (end == 2) {
element = args[0];
type = args[1];
} else {
element = instance.node;
type = args[0];
}
return {
element: element,
type: type,
callback: callback
};
}
function matchEvent(a, b) {
return (
(a.element == b.element) &&
(a.type == b.type) &&
(b.callback == null || (a.callback == b.callback))
);
}
function Registry() {
var registry = this;
(this.reset = function() {
this.components = [];
this.allInstances = {};
this.events = [];
}).call(this);
function ComponentInfo(component) {
this.component = component;
this.attachedTo = [];
this.instances = {};
this.addInstance = function(instance) {
var instanceInfo = new InstanceInfo(instance);
this.instances[instance.identity] = instanceInfo;
this.attachedTo.push(instance.node);
return instanceInfo;
}
this.removeInstance = function(instance) {
delete this.instances[instance.identity];
var indexOfNode = this.attachedTo.indexOf(instance.node);
(indexOfNode > -1) && this.attachedTo.splice(indexOfNode, 1);
if (!this.instances.length) {
//if I hold no more instances remove me from registry
registry.removeComponentInfo(this);
}
}
this.isAttachedTo = function(node) {
return this.attachedTo.indexOf(node) > -1;
}
}
function InstanceInfo(instance) {
this.instance = instance;
this.events = [];
this.addBind = function(event) {
this.events.push(event);
registry.events.push(event);
};
this.removeBind = function(event) {
for (var i = 0, e; e = this.events[i]; i++) {
if (matchEvent(e, event)) {
this.events.splice(i, 1);
}
}
}
}
this.addInstance = function(instance) {
var component = this.findComponentInfo(instance);
if (!component) {
component = new ComponentInfo(instance.constructor);
this.components.push(component);
}
var inst = component.addInstance(instance);
this.allInstances[instance.identity] = inst;
return component;
};
this.removeInstance = function(instance) {
var index, instInfo = this.findInstanceInfo(instance);
//remove from component info
var componentInfo = this.findComponentInfo(instance);
componentInfo && componentInfo.removeInstance(instance);
//remove from registry
delete this.allInstances[instance.identity];
};
this.removeComponentInfo = function(componentInfo) {
var index = this.components.indexOf(componentInfo);
(index > -1) && this.components.splice(index, 1);
};
this.findComponentInfo = function(which) {
var component = which.attachTo ? which : which.constructor;
for (var i = 0, c; c = this.components[i]; i++) {
if (c.component === component) {
return c;
}
}
return null;
};
this.findInstanceInfo = function(instance) {
return this.allInstances[instance.identity] || null;
};
this.findInstanceInfoByNode = function(node) {
var result = [];
Object.keys(this.allInstances).forEach(function(k) {
var thisInstanceInfo = this.allInstances[k];
if(thisInstanceInfo.instance.node === node) {
result.push(thisInstanceInfo);
}
}, this);
return result;
};
this.on = function(componentOn) {
var instance = registry.findInstanceInfo(this), boundCallback;
// unpacking arguments by hand benchmarked faster
var l = arguments.length, i = 1;
var otherArgs = new Array(l - 1);
for (; i < l; i++) otherArgs[i - 1] = arguments[i];
if (instance) {
boundCallback = componentOn.apply(null, otherArgs);
if (boundCallback) {
otherArgs[otherArgs.length-1] = boundCallback;
}
var event = parseEventArgs(this, otherArgs);
instance.addBind(event);
}
};
this.off = function(el, type, callback) {
var event = parseEventArgs(this, arguments),
instance = registry.findInstanceInfo(this);
if (instance) {
instance.removeBind(event);
}
};
//debug tools may want to add advice to trigger
if (window.DEBUG && DEBUG.enabled) {
registry.trigger = new Function;
}
this.teardown = function() {
registry.removeInstance(this);
};
this.withRegistration = function() {
this.before('initialize', function() {
registry.addInstance(this);
});
this.around('on', registry.on);
this.after('off', registry.off);
//debug tools may want to add advice to trigger
window.DEBUG && DEBUG.enabled && this.after('trigger', registry.trigger);
this.after('teardown', {obj:registry, fnName:'teardown'});
};
}
return new Registry;
}
);

Просмотреть файл

@ -0,0 +1,236 @@
// ==========================================
// Copyright 2013 Twitter, Inc
// Licensed under The MIT License
// http://opensource.org/licenses/MIT
// ==========================================
"use strict";
define(
[],
function () {
var arry = [];
var DEFAULT_INTERVAL = 100;
var utils = {
isDomObj: function(obj) {
return !!(obj.nodeType || (obj === window));
},
toArray: function(obj, from) {
return arry.slice.call(obj, from);
},
// returns new object representing multiple objects merged together
// optional final argument is boolean which specifies if merge is recursive
// original objects are unmodified
//
// usage:
// var base = {a:2, b:6};
// var extra = {b:3, c:4};
// merge(base, extra); //{a:2, b:3, c:4}
// base; //{a:2, b:6}
//
// var base = {a:2, b:6};
// var extra = {b:3, c:4};
// var extraExtra = {a:4, d:9};
// merge(base, extra, extraExtra); //{a:4, b:3, c:4. d: 9}
// base; //{a:2, b:6}
//
// var base = {a:2, b:{bb:4, cc:5}};
// var extra = {a:4, b:{cc:7, dd:1}};
// merge(base, extra, true); //{a:4, b:{bb:4, cc:7, dd:1}}
// base; //{a:2, b:6}
merge: function(/*obj1, obj2,....deepCopy*/) {
// unpacking arguments by hand benchmarked faster
var l = arguments.length,
i = 0,
args = new Array(l + 1);
for (; i < l; i++) args[i + 1] = arguments[i];
if (l === 0) {
return {};
}
//start with empty object so a copy is created
args[0] = {};
if (args[args.length - 1] === true) {
//jquery extend requires deep copy as first arg
args.pop();
args.unshift(true);
}
return $.extend.apply(undefined, args);
},
// updates base in place by copying properties of extra to it
// optionally clobber protected
// usage:
// var base = {a:2, b:6};
// var extra = {c:4};
// push(base, extra); //{a:2, b:6, c:4}
// base; //{a:2, b:6, c:4}
//
// var base = {a:2, b:6};
// var extra = {b: 4 c:4};
// push(base, extra, true); //Error ("utils.push attempted to overwrite 'b' while running in protected mode")
// base; //{a:2, b:6}
//
// objects with the same key will merge recursively when protect is false
// eg:
// var base = {a:16, b:{bb:4, cc:10}};
// var extra = {b:{cc:25, dd:19}, c:5};
// push(base, extra); //{a:16, {bb:4, cc:25, dd:19}, c:5}
//
push: function(base, extra, protect) {
if (base) {
Object.keys(extra || {}).forEach(function(key) {
if (base[key] && protect) {
throw Error("utils.push attempted to overwrite '" + key + "' while running in protected mode");
}
if (typeof base[key] == "object" && typeof extra[key] == "object") {
//recurse
this.push(base[key], extra[key]);
} else {
//no protect, so extra wins
base[key] = extra[key];
}
}, this);
}
return base;
},
isEnumerable: function(obj, property) {
return Object.keys(obj).indexOf(property) > -1;
},
//build a function from other function(s)
//util.compose(a,b,c) -> a(b(c()));
//implementation lifted from underscore.js (c) 2009-2012 Jeremy Ashkenas
compose: function() {
var funcs = arguments;
return function() {
var args = arguments;
for (var i = funcs.length-1; i >= 0; i--) {
args = [funcs[i].apply(this, args)];
}
return args[0];
};
},
// Can only unique arrays of homogeneous primitives, e.g. an array of only strings, an array of only booleans, or an array of only numerics
uniqueArray: function(array) {
var u = {}, a = [];
for (var i = 0, l = array.length; i < l; ++i) {
if (u.hasOwnProperty(array[i])) {
continue;
}
a.push(array[i]);
u[array[i]] = 1;
}
return a;
},
debounce: function(func, wait, immediate) {
if (typeof wait != 'number') {
wait = DEFAULT_INTERVAL;
}
var timeout, result;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) {
result = func.apply(context, args);
}
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
}
return result;
};
},
throttle: function(func, wait) {
if (typeof wait != 'number') {
wait = DEFAULT_INTERVAL;
}
var context, args, timeout, throttling, more, result;
var whenDone = this.debounce(function(){
more = throttling = false;
}, wait);
return function() {
context = this; args = arguments;
var later = function() {
timeout = null;
if (more) {
result = func.apply(context, args);
}
whenDone();
};
if (!timeout) {
timeout = setTimeout(later, wait);
}
if (throttling) {
more = true;
} else {
throttling = true;
result = func.apply(context, args);
}
whenDone();
return result;
};
},
countThen: function(num, base) {
return function() {
if (!--num) { return base.apply(this, arguments); }
};
},
delegate: function(rules) {
return function(e, data) {
var target = $(e.target), parent;
Object.keys(rules).forEach(function(selector) {
if ((parent = target.closest(selector)).length) {
data = data || {};
data.el = parent[0];
return rules[selector].apply(this, [e, data]);
}
}, this);
};
}
};
return utils;
}
);

Просмотреть файл

@ -0,0 +1,157 @@
"use strict";
define(
[
'../../lib/registry',
'../../lib/utils'
],
function(registry, utils) {
var logFilter;
//******************************************************************************************
// Search object model
//******************************************************************************************
function traverse(util, searchTerm, options) {
var options = options || {};
var obj = options.obj || window;
var path = options.path || ((obj==window) ? "window" : "");
var props = Object.keys(obj);
props.forEach(function(prop) {
if ((tests[util] || util)(searchTerm, obj, prop)){
console.log([path, ".", prop].join(""), "->",["(", typeof obj[prop], ")"].join(""), obj[prop]);
}
if(Object.prototype.toString.call(obj[prop])=="[object Object]" && (obj[prop] != obj) && path.split(".").indexOf(prop) == -1) {
traverse(util, searchTerm, {obj: obj[prop], path: [path,prop].join(".")});
}
});
}
function search(util, expected, searchTerm, options) {
if (!expected || typeof searchTerm == expected) {
traverse(util, searchTerm, options);
} else {
console.error([searchTerm, 'must be', expected].join(' '))
}
}
var tests = {
'name': function(searchTerm, obj, prop) {return searchTerm == prop},
'nameContains': function(searchTerm, obj, prop) {return prop.indexOf(searchTerm)>-1},
'type': function(searchTerm, obj, prop) {return obj[prop] instanceof searchTerm},
'value': function(searchTerm, obj, prop) {return obj[prop] === searchTerm},
'valueCoerced': function(searchTerm, obj, prop) {return obj[prop] == searchTerm}
}
function byName(searchTerm, options) {search('name', 'string', searchTerm, options);};
function byNameContains(searchTerm, options) {search('nameContains', 'string', searchTerm, options);};
function byType(searchTerm, options) {search('type', 'function', searchTerm, options);};
function byValue(searchTerm, options) {search('value', null, searchTerm, options);};
function byValueCoerced(searchTerm, options) {search('valueCoerced', null, searchTerm, options);};
function custom(fn, options) {traverse(fn, null, options);};
//******************************************************************************************
// Event logging
//******************************************************************************************
var ALL = 'all'; //no filter
//no logging by default
var defaultEventNamesFilter = [];
var defaultActionsFilter = [];
var logFilter = retrieveLogFilter();
function filterEventLogsByAction(/*actions*/) {
var actions = [].slice.call(arguments);
logFilter.eventNames.length || (logFilter.eventNames = ALL);
logFilter.actions = actions.length ? actions : ALL;
saveLogFilter();
}
function filterEventLogsByName(/*eventNames*/) {
var eventNames = [].slice.call(arguments);
logFilter.actions.length || (logFilter.actions = ALL);
logFilter.eventNames = eventNames.length ? eventNames : ALL;
saveLogFilter();
}
function hideAllEventLogs() {
logFilter.actions = [];
logFilter.eventNames = [];
saveLogFilter();
}
function showAllEventLogs() {
logFilter.actions = ALL;
logFilter.eventNames = ALL;
saveLogFilter();
}
function saveLogFilter() {
if (window.localStorage) {
localStorage.setItem('logFilter_eventNames', logFilter.eventNames);
localStorage.setItem('logFilter_actions', logFilter.actions);
}
}
function retrieveLogFilter() {
var result = {
eventNames: (window.localStorage && localStorage.getItem('logFilter_eventNames')) || defaultEventNamesFilter,
actions: (window.localStorage && localStorage.getItem('logFilter_actions')) || defaultActionsFilter
};
//reconstitute arrays
Object.keys(result).forEach(function(k) {
var thisProp = result[k];
if (typeof thisProp == 'string' && thisProp !== ALL) {
result[k] = thisProp.split(',');
}
});
return result;
}
return {
enable: function(enable) {
this.enabled = !!enable;
if (enable && window.console) {
console.info('Booting in DEBUG mode');
console.info('You can configure event logging with DEBUG.events.logAll()/logNone()/logByName()/logByAction()');
}
window.DEBUG = this;
},
find: {
byName: byName,
byNameContains: byNameContains,
byType: byType,
byValue: byValue,
byValueCoerced: byValueCoerced,
custom: custom
},
events: {
logFilter: logFilter,
// Accepts any number of action args
// e.g. DEBUG.events.logByAction("on", "off")
logByAction: filterEventLogsByAction,
// Accepts any number of event name args (inc. regex or wildcards)
// e.g. DEBUG.events.logByName(/ui.*/, "*Thread*");
logByName: filterEventLogsByName,
logAll: showAllEventLogs,
logNone: hideAllEventLogs
}
};
}
);

Просмотреть файл

@ -0,0 +1,19 @@
Copyright (c) 2013 Twitter, Inc and others
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Просмотреть файл

@ -0,0 +1,145 @@
# jasmine-flight [![Build Status](https://travis-ci.org/flightjs/jasmine-flight.png?branch=master)](http://travis-ci.org/flightjs/jasmine-flight)
Extensions to the Jasmine test framework for use with [Flight](https://github.com/flightjs/flight)
# Getting started
Include [jasmine-flight.js](https://raw.github.com/flightjs/jasmine-flight/master/lib/jasmine-flight.js)
in your app and load it in your test runner.
Or install it with [Bower](http://bower.io/):
```bash
bower install --save-dev jasmine-flight
```
**N.B.** jasmine-flight depends on
[jasmine](https://github.com/pivotal/jasmine) and
[jasmine-jquery](https://github.com/velesin/jasmine-jquery)
## Components
```javascript
describeComponent('path/to/component', function () {
beforeEach(function () {
setupComponent();
});
it('should do x', function () {
// a component instance is now accessible as this.component
// the component root node is attached to the DOM
// the component root node is also available as this.$node
});
});
```
## Mixins
```javascript
describeMixin('path/to/mixin', function () {
// initialize the component and attach it to the DOM
beforeEach(function () {
setupComponent();
});
it('should do x', function () {
expect(this.component.doSomething()).toBe(expected);
});
});
```
## Event spy
```javascript
describeComponent('data/twitter_profile', function () {
beforeEach(function () {
setupComponent();
});
describe('listens for uiNeedsTwitterUserId', function () {
// was the event triggered?
it('and triggers dataTwitterUserId', function () {
var eventSpy = spyOnEvent(document, 'dataTwitterProfile');
$(document).trigger('uiNeedsTwitterUserId', {
screen_name: 'tbrd'
});
expect(eventSpy).toHaveBeenTriggeredOn(document);
});
// is the user id correct?
it('and has correct id', function () {
var eventSpy = spyOnEvent(document, 'dataTwitterUserId');
$(document).trigger('uiNeedsTwitteruserId', {
screen_name: 'tbrd'
});
expect(eventSpy.mostRecentCall.data).toEqual({
screen_name: 'tbrd',
id: 4149861
});
});
});
});
```
## setupComponent
```javascript
setupComponent(optionalFixture, optionalOptions);
```
Calling `setupComponent` twice will create an instance, tear it down and create a new one.
### HTML Fixtures
```javascript
describeComponent('ui/twitter_profile', function () {
// is the component attached to the fixture?
it('this.component.$node has class "foo"', function () {
setupComponent('<span class="foo">Test</span>');
expect(this.component.$node).toHaveClass('foo');
});
});
```
### Component Options
```javascript
describeComponent('data/twitter_profile', function () {
// is the option set correctly?
it('this.component.attr.baseUrl is set', function () {
setupComponent({
baseUrl: 'http://twitter.com/1.1/'
});
expect(this.component.attr.baseUrl).toBe('http://twitter.com/1.1/');
});
});
```
# Teardown
Components are automatically torn down after each test.
## Contributing to this project
Anyone and everyone is welcome to contribute. Please take a moment to
review the [guidelines for contributing](CONTRIBUTING.md).
* [Bug reports](CONTRIBUTING.md#bugs)
* [Feature requests](CONTRIBUTING.md#features)
* [Pull requests](CONTRIBUTING.md#pull-requests)
## Authors
* [@tbrd](http://github.com/tbrd)
## Thanks
* [@esbie](http://github.com/esbie) and
[@skilldrick](http://github.com/skilldrick) for creating the original
`describeComponent` & `describeMixin` methods.
## License
Copyright 2013 Twitter, Inc and other contributors.
Licensed under the MIT License

Просмотреть файл

@ -0,0 +1,30 @@
{
"name": "jasmine-flight",
"version": "1.1.0",
"description": "Extensions to the Jasmine test framework for use with Flight",
"main": "lib/jasmine-flight.js",
"keywords": [
"flight",
"jasmine",
"test"
],
"ignore": [
".*",
"test",
"package.json",
"karma.conf.js",
"CONTRIBUTING.md",
"CHANGELOG.md"
],
"devDependencies": {
"flight": "~1.0.9"
},
"gitHead": "5174302b9a87ebdda99de6a436ec2a64200fc5ff",
"readme": "# jasmine-flight [![Build Status](https://travis-ci.org/flightjs/jasmine-flight.png?branch=master)](http://travis-ci.org/flightjs/jasmine-flight)\n\nExtensions to the Jasmine test framework for use with [Flight](https://github.com/flightjs/flight)\n\n# Getting started\n\nInclude [jasmine-flight.js](https://raw.github.com/flightjs/jasmine-flight/master/lib/jasmine-flight.js)\nin your app and load it in your test runner.\n\nOr install it with [Bower](http://bower.io/):\n\n```bash\nbower install --save-dev jasmine-flight\n```\n\n**N.B.** jasmine-flight depends on\n[jasmine](https://github.com/pivotal/jasmine) and\n[jasmine-jquery](https://github.com/velesin/jasmine-jquery)\n\n## Components\n\n```javascript\ndescribeComponent('path/to/component', function () {\n beforeEach(function () {\n setupComponent();\n });\n\n it('should do x', function () {\n // a component instance is now accessible as this.component\n // the component root node is attached to the DOM\n // the component root node is also available as this.$node\n });\n});\n```\n\n## Mixins\n\n```javascript\ndescribeMixin('path/to/mixin', function () {\n // initialize the component and attach it to the DOM\n beforeEach(function () {\n setupComponent();\n });\n\n it('should do x', function () {\n expect(this.component.doSomething()).toBe(expected);\n });\n});\n```\n\n## Event spy\n\n```javascript\ndescribeComponent('data/twitter_profile', function () {\n beforeEach(function () {\n setupComponent();\n });\n\n describe('listens for uiNeedsTwitterUserId', function () {\n // was the event triggered?\n it('and triggers dataTwitterUserId', function () {\n var eventSpy = spyOnEvent(document, 'dataTwitterProfile');\n $(document).trigger('uiNeedsTwitterUserId', {\n screen_name: 'tbrd'\n });\n expect(eventSpy).toHaveBeenTriggeredOn(document);\n });\n\n // is the user id correct?\n it('and has correct id', function () {\n var eventSpy = spyOnEvent(document, 'dataTwitterUserId');\n $(document).trigger('uiNeedsTwitteruserId', {\n screen_name: 'tbrd'\n });\n expect(eventSpy.mostRecentCall.data).toEqual({\n screen_name: 'tbrd',\n id: 4149861\n });\n });\n });\n});\n```\n\n## setupComponent\n\n```javascript\nsetupComponent(optionalFixture, optionalOptions);\n```\n\nCalling `setupComponent` twice will create an instance, tear it down and create a new one.\n\n### HTML Fixtures\n\n```javascript\ndescribeComponent('ui/twitter_profile', function () {\n // is the component attached to the fixture?\n it('this.component.$node has class \"foo\"', function () {\n setupComponent('<span class=\"foo\">Test</span>');\n expect(this.component.$node).toHaveClass('foo');\n });\n});\n```\n\n### Component Options\n\n```javascript\ndescribeComponent('data/twitter_profile', function () {\n // is the option set correctly?\n it('this.component.attr.baseUrl is set', function () {\n setupComponent({\n baseUrl: 'http://twitter.com/1.1/'\n });\n expect(this.component.attr.baseUrl).toBe('http://twitter.com/1.1/');\n });\n});\n```\n\n# Teardown\n\nComponents are automatically torn down after each test.\n\n## Contributing to this project\n\nAnyone and everyone is welcome to contribute. Please take a moment to\nreview the [guidelines for contributing](CONTRIBUTING.md).\n\n* [Bug reports](CONTRIBUTING.md#bugs)\n* [Feature requests](CONTRIBUTING.md#features)\n* [Pull requests](CONTRIBUTING.md#pull-requests)\n\n## Authors\n\n* [@tbrd](http://github.com/tbrd)\n\n## Thanks\n\n* [@esbie](http://github.com/esbie) and\n [@skilldrick](http://github.com/skilldrick) for creating the original\n `describeComponent` & `describeMixin` methods.\n\n## License\n\nCopyright 2013 Twitter, Inc and other contributors.\n\nLicensed under the MIT License\n",
"readmeFilename": "README.md",
"_id": "jasmine-flight@1.1.0",
"repository": {
"type": "git",
"url": "git://github.com/flightjs/jasmine-flight.git"
}
}

Просмотреть файл

@ -0,0 +1,444 @@
/**
* Copyright 2013, Twitter Inc. and other contributors
* Licensed under the MIT License
*/
(function (root) {
'use strict';
jasmine.flight = {};
/**
* Wrapper for describe. Load component before each test.
*
* @param componentPath
* @param specDefinitions
*/
root.describeComponent = function (componentPath, specDefinitions) {
jasmine.getEnv().describeComponent(componentPath, specDefinitions);
};
jasmine.Env.prototype.describeComponent = function (componentPath, specDefinitions) {
describe(componentPath, function () {
beforeEach(function () {
this.Component = this.component = this.$node = null;
var requireCallback = function (registry, Component) {
registry.reset();
this.Component = Component;
}.bind(this);
require(['flight/lib/registry', componentPath], requireCallback);
waitsFor(function () {
return this.Component !== null;
}.bind(this));
});
afterEach(function () {
if (this.$node) {
this.$node.remove();
this.$node = null;
}
var requireCallback = function (defineComponent) {
if (this.component) {
this.component = null;
}
this.Component = null;
defineComponent.teardownAll();
}.bind(this);
require(['flight/lib/component'], requireCallback);
waitsFor(function () {
return this.Component === null;
}.bind(this));
});
specDefinitions.apply(this);
});
};
/**
* Wrapper for describe. Load mixin before each test.
*
* @param mixinPath
* @param specDefinitions
*/
root.describeMixin = function (mixinPath, specDefinitions) {
jasmine.getEnv().describeMixin(mixinPath, specDefinitions);
};
jasmine.Env.prototype.describeMixin = function (mixinPath, specDefinitions) {
describe(mixinPath, function () {
beforeEach(function () {
this.Component = this.component = this.$node = null;
var requireCallback = function (registry, defineComponent, Mixin) {
registry.reset();
this.Component = defineComponent(function () {}, Mixin);
}.bind(this);
require(['flight/lib/registry', 'flight/lib/component', mixinPath], requireCallback);
waitsFor(function () {
return this.Component !== null;
});
});
afterEach(function () {
if (this.$node) {
this.$node.remove();
this.$node = null;
}
var requireCallback = function (defineComponent) {
if (this.component) {
this.component = null;
}
this.Component = null;
defineComponent.teardownAll();
}.bind(this);
require(['flight/lib/component'], requireCallback);
waitsFor(function () {
return this.Component === null;
}.bind(this));
});
specDefinitions.apply(this);
});
};
/**
* Wrapper for describe. Load module before each test.
*
* @param modulePath
* @param specDefinitions
*/
root.describeModule = function (modulePath, specDefinitions) {
return jasmine.getEnv().describeModule(modulePath, specDefinitions);
};
jasmine.Env.prototype.describeModule = function (modulePath, specDefinitions) {
describe(modulePath, function () {
beforeEach(function () {
this.module = null;
var requireCallback = function (module) {
this.module = module;
}.bind(this);
require([modulePath], requireCallback);
waitsFor(function () {
return this.module !== null;
});
});
specDefinitions.apply(this);
});
};
/**
* Create root node and initialize component. Fixture should be html string
* or jQuery object.
*
* @param fixture {String} (Optional)
* @param options {Options} (Optional)
*/
root.setupComponent = function (fixture, options) {
jasmine.getEnv().currentSpec.setupComponent(fixture, options);
};
jasmine.Spec.prototype.setupComponent = function (fixture, options) {
if (this.component) {
this.component.teardown();
this.$node.remove();
}
this.$node = $('<div class="component-root" />');
$('body').append(this.$node);
if (fixture instanceof jQuery || typeof fixture === 'string') {
this.$node.append(fixture);
} else {
options = fixture;
fixture = null;
}
options = options === undefined ? {} : options;
this.component = new this.Component(this.$node, options);
};
(function (namespace) {
var eventsData = {
spiedEvents: {},
handlers: []
};
namespace.formatElement = function ($element) {
var limit = 200;
var output = '';
if ($element instanceof jQuery) {
output = jasmine.JQuery.elementToString($element);
if (output.length > limit) {
output = output.slice(0, 200) + '...';
}
} else {
//$element should always be a jQuery object
output = 'element is not a jQuery object';
}
return output;
};
namespace.compareColors = function (color1, color2) {
if (color1.charAt(0) === color2.charAt(0)) {
return color1 === color2;
} else {
return namespace.hex2rgb(color1) === namespace.hex2rgb(color2);
}
};
namespace.hex2rgb = function (colorString) {
if (colorString.charAt(0) !== '#') return colorString;
// note: hexStr should be #rrggbb
var hex = parseInt(colorString.substring(1), 16);
var r = (hex & 0xff0000) >> 16;
var g = (hex & 0x00ff00) >> 8;
var b = hex & 0x0000ff;
return 'rgb(' + r + ', ' + g + ', ' + b + ')';
};
namespace.events = {
spyOn: function (selector, eventName) {
eventsData.spiedEvents[[selector, eventName]] = {
callCount: 0,
calls: [],
mostRecentCall: {},
name: eventName
};
var handler = function (e, data) {
var call = {
event: e,
args: jasmine.util.argsToArray(arguments),
data: data
};
eventsData.spiedEvents[[selector, eventName]].callCount++;
eventsData.spiedEvents[[selector, eventName]].calls.push(call);
eventsData.spiedEvents[[selector, eventName]].mostRecentCall = call;
};
jQuery(selector).on(eventName, handler);
eventsData.handlers.push(handler);
return eventsData.spiedEvents[[selector, eventName]];
},
eventArgs: function (selector, eventName, expectedArg) {
var actualArgs = eventsData.spiedEvents[[selector, eventName]].mostRecentCall.args;
if (!actualArgs) {
throw 'No event spy found on ' + eventName + '. Try adding a call to spyOnEvent or make sure that the selector the event is triggered on and the selector being spied on are correct.';
}
// remove extra event metadata if it is not tested for
if ((actualArgs.length === 2) && typeof actualArgs[1] === 'object' &&
expectedArg && !expectedArg.scribeContext && !expectedArg.sourceEventData && !expectedArg.scribeData) {
actualArgs[1] = $.extend({}, actualArgs[1]);
delete actualArgs[1].sourceEventData;
delete actualArgs[1].scribeContext;
delete actualArgs[1].scribeData;
}
return actualArgs;
},
wasTriggered: function (selector, event) {
var spiedEvent = eventsData.spiedEvents[[selector, event]];
return spiedEvent && spiedEvent.callCount > 0;
},
wasTriggeredWith: function (selector, eventName, expectedArg, env) {
var actualArgs = jasmine.flight.events.eventArgs(selector, eventName, expectedArg);
return actualArgs && env.contains_(actualArgs, expectedArg);
},
wasTriggeredWithData: function (selector, eventName, expectedArg, env) {
var actualArgs = jasmine.flight.events.eventArgs(selector, eventName, expectedArg);
var valid;
if (actualArgs) {
valid = false;
for (var i = 0; i < actualArgs.length; i++) {
if (jasmine.flight.validateHash(expectedArg, actualArgs[i])) {
return true;
}
}
return valid;
}
return false;
},
cleanUp: function () {
eventsData.spiedEvents = {};
eventsData.handlers = [];
}
};
namespace.validateHash = function (a, b, intersection) {
var validHash;
for (var field in a) {
if ((typeof a[field] === 'object') && (typeof b[field] === 'object')) {
validHash = jasmine.flight.validateHash(a[field], b[field]);
} else if (intersection && (typeof a[field] === 'undefined' || typeof b[field] === 'undefined')) {
validHash = true;
} else {
validHash = (a[field] === b[field]);
}
if (!validHash) {
break;
}
}
return validHash;
};
})(jasmine.flight);
beforeEach(function () {
this.addMatchers({
toHaveBeenTriggeredOn: function () {
var selector = arguments[0];
var eventName = typeof this.actual === 'string' ? this.actual : this.actual.name;
var wasTriggered = jasmine.flight.events.wasTriggered(selector, eventName);
this.message = function () {
var $pp = function (obj) {
var description;
var attr;
if (!(obj instanceof jQuery)) {
obj = $(obj);
}
description = [
obj.get(0).nodeName
];
attr = obj.get(0).attributes || [];
for (var x = 0; x < attr.length; x++) {
description.push(attr[x].name + '="' + attr[x].value + '"');
}
return '<' + description.join(' ') + '>';
};
if (wasTriggered) {
return [
'<div class="value-mismatch">Expected event ' + eventName + ' to have been triggered on' + selector,
'<div class="value-mismatch">Expected event ' + eventName + ' not to have been triggered on' + selector
];
} else {
return [
'Expected event ' + eventName + ' to have been triggered on ' + $pp(selector),
'Expected event ' + eventName + ' not to have been triggered on ' + $pp(selector)
];
}
};
return wasTriggered;
},
toHaveBeenTriggeredOnAndWith: function () {
var selector = arguments[0];
var expectedArg = arguments[1];
var exactMatch = !arguments[2];
var wasTriggered = jasmine.flight.events.wasTriggered(selector, this.actual);
this.message = function () {
var $pp = function (obj) {
var description;
var attr;
if (!(obj instanceof jQuery)) {
obj = $(obj);
}
description = [
obj.get(0).nodeName
];
attr = obj.get(0).attributes || [];
for (var x = 0; x < attr.length; x++) {
description.push(attr[x].name + '="' + attr[x].value + '"');
}
return '<' + description.join(' ') + '>';
};
if (wasTriggered) {
var actualArg = jasmine.flight.events.eventArgs(selector, this.actual, expectedArg)[1];
return [
'<div class="value-mismatch">Expected event ' + this.actual.name + ' to have been triggered on' + selector,
'<div class="value-mismatch">Expected event ' + this.actual.name + ' not to have been triggered on' + selector
];
} else {
return [
'Expected event ' + this.actual.name + ' to have been triggered on ' + $pp(selector),
'Expected event ' + this.actual.name + ' not to have been triggered on ' + $pp(selector)
];
}
};
if (!wasTriggered) {
return false;
}
if (exactMatch) {
return jasmine.flight.events.wasTriggeredWith(selector, this.actual, expectedArg, this.env);
} else {
return jasmine.flight.events.wasTriggeredWithData(selector, this.actual, expectedArg, this.env);
}
},
toHaveCss: function (prop, val) {
var result;
if (val instanceof RegExp) {
result = val.test(this.actual.css(prop));
} else if (prop.match(/color/)) {
//IE returns colors as hex strings; other browsers return rgb(r, g, b) strings
result = jasmine.flight.compareColors(this.actual.css(prop), val);
} else {
result = this.actual.css(prop) === val;
//sometimes .css() returns strings when it should return numbers
if (!result && typeof val === 'number') {
result = parseFloat(this.actual.css(prop), 10) === val;
}
}
this.actual = jasmine.flight.formatElement(this.actual);
return result;
}
});
});
root.spyOnEvent = function (selector, eventName) {
jasmine.JQuery.events.spyOn(selector, eventName);
return jasmine.flight.events.spyOn(selector, eventName);
};
}(this));

Просмотреть файл

@ -0,0 +1,659 @@
/*!
Jasmine-jQuery: a set of jQuery helpers for Jasmine tests.
Version 1.5.2
https://github.com/velesin/jasmine-jquery
Copyright (c) 2010-2013 Wojciech Zawistowski, Travis Jeffery
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
var readFixtures = function() {
return jasmine.getFixtures().proxyCallTo_('read', arguments)
}
var preloadFixtures = function() {
jasmine.getFixtures().proxyCallTo_('preload', arguments)
}
var loadFixtures = function() {
jasmine.getFixtures().proxyCallTo_('load', arguments)
}
var appendLoadFixtures = function() {
jasmine.getFixtures().proxyCallTo_('appendLoad', arguments)
}
var setFixtures = function(html) {
jasmine.getFixtures().proxyCallTo_('set', arguments)
}
var appendSetFixtures = function() {
jasmine.getFixtures().proxyCallTo_('appendSet', arguments)
}
var sandbox = function(attributes) {
return jasmine.getFixtures().sandbox(attributes)
}
var spyOnEvent = function(selector, eventName) {
return jasmine.JQuery.events.spyOn(selector, eventName)
}
var preloadStyleFixtures = function() {
jasmine.getStyleFixtures().proxyCallTo_('preload', arguments)
}
var loadStyleFixtures = function() {
jasmine.getStyleFixtures().proxyCallTo_('load', arguments)
}
var appendLoadStyleFixtures = function() {
jasmine.getStyleFixtures().proxyCallTo_('appendLoad', arguments)
}
var setStyleFixtures = function(html) {
jasmine.getStyleFixtures().proxyCallTo_('set', arguments)
}
var appendSetStyleFixtures = function(html) {
jasmine.getStyleFixtures().proxyCallTo_('appendSet', arguments)
}
var loadJSONFixtures = function() {
return jasmine.getJSONFixtures().proxyCallTo_('load', arguments)
}
var getJSONFixture = function(url) {
return jasmine.getJSONFixtures().proxyCallTo_('read', arguments)[url]
}
jasmine.spiedEventsKey = function (selector, eventName) {
return [$(selector).selector, eventName].toString()
}
jasmine.getFixtures = function() {
return jasmine.currentFixtures_ = jasmine.currentFixtures_ || new jasmine.Fixtures()
}
jasmine.getStyleFixtures = function() {
return jasmine.currentStyleFixtures_ = jasmine.currentStyleFixtures_ || new jasmine.StyleFixtures()
}
jasmine.Fixtures = function() {
this.containerId = 'jasmine-fixtures'
this.fixturesCache_ = {}
this.fixturesPath = 'spec/javascripts/fixtures'
}
jasmine.Fixtures.prototype.set = function(html) {
this.cleanUp()
this.createContainer_(html)
}
jasmine.Fixtures.prototype.appendSet= function(html) {
this.addToContainer_(html)
}
jasmine.Fixtures.prototype.preload = function() {
this.read.apply(this, arguments)
}
jasmine.Fixtures.prototype.load = function() {
this.cleanUp()
this.createContainer_(this.read.apply(this, arguments))
}
jasmine.Fixtures.prototype.appendLoad = function() {
this.addToContainer_(this.read.apply(this, arguments))
}
jasmine.Fixtures.prototype.read = function() {
var htmlChunks = []
var fixtureUrls = arguments
for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
htmlChunks.push(this.getFixtureHtml_(fixtureUrls[urlIndex]))
}
return htmlChunks.join('')
}
jasmine.Fixtures.prototype.clearCache = function() {
this.fixturesCache_ = {}
}
jasmine.Fixtures.prototype.cleanUp = function() {
$('#' + this.containerId).remove()
}
jasmine.Fixtures.prototype.sandbox = function(attributes) {
var attributesToSet = attributes || {}
return $('<div id="sandbox" />').attr(attributesToSet)
}
jasmine.Fixtures.prototype.createContainer_ = function(html) {
var container
if(html instanceof $) {
container = $('<div id="' + this.containerId + '" />')
container.html(html)
} else {
container = '<div id="' + this.containerId + '">' + html + '</div>'
}
$(document.body).append(container)
}
jasmine.Fixtures.prototype.addToContainer_ = function(html){
var container = $(document.body).find('#'+this.containerId).append(html)
if(!container.length){
this.createContainer_(html)
}
}
jasmine.Fixtures.prototype.getFixtureHtml_ = function(url) {
if (typeof this.fixturesCache_[url] === 'undefined') {
this.loadFixtureIntoCache_(url)
}
return this.fixturesCache_[url]
}
jasmine.Fixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
var url = this.makeFixtureUrl_(relativeUrl)
var request = $.ajax({
type: "GET",
url: url + "?" + new Date().getTime(),
async: false
})
this.fixturesCache_[relativeUrl] = request.responseText
}
jasmine.Fixtures.prototype.makeFixtureUrl_ = function(relativeUrl){
return this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
}
jasmine.Fixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
return this[methodName].apply(this, passedArguments)
}
jasmine.StyleFixtures = function() {
this.fixturesCache_ = {}
this.fixturesNodes_ = []
this.fixturesPath = 'spec/javascripts/fixtures'
}
jasmine.StyleFixtures.prototype.set = function(css) {
this.cleanUp()
this.createStyle_(css)
}
jasmine.StyleFixtures.prototype.appendSet = function(css) {
this.createStyle_(css)
}
jasmine.StyleFixtures.prototype.preload = function() {
this.read_.apply(this, arguments)
}
jasmine.StyleFixtures.prototype.load = function() {
this.cleanUp()
this.createStyle_(this.read_.apply(this, arguments))
}
jasmine.StyleFixtures.prototype.appendLoad = function() {
this.createStyle_(this.read_.apply(this, arguments))
}
jasmine.StyleFixtures.prototype.cleanUp = function() {
while(this.fixturesNodes_.length) {
this.fixturesNodes_.pop().remove()
}
}
jasmine.StyleFixtures.prototype.createStyle_ = function(html) {
var styleText = $('<div></div>').html(html).text(),
style = $('<style>' + styleText + '</style>')
this.fixturesNodes_.push(style)
$('head').append(style)
}
jasmine.StyleFixtures.prototype.clearCache = jasmine.Fixtures.prototype.clearCache
jasmine.StyleFixtures.prototype.read_ = jasmine.Fixtures.prototype.read
jasmine.StyleFixtures.prototype.getFixtureHtml_ = jasmine.Fixtures.prototype.getFixtureHtml_
jasmine.StyleFixtures.prototype.loadFixtureIntoCache_ = jasmine.Fixtures.prototype.loadFixtureIntoCache_
jasmine.StyleFixtures.prototype.makeFixtureUrl_ = jasmine.Fixtures.prototype.makeFixtureUrl_
jasmine.StyleFixtures.prototype.proxyCallTo_ = jasmine.Fixtures.prototype.proxyCallTo_
jasmine.getJSONFixtures = function() {
return jasmine.currentJSONFixtures_ = jasmine.currentJSONFixtures_ || new jasmine.JSONFixtures()
}
jasmine.JSONFixtures = function() {
this.fixturesCache_ = {}
this.fixturesPath = 'spec/javascripts/fixtures/json'
}
jasmine.JSONFixtures.prototype.load = function() {
this.read.apply(this, arguments)
return this.fixturesCache_
}
jasmine.JSONFixtures.prototype.read = function() {
var fixtureUrls = arguments
for(var urlCount = fixtureUrls.length, urlIndex = 0; urlIndex < urlCount; urlIndex++) {
this.getFixtureData_(fixtureUrls[urlIndex])
}
return this.fixturesCache_
}
jasmine.JSONFixtures.prototype.clearCache = function() {
this.fixturesCache_ = {}
}
jasmine.JSONFixtures.prototype.getFixtureData_ = function(url) {
this.loadFixtureIntoCache_(url)
return this.fixturesCache_[url]
}
jasmine.JSONFixtures.prototype.loadFixtureIntoCache_ = function(relativeUrl) {
var self = this
var url = this.fixturesPath.match('/$') ? this.fixturesPath + relativeUrl : this.fixturesPath + '/' + relativeUrl
$.ajax({
async: false, // must be synchronous to guarantee that no tests are run before fixture is loaded
cache: false,
dataType: 'json',
url: url,
success: function(data) {
self.fixturesCache_[relativeUrl] = data
},
error: function(jqXHR, status, errorThrown) {
throw Error('JSONFixture could not be loaded: ' + url + ' (status: ' + status + ', message: ' + errorThrown.message + ')')
}
})
}
jasmine.JSONFixtures.prototype.proxyCallTo_ = function(methodName, passedArguments) {
return this[methodName].apply(this, passedArguments)
}
jasmine.JQuery = function() {}
jasmine.JQuery.browserTagCaseIndependentHtml = function(html) {
return $('<div/>').append(html).html()
}
jasmine.JQuery.elementToString = function(element) {
var domEl = $(element).get(0)
if (domEl == undefined || domEl.cloneNode)
return $('<div />').append($(element).clone()).html()
else
return element.toString()
}
jasmine.JQuery.matchersClass = {}
!function(namespace) {
var data = {
spiedEvents: {},
handlers: []
}
namespace.events = {
spyOn: function(selector, eventName) {
var handler = function(e) {
data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)] = jasmine.util.argsToArray(arguments)
}
$(selector).on(eventName, handler)
data.handlers.push(handler)
return {
selector: selector,
eventName: eventName,
handler: handler,
reset: function(){
delete data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)]
}
}
},
args: function(selector, eventName) {
var actualArgs = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)];
if (!actualArgs) {
throw "There is no spy for " + eventName + " on " + selector.toString() + ". Make sure to create a spy using spyOnEvent.";
}
return actualArgs;
},
wasTriggered: function(selector, eventName) {
return !!(data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)])
},
wasTriggeredWith: function(selector, eventName, expectedArgs, env) {
var actualArgs = jasmine.JQuery.events.args(selector, eventName).slice(1);
if (Object.prototype.toString.call(expectedArgs) !== '[object Array]') {
actualArgs = actualArgs[0];
}
return env.equals_(expectedArgs, actualArgs);
},
wasPrevented: function(selector, eventName) {
var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)],
e = args ? args[0] : undefined;
return e && e.isDefaultPrevented()
},
wasStopped: function(selector, eventName) {
var args = data.spiedEvents[jasmine.spiedEventsKey(selector, eventName)],
e = args ? args[0] : undefined;
return e && e.isPropagationStopped()
},
cleanUp: function() {
data.spiedEvents = {}
data.handlers = []
}
}
}(jasmine.JQuery)
!function(){
var jQueryMatchers = {
toHaveClass: function(className) {
return this.actual.hasClass(className)
},
toHaveCss: function(css){
for (var prop in css){
if (this.actual.css(prop) !== css[prop]) return false
}
return true
},
toBeVisible: function() {
return this.actual.is(':visible')
},
toBeHidden: function() {
return this.actual.is(':hidden')
},
toBeSelected: function() {
return this.actual.is(':selected')
},
toBeChecked: function() {
return this.actual.is(':checked')
},
toBeEmpty: function() {
return this.actual.is(':empty')
},
toExist: function() {
return $(document).find(this.actual).length
},
toHaveLength: function(length) {
return this.actual.length === length
},
toHaveAttr: function(attributeName, expectedAttributeValue) {
return hasProperty(this.actual.attr(attributeName), expectedAttributeValue)
},
toHaveProp: function(propertyName, expectedPropertyValue) {
return hasProperty(this.actual.prop(propertyName), expectedPropertyValue)
},
toHaveId: function(id) {
return this.actual.attr('id') == id
},
toHaveHtml: function(html) {
return this.actual.html() == jasmine.JQuery.browserTagCaseIndependentHtml(html)
},
toContainHtml: function(html){
var actualHtml = this.actual.html()
var expectedHtml = jasmine.JQuery.browserTagCaseIndependentHtml(html)
return (actualHtml.indexOf(expectedHtml) >= 0)
},
toHaveText: function(text) {
var trimmedText = $.trim(this.actual.text())
if (text && $.isFunction(text.test)) {
return text.test(trimmedText)
} else {
return trimmedText == text
}
},
toContainText: function(text) {
var trimmedText = $.trim(this.actual.text())
if (text && $.isFunction(text.test)) {
return text.test(trimmedText)
} else {
return trimmedText.indexOf(text) != -1;
}
},
toHaveValue: function(value) {
return this.actual.val() === value
},
toHaveData: function(key, expectedValue) {
return hasProperty(this.actual.data(key), expectedValue)
},
toBe: function(selector) {
return this.actual.is(selector)
},
toContain: function(selector) {
return this.actual.find(selector).length
},
toBeDisabled: function(selector){
return this.actual.is(':disabled')
},
toBeFocused: function(selector) {
return this.actual[0] === this.actual[0].ownerDocument.activeElement
},
toHandle: function(event) {
var events = $._data(this.actual.get(0), "events")
if(!events || !event || typeof event !== "string") {
return false
}
var namespaces = event.split(".")
var eventType = namespaces.shift()
var sortedNamespaces = namespaces.slice(0).sort()
var namespaceRegExp = new RegExp("(^|\\.)" + sortedNamespaces.join("\\.(?:.*\\.)?") + "(\\.|$)")
if(events[eventType] && namespaces.length) {
for(var i = 0; i < events[eventType].length; i++) {
var namespace = events[eventType][i].namespace
if(namespaceRegExp.test(namespace)) {
return true
}
}
} else {
return events[eventType] && events[eventType].length > 0
}
},
// tests the existence of a specific event binding + handler
toHandleWith: function(eventName, eventHandler) {
var stack = $._data(this.actual.get(0), "events")[eventName]
for (var i = 0; i < stack.length; i++) {
if (stack[i].handler == eventHandler) return true
}
return false
}
}
var hasProperty = function(actualValue, expectedValue) {
if (expectedValue === undefined) return actualValue !== undefined
return actualValue == expectedValue
}
var bindMatcher = function(methodName) {
var builtInMatcher = jasmine.Matchers.prototype[methodName]
jasmine.JQuery.matchersClass[methodName] = function() {
if (this.actual
&& (this.actual instanceof $
|| jasmine.isDomNode(this.actual))) {
this.actual = $(this.actual)
var result = jQueryMatchers[methodName].apply(this, arguments)
var element
if (this.actual.get && (element = this.actual.get()[0]) && !$.isWindow(element) && element.tagName !== "HTML")
this.actual = jasmine.JQuery.elementToString(this.actual)
return result
}
if (builtInMatcher) {
return builtInMatcher.apply(this, arguments)
}
return false
}
}
for(var methodName in jQueryMatchers) {
bindMatcher(methodName)
}
}()
beforeEach(function() {
this.addMatchers(jasmine.JQuery.matchersClass)
this.addMatchers({
toHaveBeenTriggeredOn: function(selector) {
this.message = function() {
return [
"Expected event " + this.actual + " to have been triggered on " + selector,
"Expected event " + this.actual + " not to have been triggered on " + selector
]
}
return jasmine.JQuery.events.wasTriggered(selector, this.actual)
}
})
this.addMatchers({
toHaveBeenTriggered: function(){
var eventName = this.actual.eventName,
selector = this.actual.selector
this.message = function() {
return [
"Expected event " + eventName + " to have been triggered on " + selector,
"Expected event " + eventName + " not to have been triggered on " + selector
]
}
return jasmine.JQuery.events.wasTriggered(selector, eventName)
}
})
this.addMatchers({
toHaveBeenTriggeredOnAndWith: function() {
var selector = arguments[0],
expectedArgs = arguments[1],
wasTriggered = jasmine.JQuery.events.wasTriggered(selector, this.actual);
this.message = function() {
if (wasTriggered) {
var actualArgs = jasmine.JQuery.events.args(selector, this.actual, expectedArgs)[1];
return [
"Expected event " + this.actual + " to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs),
"Expected event " + this.actual + " not to have been triggered with " + jasmine.pp(expectedArgs) + " but it was triggered with " + jasmine.pp(actualArgs)
]
} else {
return [
"Expected event " + this.actual + " to have been triggered on " + selector,
"Expected event " + this.actual + " not to have been triggered on " + selector
]
}
}
return wasTriggered && jasmine.JQuery.events.wasTriggeredWith(selector, this.actual, expectedArgs, this.env);
}
})
this.addMatchers({
toHaveBeenPreventedOn: function(selector) {
this.message = function() {
return [
"Expected event " + this.actual + " to have been prevented on " + selector,
"Expected event " + this.actual + " not to have been prevented on " + selector
]
}
return jasmine.JQuery.events.wasPrevented(selector, this.actual)
}
})
this.addMatchers({
toHaveBeenPrevented: function() {
var eventName = this.actual.eventName,
selector = this.actual.selector
this.message = function() {
return [
"Expected event " + eventName + " to have been prevented on " + selector,
"Expected event " + eventName + " not to have been prevented on " + selector
]
}
return jasmine.JQuery.events.wasPrevented(selector, eventName)
}
})
this.addMatchers({
toHaveBeenStoppedOn: function(selector) {
this.message = function() {
return [
"Expected event " + this.actual + " to have been stopped on " + selector,
"Expected event " + this.actual + " not to have been stopped on " + selector
]
}
return jasmine.JQuery.events.wasStopped(selector, this.actual)
}
})
this.addMatchers({
toHaveBeenStopped: function() {
var eventName = this.actual.eventName,
selector = this.actual.selector
this.message = function() {
return [
"Expected event " + eventName + " to have been stopped on " + selector,
"Expected event " + eventName + " not to have been stopped on " + selector
]
}
return jasmine.JQuery.events.wasStopped(selector, eventName)
}
})
})
afterEach(function() {
jasmine.getFixtures().cleanUp()
jasmine.getStyleFixtures().cleanUp()
jasmine.JQuery.events.cleanUp()
})

Просмотреть файл

@ -0,0 +1,13 @@
{
"name": "jquery",
"version": "1.8.3",
"main": "./jquery.js",
"dependencies": {},
"_id": "jquery@1.8.3",
"readme": "ERROR: No README.md file found!",
"description": "ERROR: No README.md file found!",
"repository": {
"type": "git",
"url": "git://github.com/components/jquery.git"
}
}

Просмотреть файл

@ -0,0 +1,23 @@
{
"name": "components/jquery",
"description": "jQuery JavaScript Library",
"type": "component",
"homepage": "http://jquery.com",
"license": "MIT",
"support": {
"irc": "irc://irc.freenode.org/jquery",
"issues": "http://bugs.jquery.com",
"forum": "http://forum.jquery.com",
"wiki": "http://docs.jquery.com/",
"source": "https://github.com/jquery/jquery"
},
"authors": [
{
"name": "John Resig",
"email": "jeresig@gmail.com"
}
],
"extra": {
"js": "jquery.js"
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -0,0 +1,635 @@
/*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*/
/*global define: false*/
var Mustache;
/*!
* mustache.js - Logic-less {{mustache}} templates with JavaScript
* http://github.com/janl/mustache.js
*/
/*global define: false*/
var Mustache;
(function (exports) {
if (typeof module !== "undefined" && module.exports) {
module.exports = exports; // CommonJS
} else if (typeof define === "function") {
define(exports); // AMD
} else {
Mustache = exports; // <script>
}
}((function () {
var exports = {};
exports.name = "mustache.js";
exports.version = "0.7.1";
exports.tags = ["{{", "}}"];
exports.Scanner = Scanner;
exports.Context = Context;
exports.Writer = Writer;
var whiteRe = /\s*/;
var spaceRe = /\s+/;
var nonSpaceRe = /\S/;
var eqRe = /\s*=/;
var curlyRe = /\s*\}/;
var tagRe = /#|\^|\/|>|\{|&|=|!/;
// Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
// See https://github.com/janl/mustache.js/issues/189
function testRe(re, string) {
return RegExp.prototype.test.call(re, string);
}
function isWhitespace(string) {
return !testRe(nonSpaceRe, string);
}
var isArray = Array.isArray || function (obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
function escapeRe(string) {
return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
var entityMap = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
'"': '&quot;',
"'": '&#39;',
"/": '&#x2F;'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'\/]/g, function (s) {
return entityMap[s];
});
}
// Export the escaping function so that the user may override it.
// See https://github.com/janl/mustache.js/issues/244
exports.escape = escapeHtml;
function Scanner(string) {
this.string = string;
this.tail = string;
this.pos = 0;
}
/**
* Returns `true` if the tail is empty (end of string).
*/
Scanner.prototype.eos = function () {
return this.tail === "";
};
/**
* Tries to match the given regular expression at the current position.
* Returns the matched text if it can match, the empty string otherwise.
*/
Scanner.prototype.scan = function (re) {
var match = this.tail.match(re);
if (match && match.index === 0) {
this.tail = this.tail.substring(match[0].length);
this.pos += match[0].length;
return match[0];
}
return "";
};
/**
* Skips all text until the given regular expression can be matched. Returns
* the skipped string, which is the entire tail if no match can be made.
*/
Scanner.prototype.scanUntil = function (re) {
var match, pos = this.tail.search(re);
switch (pos) {
case -1:
match = this.tail;
this.pos += this.tail.length;
this.tail = "";
break;
case 0:
match = "";
break;
default:
match = this.tail.substring(0, pos);
this.tail = this.tail.substring(pos);
this.pos += pos;
}
return match;
};
function Context(view, parent) {
this.view = view;
this.parent = parent;
this.clearCache();
}
Context.make = function (view) {
return (view instanceof Context) ? view : new Context(view);
};
Context.prototype.clearCache = function () {
this._cache = {};
};
Context.prototype.push = function (view) {
return new Context(view, this);
};
Context.prototype.lookup = function (name) {
var value = this._cache[name];
if (!value) {
if (name === ".") {
value = this.view;
} else {
var context = this;
while (context) {
if (name.indexOf(".") > 0) {
var names = name.split("."), i = 0;
value = context.view;
while (value && i < names.length) {
value = value[names[i++]];
}
} else {
value = context.view[name];
}
if (value != null) {
break;
}
context = context.parent;
}
}
this._cache[name] = value;
}
if (typeof value === "function") {
value = value.call(this.view);
}
return value;
};
function Writer() {
this.clearCache();
}
Writer.prototype.clearCache = function () {
this._cache = {};
this._partialCache = {};
};
Writer.prototype.compile = function (template, tags) {
var fn = this._cache[template];
if (!fn) {
var tokens = exports.parse(template, tags);
fn = this._cache[template] = this.compileTokens(tokens, template);
}
return fn;
};
Writer.prototype.compilePartial = function (name, template, tags) {
var fn = this.compile(template, tags);
this._partialCache[name] = fn;
return fn;
};
Writer.prototype.compileTokens = function (tokens, template) {
var fn = compileTokens(tokens);
var self = this;
return function (view, partials) {
if (partials) {
if (typeof partials === "function") {
self._loadPartial = partials;
} else {
for (var name in partials) {
self.compilePartial(name, partials[name]);
}
}
}
return fn(self, Context.make(view), template);
};
};
Writer.prototype.render = function (template, view, partials) {
return this.compile(template)(view, partials);
};
Writer.prototype._section = function (name, context, text, callback) {
var value = context.lookup(name);
switch (typeof value) {
case "object":
if (isArray(value)) {
var buffer = "";
for (var i = 0, len = value.length; i < len; ++i) {
buffer += callback(this, context.push(value[i]));
}
return buffer;
}
return value ? callback(this, context.push(value)) : "";
case "function":
var self = this;
var scopedRender = function (template) {
return self.render(template, context);
};
var result = value.call(context.view, text, scopedRender);
return result != null ? result : "";
default:
if (value) {
return callback(this, context);
}
}
return "";
};
Writer.prototype._inverted = function (name, context, callback) {
var value = context.lookup(name);
// Use JavaScript's definition of falsy. Include empty arrays.
// See https://github.com/janl/mustache.js/issues/186
if (!value || (isArray(value) && value.length === 0)) {
return callback(this, context);
}
return "";
};
Writer.prototype._partial = function (name, context) {
if (!(name in this._partialCache) && this._loadPartial) {
this.compilePartial(name, this._loadPartial(name));
}
var fn = this._partialCache[name];
return fn ? fn(context) : "";
};
Writer.prototype._name = function (name, context) {
var value = context.lookup(name);
if (typeof value === "function") {
value = value.call(context.view);
}
return (value == null) ? "" : String(value);
};
Writer.prototype._escaped = function (name, context) {
return exports.escape(this._name(name, context));
};
/**
* Calculates the bounds of the section represented by the given `token` in
* the original template by drilling down into nested sections to find the
* last token that is part of that section. Returns an array of [start, end].
*/
function sectionBounds(token) {
var start = token[3];
var end = start;
var tokens;
while ((tokens = token[4]) && tokens.length) {
token = tokens[tokens.length - 1];
end = token[3];
}
return [start, end];
}
/**
* Low-level function that compiles the given `tokens` into a function
* that accepts three arguments: a Writer, a Context, and the template.
*/
function compileTokens(tokens) {
var subRenders = {};
function subRender(i, tokens, template) {
if (!subRenders[i]) {
var fn = compileTokens(tokens);
subRenders[i] = function (writer, context) {
return fn(writer, context, template);
};
}
return subRenders[i];
}
return function (writer, context, template) {
var buffer = "";
var token, sectionText;
for (var i = 0, len = tokens.length; i < len; ++i) {
token = tokens[i];
switch (token[0]) {
case "#":
sectionText = template.slice.apply(template, sectionBounds(token));
buffer += writer._section(token[1], context, sectionText, subRender(i, token[4], template));
break;
case "^":
buffer += writer._inverted(token[1], context, subRender(i, token[4], template));
break;
case ">":
buffer += writer._partial(token[1], context);
break;
case "&":
buffer += writer._name(token[1], context);
break;
case "name":
buffer += writer._escaped(token[1], context);
break;
case "text":
buffer += token[1];
break;
}
}
return buffer;
};
}
/**
* Forms the given array of `tokens` into a nested tree structure where
* tokens that represent a section have a fifth item: an array that contains
* all tokens in that section.
*/
function nestTokens(tokens) {
var tree = [];
var collector = tree;
var sections = [];
var token, section;
for (var i = 0; i < tokens.length; ++i) {
token = tokens[i];
switch (token[0]) {
case "#":
case "^":
token[4] = [];
sections.push(token);
collector.push(token);
collector = token[4];
break;
case "/":
if (sections.length === 0) {
throw new Error("Unopened section: " + token[1]);
}
section = sections.pop();
if (section[1] !== token[1]) {
throw new Error("Unclosed section: " + section[1]);
}
if (sections.length > 0) {
collector = sections[sections.length - 1][4];
} else {
collector = tree;
}
break;
default:
collector.push(token);
}
}
// Make sure there were no open sections when we're done.
section = sections.pop();
if (section) {
throw new Error("Unclosed section: " + section[1]);
}
return tree;
}
/**
* Combines the values of consecutive text tokens in the given `tokens` array
* to a single token.
*/
function squashTokens(tokens) {
var token, lastToken, squashedTokens = [];
for (var i = 0; i < tokens.length; ++i) {
token = tokens[i];
if (lastToken && lastToken[0] === "text" && token[0] === "text") {
lastToken[1] += token[1];
lastToken[3] = token[3];
} else {
lastToken = token;
squashedTokens.push(token);
}
}
return squashedTokens;
}
function escapeTags(tags) {
if (tags.length !== 2) {
throw new Error("Invalid tags: " + tags.join(" "));
}
return [
new RegExp(escapeRe(tags[0]) + "\\s*"),
new RegExp("\\s*" + escapeRe(tags[1]))
];
}
/**
* Breaks up the given `template` string into a tree of token objects. If
* `tags` is given here it must be an array with two string values: the
* opening and closing tags used in the template (e.g. ["<%", "%>"]). Of
* course, the default is to use mustaches (i.e. Mustache.tags).
*/
exports.parse = function (template, tags) {
template = template || '';
tags = tags || exports.tags;
var tagRes = escapeTags(tags);
var scanner = new Scanner(template);
var tokens = [], // Buffer to hold the tokens
spaces = [], // Indices of whitespace tokens on the current line
hasTag = false, // Is there a {{tag}} on the current line?
nonSpace = false; // Is there a non-space char on the current line?
// Strips all whitespace tokens array for the current line
// if there was a {{#tag}} on it and otherwise only space.
function stripSpace() {
if (hasTag && !nonSpace) {
while (spaces.length) {
tokens.splice(spaces.pop(), 1);
}
} else {
spaces = [];
}
hasTag = false;
nonSpace = false;
}
var start, type, value, chr;
while (!scanner.eos()) {
start = scanner.pos;
value = scanner.scanUntil(tagRes[0]);
if (value) {
for (var i = 0, len = value.length; i < len; ++i) {
chr = value.charAt(i);
if (isWhitespace(chr)) {
spaces.push(tokens.length);
} else {
nonSpace = true;
}
tokens.push(["text", chr, start, start + 1]);
start += 1;
if (chr === "\n") {
stripSpace(); // Check for whitespace on the current line.
}
}
}
start = scanner.pos;
// Match the opening tag.
if (!scanner.scan(tagRes[0])) {
break;
}
hasTag = true;
type = scanner.scan(tagRe) || "name";
// Skip any whitespace between tag and value.
scanner.scan(whiteRe);
// Extract the tag value.
if (type === "=") {
value = scanner.scanUntil(eqRe);
scanner.scan(eqRe);
scanner.scanUntil(tagRes[1]);
} else if (type === "{") {
var closeRe = new RegExp("\\s*" + escapeRe("}" + tags[1]));
value = scanner.scanUntil(closeRe);
scanner.scan(curlyRe);
scanner.scanUntil(tagRes[1]);
type = "&";
} else {
value = scanner.scanUntil(tagRes[1]);
}
// Match the closing tag.
if (!scanner.scan(tagRes[1])) {
throw new Error("Unclosed tag at " + scanner.pos);
}
tokens.push([type, value, start, scanner.pos]);
if (type === "name" || type === "{" || type === "&") {
nonSpace = true;
}
// Set the tags for the next time around.
if (type === "=") {
tags = value.split(spaceRe);
tagRes = escapeTags(tags);
}
}
tokens = squashTokens(tokens);
return nestTokens(tokens);
};
// The high-level clearCache, compile, compilePartial, and render functions
// use this default writer.
var _writer = new Writer();
/**
* Clears all cached templates and partials in the default writer.
*/
exports.clearCache = function () {
return _writer.clearCache();
};
/**
* Compiles the given `template` to a reusable function using the default
* writer.
*/
exports.compile = function (template, tags) {
return _writer.compile(template, tags);
};
/**
* Compiles the partial with the given `name` and `template` to a reusable
* function using the default writer.
*/
exports.compilePartial = function (name, template, tags) {
return _writer.compilePartial(name, template, tags);
};
/**
* Compiles the given array of tokens (the output of a parse) to a reusable
* function using the default writer.
*/
exports.compileTokens = function (tokens, template) {
return _writer.compileTokens(tokens, template);
};
/**
* Renders the `template` with the given `view` and `partials` using the
* default writer.
*/
exports.render = function (template, view, partials) {
return _writer.render(template, view, partials);
};
// This is here for backwards compatibility with 0.4.x.
exports.to_html = function (template, view, partials, send) {
var result = exports.render(template, view, partials);
if (typeof send === "function") {
send(result);
} else {
return result;
}
};
return exports;
}())));

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Flight Mail</title>
<link rel="stylesheet" href="components/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="components/bootstrap/css/bootstrap-responsive.min.css">
<link rel="stylesheet" href="app/css/custom.css">
</head>
<body>
<br>
<div class="container-fluid">
<div class="row-fluid">
<div class="span2">
<div class="sidebar-nav">
<button id="new_mail" class="btn compose" data-toggle="dropdown">New</button>
<br><br>
<ul id="folders" class="nav nav-list">
<li class="folder-item selected" id="inbox"><i class="icon-folder-close"></i> Inbox</li>
<li class="folder-item" id="later"><i class="icon-folder-close"></i> Later</li>
<li class="folder-item" id="sent"><i class="icon-share-alt"></i> Sent</li>
<li class="folder-item" id="trash"><i class="icon-trash"></i> Trash</li>
</ul>
</div>
</div>
<div id="mail_panel" class="span10">
<div id="mail_controls" class="btn-toolbar" style="margin: 0 0 13px">
<div class="btn-group">
<button id="delete_mail" class="btn mail-action" disabled><i class="icon-trash"></i> delete</button>
<button id="move_mail" class="btn mail-action" disabled><i class="icon-move"></i> move</button>
<button id="forward" class="btn compose mail-action single-item" disabled><i class="icon-arrow-right"></i> forward</button>
<button id="reply" class="btn compose mail-action single-item" disabled><i class="icon-pencil"></i> reply</button>
</div>
</div>
<table id="mail_items" class="hero-unit table table-hover" style="background-color: #FFFFFF">
<tbody id="mail_items_TB">
</tbody>
</table>
</div>
</div>
</div>
<div id="compose_box" class="compose-box modal hide fade in"></div>
<div id="move_to_selector" class="move-to-selector hide"></div>
<script src="components/jquery/jquery.js"></script>
<script src="components/es5-shim/es5-shim.js"></script>
<script src="components/es5-shim/es5-sham.js"></script>
<script data-main="requireMain.js" src="components/requirejs/require.js"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,58 @@
// Karma configuration file
//
// For all available config options and default values, see:
// https://github.com/karma-runner/karma/blob/stable/lib/config.js#L54
// base path, that will be used to resolve files and exclude
basePath = '';
// list of files / patterns to load in the browser
files = [
'components/es5-shim/es5-shim.js',
'components/es5-shim/es5-sham.js',
// frameworks
JASMINE,
JASMINE_ADAPTER,
REQUIRE,
REQUIRE_ADAPTER,
// loaded without require
'components/jquery/jquery.js',
'components/jasmine-jquery/lib/jasmine-jquery.js',
'components/jasmine-flight/lib/jasmine-flight.js',
// loaded with require
{pattern: 'components/flight/**/*.js', included: false},
{pattern: 'components/mustache/**/*.js', included: false},
{pattern: 'app/**/*.js', included: false},
{pattern: 'test/fixtures/**/*.html', included: false},
{pattern: 'test/spec/**/*.js', included: false},
'test/test-main.js'
];
// list of files to exclude
exclude = [
];
// use dots reporter, as travis terminal does not support escaping sequences
reporters = [
'dots'
];
// enable / disable watching file and executing tests whenever any file changes
// CLI --auto-watch --no-auto-watch
autoWatch = true;
// start these browsers
browsers = [
'Chrome',
'Firefox'
];
// auto run tests on start (when browsers are captured) and exit
// CLI --single-run --no-single-run
singleRun = false;

Просмотреть файл

@ -0,0 +1,11 @@
{
"private": true,
"name": "flight-example-app",
"version": "0.0.0",
"devDependencies": {
"karma": "~0.8.5"
},
"scripts": {
"test": "./node_modules/.bin/karma start --single-run --browsers Firefox"
}
}

Просмотреть файл

@ -0,0 +1,24 @@
requirejs.config({
baseUrl: '',
paths: {
'flight': 'components/flight'
}
});
require(
[
'flight/lib/compose',
'flight/lib/registry',
'flight/lib/advice',
'flight/lib/logger',
'flight/tools/debug/debug'
],
function(compose, registry, advice, withLogging, debug) {
debug.enable(true);
compose.mixin(registry, [advice.withAdvice, withLogging]);
require(['app/boot/page'], function(initialize) {
initialize();
});
}
);

Двоичные данные
third_party/speedometer/resources/gauge.png поставляемый Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Двоичные данные
third_party/speedometer/resources/gauge@2x.png поставляемый Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 33 KiB

Двоичные данные
third_party/speedometer/resources/logo.png поставляемый Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.8 KiB

Двоичные данные
third_party/speedometer/resources/logo@2x.png поставляемый Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

285
third_party/speedometer/resources/main.css поставляемый Normal file
Просмотреть файл

@ -0,0 +1,285 @@
body {
background-color: rgb(46, 51, 55);
color: rgb(235, 235, 235);
font-family: "Helvetica Neue", Helvetica, Verdana, sans-serif;
}
::selection {
color: rgb(46, 51, 55);
background-color: rgb(235, 235, 235);
}
h1,
button {
font-family: "Futura-Medium", Futura, "Helvetica Neue", Helvetica, Verdana, sans-serif;
}
code {
font-family: Menlo, Monaco, monospace;
font-size: smaller;
}
button {
cursor: pointer;
}
hr {
border: 1px solid rgb(235, 235, 235);
width: 50%;
margin: 40px auto;
}
img {
-webkit-user-select: none;
-webkit-user-drag: none;
}
main {
display: block;
position: absolute;
width: 800px;
height: 600px;
top: 50%;
left: 50%;
margin-top: -321px;
margin-left: -421px;
padding: 15px;
border: 6px solid rgb(235, 235, 235);
border-radius: 20px;
}
#logo {
position: absolute;
left: -70px;
top: 115px;
width: 75px;
height: 406px;
}
h1 {
margin-top: 30px;
font-size: 40px;
font-weight: normal;
color: rgb(235, 235, 235);
text-align: center;
}
p {
font-size: 16px;
line-height: 21px;
}
a {
color: inherit;
}
.buttons {
margin-top: 30px;
text-align: center;
}
button {
-webkit-appearance: none;
border: 3px solid rgb(235, 235, 235);
border-radius: 10px;
min-width: 200px;
padding: 5px 20px;
margin: 0 40px;
font-size: 25px;
color: rgb(235, 235, 235);
background-color: transparent;
-webkit-user-select: none;
}
button:active {
background-color: rgb(235, 235, 235);
color: rgb(46, 51, 55);
border-color: rgb(235, 235, 235) !important;
}
button:focus {
outline: none;
border-color: rgb(232, 79, 79);
}
section {
display: none;
}
section > p {
margin: 10px 20px;
}
section.selected {
display: block;
}
#testContainer {
position: absolute;
top: 15px;
left: 15px;
width: 800px;
height: 600px;
}
section#home > p {
margin: 0 auto;
width: 70%;
text-align: center;
}
section#home > p:first-child {
margin-top: 160px;
text-align: center;
}
section#home > .show-about {
margin-top: 100px;
}
section#home > .buttons {
margin-top: 80px;
}
section#running > #progress {
position: absolute;
bottom: -6px;
left: 60px;
right: 60px;
height: 6px;
background-color: rgb(128, 128, 128);
border-left: 6px solid rgb(46, 51, 55);
border-right: 6px solid rgb(46, 51, 55);
}
section#running #progress-completed {
position: absolute;
top: 0;
left: 0;
height: 6px;
width: 0;
background-color: rgb(235, 235, 235);
}
section#running > #info {
position: absolute;
bottom: -25px;
left: 60px;
right: 60px;
height: 12px;
color: rgb(128, 128, 128);
text-align: center;
font-size: 12px;
}
section#summarized-results > #result-number,
section#summarized-results > #confidence-number {
font-family: "Futura-CondensedMedium", Futura, "Helvetica Neue", Helvetica, Verdana, sans-serif;
}
section#summarized-results > #result-number {
text-align: center;
font-size: 145px;
line-height: 145px;
}
section#summarized-results > #confidence-number {
text-align: center;
font-size: 36px;
line-height: 36px;
color: rgb(128, 128, 128);
}
section#detailed-results > table {
float: left;
width: 50%;
}
section#detailed-results > .arithmetic-mean {
clear: both;
padding-top: 32px;
text-align: center;
}
section#detailed-results > .arithmetic-mean > label {
font-weight: bold;
margin-right: 10px;
color: rgb(128, 128, 128);
}
section#detailed-results > .show-about {
margin-top: 30px;
text-align: center;
}
section#about h1 {
margin-top: 20px;
font-size: 30px;
}
section#about .note {
color: rgb(128, 128, 128);
}
table {
border-spacing: 0;
border-collapse: collapse;
}
th,
td {
padding: 5px;
}
th {
text-align: right;
color: rgb(128, 128, 128);
}
.gauge {
position: relative;
width: 738px;
height: 78px;
background-image: url(gauge.png);
background-size: 100% 100%;
background-repat: no-repeat;
margin: 0 auto;
}
.gauge > .window {
position: absolute;
left: 0;
top: 33px;
bottom: 0;
right: 0;
overflow: hidden;
}
.gauge > .window > .needle {
position: absolute;
left: 363px;
bottom: -88px;
width: 4px;
height: 400px;
background-color: rgb(247, 148, 29);
-webkit-transform: rotate(-70deg);
-webkit-transform-origin: 2px 400px;
-moz-transform: rotate(-70deg);
-moz-transform-origin: 2px 400px;
transform: rotate(-70deg);
transform-origin: 2px 400px;
}
@media (-webkit-min-device-pixel-ratio: 2), (min--moz-device-pixel-ratio: 2), (min-resolution: 2dppx), (min-resolution: 192dpi) {
#logo {
content: url(logo@2x.png); /* FIXME: This does not work in Firefox. */
}
.gauge {
background-image: url(gauge@2x.png);
}
}

250
third_party/speedometer/resources/main.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,250 @@
window.benchmarkClient = {
displayUnit: 'runs/min',
iterationCount: 10,
testsCount: null,
suitesCount: null,
_timeValues: [],
_finishedTestCount: 0,
_progressCompleted: null,
willAddTestFrame: function (frame) {
var main = document.querySelector('main');
var style = getComputedStyle(main);
frame.style.left = main.offsetLeft + parseInt(style.borderLeftWidth) + parseInt(style.paddingLeft) + 'px';
frame.style.top = main.offsetTop + parseInt(style.borderTopWidth) + parseInt(style.paddingTop) + 'px';
},
willRunTest: function (suite, test) {
document.getElementById('info').textContent = suite.name + ' ( ' + this._finishedTestCount + ' / ' + this.testsCount + ' )';
},
didRunTest: function () {
this._finishedTestCount++;
this._progressCompleted.style.width = (this._finishedTestCount * 100 / this.testsCount) + '%';
},
didRunSuites: function (measuredValues) {
this._timeValues.push(measuredValues.total);
},
willStartFirstIteration: function () {
this._timeValues = [];
this._finishedTestCount = 0;
this._progressCompleted = document.getElementById('progress-completed');
document.getElementById('logo-link').onclick = function (event) { event.preventDefault(); return false; }
},
didFinishLastIteration: function () {
document.getElementById('logo-link').onclick = null;
var results = this._computeResults(this._timeValues, this.displayUnit);
this._updateGaugeNeedle(results.mean);
document.getElementById('result-number').textContent = results.formattedMean;
if (results.formattedDelta)
document.getElementById('confidence-number').textContent = '\u00b1 ' + results.formattedDelta;
this._populateDetailedResults(results.formattedValues);
document.getElementById('results-with-statistics').textContent = results.formattedMeanAndDelta;
if (this.displayUnit == 'ms') {
document.getElementById('show-summary').style.display = 'none';
showResultDetails();
} else
showResultsSummary();
},
_computeResults: function (timeValues, displayUnit) {
var suitesCount = this.suitesCount;
function totalTimeInDisplayUnit(time) {
if (displayUnit == 'ms')
return time;
return computeScore(time);
}
function sigFigFromPercentDelta(percentDelta) {
return Math.ceil(-Math.log(percentDelta)/Math.log(10)) + 3;
}
function toSigFigPrecision(number, sigFig) {
var nonDecimalDigitCount = number < 1 ? 0 : (Math.floor(Math.log(number)/Math.log(10)) + 1);
return number.toPrecision(Math.max(nonDecimalDigitCount, Math.min(6, sigFig)));
}
var values = timeValues.map(totalTimeInDisplayUnit);
var sum = values.reduce(function (a, b) { return a + b; }, 0);
var arithmeticMean = sum / values.length;
var meanSigFig = 4;
var formattedDelta;
var formattedPercentDelta;
if (window.Statistics) {
var delta = Statistics.confidenceIntervalDelta(0.95, values.length, sum, Statistics.squareSum(values));
if (!isNaN(delta)) {
var percentDelta = delta * 100 / arithmeticMean;
meanSigFig = sigFigFromPercentDelta(percentDelta);
formattedDelta = toSigFigPrecision(delta, 2);
formattedPercentDelta = toSigFigPrecision(percentDelta, 2) + '%';
}
}
var formattedMean = toSigFigPrecision(arithmeticMean, Math.max(meanSigFig, 3));
return {
formattedValues: timeValues.map(function (time) {
return toSigFigPrecision(totalTimeInDisplayUnit(time), 4) + ' ' + displayUnit;
}),
mean: arithmeticMean,
formattedMean: formattedMean,
formattedDelta: formattedDelta,
formattedMeanAndDelta: formattedMean + (formattedDelta ? ' \xb1 ' + formattedDelta + ' (' + formattedPercentDelta + ')' : ''),
};
},
_addDetailedResultsRow: function (table, iterationNumber, value) {
var row = document.createElement('tr');
var th = document.createElement('th');
th.textContent = 'Iteration ' + (iterationNumber + 1);
var td = document.createElement('td');
td.textContent = value;
row.appendChild(th);
row.appendChild(td);
table.appendChild(row);
},
_updateGaugeNeedle: function (rpm) {
var needleAngle = Math.max(0, Math.min(rpm, 140)) - 70;
var needleRotationValue = 'rotate(' + needleAngle + 'deg)';
var gaugeNeedleElement = document.querySelector('#summarized-results > .gauge .needle');
gaugeNeedleElement.style.setProperty('-webkit-transform', needleRotationValue);
gaugeNeedleElement.style.setProperty('-moz-transform', needleRotationValue);
gaugeNeedleElement.style.setProperty('-ms-transform', needleRotationValue);
gaugeNeedleElement.style.setProperty('transform', needleRotationValue);
},
_populateDetailedResults: function (formattedValues) {
var resultsTables = document.querySelectorAll('.results-table');
var i = 0;
resultsTables[0].innerHTML = '';
for (; i < Math.ceil(formattedValues.length / 2); i++)
this._addDetailedResultsRow(resultsTables[0], i, formattedValues[i]);
resultsTables[1].innerHTML = '';
for (; i < formattedValues.length; i++)
this._addDetailedResultsRow(resultsTables[1], i, formattedValues[i]);
},
prepareUI: function () {
window.addEventListener('popstate', function (event) {
if (event.state) {
var sectionToShow = event.state.section;
if (sectionToShow) {
var sections = document.querySelectorAll('main > section');
for (var i = 0; i < sections.length; i++) {
if (sections[i].id === sectionToShow)
return showSection(sectionToShow, false);
}
}
}
return showSection('home', false);
}, false);
function updateScreenSize() {
// FIXME: Detect when the window size changes during the test.
var screenIsTooSmall = window.innerWidth < 850 || window.innerHeight < 650;
document.getElementById('screen-size').textContent = window.innerWidth + 'px by ' + window.innerHeight + 'px';
document.getElementById('screen-size-warning').style.display = screenIsTooSmall ? null : 'none';
}
window.addEventListener('resize', updateScreenSize);
updateScreenSize();
}
}
function enableOneSuite(suites, suiteToEnable)
{
suiteToEnable = suiteToEnable.toLowerCase();
var found = false;
for (var i = 0; i < suites.length; i++) {
var currentSuite = suites[i];
if (currentSuite.name.toLowerCase() == suiteToEnable) {
currentSuite.disabled = false;
found = true;
} else
currentSuite.disabled = true;
}
return found;
}
function startBenchmark() {
if (location.search.length > 1) {
var parts = location.search.substring(1).split('&');
for (var i = 0; i < parts.length; i++) {
var keyValue = parts[i].split('=');
var key = keyValue[0];
var value = keyValue[1];
switch (key) {
case 'unit':
if (value == 'ms')
benchmarkClient.displayUnit = 'ms';
else
console.error('Invalid unit: ' + value);
break;
case 'iterationCount':
var parsedValue = parseInt(value);
if (!isNaN(parsedValue))
benchmarkClient.iterationCount = parsedValue;
else
console.error('Invalid iteration count: ' + value);
break;
case 'suite':
if (!enableOneSuite(Suites, value)) {
alert('Suite "' + value + '" does not exist. No tests to run.');
return false;
}
break;
}
}
}
var enabledSuites = Suites.filter(function (suite) { return !suite.disabled; });
var totalSubtestCount = enabledSuites.reduce(function (testsCount, suite) { return testsCount + suite.tests.length; }, 0);
benchmarkClient.testsCount = benchmarkClient.iterationCount * totalSubtestCount;
benchmarkClient.suitesCount = enabledSuites.length;
var runner = new BenchmarkRunner(Suites, benchmarkClient);
runner.runMultipleIterations(benchmarkClient.iterationCount);
return true;
}
function computeScore(time) {
return 60 * 1000 * benchmarkClient.suitesCount / time;
}
function showSection(sectionIdentifier, pushState) {
var currentSectionElement = document.querySelector('section.selected');
console.assert(currentSectionElement);
var newSectionElement = document.getElementById(sectionIdentifier);
console.assert(newSectionElement);
currentSectionElement.classList.remove('selected');
newSectionElement.classList.add('selected');
if (pushState)
history.pushState({section: sectionIdentifier}, document.title);
}
function showHome() {
showSection('home', true);
}
function startTest() {
if (startBenchmark())
showSection('running');
}
function showResultsSummary() {
showSection('summarized-results', true);
}
function showResultDetails() {
showSection('detailed-results', true);
}
function showAbout() {
showSection('about', true);
}
window.addEventListener('DOMContentLoaded', function () {
if (benchmarkClient.prepareUI)
benchmarkClient.prepareUI();
});

549
third_party/speedometer/resources/tests.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,549 @@
var numberOfItemsToAdd = 100;
var Suites = [];
var ENTER_KEY_CODE = 13;
var triggerEnter = function (element, type) {
var event = document.createEvent('Events');
event.initEvent(type, true, true);
event.keyCode = ENTER_KEY_CODE;
event.which = ENTER_KEY_CODE;
event.key = 'ENTER';
element.dispatchEvent(event);
}
Suites.push({
name: 'VanillaJS-TodoMVC',
url: 'todomvc/vanilla-examples/vanillajs/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('change'));
triggerEnter(newTodo, 'keypress');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'Vanilla-ES2015-TodoMVC',
url: 'todomvc/vanilla-examples/es2015/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('change'));
triggerEnter(newTodo, 'keypress');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'Vanilla-ES2015-Babel-Webpack-TodoMVC',
url: 'todomvc/vanilla-examples/es2015-babel-webpack/dist/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('change'));
triggerEnter(newTodo, 'keypress');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'React-TodoMVC',
url: 'todomvc/architecture-examples/react/index.html',
prepare: function (runner, contentWindow, contentDocument) {
contentWindow.app.Utils.store = function () {}
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('input', {
bubbles: true,
cancelable: true
}));
triggerEnter(newTodo, 'keydown');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'React-Redux-TodoMVC',
url: 'todomvc/architecture-examples/react-redux/dist/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
triggerEnter(newTodo, 'keydown');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'EmberJS-TodoMVC',
url: 'todomvc/architecture-examples/emberjs/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('#new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
triggerEnter(newTodo, 'keydown');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'BackboneJS-TodoMVC',
url: 'todomvc/architecture-examples/backbone/index.html',
prepare: function (runner, contentWindow, contentDocument) {
contentWindow.Backbone.sync = function () {}
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
triggerEnter(newTodo, 'keypress');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'AngularJS-TodoMVC',
url: 'todomvc/architecture-examples/angularjs/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('#new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
var submitEvent = document.createEvent('Event');
submitEvent.initEvent('submit', true, true);
var inputEvent = document.createEvent('Event');
inputEvent.initEvent('input', true, true);
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(inputEvent);
newTodo.form.dispatchEvent(submitEvent);
}
}),
new BenchmarkTestStep('CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++)
contentDocument.querySelector('.destroy').click();
}),
]
});
Suites.push({
name: 'Angular2-TypeScript-TodoMVC',
url: 'todomvc/architecture-examples/angular/dist/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('input', {
bubbles: true,
cancelable: true
}));
triggerEnter(newTodo, 'keyup');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'VueJS-TodoMVC',
url: 'todomvc/architecture-examples/vuejs-cli/dist/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('input', {
bubbles: true,
cancelable: true
}));
triggerEnter(newTodo, 'keyup');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'jQuery-TodoMVC',
url: 'todomvc/architecture-examples/jquery/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('#new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
triggerEnter(newTodo, 'keyup');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (newTodo, contentWindow, contentDocument) {
var checkboxes = contentDocument.getElementsByClassName('toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingAllItems', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++)
contentDocument.querySelector('.destroy').click();
}),
]
})
Suites.push({
name: 'Preact-TodoMVC',
url: 'todomvc/architecture-examples/preact/dist/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
triggerEnter(newTodo, 'keydown');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
Suites.push({
name: 'Inferno-TodoMVC',
url: 'todomvc/architecture-examples/inferno/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('change', {
bubbles: true,
cancelable: true
}));
triggerEnter(newTodo, 'keydown');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < numberOfItemsToAdd; i++)
contentDocument.querySelector('.destroy').click();
}),
]
});
function processElmWorkQueue(contentWindow)
{
contentWindow.elmWork();
var callbacks = contentWindow.rAFCallbackList;
var i = 0;
while (i < callbacks.length) {
callbacks[i]();
i++;
}
contentWindow.rAFCallbackList = [];
}
Suites.push({
name: 'Elm-TodoMVC',
url: 'todomvc/functional-prog-examples/elm/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.new-todo').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
newTodo.dispatchEvent(new Event('input', {
bubbles: true,
cancelable: true
}));
processElmWorkQueue(contentWindow);
triggerEnter(newTodo, 'keydown');
processElmWorkQueue(contentWindow);
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].click();
processElmWorkQueue(contentWindow);
}
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
contentDocument.querySelector('.destroy').click();
processElmWorkQueue(contentWindow);
}
}),
]
});
Suites.push({
name: 'Flight-TodoMVC',
url: 'todomvc/dependency-examples/flight/flight/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('#appIsReady').then(function (element) {
var newTodo = contentDocument.getElementById('new-todo');
newTodo.focus();
return newTodo;
});
},
tests: [
new BenchmarkTestStep('Adding' + numberOfItemsToAdd + 'Items', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < numberOfItemsToAdd; i++) {
newTodo.value = 'Something to do ' + i;
triggerEnter(newTodo, 'keydown');
}
}),
new BenchmarkTestStep('CompletingAllItems', function (params, contentWindow, contentDocument) {
var checkboxes = contentDocument.querySelectorAll('.toggle');
for (var i = 0; i < checkboxes.length; i++)
checkboxes[i].click();
}),
new BenchmarkTestStep('DeletingItems', function (params, contentWindow, contentDocument) {
var deleteButtons = contentDocument.querySelectorAll('.destroy');
for (var i = 0; i < deleteButtons.length; i++)
deleteButtons[i].click();
}),
]
});
var actionCount = 50;
Suites.push({
disabled: true,
name: 'FlightJS-MailClient',
url: 'flightjs-example-app/index.html',
prepare: function (runner, contentWindow, contentDocument) {
return runner.waitForElement('.span8').then(function (element) {
element.focus();
return element;
});
},
tests: [
new BenchmarkTestStep('OpeningTabs' + actionCount + 'Times', function (newTodo, contentWindow, contentDocument) {
contentDocument.getElementById('inbox').click();
for (var i = 0; i < actionCount; i++) {
contentDocument.getElementById('later').click();
contentDocument.getElementById('sent').click();
contentDocument.getElementById('trash').click();
contentDocument.getElementById('inbox').click();
}
}),
new BenchmarkTestStep('MovingEmails' + actionCount + 'Times', function (newTodo, contentWindow, contentDocument) {
contentDocument.getElementById('inbox').click();
for (var i = 0; i < actionCount; i++) {
contentDocument.getElementById('mail_2139').click();
contentDocument.getElementById('move_mail').click();
contentDocument.querySelector('#move_to_selector #later').click();
contentDocument.getElementById('later').click();
contentDocument.getElementById('mail_2139').click();
contentDocument.getElementById('move_mail').click();
contentDocument.querySelector('#move_to_selector #trash').click();
contentDocument.getElementById('trash').click();
contentDocument.getElementById('mail_2139').click();
contentDocument.getElementById('move_mail').click();
contentDocument.querySelector('#move_to_selector #inbox').click();
contentDocument.getElementById('inbox').click();
}
}),
new BenchmarkTestStep('Sending' + actionCount + 'NewEmails', function (newTodo, contentWindow, contentDocument) {
for (var i = 0; i < actionCount; i++) {
contentDocument.getElementById('new_mail').click();
contentDocument.getElementById('recipient_select').selectedIndex = 1;
var subject = contentDocument.getElementById('compose_subject');
var message = contentDocument.getElementById('compose_message');
subject.focus();
contentWindow.$(subject).trigger('keydown');
contentWindow.$(subject).text('Hello');
message.focus();
contentWindow.$(message).trigger('keydown');
contentWindow.$(message).text('Hello,\n\nThis is a test message.\n\n- WebKitten');
contentDocument.getElementById('send_composed').click();
}
}),
]
});

Просмотреть файл

@ -0,0 +1,57 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "todo-app"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

Просмотреть файл

@ -0,0 +1,11 @@
# Speedometer 2.0: Angular 4 TodoMVC example
## Test locally
1. `npm install`
2. `npm run start-prod`
3. Navigate to `http://localhost:4200/`
## Build (do this before committing!)
1. `npm run build-prod`

Просмотреть файл

@ -0,0 +1,370 @@
html,
body {
margin: 0;
padding: 0;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #f5f5f5;
color: #4d4d4d;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 300;
}
:focus {
outline: 0;
}
.hidden {
display: none;
}
.todoapp {
background: #fff;
margin: 130px 0 40px 0;
position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::-moz-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
.todoapp h1 {
position: absolute;
top: -155px;
width: 100%;
font-size: 100px;
font-weight: 100;
text-align: center;
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
.new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
}
.main {
position: relative;
z-index: 2;
border-top: 1px solid #e6e6e6;
}
label[for='toggle-all'] {
display: none;
}
.toggle-all {
position: absolute;
top: -55px;
left: -12px;
width: 60px;
height: 34px;
text-align: center;
border: none; /* Mobile Safari */
}
.toggle-all:before {
content: '';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
.toggle-all:checked:before {
color: #737373;
}
.todo-list {
margin: 0;
padding: 0;
list-style: none;
}
.todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px solid #ededed;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list li.editing {
border-bottom: none;
padding: 0;
}
.todo-list li.editing .edit {
display: block;
width: 506px;
padding: 12px 16px;
margin: 0 0 0 43px;
}
.todo-list li.editing .view {
display: none;
}
.todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
border: none; /* Mobile Safari */
-webkit-appearance: none;
appearance: none;
}
.todo-list li .toggle:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
}
.todo-list li .toggle:checked:after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
}
.todo-list li label {
word-break: break-all;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
transition: color 0.4s;
}
.todo-list li.completed label {
color: #d9d9d9;
text-decoration: line-through;
}
.todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
.todo-list li .destroy:hover {
color: #af5b5e;
}
.todo-list li .destroy:after {
content: '×';
}
.todo-list li:hover .destroy {
display: block;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing:last-child {
margin-bottom: -1px;
}
.footer {
color: #777;
padding: 10px 15px;
height: 20px;
text-align: center;
border-top: 1px solid #e6e6e6;
}
.footer:before {
content: '';
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 50px;
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.todo-count strong {
font-weight: 300;
}
.filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
.filters li {
display: inline;
}
.filters li a {
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
.filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.clear-completed,
html .clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
cursor: pointer;
}
.clear-completed:hover {
text-decoration: underline;
}
.info {
margin: 65px auto 0;
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
.info p {
line-height: 1;
}
.info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
.info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
.toggle-all,
.todo-list li .toggle {
background: none;
}
.todo-list li .toggle {
height: 40px;
}
.toggle-all {
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
@media (max-width: 430px) {
.footer {
height: 50px;
}
.filters {
bottom: 10px;
}
}

Просмотреть файл

@ -0,0 +1,141 @@
hr {
margin: 20px 0;
border: 0;
border-top: 1px dashed #c5c5c5;
border-bottom: 1px dashed #f7f7f7;
}
.learn a {
font-weight: normal;
text-decoration: none;
color: #b83f45;
}
.learn a:hover {
text-decoration: underline;
color: #787e7e;
}
.learn h3,
.learn h4,
.learn h5 {
margin: 10px 0;
font-weight: 500;
line-height: 1.2;
color: #000;
}
.learn h3 {
font-size: 24px;
}
.learn h4 {
font-size: 18px;
}
.learn h5 {
margin-bottom: 0;
font-size: 14px;
}
.learn ul {
padding: 0;
margin: 0 0 30px 25px;
}
.learn li {
line-height: 20px;
}
.learn p {
font-size: 15px;
font-weight: 300;
line-height: 1.3;
margin-top: 0;
margin-bottom: 0;
}
#issue-count {
display: none;
}
.quote {
border: none;
margin: 20px 0 60px 0;
}
.quote p {
font-style: italic;
}
.quote p:before {
content: '“';
font-size: 50px;
opacity: .15;
position: absolute;
top: -20px;
left: 3px;
}
.quote p:after {
content: '”';
font-size: 50px;
opacity: .15;
position: absolute;
bottom: -42px;
right: 3px;
}
.quote footer {
position: absolute;
bottom: -40px;
right: 0;
}
.quote footer img {
border-radius: 3px;
}
.quote footer a {
margin-left: 5px;
vertical-align: middle;
}
.speech-bubble {
position: relative;
padding: 10px;
background: rgba(0, 0, 0, .04);
border-radius: 5px;
}
.speech-bubble:after {
content: '';
position: absolute;
top: 100%;
right: 30px;
border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04);
}
.learn-bar > .learn {
position: absolute;
width: 272px;
top: 8px;
left: -300px;
padding: 10px;
border-radius: 5px;
background-color: rgba(255, 255, 255, .6);
transition-property: left;
transition-duration: 500ms;
}
@media (min-width: 899px) {
.learn-bar {
width: auto;
padding-left: 300px;
}
.learn-bar > .learn {
left: 8px;
}
}

Двоичные данные
third_party/speedometer/resources/todomvc/architecture-examples/angular/dist/favicon.ico поставляемый Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

Просмотреть файл

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Angular 4 TodoMVC example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="assets/css/todomvc-common.css">
<link rel="stylesheet" href="assets/css/todomvc-app.css">
<link href="styles.d41d8cd98f00b204e980.bundle.css" rel="stylesheet"/></head>
<body>
<app-root>Loading...</app-root>
<!-- Credits: Addy Osmani -->
<script type="text/javascript" src="inline.28efc571905d42a672b0.bundle.js"></script><script type="text/javascript" src="polyfills.3a2aed82a0c9b24e6585.bundle.js"></script><script type="text/javascript" src="vendor.9a296bbc1909830a9106.bundle.js"></script><script type="text/javascript" src="main.c82799edffc751aa6590.bundle.js"></script></body>
</html>

Просмотреть файл

@ -0,0 +1 @@
!function(e){function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}var n=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var u,i,f,l=0,s=[];l<t.length;l++)i=t[l],o[i]&&s.push(o[i][0]),o[i]=0;for(u in c)Object.prototype.hasOwnProperty.call(c,u)&&(e[u]=c[u]);for(n&&n(t,c,a);s.length;)s.shift()();if(a)for(l=0;l<a.length;l++)f=r(r.s=a[l]);return f};var t={},o={4:0};r.e=function(e){function n(){c.onerror=c.onload=null,clearTimeout(a);var r=o[e];0!==r&&(r&&r[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}if(0===o[e])return Promise.resolve();if(o[e])return o[e][2];var t=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.charset="utf-8",c.async=!0,c.timeout=12e4,r.nc&&c.setAttribute("nonce",r.nc),c.src=r.p+""+e+"."+{0:"3a2aed82a0c9b24e6585",1:"c82799edffc751aa6590",2:"a63205ae4b55b180b58c"}[e]+".chunk.js";var a=setTimeout(n,12e4);c.onerror=c.onload=n;var u=new Promise(function(r,n){o[e]=[r,n]});return o[e][2]=u,t.appendChild(c),u},r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,n,t){r.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:t})},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},r.p="",r.oe=function(e){throw console.error(e),e}}([]);

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -0,0 +1,44 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
files: [
{ pattern: './src/test.ts', watched: false }
],
preprocessors: {
'./src/test.ts': ['@angular/cli']
},
mime: {
'text/x-typescript': ['ts','tsx']
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'coverage-istanbul']
: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

9426
third_party/speedometer/resources/todomvc/architecture-examples/angular/package-lock.json сгенерированный поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,46 @@
{
"private": true,
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"start-prod": "ng serve -prod",
"build": "ng build",
"build-prod": "ng build -prod",
"test": "ng test",
"lint": "ng lint"
},
"dependencies": {
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/forms": "^4.0.0",
"@angular/http": "^4.0.0",
"@angular/platform-browser": "^4.0.0",
"@angular/platform-browser-dynamic": "^4.0.0",
"@angular/router": "^4.0.0",
"core-js": "^2.4.1",
"enhanced-resolve": "^3.3.0",
"rxjs": "^5.1.0",
"zone.js": "^0.8.4"
},
"devDependencies": {
"@angular/cli": "1.0.0",
"@angular/compiler-cli": "^4.0.0",
"@types/jasmine": "2.5.38",
"@types/node": "~6.0.60",
"codelyzer": "~2.0.0",
"jasmine-core": "~2.5.2",
"jasmine-spec-reporter": "~3.2.0",
"karma": "~1.4.1",
"karma-chrome-launcher": "~2.0.0",
"karma-cli": "~1.0.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"karma-coverage-istanbul-reporter": "^0.2.0",
"protractor": "~5.1.0",
"ts-node": "~2.0.0",
"tslint": "~4.5.0",
"typescript": "~2.2.0"
}
}

Просмотреть файл

@ -0,0 +1,30 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
},
onPrepare() {
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

Просмотреть файл

@ -0,0 +1,20 @@
<section class="todoapp">
<header class="header">
<h1>Todos</h1>
<input class="new-todo" placeholder="What needs to be done?" autofocus="" [(ngModel)]="newTodo.title" (keyup.enter)="addTodo()">
</header>
<section class="main" *ngIf="todos.length > 0">
<ul class="todo-list">
<li *ngFor="let todo of todos" [class.completed]="todo.complete">
<div class="view">
<input class="toggle" type="checkbox" (click)="toggleTodoComplete(todo)" [checked]="todo.complete">
<label>{{todo.title}}</label>
<button class="destroy" (click)="removeTodo(todo)"></button>
</div>
</li>
</ul>
</section>
<footer class="footer" *ngIf="todos.length > 0">
<span class="todo-count"><strong>{{todos.length}}</strong> {{todos.length == 1 ? 'item' : 'items'}} left</span>
</footer>
</section>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше