diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..8e5efd1f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea/
+/assets/js/config.js
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..b95a8dbb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000..94a25f7f
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/wafs.iml b/.idea/wafs.iml
new file mode 100644
index 00000000..24643cc3
--- /dev/null
+++ b/.idea/wafs.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 4a35ee0f..f2b26613 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,53 @@
The course repo for 'Web App From Scratch'
## Advantages and disadvantages of JavaScript libraries/frameworks
-...
+
+Advantages
+* Less code to write.
+* Quicker to make applications (less costs)
+* Support from communities or development teams
+* More readable code
+* No browser compatibility problems
+* Code is more secure because more people can evaluate it.
+
+Disadvantages
+* Security flaws can be detected easier because it's open source.
+* Limited possibilities because of the framework.
+* You don't learn the underlying code properly
+* They often lack functionality that a project needs.
+* Less performance because of loading unnecessary code.
+* More new things to learn if framework/library updates it code
+* Dependent on others work
## Advantages and disadvantages of client-side single page web apps
-...
+
+Advantages
+* Better user experience because you only have to load once.
+* Quick in use after loading.
+* Back-end and front-end are separated
+* Easier to make mobile app because back-end is reusable.
+
+Disadvantages
+* Hard to implemented SEO properly
+* Bad performance because it's heavy (especially for mobile devices).
+* Heavy client side frameworks are needed to load the app.
+* Site getting slower when data increases
+* JavaScript is often needed use the page (bad accessibility)
+* Analytics tools don't expect single page web apps.
## Best practices
-...
+* Don't use global variables/objects
+* Declare variables at top of scope
+* Use short clear meaningful names (English)
+* Work in strict mode
+* camelCase your code if(code != Constructor || CONSTANTS)
+* Place external scripts at the bottom of the page
+* Indent your code
+
+## Pull requests
+### Week 1
+* https://github.com/velomovies/wafs/pull/1
+* https://github.com/dipsaus9/wafs/pull/1
+
+### Week 2
+* https://github.com/velomovies/wafs/pull/5
\ No newline at end of file
diff --git a/app/index.html b/app/index.html
deleted file mode 100644
index e69de29b..00000000
diff --git a/app/static/css/styles.css b/app/static/css/styles.css
deleted file mode 100644
index e69de29b..00000000
diff --git a/app/static/js/script.js b/app/static/js/script.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/assets/css/style.css b/assets/css/style.css
new file mode 100644
index 00000000..30b9f7d4
--- /dev/null
+++ b/assets/css/style.css
@@ -0,0 +1,113 @@
+* {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Roboto', sans-serif;;
+ margin: 0;
+ color: #212121;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+h1 {
+ font-size: 2rem;
+ letter-spacing: 1px;
+}
+
+h2 {
+ font-weight: normal;
+ font-size: 1.5rem;
+ color: rgba(0,0,0,0.6);
+}
+
+nav {
+ //background: #212121;
+ height: 3.5rem;
+ display: flex;
+ align-items: center;
+}
+
+nav ul {
+ max-width: 50rem;
+ display: flex;
+ padding: 0;
+}
+
+nav ul li {
+ list-style: none;
+ padding-right: 1.5rem;
+}
+
+a {
+ text-decoration: none;
+ color: #157EE7;
+}
+
+a:hover {
+ color: #1468c7;
+}
+
+img {
+ border-radius: 0.25rem;
+}
+
+.container {
+ width: 100%;
+ max-width: 50rem;
+ margin: 0 auto;
+ padding: 1.5rem;
+}
+
+.hidden {
+ display: none;
+}
+
+#track-list {
+ padding: 0;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+#track-list li {
+ list-style: none;
+ width: 25%;
+ padding: 0.5rem;
+ transition: all cubic-bezier(0.5, 2.44, 0.6, 1.06) .25s;
+}
+
+#track-list li:hover {
+ transform: scale(1.05);
+}
+
+#track-list img {
+ max-width: 100%;
+}
+
+#track-list li div {
+ position: relative;
+ overflow: hidden;
+}
+
+
+#track-list li a {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ top: 0;
+ display: flex;
+ color: #fff;
+ flex-direction: column;
+ justify-content: flex-end;
+ background-image: linear-gradient(-180deg, rgba(0,0,0,0.00) 0%, rgba(0,0,0,0.40) 68%, rgba(0,0,0,0.59) 100%);
+ padding: 1rem;
+ transform: translateY(5%);
+ opacity: 0;
+ transition: all ease-in-out .15s;
+}
+
+#track-list li:hover a {
+ transform: translateY(0%);
+ opacity: 1;
+}
\ No newline at end of file
diff --git a/assets/js/app.js b/assets/js/app.js
new file mode 100644
index 00000000..105463dc
--- /dev/null
+++ b/assets/js/app.js
@@ -0,0 +1,240 @@
+(function () {
+ "use strict"
+
+ // General app object
+ var app = {
+ init: function() {
+
+ if(!location.hash) {
+ routie('now-playing');
+ }
+
+ nav.init()
+ api.handleRecentTrackData()
+ }
+ }
+
+ // Adding event listeners to a elements to prevent the default scroll behaviour
+ var nav = {
+ init: function () {
+ document.querySelectorAll("nav a").forEach(function (element){
+ element.addEventListener("click", function(event) {
+ event.preventDefault()
+ location.hash = this.hash
+ })
+ })
+ }
+ }
+
+ // Object with content en render functions
+ var content = {
+ "current-track": "",
+ trackList: [],
+ render: function () {
+ // Render now playing text using transparencyjs
+ Transparency.render(document.getElementById('now-playing'), this);
+
+ // Add tracklist to html
+ this.trackList.forEach(function (item) {
+ document.querySelector("#track-list").innerHTML += '
'
+ })
+ }
+ }
+
+ // Api functions
+ var api = {
+ // Last fm user
+ user: "jelleoverbeek",
+ // return format of API (JSON/XML)
+ format: "json",
+ // Get the recent tracks from API
+ getRecentTracks: function () {
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ var request = new XMLHttpRequest(),
+ limit = 50,
+ url = "https://ws.audioscrobbler.com/2.0?method=user.getrecenttracks&user=" + self.user + "&api_key=" + config.key + "&format=" + self.format + "&limit=" + limit
+
+ request.open('GET', url, true)
+
+ request.onload = function() {
+ if (request.status >= 200 && request.status < 400) {
+ var data = JSON.parse(request.responseText);
+ resolve(data)
+ } else {
+ reject('error')
+ }
+ }
+
+ request.onerror = function() {
+ reject('error');
+ }
+
+ request.send()
+ });
+ },
+ // Get individual track info form API
+ getTrackInfo: function (mbid, artist, name) {
+ var self = this;
+
+ return new Promise(function (resolve, reject) {
+ var request = new XMLHttpRequest(),
+ url = ""
+
+ if (mbid) {
+ url = "https://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=" + config.key + "&mbid=" + mbid + "&format=" + self.format
+ } else {
+ url = "https://ws.audioscrobbler.com/2.0/?method=track.getInfo&api_key=" + config.key + "&artist=" + artist + "&track=" + name + "&autocorrect=1&format=" + self.format
+ }
+
+ request.open('GET', url, true)
+
+ request.onload = function() {
+ if (request.status >= 200 && request.status < 400) {
+ var data = JSON.parse(request.responseText);
+ resolve(data)
+ } else {
+ reject('error')
+ }
+ }
+
+ request.onerror = function() {
+ reject('error');
+ }
+
+ request.send()
+ });
+ },
+ // Manipulate recieved track data
+ handleRecentTrackData: function () {
+ this.getRecentTracks()
+ .then(function (data) {
+ var tracks = data.recenttracks.track,
+ tracksWithIMG = [],
+ tracksWithMBID = []
+
+ content["current-track"] = data.recenttracks.track[0].artist["#text"] + " - " + data.recenttracks.track[0].name
+ tracks.shift()
+
+ // Filter array by images that have an image
+ function filterByIMG(item) {
+ if (item.image[3]["#text"] !== "") {
+ return item
+ }
+ }
+
+ // Filter array by images that have an mbid
+ function filterByMBID(item) {
+ if (item.mbid !== "") {
+ return item
+ }
+ }
+
+ tracksWithIMG = tracks.filter(filterByIMG)
+ // tracksWithMBID = tracksWithIMG.filter(filterByMBID)
+
+ // Only push 12 items to the content object
+ for(var i = 0; i < 12; i++) {
+ content.trackList.push({
+ artist: tracksWithIMG[i].artist["#text"],
+ name: tracksWithIMG[i].name,
+ slug: helper.slugify(tracksWithIMG[i].artist["#text"]) + '+' + helper.slugify(tracksWithIMG[i].name),
+ track: tracksWithIMG[i].artist["#text"] + " - " + tracksWithIMG[i].name,
+ imgSrc: tracksWithIMG[i].image[3]["#text"],
+ mbid: tracksWithIMG[i].mbid
+ })
+ }
+
+ content.render()
+ })
+ .catch(function (err) {
+ console.error(err);
+ });
+ }
+ }
+
+ var sections = {
+ // Return all the sections
+ getSections: function() {
+ return document.querySelectorAll("section")
+ },
+ // Hide all the sections
+ hideSections: function () {
+ this.getSections().forEach(function(element) {
+ element.classList.add("hidden")
+ })
+ },
+ // Hide all sections and show current section again
+ toggle: function (route) {
+ this.hideSections()
+ document.querySelector(route).classList.remove("hidden")
+ }
+ }
+
+ var detailPage = {
+ content: {
+ tags: []
+ },
+ init: function (slug) {
+ var self = this,
+ container = document.querySelector("#track"),
+ trackFromSlug = ""
+
+ trackFromSlug = slug.split("-").join(" ")
+ trackFromSlug = trackFromSlug.split("+")
+
+ api.getTrackInfo(false, trackFromSlug[0], trackFromSlug[1])
+ .then(function (data) {
+ console.log(data)
+ self.content.artist = data.track.artist.name
+ self.content.name = data.track.name
+ if (data.track.toptags.tag) {
+ self.content.tags = data.track.toptags.tag
+ } else {
+ self.content.tags = 'geen tags beschikbaar'
+ }
+ if (data.track.album) {
+ self.content.img = data.track.album.image[3]["#text"]
+ } else {
+ self.content.img = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAMFBMVEXp7vG6vsHm6+63u77HzM/f4+bP09bFycy8wMPi5+rr8fTAxMfM0NPX3N++wsXh5eiWmqd3AAACiUlEQVR4nO3b13KDMBBAUZpoovz/3yYIm1CEaZqR1rnnLZ7Eww1LsyGKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADe1W74zthTR21WOJC1SaCNbZnGTqRp67vFqnXUZ+S+ayx67TAwjpXvnq1mXIXpc+Z9dHCbYmJWYdfkz5l3ShPfRWtVNyyWkz2EMoXBjWlfOlusyt1buUThBVIKk6qq7u0tZBQmbaO1zvL+xk5fQmFdvQ//XXs9UUKhKqdzk/T6+ZeAwmpxAnf5GBl+YZ0vzsEvn3+FXxgtLzIuL2v4hf2qMN9biYn9aBJ+4fpCMdsrbLQ18XsKszTVleX18AvPTWliLigLS2L4hef2NM1rT7sd1PALTx0tsvfvbAc1/MITR/yk+fsnbAZVQOHxWVuzWMmrQZVQeHTmnS231NWgSij8fPU0H1HboMoo/HQF3MQbi0GVUrgrs302Ph9U4YXbEd0MqvBCy4iuB1V2oXVEV4MqrFDNX9ob0eWgiiqsq07PDhi7I7oYVFGFavg2o3//9GFE54MqqLBW5tRGj69+HlFjPMWTU1ib76OGRDOoByMqsVB106L/Jh6OqLjC14i+1mJ7PKLSCqcRHZX2JMmFqjvKkV24GNFvLFyN6BcW3hpRQYU3R1RQ4c0RFVR4/wY3Cr2ikEIK/ftXharIbirM91ThF0bJfcOfCyh8iEJPxsXqj3/x7FuFV2ju884fbIKT1uxWbfeheJUUw3KVt3ejM+YzndR30Fbu8pGZOC6Ce95idQPGU6WTLdqx2Q0YzwPDfLRLaQePBBldcDvSl7p38EzQLxXeNjj57kdIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAf+QGg0Sz/T2GZ1QAAAABJRU5ErkJggg=='
+ }
+ Transparency.render(document.getElementById('track'), self.content);
+ container.querySelector("img").src = self.content.img
+ })
+ .catch(function (err) {
+ console.error(err);
+ });
+
+ }
+ }
+
+ var helper = {
+ // source: https://gist.github.com/mathewbyrne/1280286
+ slugify: function (text) {
+ return text.toString().toLowerCase()
+ .replace(/\s+/g, '-') // Replace spaces with -
+ .replace(/[^\w\-]+/g, '') // Remove all non-word chars
+ .replace(/\-\-+/g, '-') // Replace multiple - with single -
+ .replace(/^-+/, '') // Trim - from start of text
+ .replace(/-+$/, ''); // Trim - from end of text
+ }
+ }
+
+ // Routie config
+ routie({
+ 'now-playing': function() {
+ sections.toggle("#now-playing")
+ },
+ 'recent-tracks': function() {
+ sections.toggle("#recent-tracks")
+ },
+ 'track/:track': function(slug) {
+ sections.toggle("#track")
+ detailPage.init(slug)
+ }
+ });
+
+ app.init()
+
+}())
diff --git a/assets/js/routie.js b/assets/js/routie.js
new file mode 100644
index 00000000..9357bb6a
--- /dev/null
+++ b/assets/js/routie.js
@@ -0,0 +1,218 @@
+/*!
+ * routie - a tiny hash router
+ * v0.3.2
+ * http://projects.jga.me/routie
+ * copyright Greg Allen 2016
+ * MIT License
+*/
+var Routie = function(w, isModule) {
+
+ var routes = [];
+ var map = {};
+ var reference = "routie";
+ var oldReference = w[reference];
+
+ var Route = function(path, name) {
+ this.name = name;
+ this.path = path;
+ this.keys = [];
+ this.fns = [];
+ this.params = {};
+ this.regex = pathToRegexp(this.path, this.keys, false, false);
+
+ };
+
+ Route.prototype.addHandler = function(fn) {
+ this.fns.push(fn);
+ };
+
+ Route.prototype.removeHandler = function(fn) {
+ for (var i = 0, c = this.fns.length; i < c; i++) {
+ var f = this.fns[i];
+ if (fn == f) {
+ this.fns.splice(i, 1);
+ return;
+ }
+ }
+ };
+
+ Route.prototype.run = function(params) {
+ for (var i = 0, c = this.fns.length; i < c; i++) {
+ this.fns[i].apply(this, params);
+ }
+ };
+
+ Route.prototype.match = function(path, params){
+ var m = this.regex.exec(path);
+
+ if (!m) return false;
+
+
+ for (var i = 1, len = m.length; i < len; ++i) {
+ var key = this.keys[i - 1];
+
+ var val = ('string' == typeof m[i]) ? decodeURIComponent(m[i]) : m[i];
+
+ if (key) {
+ this.params[key.name] = val;
+ }
+ params.push(val);
+ }
+
+ return true;
+ };
+
+ Route.prototype.toURL = function(params) {
+ var path = this.path;
+ for (var param in params) {
+ path = path.replace('/:'+param, '/'+params[param]);
+ }
+ path = path.replace(/\/:.*\?/g, '/').replace(/\?/g, '');
+ if (path.indexOf(':') != -1) {
+ throw new Error('missing parameters for url: '+path);
+ }
+ return path;
+ };
+
+ var pathToRegexp = function(path, keys, sensitive, strict) {
+ if (path instanceof RegExp) return path;
+ if (path instanceof Array) path = '(' + path.join('|') + ')';
+ path = path
+ .concat(strict ? '' : '/?')
+ .replace(/\/\(/g, '(?:/')
+ .replace(/\+/g, '__plus__')
+ .replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
+ keys.push({ name: key, optional: !! optional });
+ slash = slash || '';
+ return '' + (optional ? '' : slash) + '(?:' + (optional ? slash : '') + (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')' + (optional || '');
+ })
+ .replace(/([\/.])/g, '\\$1')
+ .replace(/__plus__/g, '(.+)')
+ .replace(/\*/g, '(.*)');
+ return new RegExp('^' + path + '$', sensitive ? '' : 'i');
+ };
+
+ var addHandler = function(path, fn) {
+ var s = path.split(' ');
+ var name = (s.length == 2) ? s[0] : null;
+ path = (s.length == 2) ? s[1] : s[0];
+
+ if (!map[path]) {
+ map[path] = new Route(path, name);
+ routes.push(map[path]);
+ }
+ map[path].addHandler(fn);
+ };
+
+ var routie = function(path, fn) {
+ if (typeof fn == 'function') {
+ addHandler(path, fn);
+ routie.reload();
+ } else if (typeof path == 'object') {
+ for (var p in path) {
+ addHandler(p, path[p]);
+ }
+ routie.reload();
+ } else if (typeof fn === 'undefined') {
+ routie.navigate(path);
+ }
+ };
+
+ routie.lookup = function(name, obj) {
+ for (var i = 0, c = routes.length; i < c; i++) {
+ var route = routes[i];
+ if (route.name == name) {
+ return route.toURL(obj);
+ }
+ }
+ };
+
+ routie.remove = function(path, fn) {
+ var route = map[path];
+ if (!route)
+ return;
+ route.removeHandler(fn);
+ };
+
+ routie.removeAll = function() {
+ map = {};
+ routes = [];
+ };
+
+ routie.navigate = function(path, options) {
+ options = options || {};
+ var silent = options.silent || false;
+
+ if (silent) {
+ removeListener();
+ }
+ setTimeout(function() {
+ window.location.hash = path;
+
+ if (silent) {
+ setTimeout(function() {
+ addListener();
+ }, 1);
+ }
+
+ }, 1);
+ };
+
+ routie.noConflict = function() {
+ w[reference] = oldReference;
+ return routie;
+ };
+
+ var getHash = function() {
+ return window.location.hash.substring(1);
+ };
+
+ var checkRoute = function(hash, route) {
+ var params = [];
+ if (route.match(hash, params)) {
+ route.run(params);
+ return true;
+ }
+ return false;
+ };
+
+ var hashChanged = routie.reload = function() {
+ var hash = getHash();
+ for (var i = 0, c = routes.length; i < c; i++) {
+ var route = routes[i];
+ if (checkRoute(hash, route)) {
+ return;
+ }
+ }
+ };
+
+ var addListener = function() {
+ if (w.addEventListener) {
+ w.addEventListener('hashchange', hashChanged, false);
+ } else {
+ w.attachEvent('onhashchange', hashChanged);
+ }
+ };
+
+ var removeListener = function() {
+ if (w.removeEventListener) {
+ w.removeEventListener('hashchange', hashChanged);
+ } else {
+ w.detachEvent('onhashchange', hashChanged);
+ }
+ };
+ addListener();
+
+ if (isModule){
+ return routie;
+ } else {
+ w[reference] = routie;
+ }
+
+};
+
+if (typeof module == 'undefined'){
+ Routie(window);
+} else {
+ module.exports = Routie(window,true);
+}
\ No newline at end of file
diff --git a/assets/js/transparency.js b/assets/js/transparency.js
new file mode 100644
index 00000000..124f16b0
--- /dev/null
+++ b/assets/js/transparency.js
@@ -0,0 +1,784 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 0 || element.el.name === key || element.el.getAttribute('data-bind') === key;
+ };
+
+ Transparency.clone = function(node) {
+ return $(node).clone()[0];
+ };
+
+ Transparency.jQueryPlugin = helpers.chainable(function(models, directives, options) {
+ var context, i, len, results;
+ results = [];
+ for (i = 0, len = this.length; i < len; i++) {
+ context = this[i];
+ results.push(Transparency.render(context, models, directives, options));
+ }
+ return results;
+ });
+
+ if ((typeof jQuery !== "undefined" && jQuery !== null) || (typeof Zepto !== "undefined" && Zepto !== null)) {
+ $ = jQuery || Zepto;
+ if ($ != null) {
+ $.fn.render = Transparency.jQueryPlugin;
+ }
+ }
+
+ if (typeof module !== "undefined" && module !== null ? module.exports : void 0) {
+ module.exports = Transparency;
+ }
+
+ if (typeof window !== "undefined" && window !== null) {
+ window.Transparency = Transparency;
+ }
+
+ if (typeof define !== "undefined" && define !== null ? define.amd : void 0) {
+ define(function() {
+ return Transparency;
+ });
+ }
+
+ },{"../lib/lodash.js":7,"./context":3,"./helpers":5}],2:[function(require,module,exports){
+ var Attribute, AttributeFactory, BooleanAttribute, Class, Html, Text, _, helpers,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+ hasProp = {}.hasOwnProperty;
+
+ _ = require('../lib/lodash');
+
+ helpers = require('./helpers');
+
+ module.exports = AttributeFactory = {
+ Attributes: {},
+ createAttribute: function(element, name) {
+ var Attr;
+ Attr = AttributeFactory.Attributes[name] || Attribute;
+ return new Attr(element, name);
+ }
+ };
+
+ Attribute = (function() {
+ function Attribute(el1, name1) {
+ this.el = el1;
+ this.name = name1;
+ this.templateValue = this.el.getAttribute(this.name) || '';
+ }
+
+ Attribute.prototype.set = function(value) {
+ this.el[this.name] = value;
+ return this.el.setAttribute(this.name, value.toString());
+ };
+
+ return Attribute;
+
+ })();
+
+ BooleanAttribute = (function(superClass) {
+ var BOOLEAN_ATTRIBUTES, i, len, name;
+
+ extend(BooleanAttribute, superClass);
+
+ BOOLEAN_ATTRIBUTES = ['hidden', 'async', 'defer', 'autofocus', 'formnovalidate', 'disabled', 'autofocus', 'formnovalidate', 'multiple', 'readonly', 'required', 'checked', 'scoped', 'reversed', 'selected', 'loop', 'muted', 'autoplay', 'controls', 'seamless', 'default', 'ismap', 'novalidate', 'open', 'typemustmatch', 'truespeed'];
+
+ for (i = 0, len = BOOLEAN_ATTRIBUTES.length; i < len; i++) {
+ name = BOOLEAN_ATTRIBUTES[i];
+ AttributeFactory.Attributes[name] = BooleanAttribute;
+ }
+
+ function BooleanAttribute(el1, name1) {
+ this.el = el1;
+ this.name = name1;
+ this.templateValue = this.el.getAttribute(this.name) || false;
+ }
+
+ BooleanAttribute.prototype.set = function(value) {
+ this.el[this.name] = value;
+ if (value) {
+ return this.el.setAttribute(this.name, this.name);
+ } else {
+ return this.el.removeAttribute(this.name);
+ }
+ };
+
+ return BooleanAttribute;
+
+ })(Attribute);
+
+ Text = (function(superClass) {
+ extend(Text, superClass);
+
+ AttributeFactory.Attributes['text'] = Text;
+
+ function Text(el1, name1) {
+ var child;
+ this.el = el1;
+ this.name = name1;
+ this.templateValue = ((function() {
+ var i, len, ref, results;
+ ref = this.el.childNodes;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ child = ref[i];
+ if (child.nodeType === helpers.TEXT_NODE) {
+ results.push(child.nodeValue);
+ }
+ }
+ return results;
+ }).call(this)).join('');
+ this.children = _.toArray(this.el.children);
+ if (!(this.textNode = this.el.firstChild)) {
+ this.el.appendChild(this.textNode = this.el.ownerDocument.createTextNode(''));
+ } else if (this.textNode.nodeType !== helpers.TEXT_NODE) {
+ this.textNode = this.el.insertBefore(this.el.ownerDocument.createTextNode(''), this.textNode);
+ }
+ }
+
+ Text.prototype.set = function(text) {
+ var child, i, len, ref, results;
+ while (child = this.el.firstChild) {
+ this.el.removeChild(child);
+ }
+ this.textNode.nodeValue = text;
+ this.el.appendChild(this.textNode);
+ ref = this.children;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ child = ref[i];
+ results.push(this.el.appendChild(child));
+ }
+ return results;
+ };
+
+ return Text;
+
+ })(Attribute);
+
+ Html = (function(superClass) {
+ extend(Html, superClass);
+
+ AttributeFactory.Attributes['html'] = Html;
+
+ function Html(el1) {
+ this.el = el1;
+ this.templateValue = '';
+ this.children = _.toArray(this.el.children);
+ }
+
+ Html.prototype.set = function(html) {
+ var child, i, len, ref, results;
+ while (child = this.el.firstChild) {
+ this.el.removeChild(child);
+ }
+ this.el.innerHTML = html + this.templateValue;
+ ref = this.children;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ child = ref[i];
+ results.push(this.el.appendChild(child));
+ }
+ return results;
+ };
+
+ return Html;
+
+ })(Attribute);
+
+ Class = (function(superClass) {
+ extend(Class, superClass);
+
+ AttributeFactory.Attributes['class'] = Class;
+
+ function Class(el) {
+ Class.__super__.constructor.call(this, el, 'class');
+ }
+
+ return Class;
+
+ })(Attribute);
+
+ },{"../lib/lodash":7,"./helpers":5}],3:[function(require,module,exports){
+ var Context, Instance, after, before, chainable, cloneNode, ref;
+
+ ref = require('./helpers'), before = ref.before, after = ref.after, chainable = ref.chainable, cloneNode = ref.cloneNode;
+
+ Instance = require('./instance');
+
+ module.exports = Context = (function() {
+ var attach, detach;
+
+ detach = chainable(function() {
+ this.parent = this.el.parentNode;
+ if (this.parent) {
+ this.nextSibling = this.el.nextSibling;
+ return this.parent.removeChild(this.el);
+ }
+ });
+
+ attach = chainable(function() {
+ if (this.parent) {
+ if (this.nextSibling) {
+ return this.parent.insertBefore(this.el, this.nextSibling);
+ } else {
+ return this.parent.appendChild(this.el);
+ }
+ }
+ });
+
+ function Context(el, Transparency) {
+ this.el = el;
+ this.Transparency = Transparency;
+ this.template = cloneNode(this.el);
+ this.instances = [new Instance(this.el, this.Transparency)];
+ this.instanceCache = [];
+ }
+
+ Context.prototype.render = before(detach)(after(attach)(chainable(function(models, directives, options) {
+ var children, i, index, instance, len, model, results;
+ while (models.length < this.instances.length) {
+ this.instanceCache.push(this.instances.pop().remove());
+ }
+ while (models.length > this.instances.length) {
+ instance = this.instanceCache.pop() || new Instance(cloneNode(this.template), this.Transparency);
+ this.instances.push(instance.appendTo(this.el));
+ }
+ results = [];
+ for (index = i = 0, len = models.length; i < len; index = ++i) {
+ model = models[index];
+ instance = this.instances[index];
+ children = [];
+ results.push(instance.prepare(model, children).renderValues(model, children).renderDirectives(model, index, directives).renderChildren(model, children, directives, options));
+ }
+ return results;
+ })));
+
+ return Context;
+
+ })();
+
+ },{"./helpers":5,"./instance":6}],4:[function(require,module,exports){
+ var AttributeFactory, Checkbox, Element, ElementFactory, Input, Radio, Select, TextArea, VoidElement, _, helpers,
+ hasProp = {}.hasOwnProperty,
+ extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+
+ _ = require('../lib/lodash.js');
+
+ helpers = require('./helpers');
+
+ AttributeFactory = require('./attributeFactory');
+
+ module.exports = ElementFactory = {
+ Elements: {
+ input: {}
+ },
+ createElement: function(el) {
+ var El, name;
+ if ('input' === (name = el.nodeName.toLowerCase())) {
+ El = ElementFactory.Elements[name][el.type.toLowerCase()] || Input;
+ } else {
+ El = ElementFactory.Elements[name] || Element;
+ }
+ return new El(el);
+ }
+ };
+
+ Element = (function() {
+ function Element(el1) {
+ this.el = el1;
+ this.attributes = {};
+ this.childNodes = _.toArray(this.el.childNodes);
+ this.nodeName = this.el.nodeName.toLowerCase();
+ this.classNames = this.el.className.split(' ');
+ this.originalAttributes = {};
+ }
+
+ Element.prototype.empty = function() {
+ var child;
+ while (child = this.el.firstChild) {
+ this.el.removeChild(child);
+ }
+ return this;
+ };
+
+ Element.prototype.reset = function() {
+ var attribute, name, ref, results;
+ ref = this.attributes;
+ results = [];
+ for (name in ref) {
+ attribute = ref[name];
+ results.push(attribute.set(attribute.templateValue));
+ }
+ return results;
+ };
+
+ Element.prototype.render = function(value) {
+ return this.attr('text', value);
+ };
+
+ Element.prototype.attr = function(name, value) {
+ var attribute, base;
+ attribute = (base = this.attributes)[name] || (base[name] = AttributeFactory.createAttribute(this.el, name, value));
+ if (value != null) {
+ attribute.set(value);
+ }
+ return attribute;
+ };
+
+ Element.prototype.renderDirectives = function(model, index, attributes) {
+ var directive, name, results, value;
+ results = [];
+ for (name in attributes) {
+ if (!hasProp.call(attributes, name)) continue;
+ directive = attributes[name];
+ if (!(typeof directive === 'function')) {
+ continue;
+ }
+ value = directive.call(model, {
+ element: this.el,
+ index: index,
+ value: this.attr(name).templateValue
+ });
+ if (value != null) {
+ results.push(this.attr(name, value));
+ } else {
+ results.push(void 0);
+ }
+ }
+ return results;
+ };
+
+ return Element;
+
+ })();
+
+ Select = (function(superClass) {
+ extend(Select, superClass);
+
+ ElementFactory.Elements['select'] = Select;
+
+ function Select(el) {
+ Select.__super__.constructor.call(this, el);
+ this.elements = helpers.getElements(el);
+ }
+
+ Select.prototype.render = function(value) {
+ var i, len, option, ref, results;
+ value = value.toString();
+ ref = this.elements;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ option = ref[i];
+ if (option.nodeName === 'option') {
+ results.push(option.attr('selected', option.el.value === value));
+ }
+ }
+ return results;
+ };
+
+ return Select;
+
+ })(Element);
+
+ VoidElement = (function(superClass) {
+ var VOID_ELEMENTS, i, len, nodeName;
+
+ extend(VoidElement, superClass);
+
+ function VoidElement() {
+ return VoidElement.__super__.constructor.apply(this, arguments);
+ }
+
+ VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
+
+ for (i = 0, len = VOID_ELEMENTS.length; i < len; i++) {
+ nodeName = VOID_ELEMENTS[i];
+ ElementFactory.Elements[nodeName] = VoidElement;
+ }
+
+ VoidElement.prototype.attr = function(name, value) {
+ if (name !== 'text' && name !== 'html') {
+ return VoidElement.__super__.attr.call(this, name, value);
+ }
+ };
+
+ return VoidElement;
+
+ })(Element);
+
+ Input = (function(superClass) {
+ extend(Input, superClass);
+
+ function Input() {
+ return Input.__super__.constructor.apply(this, arguments);
+ }
+
+ Input.prototype.render = function(value) {
+ return this.attr('value', value);
+ };
+
+ return Input;
+
+ })(VoidElement);
+
+ TextArea = (function(superClass) {
+ extend(TextArea, superClass);
+
+ function TextArea() {
+ return TextArea.__super__.constructor.apply(this, arguments);
+ }
+
+ ElementFactory.Elements['textarea'] = TextArea;
+
+ return TextArea;
+
+ })(Input);
+
+ Checkbox = (function(superClass) {
+ extend(Checkbox, superClass);
+
+ function Checkbox() {
+ return Checkbox.__super__.constructor.apply(this, arguments);
+ }
+
+ ElementFactory.Elements['input']['checkbox'] = Checkbox;
+
+ Checkbox.prototype.render = function(value) {
+ return this.attr('checked', Boolean(value));
+ };
+
+ return Checkbox;
+
+ })(Input);
+
+ Radio = (function(superClass) {
+ extend(Radio, superClass);
+
+ function Radio() {
+ return Radio.__super__.constructor.apply(this, arguments);
+ }
+
+ ElementFactory.Elements['input']['radio'] = Radio;
+
+ return Radio;
+
+ })(Checkbox);
+
+ },{"../lib/lodash.js":7,"./attributeFactory":2,"./helpers":5}],5:[function(require,module,exports){
+ var ElementFactory, _getElements, expando, html5Clone;
+
+ ElementFactory = require('./elementFactory');
+
+ exports.before = function(decorator) {
+ return function(method) {
+ return function() {
+ decorator.apply(this, arguments);
+ return method.apply(this, arguments);
+ };
+ };
+ };
+
+ exports.after = function(decorator) {
+ return function(method) {
+ return function() {
+ method.apply(this, arguments);
+ return decorator.apply(this, arguments);
+ };
+ };
+ };
+
+ exports.chainable = exports.after(function() {
+ return this;
+ });
+
+ exports.onlyWith$ = function(fn) {
+ if ((typeof jQuery !== "undefined" && jQuery !== null) || (typeof Zepto !== "undefined" && Zepto !== null)) {
+ return (function($) {
+ return fn(arguments);
+ })(jQuery || Zepto);
+ }
+ };
+
+ exports.getElements = function(el) {
+ var elements;
+ elements = [];
+ _getElements(el, elements);
+ return elements;
+ };
+
+ _getElements = function(template, elements) {
+ var child, results;
+ child = template.firstChild;
+ results = [];
+ while (child) {
+ if (child.nodeType === exports.ELEMENT_NODE) {
+ elements.push(new ElementFactory.createElement(child));
+ _getElements(child, elements);
+ }
+ results.push(child = child.nextSibling);
+ }
+ return results;
+ };
+
+ exports.ELEMENT_NODE = 1;
+
+ exports.TEXT_NODE = 3;
+
+ html5Clone = function() {
+ return document.createElement('nav').cloneNode(true).outerHTML !== '<:nav>';
+ };
+
+ exports.cloneNode = (typeof document === "undefined" || document === null) || html5Clone() ? function(node) {
+ return node.cloneNode(true);
+ } : function(node) {
+ var cloned, element, i, len, ref;
+ cloned = Transparency.clone(node);
+ if (cloned.nodeType === exports.ELEMENT_NODE) {
+ cloned.removeAttribute(expando);
+ ref = cloned.getElementsByTagName('*');
+ for (i = 0, len = ref.length; i < len; i++) {
+ element = ref[i];
+ element.removeAttribute(expando);
+ }
+ }
+ return cloned;
+ };
+
+ expando = 'transparency';
+
+ exports.data = function(element) {
+ return element[expando] || (element[expando] = {});
+ };
+
+ exports.nullLogger = function() {};
+
+ exports.consoleLogger = function() {
+ return console.log(arguments);
+ };
+
+ exports.log = exports.nullLogger;
+
+ },{"./elementFactory":4}],6:[function(require,module,exports){
+ var Instance, _, chainable, helpers,
+ hasProp = {}.hasOwnProperty;
+
+ _ = require('../lib/lodash.js');
+
+ chainable = (helpers = require('./helpers')).chainable;
+
+ module.exports = Instance = (function() {
+ function Instance(template, Transparency) {
+ this.Transparency = Transparency;
+ this.queryCache = {};
+ this.childNodes = _.toArray(template.childNodes);
+ this.elements = helpers.getElements(template);
+ }
+
+ Instance.prototype.remove = chainable(function() {
+ var i, len, node, ref, results;
+ ref = this.childNodes;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ node = ref[i];
+ results.push(node.parentNode.removeChild(node));
+ }
+ return results;
+ });
+
+ Instance.prototype.appendTo = chainable(function(parent) {
+ var i, len, node, ref, results;
+ ref = this.childNodes;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ node = ref[i];
+ results.push(parent.appendChild(node));
+ }
+ return results;
+ });
+
+ Instance.prototype.prepare = chainable(function(model) {
+ var element, i, len, ref, results;
+ ref = this.elements;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ element = ref[i];
+ element.reset();
+ results.push(helpers.data(element.el).model = model);
+ }
+ return results;
+ });
+
+ Instance.prototype.renderValues = chainable(function(model, children) {
+ var element, key, results, value;
+ if (_.isElement(model) && (element = this.elements[0])) {
+ return element.empty().el.appendChild(model);
+ } else if (typeof model === 'object') {
+ results = [];
+ for (key in model) {
+ if (!hasProp.call(model, key)) continue;
+ value = model[key];
+ if (value != null) {
+ if (_.isString(value) || _.isNumber(value) || _.isBoolean(value) || _.isDate(value)) {
+ results.push((function() {
+ var i, len, ref, results1;
+ ref = this.matchingElements(key);
+ results1 = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ element = ref[i];
+ results1.push(element.render(value));
+ }
+ return results1;
+ }).call(this));
+ } else if (typeof value === 'object') {
+ results.push(children.push(key));
+ } else {
+ results.push(void 0);
+ }
+ }
+ }
+ return results;
+ }
+ });
+
+ Instance.prototype.renderDirectives = chainable(function(model, index, directives) {
+ var attributes, element, key, results;
+ results = [];
+ for (key in directives) {
+ if (!hasProp.call(directives, key)) continue;
+ attributes = directives[key];
+ if (!(typeof attributes === 'object')) {
+ continue;
+ }
+ if (typeof model !== 'object') {
+ model = {
+ value: model
+ };
+ }
+ results.push((function() {
+ var i, len, ref, results1;
+ ref = this.matchingElements(key);
+ results1 = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ element = ref[i];
+ results1.push(element.renderDirectives(model, index, attributes));
+ }
+ return results1;
+ }).call(this));
+ }
+ return results;
+ });
+
+ Instance.prototype.renderChildren = chainable(function(model, children, directives, options) {
+ var element, i, key, len, results;
+ results = [];
+ for (i = 0, len = children.length; i < len; i++) {
+ key = children[i];
+ results.push((function() {
+ var j, len1, ref, results1;
+ ref = this.matchingElements(key);
+ results1 = [];
+ for (j = 0, len1 = ref.length; j < len1; j++) {
+ element = ref[j];
+ results1.push(this.Transparency.render(element.el, model[key], directives[key], options));
+ }
+ return results1;
+ }).call(this));
+ }
+ return results;
+ });
+
+ Instance.prototype.matchingElements = function(key) {
+ var base, el, elements;
+ elements = (base = this.queryCache)[key] || (base[key] = (function() {
+ var i, len, ref, results;
+ ref = this.elements;
+ results = [];
+ for (i = 0, len = ref.length; i < len; i++) {
+ el = ref[i];
+ if (this.Transparency.matcher(el, key)) {
+ results.push(el);
+ }
+ }
+ return results;
+ }).call(this));
+ helpers.log("Matching elements for '" + key + "':", elements);
+ return elements;
+ };
+
+ return Instance;
+
+ })();
+
+ },{"../lib/lodash.js":7,"./helpers":5}],7:[function(require,module,exports){
+ var _ = {};
+
+ _.toString = Object.prototype.toString;
+
+ _.toArray = function(obj) {
+ var arr = new Array(obj.length);
+ for (var i = 0; i < obj.length; i++) {
+ arr[i] = obj[i];
+ }
+ return arr;
+ };
+
+ _.isString = function(obj) { return _.toString.call(obj) == '[object String]'; };
+
+ _.isNumber = function(obj) { return _.toString.call(obj) == '[object Number]'; };
+
+ _.isArray = Array.isArray || function(obj) {
+ return _.toString.call(obj) === '[object Array]';
+ };
+
+ _.isDate = function(obj) {
+ return _.toString.call(obj) === '[object Date]';
+ };
+
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType === 1);
+ };
+
+ _.isPlainValue = function(obj) {
+ var type;
+ type = typeof obj;
+ return (type !== 'object' && type !== 'function') || exports.isDate(obj);
+ };
+
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false;
+ };
+
+ module.exports = _;
+
+ },{}]},{},[1]);
\ No newline at end of file
diff --git a/cmd-geo-script/script.js b/cmd-geo-script/script.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..b06bc7d3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,49 @@
+
+
+
+
+ WAFS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file