Commit e65f8fd3 authored by Pascal Hartig's avatar Pascal Hartig

The Big Examples Move 🚚

Moved all examples into `examples/`.

Fix #1016
parent b1c4be5f

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

...@@ -4,7 +4,7 @@ We have created this short spec to help you create awesome and consistent todo a ...@@ -4,7 +4,7 @@ We have created this short spec to help you create awesome and consistent todo a
## Template Application ## Template Application
Our [template](https://github.com/tastejs/todomvc/tree/master/template) should be used as the base when implementing a todo app. Before implementing, we recommend you interact with some of the other apps to see how they're built and how they behave. Check out the [Backbone app](http://todomvc.com/architecture-examples/backbone) if you need a reference implementation. If something is unclear or could be improved, [let us know](https://github.com/tastejs/todomvc/issues). Our [template](https://github.com/tastejs/todomvc/tree/master/template) should be used as the base when implementing a todo app. Before implementing, we recommend you interact with some of the other apps to see how they're built and how they behave. Check out the [Backbone app](http://todomvc.com/examples/backbone) if you need a reference implementation. If something is unclear or could be improved, [let us know](https://github.com/tastejs/todomvc/issues).
## Structure ## Structure
......
{
"id" : "todomvc",
"inputs" : "js/app.js",
"paths" : "js/",
"output-wrapper" : "(function(){%output%})();",
"mode" : "ADVANCED",
"define" : {
"goog.LOCALE": "en_GB"
},
"checks": {
// Unfortunately, the Closure Library violates these in many places.
// "accessControls": "ERROR",
// "visibility": "ERROR"
"checkRegExp": "WARNING",
"checkTypes": "WARNING",
"checkVars": "WARNING",
"deprecated": "WARNING",
"fileoverviewTags": "WARNING",
"invalidCasts": "WARNING",
"missingProperties": "WARNING",
"nonStandardJsDocs": "WARNING",
"undefinedVars": "WARNING"
}
}
#clear-completed, #footer, #main,
.plural {
display: none;
}
#todoapp.todos_selected #clear-completed,
#todoapp.todos_present #footer,
#todoapp.todos_present #main,
.multiple .plural {
display: inherit;
}
#todo-list li.hidden {
display: none;
}
#todo-list li .toggle.dijitChecked:after {
color: #85ada7;
text-shadow: 0 1px 0 #669991;
bottom: 1px;
position: relative;
}
/* When checkbox is selected, score through todo item content */
.dijitCheckBoxChecked + .todo-content {
color: #666;
text-decoration: line-through;
}
/* When checkbox is selected, score through todo item content after an edit */
.dijitCheckBoxChecked + .dijitInline + .todo-content {
color: #666;
text-decoration: line-through;
}
#todo-list .dijitCheckBoxInput {
opacity: 0;
position: absolute;
top: 14px;
z-index: 10;
}
/** Match up inline edit box with styling */
.dijitInputInner {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#todo-list li .dijitInputInner {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
margin: 0 0 0 43px;
z-index: 10;
}
/** Ugh, force override of edit container margin */
#todo-list li span.dijitInline {
margin: 0 !important;
}
/**
* Inline edit box doesn't provide indication via class names
* when a box is 'live'. Style values are set manually. Use the
* opacity change as indicator... :( */
.inline_edit[style~='0;'] ~ .toggle {
visibility: hidden !important;
}
.dijitOffScreen { /* For 1.8 in-line edit box */
position: absolute !important;
left: 50% !important;
top: -10000px !important;
}
/**
* Original source from https://gist.github.com/880822
* Converted to AMD-baseless format
*/
define(["dojo/_base/declare",
// Parent classes
"dijit/_WidgetBase", "dijit/_TemplatedMixin", "dijit/_WidgetsInTemplateMixin",
// General application modules
"dojo/_base/lang", "dojo/_base/event", "dojo/on", "dojo/dom-class", "dojo/dom-attr", "dojo/query", "dojo/string",
"dijit/_base/manager", "dojo/keys", "dojox/mvc", "dojo/hash", "dojo/_base/connect", "todo/model/TodoModel",
// Widget template
"dojo/text!./app.html",
// Template Widgets
"todo/form/InlineEditBox", "todo/form/CheckBox", "dojox/mvc/Group", "dojox/mvc/Repeat", "dojox/mvc/Output"],
function(declare, _WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, lang, _event, on, domClass, domAttr,
query, str, manager, keys, mvc, hash, connect, TodoModel, template) {
return declare("todo.app", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
/** Widget template HTML string */
templateString: template,
/** Hash state constants */
ACTIVE: "/active",
COMPLETED: "/completed",
constructor: function () {
/**
* Create new application Model class, this will be used to bind
* the UI elements to the data store items. Pre-populate model with
* items from localStorage if they exist...
*/
this.model = new TodoModel();
/**
* The method below set up a function binding to the composite (complete & incomplete)
* model attributes. These values are used to append CSS classes to dynamically show & hide
* the "stats" elements when the model is non-empty and has some completed items. Whenever
* the values below are updated, the function will be executed.
*/
mvc.bindInputs([this.model.complete, this.model.incomplete], lang.hitch(this, "onItemStatusUpdate"));
/**
* Hook into unload event to trigger persisting
* of the current model contents into the localStorage
* backed data store.
*/
window.onbeforeunload = lang.hitch(this, function () {
this.model.commit();
});
/** Connect to changes to the URI hash */
connect.subscribe("/dojo/hashchange", this, "onHashChange");
},
/**
* Listen for item remove events from the using event delegation,
* we don't have to attach to each item. Also, ensure todo-stats
* have the correct initial CSS classes given the starting model
* contents.
*/
postCreate: function () {
on(this.domNode, ".destroy:click", lang.hitch(this, "onRemove"));
on(this.domNode, ".view:dblclick", lang.hitch(this, "onEdit"));
this.onItemStatusUpdate();
},
/**
* Ensure application state reflects current
* hash value after rendering model in the view.
*/
startup: function () {
this.inherited(arguments);
this.onHashChange(hash());
},
/**
* Remove all items that have been completed from
* model. We have to individually check each todo
* item, removing if true.
*/
removeCompletedItems: function () {
var len = this.model.todos.length, idx = 0;
/**
* Removing array indices from a Dojo MVC Model
* array left-shifts the remaining items. When
* we find an item to remove, don't increment the
* index and, instead, decrement the total item count.
*/
while (idx < len) {
if (this.model.todos[idx].completed.value) {
this.model.todos.remove(idx);
len--;
continue;
}
idx++;
}
},
/**
* Add new a new todo item as the last element
* in the parent model.
*/
addToModel: function (content, completed) {
var insert = mvc.newStatefulModel({
data: {title: content, completed: completed}
});
this.model.todos.add(this.model.todos.length, insert);
},
/**
* Adjust CSS classes on todo-stats element based upon whether
* we a number of completed and incomplete todo items.
* Also verify state of the "Mark All" box.
*/
onItemStatusUpdate: function () {
var completed = this.model.complete.get("value"),
length = this.model.todos.get("length");
domClass.toggle(this.domNode, "todos_selected", completed > 0);
domClass.toggle(this.domNode, "multiple", completed > 1);
domClass.toggle(this.domNode, "todos_present", length);
domAttr.set(this.mark_all, "checked", length && length === completed);
setTimeout(lang.hitch(this, "onHashChange", hash()));
},
/**
* Event fired when user selects the "Mark All" checkbox.
* Update selection state of all the todos based upon current
* checked value.
*/
onMarkAll: function () {
var checked = this.mark_all.checked;
for(var i = 0, len = this.model.todos.length; i < len; i++) {
this.model.todos[i].completed.set("value", checked);
}
},
/**
* Handle key press events for the todo input
* field. If user has pressed enter, add current
* text value as new todo item in the model.
*/
onKeyPress: function (event) {
if (event.keyCode !== keys.ENTER ||
!str.trim(event.target.value).length) {
return;
}
this.addToModel(event.target.value, false);
event.target.value = "";
_event.stop(event);
},
/**
* Event handler when user has clicked to
* remove a todo item, just remove it from the
* model using the item identifier.
*/
onRemove: function (event) {
this.model.todos.remove(domAttr.get(event.target, "data-model-id"));
},
/**
* Whenever the user double clicks the item label,
* set inline edit box to true.
*/
onEdit: function (event) {
query(".inline_edit", event.target).forEach(function (inline_edit) {
manager.byNode(inline_edit).edit();
});
},
/**
* When the URI's hash value changes, modify the
* displayed list items to show either completed,
* remaining or all tasks.
* Also highlight currently selected link value.
*/
onHashChange: function (hash) {
var showIfDone = (hash === this.COMPLETED ? false :
(hash === this.ACTIVE? true : null));
query("#todo-list > li").forEach(lang.hitch(this, function (item, idx) {
var done = this.model.todos[idx].completed.get("value");
domClass.toggle(item, "hidden", done === showIfDone);
}));
/** Normalise hash value to match link hrefs */
hash = "#" + (showIfDone !== null ? hash : "/");
query("#filters a").forEach(lang.hitch(this, function (link) {
domClass.toggle(link, "selected", domAttr.get(link, "href") === hash);
}));
}
});
});
package com.todo.client;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.History;
import com.google.gwt.view.client.AbstractDataProvider;
import com.google.gwt.view.client.ListDataProvider;
import com.todo.client.ToDoItem;
import com.todo.client.ToDoRouting;
import com.todo.client.events.ToDoEvent;
import com.todo.client.events.ToDoRemovedEvent;
import com.todo.client.events.ToDoUpdatedEvent;
/**
* The presenter for the ToDo application. This class is responsible for the lifecycle of the
* {@link ToDoItem} instances.
*
* @author ceberhardt
* @author dprotti
*
*/
public class ToDoPresenter {
private static final String STORAGE_KEY = "todo-gwt";
/**
* The interface that a view for this presenter must implement.
*/
public interface View {
/**
* Gets the text that the user has input for the creation of new tasks.
*/
String getTaskText();
/**
* Clears the user input field where new tasks are added.
*/
void clearTaskText();
/**
* Sets the current task statistics.
*/
void setTaskStatistics(int totalTasks, int completedTasks);
/**
* Sets the data provider that acts as a source of {@link ToDoItem} instances.
*/
void setDataProvider(AbstractDataProvider<ToDoItem> data);
/**
* Adds the handler to the events raised by the view.
*/
void addhandler(ViewEventHandler handler);
/**
* Informs the view of the current routing state.
*/
void setRouting(ToDoRouting routing);
}
/**
* The interface that handles interactions from the view.
*/
public interface ViewEventHandler {
/**
* Invoked when a user adds a new task.
*/
void addTask();
/**
* Invoked when a user wishes to clear completed tasks.
*/
void clearCompletedTasks();
/**
* Sets the completed state of all tasks to the given state.
*/
void markAllCompleted(boolean completed);
}
/**
* Handler for view events, defers to private presenter methods.
*/
private final ViewEventHandler viewHandler = new ViewEventHandler() {
@Override
public void addTask() {
ToDoPresenter.this.addTask();
}
@Override
public void clearCompletedTasks() {
ToDoPresenter.this.clearCompletedTasks();
}
@Override
public void markAllCompleted(boolean completed) {
ToDoPresenter.this.markAllCompleted(completed);
}
};
private final List<ToDoItem> todos = new ArrayList<ToDoItem>();
private final ListDataProvider<ToDoItem> filteredTodos = new ListDataProvider<ToDoItem>();
private final View view;
private ToDoRouting routing = ToDoRouting.ALL;
private EventBus eventBus;
public ToDoPresenter(View view) {
this.view = view;
loadState();
String initialToken = History.getToken();
routing = parseRoutingToken(initialToken);
view.addhandler(viewHandler);
view.setDataProvider(filteredTodos);
view.setRouting(routing);
updateTaskStatistics();
setupHistoryHandler();
eventBus = ToDoEvent.getGlobalEventBus();
// listen to edits on individual items
eventBus.addHandler(ToDoUpdatedEvent.TYPE, new ToDoUpdatedEvent.Handler() {
@Override
public void onEvent(ToDoUpdatedEvent event) {
itemStateChanged(event.getToDo());
}
});
// listen to removals
eventBus.addHandler(ToDoRemovedEvent.TYPE, new ToDoRemovedEvent.Handler() {
@Override
public void onEvent(ToDoRemovedEvent event) {
deleteTask(event.getToDo());
}
});
}
/**
* Set up the history changed handler, which provides routing.
*/
private void setupHistoryHandler() {
History.addValueChangeHandler(new ValueChangeHandler<String>() {
public void onValueChange(ValueChangeEvent<String> event) {
String historyToken = event.getValue();
routing = parseRoutingToken(historyToken);
view.setRouting(routing);
updateFilteredList();
}
});
}
/**
* Converts the string routing token into the equivalent enum value.
*/
private ToDoRouting parseRoutingToken(String token ) {
if (token.equals("/active")) {
return ToDoRouting.ACTIVE;
} else if (token.equals("/completed")) {
return ToDoRouting.COMPLETED;
} else {
return ToDoRouting.ALL;
}
}
/**
* Updates the filtered list, which is rendered in the UI.
*/
private void updateFilteredList() {
filteredTodos.getList().clear();
for (ToDoItem task : todos) {
if (routing.getMatcher().matches(task)) {
filteredTodos.getList().add(task);
}
}
}
/**
* Computes the tasks statistics and updates the view.
*/
private void updateTaskStatistics() {
int totalTasks = todos.size();
int completeTask = 0;
for (ToDoItem task : todos) {
if (task.isCompleted()) {
completeTask++;
}
}
view.setTaskStatistics(totalTasks, completeTask);
}
/**
* Deletes the given task and updates statistics.
*/
protected void deleteTask(ToDoItem toDoItem) {
todos.remove(toDoItem);
taskStateChanged();
}
/**
* Invoked by a task when its state changes so that we can update the view statistics and persist.
*/
protected void itemStateChanged(ToDoItem toDoItem) {
toDoItem.setTitle(toDoItem.getTitle().trim());
if (toDoItem.getTitle().isEmpty()) {
todos.remove(toDoItem);
}
taskStateChanged();
}
/**
* When the task state has changed, this method will update the UI and persist.
*/
private void taskStateChanged() {
updateFilteredList();
updateTaskStatistics();
saveState();
}
/**
* Sets the completed state of all tasks.
*/
private void markAllCompleted(boolean completed) {
for (ToDoItem task : todos) {
task.setCompleted(completed);
}
taskStateChanged();
}
/**
* Adds a new task based on the user input field.
*/
private void addTask() {
String taskTitle = view.getTaskText().trim();
// if white-space only, do not add a todo
if (taskTitle.equals(""))
return;
ToDoItem toDoItem = new ToDoItem(taskTitle);
view.clearTaskText();
todos.add(toDoItem);
taskStateChanged();
}
/**
* Clears completed tasks and updates the view.
*/
private void clearCompletedTasks() {
Iterator<ToDoItem> iterator = todos.iterator();
while (iterator.hasNext()) {
ToDoItem item = iterator.next();
if (item.isCompleted()) {
iterator.remove();
}
}
taskStateChanged();
}
/**
* Saves the current to-do items to local storage.
*/
private void saveState() {
Storage storage = Storage.getLocalStorageIfSupported();
if (storage != null) {
// JSON encode the items
JSONArray todoItems = new JSONArray();
for (int i = 0; i < todos.size(); i++) {
ToDoItem toDoItem = todos.get(i);
JSONObject jsonObject = new JSONObject();
jsonObject.put("task", new JSONString(toDoItem.getTitle()));
jsonObject.put("complete", JSONBoolean.getInstance(toDoItem.isCompleted()));
todoItems.set(i, jsonObject);
}
// save to local storage
storage.setItem(STORAGE_KEY, todoItems.toString());
}
}
private void loadState() {
Storage storage = Storage.getLocalStorageIfSupported();
if (storage != null) {
try {
// get state
String state = storage.getItem(STORAGE_KEY);
// parse the JSON array
JSONArray todoItems = JSONParser.parseStrict(state).isArray();
for (int i = 0; i < todoItems.size(); i++) {
// extract the to-do item values
JSONObject jsonObject = todoItems.get(i).isObject();
String task = jsonObject.get("task").isString().stringValue();
boolean completed = jsonObject.get("complete").isBoolean().booleanValue();
// add a new item to our list
todos.add(new ToDoItem(task, completed));
}
} catch (Exception e) {
}
}
updateFilteredList();
}
}
{print} = require 'util'
{spawn} = require 'child_process'
task 'build', 'Build js/ from src/', ->
coffee = spawn 'coffee', ['-c', '-o', 'js', 'src']
coffee.stderr.on 'data', (data) ->
message = data.toString()
if message.search('is now called') < 0
process.stderr.write message
coffee.stdout.on 'data', (data) ->
print data.toString()
coffee.on 'exit', (code) ->
callback?() if code is 0
task 'watch', 'Watch src/ for changes', ->
coffee = spawn 'coffee', ['-w', '-c', '-o', 'js', 'src']
coffee.stderr.on 'data', (data) ->
process.stderr.write data.toString()
coffee.stdout.on 'data', (data) ->
print data.toString()
\ No newline at end of file
/**
* Backbone localStorage Adapter
* Version 1.1.3
*
* https://github.com/jeromegn/Backbone.localStorage
*/
(function (root, factory) {
if (typeof exports === 'object') {
module.exports = factory(require("underscore"), require("backbone"));
} else if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define(["underscore","backbone"], function(_, Backbone) {
// Use global variables if the locals are undefined.
return factory(_ || root._, Backbone || root.Backbone);
});
} else {
// RequireJS isn't being used. Assume underscore and backbone are loaded in <script> tags
factory(_, Backbone);
}
}(this, function(_, Backbone) {
// A simple module to replace `Backbone.sync` with *localStorage*-based
// persistence. Models are given GUIDS, and saved into a JSON object. Simple
// as that.
// Hold reference to Underscore.js and Backbone.js in the closure in order
// to make things work even if they are removed from the global namespace
// Generate four random hex digits.
function S4() {
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
};
// Generate a pseudo-GUID by concatenating random hexadecimal.
function guid() {
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
};
// Our Store is represented by a single JS object in *localStorage*. Create it
// with a meaningful name, like the name you'd give a table.
// window.Store is deprectated, use Backbone.LocalStorage instead
Backbone.LocalStorage = window.Store = function(name) {
this.name = name;
var store = this.localStorage().getItem(this.name);
this.records = (store && store.split(",")) || [];
};
_.extend(Backbone.LocalStorage.prototype, {
// Save the current state of the **Store** to *localStorage*.
save: function() {
this.localStorage().setItem(this.name, this.records.join(","));
},
// Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
// have an id of it's own.
create: function(model) {
if (!model.id) {
model.id = guid();
model.set(model.idAttribute, model.id);
}
this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
this.records.push(model.id.toString());
this.save();
return this.find(model);
},
// Update a model by replacing its copy in `this.data`.
update: function(model) {
this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
if (!_.include(this.records, model.id.toString()))
this.records.push(model.id.toString()); this.save();
return this.find(model);
},
// Retrieve a model from `this.data` by id.
find: function(model) {
return this.jsonData(this.localStorage().getItem(this.name+"-"+model.id));
},
// Return the array of all models currently in storage.
findAll: function() {
// Lodash removed _#chain in v1.0.0-rc.1
return (_.chain || _)(this.records)
.map(function(id){
return this.jsonData(this.localStorage().getItem(this.name+"-"+id));
}, this)
.compact()
.value();
},
// Delete a model from `this.data`, returning it.
destroy: function(model) {
if (model.isNew())
return false
this.localStorage().removeItem(this.name+"-"+model.id);
this.records = _.reject(this.records, function(id){
return id === model.id.toString();
});
this.save();
return model;
},
localStorage: function() {
return localStorage;
},
// fix for "illegal access" error on Android when JSON.parse is passed null
jsonData: function (data) {
return data && JSON.parse(data);
},
// Clear localStorage for specific collection.
_clear: function() {
var local = this.localStorage(),
itemRe = new RegExp("^" + this.name + "-");
// Remove id-tracking item (e.g., "foo").
local.removeItem(this.name);
// Lodash removed _#chain in v1.0.0-rc.1
// Match all data items (e.g., "foo-ID") and remove.
(_.chain || _)(local).keys()
.filter(function (k) { return itemRe.test(k); })
.each(function (k) { local.removeItem(k); });
},
// Size of localStorage.
_storageSize: function() {
return this.localStorage().length;
}
});
// localSync delegate to the model or collection's
// *localStorage* property, which should be an instance of `Store`.
// window.Store.sync and Backbone.localSync is deprecated, use Backbone.LocalStorage.sync instead
Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options) {
var store = model.localStorage || model.collection.localStorage;
var resp, errorMessage, syncDfd = Backbone.$.Deferred && Backbone.$.Deferred(); //If $ is having Deferred - use it.
try {
switch (method) {
case "read":
resp = model.id != undefined ? store.find(model) : store.findAll();
break;
case "create":
resp = store.create(model);
break;
case "update":
resp = store.update(model);
break;
case "delete":
resp = store.destroy(model);
break;
}
} catch(error) {
if (error.code === DOMException.QUOTA_EXCEEDED_ERR && store._storageSize() === 0)
errorMessage = "Private browsing is unsupported";
else
errorMessage = error.message;
}
if (resp) {
if (options && options.success) {
if (Backbone.VERSION === "0.9.10") {
options.success(model, resp, options);
} else {
options.success(resp);
}
}
if (syncDfd) {
syncDfd.resolve(resp);
}
} else {
errorMessage = errorMessage ? errorMessage
: "Record Not Found";
if (options && options.error)
if (Backbone.VERSION === "0.9.10") {
options.error(model, errorMessage, options);
} else {
options.error(errorMessage);
}
if (syncDfd)
syncDfd.reject(errorMessage);
}
// add compatibility with $.ajax
// always execute callback for success and error
if (options && options.complete) options.complete(resp);
return syncDfd && syncDfd.promise();
};
Backbone.ajaxSync = Backbone.sync;
Backbone.getSyncMethod = function(model) {
if(model.localStorage || (model.collection && model.collection.localStorage)) {
return Backbone.localSync;
}
return Backbone.ajaxSync;
};
// Override 'Backbone.sync' to default to localSync,
// the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
Backbone.sync = function(method, model, options) {
return Backbone.getSyncMethod(model).apply(this, [method, model, options]);
};
return Backbone.LocalStorage;
}));
/*
Aristocrat version 1.0.1
Copyright (c) 2012, Peter Michaux
All rights reserved.
Licensed under the Simplified BSD License.
https://github.com/petermichaux/aristocrat/blob/master/LICENSE
*/
var aristocrat = {};
(function() {
var regExpCache = {};
function getRegExp(className) {
return Object.prototype.hasOwnProperty.call(regExpCache, className) ?
regExpCache[className] :
(regExpCache[className] = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)'));
}
/**
@property aristocrat.hasClass
@parameter element {Element} The DOM element to test.
@parameter className {string} The class name to test for on element.
@returns {boolean}
@description
Tests if element has className in the element.className property.
aristocrat.hasClass(document.body, 'king');
*/
var hasClass = aristocrat.hasClass = function(el, className) {
return getRegExp(className).test(el.className);
};
/**
@property aristocrat.addClass
@parameter element {Element} The DOM element to test.
@parameter className {string} The class name to add to element.
@description
Add className to element.className if className is not already in element.className.
aristocrat.addClass(document.body, 'king');
*/
var addClass = aristocrat.addClass = function(el, className) {
if (!hasClass(el, className)) {
el.className = el.className + ' ' + className;
}
};
/**
@property aristocrat.removeClass
@parameter element {Element} The DOM element to test.
@parameter className {string} The class name to remove from element.
@description
Removes all occurrences of className in element.className.
aristocrat.removeClass(document.body, 'king');
*/
var removeClass = aristocrat.removeClass = function(el, className) {
var re = getRegExp(className);
while (re.test(el.className)) { // in case multiple occurrences
el.className = el.className.replace(re, ' ');
}
};
/**
@property aristocrat.toggleClass
@parameter element {Element} The DOM element to test.
@parameter className {string} The class name to toggle on element.
@description
If element.className has className then className is removed. Otherwise
className is added.
aristocrat.toggleClass(document.body, 'king');
*/
aristocrat.toggleClass = function(el, className) {
if (hasClass(el, className)) {
removeClass(el, className);
}
else {
addClass(el, className);
}
};
}());
<!DOCTYPE html>
<!--
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
<title>Selection</title>
<script src="../platform/platform.js"></script>
<link rel="import" href="core-selection.html">
</head>
<body unresolved>
<polymer-element name="selection-example">
<template>
<style>
polyfill-next-selector { content: 'ul > *'; }
::content > * {
cursor: pointer;
}
polyfill-next-selector { content: 'ul > .selected'; }
::content > .selected {
font-weight: bold;
font-style: italic;
}
</style>
<ul on-tap="{{itemTapAction}}">
<content></content>
</ul>
<core-selection id="selection" multi on-core-select="{{selectAction}}"></core-selection>
</template>
<script>
Polymer('selection-example', {
itemTapAction: function(e, detail, sender) {
this.$.selection.select(e.target);
},
selectAction: function(e, detail, sender) {
detail.item.classList.toggle('selected', detail.isSelected);
}
});
</script>
</polymer-element>
<selection-example>
<li>Red</li>
<li>Green</li>
<li>Blue</li>
</selection-example>
</body>
</html>
Platform
========
Aggregated polyfills the Polymer platform.
[![Analytics](https://ga-beacon.appspot.com/UA-39334307-2/Polymer/platform/README)](https://github.com/igrigorik/ga-beacon)
<!--
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="layout.html">
<script src="polymer.js"></script>
<!--<link rel="import" href="../polymer-dev/polymer.html">-->
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -22,7 +22,7 @@ We think it's best for the project if the code you write looks like the code the ...@@ -22,7 +22,7 @@ We think it's best for the project if the code you write looks like the code the
- **Read the [App Specification](app-spec.md) thoroughly** - **Read the [App Specification](app-spec.md) thoroughly**
- Use the [automated browser tests](/browser-tests) to ensure that your app meets the app specification requirements. For bonus points add the test output to your pull request! - Use the [automated browser tests](/browser-tests) to ensure that your app meets the app specification requirements. For bonus points add the test output to your pull request!
- Make sure it hasn't already been submitted or declined by searching the issue tracker - Make sure it hasn't already been submitted or declined by searching the issue tracker
- Looking at our most recent [reference app](https://github.com/tastejs/todomvc/tree/master/architecture-examples/backbone) - Looking at our most recent [reference app](https://github.com/tastejs/todomvc/tree/master/examples/backbone)
One of us will be happy to review your submission and discuss any changes that may be required before it can be included. Apps will typically land first in Labs, reaching the 'stable' mark once we and the community are happy with it. One of us will be happy to review your submission and discuss any changes that may be required before it can be included. Apps will typically land first in Labs, reaching the 'stable' mark once we and the community are happy with it.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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