Commit 87d90ac8 authored by Pascal Hartig's avatar Pascal Hartig Committed by Sindre Sorhus

TroopJS Update

Closes #422
parent bd8155f5
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Troop.js • TodoMVC</title> <title>Troop.js • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css"> <link rel="stylesheet" href="../../../assets/base.css">
<!-- CSS overrides - remove if you don't need it -->
<link rel="stylesheet" href="css/app.css"> <link rel="stylesheet" href="css/app.css">
<!--[if IE]> <!--[if IE]>
<script src="../../../assets/ie.js"></script> <script src="../../../assets/ie.js"></script>
...@@ -17,17 +16,13 @@ ...@@ -17,17 +16,13 @@
<h1>todos</h1> <h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?" autofocus data-weave="widget/create"> <input id="new-todo" placeholder="What needs to be done?" autofocus data-weave="widget/create">
</header> </header>
<!-- This section should be hidden by default and shown when there are todos -->
<section id="main" data-weave="widget/display"> <section id="main" data-weave="widget/display">
<input id="toggle-all" type="checkbox" data-weave="widget/mark"> <input id="toggle-all" type="checkbox" data-weave="widget/mark">
<label for="toggle-all">Mark all as complete</label> <label for="toggle-all">Mark all as complete</label>
<ul id="todo-list" data-weave="widget/list"></ul> <ul id="todo-list" data-weave="widget/list"></ul>
</section> </section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer id="footer" data-weave="widget/display"> <footer id="footer" data-weave="widget/display">
<!-- This should be `0 items left` by default -->
<span id="todo-count" data-weave="widget/count"><strong>0</strong> items left</span> <span id="todo-count" data-weave="widget/count"><strong>0</strong> items left</span>
<!-- Remove this if you don't implement routing -->
<ul id="filters" data-weave="widget/filters"> <ul id="filters" data-weave="widget/filters">
<li> <li>
<a href="#/">All</a> <a href="#/">All</a>
...@@ -44,11 +39,9 @@ ...@@ -44,11 +39,9 @@
</section> </section>
<footer id="info"> <footer id="info">
<p>Double-click to edit a todo</p> <p>Double-click to edit a todo</p>
<!-- Change this out with your name and url ↓ -->
<p>Created by <a href="http://github.com/mikaelkaron">Mikael Karon</a></p> <p>Created by <a href="http://github.com/mikaelkaron">Mikael Karon</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p> <p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer> </footer>
<!-- Scripts here. Don't remove this ↓ -->
<script src="../../../assets/base.js"></script> <script src="../../../assets/base.js"></script>
<script type="text/javascript" data-main="js/app.js" src="../../../assets/require.min.js"></script> <script type="text/javascript" data-main="js/app.js" src="../../../assets/require.min.js"></script>
</body> </body>
......
require({ require({
"paths" : { 'paths': {
"jquery" : "../../../../assets/jquery.min", 'jquery': '../../../../assets/jquery.min',
"troopjs-bundle" : "lib/troopjs-bundle.min" 'troopjs-bundle': 'lib/troopjs-bundle.min'
}, }
}, [ "require", "jquery", "troopjs-bundle" ], function Deps(parentRequire, jQuery) { }, [ 'require', 'jquery', 'troopjs-bundle' ], function Deps(parentRequire, jQuery) {
// Application and plug-ins // Application and plug-ins
parentRequire([ parentRequire([
"widget/application", 'widget/application',
"troopjs-jquery/weave", 'troopjs-jquery/weave',
"troopjs-jquery/destroy", 'troopjs-jquery/destroy',
"troopjs-jquery/hashchange", 'troopjs-jquery/hashchange',
"troopjs-jquery/action" ], function App(Application) { 'troopjs-jquery/action' ], function App(Application) {
// Hook ready // Hook ready
jQuery(document).ready(function ready($) { jQuery(document).ready(function ready($) {
Application($(this.body), "app/todos").start(); Application($(this.body), 'app/todos').start();
}); });
}); });
}); });
define({ define({
"store": "todos-troopjs" 'store': 'todos-troopjs'
}); });
define( [ "troopjs-core/widget/application", "troopjs-core/route/router", "jquery" ], function ApplicationModule(Application, Router, $) { define( [ 'troopjs-core/widget/application', 'troopjs-core/route/router', 'jquery' ], function ApplicationModule(Application, Router, $) {
function forward(signal, deferred) { function forward(signal, deferred) {
var services = $.map(this.services, function map(service, index) { var services = $.map(this.services, function map(service, index) {
...@@ -13,11 +13,11 @@ define( [ "troopjs-core/widget/application", "troopjs-core/route/router", "jquer ...@@ -13,11 +13,11 @@ define( [ "troopjs-core/widget/application", "troopjs-core/route/router", "jquer
} }
return Application.extend({ return Application.extend({
"sig/initialize" : forward, 'sig/initialize': forward,
"sig/finalize" : forward, 'sig/finalize': forward,
"sig/start" : forward, 'sig/start': forward,
"sif/stop" : forward, 'sif/stop': forward,
services : [ Router($(window)) ] services: [ Router($(window)) ]
}); });
}); });
define( [ "troopjs-core/component/widget", "jquery" ], function ClearModule(Widget, $) { define( [ 'troopjs-core/component/widget', 'jquery' ], function ClearModule(Widget, $) {
function filter(item, index) { function filter(item, index) {
return item === null || !item.completed; return item === null || !item.completed;
} }
return Widget.extend({ return Widget.extend({
"hub:memory/todos/change" : function onChange(topic, items) { 'hub:memory/todos/change': function onChange(topic, items) {
var count = $.grep(items, filter, true).length; var count = $.grep(items, filter, true).length;
this.$element.text("Clear completed (" + count + ")")[count > 0 ? "show" : "hide"](); this.$element.text('Clear completed (' + count + ')')[count > 0 ? 'show' : 'hide']();
}, },
"dom/click" : function onClear(topic, $event) { 'dom/click': function onClear(topic, $event) {
this.publish("todos/clear"); this.publish('todos/clear');
} }
}); });
}); });
define( [ "troopjs-core/component/widget", "jquery" ], function CountModule(Widget, $) { define( [ 'troopjs-core/component/widget', 'jquery' ], function CountModule(Widget, $) {
function filter(item, index) { function filter(item, index) {
return item === null || item.completed; return item === null || item.completed;
} }
return Widget.extend({ return Widget.extend({
"hub:memory/todos/change" : function onChange(topic, items) { 'hub:memory/todos/change': function onChange(topic, items) {
var count = $.grep(items, filter, true).length; var count = $.grep(items, filter, true).length;
this.$element.html("<strong>" + count + "</strong> " + (count === 1 ? "item" : "items") + " left"); this.$element.html('<strong>' + count + '</strong> ' + (count === 1 ? 'item' : 'items') + ' left');
} }
}); });
}); });
define( [ "troopjs-core/component/widget" ], function CreateModule(Widget) { define( [ 'troopjs-core/component/widget' ], function CreateModule(Widget) {
var ENTER_KEY = 13; var ENTER_KEY = 13;
return Widget.extend({ return Widget.extend({
"dom/keyup" : function onKeyUp(topic, $event) { 'dom/keyup': function onKeyUp(topic, $event) {
var self = this; var $element = this.$element;
var $element = self.$element;
var value; var value;
switch($event.keyCode) { if ($event.keyCode === ENTER_KEY) {
case ENTER_KEY:
value = $element.val().trim(); value = $element.val().trim();
if (value !== "") { if (value !== '') {
self.publish("todos/add", value); this.publish('todos/add', value);
$element.val(""); $element.val('');
} }
} }
} }
......
define( [ "troopjs-core/component/widget", "jquery" ], function DisplayModule(Widget, $) { define( [ 'troopjs-core/component/widget', 'jquery' ], function DisplayModule(Widget, $) {
function filter(item, index) { function filter(item, index) {
return item === null; return item === null;
} }
return Widget.extend({ return Widget.extend({
"hub:memory/todos/change": function onChange(topic, items) { 'hub:memory/todos/change': function onChange(topic, items) {
this.$element[$.grep(items, filter, true).length > 0 ? "show" : "hide"](); this.$element[$.grep(items, filter, true).length > 0 ? 'show' : 'hide']();
} }
}); });
}); });
define( ['jquery'], function EscapeModule($) {
var entityMap = {
escape: {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'/': '&#x2F;'
}
},
invert = function(obj) {
var result = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
result[obj[key]] = key;
}
}
return result;
},
nativeKeys = Object.keys,
keys = nativeKeys || function(obj) {
if (obj !== Object(obj)) {
throw new TypeError('Invalid object');
}
var keys = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys[keys.length] = key;
}
}
return keys;
};
exports = {};
entityMap.unescape = invert(entityMap.escape);
var entityRegexes = {
escape: new RegExp('[' + keys(entityMap.escape).join('') + ']', 'g'),
unescape: new RegExp('(' + keys(entityMap.unescape).join('|') + ')', 'g')
};
$.each(['escape', 'unescape'], function(i, method) {
exports[method] = function(string) {
if (string == null) {
return '';
}
return ('' + string).replace(entityRegexes[method], function(match) {
return entityMap[method][match];
});
};
});
return exports;
});
define( [ "troopjs-core/component/widget", "jquery" ], function FiltersModule(Widget, $) { define( [ 'troopjs-core/component/widget', 'jquery' ], function FiltersModule(Widget, $) {
return Widget.extend({ return Widget.extend({
"hub:memory/route" : function onRoute(topic, uri) { 'hub:memory/route': function onRoute(topic, uri) {
this.publish("todos/filter", uri.source); this.publish('todos/filter', uri.source);
}, },
"hub:memory/todos/filter" : function onFilter(topic, filter) { 'hub:memory/todos/filter': function onFilter(topic, filter) {
filter = filter || "/"; filter = filter || '/';
// Update UI // Update UI
$("a[href^='#']") $('a[href^="#"]')
.removeClass("selected") .removeClass('selected')
.filter("[href='#" + filter + "']") .filter('[href="#' + filter + '"]')
.addClass("selected"); .addClass('selected');
} }
}); });
}); });
<% <%
var i = data.i; var i = data.i;
var item = data.item; var item = data.item;
var title = data.itemTitle;
var completed = item.completed; var completed = item.completed;
%> %>
<li class="<%= (completed ? 'completed' : 'active') %>"> <li class="<%= (completed ? 'completed' : 'active') %>">
<div class="view" data-action="prepare(<%= i %>)"> <div class="view" data-action="prepare(<%= i %>)">
<input class="toggle" type="checkbox" <%= (completed ? 'checked' : '') %> data-action="status(<%= i %>)"> <input class="toggle" type="checkbox" <%= (completed ? 'checked' : '') %> data-action="status(<%= i %>)">
<label><%= item.title %></label> <label><%= title %></label>
<button class="destroy" data-action="delete(<%= i %>)"></button> <button class="destroy" data-action="delete(<%= i %>)"></button>
</div> </div>
<input class="edit" data-action="commit(<%= i %>)"> <input class="edit" data-action="commit(<%= i %>)">
......
define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", "template!./item.html" ], function ListModule(Widget, store, $, template) { define( [ './escape', 'troopjs-core/component/widget', 'troopjs-core/store/local', 'jquery', 'template!./item.html' ], function ListModule(Escaper, Widget, store, $, template) {
var ENTER_KEY = 13; var ENTER_KEY = 13;
var FILTER_ACTIVE = "filter-active"; var FILTER_ACTIVE = 'filter-active';
var FILTER_COMPLETED = "filter-completed"; var FILTER_COMPLETED = 'filter-completed';
function filter(item, index) { function filter(item, index) {
return item === null; return item === null;
...@@ -26,16 +26,17 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -26,16 +26,17 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
$.each(items, function itemIterator(i, item) { $.each(items, function itemIterator(i, item) {
// Append to self // Append to self
self.append(template, { self.append(template, {
"i": i, 'i': i,
"item": item 'item': item,
'itemTitle': Escaper.escape(item.title)
}); });
}); });
}) })
.done(function doneInit(items) { .done(function doneInit(items) {
self.publish("todos/change", items); self.publish('todos/change', items);
}); });
}, { }, {
"hub/todos/add" : function onAdd(topic, title) { 'hub/todos/add': function onAdd(topic, title) {
var self = this; var self = this;
// Defer set // Defer set
...@@ -50,14 +51,15 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -50,14 +51,15 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
// Create new item, store in items // Create new item, store in items
var item = items[i] = { var item = items[i] = {
"completed": false, 'completed': false,
"title": title 'title': title
}; };
// Append new item to self // Append new item to self
self.append(template, { self.append(template, {
"i": i, 'i': i,
"item": item 'item': item,
'itemTitle': Escaper.escape(item.title)
}); });
// Set items and resolve set // Set items and resolve set
...@@ -65,51 +67,51 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -65,51 +67,51 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
}); });
}) })
.done(function doneSet(items) { .done(function doneSet(items) {
self.publish("todos/change", items); self.publish('todos/change', items);
}); });
}, },
"hub/todos/mark" : function onMark(topic, value) { 'hub/todos/mark': function onMark(topic, value) {
this.$element.find(":checkbox").prop("checked", value).change(); this.$element.find(':checkbox').prop('checked', value).change();
}, },
"hub/todos/clear" : function onClear(topic) { 'hub/todos/clear': function onClear(topic) {
this.$element.find(".completed .destroy").click(); this.$element.find('.completed .destroy').click();
}, },
"hub:memory/todos/filter" : function onFilter(topic, filter) { 'hub:memory/todos/filter': function onFilter(topic, filter) {
var $element = this.$element; var $element = this.$element;
switch (filter) { switch (filter) {
case "/completed": case '/completed':
$element $element
.removeClass(FILTER_ACTIVE) .removeClass(FILTER_ACTIVE)
.addClass(FILTER_COMPLETED); .addClass(FILTER_COMPLETED);
break; break;
case "/active": case '/active':
$element $element
.removeClass(FILTER_COMPLETED) .removeClass(FILTER_COMPLETED)
.addClass(FILTER_ACTIVE); .addClass(FILTER_ACTIVE);
break; break;
default: default:
$element.removeClass([FILTER_ACTIVE, FILTER_COMPLETED].join(" ")); $element.removeClass([FILTER_ACTIVE, FILTER_COMPLETED].join(' '));
} }
}, },
"dom/action.change.click.dblclick.focusout.keyup" : $.noop, 'dom/action.change.click.dblclick.focusout.keyup': $.noop,
"dom/action/status.change" : function onStatus(topic, $event, index) { 'dom/action/status.change': function onStatus(topic, $event, index) {
var self = this; var self = this;
var $target = $($event.target); var $target = $($event.target);
var completed = $target.prop("checked"); var completed = $target.prop('checked');
// Update UI // Update UI
$target $target
.closest("li") .closest('li')
.toggleClass("completed", completed) .toggleClass('completed', completed)
.toggleClass("active", !completed); .toggleClass('active', !completed);
// Defer set // Defer set
$.Deferred(function deferredSet(deferSet) { $.Deferred(function deferredSet(deferSet) {
...@@ -126,16 +128,16 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -126,16 +128,16 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
}); });
}) })
.done(function doneSet(items) { .done(function doneSet(items) {
self.publish("todos/change", items); self.publish('todos/change', items);
}); });
}, },
"dom/action/delete.click" : function onDelete(topic, $event, index) { 'dom/action/delete.click': function onDelete(topic, $event, index) {
var self = this; var self = this;
// Update UI // Update UI
$($event.target) $($event.target)
.closest("li") .closest('li')
.remove(); .remove();
// Defer set // Defer set
...@@ -154,22 +156,22 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -154,22 +156,22 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
}); });
}) })
.done(function doneSet(items) { .done(function doneSet(items) {
self.publish("todos/change", items); self.publish('todos/change', items);
}); });
}, },
"dom/action/prepare.dblclick" : function onPrepare(topic, $event, index) { 'dom/action/prepare.dblclick': function onPrepare(topic, $event, index) {
var self = this; var self = this;
// Get LI and update // Get LI and update
var $li = $($event.target) var $li = $($event.target)
.closest("li") .closest('li')
.addClass("editing"); .addClass('editing');
// Get INPUT and disable // Get INPUT and disable
var $input = $li var $input = $li
.find("input") .find('input')
.prop("disabled", true); .prop('disabled', true);
// Defer get // Defer get
$.Deferred(function deferredGet(deferGet) { $.Deferred(function deferredGet(deferGet) {
...@@ -180,38 +182,37 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -180,38 +182,37 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
// Update input value, enable and select // Update input value, enable and select
$input $input
.val(items[index].title) .val(items[index].title)
.removeProp("disabled") .removeProp('disabled')
.focus(); .focus();
}) })
.fail(function failGet() { .fail(function failGet() {
$li.removeClass("editing"); $li.removeClass('editing');
}); });
}, },
"dom/action/commit.keyup" : function onCommitKeyUp(topic, $event) { 'dom/action/commit.keyup': function onCommitKeyUp(topic, $event) {
switch($event.originalEvent.keyCode) { if ($event.originalEvent.keyCode === ENTER_KEY) {
case ENTER_KEY:
$($event.target).focusout(); $($event.target).focusout();
} }
}, },
"dom/action/commit.focusout" : function onCommitFocusOut(topic, $event, index) { 'dom/action/commit.focusout': function onCommitFocusOut(topic, $event, index) {
var self = this; var self = this;
var $target = $($event.target); var $target = $($event.target);
var title = $target.val().trim(); var title = $target.val().trim();
if (title === "") { if (title === '') {
$target $target
.closest("li.editing") .closest('li.editing')
.removeClass("editing") .removeClass('editing')
.find(".destroy") .find('.destroy')
.click(); .click();
} }
else { else {
// Defer set // Defer set
$.Deferred(function deferredSet(deferSet) { $.Deferred(function deferredSet(deferSet) {
// Disable // Disable
$target.prop("disabled", true); $target.prop('disabled', true);
// Defer get // Defer get
$.Deferred(function deferredGet(deferGet) { $.Deferred(function deferredGet(deferGet) {
...@@ -229,16 +230,16 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery", ...@@ -229,16 +230,16 @@ define( [ "troopjs-core/component/widget", "troopjs-core/store/local", "jquery",
.done(function doneSet(items) { .done(function doneSet(items) {
// Update UI // Update UI
$target $target
.closest("li") .closest('li')
.removeClass("editing") .removeClass('editing')
.find("label") .find('label')
.text(title); .text(title);
self.publish("todos/change", items); self.publish('todos/change', items);
}) })
.always(function alwaysSet() { .always(function alwaysSet() {
// Enable // Enable
$target.removeProp("disabled"); $target.removeProp('disabled');
}); });
} }
} }
......
define( [ "troopjs-core/component/widget" ], function MarkModule(Widget) { define( [ 'troopjs-core/component/widget' ], function MarkModule(Widget) {
return Widget.extend({ return Widget.extend({
"hub:memory/todos/change" : function onChange(topic, items) { 'hub:memory/todos/change': function onChange(topic, items) {
var total = 0; var total = 0;
var count = 0; var count = 0;
var $element = this.$element; var $element = this.$element;
...@@ -20,23 +20,23 @@ define( [ "troopjs-core/component/widget" ], function MarkModule(Widget) { ...@@ -20,23 +20,23 @@ define( [ "troopjs-core/component/widget" ], function MarkModule(Widget) {
if (count === 0) { if (count === 0) {
$element $element
.prop("indeterminate", false) .prop('indeterminate', false)
.prop("checked", false); .prop('checked', false);
} }
else if (count === total) { else if (count === total) {
$element $element
.prop("indeterminate", false) .prop('indeterminate', false)
.prop("checked", true); .prop('checked', true);
} }
else { else {
$element $element
.prop("indeterminate", true) .prop('indeterminate', true)
.prop("checked", false); .prop('checked', false);
} }
}, },
"dom/change" : function onMark(topic, $event) { 'dom/change': function onMark(topic, $event) {
this.publish("todos/mark", $($event.target).prop("checked")); this.publish('todos/mark', $($event.target).prop('checked'));
} }
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment