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 += '
  • ' + item.track + '
  • ' + }) + } + } + + // 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 + + + + + + + +
    +
    +

    Now playing

    +

    +
    +
    + +
    +
    +

    Played tracks

    +
      +
      +
      + +
      +
      +

      -

      +
        +
      • +
      + +
      +
      + + + + + + + \ No newline at end of file