Added lawnchair to list of working utilities, and am adding the editor.
This commit is contained in:
parent
de33547e83
commit
f4090dd0d2
11
grunt.coffee
11
grunt.coffee
|
@ -91,12 +91,9 @@ module.exports = (grunt) ->
|
|||
|
||||
install:
|
||||
src: [
|
||||
"src/index.html"
|
||||
"src/priority.js"
|
||||
"src/*_tmpl.js"
|
||||
"src/style.css"
|
||||
"libs/jquery/jquery-1.7.2.js"
|
||||
"libs/require.js"
|
||||
"libs/lawnchair/lawnchair.js"
|
||||
]
|
||||
dest: "dist"
|
||||
|
||||
|
@ -106,7 +103,7 @@ module.exports = (grunt) ->
|
|||
uglify: {}
|
||||
|
||||
|
||||
grunt.registerTask "default", "coffee:dev recess:dev haml:dev hamltojs:dev"
|
||||
grunt.registerTask "default", "coffee:dev recess:dev haml:dev hamltojs:dev install"
|
||||
|
||||
# _ _ _ __ __ _ _ _ _ _____ __ __ _
|
||||
# | || | /_\ | \/ | | | |_ ___ | || |_ _| \/ | |
|
||||
|
@ -143,7 +140,7 @@ module.exports = (grunt) ->
|
|||
grunt.registerHelper "templatize", (src, dest, done) ->
|
||||
file = grunt.file.read(src)
|
||||
out = path.basename(src, ".html")
|
||||
grunt.file.write path.join(dest, out + ".js"), "define(" + _und.template(file).source + ");"
|
||||
grunt.file.write path.join(dest, out + ".js"), "define(function() { return " + _und.template(result.stdout).source + "});"
|
||||
done()
|
||||
|
||||
grunt.registerMultiTask "templatize", "Compile Underscored HTML to Javascript", ->
|
||||
|
@ -169,7 +166,7 @@ module.exports = (grunt) ->
|
|||
grunt.utils.spawn args, (err, result) ->
|
||||
console.log err if err
|
||||
out = path.basename(src, ".haml")
|
||||
grunt.file.write path.join(dest, out + ".js"), "define(" + _und.template(result.stdout).source + ");"
|
||||
grunt.file.write path.join(dest, out + ".js"), "define(function() { return " + _und.template(result.stdout).source + "});"
|
||||
done()
|
||||
|
||||
grunt.registerMultiTask "hamltojs", "Compile Underscored HAML to Javascript", ->
|
||||
|
|
8
grunt.js
8
grunt.js
|
@ -111,7 +111,7 @@ module.exports = function(grunt) {
|
|||
findNestedDependencies: true
|
||||
},
|
||||
install: {
|
||||
src: ["src/index.html", "src/priority.js", "src/*_tmpl.js", "src/style.css", "libs/jquery/jquery-1.7.2.js", "libs/require.js"],
|
||||
src: ["libs/jquery/jquery-1.7.2.js", "libs/require.js", "libs/lawnchair/lawnchair.js"],
|
||||
dest: "dist"
|
||||
},
|
||||
mocha: {
|
||||
|
@ -119,7 +119,7 @@ module.exports = function(grunt) {
|
|||
},
|
||||
uglify: {}
|
||||
});
|
||||
grunt.registerTask("default", "coffee:dev recess:dev haml:dev hamltojs:dev");
|
||||
grunt.registerTask("default", "coffee:dev recess:dev haml:dev hamltojs:dev install");
|
||||
grunt.registerHelper("haml", function(src, dest, done) {
|
||||
var args;
|
||||
args = {
|
||||
|
@ -149,7 +149,7 @@ module.exports = function(grunt) {
|
|||
var file, out;
|
||||
file = grunt.file.read(src);
|
||||
out = path.basename(src, ".html");
|
||||
grunt.file.write(path.join(dest, out + ".js"), "define(" + _und.template(file).source + ");");
|
||||
grunt.file.write(path.join(dest, out + ".js"), "define(function() { return " + _und.template(result.stdout).source + "});");
|
||||
return done();
|
||||
});
|
||||
grunt.registerMultiTask("templatize", "Compile Underscored HTML to Javascript", function() {
|
||||
|
@ -176,7 +176,7 @@ module.exports = function(grunt) {
|
|||
console.log(err);
|
||||
}
|
||||
out = path.basename(src, ".haml");
|
||||
grunt.file.write(path.join(dest, out + ".js"), "define(" + _und.template(result.stdout).source + ");");
|
||||
grunt.file.write(path.join(dest, out + ".js"), "define(function() { return " + _und.template(result.stdout).source + "});");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,438 @@
|
|||
/**
|
||||
* Lawnchair!
|
||||
* ---
|
||||
* clientside json store
|
||||
*
|
||||
*/
|
||||
var Lawnchair = function (options, callback) {
|
||||
// ensure Lawnchair was called as a constructor
|
||||
if (!(this instanceof Lawnchair)) return new Lawnchair(options, callback);
|
||||
|
||||
// lawnchair requires json
|
||||
if (!JSON) throw 'JSON unavailable! Include http://www.json.org/json2.js to fix.'
|
||||
// options are optional; callback is not
|
||||
if (arguments.length <= 2 && arguments.length > 0) {
|
||||
callback = (typeof arguments[0] === 'function') ? arguments[0] : arguments[1];
|
||||
options = (typeof arguments[0] === 'function') ? {} : arguments[0];
|
||||
} else {
|
||||
throw 'Incorrect # of ctor args!'
|
||||
}
|
||||
// TODO perhaps allow for pub/sub instead?
|
||||
if (typeof callback !== 'function') throw 'No callback was provided';
|
||||
|
||||
// default configuration
|
||||
this.record = options.record || 'record' // default for records
|
||||
this.name = options.name || 'records' // default name for underlying store
|
||||
|
||||
// mixin first valid adapter
|
||||
var adapter
|
||||
// if the adapter is passed in we try to load that only
|
||||
if (options.adapter) {
|
||||
for (var i = 0, l = Lawnchair.adapters.length; i < l; i++) {
|
||||
if (Lawnchair.adapters[i].adapter === options.adapter) {
|
||||
adapter = Lawnchair.adapters[i].valid() ? Lawnchair.adapters[i] : undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// otherwise find the first valid adapter for this env
|
||||
}
|
||||
else {
|
||||
for (var i = 0, l = Lawnchair.adapters.length; i < l; i++) {
|
||||
adapter = Lawnchair.adapters[i].valid() ? Lawnchair.adapters[i] : undefined
|
||||
if (adapter) break
|
||||
}
|
||||
}
|
||||
|
||||
// we have failed
|
||||
if (!adapter) throw 'No valid adapter.'
|
||||
|
||||
// yay! mixin the adapter
|
||||
for (var j in adapter)
|
||||
this[j] = adapter[j]
|
||||
|
||||
// call init for each mixed in plugin
|
||||
for (var i = 0, l = Lawnchair.plugins.length; i < l; i++)
|
||||
Lawnchair.plugins[i].call(this)
|
||||
|
||||
// init the adapter
|
||||
this.init(options, callback)
|
||||
}
|
||||
|
||||
Lawnchair.adapters = []
|
||||
|
||||
/**
|
||||
* queues an adapter for mixin
|
||||
* ===
|
||||
* - ensures an adapter conforms to a specific interface
|
||||
*
|
||||
*/
|
||||
Lawnchair.adapter = function (id, obj) {
|
||||
// add the adapter id to the adapter obj
|
||||
// ugly here for a cleaner dsl for implementing adapters
|
||||
obj['adapter'] = id
|
||||
// methods required to implement a lawnchair adapter
|
||||
var implementing = 'adapter valid init keys save batch get exists all remove nuke'.split(' ')
|
||||
, indexOf = this.prototype.indexOf
|
||||
// mix in the adapter
|
||||
for (var i in obj) {
|
||||
if (indexOf(implementing, i) === -1) throw 'Invalid adapter! Nonstandard method: ' + i
|
||||
}
|
||||
// if we made it this far the adapter interface is valid
|
||||
// insert the new adapter as the preferred adapter
|
||||
Lawnchair.adapters.splice(0,0,obj)
|
||||
}
|
||||
|
||||
Lawnchair.plugins = []
|
||||
|
||||
/**
|
||||
* generic shallow extension for plugins
|
||||
* ===
|
||||
* - if an init method is found it registers it to be called when the lawnchair is inited
|
||||
* - yes we could use hasOwnProp but nobody here is an asshole
|
||||
*/
|
||||
Lawnchair.plugin = function (obj) {
|
||||
for (var i in obj)
|
||||
i === 'init' ? Lawnchair.plugins.push(obj[i]) : this.prototype[i] = obj[i]
|
||||
}
|
||||
|
||||
/**
|
||||
* helpers
|
||||
*
|
||||
*/
|
||||
Lawnchair.prototype = {
|
||||
|
||||
isArray: Array.isArray || function(o) { return Object.prototype.toString.call(o) === '[object Array]' },
|
||||
|
||||
/**
|
||||
* this code exists for ie8... for more background see:
|
||||
* http://www.flickr.com/photos/westcoastlogic/5955365742/in/photostream
|
||||
*/
|
||||
indexOf: function(ary, item, i, l) {
|
||||
if (ary.indexOf) return ary.indexOf(item)
|
||||
for (i = 0, l = ary.length; i < l; i++) if (ary[i] === item) return i
|
||||
return -1
|
||||
},
|
||||
|
||||
// awesome shorthand callbacks as strings. this is shameless theft from dojo.
|
||||
lambda: function (callback) {
|
||||
return this.fn(this.record, callback)
|
||||
},
|
||||
|
||||
// first stab at named parameters for terse callbacks; dojo: first != best // ;D
|
||||
fn: function (name, callback) {
|
||||
return typeof callback == 'string' ? new Function(name, callback) : callback
|
||||
},
|
||||
|
||||
// returns a unique identifier (by way of Backbone.localStorage.js)
|
||||
// TODO investigate smaller UUIDs to cut on storage cost
|
||||
uuid: function () {
|
||||
var S4 = function () {
|
||||
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
||||
}
|
||||
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
|
||||
},
|
||||
|
||||
// a classic iterator
|
||||
each: function (callback) {
|
||||
var cb = this.lambda(callback)
|
||||
// iterate from chain
|
||||
if (this.__results) {
|
||||
for (var i = 0, l = this.__results.length; i < l; i++) cb.call(this, this.__results[i], i)
|
||||
}
|
||||
// otherwise iterate the entire collection
|
||||
else {
|
||||
this.all(function(r) {
|
||||
for (var i = 0, l = r.length; i < l; i++) cb.call(this, r[i], i)
|
||||
})
|
||||
}
|
||||
return this
|
||||
}
|
||||
// --
|
||||
};
|
||||
// window.name code courtesy Remy Sharp: http://24ways.org/2009/breaking-out-the-edges-of-the-browser
|
||||
Lawnchair.adapter('window-name', (function(index, store) {
|
||||
if (typeof window==='undefined') {
|
||||
window = { top: { } }; // node/optimizer compatibility
|
||||
}
|
||||
|
||||
var data = window.top.name ? JSON.parse(window.top.name) : {}
|
||||
|
||||
return {
|
||||
|
||||
valid: function () {
|
||||
return typeof window.top.name != 'undefined'
|
||||
},
|
||||
|
||||
init: function (options, callback) {
|
||||
data[this.name] = data[this.name] || {index:[],store:{}}
|
||||
index = data[this.name].index
|
||||
store = data[this.name].store
|
||||
this.fn(this.name, callback).call(this, this)
|
||||
},
|
||||
|
||||
keys: function (callback) {
|
||||
this.fn('keys', callback).call(this, index)
|
||||
return this
|
||||
},
|
||||
|
||||
save: function (obj, cb) {
|
||||
// data[key] = value + ''; // force to string
|
||||
// window.top.name = JSON.stringify(data);
|
||||
var key = obj.key || this.uuid()
|
||||
this.exists(key, function(exists) {
|
||||
if (!exists) {
|
||||
if (obj.key) delete obj.key
|
||||
index.push(key)
|
||||
}
|
||||
store[key] = obj
|
||||
window.top.name = JSON.stringify(data) // TODO wow, this is the only diff from the memory adapter
|
||||
if (cb) {
|
||||
obj.key = key
|
||||
this.lambda(cb).call(this, obj)
|
||||
}
|
||||
})
|
||||
return this
|
||||
},
|
||||
|
||||
batch: function (objs, cb) {
|
||||
var r = []
|
||||
for (var i = 0, l = objs.length; i < l; i++) {
|
||||
this.save(objs[i], function(record) {
|
||||
r.push(record)
|
||||
})
|
||||
}
|
||||
if (cb) this.lambda(cb).call(this, r)
|
||||
return this
|
||||
},
|
||||
|
||||
get: function (keyOrArray, cb) {
|
||||
var r;
|
||||
if (this.isArray(keyOrArray)) {
|
||||
r = []
|
||||
for (var i = 0, l = keyOrArray.length; i < l; i++) {
|
||||
r.push(store[keyOrArray[i]])
|
||||
}
|
||||
} else {
|
||||
r = store[keyOrArray]
|
||||
if (r) r.key = keyOrArray
|
||||
}
|
||||
if (cb) this.lambda(cb).call(this, r)
|
||||
return this
|
||||
},
|
||||
|
||||
exists: function (key, cb) {
|
||||
this.lambda(cb).call(this, !!(store[key]))
|
||||
return this
|
||||
},
|
||||
|
||||
all: function (cb) {
|
||||
var r = []
|
||||
for (var i = 0, l = index.length; i < l; i++) {
|
||||
var obj = store[index[i]]
|
||||
obj.key = index[i]
|
||||
r.push(obj)
|
||||
}
|
||||
this.fn(this.name, cb).call(this, r)
|
||||
return this
|
||||
},
|
||||
|
||||
remove: function (keyOrArray, cb) {
|
||||
var del = this.isArray(keyOrArray) ? keyOrArray : [keyOrArray]
|
||||
for (var i = 0, l = del.length; i < l; i++) {
|
||||
delete store[del[i]]
|
||||
index.splice(this.indexOf(index, del[i]), 1)
|
||||
}
|
||||
window.top.name = JSON.stringify(data)
|
||||
if (cb) this.lambda(cb).call(this)
|
||||
return this
|
||||
},
|
||||
|
||||
nuke: function (cb) {
|
||||
store = {}
|
||||
index = []
|
||||
window.top.name = JSON.stringify(data)
|
||||
if (cb) this.lambda(cb).call(this)
|
||||
return this
|
||||
}
|
||||
}
|
||||
/////
|
||||
})())
|
||||
/**
|
||||
* dom storage adapter
|
||||
* ===
|
||||
* - originally authored by Joseph Pecoraro
|
||||
*
|
||||
*/
|
||||
//
|
||||
// TODO does it make sense to be chainable all over the place?
|
||||
// chainable: nuke, remove, all, get, save, all
|
||||
// not chainable: valid, keys
|
||||
//
|
||||
Lawnchair.adapter('dom', (function() {
|
||||
var storage = window.localStorage
|
||||
// the indexer is an encapsulation of the helpers needed to keep an ordered index of the keys
|
||||
var indexer = function(name) {
|
||||
return {
|
||||
// the key
|
||||
key: name + '._index_',
|
||||
// returns the index
|
||||
all: function() {
|
||||
var a = storage.getItem(this.key)
|
||||
if (a) {
|
||||
a = JSON.parse(a)
|
||||
}
|
||||
if (a === null) storage.setItem(this.key, JSON.stringify([])) // lazy init
|
||||
return JSON.parse(storage.getItem(this.key))
|
||||
},
|
||||
// adds a key to the index
|
||||
add: function (key) {
|
||||
var a = this.all()
|
||||
a.push(key)
|
||||
storage.setItem(this.key, JSON.stringify(a))
|
||||
},
|
||||
// deletes a key from the index
|
||||
del: function (key) {
|
||||
var a = this.all(), r = []
|
||||
// FIXME this is crazy inefficient but I'm in a strata meeting and half concentrating
|
||||
for (var i = 0, l = a.length; i < l; i++) {
|
||||
if (a[i] != key) r.push(a[i])
|
||||
}
|
||||
storage.setItem(this.key, JSON.stringify(r))
|
||||
},
|
||||
// returns index for a key
|
||||
find: function (key) {
|
||||
var a = this.all()
|
||||
for (var i = 0, l = a.length; i < l; i++) {
|
||||
if (key === a[i]) return i
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adapter api
|
||||
return {
|
||||
|
||||
// ensure we are in an env with localStorage
|
||||
valid: function () {
|
||||
return !!storage && function() {
|
||||
// in mobile safari if safe browsing is enabled, window.storage
|
||||
// is defined but setItem calls throw exceptions.
|
||||
var success = true
|
||||
var value = Math.random()
|
||||
try {
|
||||
storage.setItem(value, value)
|
||||
} catch (e) {
|
||||
success = false
|
||||
}
|
||||
storage.removeItem(value)
|
||||
return success
|
||||
}()
|
||||
},
|
||||
|
||||
init: function (options, callback) {
|
||||
this.indexer = indexer(this.name)
|
||||
if (callback) this.fn(this.name, callback).call(this, this)
|
||||
},
|
||||
|
||||
save: function (obj, callback) {
|
||||
var key = obj.key ? this.name + '.' + obj.key : this.name + '.' + this.uuid()
|
||||
// if the key is not in the index push it on
|
||||
if (this.indexer.find(key) === false) this.indexer.add(key)
|
||||
// now we kil the key and use it in the store colleciton
|
||||
delete obj.key;
|
||||
storage.setItem(key, JSON.stringify(obj))
|
||||
obj.key = key.slice(this.name.length + 1)
|
||||
if (callback) {
|
||||
this.lambda(callback).call(this, obj)
|
||||
}
|
||||
return this
|
||||
},
|
||||
|
||||
batch: function (ary, callback) {
|
||||
var saved = []
|
||||
// not particularily efficient but this is more for sqlite situations
|
||||
for (var i = 0, l = ary.length; i < l; i++) {
|
||||
this.save(ary[i], function(r){
|
||||
saved.push(r)
|
||||
})
|
||||
}
|
||||
if (callback) this.lambda(callback).call(this, saved)
|
||||
return this
|
||||
},
|
||||
|
||||
// accepts [options], callback
|
||||
keys: function(callback) {
|
||||
if (callback) {
|
||||
var name = this.name
|
||||
, keys = this.indexer.all().map(function(r){ return r.replace(name + '.', '') })
|
||||
this.fn('keys', callback).call(this, keys)
|
||||
}
|
||||
return this // TODO options for limit/offset, return promise
|
||||
},
|
||||
|
||||
get: function (key, callback) {
|
||||
if (this.isArray(key)) {
|
||||
var r = []
|
||||
for (var i = 0, l = key.length; i < l; i++) {
|
||||
var k = this.name + '.' + key[i]
|
||||
var obj = storage.getItem(k)
|
||||
if (obj) {
|
||||
obj = JSON.parse(obj)
|
||||
obj.key = key[i]
|
||||
r.push(obj)
|
||||
}
|
||||
}
|
||||
if (callback) this.lambda(callback).call(this, r)
|
||||
} else {
|
||||
var k = this.name + '.' + key
|
||||
var obj = storage.getItem(k)
|
||||
if (obj) {
|
||||
obj = JSON.parse(obj)
|
||||
obj.key = key
|
||||
}
|
||||
if (callback) this.lambda(callback).call(this, obj)
|
||||
}
|
||||
return this
|
||||
},
|
||||
|
||||
exists: function (key, cb) {
|
||||
var exists = this.indexer.find(this.name+'.'+key) === false ? false : true ;
|
||||
this.lambda(cb).call(this, exists);
|
||||
return this;
|
||||
},
|
||||
// NOTE adapters cannot set this.__results but plugins do
|
||||
// this probably should be reviewed
|
||||
all: function (callback) {
|
||||
var idx = this.indexer.all()
|
||||
, r = []
|
||||
, o
|
||||
, k
|
||||
for (var i = 0, l = idx.length; i < l; i++) {
|
||||
k = idx[i] //v
|
||||
o = JSON.parse(storage.getItem(k))
|
||||
o.key = k.replace(this.name + '.', '')
|
||||
r.push(o)
|
||||
}
|
||||
if (callback) this.fn(this.name, callback).call(this, r)
|
||||
return this
|
||||
},
|
||||
|
||||
remove: function (keyOrObj, callback) {
|
||||
var key = this.name + '.' + ((keyOrObj.key) ? keyOrObj.key : keyOrObj)
|
||||
this.indexer.del(key)
|
||||
storage.removeItem(key)
|
||||
if (callback) this.lambda(callback).call(this)
|
||||
return this
|
||||
},
|
||||
|
||||
nuke: function (callback) {
|
||||
this.all(function(r) {
|
||||
for (var i = 0, l = r.length; i < l; i++) {
|
||||
this.remove(r[i]);
|
||||
}
|
||||
if (callback) this.lambda(callback).call(this)
|
||||
})
|
||||
return this
|
||||
}
|
||||
}})());
|
|
@ -0,0 +1,3 @@
|
|||
.edit-priority
|
||||
.input.edit-priority-field(type="text" value="<%= p.name %>" data-for="<%= p.pos %>")
|
||||
.button.delete-priority-field(data-for="<%= p.pos %>")
|
|
@ -12,13 +12,15 @@
|
|||
%title Priority / Ignore
|
||||
|
||||
%body
|
||||
#content
|
||||
#leftbrain.column
|
||||
%h1.prioritize Today I Will Pay Attention To:
|
||||
#priorities
|
||||
#rightbrain.column
|
||||
%h1.prioritize Today I Will Ignore:
|
||||
#ignorities
|
||||
#grid.container
|
||||
.flow
|
||||
.row-fluid
|
||||
#leftbrain.span6
|
||||
%h1#prioritize(data-for="0") Today I Will Pay Attention To:
|
||||
#priorities
|
||||
#rightbrain.span6
|
||||
%h1#ignorize(data-for="0") Today I Will Ignore:
|
||||
#ignorities
|
||||
|
||||
#message(style="display:none")
|
||||
%h2 How to Use
|
||||
|
|
|
@ -2,47 +2,70 @@ require.config
|
|||
paths:
|
||||
'jquery': 'jquery-1.7.2'
|
||||
|
||||
require ['jquery', 'priority_tmpl'], ($, priority_template) ->
|
||||
require ['jquery', 'priority_tmpl', 'lawnchair'], ($, priority_template) ->
|
||||
|
||||
class Prioritize
|
||||
|
||||
constructor(@repo) ->
|
||||
constructor: (@repo) ->
|
||||
@repo.get 'priorities', (p) =>
|
||||
@priorities = if p? and p.priorities? then p.priorities else []
|
||||
@render()
|
||||
|
||||
$('body').on 'click', @render
|
||||
$('#thumbsup').on 'click', () => @newPriority('priority')
|
||||
$('#thumbsdn').on 'click', () => @newPriority('ignore')
|
||||
$('#prioritize').on 'click', (ev) => @editPriority(ev, 'priority')
|
||||
$('#ignorize').on 'click', (ev) => @editPriority(ev, 'ignore')
|
||||
|
||||
|
||||
editPriority: (ev, ty = 'parent') =>
|
||||
|
||||
|
||||
newPriority: (ty, ev) =>
|
||||
ev.stopPropagation()
|
||||
return if $('.edit-priority').length > 0
|
||||
target = if ty == 'priority' then $('#priorities') else $('#ignorities')
|
||||
target.append(edit_priorities_template({fur: ty}))
|
||||
input = $('input.edit-priority-field', target)
|
||||
|
||||
maybeNewPrioritySave = (ev) =>
|
||||
prioritySave = =>
|
||||
@priorities.push({cat: ty, name: input.val()})
|
||||
@save()
|
||||
|
||||
code = if ev.keyCode then ev.keyCode else ev.which
|
||||
return prioritySave() if code == 13
|
||||
return @cleanAndRender() if code == 27
|
||||
|
||||
input.on 'keyup', maybeNewPrioritySave
|
||||
$('.delete-priority-field', target).on 'click', @render
|
||||
input.focus()
|
||||
|
||||
save: ->
|
||||
@repo.save {key: 'priorities', 'priorities': @priorities}, () =>
|
||||
@render()
|
||||
|
||||
clean: ->
|
||||
@priorities = ({name: p.name, cat: p.cat} for p in @priorities when c.name.trim() != "")
|
||||
|
||||
cleanAndRender: ->
|
||||
@clean()
|
||||
@render()
|
||||
|
||||
save: ->
|
||||
@repo.save {key: 'priorities', 'priorities': @priorities}, =>
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
priority_enumerate = (cat) ->
|
||||
(c for c in @priorities if c.cat == cat)
|
||||
priority_enumerate = (cat) =>
|
||||
r = []
|
||||
for i in [0...@priorities.length]
|
||||
if @priorities[i].cat == cat
|
||||
r.push({name: @priorities[i].name, cat: @priorities[i].cat, pos: i})
|
||||
r
|
||||
|
||||
priority_render = (cat) ->
|
||||
$('#priority_list').html(priority_template({priorities: priority_enumerate('priority')}))
|
||||
$('#ignore_list').html(priority_template({priorities: priority_enumerate('ignore')}))
|
||||
$('#priorities').html(priority_template({priorities: priority_enumerate('priority')}))
|
||||
$('#ignorities').html(priority_template({priorities: priority_enumerate('ignore')}))
|
||||
|
||||
$ ->
|
||||
prioritize = new Lawnchair {name: 'Prioritize'}, ->
|
||||
p = this
|
||||
p.save
|
||||
key: 'priorities',
|
||||
priorities: [
|
||||
{cat: 'priority', name: 'Omaha, Stormy, Raeney'}
|
||||
{cat: 'ignore', name: 'Politics'}
|
||||
{cat: 'priority', name: 'Spiral Genetics'}
|
||||
{cat: 'priority', name: 'Looking for Work'}
|
||||
{cat: 'priority', name: 'Writing'}
|
||||
{cat: 'priority', name: 'Productivity Core'}
|
||||
{cat: 'priority', name: 'Story Core'}
|
||||
{cat: 'ignore', name: 'Smut'}
|
||||
{cat: 'ignore', name: 'Religious Arguments'}
|
||||
{cat: 'ignore', name: 'PASWO'}
|
||||
{cat: 'ignore', name: 'Twitter'}
|
||||
], ->
|
||||
handler = new Prioritize(p)
|
||||
handler = new Prioritize(this)
|
||||
handler.render()
|
||||
|
|
414
src/style.less
414
src/style.less
|
@ -55,41 +55,320 @@ input[type="search"]::-webkit-search-cancel-button {
|
|||
}
|
||||
|
||||
|
||||
* {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
font: 13pt/190% Calibri,Georgia,"Lucida Bright",Lucidabright,"Bitstream Vera Serif",serif;
|
||||
font: 13pt/190% Montserrat,Calibri,Georgia,"Lucida Bright",Lucidabright,"Bitstream Vera Serif",serif;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: .25in .75in .25in 1.5in;
|
||||
}
|
||||
.clearoncolumn {
|
||||
clear: none;
|
||||
.clearfix {
|
||||
*zoom: 1;
|
||||
&:before,
|
||||
&:after {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
&:after {
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 480px) {
|
||||
body {
|
||||
margin: .25in .75in .25in 1.5in;
|
||||
}
|
||||
.clearoncolumn {
|
||||
clear: none;
|
||||
}
|
||||
// Block level inputs
|
||||
.input-block-level {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 28px; // Make inputs at least the height of their button counterpart
|
||||
.box-sizing(border-box); // Makes inputs behave like true block-level elements
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 479px) {
|
||||
body {
|
||||
margin: 2% 2% 0 6%;
|
||||
|
||||
// GRID
|
||||
// --------------------------------------------------
|
||||
|
||||
// Default 940px grid
|
||||
// -------------------------
|
||||
@gridColumns: 12;
|
||||
@gridColumnWidth: 60px;
|
||||
@gridGutterWidth: 20px;
|
||||
@gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
|
||||
|
||||
// Fluid grid
|
||||
// -------------------------
|
||||
@fluidGridColumnWidth: 6.382978723%;
|
||||
@fluidGridGutterWidth: 2.127659574%;
|
||||
|
||||
#grid {
|
||||
|
||||
.core (@gridColumnWidth, @gridGutterWidth) {
|
||||
|
||||
.spanX (@index) when (@index > 0) {
|
||||
(~".span@{index}") { .span(@index); }
|
||||
.spanX(@index - 1);
|
||||
}
|
||||
.clearoncolumn {
|
||||
clear: both;
|
||||
.spanX (0) {}
|
||||
|
||||
.offsetX (@index) when (@index > 0) {
|
||||
(~".offset@{index}") { .offset(@index); }
|
||||
.offsetX(@index - 1);
|
||||
}
|
||||
.offsetX (0) {}
|
||||
|
||||
.offset (@columns) {
|
||||
margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1));
|
||||
}
|
||||
|
||||
.span (@columns) {
|
||||
width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-left: @gridGutterWidth * -1;
|
||||
.clearfix();
|
||||
}
|
||||
|
||||
[class*="span"] {
|
||||
float: left;
|
||||
margin-left: @gridGutterWidth;
|
||||
}
|
||||
|
||||
// Set the container width, and override it for fixed navbars in media queries
|
||||
.container,
|
||||
.navbar-fixed-top .container,
|
||||
.navbar-fixed-bottom .container { .span(@gridColumns); }
|
||||
|
||||
// generate .spanX and .offsetX
|
||||
.spanX (@gridColumns);
|
||||
.offsetX (@gridColumns);
|
||||
|
||||
}
|
||||
|
||||
.fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) {
|
||||
|
||||
.spanX (@index) when (@index > 0) {
|
||||
(~".span@{index}") { .span(@index); }
|
||||
.spanX(@index - 1);
|
||||
}
|
||||
.spanX (0) {}
|
||||
|
||||
.span (@columns) {
|
||||
width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));
|
||||
*width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);
|
||||
}
|
||||
|
||||
.row-fluid {
|
||||
width: 100%;
|
||||
.clearfix();
|
||||
[class*="span"] {
|
||||
.input-block-level();
|
||||
float: left;
|
||||
margin-left: @fluidGridGutterWidth;
|
||||
*margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
|
||||
}
|
||||
[class*="span"]:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
// generate .spanX
|
||||
.spanX (@gridColumns);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.input(@gridColumnWidth, @gridGutterWidth) {
|
||||
|
||||
.spanX (@index) when (@index > 0) {
|
||||
(~"input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index}") { .span(@index); }
|
||||
.spanX(@index - 1);
|
||||
}
|
||||
.spanX (0) {}
|
||||
|
||||
.span(@columns) {
|
||||
width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 10;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
.uneditable-input {
|
||||
margin-left: 0; // override margin-left from core grid system
|
||||
}
|
||||
|
||||
// generate .spanX
|
||||
.spanX (@gridColumns);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 979px) {
|
||||
|
||||
// Fixed grid
|
||||
#grid > .core(42px, 20px);
|
||||
|
||||
// Fluid grid
|
||||
#grid > .fluid(5.801104972%, 2.762430939%);
|
||||
|
||||
// Input grid
|
||||
#grid > .input(42px, 20px);
|
||||
|
||||
// No need to reset .thumbnails here since it is the same @gridGutterWidth
|
||||
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
|
||||
// Fixed grid
|
||||
#grid > .core(70px, 30px);
|
||||
|
||||
// Fluid grid
|
||||
#grid > .fluid(5.982905983%, 2.564102564%);
|
||||
|
||||
// Input grid
|
||||
#grid > .input(70px, 30px);
|
||||
|
||||
// Thumbnails
|
||||
.thumbnails {
|
||||
margin-left: -30px;
|
||||
}
|
||||
.thumbnails > li {
|
||||
margin-left: 30px;
|
||||
}
|
||||
.row-fluid .thumbnails {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
|
||||
// Smooth out the collapsing/expanding nav
|
||||
.nav-collapse {
|
||||
-webkit-transform: translate3d(0, 0, 0); // activate the GPU
|
||||
}
|
||||
|
||||
// Block level the page header small tag for readability
|
||||
.page-header h1 small {
|
||||
display: block;
|
||||
line-height: @baseLineHeight;
|
||||
}
|
||||
|
||||
// Update checkboxes for iOS
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
// Remove the horizontal form styles
|
||||
.form-horizontal .control-group > label {
|
||||
float: none;
|
||||
width: auto;
|
||||
padding-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.modal-header .close {
|
||||
padding: 10px;
|
||||
margin: -10px;
|
||||
}
|
||||
|
||||
// Carousel
|
||||
.carousel-caption {
|
||||
position: static;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// LANDSCAPE PHONE TO SMALL DESKTOP & PORTRAIT TABLET
|
||||
// --------------------------------------------------
|
||||
|
||||
@media (max-width: 767px) {
|
||||
|
||||
// Padding to set content in a bit
|
||||
body {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
// Negative indent the now static "fixed" navbar
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
}
|
||||
// Remove padding on container given explicit padding set on body
|
||||
.container-fluid {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// TYPOGRAPHY
|
||||
// ----------
|
||||
// Reset horizontal dl
|
||||
.dl-horizontal {
|
||||
dt {
|
||||
float: none;
|
||||
clear: none;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
}
|
||||
dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// GRID & CONTAINERS
|
||||
// -----------------
|
||||
// Remove width from containers
|
||||
.container {
|
||||
width: auto;
|
||||
}
|
||||
// Fluid rows
|
||||
.row-fluid {
|
||||
width: 100%;
|
||||
}
|
||||
// Undo negative margin on rows and thumbnails
|
||||
.row,
|
||||
.thumbnails {
|
||||
margin-left: 0;
|
||||
}
|
||||
// Make all grid-sized elements block level again
|
||||
[class*="span"],
|
||||
.row-fluid [class*="span"] {
|
||||
float: none;
|
||||
display: block;
|
||||
width: auto;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
// FORM FIELDS
|
||||
// -----------
|
||||
// Make span* classes full width
|
||||
.input-large,
|
||||
.input-xlarge,
|
||||
.input-xxlarge,
|
||||
input[class*="span"],
|
||||
select[class*="span"],
|
||||
textarea[class*="span"],
|
||||
.uneditable-input {
|
||||
.input-block-level();
|
||||
}
|
||||
// But don't let it screw up prepend/append inputs
|
||||
.input-prepend input,
|
||||
.input-append input,
|
||||
.input-prepend input[class*="span"],
|
||||
.input-append input[class*="span"] {
|
||||
display: inline-block; // redeclare so they don't wrap to new lines
|
||||
width: auto;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@baseLineHeight: 18px;
|
||||
|
||||
// Box sizing
|
||||
.box-sizing(@boxmodel) {
|
||||
-webkit-box-sizing: @boxmodel;
|
||||
-moz-box-sizing: @boxmodel;
|
||||
-ms-box-sizing: @boxmodel;
|
||||
box-sizing: @boxmodel;
|
||||
}
|
||||
|
||||
p,li,ul {
|
||||
|
@ -110,92 +389,23 @@ ul + p {
|
|||
margin-top: 1em;
|
||||
}
|
||||
|
||||
#content {
|
||||
max-width: 732px;
|
||||
}
|
||||
#prioritize { background: url(thumbsup.png) top left no-repeat; }
|
||||
#ignorize { background: url(thumbsdown.png) top left no-repeat; }
|
||||
|
||||
#braindiv {
|
||||
#msg {
|
||||
font-size: 24px;
|
||||
color: #999;
|
||||
|
||||
p {
|
||||
width: 7em;
|
||||
font-size: 20px;
|
||||
margin: -3px 0 -8px 0;
|
||||
padding: 0 0 0 0;
|
||||
.doing {
|
||||
color: #c00;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#braindiv {
|
||||
float: left;
|
||||
width: 45%;
|
||||
padding-right: 5%;
|
||||
|
||||
#img {
|
||||
width: 164px;
|
||||
height: 226px;
|
||||
background: url(brain-in-a-jar.jpg) top right no-repeat;
|
||||
padding: 0 0 1em 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 480px) {
|
||||
#braindiv {
|
||||
float: left;
|
||||
width: 45%;
|
||||
padding-right: 5%;
|
||||
|
||||
#img {
|
||||
width: 164px;
|
||||
height: 226px;
|
||||
background: url(brain-in-a-jar.jpg) top right no-repeat;
|
||||
padding: 0 0 1em 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 479px) {
|
||||
#braindiv {
|
||||
width: 100%;
|
||||
|
||||
#img {
|
||||
float: left;
|
||||
width: 37.5%;
|
||||
min-width: 122px;
|
||||
height: 165px;
|
||||
background: url(brain-in-a-jar-sm.jpg) top right no-repeat;
|
||||
padding: 0 0 1em 0;
|
||||
}
|
||||
|
||||
#msg {
|
||||
float: right;
|
||||
width: 60.353125%;
|
||||
}
|
||||
padding-bottom: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#rightnow {
|
||||
float: left;
|
||||
width: 49.9%;
|
||||
#grid {
|
||||
margin: 0 auto;
|
||||
|
||||
h1 {
|
||||
display: block;
|
||||
float: left;
|
||||
padding-bottom: 0;
|
||||
min-height: 72px;
|
||||
border: none;
|
||||
color: #333;
|
||||
font-size: 20px;
|
||||
font-size: 24px;
|
||||
font-weight: normal;
|
||||
line-height: 1.2;
|
||||
padding-left: 80px;
|
||||
padding-top: 18px;
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue