├── .gitignore
├── LICENCE
├── README.md
├── img
└── 2019-12-17.png
├── index.html
├── resources
├── benchmark-runner.js
├── manager.js
└── tests.js
└── todomvc
├── elm17
├── Todo.elm
├── bg.png
├── elm-package.json
├── elm.js
├── index.html
└── style.css
├── mithril
├── LICENSE
├── README.md
├── bower.json
├── bower_components
│ ├── mithril
│ │ ├── .bower.json
│ │ ├── .gitignore
│ │ ├── .travis.yml
│ │ ├── Gruntfile.js
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── background.html
│ │ ├── deploy
│ │ │ └── cdnjs-package.json
│ │ ├── mithril.d.ts
│ │ ├── mithril.js
│ │ └── package.json
│ └── todomvc-common
│ │ ├── .bower.json
│ │ ├── base.css
│ │ ├── base.js
│ │ ├── bg.png
│ │ ├── bower.json
│ │ └── readme.md
├── css
│ └── app.css
├── index.html
└── js
│ ├── app.js
│ ├── controllers
│ └── todo.js
│ ├── models
│ └── todo.js
│ └── views
│ ├── footer-view.js
│ ├── main-view.js
│ └── single-view.js
├── mogwai
├── index.html
├── pkg
│ ├── README.md
│ ├── mogwai_todo.d.ts
│ ├── mogwai_todo.js
│ ├── mogwai_todo_bg.d.ts
│ ├── mogwai_todo_bg.wasm
│ └── package.json
└── todo.css
├── preact
├── bower_components
│ └── todomvc-common
│ │ ├── .bower.json
│ │ ├── base.css
│ │ ├── base.js
│ │ ├── bg.png
│ │ ├── bower.json
│ │ └── readme.md
├── bundle.js
├── bundle.js.map
├── index.html
├── package.json
└── src
│ ├── app.js
│ ├── footer.js
│ ├── header.js
│ ├── index.js
│ ├── item.js
│ ├── model.js
│ └── util.js
├── react
├── .gitignore
├── index.html
├── js
│ ├── app.js
│ ├── app.jsx
│ ├── footer.js
│ ├── footer.jsx
│ ├── todoItem.js
│ ├── todoItem.jsx
│ ├── todoModel.js
│ └── utils.js
├── package.json
├── readme.md
├── todomvc-app-css
│ ├── index.css
│ ├── package.json
│ └── readme.md
└── todomvc-common
│ ├── base.css
│ └── base.js
├── sauron
├── index.html
├── pkg
│ ├── package.json
│ ├── todomvc.d.ts
│ ├── todomvc.js
│ ├── todomvc_bg.d.ts
│ └── todomvc_bg.wasm
└── style.css
├── seed
├── index.css
├── index.html
├── pkg
│ ├── README.md
│ ├── package.d.ts
│ ├── package.js
│ ├── package.json
│ ├── package_bg.d.ts
│ ├── package_bg.wasm
│ ├── todomvc.d.ts
│ ├── todomvc.js
│ ├── todomvc_bg.d.ts
│ └── todomvc_bg.wasm
└── text-polyfill.min.js
├── vue
├── .gitignore
├── index.html
├── js
│ ├── app.js
│ ├── routes.js
│ └── store.js
├── node_modules
│ ├── director
│ │ └── build
│ │ │ └── director.js
│ ├── todomvc-app-css
│ │ └── index.css
│ ├── todomvc-common
│ │ ├── base.css
│ │ └── base.js
│ └── vue
│ │ └── dist
│ │ └── vue.js
├── package.json
└── readme.md
└── yew
├── index.html
├── todomvc.js
└── todomvc.wasm
/.gitignore:
--------------------------------------------------------------------------------
1 | *elm-stuff
2 | *.log
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Matt Esch.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # todomvc benchmark for rust frontend webframeworks relative to react,elm,vue
2 |
3 | Rust webframeworks:
4 | - [sauron](https://github.com/ivanceras/sauron)
5 | - [mogwai](https://github.com/schell/mogwai)
6 | - [seed](https://github.com/seed-rs/seed)
7 | - [yew](https://github.com/yewstack/yew)
8 |
9 | 
10 |
11 | **[Run benchmark](https://ivanceras.github.io/sauron-perf/)**
12 |
13 | ## Setup:
14 | ```
15 | cargo install basic-http-server
16 | git clone https://github.com/ivanceras/sauron-perf
17 | cd sauron-perf
18 | basic-http-server
19 | ```
20 |
21 | Open [http://localhost:4000](http://localhost:4000)
22 |
--------------------------------------------------------------------------------
/img/2019-12-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/img/2019-12-17.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | TodoMVC Benchmark
5 |
6 |
7 |
8 |
24 |
25 |
26 |
31 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/resources/benchmark-runner.js:
--------------------------------------------------------------------------------
1 | // FIXME: Use the real promise if available.
2 | // FIXME: Make sure this interface is compatible with the real Promise.
3 | function SimplePromise() {
4 | this._chainedPromise = null;
5 | this._callback = null;
6 | }
7 |
8 | SimplePromise.prototype.then = function (callback) {
9 | if (this._callback)
10 | throw "SimplePromise doesn't support multiple calls to then";
11 | this._callback = callback;
12 | this._chainedPromise = new SimplePromise;
13 |
14 | if (this._resolved)
15 | this.resolve(this._resolvedValue);
16 |
17 | return this._chainedPromise;
18 | }
19 |
20 | SimplePromise.prototype.resolve = function (value) {
21 | if (!this._callback) {
22 | this._resolved = true;
23 | this._resolvedValue = value;
24 | return;
25 | }
26 |
27 | var result = this._callback(value);
28 | if (result instanceof SimplePromise) {
29 | var chainedPromise = this._chainedPromise;
30 | result.then(function (result) { chainedPromise.resolve(result); });
31 | } else
32 | this._chainedPromise.resolve(result);
33 | }
34 |
35 | function BenchmarkTestStep(testName, testFunction) {
36 | this.name = testName;
37 | this.run = testFunction;
38 | }
39 |
40 | function BenchmarkRunner(suites, client) {
41 | this._suites = suites;
42 | this._prepareReturnValue = null;
43 | this._measuredValues = {};
44 | this._client = client;
45 | }
46 |
47 | BenchmarkRunner.prototype.waitForElement = function (selector) {
48 | var promise = new SimplePromise;
49 | var contentDocument = this._frame.contentDocument;
50 |
51 | function resolveIfReady() {
52 | var element = contentDocument.querySelector(selector);
53 | if (element)
54 | return promise.resolve(element);
55 | setTimeout(resolveIfReady, 50);
56 | }
57 |
58 | resolveIfReady();
59 | return promise;
60 | }
61 |
62 | BenchmarkRunner.prototype._removeFrame = function () {
63 | if (this._frame) {
64 | this._frame.parentNode.removeChild(this._frame);
65 | this._frame = null;
66 | }
67 | }
68 |
69 | BenchmarkRunner.prototype._appendFrame = function (src) {
70 | var frame = document.createElement('iframe');
71 | frame.style.width = '800px';
72 | frame.style.height = '600px'
73 | document.body.appendChild(frame);
74 | this._frame = frame;
75 | return frame;
76 | }
77 |
78 | BenchmarkRunner.prototype._waitAndWarmUp = function () {
79 | var startTime = Date.now();
80 |
81 | function Fibonacci(n) {
82 | if (Date.now() - startTime > 100)
83 | return;
84 | if (n <= 0)
85 | return 0;
86 | else if (n == 1)
87 | return 1;
88 | return Fibonacci(n - 2) + Fibonacci(n - 1);
89 | }
90 |
91 | var promise = new SimplePromise;
92 | setTimeout(function () {
93 | Fibonacci(100);
94 | promise.resolve();
95 | }, 200);
96 | return promise;
97 | }
98 |
99 | // This function ought be as simple as possible. Don't even use SimplePromise.
100 | BenchmarkRunner.prototype._runTest = function(suite, testFunction, prepareReturnValue, callback)
101 | {
102 | var now = window.performance && window.performance.now ? function () { return window.performance.now(); } : Date.now;
103 |
104 | var contentWindow = this._frame.contentWindow;
105 | var contentDocument = this._frame.contentDocument;
106 |
107 | var startTime = now();
108 | testFunction(prepareReturnValue, contentWindow, contentDocument);
109 | var endTime = now();
110 | var syncTime = endTime - startTime;
111 |
112 | var startTime = now();
113 | setTimeout(function () {
114 | setTimeout(function () {
115 | var endTime = now();
116 | callback(syncTime, endTime - startTime);
117 | }, 0)
118 | }, 0);
119 | }
120 |
121 | function BenchmarkState(suites) {
122 | this._suites = suites;
123 | this._suiteIndex = -1;
124 | this._testIndex = 0;
125 | this.next();
126 | }
127 |
128 | BenchmarkState.prototype.currentSuite = function() {
129 | return this._suites[this._suiteIndex];
130 | }
131 |
132 | BenchmarkState.prototype.currentTest = function () {
133 | var suite = this.currentSuite();
134 | return suite ? suite.tests[this._testIndex] : null;
135 | }
136 |
137 | BenchmarkState.prototype.next = function () {
138 | this._testIndex++;
139 |
140 | var suite = this._suites[this._suiteIndex];
141 | if (suite && this._testIndex < suite.tests.length)
142 | return this;
143 |
144 | this._testIndex = 0;
145 | do {
146 | this._suiteIndex++;
147 | } while (this._suiteIndex < this._suites.length && this._suites[this._suiteIndex].disabled);
148 |
149 | return this;
150 | }
151 |
152 | BenchmarkState.prototype.isFirstTest = function () {
153 | return !this._testIndex;
154 | }
155 |
156 | BenchmarkState.prototype.prepareCurrentSuite = function (runner, frame) {
157 | var suite = this.currentSuite();
158 | var promise = new SimplePromise;
159 | frame.onload = function () {
160 | suite.prepare(runner, frame.contentWindow, frame.contentDocument).then(function (result) { promise.resolve(result); });
161 | }
162 | frame.src = suite.url;
163 | return promise;
164 | }
165 |
166 | BenchmarkRunner.prototype.step = function (state) {
167 | if (!state)
168 | state = new BenchmarkState(this._suites);
169 |
170 | var suite = state.currentSuite();
171 | if (!suite) {
172 | this._finalize();
173 | var promise = new SimplePromise;
174 | promise.resolve();
175 | return promise;
176 | }
177 |
178 | if (state.isFirstTest()) {
179 | this._masuredValuesForCurrentSuite = {};
180 | var self = this;
181 | return state.prepareCurrentSuite(this, this._appendFrame()).then(function (prepareReturnValue) {
182 | self._prepareReturnValue = prepareReturnValue;
183 | return self._runTestAndRecordResults(state);
184 | });
185 | }
186 |
187 | return this._runTestAndRecordResults(state);
188 | }
189 |
190 | BenchmarkRunner.prototype._runTestAndRecordResults = function (state) {
191 | var promise = new SimplePromise;
192 | var suite = state.currentSuite();
193 | var test = state.currentTest();
194 |
195 | if (this._client && this._client.willRunTest)
196 | this._client.willRunTest(suite, test);
197 |
198 | var self = this;
199 | setTimeout(function () {
200 | self._runTest(suite, test.run, self._prepareReturnValue, function (syncTime, asyncTime) {
201 | var suiteResults = self._measuredValues[suite.name] || {tests:{}, total: 0};
202 | self._measuredValues[suite.name] = suiteResults;
203 | suiteResults.tests[test.name] = {'Sync': syncTime, 'Async': asyncTime};
204 | suiteResults.total += syncTime + asyncTime;
205 |
206 | if (self._client && self._client.willRunTest)
207 | self._client.didRunTest(suite, test);
208 |
209 | state.next();
210 | if (state.currentSuite() != suite)
211 | self._removeFrame();
212 | promise.resolve(state);
213 | });
214 | }, 0);
215 | return promise;
216 | }
217 |
218 | BenchmarkRunner.prototype._finalize = function () {
219 | this._removeFrame();
220 |
221 | if (this._client && this._client.didRunSuites)
222 | this._client.didRunSuites(this._measuredValues);
223 |
224 | // FIXME: This should be done when we start running tests.
225 | this._measuredValues = {};
226 | }
227 |
--------------------------------------------------------------------------------
/resources/manager.js:
--------------------------------------------------------------------------------
1 |
2 | var runs = [],
3 | res = document.getElementById('results'),
4 | timesRan = 0,
5 | runButton
6 |
7 | function formatTestName(suiteName, testName) {
8 | return suiteName + (testName ? '/' + testName : '');
9 | }
10 |
11 | function createUIForSuites(suites, onstep, onrun) {
12 | var control = document.createElement('nav');
13 | var ol = document.createElement('ol');
14 | var checkboxes = [];
15 |
16 | var button = document.createElement('button');
17 | button.textContent = 'Step Tests';
18 | button.onclick = onstep;
19 | control.appendChild(button);
20 |
21 | var button = runButton = document.createElement('button');
22 | button.textContent = 'Run All';
23 | button.onclick = onrun;
24 | control.appendChild(button);
25 |
26 | for (var suiteIndex = 0; suiteIndex < suites.length; suiteIndex++) {
27 | var suite = suites[suiteIndex];
28 | var li = document.createElement('li');
29 | var checkbox = document.createElement('input');
30 | checkbox.id = suite.name;
31 | checkbox.type = 'checkbox';
32 | checkbox.checked = true;
33 | checkbox.onchange = (function (suite, checkbox) { return function () { suite.disabled = !checkbox.checked; runs = []; } })(suite, checkbox);
34 | checkbox.onchange();
35 | checkboxes.push(checkbox);
36 |
37 | li.appendChild(checkbox);
38 | var label = document.createElement('label');
39 | label.appendChild(document.createTextNode(formatTestName(suite.name) + ' ' + suite.version));
40 | li.appendChild(label);
41 | label.htmlFor = checkbox.id;
42 |
43 | var testList = document.createElement('ol');
44 | for (var testIndex = 0; testIndex < suite.tests.length; testIndex++) {
45 | var testItem = document.createElement('li');
46 | var test = suite.tests[testIndex];
47 | var anchor = document.createElement('a');
48 | anchor.id = suite.name + '-' + test.name;
49 | test.anchor = anchor;
50 | anchor.appendChild(document.createTextNode(formatTestName(suite.name, test.name)));
51 | testItem.appendChild(anchor);
52 | testList.appendChild(testItem);
53 | }
54 | li.appendChild(testList);
55 |
56 | ol.appendChild(li);
57 | }
58 |
59 | control.appendChild(ol);
60 |
61 | return control;
62 | }
63 |
64 | function startTest() {
65 |
66 | var match = window.location.search.match(/[\?&]r=(\d+)/),
67 | timesToRun = match ? +(match[1]) : 1
68 |
69 | var runner = new BenchmarkRunner(Suites, {
70 | willRunTest: function (suite, test) {
71 | if (!navigator.userAgent.match("MSIE 9.0")) test.anchor.classList.add('running');
72 | },
73 | didRunTest: function (suite, test) {
74 | var classList = test.anchor.classList;
75 | if (!navigator.userAgent.match("MSIE 9.0")) classList.remove('running');
76 | if (!navigator.userAgent.match("MSIE 9.0")) classList.add('ran');
77 | },
78 | didRunSuites: function (measuredValues) {
79 | var results = '';
80 | var total = 0; // FIXME: Compute the total properly.
81 | for (var suiteName in measuredValues) {
82 | var suiteResults = measuredValues[suiteName];
83 | for (var testName in suiteResults.tests) {
84 | var testResults = suiteResults.tests[testName];
85 | for (var subtestName in testResults) {
86 | results += suiteName + ' : ' + testName + ' : ' + subtestName
87 | + ': ' + testResults[subtestName] + ' ms\n';
88 | }
89 | }
90 | results += suiteName + ' : ' + suiteResults.total + ' ms\n';
91 | total += suiteResults.total;
92 | }
93 | results += 'Run ' + (runs.length + 1) +'/' + timesToRun + ' - Total : ' + total + ' ms\n';
94 |
95 | if (!results)
96 | return;
97 |
98 | console.log(results)
99 |
100 | runs.push(measuredValues)
101 | timesRan++
102 | if (timesRan >= timesToRun) {
103 | timesRan = 0
104 | reportFastest()
105 | shuffle(Suites);
106 | } else {
107 | setTimeout(function () {
108 | runButton.click()
109 | }, 0)
110 | }
111 | }
112 | });
113 |
114 | var currentState = null;
115 | function callNextStep(state) {
116 | runner.step(state).then(function (newState) {
117 | currentState = newState;
118 | if (newState)
119 | callNextStep(newState);
120 | });
121 | }
122 |
123 | // Don't call step while step is already executing.
124 | document.body.appendChild(createUIForSuites(Suites,
125 | function () { runner.step(currentState).then(function (state) { currentState = state; }); },
126 | function () {
127 | var analysis = document.getElementById("analysis");
128 | analysis.style.display = 'none';
129 | localStorage.clear();
130 | runs = [];
131 | callNextStep(currentState);
132 | }));
133 |
134 | function reportFastest () {
135 | var results = {}
136 | runs.forEach(function (runData) {
137 | for (var key in runData) {
138 | results[key] = Math.min(results[key] || Infinity, runData[key].total)
139 | }
140 | });
141 | drawChart(results);
142 | }
143 | }
144 |
145 | google.load("visualization", "1", {packages:["corechart"]});
146 | function drawChart(results) {
147 | var rawData = [];
148 | for (var key in results) {
149 | var color = colorify(key);
150 | rawData.push([ key, Math.round(results[key]), color ]);
151 | }
152 | rawData.sort(function(a, b){ return a[1] - b[1] })
153 | rawData.unshift([ "Project" , "Time", { role: "style"} ])
154 | var data = google.visualization.arrayToDataTable(rawData);
155 |
156 | var view = new google.visualization.DataView(data);
157 | view.setColumns([0, 1,
158 | { calc: "stringify",
159 | sourceColumn: 1,
160 | type: "string",
161 | role: "annotation" },
162 | 2]);
163 |
164 | var runWord = "run" + (runs.length > 1 ? "s" : "");
165 | var title = "Best time in milliseconds over " + runs.length +
166 | " " + runWord + " (lower is better)";
167 |
168 | var options = {
169 | title: "TodoMVC Benchmark",
170 | width: 600,
171 | height: 500,
172 | legend: { position: "none" },
173 | backgroundColor: 'transparent',
174 | hAxis: {title: title},
175 | min:0,
176 | max:1500
177 | };
178 | var analysis = document.getElementById("analysis");
179 | analysis.style.display = 'block';
180 | var barchart = document.getElementById("barchart_values");
181 | var chart = new google.visualization.BarChart(barchart);
182 | chart.draw(view, options);
183 | }
184 |
185 | function shuffle ( ary ) {
186 | var i = ary.length;
187 | if ( i == 0 ) return false;
188 | while ( --i ) {
189 | var j = Math.floor( Math.random() * ( i + 1 ) );
190 | var tempi = ary[i];
191 | var tempj = ary[j];
192 | ary[i] = tempj;
193 | ary[j] = tempi;
194 | }
195 | }
196 |
197 | function colorify(n){
198 | var c = 'rgb(' + ( Math.max(0,(n.toLowerCase().charCodeAt(3 % n.length) - 97) / 26 * 255 | 0) ) +
199 | ", " + ( Math.max(0,(n.toLowerCase().charCodeAt(4 % n.length) - 97) / 26 * 255 | 0) ) +
200 | ", " + ( Math.max(0,(n.toLowerCase().charCodeAt(5 % n.length) - 97) / 26 * 255 | 0) ) + ")"
201 | return c
202 | }
203 |
204 | window.addEventListener('load', startTest);
205 |
--------------------------------------------------------------------------------
/todomvc/elm17/Todo.elm:
--------------------------------------------------------------------------------
1 | port module Todo exposing (..)
2 | {-| TodoMVC implemented in Elm, using plain HTML and CSS for rendering.
3 |
4 | This application is broken up into four distinct parts:
5 |
6 | 1. Model - a full definition of the application's state
7 | 2. Update - a way to step the application state forward
8 | 3. View - a way to visualize our application state with HTML
9 | 4. Inputs - the signals necessary to manage events
10 |
11 | This clean division of concerns is a core part of Elm. You can read more about
12 | this in the Pong tutorial: http://elm-lang.org/blog/making-pong
13 |
14 | This program is not particularly large, so definitely see the following
15 | for notes on structuring more complex GUIs with Elm:
16 | https://github.com/evancz/elm-architecture-tutorial/
17 | -}
18 |
19 | import Html exposing (..)
20 | import Html.Attributes exposing (..)
21 | import Html.Events exposing (..)
22 | import Html.App
23 | import Html.Lazy exposing (lazy, lazy2)
24 | import Json.Decode as Json
25 | import String
26 |
27 |
28 | ---- MODEL ----
29 |
30 | -- The full application state of our todo app.
31 | type alias Model =
32 | { tasks : List Task
33 | , field : String
34 | , uid : Int
35 | , visibility : String
36 | }
37 |
38 |
39 | type alias Task =
40 | { description : String
41 | , completed : Bool
42 | , editing : Bool
43 | , id : Int
44 | }
45 |
46 |
47 | newTask : String -> Int -> Task
48 | newTask desc id =
49 | { description = desc
50 | , completed = False
51 | , editing = False
52 | , id = id
53 | }
54 |
55 |
56 | emptyModel : Model
57 | emptyModel =
58 | { tasks = []
59 | , visibility = "All"
60 | , field = ""
61 | , uid = 0
62 | }
63 |
64 |
65 | ---- UPDATE ----
66 |
67 | -- A description of the kinds of actions that can be performed on the model of
68 | -- our application. See the following for more info on this pattern and
69 | -- some alternatives: https://github.com/evancz/elm-architecture-tutorial/
70 | type Action
71 | = NoOp
72 | | UpdateField String
73 | | EditingTask Int Bool
74 | | UpdateTask Int String
75 | | Add
76 | | Delete Int
77 | | DeleteComplete
78 | | Check Int Bool
79 | | CheckAll Bool
80 | | ChangeVisibility String
81 |
82 |
83 | -- How we update our Model on a given Action?
84 | update : Action -> Model -> Model
85 | update action model =
86 | case action of
87 | NoOp -> model
88 |
89 | Add ->
90 | { model |
91 | uid = model.uid + 1,
92 | field = "",
93 | tasks =
94 | if String.isEmpty model.field
95 | then model.tasks
96 | else model.tasks ++ [newTask model.field model.uid]
97 | }
98 |
99 | UpdateField str ->
100 | { model | field = str }
101 |
102 | EditingTask id isEditing ->
103 | let updateTask t = if t.id == id then { t | editing = isEditing } else t
104 | in
105 | { model | tasks = List.map updateTask model.tasks }
106 |
107 | UpdateTask id task ->
108 | let updateTask t = if t.id == id then { t | description = task } else t
109 | in
110 | { model | tasks = List.map updateTask model.tasks }
111 |
112 | Delete id ->
113 | { model | tasks = List.filter (\t -> t.id /= id) model.tasks }
114 |
115 | DeleteComplete ->
116 | { model | tasks = List.filter (not << .completed) model.tasks }
117 |
118 | Check id isCompleted ->
119 | let updateTask t = if t.id == id then { t | completed = isCompleted } else t
120 | in
121 | { model | tasks = List.map updateTask model.tasks }
122 |
123 | CheckAll isCompleted ->
124 | let updateTask t = { t | completed = isCompleted }
125 | in
126 | { model | tasks = List.map updateTask model.tasks }
127 |
128 | ChangeVisibility visibility ->
129 | { model | visibility = visibility }
130 |
131 |
132 | ---- VIEW ----
133 |
134 | view : Model -> Html Action
135 | view model =
136 | div
137 | [ class "todomvc-wrapper"
138 | , style [ ("visibility", "hidden") ]
139 | ]
140 | [ section
141 | [ id "todoapp" ]
142 | [ taskEntry model.field
143 | , taskList model.visibility model.tasks
144 | , controls model.visibility model.tasks
145 | ]
146 | , infoFooter
147 | ]
148 |
149 |
150 | onEnter : Action -> Attribute Action
151 | onEnter tagger =
152 | on "keydown" (Json.map (always tagger) (Json.customDecoder keyCode is13))
153 |
154 |
155 | is13 : Int -> Result String ()
156 | is13 code =
157 | if code == 13 then Ok () else Err "not the right key code"
158 |
159 |
160 | taskEntry : String -> Html Action
161 | taskEntry task =
162 | header
163 | [ id "header" ]
164 | [ h1 [] [ text "todos" ]
165 | , input
166 | [ id "new-todo"
167 | , placeholder "What needs to be done?"
168 | , autofocus True
169 | , value task
170 | , name "newTodo"
171 | , onInput UpdateField
172 | , onEnter Add
173 | ]
174 | []
175 | ]
176 |
177 |
178 | taskList : String -> List Task -> Html Action
179 | taskList visibility tasks =
180 | let isVisible todo =
181 | case visibility of
182 | "Completed" -> todo.completed
183 | "Active" -> not todo.completed
184 | _ -> True
185 |
186 | allCompleted = List.all .completed tasks
187 |
188 | cssVisibility = if List.isEmpty tasks then "hidden" else "visible"
189 | in
190 | section
191 | [ id "main"
192 | , style [ ("visibility", cssVisibility) ]
193 | ]
194 | [ input
195 | [ id "toggle-all"
196 | , type' "checkbox"
197 | , name "toggle"
198 | , checked allCompleted
199 | , onClick (CheckAll (not allCompleted))
200 | ]
201 | []
202 | , label
203 | [ for "toggle-all" ]
204 | [ text "Mark all as complete" ]
205 | , ul
206 | [ id "todo-list" ]
207 | (List.map todoItem (List.filter isVisible tasks))
208 | ]
209 |
210 |
211 | todoItem : Task -> Html Action
212 | todoItem todo =
213 | li
214 | [ classList [ ("completed", todo.completed), ("editing", todo.editing) ] ]
215 | [ div
216 | [ class "view" ]
217 | [ input
218 | [ class "toggle"
219 | , type' "checkbox"
220 | , checked todo.completed
221 | , onClick (Check todo.id (not todo.completed))
222 | ]
223 | []
224 | , label
225 | [ onDoubleClick (EditingTask todo.id True) ]
226 | [ text todo.description ]
227 | , button
228 | [ class "destroy"
229 | , onClick (Delete todo.id)
230 | ]
231 | []
232 | ]
233 | , input
234 | [ class "edit"
235 | , value todo.description
236 | , name "title"
237 | , id ("todo-" ++ toString todo.id)
238 | , onInput (UpdateTask todo.id)
239 | , onBlur (EditingTask todo.id False)
240 | , onEnter (EditingTask todo.id False)
241 | ]
242 | []
243 | ]
244 |
245 |
246 | controls : String -> List Task -> Html Action
247 | controls visibility tasks =
248 | let tasksCompleted = List.length (List.filter .completed tasks)
249 | tasksLeft = List.length tasks - tasksCompleted
250 | item_ = if tasksLeft == 1 then " item" else " items"
251 | in
252 | footer
253 | [ id "footer"
254 | , hidden (List.isEmpty tasks)
255 | ]
256 | [ span
257 | [ id "todo-count" ]
258 | [ strong [] [ text (toString tasksLeft) ]
259 | , text (item_ ++ " left")
260 | ]
261 | , ul
262 | [ id "filters" ]
263 | [ visibilitySwap "#/" "All" visibility
264 | , text " "
265 | , visibilitySwap "#/active" "Active" visibility
266 | , text " "
267 | , visibilitySwap "#/completed" "Completed" visibility
268 | ]
269 | , button
270 | [ class "clear-completed"
271 | , id "clear-completed"
272 | , hidden (tasksCompleted == 0)
273 | , onClick DeleteComplete
274 | ]
275 | [ text ("Clear completed (" ++ toString tasksCompleted ++ ")") ]
276 | ]
277 |
278 |
279 | visibilitySwap : String -> String -> String -> Html Action
280 | visibilitySwap uri visibility actualVisibility =
281 | li
282 | [ onClick (ChangeVisibility visibility) ]
283 | [ a [ href uri, classList [("selected", visibility == actualVisibility)] ] [ text visibility ] ]
284 |
285 |
286 | infoFooter : Html Action
287 | infoFooter =
288 | footer [ id "info" ]
289 | [ p [] [ text "Double-click to edit a todo" ]
290 | , p []
291 | [ text "Written by "
292 | , a [ href "https://github.com/evancz" ] [ text "Evan Czaplicki" ]
293 | ]
294 | , p []
295 | [ text "Part of "
296 | , a [ href "http://todomvc.com" ] [ text "TodoMVC" ]
297 | ]
298 | ]
299 |
300 |
301 | ---- INPUTS ----
302 |
303 | -- wire the entire application together
304 | main =
305 | Html.App.beginnerProgram
306 | { model = emptyModel
307 | , update = update
308 | , view = view
309 | }
310 |
--------------------------------------------------------------------------------
/todomvc/elm17/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/elm17/bg.png
--------------------------------------------------------------------------------
/todomvc/elm17/elm-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0.0",
3 | "summary": "TodoMVC created with Elm and elm-html",
4 | "repository": "https://github.com/evancz/elm-todomvc.git",
5 | "license": "BSD3",
6 | "source-directories": [
7 | "."
8 | ],
9 | "exposed-modules": [],
10 | "dependencies": {
11 | "elm-lang/core": "4.0.0 <= v < 5.0.0",
12 | "elm-lang/html": "1.0.0 <= v < 2.0.0"
13 | },
14 | "elm-version": "0.17.0 <= v < 0.18.0"
15 | }
16 |
--------------------------------------------------------------------------------
/todomvc/elm17/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Elm • TodoMVC
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/todomvc/mithril/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Jean-Philippe Monette
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/todomvc/mithril/README.md:
--------------------------------------------------------------------------------
1 | # Mithril TodoMVC Example
2 |
3 | > Mithril is a client-side Javascript MVC framework, i.e. it's a tool to make application code divided into a data layer (called "Model"), a UI layer (called View), and a glue layer (called Controller)
4 |
5 | > _[Mithril](http://lhorie.github.io/mithril/)_
6 |
7 |
8 | ## Learning Mithril
9 |
10 | The [Mithril website](http://lhorie.github.io/mithril/) is a great resource for getting started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Getting Started](http://lhorie.github.io/mithril/getting-started.html)
15 | * [API Reference](http://lhorie.github.io/mithril/mithril.html)
16 | * [Mithril on Github](https://github.com/lhorie/mithril.js)
17 |
18 | _If you have other helpful links to share, or find any of the links above no longer work, please [let me know](https://github.com/jpmonette/todomvc-mithril/issues)._
19 |
20 | ## Running
21 |
22 | 1. Clone the repo
23 | 2. Execute `bower install` in the repo (make sure yo install `npm`)
24 | 3. Open `index.html`!
25 |
26 | ## TODO
27 |
28 | * Proper routing support (fixed, waiting for latest Mithril version (v0.1.1))
29 | * Select all
30 | * Fix items left behaviour
31 |
32 | ## Credit
33 |
34 | This TodoMVC application was created by [Jean-Philippe Monette](http://blogue.jpmonette.net/)
35 |
36 | ## License
37 |
38 | Copyright (C) 2013, Jean-Philippe Monette
39 |
40 | 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:
41 |
42 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
43 |
44 | 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.
45 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-mithril",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "mithril": "git://github.com/lhorie/mithril.js.git",
6 | "todomvc-common": "~0.1.4"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mithril",
3 | "homepage": "https://github.com/lhorie/mithril.js",
4 | "version": "0.1.19",
5 | "_release": "0.1.19",
6 | "_resolution": {
7 | "type": "version",
8 | "tag": "v0.1.19",
9 | "commit": "c8e0d917f7962a6a2e1b78ce191f74cf1478a4d3"
10 | },
11 | "_source": "git://github.com/lhorie/mithril.js.git",
12 | "_target": "*",
13 | "_originalSource": "git://github.com/lhorie/mithril.js.git"
14 | }
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.10"
4 |
5 | script:
6 | - grunt test
7 | - grunt teste2e
8 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | var version = "0.1.19"
4 |
5 | var inputFolder = "./docs"
6 | var tempFolder = "./temp"
7 | var archiveFolder = "./archive"
8 | var outputFolder = "../mithril"
9 |
10 | var guideLayout = "guide"
11 | var guide = [
12 | "auto-redrawing",
13 | "benchmarks",
14 | "community",
15 | "compiling-templates",
16 | "comparison",
17 | "components",
18 | "getting-started",
19 | "installation",
20 | "integration",
21 | "practices",
22 | "refactoring",
23 | "routing",
24 | "tools",
25 | "web-services",
26 | ]
27 | var apiLayout = "api"
28 | var api = [
29 | "change-log",
30 | "roadmap",
31 | "how-to-read-signatures",
32 | "mithril",
33 | "mithril.computation",
34 | "mithril.deferred",
35 | "mithril.module",
36 | "mithril.prop",
37 | "mithril.redraw",
38 | "mithril.render",
39 | "mithril.request",
40 | "mithril.route",
41 | "mithril.sync",
42 | "mithril.trust",
43 | "mithril.withAttr",
44 | "mithril.xhr"
45 | ]
46 |
47 |
48 |
49 | var md2htmlTasks = {}
50 | var makeTasks = function(layout, pages) {
51 | pages.map(function(name) {
52 | md2htmlTasks[name] = {
53 | options: {layout: inputFolder + "/layout/" + layout + ".html"},
54 | files: [{src: [inputFolder + "/" + name + ".md"], dest: tempFolder + "/" + name + ".html"}]
55 | }
56 | })
57 | }
58 | makeTasks("guide", guide)
59 | makeTasks("api", api)
60 |
61 | var currentVersionArchiveFolder = archiveFolder + "/v" + version
62 | grunt.initConfig({
63 | md2html: md2htmlTasks,
64 | uglify: {
65 | options: {banner: "/*\nMithril v" + version + "\nhttp://github.com/lhorie/mithril.js\n(c) Leo Horie\nLicense: MIT\n*/", sourceMap: true},
66 | mithril: {src: "mithril.js", dest: currentVersionArchiveFolder + "/mithril.min.js"}
67 | },
68 | concat: {
69 | test: {src: ["mithril.js", "./tests/test.js", "./tests/mock.js", "./tests/mithril-tests.js"], dest: currentVersionArchiveFolder + "/mithril-tests.js"}
70 | },
71 | zip: {
72 | distribution: {
73 | cwd: currentVersionArchiveFolder + "/",
74 | src: [currentVersionArchiveFolder + "/mithril.min.js", currentVersionArchiveFolder + "/mithril.min.map", currentVersionArchiveFolder + "/mithril.js"],
75 | dest: currentVersionArchiveFolder + "/mithril.min.zip"
76 | }
77 | },
78 | replace: {
79 | options: {force: true, patterns: [{match: /\.md/g, replacement: ".html"}, {match: /\$version/g, replacement: version}]},
80 | links: {expand: true, flatten: true, src: [tempFolder + "/**/*.html"], dest: currentVersionArchiveFolder + "/"},
81 | index: {src: inputFolder + "/layout/index.html", dest: currentVersionArchiveFolder + "/index.html"},
82 | commonjs: {expand: true, flatten: true, src: [inputFolder + "/layout/*.json"], dest: currentVersionArchiveFolder},
83 | cdnjs: {src: "deploy/cdnjs-package.json", dest: "../cdnjs/ajax/libs/mithril/package.json"}
84 | },
85 | copy: {
86 | style: {src: inputFolder + "/layout/style.css", dest: currentVersionArchiveFolder + "/style.css"},
87 | pages: {src: inputFolder + "/layout/pages.json", dest: currentVersionArchiveFolder + "/pages.json"},
88 | lib: {expand: true, cwd: inputFolder + "/layout/lib/", src: "./**", dest: currentVersionArchiveFolder + "/lib/"},
89 | tools: {expand: true, cwd: inputFolder + "/layout/tools/", src: "./**", dest: currentVersionArchiveFolder + "/tools/"},
90 | comparisons: {expand: true, cwd: inputFolder + "/layout/comparisons/", src: "./**", dest: currentVersionArchiveFolder + "/comparisons/"},
91 | unminified: {src: "mithril.js", dest: currentVersionArchiveFolder + "/mithril.js"},
92 | typescript: {src: "mithril.d.ts", dest: currentVersionArchiveFolder + "/mithril.d.ts"},
93 | publish: {expand: true, cwd: currentVersionArchiveFolder, src: "./**", dest: outputFolder},
94 | archive: {expand: true, cwd: currentVersionArchiveFolder, src: "./**", dest: outputFolder + "/archive/v" + version},
95 | cdnjs1: {src: currentVersionArchiveFolder + "/mithril.js", dest: "../cdnjs/ajax/libs/mithril/" + version + "/mithril.js"},
96 | cdnjs2: {src: currentVersionArchiveFolder + "/mithril.min.js", dest: "../cdnjs/ajax/libs/mithril/" + version + "/mithril.min.js"},
97 | cdnjs3: {src: currentVersionArchiveFolder + "/mithril.min.map", dest: "../cdnjs/ajax/libs/mithril/" + version + "/mithril.min.map"},
98 | jsdelivr1: {src: currentVersionArchiveFolder + "/mithril.js", dest: "../jsdelivr/files/mithril/" + version + "/mithril.js"},
99 | jsdelivr2: {src: currentVersionArchiveFolder + "/mithril.min.js", dest: "../jsdelivr/files/mithril/" + version + "/mithril.min.js"},
100 | jsdelivr3: {src: currentVersionArchiveFolder + "/mithril.min.map", dest: "../jsdelivr/files/mithril/" + version + "/mithril.min.map"}
101 | },
102 | execute: {
103 | tests: {src: [currentVersionArchiveFolder + "/mithril-tests.js"]}
104 | },
105 | qunit: {
106 | all: ['tests/e2e/**/*.html']
107 | },
108 | connect: {
109 | server: {
110 | options: {
111 | port: 8000,
112 | base: '.'
113 | }
114 | }
115 | },
116 | clean: {
117 | options: {force: true},
118 | generated: [tempFolder]
119 | }
120 | });
121 |
122 | grunt.loadNpmTasks("grunt-contrib-clean");
123 | grunt.loadNpmTasks('grunt-contrib-concat');
124 | grunt.loadNpmTasks("grunt-contrib-copy");
125 | grunt.loadNpmTasks("grunt-contrib-uglify");
126 | grunt.loadNpmTasks('grunt-execute');
127 | grunt.loadNpmTasks("grunt-md2html");
128 | grunt.loadNpmTasks("grunt-replace");
129 | grunt.loadNpmTasks('grunt-zip');
130 | grunt.loadNpmTasks('grunt-contrib-qunit');
131 | grunt.loadNpmTasks('grunt-contrib-connect');
132 |
133 | grunt.registerTask("build", ["test", "uglify", "zip", "md2html", "replace", "copy", "clean"]);
134 | grunt.registerTask("test", ["concat", "execute"]);
135 | grunt.registerTask('teste2e', ['connect', 'qunit']);
136 | grunt.registerTask("default", ["build"]);
137 |
138 | };
139 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Leo Horie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/lhorie/mithril.js)
2 |
3 | # Mithril
4 |
5 | A Javascript Framework for Building Brilliant Applications
6 |
7 | See the [website](http://lhorie.github.io/mithril) for documentation
8 |
9 | There's also a [blog](http://lhorie.github.io/mithril-blog) and a [mailing list](https://groups.google.com/forum/#!forum/mithriljs)
10 |
11 | ---
12 |
13 | ## What is Mithril?
14 |
15 | Mithril is a client-side MVC framework - a tool to organize code in a way that is easy to think about and to maintain.
16 |
17 | ### Light-weight
18 |
19 | - Only 4kb gzipped, no dependencies
20 | - Small API, small learning curve
21 |
22 | ### Robust
23 |
24 | - Safe-by-default templates
25 | - Hierarchical MVC via components
26 |
27 | ### Fast
28 |
29 | - Virtual DOM diffing and compilable templates
30 | - Intelligent auto-redrawing system
31 |
32 | ---
33 |
34 | ## Sample code
35 |
36 | ```javascript
37 | //namespace
38 | var app = {};
39 |
40 | //model
41 | app.PageList = function() {
42 | return m.request({method: "GET", url: "pages.json"});
43 | };
44 |
45 | //controller
46 | app.controller = function() {
47 | this.pages = app.PageList();
48 |
49 | this.rotate = function() {
50 | this.pages().push(this.pages().shift())
51 | }.bind(this)
52 | };
53 |
54 | //view
55 | app.view = function(ctrl) {
56 | return [
57 | ctrl.pages().map(function(page) {
58 | return m("a", {href: page.url}, page.title);
59 | }),
60 | m("a", {onclick: ctrl.rotate}, "Rotate links")
61 | ];
62 | };
63 |
64 | //initialize
65 | m.module(document.getElementById("example"), app);
66 | ```
67 |
68 | ---
69 |
70 | ### Learn more
71 |
72 | - [Tutorial](http://lhorie.github.io/mithril/getting-started.html)
73 | - [Differences from Other MVC Frameworks](http://lhorie.github.io/mithril/comparison.html)
74 | - [Benchmarks](http://lhorie.github.io/mithril/benchmarks.html)
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/background.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/deploy/cdnjs-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mithril",
3 | "npmName": "mithril",
4 | "version": "$version",
5 | "filename": "mithril.min.js",
6 | "description": "A Javascript Framework for building brilliant applications",
7 | "homepage": "http://lhorie.github.io/mithril",
8 | "license": "MIT",
9 | "main": "mithril",
10 | "keywords": [
11 | "mvc",
12 | "browser"
13 | ],
14 | "author": "Leo Horie (http://lhorie.blogspot.com/)",
15 | "contributors": [
16 | "Leo Horie (http://lhorie.blogspot.com/)"
17 | ],
18 | "bugs": "https://github.com/lhorie/mithril.js/issues",
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/lhorie/mithril.js.git"
22 | },
23 | "npmFileMap": [
24 | {
25 | "basePath": "/",
26 | "files": [
27 | "mithril.js",
28 | "mithril.min.js",
29 | "mithril.min.map"
30 | ]
31 | }
32 | ]
33 | }
34 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/mithril.d.ts:
--------------------------------------------------------------------------------
1 | //Mithril type definitions for Typescript
2 |
3 | interface MithrilStatic {
4 | (selector: string, attributes: Object, children?: any): MithrilVirtualElement;
5 | (selector: string, children?: any): MithrilVirtualElement;
6 | prop(value?: any): (value?: any) => any;
7 | withAttr(property: string, callback: (value: any) => void): (e: Event) => any;
8 | module(rootElement: Element, module: MithrilModule): void;
9 | trust(html: string): String;
10 | render(rootElement: Element, children?: any): void;
11 | render(rootElement: HTMLDocument, children?: any): void;
12 | redraw(): void;
13 | route(rootElement: Element, defaultRoute: string, routes: { [key: string]: MithrilModule }): void;
14 | route(rootElement: HTMLDocument, defaultRoute: string, routes: { [key: string]: MithrilModule }): void;
15 | route(path: string, params?: any, shouldReplaceHistory?: boolean): void;
16 | route(): string;
17 | route(element: Element, isInitialized: boolean): void;
18 | request(options: MithrilXHROptions): MithrilPromise;
19 | deferred(): MithrilDeferred;
20 | sync(promises: MithrilPromise[]): MithrilPromise;
21 | startComputation(): void;
22 | endComputation(): void;
23 | }
24 |
25 | interface MithrilVirtualElement {
26 | tag: string;
27 | attrs: Object;
28 | children: any;
29 | }
30 |
31 | interface MithrilModule {
32 | controller: Function;
33 | view: Function;
34 | }
35 |
36 | interface MithrilDeferred {
37 | resolve(value?: any): void;
38 | reject(value?: any): void;
39 | promise: MithrilPromise;
40 | }
41 |
42 | interface MithrilPromise {
43 | (value?: any): any;
44 | then(successCallback?: (value: any) => any, errorCallback?: (value: any) => any): MithrilPromise;
45 | }
46 |
47 | interface MithrilXHROptions {
48 | method: string;
49 | url: string;
50 | user?: string;
51 | password?: string;
52 | data?: any;
53 | background?: boolean;
54 | unwrapSuccess?(data: any): any;
55 | unwrapError?(data: any): any;
56 | serialize?(dataToSerialize: any): string;
57 | deserialize?(dataToDeserialize: string): any;
58 | extract?(xhr: XMLHttpRequest, options: MithrilXHROptions);
59 | type?(data: Object): void;
60 | config?(xhr: XMLHttpRequest, options: MithrilXHROptions)
61 | }
62 |
63 | declare var Mithril: MithrilStatic;
64 | declare var m: MithrilStatic;
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/mithril/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mithril",
3 | "version": "0.1.0",
4 | "scripts": {
5 | "test": "grunt test"
6 | },
7 | "devDependencies": {
8 | "grunt-cli": "*",
9 | "grunt-contrib-copy": "*",
10 | "grunt-contrib-uglify": "*",
11 | "grunt-contrib-clean": "*",
12 | "grunt-contrib-concat": "*",
13 | "grunt-contrib-watch": "*",
14 | "grunt-execute": "*",
15 | "grunt-md2html": "*",
16 | "grunt-replace": "*",
17 | "grunt-contrib-qunit": "*",
18 | "grunt-contrib-connect": "*",
19 | "grunt-zip": "*"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/todomvc-common/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-common",
3 | "version": "0.1.9",
4 | "homepage": "https://github.com/tastejs/todomvc-common",
5 | "_release": "0.1.9",
6 | "_resolution": {
7 | "type": "version",
8 | "tag": "v0.1.9",
9 | "commit": "7dd61b0ebf56c020e719a69444442cc7ae7242ff"
10 | },
11 | "_source": "git://github.com/tastejs/todomvc-common.git",
12 | "_target": "~0.1.4",
13 | "_originalSource": "todomvc-common"
14 | }
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/todomvc-common/base.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | color: inherit;
16 | -webkit-appearance: none;
17 | -ms-appearance: none;
18 | -o-appearance: none;
19 | appearance: none;
20 | }
21 |
22 | body {
23 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
24 | line-height: 1.4em;
25 | background: #eaeaea url('bg.png');
26 | color: #4d4d4d;
27 | width: 550px;
28 | margin: 0 auto;
29 | -webkit-font-smoothing: antialiased;
30 | -moz-font-smoothing: antialiased;
31 | -ms-font-smoothing: antialiased;
32 | -o-font-smoothing: antialiased;
33 | font-smoothing: antialiased;
34 | }
35 |
36 | button,
37 | input[type="checkbox"] {
38 | outline: none;
39 | }
40 |
41 | #todoapp {
42 | background: #fff;
43 | background: rgba(255, 255, 255, 0.9);
44 | margin: 130px 0 40px 0;
45 | border: 1px solid #ccc;
46 | position: relative;
47 | border-top-left-radius: 2px;
48 | border-top-right-radius: 2px;
49 | box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
50 | 0 25px 50px 0 rgba(0, 0, 0, 0.15);
51 | }
52 |
53 | #todoapp:before {
54 | content: '';
55 | border-left: 1px solid #f5d6d6;
56 | border-right: 1px solid #f5d6d6;
57 | width: 2px;
58 | position: absolute;
59 | top: 0;
60 | left: 40px;
61 | height: 100%;
62 | }
63 |
64 | #todoapp input::-webkit-input-placeholder {
65 | font-style: italic;
66 | }
67 |
68 | #todoapp input::-moz-placeholder {
69 | font-style: italic;
70 | color: #a9a9a9;
71 | }
72 |
73 | #todoapp h1 {
74 | position: absolute;
75 | top: -120px;
76 | width: 100%;
77 | font-size: 70px;
78 | font-weight: bold;
79 | text-align: center;
80 | color: #b3b3b3;
81 | color: rgba(255, 255, 255, 0.3);
82 | text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
83 | -webkit-text-rendering: optimizeLegibility;
84 | -moz-text-rendering: optimizeLegibility;
85 | -ms-text-rendering: optimizeLegibility;
86 | -o-text-rendering: optimizeLegibility;
87 | text-rendering: optimizeLegibility;
88 | }
89 |
90 | #header {
91 | padding-top: 15px;
92 | border-radius: inherit;
93 | }
94 |
95 | #header:before {
96 | content: '';
97 | position: absolute;
98 | top: 0;
99 | right: 0;
100 | left: 0;
101 | height: 15px;
102 | z-index: 2;
103 | border-bottom: 1px solid #6c615c;
104 | background: #8d7d77;
105 | background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
106 | background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
107 | background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
108 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
109 | border-top-left-radius: 1px;
110 | border-top-right-radius: 1px;
111 | }
112 |
113 | #new-todo,
114 | .edit {
115 | position: relative;
116 | margin: 0;
117 | width: 100%;
118 | font-size: 24px;
119 | font-family: inherit;
120 | line-height: 1.4em;
121 | border: 0;
122 | outline: none;
123 | color: inherit;
124 | padding: 6px;
125 | border: 1px solid #999;
126 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
127 | -moz-box-sizing: border-box;
128 | -ms-box-sizing: border-box;
129 | -o-box-sizing: border-box;
130 | box-sizing: border-box;
131 | -webkit-font-smoothing: antialiased;
132 | -moz-font-smoothing: antialiased;
133 | -ms-font-smoothing: antialiased;
134 | -o-font-smoothing: antialiased;
135 | font-smoothing: antialiased;
136 | }
137 |
138 | #new-todo {
139 | padding: 16px 16px 16px 60px;
140 | border: none;
141 | background: rgba(0, 0, 0, 0.02);
142 | z-index: 2;
143 | box-shadow: none;
144 | }
145 |
146 | #main {
147 | position: relative;
148 | z-index: 2;
149 | border-top: 1px dotted #adadad;
150 | }
151 |
152 | label[for='toggle-all'] {
153 | display: none;
154 | }
155 |
156 | #toggle-all {
157 | position: absolute;
158 | top: -42px;
159 | left: -4px;
160 | width: 40px;
161 | text-align: center;
162 | /* Mobile Safari */
163 | border: none;
164 | }
165 |
166 | #toggle-all:before {
167 | content: '»';
168 | font-size: 28px;
169 | color: #d9d9d9;
170 | padding: 0 25px 7px;
171 | }
172 |
173 | #toggle-all:checked:before {
174 | color: #737373;
175 | }
176 |
177 | #todo-list {
178 | margin: 0;
179 | padding: 0;
180 | list-style: none;
181 | }
182 |
183 | #todo-list li {
184 | position: relative;
185 | font-size: 24px;
186 | border-bottom: 1px dotted #ccc;
187 | }
188 |
189 | #todo-list li:last-child {
190 | border-bottom: none;
191 | }
192 |
193 | #todo-list li.editing {
194 | border-bottom: none;
195 | padding: 0;
196 | }
197 |
198 | #todo-list li.editing .edit {
199 | display: block;
200 | width: 506px;
201 | padding: 13px 17px 12px 17px;
202 | margin: 0 0 0 43px;
203 | }
204 |
205 | #todo-list li.editing .view {
206 | display: none;
207 | }
208 |
209 | #todo-list li .toggle {
210 | text-align: center;
211 | width: 40px;
212 | /* auto, since non-WebKit browsers doesn't support input styling */
213 | height: auto;
214 | position: absolute;
215 | top: 0;
216 | bottom: 0;
217 | margin: auto 0;
218 | /* Mobile Safari */
219 | border: none;
220 | -webkit-appearance: none;
221 | -ms-appearance: none;
222 | -o-appearance: none;
223 | appearance: none;
224 | }
225 |
226 | #todo-list li .toggle:after {
227 | content: '✔';
228 | /* 40 + a couple of pixels visual adjustment */
229 | line-height: 43px;
230 | font-size: 20px;
231 | color: #d9d9d9;
232 | text-shadow: 0 -1px 0 #bfbfbf;
233 | }
234 |
235 | #todo-list li .toggle:checked:after {
236 | color: #85ada7;
237 | text-shadow: 0 1px 0 #669991;
238 | bottom: 1px;
239 | position: relative;
240 | }
241 |
242 | #todo-list li label {
243 | white-space: pre;
244 | word-break: break-word;
245 | padding: 15px 60px 15px 15px;
246 | margin-left: 45px;
247 | display: block;
248 | line-height: 1.2;
249 | -webkit-transition: color 0.4s;
250 | transition: color 0.4s;
251 | }
252 |
253 | #todo-list li.completed label {
254 | color: #a9a9a9;
255 | text-decoration: line-through;
256 | }
257 |
258 | #todo-list li .destroy {
259 | display: none;
260 | position: absolute;
261 | top: 0;
262 | right: 10px;
263 | bottom: 0;
264 | width: 40px;
265 | height: 40px;
266 | margin: auto 0;
267 | font-size: 22px;
268 | color: #a88a8a;
269 | -webkit-transition: all 0.2s;
270 | transition: all 0.2s;
271 | }
272 |
273 | #todo-list li .destroy:hover {
274 | text-shadow: 0 0 1px #000,
275 | 0 0 10px rgba(199, 107, 107, 0.8);
276 | -webkit-transform: scale(1.3);
277 | -ms-transform: scale(1.3);
278 | transform: scale(1.3);
279 | }
280 |
281 | #todo-list li .destroy:after {
282 | content: '✖';
283 | }
284 |
285 | #todo-list li:hover .destroy {
286 | display: block;
287 | }
288 |
289 | #todo-list li .edit {
290 | display: none;
291 | }
292 |
293 | #todo-list li.editing:last-child {
294 | margin-bottom: -1px;
295 | }
296 |
297 | #footer {
298 | color: #777;
299 | padding: 0 15px;
300 | position: absolute;
301 | right: 0;
302 | bottom: -31px;
303 | left: 0;
304 | height: 20px;
305 | z-index: 1;
306 | text-align: center;
307 | }
308 |
309 | #footer:before {
310 | content: '';
311 | position: absolute;
312 | right: 0;
313 | bottom: 31px;
314 | left: 0;
315 | height: 50px;
316 | z-index: -1;
317 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
318 | 0 6px 0 -3px rgba(255, 255, 255, 0.8),
319 | 0 7px 1px -3px rgba(0, 0, 0, 0.3),
320 | 0 43px 0 -6px rgba(255, 255, 255, 0.8),
321 | 0 44px 2px -6px rgba(0, 0, 0, 0.2);
322 | }
323 |
324 | #todo-count {
325 | float: left;
326 | text-align: left;
327 | }
328 |
329 | #filters {
330 | margin: 0;
331 | padding: 0;
332 | list-style: none;
333 | position: absolute;
334 | right: 0;
335 | left: 0;
336 | }
337 |
338 | #filters li {
339 | display: inline;
340 | }
341 |
342 | #filters li a {
343 | color: #83756f;
344 | margin: 2px;
345 | text-decoration: none;
346 | }
347 |
348 | #filters li a.selected {
349 | font-weight: bold;
350 | }
351 |
352 | #clear-completed {
353 | float: right;
354 | position: relative;
355 | line-height: 20px;
356 | text-decoration: none;
357 | background: rgba(0, 0, 0, 0.1);
358 | font-size: 11px;
359 | padding: 0 10px;
360 | border-radius: 3px;
361 | box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
362 | }
363 |
364 | #clear-completed:hover {
365 | background: rgba(0, 0, 0, 0.15);
366 | box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
367 | }
368 |
369 | #info {
370 | margin: 65px auto 0;
371 | color: #a6a6a6;
372 | font-size: 12px;
373 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
374 | text-align: center;
375 | }
376 |
377 | #info a {
378 | color: inherit;
379 | }
380 |
381 | /*
382 | Hack to remove background from Mobile Safari.
383 | Can't use it globally since it destroys checkboxes in Firefox and Opera
384 | */
385 |
386 | @media screen and (-webkit-min-device-pixel-ratio:0) {
387 | #toggle-all,
388 | #todo-list li .toggle {
389 | background: none;
390 | }
391 |
392 | #todo-list li .toggle {
393 | height: 40px;
394 | }
395 |
396 | #toggle-all {
397 | top: -56px;
398 | left: -15px;
399 | width: 65px;
400 | height: 41px;
401 | -webkit-transform: rotate(90deg);
402 | -ms-transform: rotate(90deg);
403 | transform: rotate(90deg);
404 | -webkit-appearance: none;
405 | appearance: none;
406 | }
407 | }
408 |
409 | .hidden {
410 | display: none;
411 | }
412 |
413 | hr {
414 | margin: 20px 0;
415 | border: 0;
416 | border-top: 1px dashed #C5C5C5;
417 | border-bottom: 1px dashed #F7F7F7;
418 | }
419 |
420 | .learn a {
421 | font-weight: normal;
422 | text-decoration: none;
423 | color: #b83f45;
424 | }
425 |
426 | .learn a:hover {
427 | text-decoration: underline;
428 | color: #787e7e;
429 | }
430 |
431 | .learn h3,
432 | .learn h4,
433 | .learn h5 {
434 | margin: 10px 0;
435 | font-weight: 500;
436 | line-height: 1.2;
437 | color: #000;
438 | }
439 |
440 | .learn h3 {
441 | font-size: 24px;
442 | }
443 |
444 | .learn h4 {
445 | font-size: 18px;
446 | }
447 |
448 | .learn h5 {
449 | margin-bottom: 0;
450 | font-size: 14px;
451 | }
452 |
453 | .learn ul {
454 | padding: 0;
455 | margin: 0 0 30px 25px;
456 | }
457 |
458 | .learn li {
459 | line-height: 20px;
460 | }
461 |
462 | .learn p {
463 | font-size: 15px;
464 | font-weight: 300;
465 | line-height: 1.3;
466 | margin-top: 0;
467 | margin-bottom: 0;
468 | }
469 |
470 | .quote {
471 | border: none;
472 | margin: 20px 0 60px 0;
473 | }
474 |
475 | .quote p {
476 | font-style: italic;
477 | }
478 |
479 | .quote p:before {
480 | content: '“';
481 | font-size: 50px;
482 | opacity: .15;
483 | position: absolute;
484 | top: -20px;
485 | left: 3px;
486 | }
487 |
488 | .quote p:after {
489 | content: '”';
490 | font-size: 50px;
491 | opacity: .15;
492 | position: absolute;
493 | bottom: -42px;
494 | right: 3px;
495 | }
496 |
497 | .quote footer {
498 | position: absolute;
499 | bottom: -40px;
500 | right: 0;
501 | }
502 |
503 | .quote footer img {
504 | border-radius: 3px;
505 | }
506 |
507 | .quote footer a {
508 | margin-left: 5px;
509 | vertical-align: middle;
510 | }
511 |
512 | .speech-bubble {
513 | position: relative;
514 | padding: 10px;
515 | background: rgba(0, 0, 0, .04);
516 | border-radius: 5px;
517 | }
518 |
519 | .speech-bubble:after {
520 | content: '';
521 | position: absolute;
522 | top: 100%;
523 | right: 30px;
524 | border: 13px solid transparent;
525 | border-top-color: rgba(0, 0, 0, .04);
526 | }
527 |
528 | .learn-bar > .learn {
529 | position: absolute;
530 | width: 272px;
531 | top: 8px;
532 | left: -300px;
533 | padding: 10px;
534 | border-radius: 5px;
535 | background-color: rgba(255, 255, 255, .6);
536 | -webkit-transition-property: left;
537 | transition-property: left;
538 | -webkit-transition-duration: 500ms;
539 | transition-duration: 500ms;
540 | }
541 |
542 | @media (min-width: 899px) {
543 | .learn-bar {
544 | width: auto;
545 | margin: 0 0 0 300px;
546 | }
547 |
548 | .learn-bar > .learn {
549 | left: 8px;
550 | }
551 |
552 | .learn-bar #todoapp {
553 | width: 550px;
554 | margin: 130px auto 40px auto;
555 | }
556 | }
557 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/todomvc-common/base.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | // Underscore's Template Module
5 | // Courtesy of underscorejs.org
6 | var _ = (function (_) {
7 | _.defaults = function (object) {
8 | if (!object) {
9 | return object;
10 | }
11 | for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
12 | var iterable = arguments[argsIndex];
13 | if (iterable) {
14 | for (var key in iterable) {
15 | if (object[key] == null) {
16 | object[key] = iterable[key];
17 | }
18 | }
19 | }
20 | }
21 | return object;
22 | }
23 |
24 | // By default, Underscore uses ERB-style template delimiters, change the
25 | // following template settings to use alternative delimiters.
26 | _.templateSettings = {
27 | evaluate : /<%([\s\S]+?)%>/g,
28 | interpolate : /<%=([\s\S]+?)%>/g,
29 | escape : /<%-([\s\S]+?)%>/g
30 | };
31 |
32 | // When customizing `templateSettings`, if you don't want to define an
33 | // interpolation, evaluation or escaping regex, we need one that is
34 | // guaranteed not to match.
35 | var noMatch = /(.)^/;
36 |
37 | // Certain characters need to be escaped so that they can be put into a
38 | // string literal.
39 | var escapes = {
40 | "'": "'",
41 | '\\': '\\',
42 | '\r': 'r',
43 | '\n': 'n',
44 | '\t': 't',
45 | '\u2028': 'u2028',
46 | '\u2029': 'u2029'
47 | };
48 |
49 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
50 |
51 | // JavaScript micro-templating, similar to John Resig's implementation.
52 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
53 | // and correctly escapes quotes within interpolated code.
54 | _.template = function(text, data, settings) {
55 | var render;
56 | settings = _.defaults({}, settings, _.templateSettings);
57 |
58 | // Combine delimiters into one regular expression via alternation.
59 | var matcher = new RegExp([
60 | (settings.escape || noMatch).source,
61 | (settings.interpolate || noMatch).source,
62 | (settings.evaluate || noMatch).source
63 | ].join('|') + '|$', 'g');
64 |
65 | // Compile the template source, escaping string literals appropriately.
66 | var index = 0;
67 | var source = "__p+='";
68 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
69 | source += text.slice(index, offset)
70 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
71 |
72 | if (escape) {
73 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
74 | }
75 | if (interpolate) {
76 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
77 | }
78 | if (evaluate) {
79 | source += "';\n" + evaluate + "\n__p+='";
80 | }
81 | index = offset + match.length;
82 | return match;
83 | });
84 | source += "';\n";
85 |
86 | // If a variable is not specified, place data values in local scope.
87 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
88 |
89 | source = "var __t,__p='',__j=Array.prototype.join," +
90 | "print=function(){__p+=__j.call(arguments,'');};\n" +
91 | source + "return __p;\n";
92 |
93 | try {
94 | render = new Function(settings.variable || 'obj', '_', source);
95 | } catch (e) {
96 | e.source = source;
97 | throw e;
98 | }
99 |
100 | if (data) return render(data, _);
101 | var template = function(data) {
102 | return render.call(this, data, _);
103 | };
104 |
105 | // Provide the compiled function source as a convenience for precompilation.
106 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
107 |
108 | return template;
109 | };
110 |
111 | return _;
112 | })({});
113 |
114 | if (location.hostname === 'todomvc.com') {
115 | window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
116 | }
117 |
118 | function redirect() {
119 | if (location.hostname === 'tastejs.github.io') {
120 | location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
121 | }
122 | }
123 |
124 | function findRoot() {
125 | var base;
126 |
127 | [/labs/, /\w*-examples/].forEach(function (href) {
128 | var match = location.href.match(href);
129 |
130 | if (!base && match) {
131 | base = location.href.indexOf(match);
132 | }
133 | });
134 |
135 | return location.href.substr(0, base);
136 | }
137 |
138 | function getFile(file, callback) {
139 | if (!location.host) {
140 | return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
141 | }
142 |
143 | var xhr = new XMLHttpRequest();
144 |
145 | xhr.open('GET', findRoot() + file, true);
146 | xhr.send();
147 |
148 | xhr.onload = function () {
149 | if (xhr.status === 200 && callback) {
150 | callback(xhr.responseText);
151 | }
152 | };
153 | }
154 |
155 | function Learn(learnJSON, config) {
156 | if (!(this instanceof Learn)) {
157 | return new Learn(learnJSON, config);
158 | }
159 |
160 | var template, framework;
161 |
162 | if (typeof learnJSON !== 'object') {
163 | try {
164 | learnJSON = JSON.parse(learnJSON);
165 | } catch (e) {
166 | return;
167 | }
168 | }
169 |
170 | if (config) {
171 | template = config.template;
172 | framework = config.framework;
173 | }
174 |
175 | if (!template && learnJSON.templates) {
176 | template = learnJSON.templates.todomvc;
177 | }
178 |
179 | if (!framework && document.querySelector('[data-framework]')) {
180 | framework = document.querySelector('[data-framework]').getAttribute('data-framework');
181 | }
182 |
183 |
184 | if (template && learnJSON[framework]) {
185 | this.frameworkJSON = learnJSON[framework];
186 | this.template = template;
187 |
188 | this.append();
189 | }
190 | }
191 |
192 | Learn.prototype.append = function () {
193 | var aside = document.createElement('aside');
194 | aside.innerHTML = _.template(this.template, this.frameworkJSON);
195 | aside.className = 'learn';
196 |
197 | // Localize demo links
198 | var demoLinks = aside.querySelectorAll('.demo-link');
199 | Array.prototype.forEach.call(demoLinks, function (demoLink) {
200 | demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
201 | });
202 |
203 | document.body.className = (document.body.className + ' learn-bar').trim();
204 | document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
205 | };
206 |
207 | redirect();
208 | // getFile('learn.json', Learn);
209 | })();
210 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/todomvc-common/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/mithril/bower_components/todomvc-common/bg.png
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/todomvc-common/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-common",
3 | "version": "0.1.9"
4 | }
5 |
--------------------------------------------------------------------------------
/todomvc/mithril/bower_components/todomvc-common/readme.md:
--------------------------------------------------------------------------------
1 | # todomvc-common
2 |
3 | > Bower component for some common utilities we use in every app
4 |
5 |
6 | ## License
7 |
8 | MIT
9 |
--------------------------------------------------------------------------------
/todomvc/mithril/css/app.css:
--------------------------------------------------------------------------------
1 | /* base.css overrides */
2 |
--------------------------------------------------------------------------------
/todomvc/mithril/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Mithril • TodoMVC
6 |
7 |
8 |
9 |
10 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/app.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function( window ) {
4 | 'use strict';
5 |
6 | app.ENTER_KEY = 13;
7 | app.ESC_KEY = 27;
8 |
9 | m.route(document.getElementById('todoapp'), '/', {
10 | '/': app,
11 | '/:filter': app
12 | });
13 |
14 | })(window);
15 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/controllers/todo.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | app.controller = function() {
7 |
8 | this.list = new app.TodoList(); // Todo collection
9 | this.title = m.prop(''); // Temp title placeholder
10 | this.filter = m.prop(m.route.param('filter') || ''); // TodoList filter
11 |
12 | // Add a Todo
13 | this.add = function(title) {
14 | if(this.title()) {
15 | this.list.push(new app.Todo({title: title()}));
16 | this.title('');
17 | }
18 | };
19 |
20 | //check whether a todo is visible
21 | this.isVisible = function(todo) {
22 | if(this.filter() == '')
23 | return true;
24 | if (this.filter() == 'active')
25 | return !todo.completed();
26 | if (this.filter() == 'completed')
27 | return todo.completed();
28 | }
29 |
30 | this.clearTitle = function() {
31 | this.title('')
32 | }
33 |
34 | // Removing a Todo from the list
35 | this.remove = function(key) {
36 | this.list.splice(key, 1)
37 | }
38 |
39 | // Remove all Todos where Completed == true
40 | this.clearCompleted = function() {
41 | for(var i = 0; i < this.list.length; i++) {
42 | if(this.list[i].completed())
43 | this.list.splice(i, 1)
44 | }
45 | }
46 |
47 | // Total amount of Todos completed
48 | this.amountCompleted = function() {
49 | var amount = 0;
50 |
51 | for(var i = 0; i < this.list.length; i++)
52 | if(this.list[i].completed())
53 | amount++;
54 |
55 | return amount;
56 | }
57 | };
58 |
59 | })();
60 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/models/todo.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | // Todo Model
7 | app.Todo = function(data) {
8 | this.title = m.prop(data.title);
9 | this.completed = m.prop(false);
10 | };
11 |
12 | // List of Todos
13 | var list = [];
14 | app.TodoList = function() {
15 | return list;
16 | };
17 |
18 | })();
19 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/views/footer-view.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | app.footer = function(ctrl) {
7 | return m('footer#footer', [
8 | m('span#todo-count', [
9 | m('strong', ctrl.list.length), ' item' + (ctrl.list.length > 1 ? 's' : '') + ' left'
10 | ]),
11 | m('ul#filters', [
12 | m('li', [
13 | m('a[href=/]', {
14 | config: m.route,
15 | class: ctrl.filter() == '' ? 'selected' : ''
16 | }, 'All')
17 | ]),
18 | m('li', [
19 | m('a[href=/active]', {
20 | config: m.route,
21 | class: ctrl.filter() == 'active' ? 'selected' : ''
22 | }, 'Active')
23 | ]),
24 | m('li', [
25 | m('a[href=/completed]', {
26 | config: m.route,
27 | class: ctrl.filter() == 'completed' ? 'selected' : ''
28 | }, 'Completed')
29 | ])
30 | ]),
31 | ctrl.amountCompleted() == 0 ? '' : m('button#clear-completed', {
32 | onclick: ctrl.clearCompleted.bind(ctrl)
33 | }, 'Clear completed (' + ctrl.amountCompleted() + ')')
34 | ]);
35 | }
36 |
37 | })();
38 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/views/main-view.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | //view utility
7 | app.watchInput = function(ontype, onenter, onescape) {
8 | return function(e) {
9 | ontype(e)
10 | if (e.keyCode == app.ENTER_KEY) onenter()
11 | if (e.keyCode == app.ESC_KEY) onescape()
12 | }
13 | };
14 |
15 |
16 |
17 | app.view = function(ctrl) {
18 | return [
19 | m('header#header', [
20 | m('h1', 'todos'),
21 | m('input#new-todo[placeholder="What needs to be done?"]', {
22 | onkeypress: app.watchInput(
23 | m.withAttr('value', ctrl.title),
24 | ctrl.add.bind(ctrl, ctrl.title),
25 | ctrl.clearTitle.bind(ctrl)
26 | ),
27 | value: ctrl.title()
28 | })
29 | ]),
30 | m('section#main', [
31 | m('input#toggle-all[type=checkbox]'),
32 | m('ul#todo-list', [
33 | ctrl.list.filter(ctrl.isVisible.bind(ctrl)).map(function(task, index) {
34 | return m('li', { class: task.completed() ? 'completed' : ''}, [
35 | m('.view', [
36 | m('input.toggle[type=checkbox]', {
37 | onclick: m.withAttr('checked', task.completed),
38 | checked: task.completed()
39 | }),
40 | m('label', task.title()),
41 | m('button.destroy', { onclick: ctrl.remove.bind(ctrl, index)})
42 | ]),
43 | m('input.edit')
44 | ])
45 | })
46 | ])
47 | ]),
48 | ctrl.list.length == 0 ? '' : app.footer(ctrl)
49 | ];
50 | };
51 |
52 | })();
53 |
--------------------------------------------------------------------------------
/todomvc/mithril/js/views/single-view.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | // Single todo view
7 | app.single = function(ctrl, task, index) {
8 | return m('li', { class: task.completed() ? 'completed' : ''}, [
9 | m('.view', [
10 | m('input.toggle[type=checkbox]', {
11 | onclick: m.withAttr('checked', task.completed),
12 | checked: task.completed()
13 | }),
14 | m('label', task.title()),
15 | m('button.destroy', { onclick: ctrl.remove.bind(ctrl, index)})
16 | ]),
17 | m('input.edit')
18 | ]);
19 | };
20 |
21 | })();
22 |
--------------------------------------------------------------------------------
/todomvc/mogwai/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Mogwai • TodoMVC
6 |
7 |
8 |
9 |
10 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/todomvc/mogwai/pkg/README.md:
--------------------------------------------------------------------------------
1 |
19 |
20 | ## About
21 |
22 | [**📚 Read this template tutorial! 📚**][template-docs]
23 |
24 | This template is designed for compiling Rust libraries into WebAssembly and
25 | publishing the resulting package to NPM.
26 |
27 | Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
28 | templates and usages of `wasm-pack`.
29 |
30 | [tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
31 | [template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
32 |
33 | ## 🚴 Usage
34 |
35 | ### 🐑 Use `cargo generate` to Clone this Template
36 |
37 | [Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
38 |
39 | ```
40 | cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
41 | cd my-project
42 | ```
43 |
44 | ### 🛠️ Build with `wasm-pack build`
45 |
46 | ```
47 | wasm-pack build
48 | ```
49 |
50 | ### 🔬 Test in Headless Browsers with `wasm-pack test`
51 |
52 | ```
53 | wasm-pack test --headless --firefox
54 | ```
55 |
56 | ### 🎁 Publish to NPM with `wasm-pack publish`
57 |
58 | ```
59 | wasm-pack publish
60 | ```
61 |
62 | ## 🔋 Batteries Included
63 |
64 | * [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
65 | between WebAssembly and JavaScript.
66 | * [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
67 | for logging panic messages to the developer console.
68 | * [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized
69 | for small code size.
70 |
--------------------------------------------------------------------------------
/todomvc/mogwai/pkg/mogwai_todo.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /**
3 | */
4 | export function main(): void;
5 |
6 | /**
7 | * If `module_or_path` is {RequestInfo}, makes a request and
8 | * for everything else, calls `WebAssembly.instantiate` directly.
9 | *
10 | * @param {RequestInfo | BufferSource | WebAssembly.Module} module_or_path
11 | *
12 | * @returns {Promise}
13 | */
14 | export default function init (module_or_path: RequestInfo | BufferSource | WebAssembly.Module): Promise;
15 |
--------------------------------------------------------------------------------
/todomvc/mogwai/pkg/mogwai_todo_bg.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | export const memory: WebAssembly.Memory;
3 | export function main(): void;
4 | export function __wbindgen_exn_store(a: number): void;
5 | export function __wbindgen_malloc(a: number): number;
6 | export function __wbindgen_realloc(a: number, b: number, c: number): number;
7 | export function __wbindgen_free(a: number, b: number): void;
8 | export const __wbg_function_table: WebAssembly.Table;
9 |
--------------------------------------------------------------------------------
/todomvc/mogwai/pkg/mogwai_todo_bg.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/mogwai/pkg/mogwai_todo_bg.wasm
--------------------------------------------------------------------------------
/todomvc/mogwai/pkg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mogwai-todo",
3 | "collaborators": [
4 | "Schell Scivally "
5 | ],
6 | "version": "0.1.0",
7 | "files": [
8 | "mogwai_todo_bg.wasm",
9 | "mogwai_todo.js",
10 | "mogwai_todo.d.ts"
11 | ],
12 | "browser": "mogwai_todo.js",
13 | "types": "mogwai_todo.d.ts"
14 | }
--------------------------------------------------------------------------------
/todomvc/mogwai/todo.css:
--------------------------------------------------------------------------------
1 | hr {
2 | margin: 20px 0;
3 | border: 0;
4 | border-top: 1px dashed #c5c5c5;
5 | border-bottom: 1px dashed #f7f7f7;
6 | }
7 |
8 | .learn a {
9 | font-weight: normal;
10 | text-decoration: none;
11 | color: #b83f45;
12 | }
13 |
14 | .learn a:hover {
15 | text-decoration: underline;
16 | color: #787e7e;
17 | }
18 |
19 | .learn h3,
20 | .learn h4,
21 | .learn h5 {
22 | margin: 10px 0;
23 | font-weight: 500;
24 | line-height: 1.2;
25 | color: #000;
26 | }
27 |
28 | .learn h3 {
29 | font-size: 24px;
30 | }
31 |
32 | .learn h4 {
33 | font-size: 18px;
34 | }
35 |
36 | .learn h5 {
37 | margin-bottom: 0;
38 | font-size: 14px;
39 | }
40 |
41 | .learn ul {
42 | padding: 0;
43 | margin: 0 0 30px 25px;
44 | }
45 |
46 | .learn li {
47 | line-height: 20px;
48 | }
49 |
50 | .learn p {
51 | font-size: 15px;
52 | font-weight: 300;
53 | line-height: 1.3;
54 | margin-top: 0;
55 | margin-bottom: 0;
56 | }
57 |
58 | #issue-count {
59 | display: none;
60 | }
61 |
62 | .quote {
63 | border: none;
64 | margin: 20px 0 60px 0;
65 | }
66 |
67 | .quote p {
68 | font-style: italic;
69 | }
70 |
71 | .quote p:before {
72 | content: '“';
73 | font-size: 50px;
74 | opacity: .15;
75 | position: absolute;
76 | top: -20px;
77 | left: 3px;
78 | }
79 |
80 | .quote p:after {
81 | content: '”';
82 | font-size: 50px;
83 | opacity: .15;
84 | position: absolute;
85 | bottom: -42px;
86 | right: 3px;
87 | }
88 |
89 | .quote footer {
90 | position: absolute;
91 | bottom: -40px;
92 | right: 0;
93 | }
94 |
95 | .quote footer img {
96 | border-radius: 3px;
97 | }
98 |
99 | .quote footer a {
100 | margin-left: 5px;
101 | vertical-align: middle;
102 | }
103 |
104 | .speech-bubble {
105 | position: relative;
106 | padding: 10px;
107 | background: rgba(0, 0, 0, .04);
108 | border-radius: 5px;
109 | }
110 |
111 | .speech-bubble:after {
112 | content: '';
113 | position: absolute;
114 | top: 100%;
115 | right: 30px;
116 | border: 13px solid transparent;
117 | border-top-color: rgba(0, 0, 0, .04);
118 | }
119 |
120 | .learn-bar > .learn {
121 | position: absolute;
122 | width: 272px;
123 | top: 8px;
124 | left: -300px;
125 | padding: 10px;
126 | border-radius: 5px;
127 | background-color: rgba(255, 255, 255, .6);
128 | transition-property: left;
129 | transition-duration: 500ms;
130 | }
131 |
132 | @media (min-width: 899px) {
133 | .learn-bar {
134 | width: auto;
135 | padding-left: 300px;
136 | }
137 |
138 | .learn-bar > .learn {
139 | left: 8px;
140 | }
141 | }
142 |
143 | html,
144 | body {
145 | margin: 0;
146 | padding: 0;
147 | }
148 |
149 | button {
150 | margin: 0;
151 | padding: 0;
152 | border: 0;
153 | background: none;
154 | font-size: 100%;
155 | vertical-align: baseline;
156 | font-family: inherit;
157 | font-weight: inherit;
158 | color: inherit;
159 | -webkit-appearance: none;
160 | appearance: none;
161 | -webkit-font-smoothing: antialiased;
162 | -moz-osx-font-smoothing: grayscale;
163 | }
164 |
165 | body {
166 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
167 | line-height: 1.4em;
168 | background: #f5f5f5;
169 | color: #4d4d4d;
170 | min-width: 230px;
171 | max-width: 550px;
172 | margin: 0 auto;
173 | -webkit-font-smoothing: antialiased;
174 | -moz-osx-font-smoothing: grayscale;
175 | font-weight: 300;
176 | }
177 |
178 | :focus {
179 | outline: 0;
180 | }
181 |
182 | .hidden {
183 | display: none;
184 | }
185 |
186 | .todoapp {
187 | background: #fff;
188 | margin: 130px 0 40px 0;
189 | position: relative;
190 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
191 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
192 | }
193 |
194 | .todoapp input::-webkit-input-placeholder {
195 | font-style: italic;
196 | font-weight: 300;
197 | color: #e6e6e6;
198 | }
199 |
200 | .todoapp input::-moz-placeholder {
201 | font-style: italic;
202 | font-weight: 300;
203 | color: #e6e6e6;
204 | }
205 |
206 | .todoapp input::input-placeholder {
207 | font-style: italic;
208 | font-weight: 300;
209 | color: #e6e6e6;
210 | }
211 |
212 | .todoapp h1 {
213 | position: absolute;
214 | top: -155px;
215 | width: 100%;
216 | font-size: 100px;
217 | font-weight: 100;
218 | text-align: center;
219 | color: rgba(175, 47, 47, 0.15);
220 | -webkit-text-rendering: optimizeLegibility;
221 | -moz-text-rendering: optimizeLegibility;
222 | text-rendering: optimizeLegibility;
223 | }
224 |
225 | .new-todo,
226 | .edit {
227 | position: relative;
228 | margin: 0;
229 | width: 100%;
230 | font-size: 24px;
231 | font-family: inherit;
232 | font-weight: inherit;
233 | line-height: 1.4em;
234 | border: 0;
235 | color: inherit;
236 | padding: 6px;
237 | border: 1px solid #999;
238 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
239 | box-sizing: border-box;
240 | -webkit-font-smoothing: antialiased;
241 | -moz-osx-font-smoothing: grayscale;
242 | }
243 |
244 | .new-todo {
245 | padding: 16px 16px 16px 60px;
246 | border: none;
247 | background: rgba(0, 0, 0, 0.003);
248 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
249 | }
250 |
251 | .main {
252 | position: relative;
253 | z-index: 2;
254 | border-top: 1px solid #e6e6e6;
255 | }
256 |
257 | .toggle-all {
258 | text-align: center;
259 | border: none; /* Mobile Safari */
260 | opacity: 0;
261 | position: absolute;
262 | }
263 |
264 | .toggle-all + label {
265 | width: 60px;
266 | height: 34px;
267 | font-size: 0;
268 | position: absolute;
269 | top: -52px;
270 | left: -13px;
271 | -webkit-transform: rotate(90deg);
272 | transform: rotate(90deg);
273 | }
274 |
275 | .toggle-all + label:before {
276 | content: '❯';
277 | font-size: 22px;
278 | color: #e6e6e6;
279 | padding: 10px 27px 10px 27px;
280 | }
281 |
282 | .toggle-all:checked + label:before {
283 | color: #737373;
284 | }
285 |
286 | .todo-list {
287 | margin: 0;
288 | padding: 0;
289 | list-style: none;
290 | }
291 |
292 | .todo-list li {
293 | position: relative;
294 | font-size: 24px;
295 | border-bottom: 1px solid #ededed;
296 | }
297 |
298 | .todo-list li:last-child {
299 | border-bottom: none;
300 | }
301 |
302 | .todo-list li.editing {
303 | border-bottom: none;
304 | padding: 0;
305 | }
306 |
307 | .todo-list li.editing .edit {
308 | display: block;
309 | width: 506px;
310 | padding: 12px 16px;
311 | margin: 0 0 0 43px;
312 | }
313 |
314 | .todo-list li.editing .view {
315 | display: none;
316 | }
317 |
318 | .todo-list li .toggle {
319 | text-align: center;
320 | width: 40px;
321 | /* auto, since non-WebKit browsers doesn't support input styling */
322 | height: auto;
323 | position: absolute;
324 | top: 0;
325 | bottom: 0;
326 | margin: auto 0;
327 | border: none; /* Mobile Safari */
328 | -webkit-appearance: none;
329 | appearance: none;
330 | }
331 |
332 | .todo-list li .toggle {
333 | opacity: 0;
334 | }
335 |
336 | .todo-list li .toggle + label {
337 | /*
338 | Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
339 | 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/
340 | */
341 | 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');
342 | background-repeat: no-repeat;
343 | background-position: center left;
344 | }
345 |
346 | .todo-list li .toggle:checked + label {
347 | 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');
348 | }
349 |
350 | .todo-list li label {
351 | word-break: break-all;
352 | padding: 15px 15px 15px 60px;
353 | display: block;
354 | line-height: 1.2;
355 | transition: color 0.4s;
356 | }
357 |
358 | .todo-list li.completed label {
359 | color: #d9d9d9;
360 | text-decoration: line-through;
361 | }
362 |
363 | .todo-list li .destroy {
364 | display: none;
365 | position: absolute;
366 | top: 0;
367 | right: 10px;
368 | bottom: 0;
369 | width: 40px;
370 | height: 40px;
371 | margin: auto 0;
372 | font-size: 30px;
373 | color: #cc9a9a;
374 | margin-bottom: 11px;
375 | transition: color 0.2s ease-out;
376 | }
377 |
378 | .todo-list li .destroy:hover {
379 | color: #af5b5e;
380 | }
381 |
382 | .todo-list li .destroy:after {
383 | content: '×';
384 | }
385 |
386 | .todo-list li:hover .destroy {
387 | display: block;
388 | }
389 |
390 | .todo-list li .edit {
391 | display: none;
392 | }
393 |
394 | .todo-list li.editing:last-child {
395 | margin-bottom: -1px;
396 | }
397 |
398 | .footer {
399 | color: #777;
400 | padding: 10px 15px;
401 | height: 20px;
402 | text-align: center;
403 | border-top: 1px solid #e6e6e6;
404 | }
405 |
406 | .footer:before {
407 | content: '';
408 | position: absolute;
409 | right: 0;
410 | bottom: 0;
411 | left: 0;
412 | height: 50px;
413 | overflow: hidden;
414 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
415 | 0 8px 0 -3px #f6f6f6,
416 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
417 | 0 16px 0 -6px #f6f6f6,
418 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
419 | }
420 |
421 | .todo-count {
422 | float: left;
423 | text-align: left;
424 | }
425 |
426 | .todo-count strong {
427 | font-weight: 300;
428 | }
429 |
430 | .filters {
431 | margin: 0;
432 | padding: 0;
433 | list-style: none;
434 | position: absolute;
435 | right: 0;
436 | left: 0;
437 | }
438 |
439 | .filters li {
440 | display: inline;
441 | }
442 |
443 | .filters li a {
444 | color: inherit;
445 | margin: 3px;
446 | padding: 3px 7px;
447 | text-decoration: none;
448 | border: 1px solid transparent;
449 | border-radius: 3px;
450 | }
451 |
452 | .filters li a:hover {
453 | border-color: rgba(175, 47, 47, 0.1);
454 | }
455 |
456 | .filters li a.selected {
457 | border-color: rgba(175, 47, 47, 0.2);
458 | }
459 |
460 | .clear-completed,
461 | html .clear-completed:active {
462 | float: right;
463 | position: relative;
464 | line-height: 20px;
465 | text-decoration: none;
466 | cursor: pointer;
467 | }
468 |
469 | .clear-completed:hover {
470 | text-decoration: underline;
471 | }
472 |
473 | .info {
474 | margin: 65px auto 0;
475 | color: #bfbfbf;
476 | font-size: 10px;
477 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
478 | text-align: center;
479 | }
480 |
481 | .info p {
482 | line-height: 1;
483 | }
484 |
485 | .info a {
486 | color: inherit;
487 | text-decoration: none;
488 | font-weight: 400;
489 | }
490 |
491 | .info a:hover {
492 | text-decoration: underline;
493 | }
494 |
495 | /*
496 | Hack to remove background from Mobile Safari.
497 | Can't use it globally since it destroys checkboxes in Firefox
498 | */
499 | @media screen and (-webkit-min-device-pixel-ratio:0) {
500 | .toggle-all,
501 | .todo-list li .toggle {
502 | background: none;
503 | }
504 |
505 | .todo-list li .toggle {
506 | height: 40px;
507 | }
508 | }
509 |
510 | @media (max-width: 430px) {
511 | .footer {
512 | height: 50px;
513 | }
514 |
515 | .filters {
516 | bottom: 10px;
517 | }
518 | }
519 |
--------------------------------------------------------------------------------
/todomvc/preact/bower_components/todomvc-common/.bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-common",
3 | "version": "0.1.9",
4 | "homepage": "https://github.com/tastejs/todomvc-common",
5 | "_release": "0.1.9",
6 | "_resolution": {
7 | "type": "version",
8 | "tag": "v0.1.9",
9 | "commit": "7dd61b0ebf56c020e719a69444442cc7ae7242ff"
10 | },
11 | "_source": "git://github.com/tastejs/todomvc-common.git",
12 | "_target": "~0.1.4",
13 | "_originalSource": "todomvc-common"
14 | }
--------------------------------------------------------------------------------
/todomvc/preact/bower_components/todomvc-common/base.js:
--------------------------------------------------------------------------------
1 | (function () {
2 | 'use strict';
3 |
4 | // Underscore's Template Module
5 | // Courtesy of underscorejs.org
6 | var _ = (function (_) {
7 | _.defaults = function (object) {
8 | if (!object) {
9 | return object;
10 | }
11 | for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
12 | var iterable = arguments[argsIndex];
13 | if (iterable) {
14 | for (var key in iterable) {
15 | if (object[key] == null) {
16 | object[key] = iterable[key];
17 | }
18 | }
19 | }
20 | }
21 | return object;
22 | }
23 |
24 | // By default, Underscore uses ERB-style template delimiters, change the
25 | // following template settings to use alternative delimiters.
26 | _.templateSettings = {
27 | evaluate : /<%([\s\S]+?)%>/g,
28 | interpolate : /<%=([\s\S]+?)%>/g,
29 | escape : /<%-([\s\S]+?)%>/g
30 | };
31 |
32 | // When customizing `templateSettings`, if you don't want to define an
33 | // interpolation, evaluation or escaping regex, we need one that is
34 | // guaranteed not to match.
35 | var noMatch = /(.)^/;
36 |
37 | // Certain characters need to be escaped so that they can be put into a
38 | // string literal.
39 | var escapes = {
40 | "'": "'",
41 | '\\': '\\',
42 | '\r': 'r',
43 | '\n': 'n',
44 | '\t': 't',
45 | '\u2028': 'u2028',
46 | '\u2029': 'u2029'
47 | };
48 |
49 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
50 |
51 | // JavaScript micro-templating, similar to John Resig's implementation.
52 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
53 | // and correctly escapes quotes within interpolated code.
54 | _.template = function(text, data, settings) {
55 | var render;
56 | settings = _.defaults({}, settings, _.templateSettings);
57 |
58 | // Combine delimiters into one regular expression via alternation.
59 | var matcher = new RegExp([
60 | (settings.escape || noMatch).source,
61 | (settings.interpolate || noMatch).source,
62 | (settings.evaluate || noMatch).source
63 | ].join('|') + '|$', 'g');
64 |
65 | // Compile the template source, escaping string literals appropriately.
66 | var index = 0;
67 | var source = "__p+='";
68 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
69 | source += text.slice(index, offset)
70 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
71 |
72 | if (escape) {
73 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
74 | }
75 | if (interpolate) {
76 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
77 | }
78 | if (evaluate) {
79 | source += "';\n" + evaluate + "\n__p+='";
80 | }
81 | index = offset + match.length;
82 | return match;
83 | });
84 | source += "';\n";
85 |
86 | // If a variable is not specified, place data values in local scope.
87 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
88 |
89 | source = "var __t,__p='',__j=Array.prototype.join," +
90 | "print=function(){__p+=__j.call(arguments,'');};\n" +
91 | source + "return __p;\n";
92 |
93 | try {
94 | render = new Function(settings.variable || 'obj', '_', source);
95 | } catch (e) {
96 | e.source = source;
97 | throw e;
98 | }
99 |
100 | if (data) return render(data, _);
101 | var template = function(data) {
102 | return render.call(this, data, _);
103 | };
104 |
105 | // Provide the compiled function source as a convenience for precompilation.
106 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
107 |
108 | return template;
109 | };
110 |
111 | return _;
112 | })({});
113 |
114 | if (location.hostname === 'todomvc.com') {
115 | window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
116 | }
117 |
118 | function redirect() {
119 | if (location.hostname === 'tastejs.github.io') {
120 | location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
121 | }
122 | }
123 |
124 | function findRoot() {
125 | var base;
126 |
127 | [/labs/, /\w*-examples/].forEach(function (href) {
128 | var match = location.href.match(href);
129 |
130 | if (!base && match) {
131 | base = location.href.indexOf(match);
132 | }
133 | });
134 |
135 | return location.href.substr(0, base);
136 | }
137 |
138 | function getFile(file, callback) {
139 | if (!location.host) {
140 | return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
141 | }
142 |
143 | var xhr = new XMLHttpRequest();
144 |
145 | xhr.open('GET', findRoot() + file, true);
146 | xhr.send();
147 |
148 | xhr.onload = function () {
149 | if (xhr.status === 200 && callback) {
150 | callback(xhr.responseText);
151 | }
152 | };
153 | }
154 |
155 | function Learn(learnJSON, config) {
156 | if (!(this instanceof Learn)) {
157 | return new Learn(learnJSON, config);
158 | }
159 |
160 | var template, framework;
161 |
162 | if (typeof learnJSON !== 'object') {
163 | try {
164 | learnJSON = JSON.parse(learnJSON);
165 | } catch (e) {
166 | return;
167 | }
168 | }
169 |
170 | if (config) {
171 | template = config.template;
172 | framework = config.framework;
173 | }
174 |
175 | if (!template && learnJSON.templates) {
176 | template = learnJSON.templates.todomvc;
177 | }
178 |
179 | if (!framework && document.querySelector('[data-framework]')) {
180 | framework = document.querySelector('[data-framework]').getAttribute('data-framework');
181 | }
182 |
183 |
184 | if (template && learnJSON[framework]) {
185 | this.frameworkJSON = learnJSON[framework];
186 | this.template = template;
187 |
188 | this.append();
189 | }
190 | }
191 |
192 | Learn.prototype.append = function () {
193 | var aside = document.createElement('aside');
194 | aside.innerHTML = _.template(this.template, this.frameworkJSON);
195 | aside.className = 'learn';
196 |
197 | // Localize demo links
198 | var demoLinks = aside.querySelectorAll('.demo-link');
199 | Array.prototype.forEach.call(demoLinks, function (demoLink) {
200 | demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
201 | });
202 |
203 | document.body.className = (document.body.className + ' learn-bar').trim();
204 | document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
205 | };
206 |
207 | redirect();
208 | // getFile('learn.json', Learn);
209 | })();
210 |
--------------------------------------------------------------------------------
/todomvc/preact/bower_components/todomvc-common/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/preact/bower_components/todomvc-common/bg.png
--------------------------------------------------------------------------------
/todomvc/preact/bower_components/todomvc-common/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc-common",
3 | "version": "0.1.9"
4 | }
5 |
--------------------------------------------------------------------------------
/todomvc/preact/bower_components/todomvc-common/readme.md:
--------------------------------------------------------------------------------
1 | # todomvc-common
2 |
3 | > Bower component for some common utilities we use in every app
4 |
5 |
6 | ## License
7 |
8 | MIT
9 |
--------------------------------------------------------------------------------
/todomvc/preact/index.html:
--------------------------------------------------------------------------------
1 | Preact • TodoMVC
--------------------------------------------------------------------------------
/todomvc/preact/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "preact-todomvc",
3 | "version": "0.2.0",
4 | "scripts": {
5 | "build": "preact build --template index.html && cp -r build/{bundle.js,bundle.js.map,index.html} ./ && rm -rf build"
6 | },
7 | "dependencies": {
8 | "linkstate": "^1.0.1",
9 | "preact": "^8.1.0",
10 | "preact-router": "^2.0.0"
11 | },
12 | "devDependencies": {
13 | "preact-cli": "^1.3.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/todomvc/preact/src/app.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import linkState from 'linkstate';
3 | import Router from 'preact-router';
4 | import createTodoModel from './model';
5 | import TodoHeader from './header';
6 | import TodoFooter from './footer';
7 | import TodoItem from './item';
8 |
9 | const ALL_TODOS = 'all';
10 | const ACTIVE_TODOS = 'active';
11 | const COMPLETED_TODOS = 'completed';
12 |
13 | const FILTERS = {
14 | [ALL_TODOS]: todo => true,
15 | [ACTIVE_TODOS]: todo => !todo.completed,
16 | [COMPLETED_TODOS]: todo => todo.completed
17 | };
18 |
19 | export default class App extends Component {
20 | model = createTodoModel();
21 |
22 | state = {
23 | todos: this.model.todos,
24 | nowShowing: ALL_TODOS
25 | };
26 |
27 | handleRoute = ({ url }) => {
28 | let nowShowing = url.replace(/\/$/,'').split('/').pop();
29 | if (!FILTERS[nowShowing]) {
30 | nowShowing = ALL_TODOS;
31 | }
32 | this.setState({ nowShowing });
33 | };
34 |
35 | toggleAll = e => {
36 | this.model.toggleAll(e.target.checked);
37 | };
38 |
39 | save = (todo, text) => {
40 | this.model.save(todo, text);
41 | this.reset();
42 | };
43 |
44 | reset = () => {
45 | this.setState({ editing: null });
46 | };
47 |
48 | componentWillMount() {
49 | this.model.subscribe( state => {
50 | this.setState({ todos: state.todos });
51 | });
52 | }
53 |
54 | render({ }, { nowShowing=ALL_TODOS, todos, newTodo, editing }) {
55 | let shownTodos = todos.filter( FILTERS[nowShowing] ),
56 | activeTodoCount = todos.reduce( (a, todo) => a + (todo.completed ? 0 : 1), 0),
57 | completedCount = todos.length - activeTodoCount;
58 |
59 | return (
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | { todos.length ? (
68 |
90 | ) : null }
91 |
92 | { (activeTodoCount || completedCount) ? (
93 |
99 | ) : null }
100 |
101 | );
102 | }
103 | }
104 |
105 |
106 | // just a fake component we can feed to router. yay.
107 | const Noop = () => null;
108 |
--------------------------------------------------------------------------------
/todomvc/preact/src/footer.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import { pluralize } from './util';
3 |
4 | const ALL_TODOS = 'all';
5 | const ACTIVE_TODOS = 'active';
6 | const COMPLETED_TODOS = 'completed';
7 |
8 | export default ({ nowShowing, count, completedCount, onClearCompleted }) => (
9 |
32 | );
33 |
--------------------------------------------------------------------------------
/todomvc/preact/src/header.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import linkState from 'linkstate';
3 |
4 | const ENTER_KEY = 13;
5 |
6 | export default class TodoHeader extends Component {
7 | handleKey = e => {
8 | if (e.keyCode!==ENTER_KEY) return;
9 | e.preventDefault();
10 |
11 | let text = this.state.text.trim();
12 | if (text) {
13 | this.props.addTodo(text);
14 | this.setState({ text: '' });
15 | }
16 | };
17 |
18 | render({ }, { text }) {
19 | return (
20 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/todomvc/preact/src/index.js:
--------------------------------------------------------------------------------
1 | import { h, render } from 'preact';
2 | import App from './app';
3 |
4 | render(, document.getElementById('todoapp'));
5 |
--------------------------------------------------------------------------------
/todomvc/preact/src/item.js:
--------------------------------------------------------------------------------
1 | import { h, Component } from 'preact';
2 | import linkState from 'linkstate';
3 |
4 | const ESCAPE_KEY = 27;
5 | const ENTER_KEY = 13;
6 |
7 | export default class TodoItem extends Component {
8 | handleSubmit = () => {
9 | let val = this.state.editText.trim(),
10 | { todo, onSave, onDestroy } = this.props;
11 | if (val) {
12 | onSave(todo, val);
13 | this.setState({ editText: val });
14 | }
15 | else {
16 | onDestroy(todo);
17 | }
18 | };
19 |
20 | handleEdit = () => {
21 | let { todo, onEdit } = this.props;
22 | onEdit(todo);
23 | this.setState({ editText: todo.title });
24 | };
25 |
26 | toggle = e => {
27 | let { todo, onToggle } = this.props;
28 | onToggle(todo);
29 | e.preventDefault();
30 | };
31 |
32 | handleKeyDown = e => {
33 | let { todo, onCancel } = this.props;
34 | if (e.which===ESCAPE_KEY) {
35 | this.setState({ editText: todo.title });
36 | onCancel(todo);
37 | }
38 | else if (e.which===ENTER_KEY) {
39 | this.handleSubmit(todo);
40 | }
41 | };
42 |
43 | destroy = () => {
44 | let { todo, onDestroy } = this.props;
45 | onDestroy(todo);
46 | };
47 |
48 | focus(c) {
49 | if (c) setTimeout(() => c.focus(), 1);
50 | }
51 |
52 | // componentDidUpdate({ editing }) {
53 | // let node = editing && this.base && this.base.querySelector('.edit');
54 | // if (node) node.focus();
55 | // }
56 |
57 | render({ todo:{ title, completed }, editing }, { editText }) {
58 | return (
59 |
60 |
61 |
67 |
68 |
69 |
70 | { editing && (
71 |
79 | ) }
80 |
81 | );
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/todomvc/preact/src/model.js:
--------------------------------------------------------------------------------
1 | import { uuid, store } from './util';
2 |
3 | // note: commented out localStorage persistence as it mucks up tests.
4 |
5 | export default () => {
6 | let onChanges = [];
7 |
8 | function inform() {
9 | for (let i=onChanges.length; i--; ) {
10 | onChanges[i](model);
11 | }
12 | }
13 |
14 | let model = {
15 | todos: [],
16 |
17 | onChanges: [],
18 |
19 | subscribe(fn) {
20 | onChanges.push(fn);
21 | },
22 |
23 | addTodo(title) {
24 | model.todos = model.todos.concat({
25 | id: uuid(),
26 | title,
27 | completed: false
28 | });
29 | inform();
30 | },
31 |
32 | toggleAll(completed) {
33 | model.todos = model.todos.map(
34 | todo => ({ ...todo, completed })
35 | );
36 | inform();
37 | },
38 |
39 | toggle(todoToToggle) {
40 | model.todos = model.todos.map( todo => (
41 | todo !== todoToToggle ? todo : ({ ...todo, completed: !todo.completed })
42 | ) );
43 | inform();
44 | },
45 |
46 | destroy(todo) {
47 | model.todos = model.todos.filter( t => t !== todo );
48 | inform();
49 | },
50 |
51 | save(todoToSave, title) {
52 | model.todos = model.todos.map( todo => (
53 | todo !== todoToSave ? todo : ({ ...todo, title })
54 | ));
55 | inform();
56 | },
57 |
58 | clearCompleted() {
59 | model.todos = model.todos.filter( todo => !todo.completed );
60 | inform();
61 | }
62 | };
63 |
64 | return model;
65 | };
66 |
--------------------------------------------------------------------------------
/todomvc/preact/src/util.js:
--------------------------------------------------------------------------------
1 | export function uuid() {
2 | let uuid = '';
3 | for (let i=0; i<32; i++) {
4 | let random = Math.random() * 16 | 0;
5 | if (i === 8 || i === 12 || i === 16 || i === 20) {
6 | uuid += '-';
7 | }
8 | uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16);
9 | }
10 | return uuid;
11 | }
12 |
13 | export function pluralize(count, word) {
14 | return count === 1 ? word : word + 's';
15 | }
16 |
17 | export function store(namespace, data) {
18 | if (data) {
19 | return localStorage.setItem(namespace, JSON.stringify(data));
20 | }
21 |
22 | let store = localStorage.getItem(namespace);
23 | return (store && JSON.parse(store)) || [];
24 | }
25 |
--------------------------------------------------------------------------------
/todomvc/react/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/director
2 | !node_modules/director/build/director.js
3 |
4 | node_modules/react
5 | !node_modules/react/dist/react-with-addons.js
6 | !node_modules/react/dist/JSXTransformer.js
7 | node_modules/todomvc-app-css
8 | !node_modules/todomvc-app-css/index.css
9 |
10 | node_modules/todomvc-common
11 | !node_modules/todomvc-common/base.css
12 | !node_modules/todomvc-common/base.js
13 |
--------------------------------------------------------------------------------
/todomvc/react/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/todomvc/react/js/app.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React, Router, ReactDOM*/
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.ALL_TODOS = 'all';
12 | app.ACTIVE_TODOS = 'active';
13 | app.COMPLETED_TODOS = 'completed';
14 | var TodoFooter = React.createFactory(app.TodoFooter);
15 | var TodoItem = React.createFactory(app.TodoItem);
16 |
17 | var ENTER_KEY = 13;
18 |
19 | var TodoApp = React.createClass({
20 | getInitialState: function () {
21 | return {
22 | nowShowing: app.ALL_TODOS,
23 | editing: null,
24 | newTodo: ''
25 | };
26 | },
27 |
28 | componentDidMount: function () {
29 | var setState = this.setState;
30 | var router = Router({
31 | '/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
32 | '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
33 | '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
34 | });
35 | router.init('/');
36 | },
37 |
38 | handleChange: function (event) {
39 | this.setState({newTodo: event.target.value});
40 | },
41 |
42 | handleNewTodoKeyDown: function (event) {
43 | if (event.keyCode !== ENTER_KEY) {
44 | return;
45 | }
46 |
47 | event.preventDefault();
48 |
49 | var val = this.state.newTodo.trim();
50 |
51 | if (val) {
52 | this.props.model.addTodo(val);
53 | this.setState({newTodo: ''});
54 | }
55 | },
56 |
57 | toggleAll: function (event) {
58 | var checked = event.target.checked;
59 | this.props.model.toggleAll(checked);
60 | },
61 |
62 | toggle: function (todoToToggle) {
63 | this.props.model.toggle(todoToToggle);
64 | },
65 |
66 | destroy: function (todo) {
67 | this.props.model.destroy(todo);
68 | },
69 |
70 | edit: function (todo) {
71 | this.setState({editing: todo.id});
72 | },
73 |
74 | save: function (todoToSave, text) {
75 | this.props.model.save(todoToSave, text);
76 | this.setState({editing: null});
77 | },
78 |
79 | cancel: function () {
80 | this.setState({editing: null});
81 | },
82 |
83 | clearCompleted: function () {
84 | this.props.model.clearCompleted();
85 | },
86 |
87 | render: function () {
88 | var footer;
89 | var main;
90 | var todos = this.props.model.todos;
91 |
92 | var shownTodos = todos.filter(function (todo) {
93 | switch (this.state.nowShowing) {
94 | case app.ACTIVE_TODOS:
95 | return !todo.completed;
96 | case app.COMPLETED_TODOS:
97 | return todo.completed;
98 | default:
99 | return true;
100 | }
101 | }, this);
102 |
103 | var todoItems = shownTodos.map(function (todo) {
104 | return (
105 | TodoItem({
106 | key: todo.id,
107 | todo: todo,
108 | onToggle: this.toggle.bind(this, todo),
109 | onDestroy: this.destroy.bind(this, todo),
110 | onEdit: this.edit.bind(this, todo),
111 | editing: this.state.editing === todo.id,
112 | onSave: this.save.bind(this, todo),
113 | onCancel: this.cancel}
114 | )
115 | );
116 | }, this);
117 |
118 | var activeTodoCount = todos.reduce(function (accum, todo) {
119 | return todo.completed ? accum : accum + 1;
120 | }, 0);
121 |
122 | var completedCount = todos.length - activeTodoCount;
123 |
124 | if (activeTodoCount || completedCount) {
125 | footer =
126 | TodoFooter({
127 | count: activeTodoCount,
128 | completedCount: completedCount,
129 | nowShowing: this.state.nowShowing,
130 | onClearCompleted: this.clearCompleted}
131 | );
132 | }
133 |
134 | if (todos.length) {
135 | main = (
136 | React.createElement('section', {className: "main"}, [
137 | React.createElement('input', {
138 | className: "toggle-all",
139 | type: "checkbox",
140 | onChange: this.toggleAll,
141 | checked: activeTodoCount === 0}
142 | ),
143 | React.createElement('ul', {className: "todo-list"}, [
144 | todoItems
145 | ])
146 | ])
147 | );
148 | }
149 |
150 | return (
151 | React.createElement('div', null, [
152 | React.createElement('header', {className: "header"}, [
153 | React.createElement('h1', null, ["todos"]),
154 | React.createElement('input', {
155 | className: "new-todo",
156 | placeholder: "What needs to be done?",
157 | value: this.state.newTodo,
158 | onKeyDown: this.handleNewTodoKeyDown,
159 | onChange: this.handleChange,
160 | autoFocus: true}
161 | )
162 | ]),
163 | main,
164 | footer
165 | ])
166 | );
167 | }
168 | });
169 |
170 | var model = new app.TodoModel('react-todos');
171 |
172 | function render() {
173 | ReactDOM.render(
174 | React.createFactory(TodoApp)({model: model}),
175 | document.getElementsByClassName('todoapp')[0]
176 | );
177 | }
178 |
179 | window.Utils = app.Utils
180 | model.subscribe(render);
181 | render();
182 | })();
183 |
--------------------------------------------------------------------------------
/todomvc/react/js/app.jsx:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React, Router, ReactDOM*/
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.ALL_TODOS = 'all';
12 | app.ACTIVE_TODOS = 'active';
13 | app.COMPLETED_TODOS = 'completed';
14 | var TodoFooter = app.TodoFooter;
15 | var TodoItem = app.TodoItem;
16 |
17 | var ENTER_KEY = 13;
18 |
19 | var TodoApp = React.createClass({
20 | getInitialState: function () {
21 | return {
22 | nowShowing: app.ALL_TODOS,
23 | editing: null,
24 | newTodo: ''
25 | };
26 | },
27 |
28 | componentDidMount: function () {
29 | var setState = this.setState;
30 | var router = Router({
31 | '/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
32 | '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
33 | '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
34 | });
35 | router.init('/');
36 | },
37 |
38 | handleChange: function (event) {
39 | this.setState({newTodo: event.target.value});
40 | },
41 |
42 | handleNewTodoKeyDown: function (event) {
43 | if (event.keyCode !== ENTER_KEY) {
44 | return;
45 | }
46 |
47 | event.preventDefault();
48 |
49 | var val = this.state.newTodo.trim();
50 |
51 | if (val) {
52 | this.props.model.addTodo(val);
53 | this.setState({newTodo: ''});
54 | }
55 | },
56 |
57 | toggleAll: function (event) {
58 | var checked = event.target.checked;
59 | this.props.model.toggleAll(checked);
60 | },
61 |
62 | toggle: function (todoToToggle) {
63 | this.props.model.toggle(todoToToggle);
64 | },
65 |
66 | destroy: function (todo) {
67 | this.props.model.destroy(todo);
68 | },
69 |
70 | edit: function (todo) {
71 | this.setState({editing: todo.id});
72 | },
73 |
74 | save: function (todoToSave, text) {
75 | this.props.model.save(todoToSave, text);
76 | this.setState({editing: null});
77 | },
78 |
79 | cancel: function () {
80 | this.setState({editing: null});
81 | },
82 |
83 | clearCompleted: function () {
84 | this.props.model.clearCompleted();
85 | },
86 |
87 | render: function () {
88 | var footer;
89 | var main;
90 | var todos = this.props.model.todos;
91 |
92 | var shownTodos = todos.filter(function (todo) {
93 | switch (this.state.nowShowing) {
94 | case app.ACTIVE_TODOS:
95 | return !todo.completed;
96 | case app.COMPLETED_TODOS:
97 | return todo.completed;
98 | default:
99 | return true;
100 | }
101 | }, this);
102 |
103 | var todoItems = shownTodos.map(function (todo) {
104 | return (
105 |
115 | );
116 | }, this);
117 |
118 | var activeTodoCount = todos.reduce(function (accum, todo) {
119 | return todo.completed ? accum : accum + 1;
120 | }, 0);
121 |
122 | var completedCount = todos.length - activeTodoCount;
123 |
124 | if (activeTodoCount || completedCount) {
125 | footer =
126 | ;
132 | }
133 |
134 | if (todos.length) {
135 | main = (
136 |
147 | );
148 | }
149 |
150 | return (
151 |
152 |
163 | {main}
164 | {footer}
165 |
166 | );
167 | }
168 | });
169 |
170 | var model = new app.TodoModel('react-todos');
171 |
172 | function render() {
173 | ReactDOM.render(
174 | ,
175 | document.getElementsByClassName('todoapp')[0]
176 | );
177 | }
178 |
179 | model.subscribe(render);
180 | render();
181 | })();
182 |
--------------------------------------------------------------------------------
/todomvc/react/js/footer.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.TodoFooter = React.createClass({
12 | render: function () {
13 | var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');
14 | var clearButton = null;
15 |
16 | if (this.props.completedCount > 0) {
17 | clearButton = (
18 | React.createElement('button', {
19 | className: "clear-completed",
20 | onClick: this.props.onClearCompleted}, [
21 | "Clear completed"
22 | ])
23 | );
24 | }
25 |
26 | var nowShowing = this.props.nowShowing;
27 | return (
28 | React.createElement('footer', {className: "footer"}, [
29 | React.createElement('span', {className: "todo-count"}, [
30 | React.createElement('strong', null, [this.props.count])," ", activeTodoWord, " left"
31 | ]),
32 | React.createElement('ul', {className: "filters"}, [
33 | React.createElement('li', null, [
34 | React.createElement('a', {
35 | href: "#/",
36 | className: classNames({selected: nowShowing === app.ALL_TODOS})}, [
37 | "All"
38 | ])
39 | ]),
40 | ' ',
41 | React.createElement('li', null, [
42 | React.createElement('a', {
43 | href: "#/active",
44 | className: classNames({selected: nowShowing === app.ACTIVE_TODOS})}, [
45 | "Active"
46 | ])
47 | ]),
48 | ' ',
49 | React.createElement('li', null, [
50 | React.createElement('a', {
51 | href: "#/completed",
52 | className: classNames({selected: nowShowing === app.COMPLETED_TODOS})}, [
53 | "Completed"
54 | ])
55 | ])
56 | ]),
57 | clearButton
58 | ])
59 | );
60 | }
61 | });
62 | })();
63 |
--------------------------------------------------------------------------------
/todomvc/react/js/footer.jsx:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | app.TodoFooter = React.createClass({
12 | render: function () {
13 | var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');
14 | var clearButton = null;
15 |
16 | if (this.props.completedCount > 0) {
17 | clearButton = (
18 |
23 | );
24 | }
25 |
26 | var nowShowing = this.props.nowShowing;
27 | return (
28 |
59 | );
60 | }
61 | });
62 | })();
63 |
--------------------------------------------------------------------------------
/todomvc/react/js/todoItem.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark: false */
2 | /*jshint white: false */
3 | /*jshint trailing: false */
4 | /*jshint newcap: false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | var ESCAPE_KEY = 27;
12 | var ENTER_KEY = 13;
13 |
14 | app.TodoItem = React.createClass({
15 | handleSubmit: function (event) {
16 | var val = this.state.editText.trim();
17 | if (val) {
18 | this.props.onSave(val);
19 | this.setState({editText: val});
20 | } else {
21 | this.props.onDestroy();
22 | }
23 | },
24 |
25 | handleEdit: function () {
26 | this.props.onEdit();
27 | this.setState({editText: this.props.todo.title});
28 | },
29 |
30 | handleKeyDown: function (event) {
31 | if (event.which === ESCAPE_KEY) {
32 | this.setState({editText: this.props.todo.title});
33 | this.props.onCancel(event);
34 | } else if (event.which === ENTER_KEY) {
35 | this.handleSubmit(event);
36 | }
37 | },
38 |
39 | handleChange: function (event) {
40 | if (this.props.editing) {
41 | this.setState({editText: event.target.value});
42 | }
43 | },
44 |
45 | getInitialState: function () {
46 | return {editText: this.props.todo.title};
47 | },
48 |
49 | /**
50 | * This is a completely optional performance enhancement that you can
51 | * implement on any React component. If you were to delete this method
52 | * the app would still work correctly (and still be very performant!), we
53 | * just use it as an example of how little code it takes to get an order
54 | * of magnitude performance improvement.
55 | */
56 | shouldComponentUpdate: function (nextProps, nextState) {
57 | return (
58 | nextProps.todo !== this.props.todo ||
59 | nextProps.editing !== this.props.editing ||
60 | nextState.editText !== this.state.editText
61 | );
62 | },
63 |
64 | /**
65 | * Safely manipulate the DOM after updating the state when invoking
66 | * `this.props.onEdit()` in the `handleEdit` method above.
67 | * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate
68 | * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate
69 | */
70 | componentDidUpdate: function (prevProps) {
71 | if (!prevProps.editing && this.props.editing) {
72 | var node = React.findDOMNode(this.refs.editField);
73 | node.focus();
74 | node.setSelectionRange(node.value.length, node.value.length);
75 | }
76 | },
77 |
78 | render: function () {
79 | return (
80 | React.createElement('li', {className: classNames({
81 | completed: this.props.todo.completed,
82 | editing: this.props.editing
83 | })}, [
84 | React.createElement('div', {className: "view"}, [
85 | React.createElement('input', {
86 | className: "toggle",
87 | type: "checkbox",
88 | checked: this.props.todo.completed,
89 | onChange: this.props.onToggle}
90 | ),
91 | React.createElement('label', {onDoubleClick: this.handleEdit}, [
92 | this.props.todo.title
93 | ]),
94 | React.createElement('button', {className: "destroy", onClick: this.props.onDestroy})
95 | ]),
96 | React.createElement('input', {
97 | ref: "editField",
98 | className: "edit",
99 | value: this.state.editText,
100 | onBlur: this.handleSubmit,
101 | onChange: this.handleChange,
102 | onKeyDown: this.handleKeyDown}
103 | )
104 | ])
105 | );
106 | }
107 | });
108 | })();
109 |
--------------------------------------------------------------------------------
/todomvc/react/js/todoItem.jsx:
--------------------------------------------------------------------------------
1 | /*jshint quotmark: false */
2 | /*jshint white: false */
3 | /*jshint trailing: false */
4 | /*jshint newcap: false */
5 | /*global React */
6 | var app = app || {};
7 |
8 | (function () {
9 | 'use strict';
10 |
11 | var ESCAPE_KEY = 27;
12 | var ENTER_KEY = 13;
13 |
14 | app.TodoItem = React.createClass({
15 | handleSubmit: function (event) {
16 | var val = this.state.editText.trim();
17 | if (val) {
18 | this.props.onSave(val);
19 | this.setState({editText: val});
20 | } else {
21 | this.props.onDestroy();
22 | }
23 | },
24 |
25 | handleEdit: function () {
26 | this.props.onEdit();
27 | this.setState({editText: this.props.todo.title});
28 | },
29 |
30 | handleKeyDown: function (event) {
31 | if (event.which === ESCAPE_KEY) {
32 | this.setState({editText: this.props.todo.title});
33 | this.props.onCancel(event);
34 | } else if (event.which === ENTER_KEY) {
35 | this.handleSubmit(event);
36 | }
37 | },
38 |
39 | handleChange: function (event) {
40 | if (this.props.editing) {
41 | this.setState({editText: event.target.value});
42 | }
43 | },
44 |
45 | getInitialState: function () {
46 | return {editText: this.props.todo.title};
47 | },
48 |
49 | /**
50 | * This is a completely optional performance enhancement that you can
51 | * implement on any React component. If you were to delete this method
52 | * the app would still work correctly (and still be very performant!), we
53 | * just use it as an example of how little code it takes to get an order
54 | * of magnitude performance improvement.
55 | */
56 | shouldComponentUpdate: function (nextProps, nextState) {
57 | return (
58 | nextProps.todo !== this.props.todo ||
59 | nextProps.editing !== this.props.editing ||
60 | nextState.editText !== this.state.editText
61 | );
62 | },
63 |
64 | /**
65 | * Safely manipulate the DOM after updating the state when invoking
66 | * `this.props.onEdit()` in the `handleEdit` method above.
67 | * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate
68 | * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate
69 | */
70 | componentDidUpdate: function (prevProps) {
71 | if (!prevProps.editing && this.props.editing) {
72 | var node = React.findDOMNode(this.refs.editField);
73 | node.focus();
74 | node.setSelectionRange(node.value.length, node.value.length);
75 | }
76 | },
77 |
78 | render: function () {
79 | return (
80 |
84 |
85 |
91 |
94 |
95 |
96 |
104 |
105 | );
106 | }
107 | });
108 | })();
109 |
--------------------------------------------------------------------------------
/todomvc/react/js/todoModel.js:
--------------------------------------------------------------------------------
1 | /*jshint quotmark:false */
2 | /*jshint white:false */
3 | /*jshint trailing:false */
4 | /*jshint newcap:false */
5 | var app = app || {};
6 |
7 | (function () {
8 | 'use strict';
9 |
10 | var Utils = app.Utils;
11 | // Generic "model" object. You can use whatever
12 | // framework you want. For this application it
13 | // may not even be worth separating this logic
14 | // out, but we do this to demonstrate one way to
15 | // separate out parts of your application.
16 | app.TodoModel = function (key) {
17 | this.key = key;
18 | this.todos = Utils.store(key);
19 | this.onChanges = [];
20 | };
21 |
22 | app.TodoModel.prototype.subscribe = function (onChange) {
23 | this.onChanges.push(onChange);
24 | };
25 |
26 | app.TodoModel.prototype.inform = function () {
27 | Utils.store(this.key, this.todos);
28 | this.onChanges.forEach(function (cb) { cb(); });
29 | };
30 |
31 | app.TodoModel.prototype.addTodo = function (title) {
32 | this.todos = this.todos.concat({
33 | id: Utils.uuid(),
34 | title: title,
35 | completed: false
36 | });
37 |
38 | this.inform();
39 | };
40 |
41 | app.TodoModel.prototype.toggleAll = function (checked) {
42 | // Note: it's usually better to use immutable data structures since they're
43 | // easier to reason about and React works very well with them. That's why
44 | // we use map() and filter() everywhere instead of mutating the array or
45 | // todo items themselves.
46 | this.todos = this.todos.map(function (todo) {
47 | return Utils.extend({}, todo, {completed: checked});
48 | });
49 |
50 | this.inform();
51 | };
52 |
53 | app.TodoModel.prototype.toggle = function (todoToToggle) {
54 | this.todos = this.todos.map(function (todo) {
55 | return todo !== todoToToggle ?
56 | todo :
57 | Utils.extend({}, todo, {completed: !todo.completed});
58 | });
59 |
60 | this.inform();
61 | };
62 |
63 | app.TodoModel.prototype.destroy = function (todo) {
64 | this.todos = this.todos.filter(function (candidate) {
65 | return candidate !== todo;
66 | });
67 |
68 | this.inform();
69 | };
70 |
71 | app.TodoModel.prototype.save = function (todoToSave, text) {
72 | this.todos = this.todos.map(function (todo) {
73 | return todo !== todoToSave ? todo : Utils.extend({}, todo, {title: text});
74 | });
75 |
76 | this.inform();
77 | };
78 |
79 | app.TodoModel.prototype.clearCompleted = function () {
80 | this.todos = this.todos.filter(function (todo) {
81 | return !todo.completed;
82 | });
83 |
84 | this.inform();
85 | };
86 |
87 | })();
88 |
--------------------------------------------------------------------------------
/todomvc/react/js/utils.js:
--------------------------------------------------------------------------------
1 | var app = app || {};
2 |
3 | (function () {
4 | 'use strict';
5 |
6 | app.Utils = {
7 | uuid: function () {
8 | /*jshint bitwise:false */
9 | var i, random;
10 | var uuid = '';
11 |
12 | for (i = 0; i < 32; i++) {
13 | random = Math.random() * 16 | 0;
14 | if (i === 8 || i === 12 || i === 16 || i === 20) {
15 | uuid += '-';
16 | }
17 | uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random))
18 | .toString(16);
19 | }
20 |
21 | return uuid;
22 | },
23 |
24 | pluralize: function (count, word) {
25 | return count === 1 ? word : word + 's';
26 | },
27 |
28 | store: function (namespace, data) {
29 | if (data) {
30 | return localStorage.setItem(namespace, JSON.stringify(data));
31 | }
32 |
33 | var store = localStorage.getItem(namespace);
34 | return (store && JSON.parse(store)) || [];
35 | },
36 |
37 | extend: function () {
38 | var newObj = {};
39 | for (var i = 0; i < arguments.length; i++) {
40 | var obj = arguments[i];
41 | for (var key in obj) {
42 | if (obj.hasOwnProperty(key)) {
43 | newObj[key] = obj[key];
44 | }
45 | }
46 | }
47 | return newObj;
48 | }
49 | };
50 | })();
51 |
--------------------------------------------------------------------------------
/todomvc/react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "dependencies": {
4 | "classnames": "^2.1.5",
5 | "director": "^1.2.0",
6 | "react": "^15.0.0",
7 | "react-dom": "^15.0.2",
8 | "todomvc-app-css": "^2.0.0",
9 | "todomvc-common": "^1.0.1"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/todomvc/react/readme.md:
--------------------------------------------------------------------------------
1 | # React TodoMVC Example
2 |
3 | > React is a JavaScript library for creating user interfaces. Its core principles are declarative code, efficiency, and flexibility. Simply specify what your component looks like and React will keep it up-to-date when the underlying data changes.
4 |
5 | > _[React - facebook.github.io/react](http://facebook.github.io/react)_
6 |
7 |
8 | ## Learning React
9 |
10 | The [React getting started documentation](http://facebook.github.io/react/docs/getting-started.html) is a great way to get started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Documentation](http://facebook.github.io/react/docs/getting-started.html)
15 | * [API Reference](http://facebook.github.io/react/docs/reference.html)
16 | * [Blog](http://facebook.github.io/react/blog/)
17 | * [React on GitHub](https://github.com/facebook/react)
18 | * [Support](http://facebook.github.io/react/support.html)
19 |
20 | Articles and guides from the community:
21 |
22 | * [How is Facebook's React JavaScript library](http://www.quora.com/React-JS-Library/How-is-Facebooks-React-JavaScript-library)
23 | * [React: Under the hood](http://www.quora.com/Pete-Hunt/Posts/React-Under-the-Hood)
24 |
25 | Get help from other React users:
26 |
27 | * [React on StackOverflow](http://stackoverflow.com/questions/tagged/reactjs)
28 | * [Discussion Forum](https://discuss.reactjs.org/)
29 |
30 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
31 |
32 |
33 | ## Running
34 |
35 | The app is built with [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) and compiled at runtime for a lighter and more fun code reading experience. As stated in the link, JSX is not mandatory.
36 |
37 | To run the app, spin up an HTTP server (e.g. `python -m SimpleHTTPServer`) and visit http://localhost/.../myexample/.
38 |
--------------------------------------------------------------------------------
/todomvc/react/todomvc-app-css/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | font-weight: inherit;
16 | color: inherit;
17 | -webkit-appearance: none;
18 | appearance: none;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | }
22 |
23 | body {
24 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
25 | line-height: 1.4em;
26 | background: #f5f5f5;
27 | color: #4d4d4d;
28 | min-width: 230px;
29 | max-width: 550px;
30 | margin: 0 auto;
31 | -webkit-font-smoothing: antialiased;
32 | -moz-osx-font-smoothing: grayscale;
33 | font-weight: 300;
34 | }
35 |
36 | button,
37 | input[type="checkbox"] {
38 | outline: none;
39 | }
40 |
41 | .hidden {
42 | display: none;
43 | }
44 |
45 | .todoapp {
46 | background: #fff;
47 | margin: 130px 0 40px 0;
48 | position: relative;
49 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
50 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
51 | }
52 |
53 | .todoapp input::-webkit-input-placeholder {
54 | font-style: italic;
55 | font-weight: 300;
56 | color: #e6e6e6;
57 | }
58 |
59 | .todoapp input::-moz-placeholder {
60 | font-style: italic;
61 | font-weight: 300;
62 | color: #e6e6e6;
63 | }
64 |
65 | .todoapp input::input-placeholder {
66 | font-style: italic;
67 | font-weight: 300;
68 | color: #e6e6e6;
69 | }
70 |
71 | .todoapp h1 {
72 | position: absolute;
73 | top: -155px;
74 | width: 100%;
75 | font-size: 100px;
76 | font-weight: 100;
77 | text-align: center;
78 | color: rgba(175, 47, 47, 0.15);
79 | -webkit-text-rendering: optimizeLegibility;
80 | -moz-text-rendering: optimizeLegibility;
81 | text-rendering: optimizeLegibility;
82 | }
83 |
84 | .new-todo,
85 | .edit {
86 | position: relative;
87 | margin: 0;
88 | width: 100%;
89 | font-size: 24px;
90 | font-family: inherit;
91 | font-weight: inherit;
92 | line-height: 1.4em;
93 | border: 0;
94 | outline: none;
95 | color: inherit;
96 | padding: 6px;
97 | border: 1px solid #999;
98 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
99 | box-sizing: border-box;
100 | -webkit-font-smoothing: antialiased;
101 | -moz-osx-font-smoothing: grayscale;
102 | }
103 |
104 | .new-todo {
105 | padding: 16px 16px 16px 60px;
106 | border: none;
107 | background: rgba(0, 0, 0, 0.003);
108 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
109 | }
110 |
111 | .main {
112 | position: relative;
113 | z-index: 2;
114 | border-top: 1px solid #e6e6e6;
115 | }
116 |
117 | label[for='toggle-all'] {
118 | display: none;
119 | }
120 |
121 | .toggle-all {
122 | position: absolute;
123 | top: -55px;
124 | left: -12px;
125 | width: 60px;
126 | height: 34px;
127 | text-align: center;
128 | border: none; /* Mobile Safari */
129 | }
130 |
131 | .toggle-all:before {
132 | content: '❯';
133 | font-size: 22px;
134 | color: #e6e6e6;
135 | padding: 10px 27px 10px 27px;
136 | }
137 |
138 | .toggle-all:checked:before {
139 | color: #737373;
140 | }
141 |
142 | .todo-list {
143 | margin: 0;
144 | padding: 0;
145 | list-style: none;
146 | }
147 |
148 | .todo-list li {
149 | position: relative;
150 | font-size: 24px;
151 | border-bottom: 1px solid #ededed;
152 | }
153 |
154 | .todo-list li:last-child {
155 | border-bottom: none;
156 | }
157 |
158 | .todo-list li.editing {
159 | border-bottom: none;
160 | padding: 0;
161 | }
162 |
163 | .todo-list li.editing .edit {
164 | display: block;
165 | width: 506px;
166 | padding: 13px 17px 12px 17px;
167 | margin: 0 0 0 43px;
168 | }
169 |
170 | .todo-list li.editing .view {
171 | display: none;
172 | }
173 |
174 | .todo-list li .toggle {
175 | text-align: center;
176 | width: 40px;
177 | /* auto, since non-WebKit browsers doesn't support input styling */
178 | height: auto;
179 | position: absolute;
180 | top: 0;
181 | bottom: 0;
182 | margin: auto 0;
183 | border: none; /* Mobile Safari */
184 | -webkit-appearance: none;
185 | appearance: none;
186 | }
187 |
188 | .todo-list li .toggle:after {
189 | content: url('data:image/svg+xml;utf8,');
190 | }
191 |
192 | .todo-list li .toggle:checked:after {
193 | content: url('data:image/svg+xml;utf8,');
194 | }
195 |
196 | .todo-list li label {
197 | white-space: pre-line;
198 | word-break: break-all;
199 | padding: 15px 60px 15px 15px;
200 | margin-left: 45px;
201 | display: block;
202 | line-height: 1.2;
203 | transition: color 0.4s;
204 | }
205 |
206 | .todo-list li.completed label {
207 | color: #d9d9d9;
208 | text-decoration: line-through;
209 | }
210 |
211 | .todo-list li .destroy {
212 | display: none;
213 | position: absolute;
214 | top: 0;
215 | right: 10px;
216 | bottom: 0;
217 | width: 40px;
218 | height: 40px;
219 | margin: auto 0;
220 | font-size: 30px;
221 | color: #cc9a9a;
222 | margin-bottom: 11px;
223 | transition: color 0.2s ease-out;
224 | }
225 |
226 | .todo-list li .destroy:hover {
227 | color: #af5b5e;
228 | }
229 |
230 | .todo-list li .destroy:after {
231 | content: '×';
232 | }
233 |
234 | .todo-list li:hover .destroy {
235 | display: block;
236 | }
237 |
238 | .todo-list li .edit {
239 | display: none;
240 | }
241 |
242 | .todo-list li.editing:last-child {
243 | margin-bottom: -1px;
244 | }
245 |
246 | .footer {
247 | color: #777;
248 | padding: 10px 15px;
249 | height: 20px;
250 | text-align: center;
251 | border-top: 1px solid #e6e6e6;
252 | }
253 |
254 | .footer:before {
255 | content: '';
256 | position: absolute;
257 | right: 0;
258 | bottom: 0;
259 | left: 0;
260 | height: 50px;
261 | overflow: hidden;
262 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
263 | 0 8px 0 -3px #f6f6f6,
264 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
265 | 0 16px 0 -6px #f6f6f6,
266 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
267 | }
268 |
269 | .todo-count {
270 | float: left;
271 | text-align: left;
272 | }
273 |
274 | .todo-count strong {
275 | font-weight: 300;
276 | }
277 |
278 | .filters {
279 | margin: 0;
280 | padding: 0;
281 | list-style: none;
282 | position: absolute;
283 | right: 0;
284 | left: 0;
285 | }
286 |
287 | .filters li {
288 | display: inline;
289 | }
290 |
291 | .filters li a {
292 | color: inherit;
293 | margin: 3px;
294 | padding: 3px 7px;
295 | text-decoration: none;
296 | border: 1px solid transparent;
297 | border-radius: 3px;
298 | }
299 |
300 | .filters li a.selected,
301 | .filters li a:hover {
302 | border-color: rgba(175, 47, 47, 0.1);
303 | }
304 |
305 | .filters li a.selected {
306 | border-color: rgba(175, 47, 47, 0.2);
307 | }
308 |
309 | .clear-completed,
310 | html .clear-completed:active {
311 | float: right;
312 | position: relative;
313 | line-height: 20px;
314 | text-decoration: none;
315 | cursor: pointer;
316 | }
317 |
318 | .clear-completed:hover {
319 | text-decoration: underline;
320 | }
321 |
322 | .info {
323 | margin: 65px auto 0;
324 | color: #bfbfbf;
325 | font-size: 10px;
326 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
327 | text-align: center;
328 | }
329 |
330 | .info p {
331 | line-height: 1;
332 | }
333 |
334 | .info a {
335 | color: inherit;
336 | text-decoration: none;
337 | font-weight: 400;
338 | }
339 |
340 | .info a:hover {
341 | text-decoration: underline;
342 | }
343 |
344 | /*
345 | Hack to remove background from Mobile Safari.
346 | Can't use it globally since it destroys checkboxes in Firefox
347 | */
348 | @media screen and (-webkit-min-device-pixel-ratio:0) {
349 | .toggle-all,
350 | .todo-list li .toggle {
351 | background: none;
352 | }
353 |
354 | .todo-list li .toggle {
355 | height: 40px;
356 | }
357 |
358 | .toggle-all {
359 | -webkit-transform: rotate(90deg);
360 | transform: rotate(90deg);
361 | -webkit-appearance: none;
362 | appearance: none;
363 | }
364 | }
365 |
366 | @media (max-width: 430px) {
367 | .footer {
368 | height: 50px;
369 | }
370 |
371 | .filters {
372 | bottom: 10px;
373 | }
374 | }
375 |
--------------------------------------------------------------------------------
/todomvc/react/todomvc-app-css/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_args": [
3 | [
4 | "todomvc-app-css@^2.0.0",
5 | "/Users/lorenzo/Projects/todomvc-perf-comparison/todomvc/react"
6 | ]
7 | ],
8 | "_from": "todomvc-app-css@>=2.0.0 <3.0.0",
9 | "_id": "todomvc-app-css@2.0.4",
10 | "_inCache": true,
11 | "_installable": true,
12 | "_location": "/todomvc-app-css",
13 | "_nodeVersion": "4.2.4",
14 | "_npmUser": {
15 | "email": "sindresorhus@gmail.com",
16 | "name": "sindresorhus"
17 | },
18 | "_npmVersion": "2.14.12",
19 | "_phantomChildren": {},
20 | "_requested": {
21 | "name": "todomvc-app-css",
22 | "raw": "todomvc-app-css@^2.0.0",
23 | "rawSpec": "^2.0.0",
24 | "scope": null,
25 | "spec": ">=2.0.0 <3.0.0",
26 | "type": "range"
27 | },
28 | "_requiredBy": [
29 | "/"
30 | ],
31 | "_resolved": "https://registry.npmjs.org/todomvc-app-css/-/todomvc-app-css-2.0.4.tgz",
32 | "_shasum": "a1b62664d1e3ade62140b6c40a5bb92adea0f0ff",
33 | "_shrinkwrap": null,
34 | "_spec": "todomvc-app-css@^2.0.0",
35 | "_where": "/Users/lorenzo/Projects/todomvc-perf-comparison/todomvc/react",
36 | "author": {
37 | "email": "sindresorhus@gmail.com",
38 | "name": "Sindre Sorhus",
39 | "url": "sindresorhus.com"
40 | },
41 | "bugs": {
42 | "url": "https://github.com/tastejs/todomvc-app-css/issues"
43 | },
44 | "dependencies": {},
45 | "description": "CSS for TodoMVC apps",
46 | "devDependencies": {},
47 | "directories": {},
48 | "dist": {
49 | "shasum": "a1b62664d1e3ade62140b6c40a5bb92adea0f0ff",
50 | "tarball": "https://registry.npmjs.org/todomvc-app-css/-/todomvc-app-css-2.0.4.tgz"
51 | },
52 | "files": [
53 | "index.css"
54 | ],
55 | "gitHead": "47337a0da5727cbca2672c3055411405bd43bde4",
56 | "homepage": "https://github.com/tastejs/todomvc-app-css",
57 | "keywords": [
58 | "app",
59 | "css",
60 | "style",
61 | "stylesheet",
62 | "tastejs",
63 | "template",
64 | "todo",
65 | "todomvc"
66 | ],
67 | "license": "CC-BY-4.0",
68 | "maintainers": [
69 | {
70 | "name": "sindresorhus",
71 | "email": "sindresorhus@gmail.com"
72 | },
73 | {
74 | "name": "addyosmani",
75 | "email": "addyosmani@gmail.com"
76 | },
77 | {
78 | "name": "passy",
79 | "email": "phartig@rdrei.net"
80 | },
81 | {
82 | "name": "stephenplusplus",
83 | "email": "sawchuk@gmail.com"
84 | }
85 | ],
86 | "name": "todomvc-app-css",
87 | "optionalDependencies": {},
88 | "readme": "ERROR: No README data found!",
89 | "repository": {
90 | "type": "git",
91 | "url": "git+https://github.com/tastejs/todomvc-app-css.git"
92 | },
93 | "scripts": {},
94 | "style": "index.css",
95 | "version": "2.0.4"
96 | }
97 |
--------------------------------------------------------------------------------
/todomvc/react/todomvc-app-css/readme.md:
--------------------------------------------------------------------------------
1 | # todomvc-app-css
2 |
3 | > CSS for TodoMVC apps
4 |
5 | 
6 |
7 |
8 | ## Install
9 |
10 |
11 | ```
12 | $ npm install --save todomvc-app-css
13 | ```
14 |
15 |
16 | ## Getting started
17 |
18 | ```html
19 |
20 | ```
21 |
22 | See the [TodoMVC app template](https://github.com/tastejs/todomvc-app-template).
23 |
24 |
25 |
26 | ## License
27 |
28 | 
This work by Sindre Sorhus is licensed under a Creative Commons Attribution 4.0 International License.
29 |
--------------------------------------------------------------------------------
/todomvc/react/todomvc-common/base.css:
--------------------------------------------------------------------------------
1 | hr {
2 | margin: 20px 0;
3 | border: 0;
4 | border-top: 1px dashed #c5c5c5;
5 | border-bottom: 1px dashed #f7f7f7;
6 | }
7 |
8 | .learn a {
9 | font-weight: normal;
10 | text-decoration: none;
11 | color: #b83f45;
12 | }
13 |
14 | .learn a:hover {
15 | text-decoration: underline;
16 | color: #787e7e;
17 | }
18 |
19 | .learn h3,
20 | .learn h4,
21 | .learn h5 {
22 | margin: 10px 0;
23 | font-weight: 500;
24 | line-height: 1.2;
25 | color: #000;
26 | }
27 |
28 | .learn h3 {
29 | font-size: 24px;
30 | }
31 |
32 | .learn h4 {
33 | font-size: 18px;
34 | }
35 |
36 | .learn h5 {
37 | margin-bottom: 0;
38 | font-size: 14px;
39 | }
40 |
41 | .learn ul {
42 | padding: 0;
43 | margin: 0 0 30px 25px;
44 | }
45 |
46 | .learn li {
47 | line-height: 20px;
48 | }
49 |
50 | .learn p {
51 | font-size: 15px;
52 | font-weight: 300;
53 | line-height: 1.3;
54 | margin-top: 0;
55 | margin-bottom: 0;
56 | }
57 |
58 | #issue-count {
59 | display: none;
60 | }
61 |
62 | .quote {
63 | border: none;
64 | margin: 20px 0 60px 0;
65 | }
66 |
67 | .quote p {
68 | font-style: italic;
69 | }
70 |
71 | .quote p:before {
72 | content: '“';
73 | font-size: 50px;
74 | opacity: .15;
75 | position: absolute;
76 | top: -20px;
77 | left: 3px;
78 | }
79 |
80 | .quote p:after {
81 | content: '”';
82 | font-size: 50px;
83 | opacity: .15;
84 | position: absolute;
85 | bottom: -42px;
86 | right: 3px;
87 | }
88 |
89 | .quote footer {
90 | position: absolute;
91 | bottom: -40px;
92 | right: 0;
93 | }
94 |
95 | .quote footer img {
96 | border-radius: 3px;
97 | }
98 |
99 | .quote footer a {
100 | margin-left: 5px;
101 | vertical-align: middle;
102 | }
103 |
104 | .speech-bubble {
105 | position: relative;
106 | padding: 10px;
107 | background: rgba(0, 0, 0, .04);
108 | border-radius: 5px;
109 | }
110 |
111 | .speech-bubble:after {
112 | content: '';
113 | position: absolute;
114 | top: 100%;
115 | right: 30px;
116 | border: 13px solid transparent;
117 | border-top-color: rgba(0, 0, 0, .04);
118 | }
119 |
120 | .learn-bar > .learn {
121 | position: absolute;
122 | width: 272px;
123 | top: 8px;
124 | left: -300px;
125 | padding: 10px;
126 | border-radius: 5px;
127 | background-color: rgba(255, 255, 255, .6);
128 | transition-property: left;
129 | transition-duration: 500ms;
130 | }
131 |
132 | @media (min-width: 899px) {
133 | .learn-bar {
134 | width: auto;
135 | padding-left: 300px;
136 | }
137 |
138 | .learn-bar > .learn {
139 | left: 8px;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/todomvc/react/todomvc-common/base.js:
--------------------------------------------------------------------------------
1 | /* global _ */
2 | (function () {
3 | 'use strict';
4 |
5 | /* jshint ignore:start */
6 | // Underscore's Template Module
7 | // Courtesy of underscorejs.org
8 | var _ = (function (_) {
9 | _.defaults = function (object) {
10 | if (!object) {
11 | return object;
12 | }
13 | for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
14 | var iterable = arguments[argsIndex];
15 | if (iterable) {
16 | for (var key in iterable) {
17 | if (object[key] == null) {
18 | object[key] = iterable[key];
19 | }
20 | }
21 | }
22 | }
23 | return object;
24 | }
25 |
26 | // By default, Underscore uses ERB-style template delimiters, change the
27 | // following template settings to use alternative delimiters.
28 | _.templateSettings = {
29 | evaluate : /<%([\s\S]+?)%>/g,
30 | interpolate : /<%=([\s\S]+?)%>/g,
31 | escape : /<%-([\s\S]+?)%>/g
32 | };
33 |
34 | // When customizing `templateSettings`, if you don't want to define an
35 | // interpolation, evaluation or escaping regex, we need one that is
36 | // guaranteed not to match.
37 | var noMatch = /(.)^/;
38 |
39 | // Certain characters need to be escaped so that they can be put into a
40 | // string literal.
41 | var escapes = {
42 | "'": "'",
43 | '\\': '\\',
44 | '\r': 'r',
45 | '\n': 'n',
46 | '\t': 't',
47 | '\u2028': 'u2028',
48 | '\u2029': 'u2029'
49 | };
50 |
51 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
52 |
53 | // JavaScript micro-templating, similar to John Resig's implementation.
54 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
55 | // and correctly escapes quotes within interpolated code.
56 | _.template = function(text, data, settings) {
57 | var render;
58 | settings = _.defaults({}, settings, _.templateSettings);
59 |
60 | // Combine delimiters into one regular expression via alternation.
61 | var matcher = new RegExp([
62 | (settings.escape || noMatch).source,
63 | (settings.interpolate || noMatch).source,
64 | (settings.evaluate || noMatch).source
65 | ].join('|') + '|$', 'g');
66 |
67 | // Compile the template source, escaping string literals appropriately.
68 | var index = 0;
69 | var source = "__p+='";
70 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
71 | source += text.slice(index, offset)
72 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
73 |
74 | if (escape) {
75 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
76 | }
77 | if (interpolate) {
78 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
79 | }
80 | if (evaluate) {
81 | source += "';\n" + evaluate + "\n__p+='";
82 | }
83 | index = offset + match.length;
84 | return match;
85 | });
86 | source += "';\n";
87 |
88 | // If a variable is not specified, place data values in local scope.
89 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
90 |
91 | source = "var __t,__p='',__j=Array.prototype.join," +
92 | "print=function(){__p+=__j.call(arguments,'');};\n" +
93 | source + "return __p;\n";
94 |
95 | try {
96 | render = new Function(settings.variable || 'obj', '_', source);
97 | } catch (e) {
98 | e.source = source;
99 | throw e;
100 | }
101 |
102 | if (data) return render(data, _);
103 | var template = function(data) {
104 | return render.call(this, data, _);
105 | };
106 |
107 | // Provide the compiled function source as a convenience for precompilation.
108 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
109 |
110 | return template;
111 | };
112 |
113 | return _;
114 | })({});
115 |
116 | if (location.hostname === 'todomvc.com') {
117 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
118 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
119 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
120 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
121 | ga('create', 'UA-31081062-1', 'auto');
122 | ga('send', 'pageview');
123 | }
124 | /* jshint ignore:end */
125 |
126 | function redirect() {
127 | if (location.hostname === 'tastejs.github.io') {
128 | location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
129 | }
130 | }
131 |
132 | function findRoot() {
133 | var base = location.href.indexOf('examples/');
134 | return location.href.substr(0, base);
135 | }
136 |
137 | function getFile(file, callback) {
138 | if (!location.host) {
139 | return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
140 | }
141 |
142 | var xhr = new XMLHttpRequest();
143 |
144 | xhr.open('GET', findRoot() + file, true);
145 | xhr.send();
146 |
147 | xhr.onload = function () {
148 | if (xhr.status === 200 && callback) {
149 | callback(xhr.responseText);
150 | }
151 | };
152 | }
153 |
154 | function Learn(learnJSON, config) {
155 | if (!(this instanceof Learn)) {
156 | return new Learn(learnJSON, config);
157 | }
158 |
159 | var template, framework;
160 |
161 | if (typeof learnJSON !== 'object') {
162 | try {
163 | learnJSON = JSON.parse(learnJSON);
164 | } catch (e) {
165 | return;
166 | }
167 | }
168 |
169 | if (config) {
170 | template = config.template;
171 | framework = config.framework;
172 | }
173 |
174 | if (!template && learnJSON.templates) {
175 | template = learnJSON.templates.todomvc;
176 | }
177 |
178 | if (!framework && document.querySelector('[data-framework]')) {
179 | framework = document.querySelector('[data-framework]').dataset.framework;
180 | }
181 |
182 | this.template = template;
183 |
184 | if (learnJSON.backend) {
185 | this.frameworkJSON = learnJSON.backend;
186 | this.frameworkJSON.issueLabel = framework;
187 | this.append({
188 | backend: true
189 | });
190 | } else if (learnJSON[framework]) {
191 | this.frameworkJSON = learnJSON[framework];
192 | this.frameworkJSON.issueLabel = framework;
193 | this.append();
194 | }
195 |
196 | this.fetchIssueCount();
197 | }
198 |
199 | Learn.prototype.append = function (opts) {
200 | var aside = document.createElement('aside');
201 | aside.innerHTML = _.template(this.template, this.frameworkJSON);
202 | aside.className = 'learn';
203 |
204 | if (opts && opts.backend) {
205 | // Remove demo link
206 | var sourceLinks = aside.querySelector('.source-links');
207 | var heading = sourceLinks.firstElementChild;
208 | var sourceLink = sourceLinks.lastElementChild;
209 | // Correct link path
210 | var href = sourceLink.getAttribute('href');
211 | sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
212 | sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
213 | } else {
214 | // Localize demo links
215 | var demoLinks = aside.querySelectorAll('.demo-link');
216 | Array.prototype.forEach.call(demoLinks, function (demoLink) {
217 | if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
218 | demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
219 | }
220 | });
221 | }
222 |
223 | document.body.className = (document.body.className + ' learn-bar').trim();
224 | document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
225 | };
226 |
227 | Learn.prototype.fetchIssueCount = function () {
228 | var issueLink = document.getElementById('issue-count-link');
229 | if (issueLink) {
230 | var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
231 | var xhr = new XMLHttpRequest();
232 | xhr.open('GET', url, true);
233 | xhr.onload = function (e) {
234 | var parsedResponse = JSON.parse(e.target.responseText);
235 | if (parsedResponse instanceof Array) {
236 | var count = parsedResponse.length;
237 | if (count !== 0) {
238 | issueLink.innerHTML = 'This app has ' + count + ' open issues';
239 | document.getElementById('issue-count').style.display = 'inline';
240 | }
241 | }
242 | };
243 | xhr.send();
244 | }
245 | };
246 |
247 | redirect();
248 | // getFile('learn.json', Learn);
249 | })();
250 |
--------------------------------------------------------------------------------
/todomvc/sauron/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Sauron • TodoMVC
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/todomvc/sauron/pkg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc",
3 | "collaborators": [
4 | "Jovansonlee Cesar "
5 | ],
6 | "version": "0.1.0",
7 | "license": "MIT",
8 | "files": [
9 | "todomvc_bg.wasm",
10 | "todomvc.js",
11 | "todomvc.d.ts"
12 | ],
13 | "browser": "todomvc.js",
14 | "types": "todomvc.d.ts"
15 | }
--------------------------------------------------------------------------------
/todomvc/sauron/pkg/todomvc.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /**
3 | */
4 | export function main(): void;
5 |
6 | /**
7 | * If `module_or_path` is {RequestInfo}, makes a request and
8 | * for everything else, calls `WebAssembly.instantiate` directly.
9 | *
10 | * @param {RequestInfo | BufferSource | WebAssembly.Module} module_or_path
11 | *
12 | * @returns {Promise}
13 | */
14 | export default function init (module_or_path: RequestInfo | BufferSource | WebAssembly.Module): Promise;
15 |
--------------------------------------------------------------------------------
/todomvc/sauron/pkg/todomvc_bg.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | export const memory: WebAssembly.Memory;
3 | export function main(): void;
4 | export function __wbindgen_exn_store(a: number): void;
5 | export function __wbindgen_malloc(a: number): number;
6 | export function __wbindgen_realloc(a: number, b: number, c: number): number;
7 | export function __wbindgen_free(a: number, b: number): void;
8 | export const __wbg_function_table: WebAssembly.Table;
9 | export function __wbindgen_start(): void;
10 |
--------------------------------------------------------------------------------
/todomvc/sauron/pkg/todomvc_bg.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/sauron/pkg/todomvc_bg.wasm
--------------------------------------------------------------------------------
/todomvc/sauron/style.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | font-weight: inherit;
16 | color: inherit;
17 | -webkit-appearance: none;
18 | appearance: none;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | }
22 |
23 | body {
24 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
25 | line-height: 1.4em;
26 | background: #f5f5f5;
27 | color: #4d4d4d;
28 | min-width: 230px;
29 | max-width: 550px;
30 | margin: 0 auto;
31 | -webkit-font-smoothing: antialiased;
32 | -moz-osx-font-smoothing: grayscale;
33 | font-weight: 300;
34 | }
35 |
36 | :focus {
37 | outline: 0;
38 | }
39 |
40 | .hidden {
41 | display: none;
42 | }
43 |
44 | .todoapp {
45 | background: #fff;
46 | margin: 130px 0 40px 0;
47 | position: relative;
48 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
49 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
50 | }
51 |
52 | .todoapp input::-webkit-input-placeholder {
53 | font-style: italic;
54 | font-weight: 300;
55 | color: #e6e6e6;
56 | }
57 |
58 | .todoapp input::-moz-placeholder {
59 | font-style: italic;
60 | font-weight: 300;
61 | color: #e6e6e6;
62 | }
63 |
64 | .todoapp input::input-placeholder {
65 | font-style: italic;
66 | font-weight: 300;
67 | color: #e6e6e6;
68 | }
69 |
70 | .todoapp h1 {
71 | position: absolute;
72 | top: -155px;
73 | width: 100%;
74 | font-size: 100px;
75 | font-weight: 100;
76 | text-align: center;
77 | color: rgba(175, 47, 47, 0.15);
78 | -webkit-text-rendering: optimizeLegibility;
79 | -moz-text-rendering: optimizeLegibility;
80 | text-rendering: optimizeLegibility;
81 | }
82 |
83 | .new-todo,
84 | .edit {
85 | position: relative;
86 | margin: 0;
87 | width: 100%;
88 | font-size: 24px;
89 | font-family: inherit;
90 | font-weight: inherit;
91 | line-height: 1.4em;
92 | border: 0;
93 | color: inherit;
94 | padding: 6px;
95 | border: 1px solid #999;
96 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
97 | box-sizing: border-box;
98 | -webkit-font-smoothing: antialiased;
99 | -moz-osx-font-smoothing: grayscale;
100 | }
101 |
102 | .new-todo {
103 | padding: 16px 16px 16px 60px;
104 | border: none;
105 | background: rgba(0, 0, 0, 0.003);
106 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
107 | }
108 |
109 | .main {
110 | position: relative;
111 | z-index: 2;
112 | border-top: 1px solid #e6e6e6;
113 | }
114 |
115 | .toggle-all {
116 | width: 1px;
117 | height: 1px;
118 | border: none; /* Mobile Safari */
119 | opacity: 0;
120 | position: absolute;
121 | right: 100%;
122 | bottom: 100%;
123 | }
124 |
125 | .toggle-all + label {
126 | width: 60px;
127 | height: 34px;
128 | font-size: 0;
129 | position: absolute;
130 | top: -52px;
131 | left: -13px;
132 | -webkit-transform: rotate(90deg);
133 | transform: rotate(90deg);
134 | }
135 |
136 | .toggle-all + label:before {
137 | content: '❯';
138 | font-size: 22px;
139 | color: #e6e6e6;
140 | padding: 10px 27px 10px 27px;
141 | }
142 |
143 | .toggle-all:checked + label:before {
144 | color: #737373;
145 | }
146 |
147 | .todo-list {
148 | margin: 0;
149 | padding: 0;
150 | list-style: none;
151 | }
152 |
153 | .todo-list li {
154 | position: relative;
155 | font-size: 24px;
156 | border-bottom: 1px solid #ededed;
157 | }
158 |
159 | .todo-list li:last-child {
160 | border-bottom: none;
161 | }
162 |
163 | .todo-list li.editing {
164 | border-bottom: none;
165 | padding: 0;
166 | }
167 |
168 | .todo-list li.editing .edit {
169 | display: block;
170 | width: 506px;
171 | padding: 12px 16px;
172 | margin: 0 0 0 43px;
173 | }
174 |
175 | .todo-list li.editing .view {
176 | display: none;
177 | }
178 |
179 | .todo-list li .toggle {
180 | text-align: center;
181 | width: 40px;
182 | /* auto, since non-WebKit browsers doesn't support input styling */
183 | height: auto;
184 | position: absolute;
185 | top: 0;
186 | bottom: 0;
187 | margin: auto 0;
188 | border: none; /* Mobile Safari */
189 | -webkit-appearance: none;
190 | appearance: none;
191 | }
192 |
193 | .todo-list li .toggle {
194 | opacity: 0;
195 | }
196 |
197 | .todo-list li .toggle + label {
198 | /*
199 | Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
200 | 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/
201 | */
202 | 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');
203 | background-repeat: no-repeat;
204 | background-position: center left;
205 | }
206 |
207 | .todo-list li .toggle:checked + label {
208 | 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');
209 | }
210 |
211 | .todo-list li label {
212 | word-break: break-all;
213 | padding: 15px 15px 15px 60px;
214 | display: block;
215 | line-height: 1.2;
216 | transition: color 0.4s;
217 | }
218 |
219 | .todo-list li.completed label {
220 | color: #d9d9d9;
221 | text-decoration: line-through;
222 | }
223 |
224 | .todo-list li .destroy {
225 | display: none;
226 | position: absolute;
227 | top: 0;
228 | right: 10px;
229 | bottom: 0;
230 | width: 40px;
231 | height: 40px;
232 | margin: auto 0;
233 | font-size: 30px;
234 | color: #cc9a9a;
235 | margin-bottom: 11px;
236 | transition: color 0.2s ease-out;
237 | }
238 |
239 | .todo-list li .destroy:hover {
240 | color: #af5b5e;
241 | }
242 |
243 | .todo-list li .destroy:after {
244 | content: '×';
245 | }
246 |
247 | .todo-list li:hover .destroy {
248 | display: block;
249 | }
250 |
251 | .todo-list li .edit {
252 | display: none;
253 | }
254 |
255 | .todo-list li.editing:last-child {
256 | margin-bottom: -1px;
257 | }
258 |
259 | .footer {
260 | color: #777;
261 | padding: 10px 15px;
262 | height: 20px;
263 | text-align: center;
264 | border-top: 1px solid #e6e6e6;
265 | }
266 |
267 | .footer:before {
268 | content: '';
269 | position: absolute;
270 | right: 0;
271 | bottom: 0;
272 | left: 0;
273 | height: 50px;
274 | overflow: hidden;
275 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
276 | 0 8px 0 -3px #f6f6f6,
277 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
278 | 0 16px 0 -6px #f6f6f6,
279 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
280 | }
281 |
282 | .todo-count {
283 | float: left;
284 | text-align: left;
285 | }
286 |
287 | .todo-count strong {
288 | font-weight: 300;
289 | }
290 |
291 | .filters {
292 | margin: 0;
293 | padding: 0;
294 | list-style: none;
295 | position: absolute;
296 | right: 0;
297 | left: 0;
298 | }
299 |
300 | .filters li {
301 | display: inline;
302 | }
303 |
304 | .filters li a {
305 | color: inherit;
306 | margin: 3px;
307 | padding: 3px 7px;
308 | text-decoration: none;
309 | border: 1px solid transparent;
310 | border-radius: 3px;
311 | }
312 |
313 | .filters li a:hover {
314 | border-color: rgba(175, 47, 47, 0.1);
315 | }
316 |
317 | .filters li a.selected {
318 | border-color: rgba(175, 47, 47, 0.2);
319 | }
320 |
321 | .clear-completed,
322 | html .clear-completed:active {
323 | float: right;
324 | position: relative;
325 | line-height: 20px;
326 | text-decoration: none;
327 | cursor: pointer;
328 | }
329 |
330 | .clear-completed:hover {
331 | text-decoration: underline;
332 | }
333 |
334 | .info {
335 | margin: 65px auto 0;
336 | color: #bfbfbf;
337 | font-size: 10px;
338 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
339 | text-align: center;
340 | }
341 |
342 | .info p {
343 | line-height: 1;
344 | }
345 |
346 | .info a {
347 | color: inherit;
348 | text-decoration: none;
349 | font-weight: 400;
350 | }
351 |
352 | .info a:hover {
353 | text-decoration: underline;
354 | }
355 |
356 | /*
357 | Hack to remove background from Mobile Safari.
358 | Can't use it globally since it destroys checkboxes in Firefox
359 | */
360 | @media screen and (-webkit-min-device-pixel-ratio:0) {
361 | .toggle-all,
362 | .todo-list li .toggle {
363 | background: none;
364 | }
365 |
366 | .todo-list li .toggle {
367 | height: 40px;
368 | }
369 | }
370 |
371 | @media (max-width: 430px) {
372 | .footer {
373 | height: 50px;
374 | }
375 |
376 | .filters {
377 | bottom: 10px;
378 | }
379 | }
380 |
--------------------------------------------------------------------------------
/todomvc/seed/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | font-weight: inherit;
16 | color: inherit;
17 | -webkit-appearance: none;
18 | appearance: none;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | }
22 |
23 | body {
24 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
25 | line-height: 1.4em;
26 | background: #f5f5f5;
27 | color: #4d4d4d;
28 | min-width: 230px;
29 | max-width: 550px;
30 | margin: 0 auto;
31 | -webkit-font-smoothing: antialiased;
32 | -moz-osx-font-smoothing: grayscale;
33 | font-weight: 300;
34 | }
35 |
36 | :focus {
37 | outline: 0;
38 | }
39 |
40 | .hidden {
41 | display: none;
42 | }
43 |
44 | .todoapp {
45 | background: #fff;
46 | margin: 130px 0 40px 0;
47 | position: relative;
48 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
49 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
50 | }
51 |
52 | .todoapp input::-webkit-input-placeholder {
53 | font-style: italic;
54 | font-weight: 300;
55 | color: #e6e6e6;
56 | }
57 |
58 | .todoapp input::-moz-placeholder {
59 | font-style: italic;
60 | font-weight: 300;
61 | color: #e6e6e6;
62 | }
63 |
64 | .todoapp input::input-placeholder {
65 | font-style: italic;
66 | font-weight: 300;
67 | color: #e6e6e6;
68 | }
69 |
70 | .todoapp h1 {
71 | position: absolute;
72 | top: -155px;
73 | width: 100%;
74 | font-size: 100px;
75 | font-weight: 100;
76 | text-align: center;
77 | color: rgba(175, 47, 47, 0.15);
78 | -webkit-text-rendering: optimizeLegibility;
79 | -moz-text-rendering: optimizeLegibility;
80 | text-rendering: optimizeLegibility;
81 | }
82 |
83 | .new-todo,
84 | .edit {
85 | position: relative;
86 | margin: 0;
87 | width: 100%;
88 | font-size: 24px;
89 | font-family: inherit;
90 | font-weight: inherit;
91 | line-height: 1.4em;
92 | border: 0;
93 | color: inherit;
94 | padding: 6px;
95 | border: 1px solid #999;
96 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
97 | box-sizing: border-box;
98 | -webkit-font-smoothing: antialiased;
99 | -moz-osx-font-smoothing: grayscale;
100 | }
101 |
102 | .new-todo {
103 | padding: 16px 16px 16px 60px;
104 | border: none;
105 | background: rgba(0, 0, 0, 0.003);
106 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
107 | }
108 |
109 | .main {
110 | position: relative;
111 | z-index: 2;
112 | border-top: 1px solid #e6e6e6;
113 | }
114 |
115 | .toggle-all {
116 | text-align: center;
117 | border: none; /* Mobile Safari */
118 | opacity: 0;
119 | position: absolute;
120 | }
121 |
122 | .toggle-all + label {
123 | width: 60px;
124 | height: 34px;
125 | font-size: 0;
126 | position: absolute;
127 | top: -52px;
128 | left: -13px;
129 | -webkit-transform: rotate(90deg);
130 | transform: rotate(90deg);
131 | }
132 |
133 | .toggle-all + label:before {
134 | content: '❯';
135 | font-size: 22px;
136 | color: #e6e6e6;
137 | padding: 10px 27px 10px 27px;
138 | }
139 |
140 | .toggle-all:checked + label:before {
141 | color: #737373;
142 | }
143 |
144 | .todo-list {
145 | margin: 0;
146 | padding: 0;
147 | list-style: none;
148 | }
149 |
150 | .todo-list li {
151 | position: relative;
152 | font-size: 24px;
153 | border-bottom: 1px solid #ededed;
154 | }
155 |
156 | .todo-list li:last-child {
157 | border-bottom: none;
158 | }
159 |
160 | .todo-list li.editing {
161 | border-bottom: none;
162 | padding: 0;
163 | }
164 |
165 | .todo-list li.editing .edit {
166 | display: block;
167 | width: 506px;
168 | padding: 12px 16px;
169 | margin: 0 0 0 43px;
170 | }
171 |
172 | .todo-list li.editing .view {
173 | display: none;
174 | }
175 |
176 | .todo-list li .toggle {
177 | text-align: center;
178 | width: 40px;
179 | /* auto, since non-WebKit browsers doesn't support input styling */
180 | height: auto;
181 | position: absolute;
182 | top: 0;
183 | bottom: 0;
184 | margin: auto 0;
185 | border: none; /* Mobile Safari */
186 | -webkit-appearance: none;
187 | appearance: none;
188 | }
189 |
190 | .todo-list li .toggle {
191 | opacity: 0;
192 | }
193 |
194 | .todo-list li .toggle + label {
195 | /*
196 | Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
197 | 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/
198 | */
199 | 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');
200 | background-repeat: no-repeat;
201 | background-position: center left;
202 | }
203 |
204 | .todo-list li .toggle:checked + label {
205 | 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');
206 | }
207 |
208 | .todo-list li label {
209 | word-break: break-all;
210 | padding: 15px 15px 15px 60px;
211 | display: block;
212 | line-height: 1.2;
213 | transition: color 0.4s;
214 | }
215 |
216 | .todo-list li.completed label {
217 | color: #d9d9d9;
218 | text-decoration: line-through;
219 | }
220 |
221 | .todo-list li .destroy {
222 | display: none;
223 | position: absolute;
224 | top: 0;
225 | right: 10px;
226 | bottom: 0;
227 | width: 40px;
228 | height: 40px;
229 | margin: auto 0;
230 | font-size: 30px;
231 | color: #cc9a9a;
232 | margin-bottom: 11px;
233 | transition: color 0.2s ease-out;
234 | }
235 |
236 | .todo-list li .destroy:hover {
237 | color: #af5b5e;
238 | }
239 |
240 | .todo-list li .destroy:after {
241 | content: '×';
242 | }
243 |
244 | .todo-list li:hover .destroy {
245 | display: block;
246 | }
247 |
248 | .todo-list li .edit {
249 | display: none;
250 | }
251 |
252 | .todo-list li.editing:last-child {
253 | margin-bottom: -1px;
254 | }
255 |
256 | .footer {
257 | color: #777;
258 | padding: 10px 15px;
259 | height: 20px;
260 | text-align: center;
261 | border-top: 1px solid #e6e6e6;
262 | }
263 |
264 | .footer:before {
265 | content: '';
266 | position: absolute;
267 | right: 0;
268 | bottom: 0;
269 | left: 0;
270 | height: 50px;
271 | overflow: hidden;
272 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
273 | 0 8px 0 -3px #f6f6f6,
274 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
275 | 0 16px 0 -6px #f6f6f6,
276 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
277 | }
278 |
279 | .todo-count {
280 | float: left;
281 | text-align: left;
282 | }
283 |
284 | .todo-count strong {
285 | font-weight: 300;
286 | }
287 |
288 | .filters {
289 | margin: 0;
290 | padding: 0;
291 | list-style: none;
292 | position: absolute;
293 | right: 0;
294 | left: 0;
295 | }
296 |
297 | .filters li {
298 | display: inline;
299 | }
300 |
301 | .filters li a {
302 | color: inherit;
303 | margin: 3px;
304 | padding: 3px 7px;
305 | text-decoration: none;
306 | border: 1px solid transparent;
307 | border-radius: 3px;
308 | }
309 |
310 | .filters li a:hover {
311 | border-color: rgba(175, 47, 47, 0.1);
312 | }
313 |
314 | .filters li a.selected {
315 | border-color: rgba(175, 47, 47, 0.2);
316 | }
317 |
318 | .clear-completed,
319 | html .clear-completed:active {
320 | float: right;
321 | position: relative;
322 | line-height: 20px;
323 | text-decoration: none;
324 | cursor: pointer;
325 | }
326 |
327 | .clear-completed:hover {
328 | text-decoration: underline;
329 | }
330 |
331 | .info {
332 | margin: 65px auto 0;
333 | color: #bfbfbf;
334 | font-size: 10px;
335 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
336 | text-align: center;
337 | }
338 |
339 | .info p {
340 | line-height: 1;
341 | }
342 |
343 | .info a {
344 | color: inherit;
345 | text-decoration: none;
346 | font-weight: 400;
347 | }
348 |
349 | .info a:hover {
350 | text-decoration: underline;
351 | }
352 |
353 | /*
354 | Hack to remove background from Mobile Safari.
355 | Can't use it globally since it destroys checkboxes in Firefox
356 | */
357 | @media screen and (-webkit-min-device-pixel-ratio:0) {
358 | .toggle-all,
359 | .todo-list li .toggle {
360 | background: none;
361 | }
362 |
363 | .todo-list li .toggle {
364 | height: 40px;
365 | }
366 | }
367 |
368 | @media (max-width: 430px) {
369 | .footer {
370 | height: 50px;
371 | }
372 |
373 | .filters {
374 | bottom: 10px;
375 | }
376 | }
377 |
--------------------------------------------------------------------------------
/todomvc/seed/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Seed • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/todomvc/seed/pkg/README.md:
--------------------------------------------------------------------------------
1 | # Rust & Seed TodoMVC Example
2 |
3 |
4 | > Rust is a systems programming language with a focus on safety,
5 | especially safe concurrency.
6 |
7 | > _[Rust](https://www.rust-lang.org)_
8 |
9 | > wasm-bindgen, and its web-sys package allow Rust to be used in web browsers via WASM.
10 |
11 | > [Wasm-bindgen](https://rustwasm.github.io/wasm-bindgen/)
12 |
13 | > Seed is a high-level framework for building websites using these tools.
14 |
15 | > _[Seed](https://github.com/seed-rs/seed)_
16 |
17 | ## Learning Rust
18 |
19 | The [Rust book](https://doc.rust-lang.org/book/index.html) is a great resource for getting started.
20 |
21 | Here are some links you may find helpful:
22 |
23 | * [Code Playground](https://play.rust-lang.org/)
24 | * [Rust Documentation](https://doc.rust-lang.org/)
25 | * [Rust Source Code](https://github.com/rust-lang/rust)
26 | * [wasm-bindgen Source Code](https://github.com/rustwasm/wasm-bindgen)
27 | * [Seed guide](https://github.com/seed-rs/seed)
28 | * [Seed quickstart repo](https://github.com/seed-rs/seed-quickstart)
29 |
30 | Get help from Rust users:
31 |
32 | * [Rust on StackOverflow](http://stackoverflow.com/questions/tagged/rust)
33 | * [Reddit](https://www.reddit.com/r/rust/)
34 | * [Gitter chat](https://gitter.im/rust-lang/rust)
35 |
36 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
37 |
38 |
39 | ## Running
40 |
41 | #### Prerequisites
42 |
43 | - This framework requires you to first install [Rust](https://www.rust-lang.org/tools/install).
44 | - You'll need a recent version of Rust: `rustup update`
45 | - The wasm32 target: `rustup target add wasm32-unknown-unknown`
46 | - And cargo-make: `cargo install --force cargo-make`
47 |
48 |
49 | #### Build & Run
50 | ```bash
51 | cargo make start
52 | ```
53 |
54 | Open [127.0.0.1:8000](http://127.0.0.1:8000) in your browser.
55 |
56 | ---
57 |
58 | ### [How to make this example standalone]
59 | - **`Makefile.toml`**
60 | - Replace tasks with aliases with their parents.
61 | - Remove root Makefile import.
62 | - **`Cargo.toml`**
63 | - replace Seed path with version number
64 | - This file
65 | - Remove this chapter
66 |
--------------------------------------------------------------------------------
/todomvc/seed/pkg/package.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /**
3 | */
4 | export function render(): void;
5 |
6 | /**
7 | * If `module_or_path` is {RequestInfo}, makes a request and
8 | * for everything else, calls `WebAssembly.instantiate` directly.
9 | *
10 | * @param {RequestInfo | BufferSource | WebAssembly.Module} module_or_path
11 | *
12 | * @returns {Promise}
13 | */
14 | export default function init (module_or_path?: RequestInfo | BufferSource | WebAssembly.Module): Promise;
15 |
--------------------------------------------------------------------------------
/todomvc/seed/pkg/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todomvc",
3 | "collaborators": [
4 | "Your Name "
5 | ],
6 | "version": "0.1.0",
7 | "files": [
8 | "package_bg.wasm",
9 | "package.js",
10 | "package.d.ts"
11 | ],
12 | "module": "package.js",
13 | "types": "package.d.ts",
14 | "sideEffects": "false"
15 | }
--------------------------------------------------------------------------------
/todomvc/seed/pkg/package_bg.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | export const memory: WebAssembly.Memory;
3 | export function render(): void;
4 | export function __wbindgen_exn_store(a: number): void;
5 | export function __wbindgen_malloc(a: number): number;
6 | export function __wbindgen_realloc(a: number, b: number, c: number): number;
7 | export function __wbindgen_free(a: number, b: number): void;
8 | export const __wbg_function_table: WebAssembly.Table;
9 | export function __wbindgen_start(): void;
10 |
--------------------------------------------------------------------------------
/todomvc/seed/pkg/package_bg.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/seed/pkg/package_bg.wasm
--------------------------------------------------------------------------------
/todomvc/seed/pkg/todomvc.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /**
3 | */
4 | export function render(): void;
5 |
6 | /**
7 | * If `module_or_path` is {RequestInfo}, makes a request and
8 | * for everything else, calls `WebAssembly.instantiate` directly.
9 | *
10 | * @param {RequestInfo | BufferSource | WebAssembly.Module} module_or_path
11 | *
12 | * @returns {Promise}
13 | */
14 | export default function init (module_or_path: RequestInfo | BufferSource | WebAssembly.Module): Promise;
15 |
--------------------------------------------------------------------------------
/todomvc/seed/pkg/todomvc_bg.d.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | export const memory: WebAssembly.Memory;
3 | export function render(): void;
4 | export function __wbindgen_exn_store(a: number): void;
5 | export function __wbindgen_malloc(a: number): number;
6 | export function __wbindgen_realloc(a: number, b: number, c: number): number;
7 | export function __wbindgen_free(a: number, b: number): void;
8 | export const __wbg_function_table: WebAssembly.Table;
9 | export function __wbindgen_start(): void;
10 |
--------------------------------------------------------------------------------
/todomvc/seed/pkg/todomvc_bg.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/seed/pkg/todomvc_bg.wasm
--------------------------------------------------------------------------------
/todomvc/seed/text-polyfill.min.js:
--------------------------------------------------------------------------------
1 | (function(l){function m(b){b=void 0===b?"utf-8":b;if("utf-8"!==b)throw new RangeError("Failed to construct 'TextEncoder': The encoding label provided ('"+b+"') is invalid.");}function k(b,a){b=void 0===b?"utf-8":b;a=void 0===a?{fatal:!1}:a;if("utf-8"!==b)throw new RangeError("Failed to construct 'TextDecoder': The encoding label provided ('"+b+"') is invalid.");if(a.fatal)throw Error("Failed to construct 'TextDecoder': the 'fatal' option is unsupported.");}if(l.TextEncoder&&l.TextDecoder)return!1;
2 | Object.defineProperty(m.prototype,"encoding",{value:"utf-8"});m.prototype.encode=function(b,a){a=void 0===a?{stream:!1}:a;if(a.stream)throw Error("Failed to encode: the 'stream' option is unsupported.");a=0;for(var h=b.length,f=0,c=Math.max(32,h+(h>>1)+7),e=new Uint8Array(c>>3<<3);a=d){if(a=d)continue}f+4>e.length&&(c+=8,c*=1+a/b.length*2,c=c>>3<<3,
3 | g=new Uint8Array(c),g.set(e),e=g);if(0===(d&4294967168))e[f++]=d;else{if(0===(d&4294965248))e[f++]=d>>6&31|192;else if(0===(d&4294901760))e[f++]=d>>12&15|224,e[f++]=d>>6&63|128;else if(0===(d&4292870144))e[f++]=d>>18&7|240,e[f++]=d>>12&63|128,e[f++]=d>>6&63|128;else continue;e[f++]=d&63|128}}return e.slice(0,f)};Object.defineProperty(k.prototype,"encoding",{value:"utf-8"});Object.defineProperty(k.prototype,"fatal",{value:!1});Object.defineProperty(k.prototype,"ignoreBOM",{value:!1});k.prototype.decode=
4 | function(b,a){a=void 0===a?{stream:!1}:a;if(a.stream)throw Error("Failed to decode: the 'stream' option is unsupported.");b=new Uint8Array(b);a=0;for(var h=b.length,f=[];a>>10&1023|55296),c=56320|
5 | c&1023);f.push(c)}}return String.fromCharCode.apply(null,f)};l.TextEncoder=m;l.TextDecoder=k})("undefined"!==typeof window?window:"undefined"!==typeof global?global:this);
6 |
--------------------------------------------------------------------------------
/todomvc/vue/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/vue/.gitignore
--------------------------------------------------------------------------------
/todomvc/vue/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Vue.js • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
43 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/todomvc/vue/js/app.js:
--------------------------------------------------------------------------------
1 | /*global Vue, todoStorage */
2 |
3 | (function (exports) {
4 |
5 | 'use strict';
6 |
7 | var filters = {
8 | all: function (todos) {
9 | return todos;
10 | },
11 | active: function (todos) {
12 | return todos.filter(function (todo) {
13 | return !todo.completed;
14 | });
15 | },
16 | completed: function (todos) {
17 | return todos.filter(function (todo) {
18 | return todo.completed;
19 | });
20 | }
21 | };
22 |
23 | exports.app = new Vue({
24 |
25 | // the root element that will be compiled
26 | el: '.todoapp',
27 |
28 | // app initial state
29 | data: {
30 | todos: todoStorage.fetch(),
31 | newTodo: '',
32 | editedTodo: null,
33 | visibility: 'all'
34 | },
35 |
36 | // watch todos change for localStorage persistence
37 | watch: {
38 | todos: {
39 | deep: true,
40 | handler: todoStorage.save
41 | }
42 | },
43 |
44 | // computed properties
45 | // http://vuejs.org/guide/computed.html
46 | computed: {
47 | filteredTodos: function () {
48 | return filters[this.visibility](this.todos);
49 | },
50 | remaining: function () {
51 | return filters.active(this.todos).length;
52 | },
53 | allDone: {
54 | get: function () {
55 | return this.remaining === 0;
56 | },
57 | set: function (value) {
58 | this.todos.forEach(function (todo) {
59 | todo.completed = value;
60 | });
61 | }
62 | }
63 | },
64 |
65 | // methods that implement data logic.
66 | // note there's no DOM manipulation here at all.
67 | methods: {
68 |
69 | addTodo: function () {
70 | var value = this.newTodo && this.newTodo.trim();
71 | if (!value) {
72 | return;
73 | }
74 | this.todos.push({ title: value, completed: false });
75 | this.newTodo = '';
76 | },
77 |
78 | removeTodo: function (todo) {
79 | this.todos.$remove(todo);
80 | },
81 |
82 | editTodo: function (todo) {
83 | this.beforeEditCache = todo.title;
84 | this.editedTodo = todo;
85 | },
86 |
87 | doneEdit: function (todo) {
88 | if (!this.editedTodo) {
89 | return;
90 | }
91 | this.editedTodo = null;
92 | todo.title = todo.title.trim();
93 | if (!todo.title) {
94 | this.removeTodo(todo);
95 | }
96 | },
97 |
98 | cancelEdit: function (todo) {
99 | this.editedTodo = null;
100 | todo.title = this.beforeEditCache;
101 | },
102 |
103 | removeCompleted: function () {
104 | this.todos = filters.active(this.todos);
105 | }
106 | },
107 |
108 | // a custom directive to wait for the DOM to be updated
109 | // before focusing on the input field.
110 | // http://vuejs.org/guide/custom-directive.html
111 | directives: {
112 | 'todo-focus': function (value) {
113 | if (!value) {
114 | return;
115 | }
116 | var el = this.el;
117 | Vue.nextTick(function () {
118 | el.focus();
119 | });
120 | }
121 | }
122 | });
123 |
124 | })(window);
125 |
--------------------------------------------------------------------------------
/todomvc/vue/js/routes.js:
--------------------------------------------------------------------------------
1 | /*global app, Router */
2 |
3 | (function (app, Router) {
4 |
5 | 'use strict';
6 |
7 | var router = new Router();
8 |
9 | ['all', 'active', 'completed'].forEach(function (visibility) {
10 | router.on(visibility, function () {
11 | app.visibility = visibility;
12 | });
13 | });
14 |
15 | router.configure({
16 | notfound: function () {
17 | window.location.hash = '';
18 | app.visibility = 'all';
19 | }
20 | });
21 |
22 | router.init();
23 |
24 | })(app, Router);
25 |
--------------------------------------------------------------------------------
/todomvc/vue/js/store.js:
--------------------------------------------------------------------------------
1 | /*jshint unused:false */
2 |
3 | (function (exports) {
4 |
5 | 'use strict';
6 |
7 | var STORAGE_KEY = 'todos-vuejs';
8 |
9 | exports.todoStorage = {
10 | fetch: function () {
11 | return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
12 | },
13 | save: function (todos) {
14 | localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
15 | }
16 | };
17 |
18 | })(window);
19 |
--------------------------------------------------------------------------------
/todomvc/vue/node_modules/todomvc-app-css/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | button {
8 | margin: 0;
9 | padding: 0;
10 | border: 0;
11 | background: none;
12 | font-size: 100%;
13 | vertical-align: baseline;
14 | font-family: inherit;
15 | font-weight: inherit;
16 | color: inherit;
17 | -webkit-appearance: none;
18 | appearance: none;
19 | -webkit-font-smoothing: antialiased;
20 | -moz-osx-font-smoothing: grayscale;
21 | }
22 |
23 | body {
24 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
25 | line-height: 1.4em;
26 | background: #f5f5f5;
27 | color: #4d4d4d;
28 | min-width: 230px;
29 | max-width: 550px;
30 | margin: 0 auto;
31 | -webkit-font-smoothing: antialiased;
32 | -moz-osx-font-smoothing: grayscale;
33 | font-weight: 300;
34 | }
35 |
36 | :focus {
37 | outline: 0;
38 | }
39 |
40 | .hidden {
41 | display: none;
42 | }
43 |
44 | .todoapp {
45 | background: #fff;
46 | margin: 130px 0 40px 0;
47 | position: relative;
48 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
49 | 0 25px 50px 0 rgba(0, 0, 0, 0.1);
50 | }
51 |
52 | .todoapp input::-webkit-input-placeholder {
53 | font-style: italic;
54 | font-weight: 300;
55 | color: #e6e6e6;
56 | }
57 |
58 | .todoapp input::-moz-placeholder {
59 | font-style: italic;
60 | font-weight: 300;
61 | color: #e6e6e6;
62 | }
63 |
64 | .todoapp input::input-placeholder {
65 | font-style: italic;
66 | font-weight: 300;
67 | color: #e6e6e6;
68 | }
69 |
70 | .todoapp h1 {
71 | position: absolute;
72 | top: -155px;
73 | width: 100%;
74 | font-size: 100px;
75 | font-weight: 100;
76 | text-align: center;
77 | color: rgba(175, 47, 47, 0.15);
78 | -webkit-text-rendering: optimizeLegibility;
79 | -moz-text-rendering: optimizeLegibility;
80 | text-rendering: optimizeLegibility;
81 | }
82 |
83 | .new-todo,
84 | .edit {
85 | position: relative;
86 | margin: 0;
87 | width: 100%;
88 | font-size: 24px;
89 | font-family: inherit;
90 | font-weight: inherit;
91 | line-height: 1.4em;
92 | border: 0;
93 | color: inherit;
94 | padding: 6px;
95 | border: 1px solid #999;
96 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
97 | box-sizing: border-box;
98 | -webkit-font-smoothing: antialiased;
99 | -moz-osx-font-smoothing: grayscale;
100 | }
101 |
102 | .new-todo {
103 | padding: 16px 16px 16px 60px;
104 | border: none;
105 | background: rgba(0, 0, 0, 0.003);
106 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
107 | }
108 |
109 | .main {
110 | position: relative;
111 | z-index: 2;
112 | border-top: 1px solid #e6e6e6;
113 | }
114 |
115 | label[for='toggle-all'] {
116 | display: none;
117 | }
118 |
119 | .toggle-all {
120 | position: absolute;
121 | top: -55px;
122 | left: -12px;
123 | width: 60px;
124 | height: 34px;
125 | text-align: center;
126 | border: none; /* Mobile Safari */
127 | }
128 |
129 | .toggle-all:before {
130 | content: '❯';
131 | font-size: 22px;
132 | color: #e6e6e6;
133 | padding: 10px 27px 10px 27px;
134 | }
135 |
136 | .toggle-all:checked:before {
137 | color: #737373;
138 | }
139 |
140 | .todo-list {
141 | margin: 0;
142 | padding: 0;
143 | list-style: none;
144 | }
145 |
146 | .todo-list li {
147 | position: relative;
148 | font-size: 24px;
149 | border-bottom: 1px solid #ededed;
150 | }
151 |
152 | .todo-list li:last-child {
153 | border-bottom: none;
154 | }
155 |
156 | .todo-list li.editing {
157 | border-bottom: none;
158 | padding: 0;
159 | }
160 |
161 | .todo-list li.editing .edit {
162 | display: block;
163 | width: 506px;
164 | padding: 12px 16px;
165 | margin: 0 0 0 43px;
166 | }
167 |
168 | .todo-list li.editing .view {
169 | display: none;
170 | }
171 |
172 | .todo-list li .toggle {
173 | text-align: center;
174 | width: 40px;
175 | /* auto, since non-WebKit browsers doesn't support input styling */
176 | height: auto;
177 | position: absolute;
178 | top: 0;
179 | bottom: 0;
180 | margin: auto 0;
181 | border: none; /* Mobile Safari */
182 | -webkit-appearance: none;
183 | appearance: none;
184 | }
185 |
186 | .todo-list li .toggle:after {
187 | content: url('data:image/svg+xml;utf8,');
188 | }
189 |
190 | .todo-list li .toggle:checked:after {
191 | content: url('data:image/svg+xml;utf8,');
192 | }
193 |
194 | .todo-list li label {
195 | word-break: break-all;
196 | padding: 15px 60px 15px 15px;
197 | margin-left: 45px;
198 | display: block;
199 | line-height: 1.2;
200 | transition: color 0.4s;
201 | }
202 |
203 | .todo-list li.completed label {
204 | color: #d9d9d9;
205 | text-decoration: line-through;
206 | }
207 |
208 | .todo-list li .destroy {
209 | display: none;
210 | position: absolute;
211 | top: 0;
212 | right: 10px;
213 | bottom: 0;
214 | width: 40px;
215 | height: 40px;
216 | margin: auto 0;
217 | font-size: 30px;
218 | color: #cc9a9a;
219 | margin-bottom: 11px;
220 | transition: color 0.2s ease-out;
221 | }
222 |
223 | .todo-list li .destroy:hover {
224 | color: #af5b5e;
225 | }
226 |
227 | .todo-list li .destroy:after {
228 | content: '×';
229 | }
230 |
231 | .todo-list li:hover .destroy {
232 | display: block;
233 | }
234 |
235 | .todo-list li .edit {
236 | display: none;
237 | }
238 |
239 | .todo-list li.editing:last-child {
240 | margin-bottom: -1px;
241 | }
242 |
243 | .footer {
244 | color: #777;
245 | padding: 10px 15px;
246 | height: 20px;
247 | text-align: center;
248 | border-top: 1px solid #e6e6e6;
249 | }
250 |
251 | .footer:before {
252 | content: '';
253 | position: absolute;
254 | right: 0;
255 | bottom: 0;
256 | left: 0;
257 | height: 50px;
258 | overflow: hidden;
259 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
260 | 0 8px 0 -3px #f6f6f6,
261 | 0 9px 1px -3px rgba(0, 0, 0, 0.2),
262 | 0 16px 0 -6px #f6f6f6,
263 | 0 17px 2px -6px rgba(0, 0, 0, 0.2);
264 | }
265 |
266 | .todo-count {
267 | float: left;
268 | text-align: left;
269 | }
270 |
271 | .todo-count strong {
272 | font-weight: 300;
273 | }
274 |
275 | .filters {
276 | margin: 0;
277 | padding: 0;
278 | list-style: none;
279 | position: absolute;
280 | right: 0;
281 | left: 0;
282 | }
283 |
284 | .filters li {
285 | display: inline;
286 | }
287 |
288 | .filters li a {
289 | color: inherit;
290 | margin: 3px;
291 | padding: 3px 7px;
292 | text-decoration: none;
293 | border: 1px solid transparent;
294 | border-radius: 3px;
295 | }
296 |
297 | .filters li a:hover {
298 | border-color: rgba(175, 47, 47, 0.1);
299 | }
300 |
301 | .filters li a.selected {
302 | border-color: rgba(175, 47, 47, 0.2);
303 | }
304 |
305 | .clear-completed,
306 | html .clear-completed:active {
307 | float: right;
308 | position: relative;
309 | line-height: 20px;
310 | text-decoration: none;
311 | cursor: pointer;
312 | }
313 |
314 | .clear-completed:hover {
315 | text-decoration: underline;
316 | }
317 |
318 | .info {
319 | margin: 65px auto 0;
320 | color: #bfbfbf;
321 | font-size: 10px;
322 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
323 | text-align: center;
324 | }
325 |
326 | .info p {
327 | line-height: 1;
328 | }
329 |
330 | .info a {
331 | color: inherit;
332 | text-decoration: none;
333 | font-weight: 400;
334 | }
335 |
336 | .info a:hover {
337 | text-decoration: underline;
338 | }
339 |
340 | /*
341 | Hack to remove background from Mobile Safari.
342 | Can't use it globally since it destroys checkboxes in Firefox
343 | */
344 | @media screen and (-webkit-min-device-pixel-ratio:0) {
345 | .toggle-all,
346 | .todo-list li .toggle {
347 | background: none;
348 | }
349 |
350 | .todo-list li .toggle {
351 | height: 40px;
352 | }
353 |
354 | .toggle-all {
355 | -webkit-transform: rotate(90deg);
356 | transform: rotate(90deg);
357 | -webkit-appearance: none;
358 | appearance: none;
359 | }
360 | }
361 |
362 | @media (max-width: 430px) {
363 | .footer {
364 | height: 50px;
365 | }
366 |
367 | .filters {
368 | bottom: 10px;
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/todomvc/vue/node_modules/todomvc-common/base.css:
--------------------------------------------------------------------------------
1 | hr {
2 | margin: 20px 0;
3 | border: 0;
4 | border-top: 1px dashed #c5c5c5;
5 | border-bottom: 1px dashed #f7f7f7;
6 | }
7 |
8 | .learn a {
9 | font-weight: normal;
10 | text-decoration: none;
11 | color: #b83f45;
12 | }
13 |
14 | .learn a:hover {
15 | text-decoration: underline;
16 | color: #787e7e;
17 | }
18 |
19 | .learn h3,
20 | .learn h4,
21 | .learn h5 {
22 | margin: 10px 0;
23 | font-weight: 500;
24 | line-height: 1.2;
25 | color: #000;
26 | }
27 |
28 | .learn h3 {
29 | font-size: 24px;
30 | }
31 |
32 | .learn h4 {
33 | font-size: 18px;
34 | }
35 |
36 | .learn h5 {
37 | margin-bottom: 0;
38 | font-size: 14px;
39 | }
40 |
41 | .learn ul {
42 | padding: 0;
43 | margin: 0 0 30px 25px;
44 | }
45 |
46 | .learn li {
47 | line-height: 20px;
48 | }
49 |
50 | .learn p {
51 | font-size: 15px;
52 | font-weight: 300;
53 | line-height: 1.3;
54 | margin-top: 0;
55 | margin-bottom: 0;
56 | }
57 |
58 | #issue-count {
59 | display: none;
60 | }
61 |
62 | .quote {
63 | border: none;
64 | margin: 20px 0 60px 0;
65 | }
66 |
67 | .quote p {
68 | font-style: italic;
69 | }
70 |
71 | .quote p:before {
72 | content: '“';
73 | font-size: 50px;
74 | opacity: .15;
75 | position: absolute;
76 | top: -20px;
77 | left: 3px;
78 | }
79 |
80 | .quote p:after {
81 | content: '”';
82 | font-size: 50px;
83 | opacity: .15;
84 | position: absolute;
85 | bottom: -42px;
86 | right: 3px;
87 | }
88 |
89 | .quote footer {
90 | position: absolute;
91 | bottom: -40px;
92 | right: 0;
93 | }
94 |
95 | .quote footer img {
96 | border-radius: 3px;
97 | }
98 |
99 | .quote footer a {
100 | margin-left: 5px;
101 | vertical-align: middle;
102 | }
103 |
104 | .speech-bubble {
105 | position: relative;
106 | padding: 10px;
107 | background: rgba(0, 0, 0, .04);
108 | border-radius: 5px;
109 | }
110 |
111 | .speech-bubble:after {
112 | content: '';
113 | position: absolute;
114 | top: 100%;
115 | right: 30px;
116 | border: 13px solid transparent;
117 | border-top-color: rgba(0, 0, 0, .04);
118 | }
119 |
120 | .learn-bar > .learn {
121 | position: absolute;
122 | width: 272px;
123 | top: 8px;
124 | left: -300px;
125 | padding: 10px;
126 | border-radius: 5px;
127 | background-color: rgba(255, 255, 255, .6);
128 | transition-property: left;
129 | transition-duration: 500ms;
130 | }
131 |
132 | @media (min-width: 899px) {
133 | .learn-bar {
134 | width: auto;
135 | padding-left: 300px;
136 | }
137 |
138 | .learn-bar > .learn {
139 | left: 8px;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/todomvc/vue/node_modules/todomvc-common/base.js:
--------------------------------------------------------------------------------
1 | /* global _ */
2 | (function () {
3 | 'use strict';
4 |
5 | /* jshint ignore:start */
6 | // Underscore's Template Module
7 | // Courtesy of underscorejs.org
8 | var _ = (function (_) {
9 | _.defaults = function (object) {
10 | if (!object) {
11 | return object;
12 | }
13 | for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
14 | var iterable = arguments[argsIndex];
15 | if (iterable) {
16 | for (var key in iterable) {
17 | if (object[key] == null) {
18 | object[key] = iterable[key];
19 | }
20 | }
21 | }
22 | }
23 | return object;
24 | }
25 |
26 | // By default, Underscore uses ERB-style template delimiters, change the
27 | // following template settings to use alternative delimiters.
28 | _.templateSettings = {
29 | evaluate : /<%([\s\S]+?)%>/g,
30 | interpolate : /<%=([\s\S]+?)%>/g,
31 | escape : /<%-([\s\S]+?)%>/g
32 | };
33 |
34 | // When customizing `templateSettings`, if you don't want to define an
35 | // interpolation, evaluation or escaping regex, we need one that is
36 | // guaranteed not to match.
37 | var noMatch = /(.)^/;
38 |
39 | // Certain characters need to be escaped so that they can be put into a
40 | // string literal.
41 | var escapes = {
42 | "'": "'",
43 | '\\': '\\',
44 | '\r': 'r',
45 | '\n': 'n',
46 | '\t': 't',
47 | '\u2028': 'u2028',
48 | '\u2029': 'u2029'
49 | };
50 |
51 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
52 |
53 | // JavaScript micro-templating, similar to John Resig's implementation.
54 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
55 | // and correctly escapes quotes within interpolated code.
56 | _.template = function(text, data, settings) {
57 | var render;
58 | settings = _.defaults({}, settings, _.templateSettings);
59 |
60 | // Combine delimiters into one regular expression via alternation.
61 | var matcher = new RegExp([
62 | (settings.escape || noMatch).source,
63 | (settings.interpolate || noMatch).source,
64 | (settings.evaluate || noMatch).source
65 | ].join('|') + '|$', 'g');
66 |
67 | // Compile the template source, escaping string literals appropriately.
68 | var index = 0;
69 | var source = "__p+='";
70 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
71 | source += text.slice(index, offset)
72 | .replace(escaper, function(match) { return '\\' + escapes[match]; });
73 |
74 | if (escape) {
75 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
76 | }
77 | if (interpolate) {
78 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
79 | }
80 | if (evaluate) {
81 | source += "';\n" + evaluate + "\n__p+='";
82 | }
83 | index = offset + match.length;
84 | return match;
85 | });
86 | source += "';\n";
87 |
88 | // If a variable is not specified, place data values in local scope.
89 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
90 |
91 | source = "var __t,__p='',__j=Array.prototype.join," +
92 | "print=function(){__p+=__j.call(arguments,'');};\n" +
93 | source + "return __p;\n";
94 |
95 | try {
96 | render = new Function(settings.variable || 'obj', '_', source);
97 | } catch (e) {
98 | e.source = source;
99 | throw e;
100 | }
101 |
102 | if (data) return render(data, _);
103 | var template = function(data) {
104 | return render.call(this, data, _);
105 | };
106 |
107 | // Provide the compiled function source as a convenience for precompilation.
108 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
109 |
110 | return template;
111 | };
112 |
113 | return _;
114 | })({});
115 |
116 | if (location.hostname === 'todomvc.com') {
117 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
118 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
119 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
120 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
121 | ga('create', 'UA-31081062-1', 'auto');
122 | ga('send', 'pageview');
123 | }
124 | /* jshint ignore:end */
125 |
126 | function redirect() {
127 | if (location.hostname === 'tastejs.github.io') {
128 | location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
129 | }
130 | }
131 |
132 | function findRoot() {
133 | var base = location.href.indexOf('examples/');
134 | return location.href.substr(0, base);
135 | }
136 |
137 | function getFile(file, callback) {
138 | if (!location.host) {
139 | return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
140 | }
141 |
142 | var xhr = new XMLHttpRequest();
143 |
144 | xhr.open('GET', findRoot() + file, true);
145 | xhr.send();
146 |
147 | xhr.onload = function () {
148 | if (xhr.status === 200 && callback) {
149 | callback(xhr.responseText);
150 | }
151 | };
152 | }
153 |
154 | function Learn(learnJSON, config) {
155 | if (!(this instanceof Learn)) {
156 | return new Learn(learnJSON, config);
157 | }
158 |
159 | var template, framework;
160 |
161 | if (typeof learnJSON !== 'object') {
162 | try {
163 | learnJSON = JSON.parse(learnJSON);
164 | } catch (e) {
165 | return;
166 | }
167 | }
168 |
169 | if (config) {
170 | template = config.template;
171 | framework = config.framework;
172 | }
173 |
174 | if (!template && learnJSON.templates) {
175 | template = learnJSON.templates.todomvc;
176 | }
177 |
178 | if (!framework && document.querySelector('[data-framework]')) {
179 | framework = document.querySelector('[data-framework]').dataset.framework;
180 | }
181 |
182 | this.template = template;
183 |
184 | if (learnJSON.backend) {
185 | this.frameworkJSON = learnJSON.backend;
186 | this.frameworkJSON.issueLabel = framework;
187 | this.append({
188 | backend: true
189 | });
190 | } else if (learnJSON[framework]) {
191 | this.frameworkJSON = learnJSON[framework];
192 | this.frameworkJSON.issueLabel = framework;
193 | this.append();
194 | }
195 |
196 | this.fetchIssueCount();
197 | }
198 |
199 | Learn.prototype.append = function (opts) {
200 | var aside = document.createElement('aside');
201 | aside.innerHTML = _.template(this.template, this.frameworkJSON);
202 | aside.className = 'learn';
203 |
204 | if (opts && opts.backend) {
205 | // Remove demo link
206 | var sourceLinks = aside.querySelector('.source-links');
207 | var heading = sourceLinks.firstElementChild;
208 | var sourceLink = sourceLinks.lastElementChild;
209 | // Correct link path
210 | var href = sourceLink.getAttribute('href');
211 | sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
212 | sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
213 | } else {
214 | // Localize demo links
215 | var demoLinks = aside.querySelectorAll('.demo-link');
216 | Array.prototype.forEach.call(demoLinks, function (demoLink) {
217 | if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
218 | demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
219 | }
220 | });
221 | }
222 |
223 | document.body.className = (document.body.className + ' learn-bar').trim();
224 | document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
225 | };
226 |
227 | Learn.prototype.fetchIssueCount = function () {
228 | var issueLink = document.getElementById('issue-count-link');
229 | if (issueLink) {
230 | var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
231 | var xhr = new XMLHttpRequest();
232 | xhr.open('GET', url, true);
233 | xhr.onload = function (e) {
234 | var parsedResponse = JSON.parse(e.target.responseText);
235 | if (parsedResponse instanceof Array) {
236 | var count = parsedResponse.length;
237 | if (count !== 0) {
238 | issueLink.innerHTML = 'This app has ' + count + ' open issues';
239 | document.getElementById('issue-count').style.display = 'inline';
240 | }
241 | }
242 | };
243 | xhr.send();
244 | }
245 | };
246 |
247 | redirect();
248 | // getFile('learn.json', Learn);
249 | })();
250 |
--------------------------------------------------------------------------------
/todomvc/vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "dependencies": {
4 | "director": "^1.2.8",
5 | "vue": "^1.0.24",
6 | "todomvc-common": "^1.0.2",
7 | "todomvc-app-css": "^2.0.6"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/todomvc/vue/readme.md:
--------------------------------------------------------------------------------
1 | # Vue.js TodoMVC Example
2 |
3 | > Vue.js is a library for building interactive web interfaces.
4 | It provides data-driven, nestable view components with a simple and flexible API.
5 |
6 | > _[Vue.js - vuejs.org](http://vuejs.org)_
7 |
8 | ## Learning Vue.js
9 |
10 | The [Vue.js website](http://vuejs.org/) is a great resource to get started.
11 |
12 | Here are some links you may find helpful:
13 |
14 | * [Official Guide](http://vuejs.org/guide/)
15 | * [API Reference](http://vuejs.org/api/)
16 | * [Examples](http://vuejs.org/examples/)
17 | * [Building Larger Apps with Vue.js](http://vuejs.org/guide/application.html)
18 |
19 | Get help from other Vue.js users:
20 |
21 | * [Vue.js on Twitter](https://twitter.com/vuejs)
22 | * [Vue.js on Gitter](https://gitter.im/vuejs/vue)
23 | * [Vue.js Forum](http://forum.vuejs.org)
24 |
25 | _If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
26 |
27 | ## Credit
28 |
29 | This TodoMVC application was created by [Evan You](http://evanyou.me).
30 |
--------------------------------------------------------------------------------
/todomvc/yew/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Yew • TodoMVC
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/todomvc/yew/todomvc.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivanceras/sauron-perf/fec748b89e00ca85ef9bd12cee6431979151f76b/todomvc/yew/todomvc.wasm
--------------------------------------------------------------------------------