From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../todomvc/vanilla-examples/es2015/README.md | 10 + .../todomvc/vanilla-examples/es2015/index.html | 46 +++ .../es2015/node_modules/todomvc-app-css/index.css | 376 +++++++++++++++++++++ .../node_modules/todomvc-app-css/package.json | 58 ++++ .../es2015/node_modules/todomvc-app-css/readme.md | 28 ++ .../es2015/node_modules/todomvc-common/base.css | 141 ++++++++ .../es2015/node_modules/todomvc-common/base.js | 249 ++++++++++++++ .../node_modules/todomvc-common/package.json | 54 +++ .../es2015/node_modules/todomvc-common/readme.md | 15 + .../todomvc/vanilla-examples/es2015/package.json | 7 + .../todomvc/vanilla-examples/es2015/src/.jshintrc | 3 + .../todomvc/vanilla-examples/es2015/src/app.js | 27 ++ .../vanilla-examples/es2015/src/controller.js | 214 ++++++++++++ .../todomvc/vanilla-examples/es2015/src/helpers.js | 53 +++ .../todomvc/vanilla-examples/es2015/src/model.js | 117 +++++++ .../todomvc/vanilla-examples/es2015/src/store.js | 152 +++++++++ .../vanilla-examples/es2015/src/template.js | 95 ++++++ .../todomvc/vanilla-examples/es2015/src/view.js | 178 ++++++++++ 18 files changed, 1823 insertions(+) create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/README.md create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/index.html create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/index.css create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/package.json create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/readme.md create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.css create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/package.json create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/readme.md create mode 100755 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/package.json create mode 100755 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/.jshintrc create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/app.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/controller.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/helpers.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/model.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/store.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/template.js create mode 100644 third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/view.js (limited to 'third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015') diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/README.md b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/README.md new file mode 100644 index 0000000000..2134b4624f --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/README.md @@ -0,0 +1,10 @@ +# Speedometer 2.1: ES2015 TodoMVC example + +## Test locally + +1. Run a local server from this directory. (You could use [`npm i -g http-server`](https://github.com/indexzero/http-server).) +2. Open the URL pointing to the local server in your web browser of choice. + +## Build + +There is no build step for this example. diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/index.html b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/index.html new file mode 100644 index 0000000000..58ca3a9f44 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/index.html @@ -0,0 +1,46 @@ + + + + + ES2015 TodoMVC example + + + + +
+
+

todos

+ +
+ +
+ + +
    +
    + + +
    + +
    +

    Double-click to edit a todo

    +
    +

    Part of TodoMVC

    +
    + + + + + + + + + diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/index.css b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/index.css new file mode 100644 index 0000000000..e04fbdbdb4 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/index.css @@ -0,0 +1,376 @@ +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; +} + +.toggle-all { + text-align: center; + border: none; /* Mobile Safari */ + opacity: 0; + position: absolute; +} + +.toggle-all + label { + width: 60px; + height: 34px; + font-size: 0; + position: absolute; + top: -52px; + left: -13px; + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.toggle-all + label:before { + content: '❯'; + font-size: 22px; + color: #e6e6e6; + padding: 10px 27px 10px 27px; +} + +.toggle-all:checked + label: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 { + opacity: 0; +} + +.todo-list li .toggle + label { + /* + Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433 + IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/ + */ + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E'); + background-repeat: no-repeat; + background-position: center left; +} + +.todo-list li .toggle:checked + label { + background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E'); +} + +.todo-list li label { + word-break: break-all; + padding: 15px 15px 15px 60px; + 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; + } +} + +@media (max-width: 430px) { + .footer { + height: 50px; + } + + .filters { + bottom: 10px; + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/package.json b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/package.json new file mode 100644 index 0000000000..27caf2b32a --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/package.json @@ -0,0 +1,58 @@ +{ + "_from": "todomvc-app-css@^2.1.0", + "_id": "todomvc-app-css@2.1.0", + "_inBundle": false, + "_integrity": "sha1-tvJxbTOa+i5feZNH0qSLBTliQqU=", + "_location": "/todomvc-app-css", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "todomvc-app-css@^2.1.0", + "name": "todomvc-app-css", + "escapedName": "todomvc-app-css", + "rawSpec": "^2.1.0", + "saveSpec": null, + "fetchSpec": "^2.1.0" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/todomvc-app-css/-/todomvc-app-css-2.1.0.tgz", + "_shasum": "b6f2716d339afa2e5f799347d2a48b05396242a5", + "_spec": "todomvc-app-css@^2.1.0", + "_where": "/Users/mathiasb/projects/WebKit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015", + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/tastejs/todomvc-app-css/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "CSS for TodoMVC apps", + "files": [ + "index.css" + ], + "homepage": "https://github.com/tastejs/todomvc-app-css#readme", + "keywords": [ + "todomvc", + "tastejs", + "app", + "todo", + "template", + "css", + "style", + "stylesheet" + ], + "license": "CC-BY-4.0", + "name": "todomvc-app-css", + "repository": { + "type": "git", + "url": "git+https://github.com/tastejs/todomvc-app-css.git" + }, + "style": "index.css", + "version": "2.1.0" +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/readme.md b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/readme.md new file mode 100644 index 0000000000..6ddbebf024 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-app-css/readme.md @@ -0,0 +1,28 @@ +# todomvc-app-css + +> CSS for TodoMVC apps + +![](screenshot.png) + + +## Install + + +``` +$ npm install --save todomvc-app-css +``` + + +## Getting started + +```html + +``` + +See the [TodoMVC app template](https://github.com/tastejs/todomvc-app-template). + + + +## License + +Creative Commons License
    This work by Sindre Sorhus is licensed under a Creative Commons Attribution 4.0 International License. diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.css b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.css new file mode 100644 index 0000000000..4d25d3c84a --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.css @@ -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; + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.js new file mode 100644 index 0000000000..e1676dbb8f --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/base.js @@ -0,0 +1,249 @@ +/* global _ */ +(function () { + 'use strict'; + + /* jshint ignore:start */ + // Underscore's Template Module + // Courtesy of underscorejs.org + var _ = (function (_) { + _.defaults = function (object) { + if (!object) { + return object; + } + for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { + var iterable = arguments[argsIndex]; + if (iterable) { + for (var key in iterable) { + if (object[key] == null) { + object[key] = iterable[key]; + } + } + } + } + return object; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\t': 't', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + _.template = function(text, data, settings) { + var render; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = new RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset) + .replace(escaper, function(match) { return '\\' + escapes[match]; }); + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } + if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } + if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + index = offset + match.length; + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + "return __p;\n"; + + try { + render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + if (data) return render(data, _); + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled function source as a convenience for precompilation. + template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; + + return template; + }; + + return _; + })({}); + + if (location.hostname === 'todomvc.com') { + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); + ga('create', 'UA-31081062-1', 'auto'); + ga('send', 'pageview'); + } + /* jshint ignore:end */ + + function redirect() { + if (location.hostname === 'tastejs.github.io') { + location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); + } + } + + function findRoot() { + var base = location.href.indexOf('examples/'); + return location.href.substr(0, base); + } + + function getFile(file, callback) { + if (!location.host) { + return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); + } + + var xhr = new XMLHttpRequest(); + + xhr.open('GET', findRoot() + file, true); + xhr.send(); + + xhr.onload = function () { + if (xhr.status === 200 && callback) { + callback(xhr.responseText); + } + }; + } + + function Learn(learnJSON, config) { + if (!(this instanceof Learn)) { + return new Learn(learnJSON, config); + } + + var template, framework; + + if (typeof learnJSON !== 'object') { + try { + learnJSON = JSON.parse(learnJSON); + } catch (e) { + return; + } + } + + if (config) { + template = config.template; + framework = config.framework; + } + + if (!template && learnJSON.templates) { + template = learnJSON.templates.todomvc; + } + + if (!framework && document.querySelector('[data-framework]')) { + framework = document.querySelector('[data-framework]').dataset.framework; + } + + this.template = template; + + if (learnJSON.backend) { + this.frameworkJSON = learnJSON.backend; + this.frameworkJSON.issueLabel = framework; + this.append({ + backend: true + }); + } else if (learnJSON[framework]) { + this.frameworkJSON = learnJSON[framework]; + this.frameworkJSON.issueLabel = framework; + this.append(); + } + + this.fetchIssueCount(); + } + + Learn.prototype.append = function (opts) { + var aside = document.createElement('aside'); + aside.innerHTML = _.template(this.template, this.frameworkJSON); + aside.className = 'learn'; + + if (opts && opts.backend) { + // Remove demo link + var sourceLinks = aside.querySelector('.source-links'); + var heading = sourceLinks.firstElementChild; + var sourceLink = sourceLinks.lastElementChild; + // Correct link path + var href = sourceLink.getAttribute('href'); + sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http'))); + sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML; + } else { + // Localize demo links + var demoLinks = aside.querySelectorAll('.demo-link'); + Array.prototype.forEach.call(demoLinks, function (demoLink) { + if (demoLink.getAttribute('href').substr(0, 4) !== 'http') { + demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); + } + }); + } + + document.body.className = (document.body.className + ' learn-bar').trim(); + document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); + }; + + Learn.prototype.fetchIssueCount = function () { + var issueLink = document.getElementById('issue-count-link'); + if (issueLink) { + var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos'); + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.onload = function (e) { + var parsedResponse = JSON.parse(e.target.responseText); + if (parsedResponse instanceof Array) { + var count = parsedResponse.length; + if (count !== 0) { + issueLink.innerHTML = 'This app has ' + count + ' open issues'; + document.getElementById('issue-count').style.display = 'inline'; + } + } + }; + xhr.send(); + } + }; + + redirect(); + getFile('learn.json', Learn); +})(); diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/package.json b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/package.json new file mode 100644 index 0000000000..74e35f4266 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/package.json @@ -0,0 +1,54 @@ +{ + "_from": "todomvc-common@^1.0.4", + "_id": "todomvc-common@1.0.4", + "_inBundle": false, + "_integrity": "sha512-AA0Z4exovEqubhbZCrzzn9roVT4zvOncS319p2zIc4CsNe5B9TLL7Sei1NIV6d+WrgR5rOi+y0I9Y6GE7xgNOw==", + "_location": "/todomvc-common", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "todomvc-common@^1.0.4", + "name": "todomvc-common", + "escapedName": "todomvc-common", + "rawSpec": "^1.0.4", + "saveSpec": null, + "fetchSpec": "^1.0.4" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/todomvc-common/-/todomvc-common-1.0.4.tgz", + "_shasum": "23099af886c2f0525bfd4537e078f12d0074309e", + "_spec": "todomvc-common@^1.0.4", + "_where": "/Users/mathiasb/projects/WebKit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015", + "author": { + "name": "TasteJS" + }, + "bugs": { + "url": "https://github.com/tastejs/todomvc-common/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Common TodoMVC utilities used by our apps", + "files": [ + "base.js", + "base.css" + ], + "homepage": "https://github.com/tastejs/todomvc-common#readme", + "keywords": [ + "todomvc", + "tastejs", + "util", + "utilities" + ], + "license": "MIT", + "main": "base.js", + "name": "todomvc-common", + "repository": { + "type": "git", + "url": "git+https://github.com/tastejs/todomvc-common.git" + }, + "style": "base.css", + "version": "1.0.4" +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/readme.md b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/readme.md new file mode 100644 index 0000000000..7a5de5118f --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/node_modules/todomvc-common/readme.md @@ -0,0 +1,15 @@ +# todomvc-common + +> Common TodoMVC utilities used by our apps + + +## Install + +``` +$ npm install --save todomvc-common +``` + + +## License + +MIT © [TasteJS](http://tastejs.com) diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/package.json b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/package.json new file mode 100755 index 0000000000..7e5833048b --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "dependencies": { + "todomvc-app-css": "^2.1.0", + "todomvc-common": "^1.0.4" + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/.jshintrc b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/.jshintrc new file mode 100755 index 0000000000..ffd48eb291 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/.jshintrc @@ -0,0 +1,3 @@ +{ + "esnext": true +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/app.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/app.js new file mode 100644 index 0000000000..e65d9c56d1 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/app.js @@ -0,0 +1,27 @@ +'use strict'; + +let todo; +const setView = () => todo.controller.setView(document.location.hash); + +class Todo { + /** + * Init new Todo List + * @param {string} The name of your list + */ + constructor(name) { + this.storage = new Store(name); + this.model = new Model(this.storage); + + this.template = new Template(); + this.view = new View(this.template); + + this.controller = new Controller(this.model, this.view); + } +} + +$on(window, 'load', () => { + todo = new Todo('todos-vanillajs'); + setView(); +}); + +$on(window, 'hashchange', setView); diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/controller.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/controller.js new file mode 100644 index 0000000000..d2693ec20e --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/controller.js @@ -0,0 +1,214 @@ +'use strict'; + +class Controller { + /** + * Take a model & view, then act as controller between them + * @param {object} model The model instance + * @param {object} view The view instance + */ + constructor(model, view) { + this.model = model; + this.view = view; + + this.view.bind('newTodo', title => this.addItem(title)); + this.view.bind('itemEdit', item => this.editItem(item.id)); + this.view.bind('itemEditDone', item => this.editItemSave(item.id, item.title)); + this.view.bind('itemEditCancel', item => this.editItemCancel(item.id)); + this.view.bind('itemRemove', item => this.removeItem(item.id)); + this.view.bind('itemToggle', item => this.toggleComplete(item.id, item.completed)); + this.view.bind('removeCompleted', () => this.removeCompletedItems()); + this.view.bind('toggleAll', status => this.toggleAll(status.completed)); + } + + /** + * Load & Initialize the view + * @param {string} '' | 'active' | 'completed' + */ + setView(hash){ + let route = hash.split('/')[1]; + let page = route || ''; + this._updateFilter(page); + } + + /** + * Event fires on load. Gets all items & displays them + */ + showAll(){ + this.model.read(data => this.view.render('showEntries', data)); + } + + /** + * Renders all active tasks + */ + showActive(){ + this.model.read({completed: false}, data => this.view.render('showEntries', data)); + } + + /** + * Renders all completed tasks + */ + showCompleted(){ + this.model.read({completed: true}, data => this.view.render('showEntries', data)); + } + + /** + * An event to fire whenever you want to add an item. Simply pass in the event + * object and it'll handle the DOM insertion and saving of the new item. + */ + addItem(title){ + if (title.trim() === '') { + return; + } + + this.model.create(title, () => { + this.view.render('clearNewTodo'); + this._filter(true); + }); + } + + /* + * Triggers the item editing mode. + */ + editItem(id){ + this.model.read(id, data => { + let title = data[0].title; + this.view.render('editItem', {id, title}); + }); + } + + /* + * Finishes the item editing mode successfully. + */ + editItemSave(id, title){ + title = title.trim(); + + if (title.length !== 0) { + this.model.update(id, {title}, () => { + this.view.render('editItemDone', {id, title}); + }); + } else { + this.removeItem(id); + } + } + + /* + * Cancels the item editing mode. + */ + editItemCancel(id){ + this.model.read(id, data => { + let title = data[0].title; + this.view.render('editItemDone', {id, title}); + }); + } + + /** + * Find the DOM element with given ID, + * Then remove it from DOM & Storage + */ + removeItem(id){ + this.model.remove(id, () => this.view.render('removeItem', id)); + this._filter(); + } + + /** + * Will remove all completed items from the DOM and storage. + */ + removeCompletedItems(){ + this.model.read({completed: true}, data => { + for (let item of data) { + this.removeItem(item.id); + } + }); + + this._filter(); + } + + /** + * Give it an ID of a model and a checkbox and it will update the item + * in storage based on the checkbox's state. + * + * @param {number} id The ID of the element to complete or uncomplete + * @param {object} checkbox The checkbox to check the state of complete + * or not + * @param {boolean|undefined} silent Prevent re-filtering the todo items + */ + toggleComplete(id, completed, silent){ + this.model.update(id, {completed}, () => { + this.view.render('elementComplete', {id, completed}); + }); + + if (!silent) { + this._filter(); + } + } + + /** + * Will toggle ALL checkboxes' on/off state and completeness of models. + * Just pass in the event object. + */ + toggleAll(completed){ + this.model.read({completed: !completed}, data => { + for (let item of data) { + this.toggleComplete(item.id, completed, true); + } + }); + + this._filter(); + } + + /** + * Updates the pieces of the page which change depending on the remaining + * number of todos. + */ + _updateCount(){ + this.model.getCount(todos => { + const completed = todos.completed; + const visible = completed > 0; + const checked = completed === todos.total; + + this.view.render('updateElementCount', todos.active); + this.view.render('clearCompletedButton', {completed, visible}); + + this.view.render('toggleAll', {checked}); + this.view.render('contentBlockVisibility', {visible: todos.total > 0}); + }); + } + + /** + * Re-filters the todo items, based on the active route. + * @param {boolean|undefined} force forces a re-painting of todo items. + */ + _filter(force){ + let active = this._activeRoute; + const activeRoute = active.charAt(0).toUpperCase() + active.substr(1); + + // Update the elements on the page, which change with each completed todo + this._updateCount(); + + // If the last active route isn't "All", or we're switching routes, we + // re-create the todo item elements, calling: + // this.show[All|Active|Completed]() + if (force || this._lastActiveRoute !== 'All' || this._lastActiveRoute !== activeRoute) { + this['show' + activeRoute](); + } + + this._lastActiveRoute = activeRoute; + } + + /** + * Simply updates the filter nav's selected states + */ + _updateFilter(currentPage){ + // Store a reference to the active route, allowing us to re-filter todo + // items as they are marked complete or incomplete. + this._activeRoute = currentPage; + + if (currentPage === '') { + this._activeRoute = 'All'; + } + + this._filter(); + + this.view.render('setFilter', currentPage); + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/helpers.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/helpers.js new file mode 100644 index 0000000000..154fc48351 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/helpers.js @@ -0,0 +1,53 @@ +'use strict'; + + +// Allow for looping on nodes by chaining: +// qsa('.foo').forEach(function () {}) +NodeList.prototype.forEach = Array.prototype.forEach; + +// Get element(s) by CSS selector: +function qs(selector, scope) { + return (scope || document).querySelector(selector); +} + +function qsa(selector, scope) { + return (scope || document).querySelectorAll(selector); +} + +// addEventListener wrapper: +function $on(target, type, callback, useCapture) { + target.addEventListener(type, callback, !!useCapture); +} + +// Attach a handler to event for all elements that match the selector, +// now or in the future, based on a root element +function $delegate(target, selector, type, handler) { + let dispatchEvent = event => { + const targetElement = event.target; + const potentialElements = qsa(selector, target); + const hasMatch = Array.prototype.indexOf.call(potentialElements, targetElement) >= 0; + + if (hasMatch) { + handler.call(targetElement, event); + } + }; + + // https://developer.mozilla.org/en-US/docs/Web/Events/blur + const useCapture = type === 'blur' || type === 'focus'; + + $on(target, type, dispatchEvent, useCapture); +} + +// Find the element's parent with the given tag name: +// $parent(qs('a'), 'div') +function $parent(element, tagName) { + if (!element.parentNode) { + return; + } + + if (element.parentNode.tagName.toLowerCase() === tagName.toLowerCase()) { + return element.parentNode; + } + + return $parent(element.parentNode, tagName); +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/model.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/model.js new file mode 100644 index 0000000000..cf8d58181b --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/model.js @@ -0,0 +1,117 @@ +'use strict'; + + +/** + * Creates a new Model instance and hooks up the storage. + * @constructor + * @param {object} storage A reference to the client side storage class + */ +class Model { + constructor(storage) { + this.storage = storage; + } + + /** + * Creates a new todo model + * + * @param {string} [title] The title of the task + * @param {function} [callback] The callback to fire after the model is created + */ + create(title, callback){ + title = title || ''; + + let newItem = { + title: title.trim(), + completed: false + }; + + this.storage.save(newItem, callback); + } + + /** + * Finds and returns a model in storage. If no query is given it'll simply + * return everything. If you pass in a string or number it'll look that up as + * the ID of the model to find. Lastly, you can pass it an object to match + * against. + * + * @param {string|number|object} [query] A query to match models against + * @param {function} [callback] The callback to fire after the model is found + * + * @example + * model.read(1, func) // Will find the model with an ID of 1 + * model.read('1') // Same as above + * //Below will find a model with foo equalling bar and hello equalling world. + * model.read({ foo: 'bar', hello: 'world' }) + */ + read(query, callback){ + const queryType = typeof query; + + if (queryType === 'function') { + callback = query; + this.storage.findAll(callback); + } else if (queryType === 'string' || queryType === 'number') { + query = parseInt(query, 10); + this.storage.find({id: query}, callback); + } else { + this.storage.find(query, callback); + } + } + + /** + * Updates a model by giving it an ID, data to update, and a callback to fire when + * the update is complete. + * + * @param {number} id The id of the model to update + * @param {object} data The properties to update and their new value + * @param {function} callback The callback to fire when the update is complete. + */ + update(id, data, callback){ + this.storage.save(data, callback, id); + } + + /** + * Removes a model from storage + * + * @param {number} id The ID of the model to remove + * @param {function} callback The callback to fire when the removal is complete. + */ + remove(id, callback){ + this.storage.remove(id, callback); + } + + /** + * WARNING: Will remove ALL data from storage. + * + * @param {function} callback The callback to fire when the storage is wiped. + */ + removeAll(callback){ + this.storage.drop(callback); + } + + /** + * Returns a count of all todos + */ + getCount(callback){ + let todos = { + active: 0, + completed: 0, + total: 0 + }; + + this.storage.findAll(data => { + for (let todo of data) { + if (todo.completed) { + todos.completed++; + } else { + todos.active++; + } + + todos.total++; + } + + if (callback) { + callback(todos); + } + }); + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/store.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/store.js new file mode 100644 index 0000000000..dc22f25107 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/store.js @@ -0,0 +1,152 @@ +/*jshint eqeqeq:false */ +'use strict'; + +let uniqueID = 1; + +/** + * Creates a new client side storage object and will create an empty + * collection if no collection already exists. + * + * @param {string} name The name of our DB we want to use + * @param {function} callback Our fake DB uses callbacks because in + * real life you probably would be making AJAX calls + */ +class Store { + constructor(name, callback) { + this._dbName = name; + this.memoryStorage = this.memoryStorage || {}; + + if (!this.memoryStorage[name]) { + let data = { + todos: [] + }; + + this.memoryStorage[name] = JSON.stringify(data); + } + + if (callback) { + callback.call(this, JSON.parse(this.memoryStorage[name])); + } + } + + /** + * Finds items based on a query given as a JS object + * + * @param {object} query The query to match against (i.e. {foo: 'bar'}) + * @param {function} callback The callback to fire when the query has + * completed running + * + * @example + * db.find({foo: 'bar', hello: 'world'}, function (data) { + * // data will return any items that have foo: bar and + * // hello: world in their properties + * }) + */ + find(query, callback){ + if (!callback) { + return; + } + + let todos = JSON.parse(this.memoryStorage[this._dbName]).todos; + + callback.call(this, todos.filter(todo => { + for (let q in query) { + if (query[q] !== todo[q]) { + return false; + } + } + return true; + })); + } + + /** + * Will retrieve all data from the collection + * + * @param {function} callback The callback to fire upon retrieving data + */ + findAll(callback){ + if (callback) { + callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); + } + } + + /** + * Will save the given data to the DB. If no item exists it will create a new + * item, otherwise it'll simply update an existing item's properties + * + * @param {object} updateData The data to save back into the DB + * @param {function} callback The callback to fire after saving + * @param {number} id An optional param to enter an ID of an item to update + */ + save(updateData, callback, id){ + const data = JSON.parse(this.memoryStorage[this._dbName]); + let todos = data.todos; + const len = todos.length; + + // If an ID was actually given, find the item and update each property + if (id) { + for (let i = 0; i < len; i++) { + if (todos[i].id === id) { + for (let key in updateData) { + todos[i][key] = updateData[key]; + } + break; + } + } + + this.memoryStorage[this._dbName] = JSON.stringify(data); + + if (callback) { + callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); + } + } else { + // Generate an ID + updateData.id = uniqueID++; + + todos.push(updateData); + this.memoryStorage[this._dbName] = JSON.stringify(data); + + if (callback) { + callback.call(this, [updateData]); + } + } + } + + /** + * Will remove an item from the Store based on its ID + * + * @param {number} id The ID of the item you want to remove + * @param {function} callback The callback to fire after saving + */ + remove(id, callback){ + const data = JSON.parse(this.memoryStorage[this._dbName]); + let todos = data.todos; + const len = todos.length; + + for (let i = 0; i < todos.length; i++) { + if (todos[i].id == id) { + todos.splice(i, 1); + break; + } + } + + this.memoryStorage[this._dbName] = JSON.stringify(data); + + if (callback) { + callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); + } + } + + /** + * Will drop all storage and start fresh + * + * @param {function} callback The callback to fire after dropping the data + */ + drop(callback){ + this.memoryStorage[this._dbName] = JSON.stringify({todos: []}); + + if (callback) { + callback.call(this, JSON.parse(this.memoryStorage[this._dbName]).todos); + } + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/template.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/template.js new file mode 100644 index 0000000000..77d4dd4c60 --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/template.js @@ -0,0 +1,95 @@ +'use strict'; + + +const htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + '\'': ''', + '`': '`' +}; + +const reUnescapedHtml = /[&<>"'`]/g; +const reHasUnescapedHtml = new RegExp(reUnescapedHtml.source); + +let escape = str => (str && reHasUnescapedHtml.test(str)) ? str.replace(reUnescapedHtml, escapeHtmlChar) : str; +let escapeHtmlChar = chr => htmlEscapes[chr]; + +class Template { + constructor() { + this.defaultTemplate = ` +
  • +
    + + + +
    +
  • + `; + } + + /** + * Creates an
  • HTML string and returns it for placement in your app. + * + * NOTE: In real life you should be using a templating engine such as Mustache + * or Handlebars, however, this is a vanilla JS example. + * + * @param {object} data The object containing keys you want to find in the + * template to replace. + * @returns {string} HTML String of an
  • element + * + * @example + * view.show({ + * id: 1, + * title: "Hello World", + * completed: 0, + * }) + */ + show(data){ + let i = 0; + let view = ''; + const len = data.length; + + for (i; i < len; i++) { + let completed = ''; + let checked = ''; + let template = this.defaultTemplate; + + if (data[i].completed) { + completed = 'completed'; + checked = 'checked'; + } + + template = template.replace('{{id}}', data[i].id); + template = template.replace('{{title}}', escape(data[i].title)); + template = template.replace('{{completed}}', completed); + template = template.replace('{{checked}}', checked); + + view += template; + } + + return view; + } + + /** + * Displays a counter of how many to dos are left to complete + * + * @param {number} activeTodos The number of active todos. + * @returns {string} String containing the count + */ + itemCounter(activeTodos){ + let plural = activeTodos === 1 ? '' : 's'; + return `${activeTodos} item${plural} left`; + } + + /** + * Updates the text within the "Clear completed" button + * + * @param {[type]} completedTodos The number of completed todos. + * @returns {string} String containing the count + */ + clearCompletedButton(completedTodos){ + return (completedTodos > 0) ? 'Clear completed' : ''; + } +} diff --git a/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/view.js b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/view.js new file mode 100644 index 0000000000..4ba35d219c --- /dev/null +++ b/third_party/webkit/PerformanceTests/Speedometer/resources/todomvc/vanilla-examples/es2015/src/view.js @@ -0,0 +1,178 @@ +'use strict'; + + +// import {qs, qsa, $on, $parent, $delegate} from './helpers'; + +let _itemId = element => parseInt($parent(element, 'li').dataset.id, 10); + +let _setFilter = currentPage => { + qs('.filters .selected').className = ''; + qs(`.filters [href="#/${currentPage}"]`).className = 'selected'; +}; + +let _elementComplete = (id, completed) => { + let listItem = qs(`[data-id="${id}"]`); + + if (!listItem) { + return; + } + + listItem.className = completed ? 'completed' : ''; + + // In case it was toggled from an event and not by clicking the checkbox + qs('input', listItem).checked = completed; +}; + +let _editItem = (id, title) => { + let listItem = qs(`[data-id="${id}"]`); + + if (!listItem) { + return; + } + + listItem.className += ' editing'; + + let input = document.createElement('input'); + input.className = 'edit'; + + listItem.appendChild(input); + input.focus(); + input.value = title; +}; + +/** + * View that abstracts away the browser's DOM completely. + * It has two simple entry points: + * + * - bind(eventName, handler) + * Takes a todo application event and registers the handler + * - render(command, parameterObject) + * Renders the given command with the options + */ +class View { + constructor(template) { + this.template = template; + + this.ENTER_KEY = 13; + this.ESCAPE_KEY = 27; + + this.$todoList = qs('.todo-list'); + this.$todoItemCounter = qs('.todo-count'); + this.$clearCompleted = qs('.clear-completed'); + this.$main = qs('.main'); + this.$footer = qs('.footer'); + this.$toggleAll = qs('.toggle-all'); + this.$newTodo = qs('.new-todo'); + + this.viewCommands = { + showEntries: parameter => this.$todoList.innerHTML = this.template.show(parameter), + removeItem: parameter => this._removeItem(parameter), + updateElementCount: parameter => this.$todoItemCounter.innerHTML = this.template.itemCounter(parameter), + clearCompletedButton: parameter => this._clearCompletedButton(parameter.completed, parameter.visible), + contentBlockVisibility: parameter => this.$main.style.display = this.$footer.style.display = parameter.visible ? 'block' : 'none', + toggleAll: parameter => this.$toggleAll.checked = parameter.checked, + setFilter: parameter => _setFilter(parameter), + clearNewTodo: parameter => this.$newTodo.value = '', + elementComplete: parameter => _elementComplete(parameter.id, parameter.completed), + editItem: parameter => _editItem(parameter.id, parameter.title), + editItemDone: parameter => this._editItemDone(parameter.id, parameter.title), + }; + } + + _removeItem(id) { + let elem = qs(`[data-id="${id}"]`); + + if (elem) { + this.$todoList.removeChild(elem); + } + } + + _clearCompletedButton(completedCount, visible) { + this.$clearCompleted.innerHTML = this.template.clearCompletedButton(completedCount); + this.$clearCompleted.style.display = visible ? 'block' : 'none'; + } + + _editItemDone(id, title) { + let listItem = qs(`[data-id="${id}"]`); + + if (!listItem) { + return; + } + + let input = qs('input.edit', listItem); + listItem.removeChild(input); + + listItem.className = listItem.className.replace(' editing', ''); + + qsa('label', listItem).forEach(label => label.textContent = title); + } + + render(viewCmd, parameter) { + this.viewCommands[viewCmd](parameter); + } + + _bindItemEditDone(handler) { + let self = this; + + $delegate(self.$todoList, 'li .edit', 'blur', function () { + if (!this.dataset.iscanceled) { + handler({ + id: _itemId(this), + title: this.value + }); + } + }); + + // Remove the cursor from the input when you hit enter just like if it were a real form + $delegate(self.$todoList, 'li .edit', 'keypress', function (event) { + if (event.keyCode === self.ENTER_KEY) { + this.blur(); + } + }); + } + + _bindItemEditCancel(handler) { + let self = this; + + $delegate(self.$todoList, 'li .edit', 'keyup', function (event) { + if (event.keyCode === self.ESCAPE_KEY) { + let id = _itemId(this); + this.dataset.iscanceled = true; + this.blur(); + + handler({ id }); + } + }); + } + + bind(event, handler) { + if (event === 'newTodo') { + $on(this.$newTodo, 'change', () => handler(this.$newTodo.value)); + } else if (event === 'removeCompleted') { + $on(this.$clearCompleted, 'click', handler); + } else if (event === 'toggleAll') { + $on(this.$toggleAll, 'click', function(){ + handler({completed: this.checked}); + }); + } else if (event === 'itemEdit') { + $delegate(this.$todoList, 'li label', 'dblclick', function(){ + handler({id: _itemId(this)}); + }); + } else if (event === 'itemRemove') { + $delegate(this.$todoList, '.destroy', 'click', function(){ + handler({id: _itemId(this)}); + }); + } else if (event === 'itemToggle') { + $delegate(this.$todoList, '.toggle', 'click', function(){ + handler({ + id: _itemId(this), + completed: this.checked + }); + }); + } else if (event === 'itemEditDone') { + this._bindItemEditDone(handler); + } else if (event === 'itemEditCancel') { + this._bindItemEditCancel(handler); + } + } +} -- cgit v1.2.3