From 9f625f927aadf6d9574bd968d2cfc29dde5551c0 Mon Sep 17 00:00:00 2001 From: Robert Postill Date: Wed, 18 Jul 2012 14:01:40 -0700 Subject: Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a716775 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +allthethings +============ \ No newline at end of file -- cgit v1.2.3 From c63c8f1698e8c059e286fb49ba0264e4336a6e33 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Tue, 24 Jul 2012 15:25:22 -0400 Subject: Initial version. 0.1.0 Release --- .gitignore | 1 + README.md | 15 +- bin/att | 66 + lib/allthethings.rb | 119 + templates/project/README.md | 1 + templates/project/config.ru | 7 + templates/project/dashboards/layout.erb | 21 + templates/project/dashboards/main.erb | 1 + templates/project/jobs/sample.rb | 12 + templates/project/lib/.empty_directory | 1 + templates/project/public/images/.empty_directory | 1 + .../project/public/javascripts/.empty_directory | 1 + .../project/public/stylesheets/.empty_directory | 1 + templates/project/widgets/.empty_directory | 1 + templates/project/widgets/sample/sample.coffee | 2 + templates/project/widgets/sample/sample.html | 4 + templates/project/widgets/sample/sample.scss | 0 templates/widget/%name%.coffee.tt | 2 + templates/widget/%name%.html | 0 templates/widget/%name%.scss | 0 vendor/javascripts/application.coffee | 51 + vendor/javascripts/batman.jquery.js | 109 + vendor/javascripts/batman.js | 11828 +++++++++++++++++++ vendor/javascripts/es5-shim.js | 1021 ++ vendor/javascripts/jquery.js | 4 + vendor/javascripts/widget.coffee | 14 + 26 files changed, 13281 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100755 bin/att create mode 100644 lib/allthethings.rb create mode 100644 templates/project/README.md create mode 100644 templates/project/config.ru create mode 100644 templates/project/dashboards/layout.erb create mode 100644 templates/project/dashboards/main.erb create mode 100644 templates/project/jobs/sample.rb create mode 100644 templates/project/lib/.empty_directory create mode 100644 templates/project/public/images/.empty_directory create mode 100644 templates/project/public/javascripts/.empty_directory create mode 100644 templates/project/public/stylesheets/.empty_directory create mode 100644 templates/project/widgets/.empty_directory create mode 100644 templates/project/widgets/sample/sample.coffee create mode 100644 templates/project/widgets/sample/sample.html create mode 100644 templates/project/widgets/sample/sample.scss create mode 100644 templates/widget/%name%.coffee.tt create mode 100644 templates/widget/%name%.html create mode 100644 templates/widget/%name%.scss create mode 100644 vendor/javascripts/application.coffee create mode 100644 vendor/javascripts/batman.jquery.js create mode 100644 vendor/javascripts/batman.js create mode 100644 vendor/javascripts/es5-shim.js create mode 100644 vendor/javascripts/jquery.js create mode 100644 vendor/javascripts/widget.coffee diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84b55ed --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*DS_STORE \ No newline at end of file diff --git a/README.md b/README.md index a716775..53e34ee 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ -allthethings -============ \ No newline at end of file +TODO +==== + +- fix textfield style +- tests +- Create a better readme! +- Add data fetching capabilities +- Turn into its own gem +- Come up with a default style +- Create example widgets +- investigate if Dir.pwd is the best approach to get the local directory +- Create githubpages +- Open source! diff --git a/bin/att b/bin/att new file mode 100755 index 0000000..fe8db05 --- /dev/null +++ b/bin/att @@ -0,0 +1,66 @@ +#!/usr/bin/env ruby + +require 'thor' +require 'net/http' +require 'json' + +class MockScheduler + def method_missing(*args) + yield + end +end + +def send_event(id, data) + req = Net::HTTP::Post.new("/widgets/#{id}") + req["content-type"] = "application/json" + req.body = JSON.unparse(data.merge(:auth_token => AllTheThings::CLI.auth_token)) + res = Net::HTTP.new('localhost', 3000).start { |http| http.request(req) } + puts "Data Sent to #{id}: #{data}" +end + +SCHEDULER = MockScheduler.new + +module AllTheThings + + class CLI < Thor + include Thor::Actions + + class << self + attr_accessor :auth_token + end + + attr_accessor :name + + def self.source_root + File.expand_path('../../templates', __FILE__) + end + + desc "install PROJECT_NAME", "Sets up ALL THE THINGS needed for your dashboard project structure." + def install(name) + @name = Thor::Util.snake_case(name) + directory :project, @name + end + + desc "new_widget WIDGET_NAME", "Creates a new widget with all the fixins'" + def new_widget(name) + @name = Thor::Util.snake_case(name) + directory :widget, File.join('widgets', @name) + end + + desc "start", "Starts the server in style!" + def start(*args) + args = args.join(" ") + system("bundle exec thin -R config.ru start #{args}") + end + + desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job." + def job(name, auth_token = "") + self.class.auth_token = auth_token + f = File.join(Dir.pwd, "jobs", "#{name}.rb") + require f + end + + end +end + +AllTheThings::CLI.start \ No newline at end of file diff --git a/lib/allthethings.rb b/lib/allthethings.rb new file mode 100644 index 0000000..cf4a62a --- /dev/null +++ b/lib/allthethings.rb @@ -0,0 +1,119 @@ +require 'sinatra' +require 'sinatra/content_for' +require 'rufus/scheduler' +require 'coffee-script' +require 'sass' +require 'json' + +Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } + +SCHEDULER = Rufus::Scheduler.start_new + +set server: 'thin', connections: [], history: {} +helpers Sinatra::ContentFor + +def configure(&block) + set :public_folder, Dir.pwd + '/public' + set :views, Dir.pwd + '/dashboards' + set :default_dashboard, nil + instance_eval(&block) +end + +get '/events', provides: 'text/event-stream' do + stream :keep_open do |out| + settings.connections << out + out << latest_events + out.callback { settings.connections.delete(out) } + end +end + +get '/' do + begin + redirect "/" + (settings.default_dashboard || first_dashboard).to_s + rescue NoMethodError => e + raise Exception.new("There are no dashboards in your dashboard directory.") + end +end + +get '/:dashboard' do + erb params[:dashboard].to_sym +end + +get '/views/:widget?.html' do + widget = params[:widget] + send_file File.join(Dir.pwd, "widgets/#{widget}/#{widget}.html") +end + +post '/widgets/:id' do + request.body.rewind + body = JSON.parse(request.body.read) + auth_token = body.delete("auth_token") + if auth_token == settings.auth_token + send_event(params['id'], body) + 204 # response without entity body + else + status 401 + "Invalid API key\n" + end +end + +def framework_javascripts + ['jquery.js', 'es5-shim.js', 'batman.js', 'batman.jquery.js', 'application.coffee', 'widget.coffee'].collect do |f| + File.join(File.expand_path("../../vendor/javascripts", __FILE__), f) + end +end + +def widget_javascripts + asset_paths("/widgets/**/*.coffee") +end + +def javascripts + (framework_javascripts + widget_javascripts).collect do |f| + if File.extname(f) == ".coffee" + begin + CoffeeScript.compile(File.read(f)) + rescue ExecJS::ProgramError => e + message = e.message + ": in #{f}" + raise ExecJS::ProgramError.new(message) + end + else + File.read(f) + end + end.join("\n") +end + +def stylesheets + asset_paths("/public/**/*.scss", "/widgets/**/*.scss").collect do |f| + Sass.compile File.read(f) + end.join("\n") +end + +def asset_paths(*paths) + paths.inject([]) { |arr, path| arr + Dir[File.join(Dir.pwd, path)] } +end + +def send_event(id, body) + body["id"] = id + event = format_event(JSON.unparse(body)) + settings.history[id] = event + settings.connections.each { |out| out << event } +end + +def format_event(body) + "data: #{body}\n\n" +end + +def latest_events + settings.history.inject("") do |str, (id, body)| + str << body + end +end + +def first_dashboard + files = Dir[settings.views + "/*.erb"].collect { |f| f.match(/(\w*).erb/)[1] } + files -= ['layout'] + files.first +end + +files = Dir[Dir.pwd + '/jobs/*.rb'] +files.each { |job| require(job) } \ No newline at end of file diff --git a/templates/project/README.md b/templates/project/README.md new file mode 100644 index 0000000..32f36ad --- /dev/null +++ b/templates/project/README.md @@ -0,0 +1 @@ +Here lies instructions on how to set this thing up. \ No newline at end of file diff --git a/templates/project/config.ru b/templates/project/config.ru new file mode 100644 index 0000000..acc42a0 --- /dev/null +++ b/templates/project/config.ru @@ -0,0 +1,7 @@ +require 'allthethings' + +configure do + set :auth_token, 'YOUR_AUTH_TOKEN' +end + +run Sinatra::Application \ No newline at end of file diff --git a/templates/project/dashboards/layout.erb b/templates/project/dashboards/layout.erb new file mode 100644 index 0000000..66bf1e0 --- /dev/null +++ b/templates/project/dashboards/layout.erb @@ -0,0 +1,21 @@ + + + + + + + <%= yield_content(:title) %> + + + + + + + + +
+ <%= yield %> +
+ + + \ No newline at end of file diff --git a/templates/project/dashboards/main.erb b/templates/project/dashboards/main.erb new file mode 100644 index 0000000..b6797dd --- /dev/null +++ b/templates/project/dashboards/main.erb @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/templates/project/jobs/sample.rb b/templates/project/jobs/sample.rb new file mode 100644 index 0000000..3d7bfcd --- /dev/null +++ b/templates/project/jobs/sample.rb @@ -0,0 +1,12 @@ +SCHEDULER.every '5s' do + sayings = [ + "That's one trouble with dual identities, Robin. Dual responsibilities.", + "You know your neosauruses well, Robin. Peanut butter sandwiches it is.", + "You're far from mod, Robin. And many hippies are older than you are.", + "We're still over land, Robin, and a seal is an aquatic, marine mammal.", + "True. You owe your life to dental hygiene.", + "This money goes to building better roads. We all must do our part." + ] + + send_event('sample', { quote: sayings.sample }) +end \ No newline at end of file diff --git a/templates/project/lib/.empty_directory b/templates/project/lib/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/lib/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/templates/project/public/images/.empty_directory b/templates/project/public/images/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/public/images/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/templates/project/public/javascripts/.empty_directory b/templates/project/public/javascripts/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/public/javascripts/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/templates/project/public/stylesheets/.empty_directory b/templates/project/public/stylesheets/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/public/stylesheets/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/templates/project/widgets/.empty_directory b/templates/project/widgets/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/widgets/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/templates/project/widgets/sample/sample.coffee b/templates/project/widgets/sample/sample.coffee new file mode 100644 index 0000000..cb25885 --- /dev/null +++ b/templates/project/widgets/sample/sample.coffee @@ -0,0 +1,2 @@ +class AllTheThings.Sample extends AllTheThings.Widget + source: 'sample' \ No newline at end of file diff --git a/templates/project/widgets/sample/sample.html b/templates/project/widgets/sample/sample.html new file mode 100644 index 0000000..eea0f1c --- /dev/null +++ b/templates/project/widgets/sample/sample.html @@ -0,0 +1,4 @@ +

w00t! w00t! You've setup your first dashboard!

+

To celebrate, enjoy some of these fun Batman quotes!

+ + diff --git a/templates/project/widgets/sample/sample.scss b/templates/project/widgets/sample/sample.scss new file mode 100644 index 0000000..e69de29 diff --git a/templates/widget/%name%.coffee.tt b/templates/widget/%name%.coffee.tt new file mode 100644 index 0000000..e3e5938 --- /dev/null +++ b/templates/widget/%name%.coffee.tt @@ -0,0 +1,2 @@ +class AllTheThings.<%= Thor::Util.camel_case(name) %> extends AllTheThings.Widget + source: '<%= name %>' \ No newline at end of file diff --git a/templates/widget/%name%.html b/templates/widget/%name%.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/widget/%name%.scss b/templates/widget/%name%.scss new file mode 100644 index 0000000..e69de29 diff --git a/vendor/javascripts/application.coffee b/vendor/javascripts/application.coffee new file mode 100644 index 0000000..54050c6 --- /dev/null +++ b/vendor/javascripts/application.coffee @@ -0,0 +1,51 @@ +Batman.Filters.PrettyNumber = (num) -> + num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") unless isNaN(num) + +class window.AllTheThings extends Batman.App + @root -> + +Batman.Property.EasingSetter = + get: Batman.Property.defaultAccessor.get + set: (k, to) -> + if isNaN(to) + @[k] = to + else + timer = "interval_#{k}" + num = if !isNaN(@[k]) then @[k] else 0 + unless @[timer] || num == to + up = to > num + num_interval = Math.abs(num - to) / 90 + @[timer] = + setInterval => + num = if up then Math.ceil(num+num_interval) else Math.floor(num-num_interval) + if (up && num > to) || (!up && num < to) + num = to + clearInterval(@[timer]) + @[timer] = null + delete @[timer] + @[k] = num + @set k, to + @[k] = num + +AllTheThings.widgets = widgets = {} +AllTheThings.lastEvents = lastEvents = {} + +source = new EventSource('/events') +source.addEventListener 'open', (e)-> + console.log("Connection opened") + +source.addEventListener 'error', (e)-> + console.log("Connection error") + if (e.readyState == EventSource.CLOSED) + console.log("Connection closed") + +source.addEventListener 'message', (e) => + data = JSON.parse(e.data) + lastEvents[data.id] = data + if widgets[data.id]?.length > 0 + for widget in widgets[data.id] + widget.onData(data) + + +$(document).ready -> + AllTheThings.run() \ No newline at end of file diff --git a/vendor/javascripts/batman.jquery.js b/vendor/javascripts/batman.jquery.js new file mode 100644 index 0000000..6407098 --- /dev/null +++ b/vendor/javascripts/batman.jquery.js @@ -0,0 +1,109 @@ +(function() { + + Batman.Request.prototype._parseResponseHeaders = function(xhr) { + var headers; + return headers = xhr.getAllResponseHeaders().split('\n').reduce(function(acc, header) { + var key, matches, value; + if (matches = header.match(/([^:]*):\s*(.*)/)) { + key = matches[1]; + value = matches[2]; + acc[key] = value; + } + return acc; + }, {}); + }; + + Batman.Request.prototype._prepareOptions = function(data) { + var options, _ref, + _this = this; + options = { + url: this.get('url'), + type: this.get('method'), + dataType: this.get('type'), + data: data || this.get('data'), + username: this.get('username'), + password: this.get('password'), + headers: this.get('headers'), + beforeSend: function() { + return _this.fire('loading'); + }, + success: function(response, textStatus, xhr) { + _this.mixin({ + xhr: xhr, + status: xhr.status, + response: response, + responseHeaders: _this._parseResponseHeaders(xhr) + }); + return _this.fire('success', response); + }, + error: function(xhr, status, error) { + _this.mixin({ + xhr: xhr, + status: xhr.status, + response: xhr.responseText, + responseHeaders: _this._parseResponseHeaders(xhr) + }); + xhr.request = _this; + return _this.fire('error', xhr); + }, + complete: function() { + return _this.fire('loaded'); + } + }; + if ((_ref = this.get('method')) === 'PUT' || _ref === 'POST') { + if (!this.hasFileUploads()) { + options.contentType = this.get('contentType'); + if (typeof options.data === 'object') { + options.processData = false; + options.data = Batman.URI.queryFromParams(options.data); + } + } else { + options.contentType = false; + options.processData = false; + options.data = this.constructor.objectToFormData(options.data); + } + } + return options; + }; + + Batman.Request.prototype.send = function(data) { + return jQuery.ajax(this._prepareOptions(data)); + }; + + Batman.mixins.animation = { + show: function(addToParent) { + var jq, show, _ref, _ref1; + jq = $(this); + show = function() { + return jq.show(600); + }; + if (addToParent) { + if ((_ref = addToParent.append) != null) { + _ref.appendChild(this); + } + if ((_ref1 = addToParent.before) != null) { + _ref1.parentNode.insertBefore(this, addToParent.before); + } + jq.hide(); + setTimeout(show, 0); + } else { + show(); + } + return this; + }, + hide: function(removeFromParent) { + var _this = this; + $(this).hide(600, function() { + var _ref; + if (removeFromParent) { + if ((_ref = _this.parentNode) != null) { + _ref.removeChild(_this); + } + } + return Batman.DOM.didRemoveNode(_this); + }); + return this; + } + }; + +}).call(this); \ No newline at end of file diff --git a/vendor/javascripts/batman.js b/vendor/javascripts/batman.js new file mode 100644 index 0000000..f621cca --- /dev/null +++ b/vendor/javascripts/batman.js @@ -0,0 +1,11828 @@ +(function() { + var Batman, + __slice = [].slice; + + Batman = function() { + var mixins; + mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.Object, mixins, function(){}); + }; + + Batman.version = '0.10.0'; + + Batman.config = { + pathPrefix: '/', + usePushState: false, + minificationErrors: true + }; + + (Batman.container = (function() { + return this; + })()).Batman = Batman; + + if (typeof define === 'function') { + define('batman', [], function() { + return Batman; + }); + } + + Batman.exportHelpers = function(onto) { + var k, _i, _len, _ref; + _ref = ['mixin', 'extend', 'unmixin', 'redirect', 'typeOf', 'redirect', 'setImmediate', 'clearImmediate']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + onto["$" + k] = Batman[k]; + } + return onto; + }; + + Batman.exportGlobals = function() { + return Batman.exportHelpers(Batman.container); + }; + +}).call(this); + +(function() { + var __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.Inflector = (function() { + + Inflector.prototype.plural = function(regex, replacement) { + return this._plural.unshift([regex, replacement]); + }; + + Inflector.prototype.singular = function(regex, replacement) { + return this._singular.unshift([regex, replacement]); + }; + + Inflector.prototype.human = function(regex, replacement) { + return this._human.unshift([regex, replacement]); + }; + + Inflector.prototype.uncountable = function() { + var strings; + strings = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return this._uncountable = this._uncountable.concat(strings.map(function(x) { + return new RegExp("" + x + "$", 'i'); + })); + }; + + Inflector.prototype.irregular = function(singular, plural) { + if (singular.charAt(0) === plural.charAt(0)) { + this.plural(new RegExp("(" + (singular.charAt(0)) + ")" + (singular.slice(1)) + "$", "i"), "$1" + plural.slice(1)); + this.plural(new RegExp("(" + (singular.charAt(0)) + ")" + (plural.slice(1)) + "$", "i"), "$1" + plural.slice(1)); + return this.singular(new RegExp("(" + (plural.charAt(0)) + ")" + (plural.slice(1)) + "$", "i"), "$1" + singular.slice(1)); + } else { + this.plural(new RegExp("" + singular + "$", 'i'), plural); + this.plural(new RegExp("" + plural + "$", 'i'), plural); + return this.singular(new RegExp("" + plural + "$", 'i'), singular); + } + }; + + function Inflector() { + this._plural = []; + this._singular = []; + this._uncountable = []; + this._human = []; + } + + Inflector.prototype.ordinalize = function(number) { + var absNumber, _ref; + absNumber = Math.abs(parseInt(number)); + if (_ref = absNumber % 100, __indexOf.call([11, 12, 13], _ref) >= 0) { + return number + "th"; + } else { + switch (absNumber % 10) { + case 1: + return number + "st"; + case 2: + return number + "nd"; + case 3: + return number + "rd"; + default: + return number + "th"; + } + } + }; + + Inflector.prototype.pluralize = function(word) { + var regex, replace_string, uncountableRegex, _i, _j, _len, _len1, _ref, _ref1, _ref2; + _ref = this._uncountable; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + uncountableRegex = _ref[_i]; + if (uncountableRegex.test(word)) { + return word; + } + } + _ref1 = this._plural; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + _ref2 = _ref1[_j], regex = _ref2[0], replace_string = _ref2[1]; + if (regex.test(word)) { + return word.replace(regex, replace_string); + } + } + return word; + }; + + Inflector.prototype.singularize = function(word) { + var regex, replace_string, uncountableRegex, _i, _j, _len, _len1, _ref, _ref1, _ref2; + _ref = this._uncountable; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + uncountableRegex = _ref[_i]; + if (uncountableRegex.test(word)) { + return word; + } + } + _ref1 = this._singular; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + _ref2 = _ref1[_j], regex = _ref2[0], replace_string = _ref2[1]; + if (regex.test(word)) { + return word.replace(regex, replace_string); + } + } + return word; + }; + + Inflector.prototype.humanize = function(word) { + var regex, replace_string, _i, _len, _ref, _ref1; + _ref = this._human; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + _ref1 = _ref[_i], regex = _ref1[0], replace_string = _ref1[1]; + if (regex.test(word)) { + return word.replace(regex, replace_string); + } + } + return word; + }; + + return Inflector; + + })(); + +}).call(this); + +(function() { + var Inflector, camelize_rx, capitalize_rx, humanize_rx1, humanize_rx2, humanize_rx3, underscore_rx1, underscore_rx2; + + camelize_rx = /(?:^|_|\-)(.)/g; + + capitalize_rx = /(^|\s)([a-z])/g; + + underscore_rx1 = /([A-Z]+)([A-Z][a-z])/g; + + underscore_rx2 = /([a-z\d])([A-Z])/g; + + humanize_rx1 = /_id$/; + + humanize_rx2 = /_|-/g; + + humanize_rx3 = /^\w/g; + + Batman.helpers = { + ordinalize: function() { + return Batman.helpers.inflector.ordinalize.apply(Batman.helpers.inflector, arguments); + }, + singularize: function() { + return Batman.helpers.inflector.singularize.apply(Batman.helpers.inflector, arguments); + }, + pluralize: function(count, singular, plural, includeCount) { + var result; + if (includeCount == null) { + includeCount = true; + } + if (arguments.length < 2) { + return Batman.helpers.inflector.pluralize(count); + } else { + result = +count === 1 ? singular : plural || Batman.helpers.inflector.pluralize(singular); + if (includeCount) { + result = ("" + (count || 0) + " ") + result; + } + return result; + } + }, + camelize: function(string, firstLetterLower) { + string = string.replace(camelize_rx, function(str, p1) { + return p1.toUpperCase(); + }); + if (firstLetterLower) { + return string.substr(0, 1).toLowerCase() + string.substr(1); + } else { + return string; + } + }, + underscore: function(string) { + return string.replace(underscore_rx1, '$1_$2').replace(underscore_rx2, '$1_$2').replace('-', '_').toLowerCase(); + }, + capitalize: function(string) { + return string.replace(capitalize_rx, function(m, p1, p2) { + return p1 + p2.toUpperCase(); + }); + }, + trim: function(string) { + if (string) { + return string.trim(); + } else { + return ""; + } + }, + interpolate: function(stringOrObject, keys) { + var key, string, value; + if (typeof stringOrObject === 'object') { + string = stringOrObject[keys.count]; + if (!string) { + string = stringOrObject['other']; + } + } else { + string = stringOrObject; + } + for (key in keys) { + value = keys[key]; + string = string.replace(new RegExp("%\\{" + key + "\\}", "g"), value); + } + return string; + }, + humanize: function(string) { + string = Batman.helpers.underscore(string); + string = Batman.helpers.inflector.humanize(string); + return string.replace(humanize_rx1, '').replace(humanize_rx2, ' ').replace(humanize_rx3, function(match) { + return match.toUpperCase(); + }); + } + }; + + Inflector = new Batman.Inflector; + + Batman.helpers.inflector = Inflector; + + Inflector.plural(/$/, 's'); + + Inflector.plural(/s$/i, 's'); + + Inflector.plural(/(ax|test)is$/i, '$1es'); + + Inflector.plural(/(octop|vir)us$/i, '$1i'); + + Inflector.plural(/(octop|vir)i$/i, '$1i'); + + Inflector.plural(/(alias|status)$/i, '$1es'); + + Inflector.plural(/(bu)s$/i, '$1ses'); + + Inflector.plural(/(buffal|tomat)o$/i, '$1oes'); + + Inflector.plural(/([ti])um$/i, '$1a'); + + Inflector.plural(/([ti])a$/i, '$1a'); + + Inflector.plural(/sis$/i, 'ses'); + + Inflector.plural(/(?:([^f])fe|([lr])f)$/i, '$1$2ves'); + + Inflector.plural(/(hive)$/i, '$1s'); + + Inflector.plural(/([^aeiouy]|qu)y$/i, '$1ies'); + + Inflector.plural(/(x|ch|ss|sh)$/i, '$1es'); + + Inflector.plural(/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'); + + Inflector.plural(/([m|l])ouse$/i, '$1ice'); + + Inflector.plural(/([m|l])ice$/i, '$1ice'); + + Inflector.plural(/^(ox)$/i, '$1en'); + + Inflector.plural(/^(oxen)$/i, '$1'); + + Inflector.plural(/(quiz)$/i, '$1zes'); + + Inflector.singular(/s$/i, ''); + + Inflector.singular(/(n)ews$/i, '$1ews'); + + Inflector.singular(/([ti])a$/i, '$1um'); + + Inflector.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '$1$2sis'); + + Inflector.singular(/(^analy)ses$/i, '$1sis'); + + Inflector.singular(/([^f])ves$/i, '$1fe'); + + Inflector.singular(/(hive)s$/i, '$1'); + + Inflector.singular(/(tive)s$/i, '$1'); + + Inflector.singular(/([lr])ves$/i, '$1f'); + + Inflector.singular(/([^aeiouy]|qu)ies$/i, '$1y'); + + Inflector.singular(/(s)eries$/i, '$1eries'); + + Inflector.singular(/(m)ovies$/i, '$1ovie'); + + Inflector.singular(/(x|ch|ss|sh)es$/i, '$1'); + + Inflector.singular(/([m|l])ice$/i, '$1ouse'); + + Inflector.singular(/(bus)es$/i, '$1'); + + Inflector.singular(/(o)es$/i, '$1'); + + Inflector.singular(/(shoe)s$/i, '$1'); + + Inflector.singular(/(cris|ax|test)es$/i, '$1is'); + + Inflector.singular(/(octop|vir)i$/i, '$1us'); + + Inflector.singular(/(alias|status)es$/i, '$1'); + + Inflector.singular(/^(ox)en/i, '$1'); + + Inflector.singular(/(vert|ind)ices$/i, '$1ex'); + + Inflector.singular(/(matr)ices$/i, '$1ix'); + + Inflector.singular(/(quiz)zes$/i, '$1'); + + Inflector.singular(/(database)s$/i, '$1'); + + Inflector.irregular('person', 'people'); + + Inflector.irregular('man', 'men'); + + Inflector.irregular('child', 'children'); + + Inflector.irregular('sex', 'sexes'); + + Inflector.irregular('move', 'moves'); + + Inflector.irregular('cow', 'kine'); + + Inflector.irregular('zombie', 'zombies'); + + Inflector.uncountable('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep', 'jeans'); + +}).call(this); + +(function() { + var _implementImmediates, _objectToString, + __slice = [].slice, + __hasProp = {}.hasOwnProperty, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.typeOf = function(object) { + if (typeof object === 'undefined') { + return "Undefined"; + } + return _objectToString.call(object).slice(8, -1); + }; + + _objectToString = Object.prototype.toString; + + Batman.extend = function() { + var key, object, objects, to, value, _i, _len; + to = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + for (_i = 0, _len = objects.length; _i < _len; _i++) { + object = objects[_i]; + for (key in object) { + value = object[key]; + to[key] = value; + } + } + return to; + }; + + Batman.mixin = function() { + var hasSet, key, mixin, mixins, to, value, _i, _len; + to = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + hasSet = typeof to.set === 'function'; + for (_i = 0, _len = mixins.length; _i < _len; _i++) { + mixin = mixins[_i]; + if (Batman.typeOf(mixin) !== 'Object') { + continue; + } + for (key in mixin) { + if (!__hasProp.call(mixin, key)) continue; + value = mixin[key]; + if (key === 'initialize' || key === 'uninitialize' || key === 'prototype') { + continue; + } + if (hasSet) { + to.set(key, value); + } else if (to.nodeName != null) { + Batman.data(to, key, value); + } else { + to[key] = value; + } + } + if (typeof mixin.initialize === 'function') { + mixin.initialize.call(to); + } + } + return to; + }; + + Batman.unmixin = function() { + var from, key, mixin, mixins, _i, _len; + from = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + for (_i = 0, _len = mixins.length; _i < _len; _i++) { + mixin = mixins[_i]; + for (key in mixin) { + if (key === 'initialize' || key === 'uninitialize') { + continue; + } + delete from[key]; + } + if (typeof mixin.uninitialize === 'function') { + mixin.uninitialize.call(from); + } + } + return from; + }; + + Batman._functionName = Batman.functionName = function(f) { + var _ref; + if (f.__name__) { + return f.__name__; + } + if (f.name) { + return f.name; + } + return (_ref = f.toString().match(/\W*function\s+([\w\$]+)\(/)) != null ? _ref[1] : void 0; + }; + + Batman._isChildOf = Batman.isChildOf = function(parentNode, childNode) { + var node; + node = childNode.parentNode; + while (node) { + if (node === parentNode) { + return true; + } + node = node.parentNode; + } + return false; + }; + + Batman.setImmediate = Batman.clearImmediate = null; + + _implementImmediates = function(container) { + var canUsePostMessage, count, functions, getHandle, handler, prefix, tasks; + canUsePostMessage = function() { + var async, oldMessage; + if (!container.postMessage) { + return false; + } + async = true; + oldMessage = container.onmessage; + container.onmessage = function() { + return async = false; + }; + container.postMessage("", "*"); + container.onmessage = oldMessage; + return async; + }; + tasks = new Batman.SimpleHash; + count = 0; + getHandle = function() { + return "go" + (++count); + }; + if (container.setImmediate) { + Batman.setImmediate = container.setImmediate; + Batman.clearImmediate = container.clearImmediate; + } else if (container.msSetImmediate) { + Batman.setImmediate = msSetImmediate; + Batman.clearImmediate = msClearImmediate; + } else if (canUsePostMessage()) { + prefix = 'com.batman.'; + functions = new Batman.SimpleHash; + handler = function(e) { + var handle, _base; + if (!~e.data.search(prefix)) { + return; + } + handle = e.data.substring(prefix.length); + return typeof (_base = tasks.unset(handle)) === "function" ? _base() : void 0; + }; + if (container.addEventListener) { + container.addEventListener('message', handler, false); + } else { + container.attachEvent('onmessage', handler); + } + Batman.setImmediate = function(f) { + var handle; + tasks.set(handle = getHandle(), f); + container.postMessage(prefix + handle, "*"); + return handle; + }; + Batman.clearImmediate = function(handle) { + return tasks.unset(handle); + }; + } else if (typeof document !== 'undefined' && __indexOf.call(document.createElement("script"), "onreadystatechange") >= 0) { + Batman.setImmediate = function(f) { + var handle, script; + handle = getHandle(); + script = document.createElement("script"); + script.onreadystatechange = function() { + var _base; + if (typeof (_base = tasks.get(handle)) === "function") { + _base(); + } + script.onreadystatechange = null; + script.parentNode.removeChild(script); + return script = null; + }; + document.documentElement.appendChild(script); + return handle; + }; + Batman.clearImmediate = function(handle) { + return tasks.unset(handle); + }; + } else if (typeof process !== "undefined" && process !== null ? process.nextTick : void 0) { + functions = {}; + Batman.setImmediate = function(f) { + var handle; + handle = getHandle(); + functions[handle] = f; + process.nextTick(function() { + if (typeof functions[handle] === "function") { + functions[handle](); + } + return delete functions[handle]; + }); + return handle; + }; + Batman.clearImmediate = function(handle) { + return delete functions[handle]; + }; + } else { + Batman.setImmediate = function(f) { + return setTimeout(f, 0); + }; + Batman.clearImmediate = function(handle) { + return clearTimeout(handle); + }; + } + Batman.setImmediate = Batman.setImmediate; + return Batman.clearImmediate = Batman.clearImmediate; + }; + + Batman.setImmediate = function() { + _implementImmediates(Batman.container); + return Batman.setImmediate.apply(this, arguments); + }; + + Batman.clearImmediate = function() { + _implementImmediates(Batman.container); + return Batman.clearImmediate.apply(this, arguments); + }; + + Batman.forEach = function(container, iterator, ctx) { + var e, i, k, v, _i, _len, _results, _results1; + if (container.forEach) { + return container.forEach(iterator, ctx); + } else if (container.indexOf) { + _results = []; + for (i = _i = 0, _len = container.length; _i < _len; i = ++_i) { + e = container[i]; + _results.push(iterator.call(ctx, e, i, container)); + } + return _results; + } else { + _results1 = []; + for (k in container) { + v = container[k]; + _results1.push(iterator.call(ctx, k, v, container)); + } + return _results1; + } + }; + + Batman.objectHasKey = function(object, key) { + if (typeof object.hasKey === 'function') { + return object.hasKey(key); + } else { + return key in object; + } + }; + + Batman.contains = function(container, item) { + if (container.indexOf) { + return __indexOf.call(container, item) >= 0; + } else if (typeof container.has === 'function') { + return container.has(item); + } else { + return Batman.objectHasKey(container, item); + } + }; + + Batman.get = function(base, key) { + if (typeof base.get === 'function') { + return base.get(key); + } else { + return Batman.Property.forBaseAndKey(base, key).getValue(); + } + }; + + Batman.getPath = function(base, segments) { + var segment, _i, _len; + for (_i = 0, _len = segments.length; _i < _len; _i++) { + segment = segments[_i]; + if (base != null) { + base = Batman.get(base, segment); + if (base == null) { + return base; + } + } else { + return void 0; + } + } + return base; + }; + + Batman.escapeHTML = (function() { + var replacements; + replacements = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" + }; + return function(s) { + return ("" + s).replace(/[&<>'"]/g, function(c) { + return replacements[c]; + }); + }; + })(); + + Batman.translate = function(x, values) { + if (values == null) { + values = {}; + } + return Batman.helpers.interpolate(Batman.get(Batman.translate.messages, x), values); + }; + + Batman.translate.messages = {}; + + Batman.t = function() { + return Batman.translate.apply(Batman, arguments); + }; + + Batman.redirect = function(url) { + var _ref; + return (_ref = Batman.navigator) != null ? _ref.redirect(url) : void 0; + }; + + Batman.initializeObject = function(object) { + if (object._batman != null) { + return object._batman.check(object); + } else { + return object._batman = new Batman._Batman(object); + } + }; + +}).call(this); + +(function() { + var developer; + + Batman.developer = { + suppressed: false, + DevelopmentError: (function() { + var DevelopmentError; + DevelopmentError = function(message) { + this.message = message; + return this.name = "DevelopmentError"; + }; + DevelopmentError.prototype = Error.prototype; + return DevelopmentError; + })(), + _ie_console: function(f, args) { + var arg, _i, _len, _results; + if (args.length !== 1) { + if (typeof console !== "undefined" && console !== null) { + console[f]("..." + f + " of " + args.length + " items..."); + } + } + _results = []; + for (_i = 0, _len = args.length; _i < _len; _i++) { + arg = args[_i]; + _results.push(typeof console !== "undefined" && console !== null ? console[f](arg) : void 0); + } + return _results; + }, + suppress: function(f) { + developer.suppressed = true; + if (f) { + f(); + return developer.suppressed = false; + } + }, + unsuppress: function() { + return developer.suppressed = false; + }, + log: function() { + if (developer.suppressed || !((typeof console !== "undefined" && console !== null ? console.log : void 0) != null)) { + return; + } + if (console.log.apply) { + return console.log.apply(console, arguments); + } else { + return developer._ie_console("log", arguments); + } + }, + warn: function() { + if (developer.suppressed || !((typeof console !== "undefined" && console !== null ? console.warn : void 0) != null)) { + return; + } + if (console.warn.apply) { + return console.warn.apply(console, arguments); + } else { + return developer._ie_console("warn", arguments); + } + }, + error: function(message) { + throw new developer.DevelopmentError(message); + }, + assert: function(result, message) { + if (!result) { + return developer.error(message); + } + }, + "do": function(f) { + if (!developer.suppressed) { + return f(); + } + }, + addFilters: function() { + return Batman.extend(Batman.Filters, { + log: function(value, key) { + if (typeof console !== "undefined" && console !== null) { + if (typeof console.log === "function") { + console.log(arguments); + } + } + return value; + }, + logStack: function(value) { + if (typeof console !== "undefined" && console !== null) { + if (typeof console.log === "function") { + console.log(developer.currentFilterStack); + } + } + return value; + } + }); + } + }; + + developer = Batman.developer; + + Batman.developer.assert((function() {}).bind, "Error! Batman needs Function.bind to work! Please shim it using something like es5-shim or augmentjs!"); + +}).call(this); + +(function() { + var _Batman; + + Batman._Batman = _Batman = (function() { + + function _Batman(object) { + this.object = object; + } + + _Batman.prototype.check = function(object) { + if (object !== this.object) { + object._batman = new Batman._Batman(object); + return false; + } + return true; + }; + + _Batman.prototype.get = function(key) { + var reduction, results; + results = this.getAll(key); + switch (results.length) { + case 0: + return void 0; + case 1: + return results[0]; + default: + reduction = results[0].concat != null ? function(a, b) { + return a.concat(b); + } : results[0].merge != null ? function(a, b) { + return a.merge(b); + } : results.every(function(x) { + return typeof x === 'object'; + }) ? (results.unshift({}), function(a, b) { + return Batman.extend(a, b); + }) : void 0; + if (reduction) { + return results.reduceRight(reduction); + } else { + return results; + } + } + }; + + _Batman.prototype.getFirst = function(key) { + var results; + results = this.getAll(key); + return results[0]; + }; + + _Batman.prototype.getAll = function(keyOrGetter) { + var getter, results, val; + if (typeof keyOrGetter === 'function') { + getter = keyOrGetter; + } else { + getter = function(ancestor) { + var _ref; + return (_ref = ancestor._batman) != null ? _ref[keyOrGetter] : void 0; + }; + } + results = this.ancestors(getter); + if (val = getter(this.object)) { + results.unshift(val); + } + return results; + }; + + _Batman.prototype.ancestors = function(getter) { + var isClass, parent, proto, results, val, _ref, _ref1; + if (getter == null) { + getter = function(x) { + return x; + }; + } + results = []; + isClass = !!this.object.prototype; + parent = isClass ? (_ref = this.object.__super__) != null ? _ref.constructor : void 0 : (proto = Object.getPrototypeOf(this.object)) === this.object ? this.object.constructor.__super__ : proto; + if (parent != null) { + if ((_ref1 = parent._batman) != null) { + _ref1.check(parent); + } + val = getter(parent); + if (val != null) { + results.push(val); + } + if (parent._batman != null) { + results = results.concat(parent._batman.ancestors(getter)); + } + } + return results; + }; + + _Batman.prototype.set = function(key, value) { + return this[key] = value; + }; + + return _Batman; + + })(); + +}).call(this); + +(function() { + + Batman.Event = (function() { + + Event.forBaseAndKey = function(base, key) { + if (base.isEventEmitter) { + return base.event(key); + } else { + return new Batman.Event(base, key); + } + }; + + function Event(base, key) { + this.base = base; + this.key = key; + this.handlers = []; + this._preventCount = 0; + } + + Event.prototype.isEvent = true; + + Event.prototype.isEqual = function(other) { + return this.constructor === other.constructor && this.base === other.base && this.key === other.key; + }; + + Event.prototype.hashKey = function() { + var key; + this.hashKey = function() { + return key; + }; + return key = ""; + }; + + Event.prototype.addHandler = function(handler) { + if (this.handlers.indexOf(handler) === -1) { + this.handlers.push(handler); + } + if (this.oneShot) { + this.autofireHandler(handler); + } + return this; + }; + + Event.prototype.removeHandler = function(handler) { + var index; + if ((index = this.handlers.indexOf(handler)) !== -1) { + this.handlers.splice(index, 1); + } + return this; + }; + + Event.prototype.eachHandler = function(iterator) { + var key, _ref, _ref1; + this.handlers.slice().forEach(iterator); + if ((_ref = this.base) != null ? _ref.isEventEmitter : void 0) { + key = this.key; + return (_ref1 = this.base._batman) != null ? _ref1.ancestors(function(ancestor) { + var handlers, _ref2, _ref3; + if (ancestor.isEventEmitter && ((_ref2 = ancestor._batman) != null ? (_ref3 = _ref2.events) != null ? _ref3.hasOwnProperty(key) : void 0 : void 0)) { + handlers = ancestor.event(key).handlers; + return handlers.slice().forEach(iterator); + } + }) : void 0; + } + }; + + Event.prototype.clearHandlers = function() { + return this.handlers = []; + }; + + Event.prototype.handlerContext = function() { + return this.base; + }; + + Event.prototype.prevent = function() { + return ++this._preventCount; + }; + + Event.prototype.allow = function() { + if (this._preventCount) { + --this._preventCount; + } + return this._preventCount; + }; + + Event.prototype.isPrevented = function() { + return this._preventCount > 0; + }; + + Event.prototype.autofireHandler = function(handler) { + if (this._oneShotFired && (this._oneShotArgs != null)) { + return handler.apply(this.handlerContext(), this._oneShotArgs); + } + }; + + Event.prototype.resetOneShot = function() { + this._oneShotFired = false; + return this._oneShotArgs = null; + }; + + Event.prototype.fire = function() { + var args, context; + if (this.isPrevented() || this._oneShotFired) { + return false; + } + context = this.handlerContext(); + args = arguments; + if (this.oneShot) { + this._oneShotFired = true; + this._oneShotArgs = arguments; + } + return this.eachHandler(function(handler) { + return handler.apply(context, args); + }); + }; + + Event.prototype.allowAndFire = function() { + this.allow(); + return this.fire.apply(this, arguments); + }; + + return Event; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PropertyEvent = (function(_super) { + + __extends(PropertyEvent, _super); + + function PropertyEvent() { + return PropertyEvent.__super__.constructor.apply(this, arguments); + } + + PropertyEvent.prototype.eachHandler = function(iterator) { + return this.base.eachObserver(iterator); + }; + + PropertyEvent.prototype.handlerContext = function() { + return this.base.base; + }; + + return PropertyEvent; + + })(Batman.Event); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.EventEmitter = { + isEventEmitter: true, + hasEvent: function(key) { + var _ref, _ref1; + return (_ref = this._batman) != null ? typeof _ref.get === "function" ? (_ref1 = _ref.get('events')) != null ? _ref1.hasOwnProperty(key) : void 0 : void 0 : void 0; + }, + event: function(key) { + var eventClass, events, existingEvent, newEvent, _base; + Batman.initializeObject(this); + eventClass = this.eventClass || Batman.Event; + events = (_base = this._batman).events || (_base.events = {}); + if (events.hasOwnProperty(key)) { + return existingEvent = events[key]; + } else { + this._batman.ancestors(function(ancestor) { + var _ref, _ref1; + return existingEvent || (existingEvent = (_ref = ancestor._batman) != null ? (_ref1 = _ref.events) != null ? _ref1[key] : void 0 : void 0); + }); + newEvent = events[key] = new eventClass(this, key); + newEvent.oneShot = existingEvent != null ? existingEvent.oneShot : void 0; + return newEvent; + } + }, + on: function(key, handler) { + return this.event(key).addHandler(handler); + }, + once: function(key, originalHandler) { + var event, handler; + event = this.event(key); + handler = function() { + originalHandler.apply(this, arguments); + return event.removeHandler(handler); + }; + return event.addHandler(handler); + }, + registerAsMutableSource: function() { + return Batman.Property.registerSource(this); + }, + mutation: function(wrappedFunction) { + return function() { + var result; + result = wrappedFunction.apply(this, arguments); + this.event('change').fire(this, this); + return result; + }; + }, + prevent: function(key) { + this.event(key).prevent(); + return this; + }, + allow: function(key) { + this.event(key).allow(); + return this; + }, + isPrevented: function(key) { + return this.event(key).isPrevented(); + }, + fire: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + return (_ref = this.event(key)).fire.apply(_ref, args); + }, + allowAndFire: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + return (_ref = this.event(key)).allowAndFire.apply(_ref, args); + } + }; + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.Enumerable = { + isEnumerable: true, + map: function(f, ctx) { + var r; + if (ctx == null) { + ctx = Batman.container; + } + r = []; + this.forEach(function() { + return r.push(f.apply(ctx, arguments)); + }); + return r; + }, + mapToProperty: function(key) { + var r; + r = []; + this.forEach(function(item) { + return r.push(item.get(key)); + }); + return r; + }, + every: function(f, ctx) { + var r; + if (ctx == null) { + ctx = Batman.container; + } + r = true; + this.forEach(function() { + return r = r && f.apply(ctx, arguments); + }); + return r; + }, + some: function(f, ctx) { + var r; + if (ctx == null) { + ctx = Batman.container; + } + r = false; + this.forEach(function() { + return r = r || f.apply(ctx, arguments); + }); + return r; + }, + reduce: function(f, r) { + var count, self; + count = 0; + self = this; + this.forEach(function() { + if (r != null) { + return r = f.apply(null, [r].concat(__slice.call(arguments), [count], [self])); + } else { + return r = arguments[0]; + } + }); + return r; + }, + filter: function(f) { + var r, wrap; + r = new this.constructor; + if (r.add) { + wrap = function(r, e) { + if (f(e)) { + r.add(e); + } + return r; + }; + } else if (r.set) { + wrap = function(r, k, v) { + if (f(k, v)) { + r.set(k, v); + } + return r; + }; + } else { + if (!r.push) { + r = []; + } + wrap = function(r, e) { + if (f(e)) { + r.push(e); + } + return r; + }; + } + return this.reduce(wrap, r); + }, + inGroupsOf: function(n) { + var current, i, r; + r = []; + current = false; + i = 0; + this.forEach(function(x) { + if (i++ % n === 0) { + current = []; + r.push(current); + } + return current.push(x); + }); + return r; + } + }; + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.SimpleHash = (function() { + + function SimpleHash(obj) { + this._storage = {}; + this.length = 0; + if (obj != null) { + this.update(obj); + } + } + + Batman.extend(SimpleHash.prototype, Batman.Enumerable); + + SimpleHash.prototype.propertyClass = Batman.Property; + + SimpleHash.prototype.hasKey = function(key) { + var pair, pairs, _i, _len; + if (this.objectKey(key)) { + if (!this._objectStorage) { + return false; + } + if (pairs = this._objectStorage[this.hashKeyFor(key)]) { + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + if (this.equality(pair[0], key)) { + return true; + } + } + } + return false; + } else { + key = this.prefixedKey(key); + return this._storage.hasOwnProperty(key); + } + }; + + SimpleHash.prototype.get = function(key) { + var pair, pairs, _i, _len; + if (this.objectKey(key)) { + if (!this._objectStorage) { + return void 0; + } + if (pairs = this._objectStorage[this.hashKeyFor(key)]) { + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + if (this.equality(pair[0], key)) { + return pair[1]; + } + } + } + } else { + return this._storage[this.prefixedKey(key)]; + } + }; + + SimpleHash.prototype.set = function(key, val) { + var pair, pairs, _base, _i, _len, _name; + if (this.objectKey(key)) { + this._objectStorage || (this._objectStorage = {}); + pairs = (_base = this._objectStorage)[_name = this.hashKeyFor(key)] || (_base[_name] = []); + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + if (this.equality(pair[0], key)) { + return pair[1] = val; + } + } + this.length++; + pairs.push([key, val]); + return val; + } else { + key = this.prefixedKey(key); + if (this._storage[key] == null) { + this.length++; + } + return this._storage[key] = val; + } + }; + + SimpleHash.prototype.unset = function(key) { + var hashKey, index, obj, pair, pairs, val, value, _i, _len, _ref; + if (this.objectKey(key)) { + if (!this._objectStorage) { + return void 0; + } + hashKey = this.hashKeyFor(key); + if (pairs = this._objectStorage[hashKey]) { + for (index = _i = 0, _len = pairs.length; _i < _len; index = ++_i) { + _ref = pairs[index], obj = _ref[0], value = _ref[1]; + if (this.equality(obj, key)) { + pair = pairs.splice(index, 1); + if (!pairs.length) { + delete this._objectStorage[hashKey]; + } + this.length--; + return pair[0][1]; + } + } + } + } else { + key = this.prefixedKey(key); + val = this._storage[key]; + if (this._storage[key] != null) { + this.length--; + delete this._storage[key]; + } + return val; + } + }; + + SimpleHash.prototype.getOrSet = function(key, valueFunction) { + var currentValue; + currentValue = this.get(key); + if (!currentValue) { + currentValue = valueFunction(); + this.set(key, currentValue); + } + return currentValue; + }; + + SimpleHash.prototype.prefixedKey = function(key) { + return "_" + key; + }; + + SimpleHash.prototype.unprefixedKey = function(key) { + return key.slice(1); + }; + + SimpleHash.prototype.hashKeyFor = function(obj) { + return (obj != null ? typeof obj.hashKey === "function" ? obj.hashKey() : void 0 : void 0) || obj; + }; + + SimpleHash.prototype.equality = function(lhs, rhs) { + if (lhs === rhs) { + return true; + } + if (lhs !== lhs && rhs !== rhs) { + return true; + } + if ((lhs != null ? typeof lhs.isEqual === "function" ? lhs.isEqual(rhs) : void 0 : void 0) && (rhs != null ? typeof rhs.isEqual === "function" ? rhs.isEqual(lhs) : void 0 : void 0)) { + return true; + } + return false; + }; + + SimpleHash.prototype.objectKey = function(key) { + return typeof key !== 'string'; + }; + + SimpleHash.prototype.forEach = function(iterator, ctx) { + var key, obj, results, value, values, _i, _len, _ref, _ref1, _ref2, _ref3; + results = []; + if (this._objectStorage) { + _ref = this._objectStorage; + for (key in _ref) { + values = _ref[key]; + _ref1 = values.slice(); + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + _ref2 = _ref1[_i], obj = _ref2[0], value = _ref2[1]; + results.push(iterator.call(ctx, obj, value, this)); + } + } + } + _ref3 = this._storage; + for (key in _ref3) { + value = _ref3[key]; + results.push(iterator.call(ctx, this.unprefixedKey(key), value, this)); + } + return results; + }; + + SimpleHash.prototype.keys = function() { + var result; + result = []; + Batman.SimpleHash.prototype.forEach.call(this, function(key) { + return result.push(key); + }); + return result; + }; + + SimpleHash.prototype.toArray = SimpleHash.prototype.keys; + + SimpleHash.prototype.clear = function() { + this._storage = {}; + delete this._objectStorage; + return this.length = 0; + }; + + SimpleHash.prototype.isEmpty = function() { + return this.length === 0; + }; + + SimpleHash.prototype.merge = function() { + var hash, merged, others, _i, _len; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + merged = new this.constructor; + others.unshift(this); + for (_i = 0, _len = others.length; _i < _len; _i++) { + hash = others[_i]; + hash.forEach(function(obj, value) { + return merged.set(obj, value); + }); + } + return merged; + }; + + SimpleHash.prototype.update = function(object) { + var k, v, _results; + _results = []; + for (k in object) { + v = object[k]; + _results.push(this.set(k, v)); + } + return _results; + }; + + SimpleHash.prototype.replace = function(object) { + var _this = this; + this.forEach(function(key, value) { + if (!(key in object)) { + return _this.unset(key); + } + }); + return this.update(object); + }; + + SimpleHash.prototype.toObject = function() { + var key, obj, pair, value, _ref, _ref1; + obj = {}; + _ref = this._storage; + for (key in _ref) { + value = _ref[key]; + obj[this.unprefixedKey(key)] = value; + } + if (this._objectStorage) { + _ref1 = this._objectStorage; + for (key in _ref1) { + pair = _ref1[key]; + obj[key] = pair[0][1]; + } + } + return obj; + }; + + SimpleHash.prototype.toJSON = SimpleHash.prototype.toObject; + + return SimpleHash; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.AssociationCurator = (function(_super) { + + __extends(AssociationCurator, _super); + + AssociationCurator.availableAssociations = ['belongsTo', 'hasOne', 'hasMany']; + + function AssociationCurator(model) { + this.model = model; + AssociationCurator.__super__.constructor.call(this); + this._byTypeStorage = new Batman.SimpleHash; + } + + AssociationCurator.prototype.add = function(association) { + var associationTypeSet; + this.set(association.label, association); + if (!(associationTypeSet = this._byTypeStorage.get(association.associationType))) { + associationTypeSet = new Batman.SimpleSet; + this._byTypeStorage.set(association.associationType, associationTypeSet); + } + return associationTypeSet.add(association); + }; + + AssociationCurator.prototype.getByType = function(type) { + return this._byTypeStorage.get(type); + }; + + AssociationCurator.prototype.getByLabel = function(label) { + return this.get(label); + }; + + AssociationCurator.prototype.reset = function() { + this.forEach(function(label, association) { + return association.reset(); + }); + return true; + }; + + AssociationCurator.prototype.merge = function() { + var others, result; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + result = AssociationCurator.__super__.merge.apply(this, arguments); + result._byTypeStorage = this._byTypeStorage.merge(others.map(function(other) { + return other._byTypeStorage; + })); + return result; + }; + + AssociationCurator.prototype._markDirtyAttribute = function(key, oldValue) { + var _ref; + if ((_ref = this.lifecycle.get('state')) !== 'loading' && _ref !== 'creating' && _ref !== 'saving' && _ref !== 'saved') { + if (this.lifecycle.startTransition('set')) { + return this.dirtyKeys.set(key, oldValue); + } else { + throw new Batman.StateMachine.InvalidTransitionError("Can't set while in state " + (this.lifecycle.get('state'))); + } + } + }; + + return AssociationCurator; + + })(Batman.SimpleHash); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.SimpleSet = (function() { + + function SimpleSet() { + this._storage = []; + this.length = 0; + if (arguments.length > 0) { + this.add.apply(this, arguments); + } + } + + Batman.extend(SimpleSet.prototype, Batman.Enumerable); + + SimpleSet.prototype.has = function(item) { + return !!(~this._indexOfItem(item)); + }; + + SimpleSet.prototype.add = function() { + var addedItems, item, items, _i, _len; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + addedItems = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!(!~this._indexOfItem(item))) { + continue; + } + this._storage.push(item); + addedItems.push(item); + } + this.length = this._storage.length; + if (this.fire && addedItems.length !== 0) { + this.fire('change', this, this); + this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedItems))); + } + return addedItems; + }; + + SimpleSet.prototype.remove = function() { + var index, item, items, removedItems, _i, _len; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + removedItems = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!(~(index = this._indexOfItem(item)))) { + continue; + } + this._storage.splice(index, 1); + removedItems.push(item); + } + this.length = this._storage.length; + if (this.fire && removedItems.length !== 0) { + this.fire('change', this, this); + this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(removedItems))); + } + return removedItems; + }; + + SimpleSet.prototype.find = function(f) { + var item, _i, _len, _ref; + _ref = this._storage; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + item = _ref[_i]; + if (f(item)) { + return item; + } + } + }; + + SimpleSet.prototype.forEach = function(iterator, ctx) { + var container; + container = this; + return this._storage.slice().forEach(function(key) { + return iterator.call(ctx, key, null, container); + }); + }; + + SimpleSet.prototype.isEmpty = function() { + return this.length === 0; + }; + + SimpleSet.prototype.clear = function() { + var items; + items = this._storage; + this._storage = []; + this.length = 0; + if (this.fire && items.length !== 0) { + this.fire('change', this, this); + this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(items))); + } + return items; + }; + + SimpleSet.prototype.replace = function(other) { + try { + if (typeof this.prevent === "function") { + this.prevent('change'); + } + this.clear(); + return this.add.apply(this, other.toArray()); + } finally { + if (typeof this.allowAndFire === "function") { + this.allowAndFire('change', this, this); + } + } + }; + + SimpleSet.prototype.toArray = function() { + return this._storage.slice(); + }; + + SimpleSet.prototype.merge = function() { + var merged, others, set, _i, _len; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + merged = new this.constructor; + others.unshift(this); + for (_i = 0, _len = others.length; _i < _len; _i++) { + set = others[_i]; + set.forEach(function(v) { + return merged.add(v); + }); + } + return merged; + }; + + SimpleSet.prototype.indexedBy = function(key) { + this._indexes || (this._indexes = new Batman.SimpleHash); + return this._indexes.get(key) || this._indexes.set(key, new Batman.SetIndex(this, key)); + }; + + SimpleSet.prototype.indexedByUnique = function(key) { + this._uniqueIndexes || (this._uniqueIndexes = new Batman.SimpleHash); + return this._uniqueIndexes.get(key) || this._uniqueIndexes.set(key, new Batman.UniqueSetIndex(this, key)); + }; + + SimpleSet.prototype.sortedBy = function(key, order) { + var sortsForKey; + if (order == null) { + order = "asc"; + } + order = order.toLowerCase() === "desc" ? "desc" : "asc"; + this._sorts || (this._sorts = new Batman.SimpleHash); + sortsForKey = this._sorts.get(key) || this._sorts.set(key, new Batman.Object); + return sortsForKey.get(order) || sortsForKey.set(order, new Batman.SetSort(this, key, order)); + }; + + SimpleSet.prototype.equality = Batman.SimpleHash.prototype.equality; + + SimpleSet.prototype._indexOfItem = function(givenItem) { + var index, item, _i, _len, _ref; + _ref = this._storage; + for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { + item = _ref[index]; + if (this.equality(givenItem, item)) { + return index; + } + } + return -1; + }; + + return SimpleSet; + + })(); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.Property = (function() { + + Batman.mixin(Property.prototype, Batman.EventEmitter); + + Property._sourceTrackerStack = []; + + Property.sourceTracker = function() { + var stack; + return (stack = this._sourceTrackerStack)[stack.length - 1]; + }; + + Property.defaultAccessor = { + get: function(key) { + return this[key]; + }, + set: function(key, val) { + return this[key] = val; + }, + unset: function(key) { + var x; + x = this[key]; + delete this[key]; + return x; + }, + cache: false + }; + + Property.defaultAccessorForBase = function(base) { + var _ref; + return ((_ref = base._batman) != null ? _ref.getFirst('defaultAccessor') : void 0) || Batman.Property.defaultAccessor; + }; + + Property.accessorForBaseAndKey = function(base, key) { + var accessor, _bm, _ref, + _this = this; + if ((_bm = base._batman) != null) { + accessor = (_ref = _bm.keyAccessors) != null ? _ref.get(key) : void 0; + if (!accessor) { + _bm.ancestors(function(ancestor) { + var _ref1, _ref2; + return accessor || (accessor = (_ref1 = ancestor._batman) != null ? (_ref2 = _ref1.keyAccessors) != null ? _ref2.get(key) : void 0 : void 0); + }); + } + } + return accessor || this.defaultAccessorForBase(base); + }; + + Property.forBaseAndKey = function(base, key) { + if (base.isObservable) { + return base.property(key); + } else { + return new Batman.Keypath(base, key); + } + }; + + Property.withoutTracking = function(block) { + return this.wrapTrackingPrevention(block)(); + }; + + Property.wrapTrackingPrevention = function(block) { + return function() { + Batman.Property.pushDummySourceTracker(); + try { + return block.apply(this, arguments); + } finally { + Batman.Property.popSourceTracker(); + } + }; + }; + + Property.registerSource = function(obj) { + var _ref; + if (!obj.isEventEmitter) { + return; + } + return (_ref = this.sourceTracker()) != null ? _ref.add(obj) : void 0; + }; + + Property.pushSourceTracker = function() { + return Batman.Property._sourceTrackerStack.push(new Batman.SimpleSet); + }; + + Property.pushDummySourceTracker = function() { + return Batman.Property._sourceTrackerStack.push(null); + }; + + Property.popSourceTracker = function() { + return Batman.Property._sourceTrackerStack.pop(); + }; + + function Property(base, key) { + this.base = base; + this.key = key; + } + + Property.prototype._isolationCount = 0; + + Property.prototype.cached = false; + + Property.prototype.value = null; + + Property.prototype.sources = null; + + Property.prototype.isProperty = true; + + Property.prototype.isDead = false; + + Property.prototype.eventClass = Batman.PropertyEvent; + + Property.prototype.isEqual = function(other) { + return this.constructor === other.constructor && this.base === other.base && this.key === other.key; + }; + + Property.prototype.hashKey = function() { + var key; + this.hashKey = function() { + return key; + }; + return key = ""; + }; + + Property.prototype.event = function(key) { + var eventClass, _base; + eventClass = this.eventClass || Batman.Event; + this.events || (this.events = {}); + (_base = this.events)[key] || (_base[key] = new eventClass(this, key)); + return this.events[key]; + }; + + Property.prototype.changeEvent = function() { + var event; + event = this.event('change'); + this.changeEvent = function() { + return event; + }; + return event; + }; + + Property.prototype.accessor = function() { + var accessor; + accessor = this.constructor.accessorForBaseAndKey(this.base, this.key); + this.accessor = function() { + return accessor; + }; + return accessor; + }; + + Property.prototype.eachObserver = function(iterator) { + var key; + key = this.key; + this.changeEvent().handlers.slice().forEach(iterator); + if (this.base.isObservable) { + return this.base._batman.ancestors(function(ancestor) { + var handlers, property; + if (ancestor.isObservable && ancestor.hasProperty(key)) { + property = ancestor.property(key); + handlers = property.changeEvent().handlers; + return handlers.slice().forEach(iterator); + } + }); + } + }; + + Property.prototype.observers = function() { + var results; + results = []; + this.eachObserver(function(observer) { + return results.push(observer); + }); + return results; + }; + + Property.prototype.hasObservers = function() { + return this.observers().length > 0; + }; + + Property.prototype.updateSourcesFromTracker = function() { + var handler, newSources; + newSources = this.constructor.popSourceTracker(); + handler = this.sourceChangeHandler(); + this._eachSourceChangeEvent(function(e) { + return e.removeHandler(handler); + }); + this.sources = newSources; + return this._eachSourceChangeEvent(function(e) { + return e.addHandler(handler); + }); + }; + + Property.prototype._eachSourceChangeEvent = function(iterator) { + if (this.sources == null) { + return; + } + return this.sources.forEach(function(source) { + return iterator(source.event('change')); + }); + }; + + Property.prototype.getValue = function() { + this.registerAsMutableSource(); + if (!this.isCached()) { + this.constructor.pushSourceTracker(); + try { + this.value = this.valueFromAccessor(); + this.cached = true; + } finally { + this.updateSourcesFromTracker(); + } + } + return this.value; + }; + + Property.prototype.isCachable = function() { + var cacheable; + if (this.isFinal()) { + return true; + } + cacheable = this.accessor().cache; + if (cacheable != null) { + return !!cacheable; + } else { + return true; + } + }; + + Property.prototype.isCached = function() { + return this.isCachable() && this.cached; + }; + + Property.prototype.isFinal = function() { + return !!this.accessor()['final']; + }; + + Property.prototype.refresh = function() { + var previousValue, value; + this.cached = false; + previousValue = this.value; + value = this.getValue(); + if (value !== previousValue && !this.isIsolated()) { + this.fire(value, previousValue); + } + if (this.value !== void 0 && this.isFinal()) { + return this.lockValue(); + } + }; + + Property.prototype.sourceChangeHandler = function() { + var handler, + _this = this; + handler = this._handleSourceChange.bind(this); + Batman.developer["do"](function() { + return handler.property = _this; + }); + this.sourceChangeHandler = function() { + return handler; + }; + return handler; + }; + + Property.prototype._handleSourceChange = function() { + if (this.isIsolated()) { + return this._needsRefresh = true; + } else if (!this.isFinal() && !this.hasObservers()) { + return this.cached = false; + } else { + return this.refresh(); + } + }; + + Property.prototype.valueFromAccessor = function() { + var _ref; + return (_ref = this.accessor().get) != null ? _ref.call(this.base, this.key) : void 0; + }; + + Property.prototype.setValue = function(val) { + var set; + if (!(set = this.accessor().set)) { + return; + } + return this._changeValue(function() { + return set.call(this.base, this.key, val); + }); + }; + + Property.prototype.unsetValue = function() { + var unset; + if (!(unset = this.accessor().unset)) { + return; + } + return this._changeValue(function() { + return unset.call(this.base, this.key); + }); + }; + + Property.prototype._changeValue = function(block) { + var result; + this.cached = false; + this.constructor.pushDummySourceTracker(); + try { + result = block.apply(this); + this.refresh(); + } finally { + this.constructor.popSourceTracker(); + } + if (!(this.isCached() || this.hasObservers())) { + this.die(); + } + return result; + }; + + Property.prototype.forget = function(handler) { + if (handler != null) { + return this.changeEvent().removeHandler(handler); + } else { + return this.changeEvent().clearHandlers(); + } + }; + + Property.prototype.observeAndFire = function(handler) { + this.observe(handler); + return handler.call(this.base, this.value, this.value, this.key); + }; + + Property.prototype.observe = function(handler) { + this.changeEvent().addHandler(handler); + if (this.sources == null) { + this.getValue(); + } + return this; + }; + + Property.prototype.observeOnce = function(originalHandler) { + var event, handler; + event = this.changeEvent(); + handler = function() { + originalHandler.apply(this, arguments); + return event.removeHandler(handler); + }; + event.addHandler(handler); + if (this.sources == null) { + this.getValue(); + } + return this; + }; + + Property.prototype._removeHandlers = function() { + var handler; + handler = this.sourceChangeHandler(); + this._eachSourceChangeEvent(function(e) { + return e.removeHandler(handler); + }); + delete this.sources; + return this.changeEvent().clearHandlers(); + }; + + Property.prototype.lockValue = function() { + this._removeHandlers(); + this.getValue = function() { + return this.value; + }; + return this.setValue = this.unsetValue = this.refresh = this.observe = function() {}; + }; + + Property.prototype.die = function() { + var _ref, _ref1; + this._removeHandlers(); + if ((_ref = this.base._batman) != null) { + if ((_ref1 = _ref.properties) != null) { + _ref1.unset(this.key); + } + } + return this.isDead = true; + }; + + Property.prototype.fire = function() { + var _ref; + return (_ref = this.changeEvent()).fire.apply(_ref, __slice.call(arguments).concat([this.key])); + }; + + Property.prototype.isolate = function() { + if (this._isolationCount === 0) { + this._preIsolationValue = this.getValue(); + } + return this._isolationCount++; + }; + + Property.prototype.expose = function() { + if (this._isolationCount === 1) { + this._isolationCount--; + if (this._needsRefresh) { + this.value = this._preIsolationValue; + this.refresh(); + } else if (this.value !== this._preIsolationValue) { + this.fire(this.value, this._preIsolationValue); + } + return this._preIsolationValue = null; + } else if (this._isolationCount > 0) { + return this._isolationCount--; + } + }; + + Property.prototype.isIsolated = function() { + return this._isolationCount > 0; + }; + + return Property; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Keypath = (function(_super) { + + __extends(Keypath, _super); + + function Keypath(base, key) { + if (typeof key === 'string') { + this.segments = key.split('.'); + this.depth = this.segments.length; + } else { + this.segments = [key]; + this.depth = 1; + } + Keypath.__super__.constructor.apply(this, arguments); + } + + Keypath.prototype.isCachable = function() { + if (this.depth === 1) { + return Keypath.__super__.isCachable.apply(this, arguments); + } else { + return true; + } + }; + + Keypath.prototype.terminalProperty = function() { + var base; + base = Batman.getPath(this.base, this.segments.slice(0, -1)); + if (base == null) { + return; + } + return Batman.Keypath.forBaseAndKey(base, this.segments[this.depth - 1]); + }; + + Keypath.prototype.valueFromAccessor = function() { + if (this.depth === 1) { + return Keypath.__super__.valueFromAccessor.apply(this, arguments); + } else { + return Batman.getPath(this.base, this.segments); + } + }; + + Keypath.prototype.setValue = function(val) { + var _ref; + if (this.depth === 1) { + return Keypath.__super__.setValue.apply(this, arguments); + } else { + return (_ref = this.terminalProperty()) != null ? _ref.setValue(val) : void 0; + } + }; + + Keypath.prototype.unsetValue = function() { + var _ref; + if (this.depth === 1) { + return Keypath.__super__.unsetValue.apply(this, arguments); + } else { + return (_ref = this.terminalProperty()) != null ? _ref.unsetValue() : void 0; + } + }; + + return Keypath; + + })(Batman.Property); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.Observable = { + isObservable: true, + hasProperty: function(key) { + var _ref, _ref1; + return (_ref = this._batman) != null ? (_ref1 = _ref.properties) != null ? typeof _ref1.hasKey === "function" ? _ref1.hasKey(key) : void 0 : void 0 : void 0; + }, + property: function(key) { + var properties, propertyClass, _base; + Batman.initializeObject(this); + propertyClass = this.propertyClass || Batman.Keypath; + properties = (_base = this._batman).properties || (_base.properties = new Batman.SimpleHash); + return properties.get(key) || properties.set(key, new propertyClass(this, key)); + }, + get: function(key) { + return this.property(key).getValue(); + }, + set: function(key, val) { + return this.property(key).setValue(val); + }, + unset: function(key) { + return this.property(key).unsetValue(); + }, + getOrSet: Batman.SimpleHash.prototype.getOrSet, + forget: function(key, observer) { + var _ref; + if (key) { + this.property(key).forget(observer); + } else { + if ((_ref = this._batman.properties) != null) { + _ref.forEach(function(key, property) { + return property.forget(); + }); + } + } + return this; + }, + observe: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + (_ref = this.property(key)).observe.apply(_ref, args); + return this; + }, + observeAndFire: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + (_ref = this.property(key)).observeAndFire.apply(_ref, args); + return this; + }, + observeOnce: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + (_ref = this.property(key)).observeOnce.apply(_ref, args); + return this; + } + }; + +}).call(this); + +(function() { + + Batman.DOM = { + textInputTypes: ['text', 'search', 'tel', 'url', 'email', 'password'], + scrollIntoView: function(elementID) { + var _ref; + return (_ref = document.getElementById(elementID)) != null ? typeof _ref.scrollIntoView === "function" ? _ref.scrollIntoView() : void 0 : void 0; + }, + querySelectorAll: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) { + return jQuery(selector, node); + } : (typeof document !== "undefined" && document !== null ? document.querySelectorAll : void 0) != null ? function(node, selector) { + return node.querySelectorAll(selector); + } : function() { + return Batman.developer.error("Please include either jQuery or a querySelectorAll polyfill, or set Batman.DOM.querySelectorAll to return an empty array."); + }, + querySelector: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) { + return jQuery(selector, node)[0]; + } : (typeof document !== "undefined" && document !== null ? document.querySelector : void 0) != null ? function(node, selector) { + return node.querySelector(selector); + } : function() { + return Batman.developer.error("Please include either jQuery or a querySelector polyfill, or set Batman.DOM.querySelector to an empty function."); + }, + partial: function(container, path, context, renderer) { + var view; + renderer.prevent('rendered'); + view = new Batman.View({ + source: path, + context: context + }); + return view.on('ready', function() { + Batman.setInnerHTML(container, ''); + Batman.appendChild(container, view.get('node')); + return renderer.allowAndFire('rendered'); + }); + }, + propagateBindingEvent: Batman.propagateBindingEvent = function(binding, node) { + var current, parentBinding, parentBindings, _i, _len; + while ((current = (current || node).parentNode)) { + parentBindings = Batman._data(current, 'bindings'); + if (parentBindings != null) { + for (_i = 0, _len = parentBindings.length; _i < _len; _i++) { + parentBinding = parentBindings[_i]; + if (typeof parentBinding.childBindingAdded === "function") { + parentBinding.childBindingAdded(binding); + } + } + } + } + }, + propagateBindingEvents: Batman.propagateBindingEvents = function(newNode) { + var binding, bindings, child, _i, _j, _len, _len1, _ref; + _ref = newNode.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.propagateBindingEvents(child); + } + if (bindings = Batman._data(newNode, 'bindings')) { + for (_j = 0, _len1 = bindings.length; _j < _len1; _j++) { + binding = bindings[_j]; + Batman.propagateBindingEvent(binding, newNode); + } + } + }, + trackBinding: Batman.trackBinding = function(binding, node) { + var bindings; + if (bindings = Batman._data(node, 'bindings')) { + bindings.push(binding); + } else { + Batman._data(node, 'bindings', [binding]); + } + Batman.DOM.fire('bindingAdded', binding); + Batman.propagateBindingEvent(binding, node); + return true; + }, + onParseExit: Batman.onParseExit = function(node, callback) { + var set; + set = Batman._data(node, 'onParseExit') || Batman._data(node, 'onParseExit', new Batman.SimpleSet); + if (callback != null) { + set.add(callback); + } + return set; + }, + forgetParseExit: Batman.forgetParseExit = function(node, callback) { + return Batman.removeData(node, 'onParseExit', true); + }, + defineView: function(name, node) { + var contents; + contents = node.innerHTML; + Batman.View.store.set(Batman.Navigator.normalizePath(name), contents); + return contents; + }, + setInnerHTML: Batman.setInnerHTML = function(node, html) { + var child, childNodes, result, _i, _j, _len, _len1; + childNodes = (function() { + var _i, _len, _ref, _results; + _ref = node.childNodes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(child); + } + return _results; + })(); + for (_i = 0, _len = childNodes.length; _i < _len; _i++) { + child = childNodes[_i]; + Batman.DOM.willRemoveNode(child); + } + result = node.innerHTML = html; + for (_j = 0, _len1 = childNodes.length; _j < _len1; _j++) { + child = childNodes[_j]; + Batman.DOM.didRemoveNode(child); + } + return result; + }, + setStyleProperty: Batman.setStyleProperty = function(node, property, value, importance) { + if (node.style.setAttribute) { + return node.style.setAttribute(property, value, importance); + } else { + return node.style.setProperty(property, value, importance); + } + }, + removeNode: Batman.removeNode = function(node) { + var _ref; + Batman.DOM.willRemoveNode(node); + if ((_ref = node.parentNode) != null) { + _ref.removeChild(node); + } + return Batman.DOM.didRemoveNode(node); + }, + destroyNode: Batman.destroyNode = function(node) { + Batman.DOM.willDestroyNode(node); + Batman.removeNode(node); + return Batman.DOM.didDestroyNode(node); + }, + appendChild: Batman.appendChild = function(parent, child) { + Batman.DOM.willInsertNode(child); + parent.appendChild(child); + return Batman.DOM.didInsertNode(child); + }, + removeOrDestroyNode: Batman.removeOrDestroyNode = function(node) { + var view; + view = Batman._data(node, 'view'); + view || (view = Batman._data(node, 'yielder')); + if ((view != null) && view.get('cached')) { + return Batman.DOM.removeNode(node); + } else { + return Batman.DOM.destroyNode(node); + } + }, + insertBefore: Batman.insertBefore = function(parentNode, newNode, referenceNode) { + if (referenceNode == null) { + referenceNode = null; + } + if (!referenceNode || parentNode.childNodes.length <= 0) { + return Batman.appendChild(parentNode, newNode); + } else { + Batman.DOM.willInsertNode(newNode); + parentNode.insertBefore(newNode, referenceNode); + return Batman.DOM.didInsertNode(newNode); + } + }, + valueForNode: function(node, value, escapeValue) { + var isSetting; + if (value == null) { + value = ''; + } + if (escapeValue == null) { + escapeValue = true; + } + isSetting = arguments.length > 1; + switch (node.nodeName.toUpperCase()) { + case 'INPUT': + case 'TEXTAREA': + if (isSetting) { + return node.value = value; + } else { + return node.value; + } + break; + case 'SELECT': + if (isSetting) { + return node.value = value; + } + break; + default: + if (isSetting) { + return Batman.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value); + } else { + return node.innerHTML; + } + } + }, + nodeIsEditable: function(node) { + var _ref; + return (_ref = node.nodeName.toUpperCase()) === 'INPUT' || _ref === 'TEXTAREA' || _ref === 'SELECT'; + }, + addEventListener: Batman.addEventListener = function(node, eventName, callback) { + var listeners; + if (!(listeners = Batman._data(node, 'listeners'))) { + listeners = Batman._data(node, 'listeners', {}); + } + if (!listeners[eventName]) { + listeners[eventName] = []; + } + listeners[eventName].push(callback); + if (Batman.hasAddEventListener) { + return node.addEventListener(eventName, callback, false); + } else { + return node.attachEvent("on" + eventName, callback); + } + }, + removeEventListener: Batman.removeEventListener = function(node, eventName, callback) { + var eventListeners, index, listeners; + if (listeners = Batman._data(node, 'listeners')) { + if (eventListeners = listeners[eventName]) { + index = eventListeners.indexOf(callback); + if (index !== -1) { + eventListeners.splice(index, 1); + } + } + } + if (Batman.hasAddEventListener) { + return node.removeEventListener(eventName, callback, false); + } else { + return node.detachEvent('on' + eventName, callback); + } + }, + hasAddEventListener: Batman.hasAddEventListener = !!(typeof window !== "undefined" && window !== null ? window.addEventListener : void 0), + preventDefault: Batman.preventDefault = function(e) { + if (typeof e.preventDefault === "function") { + return e.preventDefault(); + } else { + return e.returnValue = false; + } + }, + stopPropagation: Batman.stopPropagation = function(e) { + if (e.stopPropagation) { + return e.stopPropagation(); + } else { + return e.cancelBubble = true; + } + }, + willInsertNode: function(node) { + var child, view, _i, _len, _ref, _ref1; + view = Batman._data(node, 'view'); + if (view != null) { + view.fire('beforeAppear', node); + } + if ((_ref = Batman.data(node, 'show')) != null) { + _ref.call(node); + } + _ref1 = node.childNodes; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + child = _ref1[_i]; + Batman.DOM.willInsertNode(child); + } + return true; + }, + didInsertNode: function(node) { + var child, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.fire('appear', node); + view.applyYields(); + } + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.didInsertNode(child); + } + return true; + }, + willRemoveNode: function(node) { + var child, view, _i, _len, _ref, _ref1; + view = Batman._data(node, 'view'); + if (view) { + view.fire('beforeDisappear', node); + } + if ((_ref = Batman.data(node, 'hide')) != null) { + _ref.call(node); + } + _ref1 = node.childNodes; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + child = _ref1[_i]; + Batman.DOM.willRemoveNode(child); + } + return true; + }, + didRemoveNode: function(node) { + var child, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.retractYields(); + view.fire('disappear', node); + } + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.didRemoveNode(child); + } + return true; + }, + willDestroyNode: function(node) { + var child, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.fire('beforeDestroy', node); + view.get('yields').forEach(function(name, actions) { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = actions.length; _i < _len; _i++) { + node = actions[_i].node; + _results.push(Batman.DOM.willDestroyNode(node)); + } + return _results; + }); + } + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.willDestroyNode(child); + } + return true; + }, + didDestroyNode: function(node) { + var bindings, child, eventListeners, eventName, listeners, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.fire('destroy', node); + view.get('yields').forEach(function(name, actions) { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = actions.length; _i < _len; _i++) { + node = actions[_i].node; + _results.push(Batman.DOM.didDestroyNode(node)); + } + return _results; + }); + } + if (bindings = Batman._data(node, 'bindings')) { + bindings.forEach(function(binding) { + return binding.die(); + }); + } + if (listeners = Batman._data(node, 'listeners')) { + for (eventName in listeners) { + eventListeners = listeners[eventName]; + eventListeners.forEach(function(listener) { + return Batman.removeEventListener(node, eventName, listener); + }); + } + } + Batman.removeData(node); + Batman.removeData(node, void 0, true); + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.didDestroyNode(child); + } + return true; + } + }; + + Batman.mixin(Batman.DOM, Batman.EventEmitter, Batman.Observable); + + Batman.DOM.event('bindingAdded'); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.DOM.readers = { + target: function(node, key, context, renderer) { + Batman.DOM.readers.bind(node, key, context, renderer, 'nodeChange'); + return true; + }, + source: function(node, key, context, renderer) { + Batman.DOM.readers.bind(node, key, context, renderer, 'dataChange'); + return true; + }, + bind: function(node, key, context, renderer, only) { + var bindingClass; + bindingClass = false; + switch (node.nodeName.toLowerCase()) { + case 'input': + switch (node.getAttribute('type')) { + case 'checkbox': + Batman.DOM.attrReaders.bind(node, 'checked', key, context, renderer, only); + return true; + case 'radio': + bindingClass = Batman.DOM.RadioBinding; + break; + case 'file': + bindingClass = Batman.DOM.FileBinding; + } + break; + case 'select': + bindingClass = Batman.DOM.SelectBinding; + } + bindingClass || (bindingClass = Batman.DOM.Binding); + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(bindingClass, arguments, function(){}); + return true; + }, + context: function(node, key, context, renderer) { + return context.descendWithKey(key); + }, + mixin: function(node, key, context, renderer) { + new Batman.DOM.MixinBinding(node, key, context.descend(Batman.mixins), renderer); + return true; + }, + showif: function(node, key, context, parentRenderer, invert) { + new Batman.DOM.ShowHideBinding(node, key, context, parentRenderer, false, invert); + return true; + }, + hideif: function() { + var _ref; + return (_ref = Batman.DOM.readers).showif.apply(_ref, __slice.call(arguments).concat([true])); + }, + insertif: function(node, key, context, parentRenderer, invert) { + new Batman.DOM.InsertionBinding(node, key, context, parentRenderer, false, invert); + return true; + }, + removeif: function() { + var _ref; + return (_ref = Batman.DOM.readers).insertif.apply(_ref, __slice.call(arguments).concat([true])); + }, + route: function() { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.RouteBinding, arguments, function(){}); + return true; + }, + view: function() { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.ViewBinding, arguments, function(){}); + return false; + }, + partial: function(node, path, context, renderer) { + Batman.DOM.partial(node, path, context, renderer); + return true; + }, + defineview: function(node, name, context, renderer) { + Batman.onParseExit(node, function() { + var _ref; + return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; + }); + Batman.DOM.defineView(name, node); + return false; + }, + renderif: function(node, key, context, renderer) { + new Batman.DOM.DeferredRenderingBinding(node, key, context, renderer); + return false; + }, + "yield": function(node, key) { + Batman.onParseExit(node, function() { + return Batman.DOM.Yield.withName(key).set('containerNode', node); + }); + return true; + }, + contentfor: function(node, key, context, renderer, action) { + if (action == null) { + action = 'append'; + } + Batman.onParseExit(node, function() { + var _ref; + if ((_ref = node.parentNode) != null) { + _ref.removeChild(node); + } + return renderer.view.pushYieldAction(key, action, node); + }); + return true; + }, + replace: function(node, key, context, renderer) { + Batman.DOM.readers.contentfor(node, key, context, renderer, 'replace'); + return true; + } + }; + +}).call(this); + +(function() { + var __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.DOM.events = { + click: function(node, callback, context, eventName) { + if (eventName == null) { + eventName = 'click'; + } + Batman.addEventListener(node, eventName, function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + callback.apply(null, [node].concat(__slice.call(args), [context])); + return Batman.preventDefault(args[0]); + }); + if (node.nodeName.toUpperCase() === 'A' && !node.href) { + node.href = '#'; + } + return node; + }, + doubleclick: function(node, callback, context) { + return Batman.DOM.events.click(node, callback, context, 'dblclick'); + }, + change: function(node, callback, context) { + var eventName, eventNames, oldCallback, _i, _len, _results; + eventNames = (function() { + var _ref; + switch (node.nodeName.toUpperCase()) { + case 'TEXTAREA': + return ['input', 'keyup', 'change']; + case 'INPUT': + if (_ref = node.type.toLowerCase(), __indexOf.call(Batman.DOM.textInputTypes, _ref) >= 0) { + oldCallback = callback; + callback = function(node, event) { + if (event.type === 'keyup' && Batman.DOM.events.isEnter(event)) { + return; + } + return oldCallback.apply(null, arguments); + }; + return ['input', 'keyup', 'change']; + } else { + return ['input', 'change']; + } + break; + default: + return ['change']; + } + })(); + _results = []; + for (_i = 0, _len = eventNames.length; _i < _len; _i++) { + eventName = eventNames[_i]; + _results.push(Batman.addEventListener(node, eventName, function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return callback.apply(null, [node].concat(__slice.call(args), [context])); + })); + } + return _results; + }, + isEnter: function(ev) { + var _ref, _ref1; + return ((13 <= (_ref = ev.keyCode) && _ref <= 14)) || ((13 <= (_ref1 = ev.which) && _ref1 <= 14)) || ev.keyIdentifier === 'Enter' || ev.key === 'Enter'; + }, + submit: function(node, callback, context) { + if (Batman.DOM.nodeIsEditable(node)) { + Batman.addEventListener(node, 'keydown', function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (Batman.DOM.events.isEnter(args[0])) { + return Batman.DOM._keyCapturingNode = node; + } + }); + Batman.addEventListener(node, 'keyup', function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (Batman.DOM.events.isEnter(args[0])) { + if (Batman.DOM._keyCapturingNode === node) { + Batman.preventDefault(args[0]); + callback.apply(null, [node].concat(__slice.call(args), [context])); + } + return Batman.DOM._keyCapturingNode = null; + } + }); + } else { + Batman.addEventListener(node, 'submit', function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + Batman.preventDefault(args[0]); + return callback.apply(null, [node].concat(__slice.call(args), [context])); + }); + } + return node; + }, + other: function(node, eventName, callback, context) { + return Batman.addEventListener(node, eventName, function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return callback.apply(null, [node].concat(__slice.call(args), [context])); + }); + } + }; + +}).call(this); + +(function() { + + Batman.DOM.attrReaders = { + _parseAttribute: function(value) { + if (value === 'false') { + value = false; + } + if (value === 'true') { + value = true; + } + return value; + }, + source: function(node, attr, key, context, renderer) { + return Batman.DOM.attrReaders.bind(node, attr, key, context, renderer, 'dataChange'); + }, + bind: function(node, attr, key, context, renderer, only) { + var bindingClass; + bindingClass = (function() { + switch (attr) { + case 'checked': + case 'disabled': + case 'selected': + return Batman.DOM.CheckedBinding; + case 'value': + case 'href': + case 'src': + case 'size': + return Batman.DOM.NodeAttributeBinding; + case 'class': + return Batman.DOM.ClassBinding; + case 'style': + return Batman.DOM.StyleBinding; + default: + return Batman.DOM.AttributeBinding; + } + })(); + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(bindingClass, arguments, function(){}); + return true; + }, + context: function(node, contextName, key, context) { + return context.descendWithKey(key, contextName); + }, + event: function(node, eventName, key, context) { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.EventBinding, arguments, function(){}); + return true; + }, + addclass: function(node, className, key, context, parentRenderer, invert) { + new Batman.DOM.AddClassBinding(node, className, key, context, parentRenderer, false, invert); + return true; + }, + removeclass: function(node, className, key, context, parentRenderer) { + return Batman.DOM.attrReaders.addclass(node, className, key, context, parentRenderer, true); + }, + foreach: function(node, iteratorName, key, context, parentRenderer) { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.IteratorBinding, arguments, function(){}); + return false; + }, + formfor: function(node, localName, key, context) { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.FormBinding, arguments, function(){}); + return context.descendWithKey(key, localName); + } + }; + +}).call(this); + +(function() { + var BatmanObject, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + BatmanObject = (function(_super) { + var counter, getAccessorObject, promiseWrapper, wrapSingleAccessor; + + __extends(BatmanObject, _super); + + Batman.initializeObject(BatmanObject); + + Batman.initializeObject(BatmanObject.prototype); + + BatmanObject.classMixin = function() { + return Batman.mixin.apply(Batman, [this].concat(__slice.call(arguments))); + }; + + BatmanObject.mixin = function() { + return this.classMixin.apply(this.prototype, arguments); + }; + + BatmanObject.prototype.mixin = BatmanObject.classMixin; + + counter = 0; + + BatmanObject.prototype._batmanID = function() { + var c; + this._batmanID = function() { + return c; + }; + return c = counter++; + }; + + BatmanObject.prototype.hashKey = function() { + var key; + if (typeof this.isEqual === 'function') { + return; + } + this.hashKey = function() { + return key; + }; + return key = ""; + }; + + BatmanObject.prototype.toJSON = function() { + var key, obj, value; + obj = {}; + for (key in this) { + if (!__hasProp.call(this, key)) continue; + value = this[key]; + if (key !== "_batman" && key !== "hashKey" && key !== "_batmanID") { + obj[key] = (value != null ? value.toJSON : void 0) ? value.toJSON() : value; + } + } + return obj; + }; + + getAccessorObject = function(base, accessor) { + var deprecated, _i, _len, _ref; + if (typeof accessor === 'function') { + accessor = { + get: accessor + }; + } + _ref = ['cachable', 'cacheable']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + deprecated = _ref[_i]; + if (deprecated in accessor) { + Batman.developer.warn("Property accessor option \"" + deprecated + "\" is deprecated. Use \"cache\" instead."); + if (!('cache' in accessor)) { + accessor.cache = accessor[deprecated]; + } + } + } + return accessor; + }; + + promiseWrapper = function(fetcher) { + return function(core) { + return { + get: function(key) { + var deliver, returned, val, + _this = this; + val = core.get.apply(this, arguments); + if (typeof val !== 'undefined') { + return val; + } + returned = false; + deliver = function(err, result) { + if (returned) { + _this.set(key, result); + } + return val = result; + }; + fetcher.call(this, deliver, key); + returned = true; + return val; + }, + cache: true + }; + }; + }; + + wrapSingleAccessor = function(core, wrapper) { + var k, v; + wrapper = (typeof wrapper === "function" ? wrapper(core) : void 0) || wrapper; + for (k in core) { + v = core[k]; + if (!(k in wrapper)) { + wrapper[k] = v; + } + } + return wrapper; + }; + + BatmanObject._defineAccessor = function() { + var accessor, key, keys, _base, _i, _j, _len, _ref, _results; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), accessor = arguments[_i++]; + if (!(accessor != null)) { + return Batman.Property.defaultAccessorForBase(this); + } else if (keys.length === 0 && ((_ref = Batman.typeOf(accessor)) !== 'Object' && _ref !== 'Function')) { + return Batman.Property.accessorForBaseAndKey(this, accessor); + } else if (typeof accessor.promise === 'function') { + return this._defineWrapAccessor.apply(this, __slice.call(keys).concat([promiseWrapper(accessor.promise)])); + } + Batman.initializeObject(this); + if (keys.length === 0) { + return this._batman.defaultAccessor = getAccessorObject(this, accessor); + } else { + (_base = this._batman).keyAccessors || (_base.keyAccessors = new Batman.SimpleHash); + _results = []; + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + _results.push(this._batman.keyAccessors.set(key, getAccessorObject(this, accessor))); + } + return _results; + } + }; + + BatmanObject.prototype._defineAccessor = BatmanObject._defineAccessor; + + BatmanObject._defineWrapAccessor = function() { + var key, keys, wrapper, _i, _j, _len, _results; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), wrapper = arguments[_i++]; + Batman.initializeObject(this); + if (keys.length === 0) { + return this._defineAccessor(wrapSingleAccessor(this._defineAccessor(), wrapper)); + } else { + _results = []; + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + _results.push(this._defineAccessor(key, wrapSingleAccessor(this._defineAccessor(key), wrapper))); + } + return _results; + } + }; + + BatmanObject.prototype._defineWrapAccessor = BatmanObject._defineWrapAccessor; + + BatmanObject.classAccessor = BatmanObject._defineAccessor; + + BatmanObject.accessor = function() { + var _ref; + return (_ref = this.prototype)._defineAccessor.apply(_ref, arguments); + }; + + BatmanObject.prototype.accessor = BatmanObject._defineAccessor; + + BatmanObject.wrapClassAccessor = BatmanObject._defineWrapAccessor; + + BatmanObject.wrapAccessor = function() { + var _ref; + return (_ref = this.prototype)._defineWrapAccessor.apply(_ref, arguments); + }; + + BatmanObject.prototype.wrapAccessor = BatmanObject._defineWrapAccessor; + + function BatmanObject() { + var mixins; + mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + this._batman = new Batman._Batman(this); + this.mixin.apply(this, mixins); + } + + BatmanObject.classMixin(Batman.EventEmitter, Batman.Observable); + + BatmanObject.mixin(Batman.EventEmitter, Batman.Observable); + + BatmanObject.observeAll = function() { + return this.prototype.observe.apply(this.prototype, arguments); + }; + + BatmanObject.singleton = function(singletonMethodName) { + if (singletonMethodName == null) { + singletonMethodName = "sharedInstance"; + } + return this.classAccessor(singletonMethodName, { + get: function() { + var _name; + return this[_name = "_" + singletonMethodName] || (this[_name] = new this); + } + }); + }; + + BatmanObject.accessor('_batmanID', function() { + return this._batmanID(); + }); + + return BatmanObject; + + })(Object); + + Batman.Object = BatmanObject; + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Renderer = (function(_super) { + var bindingRegexp, bindingSortOrder, bindingSortPositions, k, name, pos, _i, _j, _len, _len1, _ref; + + __extends(Renderer, _super); + + Renderer.prototype.deferEvery = 50; + + function Renderer(node, context, view) { + this.node = node; + this.context = context; + this.view = view; + this.resume = __bind(this.resume, this); + + this.start = __bind(this.start, this); + + Renderer.__super__.constructor.call(this); + if (!(this.context instanceof Batman.RenderContext)) { + Batman.developer.error("Must pass a RenderContext to a renderer for rendering"); + } + this.immediate = Batman.setImmediate(this.start); + } + + Renderer.prototype.start = function() { + this.startTime = new Date; + return this.parseNode(this.node); + }; + + Renderer.prototype.resume = function() { + this.startTime = new Date; + return this.parseNode(this.resumeNode); + }; + + Renderer.prototype.finish = function() { + this.startTime = null; + this.prevent('stopped'); + this.fire('parsed'); + return this.fire('rendered'); + }; + + Renderer.prototype.stop = function() { + Batman.clearImmediate(this.immediate); + return this.fire('stopped'); + }; + + _ref = ['parsed', 'rendered', 'stopped']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + Renderer.prototype.event(k).oneShot = true; + } + + bindingRegexp = /^data\-(.*)/; + + bindingSortOrder = ["view", "renderif", "foreach", "formfor", "context", "bind", "source", "target"]; + + bindingSortPositions = {}; + + for (pos = _j = 0, _len1 = bindingSortOrder.length; _j < _len1; pos = ++_j) { + name = bindingSortOrder[pos]; + bindingSortPositions[name] = pos; + } + + Renderer.prototype._sortBindings = function(a, b) { + var aindex, bindex; + aindex = bindingSortPositions[a[0]]; + bindex = bindingSortPositions[b[0]]; + if (aindex == null) { + aindex = bindingSortOrder.length; + } + if (bindex == null) { + bindex = bindingSortOrder.length; + } + if (aindex > bindex) { + return 1; + } else if (bindex > aindex) { + return -1; + } else if (a[0] > b[0]) { + return 1; + } else if (b[0] > a[0]) { + return -1; + } else { + return 0; + } + }; + + Renderer.prototype.parseNode = function(node) { + var argument, attribute, bindings, keypath, names, nextNode, oldContext, result, skipChildren, _base, _base1, _k, _l, _len2, _len3, _ref1, _ref2, _ref3, _ref4, + _this = this; + if (this.deferEvery && (new Date - this.startTime) > this.deferEvery) { + this.resumeNode = node; + this.timeout = Batman.setImmediate(this.resume); + return; + } + if (node.getAttribute && node.attributes) { + bindings = []; + _ref1 = node.attributes; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + attribute = _ref1[_k]; + name = (_ref2 = attribute.nodeName.match(bindingRegexp)) != null ? _ref2[1] : void 0; + if (!name) { + continue; + } + bindings.push((names = name.split('-')).length > 1 ? [names[0], names.slice(1, names.length + 1 || 9e9).join('-'), attribute.value] : [name, void 0, attribute.value]); + } + _ref3 = bindings.sort(this._sortBindings); + for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { + _ref4 = _ref3[_l], name = _ref4[0], argument = _ref4[1], keypath = _ref4[2]; + result = argument ? typeof (_base = Batman.DOM.attrReaders)[name] === "function" ? _base[name](node, argument, keypath, this.context, this) : void 0 : typeof (_base1 = Batman.DOM.readers)[name] === "function" ? _base1[name](node, keypath, this.context, this) : void 0; + if (result === false) { + skipChildren = true; + break; + } else if (result instanceof Batman.RenderContext) { + oldContext = this.context; + this.context = result; + Batman.onParseExit(node, function() { + return _this.context = oldContext; + }); + } + } + } + if ((nextNode = this.nextNode(node, skipChildren))) { + return this.parseNode(nextNode); + } else { + return this.finish(); + } + }; + + Renderer.prototype.nextNode = function(node, skipChildren) { + var children, nextParent, parentSibling, sibling, _ref1, _ref2; + if (!skipChildren) { + children = node.childNodes; + if (children != null ? children.length : void 0) { + return children[0]; + } + } + sibling = node.nextSibling; + if ((_ref1 = Batman.onParseExit(node)) != null) { + _ref1.forEach(function(callback) { + return callback(); + }); + } + Batman.forgetParseExit(node); + if (this.node === node) { + return; + } + if (sibling) { + return sibling; + } + nextParent = node; + while (nextParent = nextParent.parentNode) { + parentSibling = nextParent.nextSibling; + if ((_ref2 = Batman.onParseExit(nextParent)) != null) { + _ref2.forEach(function(callback) { + return callback(); + }); + } + Batman.forgetParseExit(nextParent); + if (this.node === nextParent) { + return; + } + if (parentSibling) { + return parentSibling; + } + } + }; + + return Renderer; + + })(Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AbstractBinding = (function(_super) { + var get_dot_rx, get_rx, keypath_rx; + + __extends(AbstractBinding, _super); + + keypath_rx = /(^|,)\s*(?:(true|false)|("[^"]*")|(\{[^\}]*\})|([a-zA-Z][\w\-\.]*[\?\!]?))\s*(?=$|,)/g; + + get_dot_rx = /(?:\]\.)(.+?)(?=[\[\.]|\s*\||$)/; + + get_rx = /(?!^\s*)\[(.*?)\]/g; + + AbstractBinding.accessor('filteredValue', { + get: function() { + var renderContext, result, self, unfilteredValue; + unfilteredValue = this.get('unfilteredValue'); + self = this; + renderContext = this.get('renderContext'); + if (this.filterFunctions.length > 0) { + Batman.developer.currentFilterStack = renderContext; + result = this.filterFunctions.reduce(function(value, fn, i) { + var args; + args = self.filterArguments[i].map(function(argument) { + if (argument._keypath) { + return self.renderContext.get(argument._keypath); + } else { + return argument; + } + }); + args.unshift(value); + while (args.length < (fn.length - 1)) { + args.push(void 0); + } + args.push(self); + return fn.apply(renderContext, args); + }, unfilteredValue); + Batman.developer.currentFilterStack = null; + return result; + } else { + return unfilteredValue; + } + }, + set: function(_, newValue) { + return this.set('unfilteredValue', newValue); + } + }); + + AbstractBinding.accessor('unfilteredValue', { + get: function() { + var k; + if (k = this.get('key')) { + return Batman.RenderContext.deProxy(Batman.getPath(this, ['keyContext', k])); + } else { + return this.get('value'); + } + }, + set: function(_, value) { + var k, keyContext, prop; + if (k = this.get('key')) { + keyContext = this.get('keyContext'); + if (keyContext && keyContext !== Batman.container) { + prop = Batman.Property.forBaseAndKey(keyContext, k); + return prop.setValue(value); + } + } else { + return this.set('value', value); + } + } + }); + + AbstractBinding.accessor('keyContext', function() { + return this.renderContext.contextForKey(this.key); + }); + + AbstractBinding.prototype.bindImmediately = true; + + AbstractBinding.prototype.shouldSet = true; + + AbstractBinding.prototype.isInputBinding = false; + + AbstractBinding.prototype.escapeValue = true; + + function AbstractBinding(node, keyPath, renderContext, renderer, only) { + this.node = node; + this.keyPath = keyPath; + this.renderContext = renderContext; + this.renderer = renderer; + this.only = only != null ? only : false; + this._fireDataChange = __bind(this._fireDataChange, this); + + this._fireNodeChange = __bind(this._fireNodeChange, this); + + this.parseFilter(); + if (this.bindImmediately) { + this.bind(); + } + } + + AbstractBinding.prototype.isTwoWay = function() { + return (this.key != null) && this.filterFunctions.length === 0; + }; + + AbstractBinding.prototype.bind = function() { + var _ref, _ref1; + if ((this.node != null) && ((_ref = this.only) === false || _ref === 'nodeChange') && Batman.DOM.nodeIsEditable(this.node)) { + Batman.DOM.events.change(this.node, this._fireNodeChange); + if (this.only === 'nodeChange') { + this._fireNodeChange(); + } + } + if ((_ref1 = this.only) === false || _ref1 === 'dataChange') { + this.observeAndFire('filteredValue', this._fireDataChange); + } + if (this.node != null) { + return Batman.DOM.trackBinding(this, this.node); + } + }; + + AbstractBinding.prototype._fireNodeChange = function(event) { + var val; + this.shouldSet = false; + val = this.value || this.get('keyContext'); + if (typeof this.nodeChange === "function") { + this.nodeChange(this.node, val, event); + } + this.fire('nodeChange', this.node, val); + return this.shouldSet = true; + }; + + AbstractBinding.prototype._fireDataChange = function(value) { + if (this.shouldSet) { + if (typeof this.dataChange === "function") { + this.dataChange(value, this.node); + } + return this.fire('dataChange', value, this.node); + } + }; + + AbstractBinding.prototype.die = function() { + var _ref; + this.forget(); + if ((_ref = this._batman.properties) != null) { + _ref.forEach(function(key, property) { + return property.die(); + }); + } + this.fire('die'); + this.dead = true; + return true; + }; + + AbstractBinding.prototype.parseFilter = function() { + var args, filter, filterName, filterString, filters, key, keyPath, orig, split; + this.filterFunctions = []; + this.filterArguments = []; + keyPath = this.keyPath; + while (get_dot_rx.test(keyPath)) { + keyPath = keyPath.replace(get_dot_rx, "]['$1']"); + } + filters = keyPath.replace(get_rx, " | get $1 ").replace(/'/g, '"').split(/(?!")\s+\|\s+(?!")/); + try { + key = this.parseSegment(orig = filters.shift())[0]; + } catch (e) { + Batman.developer.warn(e); + Batman.developer.error("Error! Couldn't parse keypath in \"" + orig + "\". Parsing error above."); + } + if (key && key._keypath) { + this.key = key._keypath; + } else { + this.value = key; + } + if (filters.length) { + while (filterString = filters.shift()) { + split = filterString.indexOf(' '); + if (split === -1) { + split = filterString.length; + } + filterName = filterString.substr(0, split); + args = filterString.substr(split); + if (!(filter = Batman.Filters[filterName])) { + return Batman.developer.error("Unrecognized filter '" + filterName + "' in key \"" + this.keyPath + "\"!"); + } + this.filterFunctions.push(filter); + try { + this.filterArguments.push(this.parseSegment(args)); + } catch (e) { + Batman.developer.error("Bad filter arguments \"" + args + "\"!"); + } + } + return true; + } + }; + + AbstractBinding.prototype.parseSegment = function(segment) { + segment = segment.replace(keypath_rx, function(match, start, bool, string, object, keypath, offset) { + var replacement; + if (start == null) { + start = ''; + } + replacement = keypath ? '{"_keypath": "' + keypath + '"}' : bool || string || object; + return start + replacement; + }); + return JSON.parse("[" + segment + "]"); + }; + + return AbstractBinding; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ViewBinding = (function(_super) { + + __extends(ViewBinding, _super); + + function ViewBinding() { + ViewBinding.__super__.constructor.apply(this, arguments); + this.renderer.prevent('rendered'); + this.node.removeAttribute('data-view'); + } + + ViewBinding.prototype.dataChange = function(viewClassOrInstance) { + var _this = this; + if (viewClassOrInstance == null) { + return; + } + if (viewClassOrInstance.isView) { + this.view = viewClassOrInstance; + this.view.set('context', this.renderContext); + this.view.set('node', this.node); + } else { + this.view = new viewClassOrInstance({ + node: this.node, + context: this.renderContext, + parentView: this.renderer.view + }); + } + this.view.on('ready', function() { + return _this.renderer.allowAndFire('rendered'); + }); + return this.die(); + }; + + return ViewBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ViewArgumentBinding = (function(_super) { + + __extends(ViewArgumentBinding, _super); + + function ViewArgumentBinding() { + return ViewArgumentBinding.__super__.constructor.apply(this, arguments); + } + + return ViewArgumentBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ShowHideBinding = (function(_super) { + + __extends(ShowHideBinding, _super); + + function ShowHideBinding(node, className, key, context, parentRenderer, invert) { + var display; + this.invert = invert != null ? invert : false; + display = node.style.display; + if (!display || display === 'none') { + display = ''; + } + this.originalDisplay = display; + ShowHideBinding.__super__.constructor.apply(this, arguments); + } + + ShowHideBinding.prototype.dataChange = function(value) { + var hide, view, _ref; + view = Batman._data(this.node, 'view'); + if (!!value === !this.invert) { + if (view != null) { + view.fire('beforeAppear', this.node); + } + if ((_ref = Batman.data(this.node, 'show')) != null) { + _ref.call(this.node); + } + this.node.style.display = this.originalDisplay; + return view != null ? view.fire('appear', this.node) : void 0; + } else { + if (view != null) { + view.fire('beforeDisappear', this.node); + } + if (typeof (hide = Batman.data(this.node, 'hide')) === 'function') { + hide.call(this.node); + } else { + Batman.setStyleProperty(this.node, 'display', 'none', 'important'); + } + return view != null ? view.fire('disappear', this.node) : void 0; + } + }; + + return ShowHideBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.SelectBinding = (function(_super) { + + __extends(SelectBinding, _super); + + SelectBinding.prototype.isInputBinding = true; + + SelectBinding.prototype.firstBind = true; + + function SelectBinding() { + this.updateOptionBindings = __bind(this.updateOptionBindings, this); + + this.nodeChange = __bind(this.nodeChange, this); + + this.dataChange = __bind(this.dataChange, this); + + this.childBindingAdded = __bind(this.childBindingAdded, this); + this.selectedBindings = new Batman.SimpleSet; + SelectBinding.__super__.constructor.apply(this, arguments); + } + + SelectBinding.prototype.childBindingAdded = function(binding) { + var dataChangeHandler, + _this = this; + if (binding instanceof Batman.DOM.CheckedBinding) { + binding.on('dataChange', dataChangeHandler = function() { + return _this.nodeChange(); + }); + binding.on('die', function() { + binding.forget('dataChange', dataChangeHandler); + return _this.selectedBindings.remove(binding); + }); + this.selectedBindings.add(binding); + } else if (binding instanceof Batman.DOM.IteratorBinding) { + binding.on('nodeAdded', dataChangeHandler = function() { + return _this._fireDataChange(_this.get('filteredValue')); + }); + binding.on('nodeRemoved', dataChangeHandler); + binding.on('die', function() { + binding.forget('nodeAdded', dataChangeHandler); + return binding.forget('nodeRemoved', dataChangeHandler); + }); + } else { + return; + } + return this._fireDataChange(this.get('filteredValue')); + }; + + SelectBinding.prototype.dataChange = function(newValue) { + var child, matches, valueToChild, _i, _len, _name, _ref, + _this = this; + if (newValue != null ? newValue.forEach : void 0) { + valueToChild = {}; + _ref = this.node.children; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + child.selected = false; + matches = valueToChild[_name = child.value] || (valueToChild[_name] = []); + matches.push(child); + } + newValue.forEach(function(value) { + var children, node, _j, _len1, _results; + if (children = valueToChild[value]) { + _results = []; + for (_j = 0, _len1 = children.length; _j < _len1; _j++) { + node = children[_j]; + _results.push(node.selected = true); + } + return _results; + } + }); + } else { + if (typeof newValue === 'undefined' && this.firstBind) { + this.set('unfilteredValue', this.node.value); + } else { + Batman.DOM.valueForNode(this.node, newValue, this.escapeValue); + } + this.firstBind = false; + } + this.updateOptionBindings(); + }; + + SelectBinding.prototype.nodeChange = function() { + var c, selections; + if (this.isTwoWay()) { + selections = this.node.multiple ? (function() { + var _i, _len, _ref, _results; + _ref = this.node.children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + c = _ref[_i]; + if (c.selected) { + _results.push(c.value); + } + } + return _results; + }).call(this) : this.node.value; + if (typeof selections === Array && selections.length === 1) { + selections = selections[0]; + } + this.set('unfilteredValue', selections); + this.updateOptionBindings(); + } + }; + + SelectBinding.prototype.updateOptionBindings = function() { + return this.selectedBindings.forEach(function(binding) { + return binding._fireNodeChange(); + }); + }; + + return SelectBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.RouteBinding = (function(_super) { + + __extends(RouteBinding, _super); + + function RouteBinding() { + return RouteBinding.__super__.constructor.apply(this, arguments); + } + + RouteBinding.prototype.onATag = false; + + RouteBinding.accessor('dispatcher', function() { + return this.renderContext.get('dispatcher') || Batman.App.get('current.dispatcher'); + }); + + RouteBinding.prototype.bind = function() { + var _this = this; + if (this.node.nodeName.toUpperCase() === 'A') { + this.onATag = true; + } + RouteBinding.__super__.bind.apply(this, arguments); + return Batman.DOM.events.click(this.node, function(node, event) { + var params; + if (event.__batmanActionTaken) { + return; + } + event.__batmanActionTaken = true; + params = _this.pathFromValue(_this.get('filteredValue')); + if (params != null) { + return Batman.redirect(params); + } + }); + }; + + RouteBinding.prototype.dataChange = function(value) { + var path; + if (value != null) { + path = this.pathFromValue(value); + } + if (this.onATag) { + if (path != null) { + path = Batman.navigator.linkTo(path); + } else { + path = "#"; + } + return this.node.href = path; + } + }; + + RouteBinding.prototype.pathFromValue = function(value) { + var _ref; + if (value != null) { + if (value.isNamedRouteQuery) { + return value.get('path'); + } else { + return (_ref = this.get('dispatcher')) != null ? _ref.pathFromParams(value) : void 0; + } + } + }; + + return RouteBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.RadioBinding = (function(_super) { + + __extends(RadioBinding, _super); + + function RadioBinding() { + return RadioBinding.__super__.constructor.apply(this, arguments); + } + + RadioBinding.prototype.isInputBinding = true; + + RadioBinding.prototype.dataChange = function(value) { + var boundValue; + if ((boundValue = this.get('filteredValue')) != null) { + return this.node.checked = boundValue === this.node.value; + } else if (this.node.checked) { + return this.set('filteredValue', this.node.value); + } + }; + + RadioBinding.prototype.nodeChange = function(node) { + if (this.isTwoWay()) { + return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node.value)); + } + }; + + return RadioBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.MixinBinding = (function(_super) { + + __extends(MixinBinding, _super); + + function MixinBinding() { + return MixinBinding.__super__.constructor.apply(this, arguments); + } + + MixinBinding.prototype.dataChange = function(value) { + if (value != null) { + return Batman.mixin(this.node, value); + } + }; + + return MixinBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.FileBinding = (function(_super) { + + __extends(FileBinding, _super); + + function FileBinding() { + return FileBinding.__super__.constructor.apply(this, arguments); + } + + FileBinding.prototype.isInputBinding = true; + + FileBinding.prototype.nodeChange = function(node, subContext) { + if (!this.isTwoWay()) { + return; + } + if (node.hasAttribute('multiple')) { + return this.set('filteredValue', Array.prototype.slice.call(node.files)); + } else { + return this.set('filteredValue', node.files[0]); + } + }; + + return FileBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.DeferredRenderingBinding = (function(_super) { + + __extends(DeferredRenderingBinding, _super); + + DeferredRenderingBinding.prototype.rendered = false; + + function DeferredRenderingBinding() { + DeferredRenderingBinding.__super__.constructor.apply(this, arguments); + this.node.removeAttribute("data-renderif"); + } + + DeferredRenderingBinding.prototype.nodeChange = function() {}; + + DeferredRenderingBinding.prototype.dataChange = function(value) { + if (value && !this.rendered) { + return this.render(); + } + }; + + DeferredRenderingBinding.prototype.render = function() { + new Batman.Renderer(this.node, this.renderContext, this.renderer.view); + return this.rendered = true; + }; + + return DeferredRenderingBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.Binding = (function(_super) { + + __extends(Binding, _super); + + function Binding(node) { + var _ref; + this.isInputBinding = (_ref = node.nodeName.toLowerCase()) === 'input' || _ref === 'textarea'; + Binding.__super__.constructor.apply(this, arguments); + } + + Binding.prototype.nodeChange = function(node, context) { + if (this.isTwoWay()) { + return this.set('filteredValue', this.node.value); + } + }; + + Binding.prototype.dataChange = function(value, node) { + return Batman.DOM.valueForNode(this.node, value, this.escapeValue); + }; + + return Binding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.DOM.AbstractAttributeBinding = (function(_super) { + + __extends(AbstractAttributeBinding, _super); + + function AbstractAttributeBinding() { + var args, attributeName, node; + node = arguments[0], attributeName = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + this.attributeName = attributeName; + AbstractAttributeBinding.__super__.constructor.apply(this, [node].concat(__slice.call(args))); + } + + return AbstractAttributeBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.FormBinding = (function(_super) { + + __extends(FormBinding, _super); + + FormBinding.current = null; + + FormBinding.prototype.errorClass = 'error'; + + FormBinding.prototype.defaultErrorsListSelector = 'div.errors'; + + FormBinding.accessor('errorsListSelector', function() { + return this.get('node').getAttribute('data-errors-list') || this.defaultErrorsListSelector; + }); + + function FormBinding(node, contextName, keyPath, renderContext, renderer, only) { + this.childBindingAdded = __bind(this.childBindingAdded, this); + FormBinding.__super__.constructor.apply(this, arguments); + this.contextName = contextName; + delete this.attributeName; + Batman.DOM.events.submit(this.get('node'), function(node, e) { + return Batman.preventDefault(e); + }); + this.setupErrorsList(); + } + + FormBinding.prototype.childBindingAdded = function(binding) { + var field, index, node; + if (binding.isInputBinding && Batman.isChildOf(this.get('node'), binding.get('node'))) { + if (~(index = binding.get('key').indexOf(this.contextName))) { + node = binding.get('node'); + field = binding.get('key').slice(index + this.contextName.length + 1); + return new Batman.DOM.AddClassBinding(node, this.errorClass, this.get('keyPath') + (" | get 'errors." + field + ".length'"), this.renderContext, this.renderer); + } + } + }; + + FormBinding.prototype.setupErrorsList = function() { + if (this.errorsListNode = Batman.DOM.querySelector(this.get('node'), this.get('errorsListSelector'))) { + Batman.setInnerHTML(this.errorsListNode, this.errorsListHTML()); + if (!this.errorsListNode.getAttribute('data-showif')) { + return this.errorsListNode.setAttribute('data-showif', "" + this.contextName + ".errors.length"); + } + } + }; + + FormBinding.prototype.errorsListHTML = function() { + return "
    \n
  • \n
"; + }; + + return FormBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.EventBinding = (function(_super) { + + __extends(EventBinding, _super); + + EventBinding.prototype.bindImmediately = false; + + function EventBinding(node, eventName, key, context) { + var attacher, callback, confirmText, + _this = this; + EventBinding.__super__.constructor.apply(this, arguments); + confirmText = this.node.getAttribute('data-confirm'); + callback = function() { + var _ref; + if (confirmText && !confirm(confirmText)) { + return; + } + return (_ref = _this.get('filteredValue')) != null ? _ref.apply(_this.get('callbackContext'), arguments) : void 0; + }; + if (attacher = Batman.DOM.events[this.attributeName]) { + attacher(this.node, callback, context); + } else { + Batman.DOM.events.other(this.node, this.attributeName, callback, context); + } + this.bind(); + } + + EventBinding.accessor('callbackContext', function() { + var contextKeySegments; + contextKeySegments = this.key.split('.'); + contextKeySegments.pop(); + if (contextKeySegments.length > 0) { + return this.get('keyContext').get(contextKeySegments.join('.')); + } else { + return this.get('keyContext'); + } + }); + + EventBinding.wrapAccessor('unfilteredValue', function(core) { + return { + get: function() { + var functionKey, k, keyContext, keys; + if (k = this.get('key')) { + keys = k.split('.'); + if (keys.length > 1) { + functionKey = keys.pop(); + keyContext = Batman.getPath(this, ['keyContext'].concat(keys)); + if (keyContext != null) { + keyContext = Batman.RenderContext.deProxy(keyContext); + return keyContext[functionKey]; + } + } + } + return core.get.apply(this, arguments); + } + }; + }); + + return EventBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.NodeAttributeBinding = (function(_super) { + + __extends(NodeAttributeBinding, _super); + + function NodeAttributeBinding() { + return NodeAttributeBinding.__super__.constructor.apply(this, arguments); + } + + NodeAttributeBinding.prototype.dataChange = function(value) { + if (value == null) { + value = ""; + } + return this.node[this.attributeName] = value; + }; + + NodeAttributeBinding.prototype.nodeChange = function(node) { + if (this.isTwoWay()) { + return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node[this.attributeName])); + } + }; + + return NodeAttributeBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.CheckedBinding = (function(_super) { + + __extends(CheckedBinding, _super); + + function CheckedBinding() { + return CheckedBinding.__super__.constructor.apply(this, arguments); + } + + CheckedBinding.prototype.isInputBinding = true; + + CheckedBinding.prototype.dataChange = function(value) { + return this.node[this.attributeName] = !!value; + }; + + return CheckedBinding; + + })(Batman.DOM.NodeAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AttributeBinding = (function(_super) { + + __extends(AttributeBinding, _super); + + function AttributeBinding() { + return AttributeBinding.__super__.constructor.apply(this, arguments); + } + + AttributeBinding.prototype.dataChange = function(value) { + return this.node.setAttribute(this.attributeName, value); + }; + + AttributeBinding.prototype.nodeChange = function(node) { + if (this.isTwoWay()) { + return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node.getAttribute(this.attributeName))); + } + }; + + return AttributeBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AddClassBinding = (function(_super) { + + __extends(AddClassBinding, _super); + + function AddClassBinding(node, className, keyPath, renderContext, renderer, only, invert) { + var name, names; + this.invert = invert != null ? invert : false; + names = className.split('|'); + this.classes = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = names.length; _i < _len; _i++) { + name = names[_i]; + _results.push({ + name: name, + pattern: new RegExp("(?:^|\\s)" + name + "(?:$|\\s)", 'i') + }); + } + return _results; + })(); + AddClassBinding.__super__.constructor.apply(this, arguments); + delete this.attributeName; + } + + AddClassBinding.prototype.dataChange = function(value) { + var currentName, includesClassName, name, pattern, _i, _len, _ref, _ref1; + currentName = this.node.className; + _ref = this.classes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + _ref1 = _ref[_i], name = _ref1.name, pattern = _ref1.pattern; + includesClassName = pattern.test(currentName); + if (!!value === !this.invert) { + if (!includesClassName) { + this.node.className = "" + currentName + " " + name; + } + } else { + if (includesClassName) { + this.node.className = currentName.replace(pattern, ' '); + } + } + } + return true; + }; + + return AddClassBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AbstractCollectionBinding = (function(_super) { + + __extends(AbstractCollectionBinding, _super); + + function AbstractCollectionBinding() { + return AbstractCollectionBinding.__super__.constructor.apply(this, arguments); + } + + AbstractCollectionBinding.prototype.bindCollection = function(newCollection) { + var _ref; + if (newCollection instanceof Batman.Hash) { + newCollection = newCollection.meta; + } + if (newCollection === this.collection) { + return true; + } else { + this.unbindCollection(); + this.collection = newCollection; + if ((_ref = this.collection) != null ? _ref.isObservable : void 0) { + this.collection.observeAndFire('toArray', this.handleArrayChanged); + return true; + } + } + return false; + }; + + AbstractCollectionBinding.prototype.unbindCollection = function() { + var _ref; + if ((_ref = this.collection) != null ? _ref.isObservable : void 0) { + return this.collection.forget('toArray', this.handleArrayChanged); + } + }; + + AbstractCollectionBinding.prototype.handleArrayChanged = function() {}; + + AbstractCollectionBinding.prototype.die = function() { + this.unbindCollection(); + return AbstractCollectionBinding.__super__.die.apply(this, arguments); + }; + + return AbstractCollectionBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.DOM.StyleBinding = (function(_super) { + + __extends(StyleBinding, _super); + + StyleBinding.SingleStyleBinding = (function(_super1) { + + __extends(SingleStyleBinding, _super1); + + SingleStyleBinding.prototype.isTwoWay = function() { + return false; + }; + + function SingleStyleBinding() { + var args, parent, _i; + args = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), parent = arguments[_i++]; + this.parent = parent; + SingleStyleBinding.__super__.constructor.apply(this, args); + } + + SingleStyleBinding.prototype.dataChange = function(value) { + return this.parent.setStyle(this.attributeName, value); + }; + + return SingleStyleBinding; + + })(Batman.DOM.AbstractAttributeBinding); + + function StyleBinding() { + this.setStyle = __bind(this.setStyle, this); + + this.handleArrayChanged = __bind(this.handleArrayChanged, this); + this.oldStyles = {}; + this.styleBindings = {}; + StyleBinding.__super__.constructor.apply(this, arguments); + } + + StyleBinding.prototype.dataChange = function(value) { + var colonSplitCSSValues, cssName, key, style, _i, _len, _ref, _ref1, _results; + if (!value) { + this.resetStyles(); + return; + } + this.unbindCollection(); + if (typeof value === 'string') { + this.resetStyles(); + _ref = value.split(';'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + style = _ref[_i]; + _ref1 = style.split(":"), cssName = _ref1[0], colonSplitCSSValues = 2 <= _ref1.length ? __slice.call(_ref1, 1) : []; + this.setStyle(cssName, colonSplitCSSValues.join(":")); + } + return; + } + if (value instanceof Batman.Hash) { + return this.bindCollection(value); + } else { + if (value instanceof Batman.Object) { + value = value.toJSON(); + } + this.resetStyles(); + _results = []; + for (key in value) { + if (!__hasProp.call(value, key)) continue; + _results.push(this.bindSingleAttribute(key, "" + this.keyPath + "." + key)); + } + return _results; + } + }; + + StyleBinding.prototype.handleArrayChanged = function(array) { + var _this = this; + return this.collection.forEach(function(key, value) { + return _this.bindSingleAttribute(key, "" + _this.keyPath + "." + key); + }); + }; + + StyleBinding.prototype.bindSingleAttribute = function(attr, keyPath) { + return this.styleBindings[attr] = new this.constructor.SingleStyleBinding(this.node, attr, keyPath, this.renderContext, this.renderer, this.only, this); + }; + + StyleBinding.prototype.setStyle = function(key, value) { + key = Batman.helpers.camelize(key.trim(), true); + if (this.oldStyles[key] == null) { + this.oldStyles[key] = this.node.style[key] || ""; + } + if (value != null ? value.trim : void 0) { + value = value.trim(); + } + if (value == null) { + value = ""; + } + return this.node.style[key] = value; + }; + + StyleBinding.prototype.resetStyles = function() { + var cssName, cssValue, _ref, _results; + _ref = this.oldStyles; + _results = []; + for (cssName in _ref) { + if (!__hasProp.call(_ref, cssName)) continue; + cssValue = _ref[cssName]; + _results.push(this.setStyle(cssName, cssValue)); + } + return _results; + }; + + StyleBinding.prototype.resetBindings = function() { + var attribute, binding, _ref; + _ref = this.styleBindings; + for (attribute in _ref) { + binding = _ref[attribute]; + binding._fireDataChange(''); + binding.die(); + } + return this.styleBindings = {}; + }; + + StyleBinding.prototype.unbindCollection = function() { + this.resetBindings(); + return StyleBinding.__super__.unbindCollection.apply(this, arguments); + }; + + return StyleBinding; + + })(Batman.DOM.AbstractCollectionBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.IteratorBinding = (function(_super) { + + __extends(IteratorBinding, _super); + + IteratorBinding.prototype.currentActionNumber = 0; + + IteratorBinding.prototype.queuedActionNumber = 0; + + IteratorBinding.prototype.bindImmediately = false; + + function IteratorBinding(sourceNode, iteratorName, key, context, parentRenderer) { + var previousSiblingNode, + _this = this; + this.iteratorName = iteratorName; + this.key = key; + this.context = context; + this.parentRenderer = parentRenderer; + this.handleArrayChanged = __bind(this.handleArrayChanged, this); + + this.nodeMap = new Batman.SimpleHash; + this.rendererMap = new Batman.SimpleHash; + this.fragment = document.createDocumentFragment(); + this.prototypeNode = sourceNode.cloneNode(true); + this.prototypeNode.removeAttribute("data-foreach-" + this.iteratorName); + previousSiblingNode = sourceNode.nextSibling; + this.startNode = document.createComment("start " + this.iteratorName + "-" + (this.get('_batmanID'))); + this.endNode = document.createComment("end " + this.iteratorName + "-" + (this.get('_batmanID'))); + this.endNode[Batman.expando] = sourceNode[Batman.expando]; + if (Batman.canDeleteExpando) { + delete sourceNode[Batman.expando]; + } + Batman.insertBefore(sourceNode.parentNode, this.startNode, previousSiblingNode); + Batman.insertBefore(sourceNode.parentNode, this.endNode, previousSiblingNode); + this.parentRenderer.prevent('rendered'); + Batman.DOM.onParseExit(sourceNode.parentNode, function() { + Batman.destroyNode(sourceNode); + _this.bind(); + return _this.parentRenderer.allowAndFire('rendered'); + }); + IteratorBinding.__super__.constructor.call(this, this.endNode, this.iteratorName, this.key, this.context, this.parentRenderer); + } + + IteratorBinding.prototype.parentNode = function() { + return this.endNode.parentNode; + }; + + IteratorBinding.prototype.die = function() { + this.dead = true; + return IteratorBinding.__super__.die.apply(this, arguments); + }; + + IteratorBinding.prototype.dataChange = function(collection) { + var items, _items; + if (collection != null) { + if (!this.bindCollection(collection)) { + items = (collection != null ? collection.forEach : void 0) ? (_items = [], collection.forEach(function(item) { + return _items.push(item); + }), _items) : Object.keys(collection); + return this.handleArrayChanged(items); + } + } else { + return this.handleArrayChanged([]); + } + }; + + IteratorBinding.prototype.handleArrayChanged = function(newItems) { + var existingNode, index, newItem, node, nodeAtIndex, parentNode, startIndex, unseenNodeMap, _i, _len, + _this = this; + parentNode = this.parentNode(); + startIndex = this._getStartNodeIndex() + 1; + unseenNodeMap = this.nodeMap.merge(); + for (index = _i = 0, _len = newItems.length; _i < _len; index = ++_i) { + newItem = newItems[index]; + nodeAtIndex = parentNode.childNodes[startIndex + index]; + if ((nodeAtIndex != null) && this._itemForNode(nodeAtIndex) === newItem) { + unseenNodeMap.unset(newItem); + continue; + } else { + node = (existingNode = this.nodeMap.get(newItem)) ? (unseenNodeMap.unset(newItem), existingNode) : this._newNodeForItem(newItem); + Batman.insertBefore(this.parentNode(), node, nodeAtIndex); + } + } + unseenNodeMap.forEach(function(item, node) { + return _this._removeItem(item); + }); + }; + + IteratorBinding.prototype._itemForNode = function(node) { + return Batman._data(node, "" + this.iteratorName + "Item"); + }; + + IteratorBinding.prototype._newNodeForItem = function(newItem) { + var newNode, renderer, + _this = this; + newNode = this.prototypeNode.cloneNode(true); + Batman._data(newNode, "" + this.iteratorName + "Item", newItem); + this.nodeMap.set(newItem, newNode); + this.parentRenderer.prevent('rendered'); + renderer = new Batman.Renderer(newNode, this.renderContext.descend(newItem, this.iteratorName), this.parentRenderer.view); + renderer.on('rendered', function() { + Batman.propagateBindingEvents(newNode); + _this.fire('nodeAdded', newNode, newItem); + return _this.parentRenderer.allowAndFire('rendered'); + }); + return newNode; + }; + + IteratorBinding.prototype._getStartNodeIndex = function() { + var index, node, _i, _len, _ref; + _ref = this.parentNode().childNodes; + for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { + node = _ref[index]; + if (node === this.startNode) { + return index; + } + } + return 0; + }; + + IteratorBinding.prototype._removeItem = function(item) { + var node; + node = this.nodeMap.unset(item); + Batman.destroyNode(node); + return this.fire('nodeRemoved', node, item); + }; + + return IteratorBinding; + + })(Batman.DOM.AbstractCollectionBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ClassBinding = (function(_super) { + + __extends(ClassBinding, _super); + + function ClassBinding() { + this.handleArrayChanged = __bind(this.handleArrayChanged, this); + return ClassBinding.__super__.constructor.apply(this, arguments); + } + + ClassBinding.prototype.dataChange = function(value) { + if (value != null) { + this.unbindCollection(); + if (typeof value === 'string') { + return this.node.className = value; + } else { + this.bindCollection(value); + return this.updateFromCollection(); + } + } + }; + + ClassBinding.prototype.updateFromCollection = function() { + var array, k, v; + if (this.collection) { + array = this.collection.map ? this.collection.map(function(x) { + return x; + }) : (function() { + var _ref, _results; + _ref = this.collection; + _results = []; + for (k in _ref) { + if (!__hasProp.call(_ref, k)) continue; + v = _ref[k]; + _results.push(k); + } + return _results; + }).call(this); + if (array.toArray != null) { + array = array.toArray(); + } + return this.node.className = array.join(' '); + } + }; + + ClassBinding.prototype.handleArrayChanged = function() { + return this.updateFromCollection(); + }; + + return ClassBinding; + + })(Batman.DOM.AbstractCollectionBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ValidationError = (function(_super) { + + __extends(ValidationError, _super); + + ValidationError.accessor('fullMessage', function() { + return Batman.t('errors.format', { + attribute: Batman.helpers.humanize(this.attribute), + message: this.message + }); + }); + + function ValidationError(attribute, message) { + ValidationError.__super__.constructor.call(this, { + attribute: attribute, + message: message + }); + } + + return ValidationError; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.StorageAdapter = (function(_super) { + + __extends(StorageAdapter, _super); + + StorageAdapter.StorageError = (function(_super1) { + + __extends(StorageError, _super1); + + StorageError.prototype.name = "StorageError"; + + function StorageError(message) { + StorageError.__super__.constructor.apply(this, arguments); + this.message = message; + } + + return StorageError; + + })(Error); + + StorageAdapter.RecordExistsError = (function(_super1) { + + __extends(RecordExistsError, _super1); + + RecordExistsError.prototype.name = 'RecordExistsError'; + + function RecordExistsError(message) { + RecordExistsError.__super__.constructor.call(this, message || "Can't create this record because it already exists in the store!"); + } + + return RecordExistsError; + + })(StorageAdapter.StorageError); + + StorageAdapter.NotFoundError = (function(_super1) { + + __extends(NotFoundError, _super1); + + NotFoundError.prototype.name = 'NotFoundError'; + + function NotFoundError(message) { + NotFoundError.__super__.constructor.call(this, message || "Record couldn't be found in storage!"); + } + + return NotFoundError; + + })(StorageAdapter.StorageError); + + function StorageAdapter(model) { + var constructor; + StorageAdapter.__super__.constructor.call(this, { + model: model + }); + constructor = this.constructor; + if (constructor.ModelMixin) { + Batman.extend(model, constructor.ModelMixin); + } + if (constructor.RecordMixin) { + Batman.extend(model.prototype, constructor.RecordMixin); + } + } + + StorageAdapter.prototype.isStorageAdapter = true; + + StorageAdapter.prototype.storageKey = function(record) { + var model; + model = (record != null ? record.constructor : void 0) || this.model; + return model.get('storageKey') || Batman.helpers.pluralize(Batman.helpers.underscore(model.get('resourceName'))); + }; + + StorageAdapter.prototype.getRecordFromData = function(attributes, constructor) { + var record; + if (constructor == null) { + constructor = this.model; + } + record = new constructor(); + record._withoutDirtyTracking(function() { + return this.fromJSON(attributes); + }); + return record; + }; + + StorageAdapter.skipIfError = function(f) { + return function(env, next) { + if (env.error != null) { + return next(); + } else { + return f.call(this, env, next); + } + }; + }; + + StorageAdapter.prototype.before = function() { + return this._addFilter.apply(this, ['before'].concat(__slice.call(arguments))); + }; + + StorageAdapter.prototype.after = function() { + return this._addFilter.apply(this, ['after'].concat(__slice.call(arguments))); + }; + + StorageAdapter.prototype._inheritFilters = function() { + var filtersByKey, filtersList, key, oldFilters, position, _results; + if (!this._batman.check(this) || !this._batman.filters) { + oldFilters = this._batman.getFirst('filters'); + this._batman.filters = { + before: {}, + after: {} + }; + if (oldFilters != null) { + _results = []; + for (position in oldFilters) { + filtersByKey = oldFilters[position]; + _results.push((function() { + var _results1; + _results1 = []; + for (key in filtersByKey) { + filtersList = filtersByKey[key]; + _results1.push(this._batman.filters[position][key] = filtersList.slice(0)); + } + return _results1; + }).call(this)); + } + return _results; + } + } + }; + + StorageAdapter.prototype._addFilter = function() { + var filter, key, keys, position, _base, _i, _j, _len; + position = arguments[0], keys = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), filter = arguments[_i++]; + this._inheritFilters(); + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + (_base = this._batman.filters[position])[key] || (_base[key] = []); + this._batman.filters[position][key].push(filter); + } + return true; + }; + + StorageAdapter.prototype.runFilter = function(position, action, env, callback) { + var actionFilters, allFilters, filters, next, + _this = this; + this._inheritFilters(); + allFilters = this._batman.filters[position].all || []; + actionFilters = this._batman.filters[position][action] || []; + env.action = action; + filters = position === 'before' ? actionFilters.concat(allFilters) : allFilters.concat(actionFilters); + next = function(newEnv) { + var nextFilter; + if (newEnv != null) { + env = newEnv; + } + if ((nextFilter = filters.shift()) != null) { + return nextFilter.call(_this, env, next); + } else { + return callback.call(_this, env); + } + }; + return next(); + }; + + StorageAdapter.prototype.runBeforeFilter = function() { + return this.runFilter.apply(this, ['before'].concat(__slice.call(arguments))); + }; + + StorageAdapter.prototype.runAfterFilter = function(action, env, callback) { + return this.runFilter('after', action, env, this.exportResult(callback)); + }; + + StorageAdapter.prototype.exportResult = function(callback) { + return function(env) { + return callback(env.error, env.result, env); + }; + }; + + StorageAdapter.prototype._jsonToAttributes = function(json) { + return JSON.parse(json); + }; + + StorageAdapter.prototype.perform = function(key, subject, options, callback) { + var env, next, + _this = this; + options || (options = {}); + env = { + options: options, + subject: subject + }; + next = function(newEnv) { + if (newEnv != null) { + env = newEnv; + } + return _this.runAfterFilter(key, env, callback); + }; + return this.runBeforeFilter(key, env, function(env) { + return this[key](env, next); + }); + }; + + return StorageAdapter; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.RestStorage = (function(_super) { + var key, _fn, _i, _len, _ref, + _this = this; + + __extends(RestStorage, _super); + + RestStorage.JSONContentType = 'application/json'; + + RestStorage.PostBodyContentType = 'application/x-www-form-urlencoded'; + + RestStorage.BaseMixin = { + request: function(action, options, callback) { + if (!callback) { + callback = options; + options = {}; + } + options.method || (options.method = 'GET'); + options.action = action; + return this._doStorageOperation(options.method.toLowerCase(), options, callback); + } + }; + + RestStorage.ModelMixin = Batman.extend({}, RestStorage.BaseMixin, { + urlNestsUnder: function() { + var key, keys, parents, _i, _len; + keys = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + parents = {}; + for (_i = 0, _len = keys.length; _i < _len; _i++) { + key = keys[_i]; + parents[key + '_id'] = Batman.helpers.pluralize(key); + } + this.url = function(options) { + var childSegment, parentID, plural; + childSegment = Batman.helpers.pluralize(this.get('resourceName').toLowerCase()); + for (key in parents) { + plural = parents[key]; + parentID = options.data[key]; + if (parentID) { + delete options.data[key]; + return "" + plural + "/" + parentID + "/" + childSegment; + } + } + return childSegment; + }; + return this.prototype.url = function() { + var childSegment, id, parentID, plural, url; + childSegment = Batman.helpers.pluralize(this.constructor.get('resourceName').toLowerCase()); + for (key in parents) { + plural = parents[key]; + parentID = this.get('dirtyKeys').get(key); + if (parentID === void 0) { + parentID = this.get(key); + } + if (parentID) { + url = "" + plural + "/" + parentID + "/" + childSegment; + break; + } + } + url || (url = childSegment); + if (id = this.get('id')) { + url += '/' + id; + } + return url; + }; + } + }); + + RestStorage.RecordMixin = Batman.extend({}, RestStorage.BaseMixin); + + RestStorage.prototype.defaultRequestOptions = { + type: 'json' + }; + + RestStorage.prototype._implicitActionNames = ['create', 'read', 'update', 'destroy', 'readAll']; + + RestStorage.prototype.serializeAsForm = true; + + function RestStorage() { + RestStorage.__super__.constructor.apply(this, arguments); + this.defaultRequestOptions = Batman.extend({}, this.defaultRequestOptions); + } + + RestStorage.prototype.recordJsonNamespace = function(record) { + return Batman.helpers.singularize(this.storageKey(record)); + }; + + RestStorage.prototype.collectionJsonNamespace = function(constructor) { + return Batman.helpers.pluralize(this.storageKey(constructor.prototype)); + }; + + RestStorage.prototype._execWithOptions = function(object, key, options) { + if (typeof object[key] === 'function') { + return object[key](options); + } else { + return object[key]; + } + }; + + RestStorage.prototype._defaultCollectionUrl = function(model) { + return "/" + (this.storageKey(model.prototype)); + }; + + RestStorage.prototype._addParams = function(url, options) { + var _ref; + if (options && options.action && !(_ref = options.action, __indexOf.call(this._implicitActionNames, _ref) >= 0)) { + url += '/' + options.action.toLowerCase(); + } + return url; + }; + + RestStorage.prototype.urlForRecord = function(record, env) { + var id, url; + if (record.url) { + url = this._execWithOptions(record, 'url', env.options); + } else { + url = record.constructor.url ? this._execWithOptions(record.constructor, 'url', env.options) : this._defaultCollectionUrl(record.constructor); + if (env.action !== 'create') { + if ((id = record.get('id')) != null) { + url = url + "/" + id; + } else { + throw new this.constructor.StorageError("Couldn't get/set record primary key on " + env.action + "!"); + } + } + } + url = this._addParams(url, env.options); + return this.urlPrefix(record, env) + url + this.urlSuffix(record, env); + }; + + RestStorage.prototype.urlForCollection = function(model, env) { + var url; + url = model.url ? this._execWithOptions(model, 'url', env.options) : this._defaultCollectionUrl(model, env.options); + url = this._addParams(url, env.options); + return this.urlPrefix(model, env) + url + this.urlSuffix(model, env); + }; + + RestStorage.prototype.urlPrefix = function(object, env) { + return this._execWithOptions(object, 'urlPrefix', env.options) || ''; + }; + + RestStorage.prototype.urlSuffix = function(object, env) { + return this._execWithOptions(object, 'urlSuffix', env.options) || ''; + }; + + RestStorage.prototype.request = function(env, next) { + var options; + options = Batman.extend(env.options, { + autosend: false, + success: function(data) { + return env.data = data; + }, + error: function(error) { + return env.error = error; + }, + loaded: function() { + env.response = env.request.get('response'); + return next(); + } + }); + env.request = new Batman.Request(options); + return env.request.send(); + }; + + RestStorage.prototype.perform = function(key, record, options, callback) { + options || (options = {}); + Batman.extend(options, this.defaultRequestOptions); + return RestStorage.__super__.perform.call(this, key, record, options, callback); + }; + + RestStorage.prototype.before('all', RestStorage.skipIfError(function(env, next) { + if (!env.options.url) { + try { + env.options.url = env.subject.prototype ? this.urlForCollection(env.subject, env) : this.urlForRecord(env.subject, env); + } catch (error) { + env.error = error; + } + } + return next(); + })); + + RestStorage.prototype.before('get', 'put', 'post', 'delete', RestStorage.skipIfError(function(env, next) { + env.options.method = env.action.toUpperCase(); + return next(); + })); + + RestStorage.prototype.before('create', 'update', RestStorage.skipIfError(function(env, next) { + var data, json, namespace; + json = env.subject.toJSON(); + if (namespace = this.recordJsonNamespace(env.subject)) { + data = {}; + data[namespace] = json; + } else { + data = json; + } + env.options.data = data; + return next(); + })); + + RestStorage.prototype.before('create', 'update', 'put', 'post', RestStorage.skipIfError(function(env, next) { + if (this.serializeAsForm) { + env.options.contentType = this.constructor.PostBodyContentType; + } else { + if (env.options.data != null) { + env.options.data = JSON.stringify(env.options.data); + env.options.contentType = this.constructor.JSONContentType; + } + } + return next(); + })); + + RestStorage.prototype.after('all', RestStorage.skipIfError(function(env, next) { + var json; + if (!(env.data != null)) { + return next(); + } + if (typeof env.data === 'string') { + if (env.data.length > 0) { + try { + json = this._jsonToAttributes(env.data); + } catch (error) { + env.error = error; + return next(); + } + } + } else if (typeof env.data === 'object') { + json = env.data; + } + if (json != null) { + env.json = json; + } + return next(); + })); + + RestStorage.prototype.extractFromNamespace = function(data, namespace) { + if (namespace && (data[namespace] != null)) { + return data[namespace]; + } else { + return data; + } + }; + + RestStorage.prototype.after('create', 'read', 'update', RestStorage.skipIfError(function(env, next) { + var json; + if (env.json != null) { + json = this.extractFromNamespace(env.json, this.recordJsonNamespace(env.subject)); + env.subject._withoutDirtyTracking(function() { + return this.fromJSON(json); + }); + } + env.result = env.subject; + return next(); + })); + + RestStorage.prototype.after('readAll', RestStorage.skipIfError(function(env, next) { + var jsonRecordAttributes, namespace; + namespace = this.collectionJsonNamespace(env.subject); + env.recordsAttributes = this.extractFromNamespace(env.json, namespace); + if (Batman.typeOf(env.recordsAttributes) !== 'Array') { + namespace = this.recordJsonNamespace(env.subject.prototype); + env.recordsAttributes = [this.extractFromNamespace(env.json, namespace)]; + } + env.result = env.records = (function() { + var _i, _len, _ref, _results; + _ref = env.recordsAttributes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + jsonRecordAttributes = _ref[_i]; + _results.push(this.getRecordFromData(jsonRecordAttributes, env.subject)); + } + return _results; + }).call(this); + return next(); + })); + + RestStorage.prototype.after('get', 'put', 'post', 'delete', RestStorage.skipIfError(function(env, next) { + var json, namespace; + if (env.json != null) { + json = env.json; + namespace = env.subject.prototype ? this.collectionJsonNamespace(env.subject) : this.recordJsonNamespace(env.subject); + env.result = namespace && (env.json[namespace] != null) ? env.json[namespace] : env.json; + } + return next(); + })); + + RestStorage.HTTPMethods = { + create: 'POST', + update: 'PUT', + read: 'GET', + readAll: 'GET', + destroy: 'DELETE' + }; + + _ref = ['create', 'read', 'update', 'destroy', 'readAll', 'get', 'post', 'put', 'delete']; + _fn = function(key) { + return RestStorage.prototype[key] = RestStorage.skipIfError(function(env, next) { + var _base; + (_base = env.options).method || (_base.method = this.constructor.HTTPMethods[key]); + return this.request(env, next); + }); + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _fn(key); + } + + return RestStorage; + + }).call(this, Batman.StorageAdapter); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.LocalStorage = (function(_super) { + + __extends(LocalStorage, _super); + + function LocalStorage() { + if (typeof window.localStorage === 'undefined') { + return null; + } + LocalStorage.__super__.constructor.apply(this, arguments); + this.storage = localStorage; + } + + LocalStorage.prototype.storageRegExpForRecord = function(record) { + return new RegExp("^" + (this.storageKey(record)) + "(\\d+)$"); + }; + + LocalStorage.prototype.nextIdForRecord = function(record) { + var nextId, re; + re = this.storageRegExpForRecord(record); + nextId = 1; + this._forAllStorageEntries(function(k, v) { + var matches; + if (matches = re.exec(k)) { + return nextId = Math.max(nextId, parseInt(matches[1], 10) + 1); + } + }); + return nextId; + }; + + LocalStorage.prototype._forAllStorageEntries = function(iterator) { + var i, key, _i, _ref; + for (i = _i = 0, _ref = this.storage.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { + key = this.storage.key(i); + iterator.call(this, key, this.storage.getItem(key)); + } + return true; + }; + + LocalStorage.prototype._storageEntriesMatching = function(constructor, options) { + var re, records; + re = this.storageRegExpForRecord(constructor.prototype); + records = []; + this._forAllStorageEntries(function(storageKey, storageString) { + var data, keyMatches; + if (keyMatches = re.exec(storageKey)) { + data = this._jsonToAttributes(storageString); + data[constructor.primaryKey] = keyMatches[1]; + if (this._dataMatches(options, data)) { + return records.push(data); + } + } + }); + return records; + }; + + LocalStorage.prototype._dataMatches = function(conditions, data) { + var k, match, v; + match = true; + for (k in conditions) { + v = conditions[k]; + if (data[k] !== v) { + match = false; + break; + } + } + return match; + }; + + LocalStorage.prototype.before('read', 'create', 'update', 'destroy', LocalStorage.skipIfError(function(env, next) { + var _this = this; + if (env.action === 'create') { + env.id = env.subject.get('id') || env.subject._withoutDirtyTracking(function() { + return env.subject.set('id', _this.nextIdForRecord(env.subject)); + }); + } else { + env.id = env.subject.get('id'); + } + if (env.id == null) { + env.error = new this.constructor.StorageError("Couldn't get/set record primary key on " + env.action + "!"); + } else { + env.key = this.storageKey(env.subject) + env.id; + } + return next(); + })); + + LocalStorage.prototype.before('create', 'update', LocalStorage.skipIfError(function(env, next) { + env.recordAttributes = JSON.stringify(env.subject); + return next(); + })); + + LocalStorage.prototype.after('read', LocalStorage.skipIfError(function(env, next) { + if (typeof env.recordAttributes === 'string') { + try { + env.recordAttributes = this._jsonToAttributes(env.recordAttributes); + } catch (error) { + env.error = error; + return next(); + } + } + env.subject._withoutDirtyTracking(function() { + return this.fromJSON(env.recordAttributes); + }); + return next(); + })); + + LocalStorage.prototype.after('read', 'create', 'update', 'destroy', LocalStorage.skipIfError(function(env, next) { + env.result = env.subject; + return next(); + })); + + LocalStorage.prototype.after('readAll', LocalStorage.skipIfError(function(env, next) { + var recordAttributes; + env.result = env.records = (function() { + var _i, _len, _ref, _results; + _ref = env.recordsAttributes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + recordAttributes = _ref[_i]; + _results.push(this.getRecordFromData(recordAttributes, env.subject)); + } + return _results; + }).call(this); + return next(); + })); + + LocalStorage.prototype.read = LocalStorage.skipIfError(function(env, next) { + env.recordAttributes = this.storage.getItem(env.key); + if (!env.recordAttributes) { + env.error = new this.constructor.NotFoundError(); + } + return next(); + }); + + LocalStorage.prototype.create = LocalStorage.skipIfError(function(_arg, next) { + var key, recordAttributes; + key = _arg.key, recordAttributes = _arg.recordAttributes; + if (this.storage.getItem(key)) { + arguments[0].error = new this.constructor.RecordExistsError; + } else { + this.storage.setItem(key, recordAttributes); + } + return next(); + }); + + LocalStorage.prototype.update = LocalStorage.skipIfError(function(_arg, next) { + var key, recordAttributes; + key = _arg.key, recordAttributes = _arg.recordAttributes; + this.storage.setItem(key, recordAttributes); + return next(); + }); + + LocalStorage.prototype.destroy = LocalStorage.skipIfError(function(_arg, next) { + var key; + key = _arg.key; + this.storage.removeItem(key); + return next(); + }); + + LocalStorage.prototype.readAll = LocalStorage.skipIfError(function(env, next) { + try { + arguments[0].recordsAttributes = this._storageEntriesMatching(env.subject, env.options.data); + } catch (error) { + arguments[0].error = error; + } + return next(); + }); + + return LocalStorage; + + })(Batman.StorageAdapter); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.SessionStorage = (function(_super) { + + __extends(SessionStorage, _super); + + function SessionStorage() { + if (typeof window.sessionStorage === 'undefined') { + return null; + } + SessionStorage.__super__.constructor.apply(this, arguments); + this.storage = sessionStorage; + } + + return SessionStorage; + + })(Batman.LocalStorage); + +}).call(this); + +(function() { + + Batman.Encoders = new Batman.Object; + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.AssociationProxy = (function(_super) { + + __extends(AssociationProxy, _super); + + AssociationProxy.prototype.isProxy = true; + + function AssociationProxy(association, model) { + this.association = association; + this.model = model; + } + + AssociationProxy.prototype.loaded = false; + + AssociationProxy.prototype.toJSON = function() { + var target; + target = this.get('target'); + if (target != null) { + return this.get('target').toJSON(); + } + }; + + AssociationProxy.prototype.load = function(callback) { + var _this = this; + this.fetch(function(err, proxiedRecord) { + if (!err) { + _this.set('loaded', true); + _this.set('target', proxiedRecord); + } + return typeof callback === "function" ? callback(err, proxiedRecord) : void 0; + }); + return this.get('target'); + }; + + AssociationProxy.prototype.fetch = function(callback) { + var record; + if ((this.get('foreignValue') || this.get('primaryValue')) == null) { + return callback(void 0, void 0); + } + record = this.fetchFromLocal(); + if (record) { + return callback(void 0, record); + } else { + return this.fetchFromRemote(callback); + } + }; + + AssociationProxy.accessor('loaded', Batman.Property.defaultAccessor); + + AssociationProxy.accessor('target', { + get: function() { + return this.fetchFromLocal(); + }, + set: function(_, v) { + return v; + } + }); + + AssociationProxy.accessor({ + get: function(k) { + var _ref; + return (_ref = this.get('target')) != null ? _ref.get(k) : void 0; + }, + set: function(k, v) { + var _ref; + return (_ref = this.get('target')) != null ? _ref.set(k, v) : void 0; + } + }); + + return AssociationProxy; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HasOneProxy = (function(_super) { + + __extends(HasOneProxy, _super); + + function HasOneProxy() { + return HasOneProxy.__super__.constructor.apply(this, arguments); + } + + HasOneProxy.accessor('primaryValue', function() { + return this.model.get(this.association.primaryKey); + }); + + HasOneProxy.prototype.fetchFromLocal = function() { + return this.association.setIndex().get(this.get('primaryValue')); + }; + + HasOneProxy.prototype.fetchFromRemote = function(callback) { + var loadOptions, + _this = this; + loadOptions = {}; + loadOptions[this.association.foreignKey] = this.get('primaryValue'); + return this.association.getRelatedModel().load(loadOptions, function(error, loadedRecords) { + if (error) { + throw error; + } + if (!loadedRecords || loadedRecords.length <= 0) { + return callback(new Error("Couldn't find related record!"), void 0); + } else { + return callback(void 0, loadedRecords[0]); + } + }); + }; + + return HasOneProxy; + + })(Batman.AssociationProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.BelongsToProxy = (function(_super) { + + __extends(BelongsToProxy, _super); + + function BelongsToProxy() { + return BelongsToProxy.__super__.constructor.apply(this, arguments); + } + + BelongsToProxy.accessor('foreignValue', function() { + return this.model.get(this.association.foreignKey); + }); + + BelongsToProxy.prototype.fetchFromLocal = function() { + return this.association.setIndex().get(this.get('foreignValue')); + }; + + BelongsToProxy.prototype.fetchFromRemote = function(callback) { + var _this = this; + return this.association.getRelatedModel().find(this.get('foreignValue'), function(error, loadedRecord) { + if (error) { + throw error; + } + return callback(void 0, loadedRecord); + }); + }; + + return BelongsToProxy; + + })(Batman.AssociationProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicBelongsToProxy = (function(_super) { + + __extends(PolymorphicBelongsToProxy, _super); + + function PolymorphicBelongsToProxy() { + return PolymorphicBelongsToProxy.__super__.constructor.apply(this, arguments); + } + + PolymorphicBelongsToProxy.accessor('foreignTypeValue', function() { + return this.model.get(this.association.foreignTypeKey); + }); + + PolymorphicBelongsToProxy.prototype.fetchFromLocal = function() { + return this.association.setIndexForType(this.get('foreignTypeValue')).get(this.get('foreignValue')); + }; + + PolymorphicBelongsToProxy.prototype.fetchFromRemote = function(callback) { + var _this = this; + return this.association.getRelatedModelForType(this.get('foreignTypeValue')).find(this.get('foreignValue'), function(error, loadedRecord) { + if (error) { + throw error; + } + return callback(void 0, loadedRecord); + }); + }; + + return PolymorphicBelongsToProxy; + + })(Batman.BelongsToProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.StateMachine = (function(_super) { + + __extends(StateMachine, _super); + + StateMachine.InvalidTransitionError = function(message) { + this.message = message != null ? message : ""; + }; + + StateMachine.InvalidTransitionError.prototype = new Error; + + StateMachine.transitions = function(table) { + var definePredicate, fromState, k, object, predicateKeys, toState, transitions, v, _fn, _ref, + _this = this; + for (k in table) { + v = table[k]; + if (!(v.from && v.to)) { + continue; + } + object = {}; + if (v.from.forEach) { + v.from.forEach(function(fromKey) { + return object[fromKey] = v.to; + }); + } else { + object[v.from] = v.to; + } + table[k] = object; + } + this.prototype.transitionTable = Batman.extend({}, this.prototype.transitionTable, table); + predicateKeys = []; + definePredicate = function(state) { + var key; + key = "is" + (Batman.helpers.capitalize(state)); + if (_this.prototype[key] != null) { + return; + } + predicateKeys.push(key); + return _this.prototype[key] = function() { + return this.get('state') === state; + }; + }; + _ref = this.prototype.transitionTable; + _fn = function(k) { + return _this.prototype[k] = function() { + return this.startTransition(k); + }; + }; + for (k in _ref) { + transitions = _ref[k]; + if (!(!this.prototype[k])) { + continue; + } + _fn(k); + for (fromState in transitions) { + toState = transitions[fromState]; + definePredicate(fromState); + definePredicate(toState); + } + } + if (predicateKeys.length) { + this.accessor.apply(this, __slice.call(predicateKeys).concat([function(key) { + return this[key](); + }])); + } + return this; + }; + + function StateMachine(startState) { + this.nextEvents = []; + this.set('_state', startState); + } + + StateMachine.accessor('state', function() { + return this.get('_state'); + }); + + StateMachine.prototype.isTransitioning = false; + + StateMachine.prototype.transitionTable = {}; + + StateMachine.prototype.onTransition = function(from, into, callback) { + return this.on("" + from + "->" + into, callback); + }; + + StateMachine.prototype.onEnter = function(into, callback) { + return this.on("enter " + into, callback); + }; + + StateMachine.prototype.onExit = function(from, callback) { + return this.on("exit " + from, callback); + }; + + StateMachine.prototype.startTransition = Batman.Property.wrapTrackingPrevention(function(event) { + var nextState, previousState; + if (this.isTransitioning) { + this.nextEvents.push(event); + return; + } + previousState = this.get('state'); + nextState = this.nextStateForEvent(event); + if (!nextState) { + return false; + } + this.isTransitioning = true; + this.fire("exit " + previousState); + this.set('_state', nextState); + this.fire("" + previousState + "->" + nextState); + this.fire("enter " + nextState); + this.fire(event); + this.isTransitioning = false; + if (this.nextEvents.length > 0) { + this.startTransition(this.nextEvents.shift()); + } + return true; + }); + + StateMachine.prototype.canStartTransition = function(event, fromState) { + if (fromState == null) { + fromState = this.get('state'); + } + return !!this.nextStateForEvent(event, fromState); + }; + + StateMachine.prototype.nextStateForEvent = function(event, fromState) { + var _ref; + if (fromState == null) { + fromState = this.get('state'); + } + return (_ref = this.transitionTable[event]) != null ? _ref[fromState] : void 0; + }; + + return StateMachine; + + })(Batman.Object); + + Batman.DelegatingStateMachine = (function(_super) { + + __extends(DelegatingStateMachine, _super); + + function DelegatingStateMachine(startState, base) { + this.base = base; + DelegatingStateMachine.__super__.constructor.call(this, startState); + } + + DelegatingStateMachine.prototype.fire = function() { + var result, _ref; + result = DelegatingStateMachine.__super__.fire.apply(this, arguments); + (_ref = this.base).fire.apply(_ref, arguments); + return result; + }; + + return DelegatingStateMachine; + + })(Batman.StateMachine); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.Model = (function(_super) { + var functionName, _i, _j, _len, _len1, _ref, _ref1; + + __extends(Model, _super); + + Model.primaryKey = 'id'; + + Model.storageKey = null; + + Model.persist = function(mechanism, options) { + Batman.initializeObject(this.prototype); + mechanism = mechanism.isStorageAdapter ? mechanism : new mechanism(this); + if (options) { + Batman.mixin(mechanism, options); + } + this.prototype._batman.storage = mechanism; + return mechanism; + }; + + Model.storageAdapter = function() { + Batman.initializeObject(this.prototype); + return this.prototype._batman.storage; + }; + + Model.encode = function() { + var encoder, encoderOrLastKey, hash, key, keys, operation, _base, _base1, _i, _j, _k, _len, _len1, _ref; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), encoderOrLastKey = arguments[_i++]; + Batman.initializeObject(this.prototype); + (_base = this.prototype._batman).encoders || (_base.encoders = new Batman.SimpleHash); + (_base1 = this.prototype._batman).decoders || (_base1.decoders = new Batman.SimpleHash); + encoder = {}; + switch (Batman.typeOf(encoderOrLastKey)) { + case 'String': + keys.push(encoderOrLastKey); + break; + case 'Function': + encoder.encode = encoderOrLastKey; + break; + default: + if (encoderOrLastKey.encode != null) { + encoder.encode = encoderOrLastKey.encode; + } + if (encoderOrLastKey.decode != null) { + encoder.decode = encoderOrLastKey.decode; + } + } + encoder = Batman.extend({}, this.defaultEncoder, encoder); + _ref = ['encode', 'decode']; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + operation = _ref[_j]; + for (_k = 0, _len1 = keys.length; _k < _len1; _k++) { + key = keys[_k]; + hash = this.prototype._batman["" + operation + "rs"]; + if (encoder[operation]) { + hash.set(key, encoder[operation]); + } else { + hash.unset(key); + } + } + } + }; + + Model.defaultEncoder = { + encode: function(x) { + return x; + }, + decode: function(x) { + return x; + } + }; + + Model.observeAndFire('primaryKey', function(newPrimaryKey, oldPrimaryKey) { + this.encode(oldPrimaryKey, { + encode: false, + decode: false + }); + return this.encode(newPrimaryKey, { + encode: false, + decode: this.defaultEncoder.decode + }); + }); + + Model.validate = function() { + var keys, match, matches, options, optionsOrFunction, validator, validators, _base, _i, _j, _k, _len, _len1, _ref, _results; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), optionsOrFunction = arguments[_i++]; + Batman.initializeObject(this.prototype); + validators = (_base = this.prototype._batman).validators || (_base.validators = []); + if (typeof optionsOrFunction === 'function') { + return validators.push({ + keys: keys, + callback: optionsOrFunction + }); + } else { + options = optionsOrFunction; + _ref = Batman.Validators; + _results = []; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + validator = _ref[_j]; + if ((matches = validator.matches(options))) { + for (_k = 0, _len1 = matches.length; _k < _len1; _k++) { + match = matches[_k]; + delete options[match]; + } + _results.push(validators.push({ + keys: keys, + validator: new validator(matches) + })); + } else { + _results.push(void 0); + } + } + return _results; + } + }; + + Model.LifecycleStateMachine = (function(_super1) { + + __extends(LifecycleStateMachine, _super1); + + function LifecycleStateMachine() { + return LifecycleStateMachine.__super__.constructor.apply(this, arguments); + } + + LifecycleStateMachine.transitions({ + load: { + empty: 'loading', + loaded: 'loading', + loading: 'loading' + }, + loaded: { + loading: 'loaded' + }, + error: { + loading: 'error' + } + }); + + return LifecycleStateMachine; + + })(Batman.DelegatingStateMachine); + + Model.classAccessor('lifecycle', function() { + var _base; + this._batman.check(this); + return (_base = this._batman).lifecycle || (_base.lifecycle = new this.LifecycleStateMachine('empty', this)); + }); + + Model.classAccessor('resourceName', { + get: function() { + if (this.resourceName != null) { + return this.resourceName; + } else { + if (Batman.config.minificationErrors) { + Batman.developer.error("Please define " + (Batman.functionName(this)) + ".resourceName in order for your model to be minification safe."); + } + return Batman.helpers.underscore(Batman.functionName(this)); + } + } + }); + + Model.classAccessor('all', { + get: function() { + this._batman.check(this); + if (this.prototype.hasStorage() && !this._batman.allLoadTriggered) { + this.load(); + this._batman.allLoadTriggered = true; + } + return this.get('loaded'); + }, + set: function(k, v) { + return this.set('loaded', v); + } + }); + + Model.classAccessor('loaded', { + get: function() { + return this._loaded || (this._loaded = new Batman.Set); + }, + set: function(k, v) { + return this._loaded = v; + } + }); + + Model.classAccessor('first', function() { + return this.get('all').toArray()[0]; + }); + + Model.classAccessor('last', function() { + var x; + x = this.get('all').toArray(); + return x[x.length - 1]; + }); + + Model.clear = function() { + var result, _ref; + Batman.initializeObject(this); + result = this.get('loaded').clear(); + if ((_ref = this._batman.get('associations')) != null) { + _ref.reset(); + } + return result; + }; + + Model.find = function(id, callback) { + var record; + Batman.developer.assert(callback, "Must call find with a callback!"); + record = new this(); + record._withoutDirtyTracking(function() { + return this.set('id', id); + }); + record.load(callback); + return record; + }; + + Model.load = function(options, callback) { + var lifecycle, _ref, + _this = this; + if ((_ref = typeof options) === 'function' || _ref === 'undefined') { + callback = options; + options = {}; + } + lifecycle = this.get('lifecycle'); + if (lifecycle.load()) { + return this._doStorageOperation('readAll', { + data: options + }, function(err, records, env) { + var mappedRecords, record; + if (err != null) { + lifecycle.error(); + return typeof callback === "function" ? callback(err, []) : void 0; + } else { + mappedRecords = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = records.length; _i < _len; _i++) { + record = records[_i]; + _results.push(this._mapIdentity(record)); + } + return _results; + }).call(_this); + lifecycle.loaded(); + return typeof callback === "function" ? callback(err, mappedRecords, env) : void 0; + } + }); + } else { + return callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (lifecycle.get('state')))); + } + }; + + Model.create = function(attrs, callback) { + var obj, _ref; + if (!callback) { + _ref = [{}, attrs], attrs = _ref[0], callback = _ref[1]; + } + obj = new this(attrs); + obj.save(callback); + return obj; + }; + + Model.findOrCreate = function(attrs, callback) { + var foundRecord, record; + record = new this(attrs); + if (record.isNew()) { + record.save(callback); + } else { + foundRecord = this._mapIdentity(record); + callback(void 0, foundRecord); + } + return record; + }; + + Model._mapIdentity = function(record) { + var existing, id, _ref; + if (typeof (id = record.get('id')) === 'undefined' || id === '') { + return record; + } else { + existing = (_ref = this.get("loaded.indexedBy.id").get(id)) != null ? _ref.toArray()[0] : void 0; + if (existing) { + existing._withoutDirtyTracking(function() { + var _ref1; + return this.updateAttributes(((_ref1 = record.get('attributes')) != null ? _ref1.toObject() : void 0) || {}); + }); + return existing; + } else { + this.get('loaded').add(record); + return record; + } + } + }; + + Model._doStorageOperation = function(operation, options, callback) { + var adapter; + Batman.developer.assert(this.prototype.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); + adapter = this.prototype._batman.get('storage'); + return adapter.perform(operation, this, options, callback); + }; + + _ref = ['find', 'load', 'create']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + functionName = _ref[_i]; + Model[functionName] = Batman.Property.wrapTrackingPrevention(Model[functionName]); + } + + Model.InstanceLifecycleStateMachine = (function(_super1) { + + __extends(InstanceLifecycleStateMachine, _super1); + + function InstanceLifecycleStateMachine() { + return InstanceLifecycleStateMachine.__super__.constructor.apply(this, arguments); + } + + InstanceLifecycleStateMachine.transitions({ + load: { + from: ['dirty', 'clean'], + to: 'loading' + }, + create: { + from: ['dirty', 'clean'], + to: 'creating' + }, + save: { + from: ['dirty', 'clean'], + to: 'saving' + }, + destroy: { + from: ['dirty', 'clean'], + to: 'destroying' + }, + failedValidation: { + from: ['saving', 'creating'], + to: 'dirty' + }, + loaded: { + loading: 'clean' + }, + created: { + creating: 'clean' + }, + saved: { + saving: 'clean' + }, + destroyed: { + destroying: 'destroyed' + }, + set: { + from: ['dirty', 'clean'], + to: 'dirty' + }, + error: { + from: ['saving', 'creating', 'loading', 'destroying'], + to: 'error' + } + }); + + return InstanceLifecycleStateMachine; + + })(Batman.DelegatingStateMachine); + + function Model(idOrAttributes) { + if (idOrAttributes == null) { + idOrAttributes = {}; + } + this.destroy = __bind(this.destroy, this); + + this.save = __bind(this.save, this); + + this.load = __bind(this.load, this); + + Batman.developer.assert(this instanceof Batman.Object, "constructors must be called with new"); + if (Batman.typeOf(idOrAttributes) === 'Object') { + Model.__super__.constructor.call(this, idOrAttributes); + } else { + Model.__super__.constructor.call(this); + this.set('id', idOrAttributes); + } + } + + Model.accessor('lifecycle', function() { + return this.lifecycle || (this.lifecycle = new Batman.Model.InstanceLifecycleStateMachine('clean', this)); + }); + + Model.accessor('attributes', function() { + return this.attributes || (this.attributes = new Batman.Hash); + }); + + Model.accessor('dirtyKeys', function() { + return this.dirtyKeys || (this.dirtyKeys = new Batman.Hash); + }); + + Model.accessor('_dirtiedKeys', function() { + return this._dirtiedKeys || (this._dirtiedKeys = new Batman.SimpleSet); + }); + + Model.accessor('errors', function() { + return this.errors || (this.errors = new Batman.ErrorsSet); + }); + + Model.accessor('isNew', function() { + return this.isNew(); + }); + + Model.accessor(Model.defaultAccessor = { + get: function(k) { + return Batman.getPath(this, ['attributes', k]); + }, + set: function(k, v) { + if (this._willSet(k)) { + return this.get('attributes').set(k, v); + } else { + return this.get(k); + } + }, + unset: function(k) { + return this.get('attributes').unset(k); + } + }); + + Model.wrapAccessor('id', function(core) { + return { + get: function() { + var primaryKey; + primaryKey = this.constructor.primaryKey; + if (primaryKey === 'id') { + return core.get.apply(this, arguments); + } else { + return this.get(primaryKey); + } + }, + set: function(key, value) { + var parsedValue, primaryKey; + if ((typeof value === "string") && (value.match(/[^0-9]/) === null) && (("" + (parsedValue = parseInt(value, 10))) === value)) { + value = parsedValue; + } + primaryKey = this.constructor.primaryKey; + if (primaryKey === 'id') { + this._willSet(key); + return core.set.apply(this, arguments); + } else { + return this.set(primaryKey, value); + } + } + }; + }); + + Model.prototype.isNew = function() { + return typeof this.get('id') === 'undefined'; + }; + + Model.prototype.updateAttributes = function(attrs) { + this.mixin(attrs); + return this; + }; + + Model.prototype.toString = function() { + return "" + (this.constructor.get('resourceName')) + ": " + (this.get('id')); + }; + + Model.prototype.toParam = function() { + return this.get('id'); + }; + + Model.prototype.toJSON = function() { + var encoders, obj, + _this = this; + obj = {}; + encoders = this._batman.get('encoders'); + if (!(!encoders || encoders.isEmpty())) { + encoders.forEach(function(key, encoder) { + var encodedVal, val; + val = _this.get(key); + if (typeof val !== 'undefined') { + encodedVal = encoder(val, key, obj, _this); + if (typeof encodedVal !== 'undefined') { + return obj[key] = encodedVal; + } + } + }); + } + return obj; + }; + + Model.prototype.fromJSON = function(data) { + var decoders, key, obj, value, + _this = this; + obj = {}; + decoders = this._batman.get('decoders'); + if (!decoders || decoders.isEmpty()) { + for (key in data) { + value = data[key]; + obj[key] = value; + } + } else { + decoders.forEach(function(key, decoder) { + if (typeof data[key] !== 'undefined') { + return obj[key] = decoder(data[key], key, data, obj, _this); + } + }); + } + if (this.constructor.primaryKey !== 'id') { + obj.id = data[this.constructor.primaryKey]; + } + Batman.developer["do"](function() { + if ((!decoders) || decoders.length <= 1) { + return Batman.developer.warn("Warning: Model " + (Batman.functionName(_this.constructor)) + " has suspiciously few decoders!"); + } + }); + return this.mixin(obj); + }; + + Model.prototype.hasStorage = function() { + return this._batman.get('storage') != null; + }; + + Model.prototype.load = function(options, callback) { + var callbackQueue, hasOptions, _ref1, _ref2, + _this = this; + if (!callback) { + _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + } + hasOptions = Object.keys(options).length !== 0; + if ((_ref2 = this.get('lifecycle.state')) === 'destroying' || _ref2 === 'destroyed') { + if (typeof callback === "function") { + callback(new Error("Can't load a destroyed record!")); + } + return; + } + if (this.get('lifecycle').load()) { + callbackQueue = []; + if (callback != null) { + callbackQueue.push(callback); + } + if (!hasOptions) { + this._currentLoad = callbackQueue; + } + return this._doStorageOperation('read', { + data: options + }, function(err, record, env) { + var _j, _len1; + if (!err) { + _this.get('lifecycle').loaded(); + record = _this.constructor._mapIdentity(record); + } else { + _this.get('lifecycle').error(); + } + if (!hasOptions) { + _this._currentLoad = null; + } + for (_j = 0, _len1 = callbackQueue.length; _j < _len1; _j++) { + callback = callbackQueue[_j]; + callback(err, record, env); + } + }); + } else { + if (this.get('lifecycle.state') === 'loading' && !hasOptions) { + if (callback != null) { + return this._currentLoad.push(callback); + } + } else { + return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (this.get('lifecycle.state')))) : void 0; + } + } + }; + + Model.prototype.save = function(options, callback) { + var endState, isNew, startState, storageOperation, _ref1, _ref2, _ref3, + _this = this; + if (!callback) { + _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + } + if ((_ref2 = this.get('lifecycle').get('state')) === 'destroying' || _ref2 === 'destroyed') { + if (typeof callback === "function") { + callback(new Error("Can't save a destroyed record!")); + } + return; + } + isNew = this.isNew(); + _ref3 = isNew ? ['create', 'create', 'created'] : ['save', 'update', 'saved'], startState = _ref3[0], storageOperation = _ref3[1], endState = _ref3[2]; + return this.validate(function(error, errors) { + var associations, creating; + if (error || errors.length) { + _this.get('lifecycle').failedValidation(); + if (typeof callback === "function") { + callback(error || errors, _this); + } + return; + } + creating = _this.isNew(); + if (_this.get('lifecycle').startTransition(startState)) { + associations = _this.constructor._batman.get('associations'); + _this._withoutDirtyTracking(function() { + var _ref4, + _this = this; + return associations != null ? (_ref4 = associations.getByType('belongsTo')) != null ? _ref4.forEach(function(association, label) { + return association.apply(_this); + }) : void 0 : void 0; + }); + return _this._doStorageOperation(storageOperation, { + data: options + }, function(err, record, env) { + if (!err) { + _this.get('dirtyKeys').clear(); + _this.get('_dirtiedKeys').clear(); + if (associations) { + record._withoutDirtyTracking(function() { + var _ref4, _ref5; + if ((_ref4 = associations.getByType('hasOne')) != null) { + _ref4.forEach(function(association, label) { + return association.apply(err, record); + }); + } + return (_ref5 = associations.getByType('hasMany')) != null ? _ref5.forEach(function(association, label) { + return association.apply(err, record); + }) : void 0; + }); + } + record = _this.constructor._mapIdentity(record); + _this.get('lifecycle').startTransition(endState); + } else { + if (err instanceof Batman.ErrorsSet) { + _this.get('lifecycle').failedValidation(); + } else { + _this.get('lifecycle').error(); + } + } + return typeof callback === "function" ? callback(err, record || _this, env) : void 0; + }); + } else { + return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't save while in state " + (_this.get('lifecycle.state')))) : void 0; + } + }); + }; + + Model.prototype.destroy = function(options, callback) { + var _ref1, + _this = this; + if (!callback) { + _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + } + if (this.get('lifecycle').destroy()) { + return this._doStorageOperation('destroy', { + data: options + }, function(err, record, env) { + if (!err) { + _this.constructor.get('loaded').remove(_this); + _this.get('lifecycle').destroyed(); + } else { + _this.get('lifecycle').error(); + } + return typeof callback === "function" ? callback(err, record, env) : void 0; + }); + } else { + return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't destroy while in state " + (this.get('lifecycle.state')))) : void 0; + } + }; + + Model.prototype.validate = function(callback) { + var args, count, errors, finishedValidation, key, validator, validators, _j, _k, _len1, _len2, _ref1; + errors = this.get('errors'); + errors.clear(); + validators = this._batman.get('validators') || []; + if (!validators || validators.length === 0) { + if (typeof callback === "function") { + callback(void 0, errors); + } + return true; + } + count = validators.reduce((function(acc, validator) { + return acc + validator.keys.length; + }), 0); + finishedValidation = function() { + if (--count === 0) { + return typeof callback === "function" ? callback(void 0, errors) : void 0; + } + }; + for (_j = 0, _len1 = validators.length; _j < _len1; _j++) { + validator = validators[_j]; + _ref1 = validator.keys; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + key = _ref1[_k]; + args = [errors, this, key, finishedValidation]; + try { + if (validator.validator) { + validator.validator.validateEach.apply(validator.validator, args); + } else { + validator.callback.apply(validator, args); + } + } catch (e) { + if (typeof callback === "function") { + callback(e, errors); + } + } + } + } + }; + + Model.prototype.associationProxy = function(association) { + var proxies, _base, _name; + Batman.initializeObject(this); + proxies = (_base = this._batman).associationProxies || (_base.associationProxies = {}); + proxies[_name = association.label] || (proxies[_name] = new association.proxyClass(association, this)); + return proxies[association.label]; + }; + + Model.prototype._willSet = function(key) { + if (this._pauseDirtyTracking) { + return true; + } + if (this.get('lifecycle').startTransition('set')) { + if (!this.get('_dirtiedKeys').has(key)) { + this.set("dirtyKeys." + key, this.get(key)); + this.get('_dirtiedKeys').add(key); + } + return true; + } else { + return false; + } + }; + + Model.prototype._doStorageOperation = function(operation, options, callback) { + var adapter, + _this = this; + Batman.developer.assert(this.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); + adapter = this._batman.get('storage'); + return adapter.perform(operation, this, options, function() { + return callback.apply(null, arguments); + }); + }; + + Model.prototype._withoutDirtyTracking = function(block) { + var result; + this._pauseDirtyTracking = true; + result = block.call(this); + this._pauseDirtyTracking = false; + return result; + }; + + _ref1 = ['load', 'save', 'validate', 'destroy']; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + functionName = _ref1[_j]; + Model.prototype[functionName] = Batman.Property.wrapTrackingPrevention(Model.prototype[functionName]); + } + + return Model; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var k, _fn, _i, _len, _ref, + _this = this; + + _ref = Batman.AssociationCurator.availableAssociations; + _fn = function(k) { + return Batman.Model[k] = function(label, scope) { + var collection, _base; + Batman.initializeObject(this); + collection = (_base = this._batman).associations || (_base.associations = new Batman.AssociationCurator(this)); + return collection.add(new Batman["" + (Batman.helpers.capitalize(k)) + "Association"](this, label, scope)); + }; + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + _fn(k); + } + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ParamsReplacer = (function(_super) { + + __extends(ParamsReplacer, _super); + + function ParamsReplacer(navigator, params) { + this.navigator = navigator; + this.params = params; + } + + ParamsReplacer.prototype.redirect = function() { + return this.navigator.replace(this.toObject()); + }; + + ParamsReplacer.prototype.replace = function(params) { + this.params.replace(params); + return this.redirect(); + }; + + ParamsReplacer.prototype.update = function(params) { + this.params.update(params); + return this.redirect(); + }; + + ParamsReplacer.prototype.clear = function() { + this.params.clear(); + return this.redirect(); + }; + + ParamsReplacer.prototype.toObject = function() { + return this.params.toObject(); + }; + + ParamsReplacer.accessor({ + get: function(k) { + return this.params.get(k); + }, + set: function(k, v) { + var oldValue, result; + oldValue = this.params.get(k); + result = this.params.set(k, v); + if (oldValue !== v) { + this.redirect(); + } + return result; + }, + unset: function(k) { + var hadKey, result; + hadKey = this.params.hasKey(k); + result = this.params.unset(k); + if (hadKey) { + this.redirect(); + } + return result; + } + }); + + return ParamsReplacer; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ParamsPusher = (function(_super) { + + __extends(ParamsPusher, _super); + + function ParamsPusher() { + return ParamsPusher.__super__.constructor.apply(this, arguments); + } + + ParamsPusher.prototype.redirect = function() { + return this.navigator.push(this.toObject()); + }; + + return ParamsPusher; + + })(Batman.ParamsReplacer); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.NamedRouteQuery = (function(_super) { + + __extends(NamedRouteQuery, _super); + + NamedRouteQuery.prototype.isNamedRouteQuery = true; + + function NamedRouteQuery(routeMap, args) { + var key; + if (args == null) { + args = []; + } + NamedRouteQuery.__super__.constructor.call(this, { + routeMap: routeMap, + args: args + }); + for (key in this.get('routeMap').childrenByName) { + this[key] = this._queryAccess.bind(this, key); + } + } + + NamedRouteQuery.accessor('route', function() { + var collectionRoute, memberRoute, route, _i, _len, _ref, _ref1; + _ref = this.get('routeMap'), memberRoute = _ref.memberRoute, collectionRoute = _ref.collectionRoute; + _ref1 = [memberRoute, collectionRoute]; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + route = _ref1[_i]; + if (route != null) { + if (route.namedArguments.length === this.get('args').length) { + return route; + } + } + } + return collectionRoute || memberRoute; + }); + + NamedRouteQuery.accessor('path', function() { + return this.path(); + }); + + NamedRouteQuery.accessor('routeMap', 'args', 'cardinality', 'hashValue', Batman.Property.defaultAccessor); + + NamedRouteQuery.accessor({ + get: function(key) { + if (key == null) { + return; + } + if (typeof key === 'string') { + return this.nextQueryForName(key); + } else { + return this.nextQueryWithArgument(key); + } + }, + cache: false + }); + + NamedRouteQuery.accessor('withHash', function() { + var _this = this; + return new Batman.Accessible(function(hashValue) { + return _this.withHash(hashValue); + }); + }); + + NamedRouteQuery.prototype.withHash = function(hashValue) { + var clone; + clone = this.clone(); + clone.set('hashValue', hashValue); + return clone; + }; + + NamedRouteQuery.prototype.nextQueryForName = function(key) { + var map; + if (map = this.get('routeMap').childrenByName[key]) { + return new Batman.NamedRouteQuery(map, this.args); + } else { + return Batman.developer.error("Couldn't find a route for the name " + key + "!"); + } + }; + + NamedRouteQuery.prototype.nextQueryWithArgument = function(arg) { + var args; + args = this.args.slice(0); + args.push(arg); + return this.clone(args); + }; + + NamedRouteQuery.prototype.path = function() { + var argumentName, argumentValue, index, namedArguments, params, _i, _len; + params = {}; + namedArguments = this.get('route.namedArguments'); + for (index = _i = 0, _len = namedArguments.length; _i < _len; index = ++_i) { + argumentName = namedArguments[index]; + if ((argumentValue = this.get('args')[index]) != null) { + params[argumentName] = this._toParam(argumentValue); + } + } + if (this.get('hashValue') != null) { + params['#'] = this.get('hashValue'); + } + return this.get('route').pathFromParams(params); + }; + + NamedRouteQuery.prototype.toString = function() { + return this.path(); + }; + + NamedRouteQuery.prototype.clone = function(args) { + if (args == null) { + args = this.args; + } + return new Batman.NamedRouteQuery(this.routeMap, args); + }; + + NamedRouteQuery.prototype._toParam = function(arg) { + if (arg instanceof Batman.AssociationProxy) { + arg = arg.get('target'); + } + if ((arg != null ? arg.toParam : void 0) != null) { + return arg.toParam(); + } else { + return arg; + } + }; + + NamedRouteQuery.prototype._queryAccess = function(key, arg) { + var query; + query = this.nextQueryForName(key); + if (arg != null) { + query = query.nextQueryWithArgument(arg); + } + return query; + }; + + return NamedRouteQuery; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Dispatcher = (function(_super) { + var ControllerDirectory; + + __extends(Dispatcher, _super); + + Dispatcher.canInferRoute = function(argument) { + return argument instanceof Batman.Model || argument instanceof Batman.AssociationProxy || argument.prototype instanceof Batman.Model; + }; + + Dispatcher.paramsFromArgument = function(argument) { + var resourceNameFromModel; + resourceNameFromModel = function(model) { + return Batman.helpers.camelize(Batman.helpers.pluralize(model.get('resourceName')), true); + }; + if (!this.canInferRoute(argument)) { + return argument; + } + if (argument instanceof Batman.Model || argument instanceof Batman.AssociationProxy) { + if (argument.isProxy) { + argument = argument.get('target'); + } + if (argument != null) { + return { + controller: resourceNameFromModel(argument.constructor), + action: 'show', + id: argument.get('id') + }; + } else { + return {}; + } + } else if (argument.prototype instanceof Batman.Model) { + return { + controller: resourceNameFromModel(argument), + action: 'index' + }; + } else { + return argument; + } + }; + + ControllerDirectory = (function(_super1) { + + __extends(ControllerDirectory, _super1); + + function ControllerDirectory() { + return ControllerDirectory.__super__.constructor.apply(this, arguments); + } + + ControllerDirectory.accessor('__app', Batman.Property.defaultAccessor); + + ControllerDirectory.accessor(function(key) { + return this.get("__app." + (Batman.helpers.capitalize(key)) + "Controller.sharedController"); + }); + + return ControllerDirectory; + + })(Batman.Object); + + Dispatcher.accessor('controllers', function() { + return new ControllerDirectory({ + __app: this.get('app') + }); + }); + + function Dispatcher(app, routeMap) { + Dispatcher.__super__.constructor.call(this, { + app: app, + routeMap: routeMap + }); + } + + Dispatcher.prototype.routeForParams = function(params) { + params = this.constructor.paramsFromArgument(params); + return this.get('routeMap').routeForParams(params); + }; + + Dispatcher.prototype.pathFromParams = function(params) { + var _ref; + if (typeof params === 'string') { + return params; + } + params = this.constructor.paramsFromArgument(params); + return (_ref = this.routeForParams(params)) != null ? _ref.pathFromParams(params) : void 0; + }; + + Dispatcher.prototype.dispatch = function(params) { + var inferredParams, path, route, _ref; + inferredParams = this.constructor.paramsFromArgument(params); + route = this.routeForParams(inferredParams); + if (route) { + _ref = route.pathAndParamsFromArgument(inferredParams), path = _ref[0], params = _ref[1]; + this.set('app.currentRoute', route); + this.set('app.currentURL', path); + this.get('app.currentParams').replace(params || {}); + route.dispatch(params); + } else { + if (Batman.typeOf(params) === 'Object' && !this.constructor.canInferRoute(params)) { + return this.get('app.currentParams').replace(params); + } else { + this.get('app.currentParams').clear(); + } + if (params !== '/404') { + return Batman.redirect('/404'); + } + } + return path; + }; + + return Dispatcher; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Route = (function(_super) { + + __extends(Route, _super); + + Route.regexps = { + namedParam: /:([\w\d]+)/g, + splatParam: /\*([\w\d]+)/g, + queryParam: '(?:\\?.+)?', + namedOrSplat: /[:|\*]([\w\d]+)/g, + namePrefix: '[:|\*]', + escapeRegExp: /[-[\]{}()+?.,\\^$|#\s]/g + }; + + Route.prototype.optionKeys = ['member', 'collection']; + + Route.prototype.testKeys = ['controller', 'action']; + + Route.prototype.isRoute = true; + + function Route(templatePath, baseParams) { + var k, matches, namedArguments, pattern, properties, regexp, regexps, _i, _len, _ref; + regexps = this.constructor.regexps; + if (templatePath.indexOf('/') !== 0) { + templatePath = "/" + templatePath; + } + pattern = templatePath.replace(regexps.escapeRegExp, '\\$&'); + regexp = RegExp("^" + (pattern.replace(regexps.namedParam, '([^\/]+)').replace(regexps.splatParam, '(.*?)')) + regexps.queryParam + "$"); + namedArguments = ((function() { + var _results; + _results = []; + while (matches = regexps.namedOrSplat.exec(pattern)) { + _results.push(matches[1]); + } + return _results; + })()); + properties = { + templatePath: templatePath, + pattern: pattern, + regexp: regexp, + namedArguments: namedArguments, + baseParams: baseParams + }; + _ref = this.optionKeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + properties[k] = baseParams[k]; + delete baseParams[k]; + } + Route.__super__.constructor.call(this, properties); + } + + Route.prototype.paramsFromPath = function(pathAndQuery) { + var index, match, matches, name, namedArguments, params, uri, _i, _len; + uri = new Batman.URI(pathAndQuery); + namedArguments = this.get('namedArguments'); + params = Batman.extend({ + path: uri.path + }, this.get('baseParams')); + matches = this.get('regexp').exec(uri.path).slice(1); + for (index = _i = 0, _len = matches.length; _i < _len; index = ++_i) { + match = matches[index]; + name = namedArguments[index]; + params[name] = match; + } + return Batman.extend(params, uri.queryParams); + }; + + Route.prototype.pathFromParams = function(argumentParams) { + var hash, key, name, newPath, params, path, query, regexp, _i, _j, _len, _len1, _ref, _ref1; + params = Batman.extend({}, argumentParams); + path = this.get('templatePath'); + _ref = this.get('namedArguments'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + name = _ref[_i]; + regexp = RegExp("" + this.constructor.regexps.namePrefix + name); + newPath = path.replace(regexp, (params[name] != null ? params[name] : '')); + if (newPath !== path) { + delete params[name]; + path = newPath; + } + } + _ref1 = this.testKeys; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + key = _ref1[_j]; + delete params[key]; + } + if (params['#']) { + hash = params['#']; + delete params['#']; + } + query = Batman.URI.queryFromParams(params); + if (query) { + path += "?" + query; + } + if (hash) { + path += "#" + hash; + } + return path; + }; + + Route.prototype.test = function(pathOrParams) { + var key, path, value, _i, _len, _ref; + if (typeof pathOrParams === 'string') { + path = pathOrParams; + } else if (pathOrParams.path != null) { + path = pathOrParams.path; + } else { + path = this.pathFromParams(pathOrParams); + _ref = this.testKeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + if ((value = this.get(key)) != null) { + if (pathOrParams[key] !== value) { + return false; + } + } + } + } + return this.get('regexp').test(path); + }; + + Route.prototype.pathAndParamsFromArgument = function(pathOrParams) { + var params, path; + if (typeof pathOrParams === 'string') { + params = this.paramsFromPath(pathOrParams); + path = pathOrParams; + } else { + params = pathOrParams; + path = this.pathFromParams(pathOrParams); + } + return [path, params]; + }; + + Route.prototype.dispatch = function(params) { + if (!this.test(params)) { + return false; + } + return this.get('callback')(params); + }; + + Route.prototype.callback = function() { + throw new Batman.DevelopmentError("Override callback in a Route subclass"); + }; + + return Route; + + })(Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ControllerActionRoute = (function(_super) { + + __extends(ControllerActionRoute, _super); + + ControllerActionRoute.prototype.optionKeys = ['member', 'collection', 'app', 'controller', 'action']; + + function ControllerActionRoute(templatePath, options) { + this.callback = __bind(this.callback, this); + + var action, controller, _ref; + if (options.signature) { + _ref = options.signature.split('#'), controller = _ref[0], action = _ref[1]; + action || (action = 'index'); + options.controller = controller; + options.action = action; + delete options.signature; + } + ControllerActionRoute.__super__.constructor.call(this, templatePath, options); + } + + ControllerActionRoute.prototype.callback = function(params) { + var controller; + controller = this.get("app.dispatcher.controllers." + (this.get('controller'))); + return controller.dispatch(this.get('action'), params); + }; + + return ControllerActionRoute; + + })(Batman.Route); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.CallbackActionRoute = (function(_super) { + + __extends(CallbackActionRoute, _super); + + function CallbackActionRoute() { + return CallbackActionRoute.__super__.constructor.apply(this, arguments); + } + + CallbackActionRoute.prototype.optionKeys = ['member', 'collection', 'callback', 'app']; + + CallbackActionRoute.prototype.controller = false; + + CallbackActionRoute.prototype.action = false; + + return CallbackActionRoute; + + })(Batman.Route); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.Hash = (function(_super) { + var k, _fn, _i, _j, _len, _len1, _ref, _ref1, + _this = this; + + __extends(Hash, _super); + + Hash.Metadata = (function(_super1) { + + __extends(Metadata, _super1); + + Batman.extend(Metadata.prototype, Batman.Enumerable); + + function Metadata(hash) { + this.hash = hash; + } + + Metadata.accessor('length', function() { + this.hash.registerAsMutableSource(); + return this.hash.length; + }); + + Metadata.accessor('isEmpty', 'keys', 'toArray', function(key) { + this.hash.registerAsMutableSource(); + return this.hash[key](); + }); + + Metadata.prototype.forEach = function() { + var _ref; + return (_ref = this.hash).forEach.apply(_ref, arguments); + }; + + return Metadata; + + })(Batman.Object); + + function Hash() { + this.meta = new this.constructor.Metadata(this); + Batman.SimpleHash.apply(this, arguments); + Hash.__super__.constructor.apply(this, arguments); + } + + Batman.extend(Hash.prototype, Batman.Enumerable); + + Hash.prototype.propertyClass = Batman.Property; + + Hash.defaultAccessor = { + get: Batman.SimpleHash.prototype.get, + set: Hash.mutation(function(key, value) { + var result; + result = Batman.SimpleHash.prototype.set.call(this, key, value); + this.fire('itemsWereAdded', key); + return result; + }), + unset: Hash.mutation(function(key) { + var result; + result = Batman.SimpleHash.prototype.unset.call(this, key); + if (result != null) { + this.fire('itemsWereRemoved', key); + } + return result; + }), + cache: false + }; + + Hash.accessor(Hash.defaultAccessor); + + Hash.prototype._preventMutationEvents = function(block) { + this.prevent('change'); + this.prevent('itemsWereAdded'); + this.prevent('itemsWereRemoved'); + try { + return block.call(this); + } finally { + this.allow('change'); + this.allow('itemsWereAdded'); + this.allow('itemsWereRemoved'); + } + }; + + Hash.prototype.clear = Hash.mutation(function() { + var keys, result; + keys = this.keys(); + this._preventMutationEvents(function() { + var _this = this; + return this.forEach(function(k) { + return _this.unset(k); + }); + }); + result = Batman.SimpleHash.prototype.clear.call(this); + this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(keys))); + return result; + }); + + Hash.prototype.update = Hash.mutation(function(object) { + var addedKeys; + addedKeys = []; + this._preventMutationEvents(function() { + var _this = this; + return Batman.forEach(object, function(k, v) { + if (!_this.hasKey(k)) { + addedKeys.push(k); + } + return _this.set(k, v); + }); + }); + if (addedKeys.length > 0) { + return this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedKeys))); + } + }); + + Hash.prototype.replace = Hash.mutation(function(object) { + var addedKeys, removedKeys; + addedKeys = []; + removedKeys = []; + this._preventMutationEvents(function() { + var _this = this; + this.forEach(function(k, _) { + if (!Batman.objectHasKey(object, k)) { + _this.unset(k); + return removedKeys.push(k); + } + }); + return Batman.forEach(object, function(k, v) { + if (!_this.hasKey(k)) { + addedKeys.push(k); + } + return _this.set(k, v); + }); + }); + if (addedKeys.length > 0) { + this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedKeys))); + } + if (removedKeys.length > 0) { + return this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(removedKeys))); + } + }); + + _ref = ['equality', 'hashKeyFor', 'objectKey', 'prefixedKey', 'unprefixedKey']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + Hash.prototype[k] = Batman.SimpleHash.prototype[k]; + } + + _ref1 = ['hasKey', 'forEach', 'isEmpty', 'keys', 'toArray', 'merge', 'toJSON', 'toObject']; + _fn = function(k) { + return Hash.prototype[k] = function() { + this.registerAsMutableSource(); + return Batman.SimpleHash.prototype[k].apply(this, arguments); + }; + }; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + k = _ref1[_j]; + _fn(k); + } + + return Hash; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.RenderCache = (function(_super) { + + __extends(RenderCache, _super); + + RenderCache.prototype.maximumLength = 4; + + function RenderCache() { + RenderCache.__super__.constructor.apply(this, arguments); + this.keyQueue = []; + } + + RenderCache.prototype.viewForOptions = function(options) { + var _this = this; + if (options.cache === false || options.viewClass.prototype.cache === false) { + return this._newViewFromOptions(options); + } + return this.getOrSet(options, function() { + return _this._newViewFromOptions(Batman.extend({}, options)); + }); + }; + + RenderCache.prototype._newViewFromOptions = function(options) { + return new options.viewClass(options); + }; + + RenderCache.wrapAccessor(function(core) { + return { + cache: false, + get: function(key) { + var result; + result = core.get.call(this, key); + if (result) { + this._addOrBubbleKey(key); + } + return result; + }, + set: function(key, value) { + var result; + result = core.set.apply(this, arguments); + result.set('cached', true); + this._addOrBubbleKey(key); + this._evictExpiredKeys(); + return result; + }, + unset: function(key) { + var result; + result = core.unset.apply(this, arguments); + result.set('cached', false); + this._removeKeyFromQueue(key); + return result; + } + }; + }); + + RenderCache.prototype.equality = function(incomingOptions, storageOptions) { + var key; + if (Object.keys(incomingOptions).length !== Object.keys(storageOptions).length) { + return false; + } + for (key in incomingOptions) { + if (!(key === 'view')) { + if (incomingOptions[key] !== storageOptions[key]) { + return false; + } + } + } + return true; + }; + + RenderCache.prototype.reset = function() { + var key, _i, _len, _ref, _results; + _ref = this.keyQueue.slice(0); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push(this.unset(key)); + } + return _results; + }; + + RenderCache.prototype._addOrBubbleKey = function(key) { + this._removeKeyFromQueue(key); + return this.keyQueue.unshift(key); + }; + + RenderCache.prototype._removeKeyFromQueue = function(key) { + var index, queuedKey, _i, _len, _ref; + _ref = this.keyQueue; + for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { + queuedKey = _ref[index]; + if (this.equality(queuedKey, key)) { + this.keyQueue.splice(index, 1); + break; + } + } + return key; + }; + + RenderCache.prototype._evictExpiredKeys = function() { + var currentKeys, i, key, _i, _ref, _ref1; + if (this.length > this.maximumLength) { + currentKeys = this.keyQueue.slice(0); + for (i = _i = _ref = this.maximumLength, _ref1 = currentKeys.length; _ref <= _ref1 ? _i < _ref1 : _i > _ref1; i = _ref <= _ref1 ? ++_i : --_i) { + key = currentKeys[i]; + if (!this.get(key).isInDOM()) { + this.unset(key); + } + } + } + }; + + return RenderCache; + + })(Batman.Hash); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.Controller = (function(_super) { + var _optionsFromFilterArguments; + + __extends(Controller, _super); + + Controller.singleton('sharedController'); + + Controller.wrapAccessor('routingKey', function(core) { + return { + get: function() { + if (this.routingKey != null) { + return this.routingKey; + } else { + if (Batman.config.minificationErrors) { + Batman.developer.error("Please define `routingKey` on the prototype of " + (Batman.functionName(this.constructor)) + " in order for your controller to be minification safe."); + } + return Batman.functionName(this.constructor).replace(/Controller$/, ''); + } + } + }; + }); + + Controller.accessor('_renderContext', function() { + return Batman.RenderContext.root().descend(this); + }); + + _optionsFromFilterArguments = function(options, nameOrFunction) { + if (!nameOrFunction) { + nameOrFunction = options; + options = {}; + } else { + if (typeof options === 'string') { + options = { + only: [options] + }; + } else { + if (options.only && Batman.typeOf(options.only) !== 'Array') { + options.only = [options.only]; + } + if (options.except && Batman.typeOf(options.except) !== 'Array') { + options.except = [options.except]; + } + } + } + options.block = nameOrFunction; + return options; + }; + + Controller.beforeFilter = function() { + var filters, options, _base; + Batman.initializeObject(this); + options = _optionsFromFilterArguments.apply(null, arguments); + filters = (_base = this._batman).beforeFilters || (_base.beforeFilters = new Batman.SimpleHash); + return filters.set(options.block, options); + }; + + Controller.afterFilter = function() { + var filters, options, _base; + Batman.initializeObject(this); + options = _optionsFromFilterArguments.apply(null, arguments); + filters = (_base = this._batman).afterFilters || (_base.afterFilters = new Batman.SimpleHash); + return filters.set(options.block, options); + }; + + Controller.afterFilter(function(params) { + if (this.autoScrollToHash && (params['#'] != null)) { + return this.scrollToHash(params['#']); + } + }); + + function Controller() { + this.redirect = __bind(this.redirect, this); + Controller.__super__.constructor.apply(this, arguments); + this._resetActionFrames(); + } + + Controller.prototype.renderCache = new Batman.RenderCache; + + Controller.prototype.defaultRenderYield = 'main'; + + Controller.prototype.autoScrollToHash = true; + + Controller.prototype.dispatch = function(action, params) { + var redirectTo; + if (params == null) { + params = {}; + } + params.controller || (params.controller = this.get('routingKey')); + params.action || (params.action = action); + params.target || (params.target = this); + this._resetActionFrames(); + this.set('action', action); + this.set('params', params); + Batman.DOM.Yield.cycleAll(); + this.executeAction(action, params); + Batman.DOM.Yield.clearAllStale(); + redirectTo = this._afterFilterRedirect; + delete this._afterFilterRedirect; + if (redirectTo) { + return Batman.redirect(redirectTo); + } + }; + + Controller.prototype.executeAction = function(action, params) { + var frame, oldRedirect, parentFrame, result, _ref, _ref1, + _this = this; + if (params == null) { + params = this.get('params'); + } + Batman.developer.assert(this[action], "Error! Controller action " + (this.get('routingKey')) + "." + action + " couldn't be found!"); + parentFrame = this._actionFrames[this._actionFrames.length - 1]; + frame = new Batman.ControllerActionFrame({ + parentFrame: parentFrame, + action: action + }, function() { + var _ref; + _this._runFilters(action, params, 'afterFilters'); + _this._resetActionFrames(); + return (_ref = Batman.navigator) != null ? _ref.redirect = oldRedirect : void 0; + }); + this._actionFrames.push(frame); + frame.startOperation({ + internal: true + }); + oldRedirect = (_ref = Batman.navigator) != null ? _ref.redirect : void 0; + if ((_ref1 = Batman.navigator) != null) { + _ref1.redirect = this.redirect; + } + this._runFilters(action, params, 'beforeFilters'); + result = this[action](params); + if (!frame.operationOccurred) { + this.render(); + } + frame.finishOperation(); + return result; + }; + + Controller.prototype.redirect = function(url) { + var frame; + frame = this._actionFrames[this._actionFrames.length - 1]; + if (frame) { + if (frame.operationOccurred) { + Batman.developer.warn("Warning! Trying to redirect but an action has already be taken during " + (this.get('routingKey')) + "." + (frame.action || this.get('action'))); + } + frame.startAndFinishOperation(); + if (this._afterFilterRedirect != null) { + return Batman.developer.warn("Warning! Multiple actions trying to redirect!"); + } else { + return this._afterFilterRedirect = url; + } + } else { + if (Batman.typeOf(url) === 'Object') { + if (!url.controller) { + url.controller = this; + } + } + return Batman.redirect(url); + } + }; + + Controller.prototype.render = function(options) { + var action, frame, view, _ref, _ref1, + _this = this; + if (options == null) { + options = {}; + } + if (frame = (_ref = this._actionFrames) != null ? _ref[this._actionFrames.length - 1] : void 0) { + frame.startOperation(); + } + if (options === false) { + frame.finishOperation(); + return; + } + action = (frame != null ? frame.action : void 0) || this.get('action'); + if (options) { + options.into || (options.into = this.defaultRenderYield); + } + if (!options.view) { + options.viewClass || (options.viewClass = this._viewClassForAction(action)); + options.context || (options.context = this.get('_renderContext')); + options.source || (options.source = Batman.helpers.underscore(this.get('routingKey') + '/' + action)); + view = this.renderCache.viewForOptions(options); + } else { + view = options.view; + options.view = null; + } + if (view) { + if ((_ref1 = Batman.currentApp) != null) { + _ref1.prevent('ready'); + } + view.on('ready', function() { + var _ref2; + Batman.DOM.Yield.withName(options.into).replace(view.get('node')); + if ((_ref2 = Batman.currentApp) != null) { + _ref2.allowAndFire('ready'); + } + return frame != null ? frame.finishOperation() : void 0; + }); + } + return view; + }; + + Controller.prototype.scrollToHash = function(hash) { + if (hash == null) { + hash = this.get('params')['#']; + } + return Batman.DOM.scrollIntoView(hash); + }; + + Controller.prototype._resetActionFrames = function() { + return this._actionFrames = []; + }; + + Controller.prototype._viewClassForAction = function(action) { + var classPrefix, _ref; + classPrefix = this.get('routingKey').replace('/', '_'); + return ((_ref = Batman.currentApp) != null ? _ref[Batman.helpers.camelize("" + classPrefix + "_" + action + "_view")] : void 0) || Batman.View; + }; + + Controller.prototype._runFilters = function(action, params, filters) { + var _ref, + _this = this; + if (filters = (_ref = this.constructor._batman) != null ? _ref.get(filters) : void 0) { + return filters.forEach(function(_, options) { + var block; + if (options.only && __indexOf.call(options.only, action) < 0) { + return; + } + if (options.except && __indexOf.call(options.except, action) >= 0) { + return; + } + block = options.block; + if (typeof block === 'function') { + return block.call(_this, params); + } else { + return typeof _this[block] === "function" ? _this[block](params) : void 0; + } + }); + } + }; + + return Controller; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Set = (function(_super) { + var k, _fn, _i, _j, _len, _len1, _ref, _ref1, + _this = this; + + __extends(Set, _super); + + function Set() { + Batman.SimpleSet.apply(this, arguments); + } + + Batman.extend(Set.prototype, Batman.Enumerable); + + Set._applySetAccessors = function(klass) { + var accessor, accessors, key, _results; + accessors = { + first: function() { + return this.toArray()[0]; + }, + last: function() { + return this.toArray()[this.length - 1]; + }, + isEmpty: function() { + return this.isEmpty(); + }, + toArray: function() { + return this.toArray(); + }, + length: function() { + this.registerAsMutableSource(); + return this.length; + }, + indexedBy: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.indexedBy(key); + }); + }, + indexedByUnique: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.indexedByUnique(key); + }); + }, + sortedBy: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.sortedBy(key); + }); + }, + sortedByDescending: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.sortedBy(key, 'desc'); + }); + } + }; + _results = []; + for (key in accessors) { + accessor = accessors[key]; + _results.push(klass.accessor(key, accessor)); + } + return _results; + }; + + Set._applySetAccessors(Set); + + _ref = ['add', 'remove', 'clear', 'replace', 'indexedBy', 'indexedByUnique', 'sortedBy', 'equality', '_indexOfItem']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + Set.prototype[k] = Batman.SimpleSet.prototype[k]; + } + + _ref1 = ['find', 'merge', 'forEach', 'toArray', 'isEmpty', 'has']; + _fn = function(k) { + return Set.prototype[k] = function() { + this.registerAsMutableSource(); + return Batman.SimpleSet.prototype[k].apply(this, arguments); + }; + }; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + k = _ref1[_j]; + _fn(k); + } + + Set.prototype.toJSON = Set.prototype.toArray; + + return Set; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ErrorsSet = (function(_super) { + + __extends(ErrorsSet, _super); + + function ErrorsSet() { + return ErrorsSet.__super__.constructor.apply(this, arguments); + } + + ErrorsSet.accessor(function(key) { + return this.indexedBy('attribute').get(key); + }); + + ErrorsSet.prototype.add = function(key, error) { + return ErrorsSet.__super__.add.call(this, new Batman.ValidationError(key, error)); + }; + + return ErrorsSet; + + })(Batman.Set); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetProxy = (function(_super) { + var k, _fn, _i, _len, _ref, + _this = this; + + __extends(SetProxy, _super); + + function SetProxy(base) { + var _this = this; + this.base = base; + SetProxy.__super__.constructor.call(this); + this.length = this.base.length; + this.base.on('itemsWereAdded', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _this.set('length', _this.base.length); + return _this.fire.apply(_this, ['itemsWereAdded'].concat(__slice.call(items))); + }); + this.base.on('itemsWereRemoved', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _this.set('length', _this.base.length); + return _this.fire.apply(_this, ['itemsWereRemoved'].concat(__slice.call(items))); + }); + } + + Batman.extend(SetProxy.prototype, Batman.Enumerable); + + SetProxy.prototype.filter = function(f) { + var r; + r = new Batman.Set(); + return this.reduce((function(r, e) { + if (f(e)) { + r.add(e); + } + return r; + }), r); + }; + + SetProxy.prototype.replace = function() { + var length, result; + length = this.property('length'); + length.isolate(); + result = this.base.replace.apply(this, arguments); + length.expose(); + return result; + }; + + _ref = ['add', 'remove', 'find', 'clear', 'has', 'merge', 'toArray', 'isEmpty', 'indexedBy', 'indexedByUnique', 'sortedBy']; + _fn = function(k) { + return SetProxy.prototype[k] = function() { + var _ref1; + return (_ref1 = this.base)[k].apply(_ref1, arguments); + }; + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + _fn(k); + } + + Batman.Set._applySetAccessors(SetProxy); + + SetProxy.accessor('length', { + get: function() { + this.registerAsMutableSource(); + return this.length; + }, + set: function(_, v) { + return this.length = v; + } + }); + + return SetProxy; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.BinarySetOperation = (function(_super) { + + __extends(BinarySetOperation, _super); + + function BinarySetOperation(left, right) { + this.left = left; + this.right = right; + this._setup = __bind(this._setup, this); + + BinarySetOperation.__super__.constructor.call(this); + this._setup(this.left, this.right); + this._setup(this.right, this.left); + } + + BinarySetOperation.prototype._setup = function(set, opposite) { + var _this = this; + set.on('itemsWereAdded', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return _this._itemsWereAddedToSource.apply(_this, [set, opposite].concat(__slice.call(items))); + }); + set.on('itemsWereRemoved', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return _this._itemsWereRemovedFromSource.apply(_this, [set, opposite].concat(__slice.call(items))); + }); + return this._itemsWereAddedToSource.apply(this, [set, opposite].concat(__slice.call(set.toArray()))); + }; + + BinarySetOperation.prototype.merge = function() { + var merged, others, set, _i, _len; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + merged = new Batman.Set; + others.unshift(this); + for (_i = 0, _len = others.length; _i < _len; _i++) { + set = others[_i]; + set.forEach(function(v) { + return merged.add(v); + }); + } + return merged; + }; + + BinarySetOperation.prototype.filter = Batman.SetProxy.prototype.filter; + + return BinarySetOperation; + + })(Batman.Set); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetUnion = (function(_super) { + + __extends(SetUnion, _super); + + function SetUnion() { + return SetUnion.__super__.constructor.apply(this, arguments); + } + + SetUnion.prototype._itemsWereAddedToSource = function() { + var items, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + return this.add.apply(this, items); + }; + + SetUnion.prototype._itemsWereRemovedFromSource = function() { + var item, items, itemsToRemove, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + itemsToRemove = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.remove.apply(this, itemsToRemove); + }; + + return SetUnion; + + })(Batman.BinarySetOperation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetIntersection = (function(_super) { + + __extends(SetIntersection, _super); + + function SetIntersection() { + return SetIntersection.__super__.constructor.apply(this, arguments); + } + + SetIntersection.prototype._itemsWereAddedToSource = function() { + var item, items, itemsToAdd, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.add.apply(this, itemsToAdd); + }; + + SetIntersection.prototype._itemsWereRemovedFromSource = function() { + var items, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + return this.remove.apply(this, items); + }; + + return SetIntersection; + + })(Batman.BinarySetOperation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetComplement = (function(_super) { + + __extends(SetComplement, _super); + + function SetComplement() { + return SetComplement.__super__.constructor.apply(this, arguments); + } + + SetComplement.prototype._itemsWereAddedToSource = function() { + var item, items, itemsToAdd, itemsToRemove, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + if (source === this.left) { + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.add.apply(this, itemsToAdd); + } else { + itemsToRemove = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.remove.apply(this, itemsToRemove); + } + }; + + SetComplement.prototype._itemsWereRemovedFromSource = function() { + var item, items, itemsToAdd, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + if (source === this.left) { + return this.remove.apply(this, items); + } else { + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.add.apply(this, itemsToAdd); + } + }; + + SetComplement.prototype._addComplement = function(items, opposite) { + var item; + return this.add.apply(this, (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })()); + }; + + return SetComplement; + + })(Batman.BinarySetOperation); + +}).call(this); + +(function() { + + Batman.mixins = new Batman.Object; + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Accessible = (function(_super) { + + __extends(Accessible, _super); + + function Accessible() { + this.accessor.apply(this, arguments); + } + + return Accessible; + + })(Batman.Object); + + Batman.TerminalAccessible = (function(_super) { + + __extends(TerminalAccessible, _super); + + function TerminalAccessible() { + return TerminalAccessible.__super__.constructor.apply(this, arguments); + } + + TerminalAccessible.prototype.propertyClass = Batman.Property; + + return TerminalAccessible; + + })(Batman.Accessible); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetObserver = (function(_super) { + + __extends(SetObserver, _super); + + function SetObserver(base) { + var _this = this; + this.base = base; + this._itemObservers = new Batman.SimpleHash; + this._setObservers = new Batman.SimpleHash; + this._setObservers.set("itemsWereAdded", function() { + return _this.fire.apply(_this, ['itemsWereAdded'].concat(__slice.call(arguments))); + }); + this._setObservers.set("itemsWereRemoved", function() { + return _this.fire.apply(_this, ['itemsWereRemoved'].concat(__slice.call(arguments))); + }); + this.on('itemsWereAdded', this.startObservingItems.bind(this)); + this.on('itemsWereRemoved', this.stopObservingItems.bind(this)); + } + + SetObserver.prototype.observedItemKeys = []; + + SetObserver.prototype.observerForItemAndKey = function(item, key) {}; + + SetObserver.prototype._getOrSetObserverForItemAndKey = function(item, key) { + var _this = this; + return this._itemObservers.getOrSet(item, function() { + var observersByKey; + observersByKey = new Batman.SimpleHash; + return observersByKey.getOrSet(key, function() { + return _this.observerForItemAndKey(item, key); + }); + }); + }; + + SetObserver.prototype.startObserving = function() { + this._manageItemObservers("observe"); + return this._manageSetObservers("addHandler"); + }; + + SetObserver.prototype.stopObserving = function() { + this._manageItemObservers("forget"); + return this._manageSetObservers("removeHandler"); + }; + + SetObserver.prototype.startObservingItems = function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(this._manageObserversForItem(item, "observe")); + } + return _results; + }; + + SetObserver.prototype.stopObservingItems = function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(this._manageObserversForItem(item, "forget")); + } + return _results; + }; + + SetObserver.prototype._manageObserversForItem = function(item, method) { + var key, _i, _len, _ref; + if (!item.isObservable) { + return; + } + _ref = this.observedItemKeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + item[method](key, this._getOrSetObserverForItemAndKey(item, key)); + } + if (method === "forget") { + return this._itemObservers.unset(item); + } + }; + + SetObserver.prototype._manageItemObservers = function(method) { + var _this = this; + return this.base.forEach(function(item) { + return _this._manageObserversForItem(item, method); + }); + }; + + SetObserver.prototype._manageSetObservers = function(method) { + var _this = this; + if (!this.base.isObservable) { + return; + } + return this._setObservers.forEach(function(key, observer) { + return _this.base.event(key)[method](observer); + }); + }; + + return SetObserver; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.SetSort = (function(_super) { + + __extends(SetSort, _super); + + function SetSort(base, key, order) { + var boundReIndex; + this.key = key; + if (order == null) { + order = "asc"; + } + SetSort.__super__.constructor.call(this, base); + this.descending = order.toLowerCase() === "desc"; + if (this.base.isObservable) { + this._setObserver = new Batman.SetObserver(this.base); + this._setObserver.observedItemKeys = [this.key]; + boundReIndex = this._reIndex.bind(this); + this._setObserver.observerForItemAndKey = function() { + return boundReIndex; + }; + this._setObserver.on('itemsWereAdded', boundReIndex); + this._setObserver.on('itemsWereRemoved', boundReIndex); + this.startObserving(); + } + this._reIndex(); + } + + SetSort.prototype.startObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.startObserving() : void 0; + }; + + SetSort.prototype.stopObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.stopObserving() : void 0; + }; + + SetSort.prototype.toArray = function() { + return this.get('_storage'); + }; + + SetSort.prototype.forEach = function(iterator, ctx) { + var e, i, _i, _len, _ref, _results; + _ref = this.get('_storage'); + _results = []; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + e = _ref[i]; + _results.push(iterator.call(ctx, e, i, this)); + } + return _results; + }; + + SetSort.prototype.compare = function(a, b) { + if (a === b) { + return 0; + } + if (a === void 0) { + return 1; + } + if (b === void 0) { + return -1; + } + if (a === null) { + return 1; + } + if (b === null) { + return -1; + } + if (a === false) { + return 1; + } + if (b === false) { + return -1; + } + if (a === true) { + return 1; + } + if (b === true) { + return -1; + } + if (a !== a) { + if (b !== b) { + return 0; + } else { + return 1; + } + } + if (b !== b) { + return -1; + } + if (a > b) { + return 1; + } + if (a < b) { + return -1; + } + return 0; + }; + + SetSort.prototype._reIndex = function() { + var newOrder, _ref, + _this = this; + newOrder = this.base.toArray().sort(function(a, b) { + var multiple, valueA, valueB; + valueA = Batman.get(a, _this.key); + if (typeof valueA === 'function') { + valueA = valueA.call(a); + } + if (valueA != null) { + valueA = valueA.valueOf(); + } + valueB = Batman.get(b, _this.key); + if (typeof valueB === 'function') { + valueB = valueB.call(b); + } + if (valueB != null) { + valueB = valueB.valueOf(); + } + multiple = _this.descending ? -1 : 1; + return _this.compare.call(_this, valueA, valueB) * multiple; + }); + if ((_ref = this._setObserver) != null) { + _ref.startObservingItems.apply(_ref, newOrder); + } + return this.set('_storage', newOrder); + }; + + return SetSort; + + })(Batman.SetProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.AssociationSet = (function(_super) { + + __extends(AssociationSet, _super); + + function AssociationSet(foreignKeyValue, association) { + var base; + this.foreignKeyValue = foreignKeyValue; + this.association = association; + base = new Batman.Set; + AssociationSet.__super__.constructor.call(this, base, 'hashKey'); + } + + AssociationSet.prototype.loaded = false; + + AssociationSet.prototype.load = function(callback) { + var _this = this; + if (this.foreignKeyValue == null) { + return callback(void 0, this); + } + return this.association.getRelatedModel().load(this._getLoadOptions(), function(err, records) { + if (!err) { + _this.markAsLoaded(); + } + return callback(err, _this); + }); + }; + + AssociationSet.prototype._getLoadOptions = function() { + var loadOptions; + loadOptions = {}; + loadOptions[this.association.foreignKey] = this.foreignKeyValue; + return loadOptions; + }; + + AssociationSet.accessor('loaded', Batman.Property.defaultAccessor); + + AssociationSet.prototype.markAsLoaded = function() { + this.set('loaded', true); + return this.fire('loaded'); + }; + + return AssociationSet; + + })(Batman.SetSort); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicAssociationSet = (function(_super) { + + __extends(PolymorphicAssociationSet, _super); + + function PolymorphicAssociationSet(foreignKeyValue, foreignTypeKeyValue, association) { + this.foreignKeyValue = foreignKeyValue; + this.foreignTypeKeyValue = foreignTypeKeyValue; + this.association = association; + PolymorphicAssociationSet.__super__.constructor.call(this, this.foreignKeyValue, this.association); + } + + PolymorphicAssociationSet.prototype._getLoadOptions = function() { + var loadOptions; + loadOptions = {}; + loadOptions[this.association.foreignKey] = this.foreignKeyValue; + loadOptions[this.association.foreignTypeKey] = this.foreignTypeKeyValue; + return loadOptions; + }; + + return PolymorphicAssociationSet; + + })(Batman.AssociationSet); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetIndex = (function(_super) { + + __extends(SetIndex, _super); + + SetIndex.accessor('toArray', function() { + return this.toArray(); + }); + + Batman.extend(SetIndex.prototype, Batman.Enumerable); + + SetIndex.prototype.propertyClass = Batman.Property; + + function SetIndex(base, key) { + var _this = this; + this.base = base; + this.key = key; + SetIndex.__super__.constructor.call(this); + this._storage = new Batman.Hash; + if (this.base.isEventEmitter) { + this._setObserver = new Batman.SetObserver(this.base); + this._setObserver.observedItemKeys = [this.key]; + this._setObserver.observerForItemAndKey = this.observerForItemAndKey.bind(this); + this._setObserver.on('itemsWereAdded', function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(_this._addItem(item)); + } + return _results; + }); + this._setObserver.on('itemsWereRemoved', function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(_this._removeItem(item)); + } + return _results; + }); + } + this.base.forEach(this._addItem.bind(this)); + this.startObserving(); + } + + SetIndex.accessor(function(key) { + return this._resultSetForKey(key); + }); + + SetIndex.prototype.startObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.startObserving() : void 0; + }; + + SetIndex.prototype.stopObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.stopObserving() : void 0; + }; + + SetIndex.prototype.observerForItemAndKey = function(item, key) { + var _this = this; + return function(newValue, oldValue) { + _this._removeItemFromKey(item, oldValue); + return _this._addItemToKey(item, newValue); + }; + }; + + SetIndex.prototype.forEach = function(iterator, ctx) { + var _this = this; + return this._storage.forEach(function(key, set) { + if (set.get('length') > 0) { + return iterator.call(ctx, key, set, _this); + } + }); + }; + + SetIndex.prototype.toArray = function() { + var results; + results = []; + this._storage.forEach(function(key, set) { + if (set.get('length') > 0) { + return results.push(key); + } + }); + return results; + }; + + SetIndex.prototype._addItem = function(item) { + return this._addItemToKey(item, this._keyForItem(item)); + }; + + SetIndex.prototype._addItemToKey = function(item, key) { + return this._resultSetForKey(key).add(item); + }; + + SetIndex.prototype._removeItem = function(item) { + return this._removeItemFromKey(item, this._keyForItem(item)); + }; + + SetIndex.prototype._removeItemFromKey = function(item, key) { + return this._resultSetForKey(key).remove(item); + }; + + SetIndex.prototype._resultSetForKey = function(key) { + return this._storage.getOrSet(key, function() { + return new Batman.Set; + }); + }; + + SetIndex.prototype._keyForItem = function(item) { + return Batman.Keypath.forBaseAndKey(item, this.key).getValue(); + }; + + return SetIndex; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicAssociationSetIndex = (function(_super) { + + __extends(PolymorphicAssociationSetIndex, _super); + + function PolymorphicAssociationSetIndex(association, type, key) { + this.association = association; + this.type = type; + PolymorphicAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); + } + + PolymorphicAssociationSetIndex.prototype._resultSetForKey = function(key) { + var _this = this; + return this._storage.getOrSet(key, function() { + return new Batman.PolymorphicAssociationSet(key, _this.type, _this.association); + }); + }; + + return PolymorphicAssociationSetIndex; + + })(Batman.SetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.AssociationSetIndex = (function(_super) { + + __extends(AssociationSetIndex, _super); + + function AssociationSetIndex(association, key) { + this.association = association; + AssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); + } + + AssociationSetIndex.prototype._resultSetForKey = function(key) { + var _this = this; + return this._storage.getOrSet(key, function() { + return new Batman.AssociationSet(key, _this.association); + }); + }; + + AssociationSetIndex.prototype._setResultSet = function(key, set) { + return this._storage.set(key, set); + }; + + return AssociationSetIndex; + + })(Batman.SetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.UniqueSetIndex = (function(_super) { + + __extends(UniqueSetIndex, _super); + + function UniqueSetIndex() { + this._uniqueIndex = new Batman.Hash; + UniqueSetIndex.__super__.constructor.apply(this, arguments); + } + + UniqueSetIndex.accessor(function(key) { + return this._uniqueIndex.get(key); + }); + + UniqueSetIndex.prototype._addItemToKey = function(item, key) { + this._resultSetForKey(key).add(item); + if (!this._uniqueIndex.hasKey(key)) { + return this._uniqueIndex.set(key, item); + } + }; + + UniqueSetIndex.prototype._removeItemFromKey = function(item, key) { + var resultSet; + resultSet = this._resultSetForKey(key); + UniqueSetIndex.__super__._removeItemFromKey.apply(this, arguments); + if (resultSet.isEmpty()) { + return this._uniqueIndex.unset(key); + } else { + return this._uniqueIndex.set(key, resultSet.toArray()[0]); + } + }; + + return UniqueSetIndex; + + })(Batman.SetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.UniqueAssociationSetIndex = (function(_super) { + + __extends(UniqueAssociationSetIndex, _super); + + function UniqueAssociationSetIndex(association, key) { + this.association = association; + UniqueAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); + } + + return UniqueAssociationSetIndex; + + })(Batman.UniqueSetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicUniqueAssociationSetIndex = (function(_super) { + + __extends(PolymorphicUniqueAssociationSetIndex, _super); + + function PolymorphicUniqueAssociationSetIndex(association, type, key) { + this.association = association; + this.type = type; + PolymorphicUniqueAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); + } + + return PolymorphicUniqueAssociationSetIndex; + + })(Batman.UniqueSetIndex); + +}).call(this); + +(function() { + + Batman.URI = (function() { + /* + # URI parsing + */ + + var attributes, childKeyMatchers, decodeQueryComponent, encodeComponent, encodeQueryComponent, keyVal, nameParser, normalizeParams, plus, queryFromParams, r20, strictParser; + + strictParser = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/; + + attributes = ["source", "protocol", "authority", "userInfo", "user", "password", "hostname", "port", "relative", "path", "directory", "file", "query", "hash"]; + + function URI(str) { + var i, matches; + matches = strictParser.exec(str); + i = 14; + while (i--) { + this[attributes[i]] = matches[i] || ''; + } + this.queryParams = this.constructor.paramsFromQuery(this.query); + delete this.authority; + delete this.userInfo; + delete this.relative; + delete this.directory; + delete this.file; + delete this.query; + } + + URI.prototype.queryString = function() { + return this.constructor.queryFromParams(this.queryParams); + }; + + URI.prototype.toString = function() { + return [this.protocol ? "" + this.protocol + ":" : void 0, this.authority() ? "//" : void 0, this.authority(), this.relative()].join(""); + }; + + URI.prototype.userInfo = function() { + return [this.user, this.password ? ":" + this.password : void 0].join(""); + }; + + URI.prototype.authority = function() { + return [this.userInfo(), this.user || this.password ? "@" : void 0, this.hostname, this.port ? ":" + this.port : void 0].join(""); + }; + + URI.prototype.relative = function() { + var query; + query = this.queryString(); + return [this.path, query ? "?" + query : void 0, this.hash ? "#" + this.hash : void 0].join(""); + }; + + URI.prototype.directory = function() { + var splitPath; + splitPath = this.path.split('/'); + if (splitPath.length > 1) { + return splitPath.slice(0, splitPath.length - 1).join('/') + "/"; + } else { + return ""; + } + }; + + URI.prototype.file = function() { + var splitPath; + splitPath = this.path.split("/"); + return splitPath[splitPath.length - 1]; + }; + + /* + # query parsing + */ + + + URI.paramsFromQuery = function(query) { + var matches, params, segment, _i, _len, _ref; + params = {}; + _ref = query.split('&'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + segment = _ref[_i]; + if (matches = segment.match(keyVal)) { + normalizeParams(params, decodeQueryComponent(matches[1]), decodeQueryComponent(matches[2])); + } else { + normalizeParams(params, decodeQueryComponent(segment), null); + } + } + return params; + }; + + URI.decodeQueryComponent = decodeQueryComponent = function(str) { + return decodeURIComponent(str.replace(plus, '%20')); + }; + + nameParser = /^[\[\]]*([^\[\]]+)\]*(.*)/; + + childKeyMatchers = [/^\[\]\[([^\[\]]+)\]$/, /^\[\](.+)$/]; + + plus = /\+/g; + + r20 = /%20/g; + + keyVal = /^([^=]*)=(.*)/; + + normalizeParams = function(params, name, v) { + var after, childKey, k, last, matches, _ref, _ref1, _ref2; + if (matches = name.match(nameParser)) { + k = matches[1]; + after = matches[2]; + } else { + return; + } + if (after === '') { + params[k] = v; + } else if (after === '[]') { + if ((_ref = params[k]) == null) { + params[k] = []; + } + if (Batman.typeOf(params[k]) !== 'Array') { + throw new Error("expected Array (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); + } + params[k].push(v); + } else if (matches = after.match(childKeyMatchers[0]) || after.match(childKeyMatchers[1])) { + childKey = matches[1]; + if ((_ref1 = params[k]) == null) { + params[k] = []; + } + if (Batman.typeOf(params[k]) !== 'Array') { + throw new Error("expected Array (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); + } + last = params[k][params[k].length - 1]; + if (Batman.typeOf(last) === 'Object' && !(childKey in last)) { + normalizeParams(last, childKey, v); + } else { + params[k].push(normalizeParams({}, childKey, v)); + } + } else { + if ((_ref2 = params[k]) == null) { + params[k] = {}; + } + if (Batman.typeOf(params[k]) !== 'Object') { + throw new Error("expected Object (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); + } + params[k] = normalizeParams(params[k], after, v); + } + return params; + }; + + /* + # query building + */ + + + URI.queryFromParams = queryFromParams = function(value, prefix) { + var arrayResults, k, v, valueType; + if (value == null) { + return prefix; + } + valueType = Batman.typeOf(value); + if (!((prefix != null) || valueType === 'Object')) { + throw new Error("value must be an Object"); + } + switch (valueType) { + case 'Array': + return ((function() { + var _i, _len; + arrayResults = []; + if (value.length === 0) { + arrayResults.push(queryFromParams(null, "" + prefix + "[]")); + } else { + for (_i = 0, _len = value.length; _i < _len; _i++) { + v = value[_i]; + arrayResults.push(queryFromParams(v, "" + prefix + "[]")); + } + } + return arrayResults; + })()).join("&"); + case 'Object': + return ((function() { + var _results; + _results = []; + for (k in value) { + v = value[k]; + _results.push(queryFromParams(v, prefix ? "" + prefix + "[" + (encodeQueryComponent(k)) + "]" : encodeQueryComponent(k))); + } + return _results; + })()).join("&"); + default: + if (prefix != null) { + return "" + prefix + "=" + (encodeQueryComponent(value)); + } else { + return encodeQueryComponent(value); + } + } + }; + + URI.encodeComponent = encodeComponent = function(str) { + if (str != null) { + return encodeURIComponent(str); + } else { + return ''; + } + }; + + URI.encodeQueryComponent = encodeQueryComponent = function(str) { + return encodeComponent(str).replace(r20, '+'); + }; + + return URI; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Request = (function(_super) { + var dataHasFileUploads; + + __extends(Request, _super); + + Request.objectToFormData = function(data) { + var formData, key, pairForList, val, _i, _len, _ref, _ref1; + pairForList = function(key, object, first) { + var k, list, v; + if (first == null) { + first = false; + } + return list = (function() { + switch (Batman.typeOf(object)) { + case 'Object': + list = (function() { + var _results; + _results = []; + for (k in object) { + v = object[k]; + _results.push(pairForList((first ? k : "" + key + "[" + k + "]"), v)); + } + return _results; + })(); + return list.reduce(function(acc, list) { + return acc.concat(list); + }, []); + case 'Array': + return object.reduce(function(acc, element) { + return acc.concat(pairForList("" + key + "[]", element)); + }, []); + default: + return [[key, object]]; + } + })(); + }; + formData = new Batman.container.FormData(); + _ref = pairForList("", data, true); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + _ref1 = _ref[_i], key = _ref1[0], val = _ref1[1]; + formData.append(key, val); + } + return formData; + }; + + Request.dataHasFileUploads = dataHasFileUploads = function(data) { + var k, type, v, _i, _len; + if ((typeof File !== "undefined" && File !== null) && data instanceof File) { + return true; + } + type = Batman.typeOf(data); + switch (type) { + case 'Object': + for (k in data) { + v = data[k]; + if (dataHasFileUploads(v)) { + return true; + } + } + break; + case 'Array': + for (_i = 0, _len = data.length; _i < _len; _i++) { + v = data[_i]; + if (dataHasFileUploads(v)) { + return true; + } + } + } + return false; + }; + + Request.wrapAccessor('method', function(core) { + return { + set: function(k, val) { + return core.set.call(this, k, val != null ? typeof val.toUpperCase === "function" ? val.toUpperCase() : void 0 : void 0); + } + }; + }); + + Request.prototype.method = 'GET'; + + Request.prototype.hasFileUploads = function() { + return dataHasFileUploads(this.data); + }; + + Request.prototype.contentType = 'application/x-www-form-urlencoded'; + + Request.prototype.autosend = true; + + function Request(options) { + var handler, handlers, k, _ref; + handlers = {}; + for (k in options) { + handler = options[k]; + if (!(k === 'success' || k === 'error' || k === 'loading' || k === 'loaded')) { + continue; + } + handlers[k] = handler; + delete options[k]; + } + Request.__super__.constructor.call(this, options); + for (k in handlers) { + handler = handlers[k]; + this.on(k, handler); + } + if (((_ref = this.get('url')) != null ? _ref.length : void 0) > 0) { + if (this.autosend) { + this.send(); + } + } else { + this.observe('url', function(url) { + if (url != null) { + return this.send(); + } + }); + } + } + + Request.prototype.send = function() { + return Batman.developer.error("Please source a dependency file for a request implementation"); + }; + + return Request; + + })(Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __slice = [].slice; + + Batman.Navigator = (function() { + + Navigator.defaultClass = function() { + if (Batman.config.usePushState && Batman.PushStateNavigator.isSupported()) { + return Batman.PushStateNavigator; + } else { + return Batman.HashbangNavigator; + } + }; + + Navigator.forApp = function(app) { + return new (this.defaultClass())(app); + }; + + function Navigator(app) { + this.app = app; + this.handleCurrentLocation = __bind(this.handleCurrentLocation, this); + + } + + Navigator.prototype.start = function() { + var _this = this; + if (typeof window === 'undefined') { + return; + } + if (this.started) { + return; + } + this.started = true; + this.startWatching(); + Batman.currentApp.prevent('ready'); + return Batman.setImmediate(function() { + if (_this.started && Batman.currentApp) { + _this.handleCurrentLocation(); + return Batman.currentApp.allowAndFire('ready'); + } + }); + }; + + Navigator.prototype.stop = function() { + this.stopWatching(); + return this.started = false; + }; + + Navigator.prototype.handleLocation = function(location) { + var path; + path = this.pathFromLocation(location); + if (path === this.cachedPath) { + return; + } + return this.dispatch(path); + }; + + Navigator.prototype.handleCurrentLocation = function() { + return this.handleLocation(window.location); + }; + + Navigator.prototype.dispatch = function(params) { + return this.cachedPath = this.app.get('dispatcher').dispatch(params); + }; + + Navigator.prototype.push = function(params) { + var path; + path = this.dispatch(params); + this.pushState(null, '', path); + return path; + }; + + Navigator.prototype.replace = function(params) { + var path; + path = this.dispatch(params); + this.replaceState(null, '', path); + return path; + }; + + Navigator.prototype.redirect = Navigator.prototype.push; + + Navigator.prototype.normalizePath = function() { + var i, seg, segments; + segments = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + segments = (function() { + var _i, _len, _results; + _results = []; + for (i = _i = 0, _len = segments.length; _i < _len; i = ++_i) { + seg = segments[i]; + _results.push(("" + seg).replace(/^(?!\/)/, '/').replace(/\/+$/, '')); + } + return _results; + })(); + return segments.join('') || '/'; + }; + + Navigator.normalizePath = Navigator.prototype.normalizePath; + + return Navigator; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PushStateNavigator = (function(_super) { + + __extends(PushStateNavigator, _super); + + function PushStateNavigator() { + return PushStateNavigator.__super__.constructor.apply(this, arguments); + } + + PushStateNavigator.isSupported = function() { + var _ref; + return (typeof window !== "undefined" && window !== null ? (_ref = window.history) != null ? _ref.pushState : void 0 : void 0) != null; + }; + + PushStateNavigator.prototype.startWatching = function() { + return Batman.addEventListener(window, 'popstate', this.handleCurrentLocation); + }; + + PushStateNavigator.prototype.stopWatching = function() { + return Batman.removeEventListener(window, 'popstate', this.handleCurrentLocation); + }; + + PushStateNavigator.prototype.pushState = function(stateObject, title, path) { + return window.history.pushState(stateObject, title, this.linkTo(path)); + }; + + PushStateNavigator.prototype.replaceState = function(stateObject, title, path) { + return window.history.replaceState(stateObject, title, this.linkTo(path)); + }; + + PushStateNavigator.prototype.linkTo = function(url) { + return this.normalizePath(Batman.config.pathPrefix, url); + }; + + PushStateNavigator.prototype.pathFromLocation = function(location) { + var fullPath, prefixPattern; + fullPath = "" + (location.pathname || '') + (location.search || ''); + prefixPattern = new RegExp("^" + (this.normalizePath(Batman.config.pathPrefix))); + return this.normalizePath(fullPath.replace(prefixPattern, '')); + }; + + PushStateNavigator.prototype.handleLocation = function(location) { + var hashbangPath, path; + path = this.pathFromLocation(location); + if (path === '/' && (hashbangPath = Batman.HashbangNavigator.prototype.pathFromLocation(location)) !== '/') { + return this.replace(hashbangPath); + } else { + return PushStateNavigator.__super__.handleLocation.apply(this, arguments); + } + }; + + return PushStateNavigator; + + })(Batman.Navigator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HashbangNavigator = (function(_super) { + + __extends(HashbangNavigator, _super); + + function HashbangNavigator() { + return HashbangNavigator.__super__.constructor.apply(this, arguments); + } + + HashbangNavigator.prototype.HASH_PREFIX = '#!'; + + if ((typeof window !== "undefined" && window !== null) && 'onhashchange' in window) { + HashbangNavigator.prototype.startWatching = function() { + return Batman.addEventListener(window, 'hashchange', this.handleCurrentLocation); + }; + HashbangNavigator.prototype.stopWatching = function() { + return Batman.removeEventListener(window, 'hashchange', this.handleCurrentLocation); + }; + } else { + HashbangNavigator.prototype.startWatching = function() { + return this.interval = setInterval(this.handleCurrentLocation, 100); + }; + HashbangNavigator.prototype.stopWatching = function() { + return this.interval = clearInterval(this.interval); + }; + } + + HashbangNavigator.prototype.pushState = function(stateObject, title, path) { + return window.location.hash = this.linkTo(path); + }; + + HashbangNavigator.prototype.replaceState = function(stateObject, title, path) { + var loc; + loc = window.location; + return loc.replace("" + loc.pathname + loc.search + (this.linkTo(path))); + }; + + HashbangNavigator.prototype.linkTo = function(url) { + return this.HASH_PREFIX + url; + }; + + HashbangNavigator.prototype.pathFromLocation = function(location) { + var hash; + hash = location.hash; + if ((hash != null ? hash.substr(0, 2) : void 0) === this.HASH_PREFIX) { + return this.normalizePath(hash.substr(2)); + } else { + return '/'; + } + }; + + HashbangNavigator.prototype.handleLocation = function(location) { + var realPath; + if (!Batman.config.usePushState) { + return HashbangNavigator.__super__.handleLocation.apply(this, arguments); + } + realPath = Batman.PushStateNavigator.prototype.pathFromLocation(location); + if (realPath === '/') { + return HashbangNavigator.__super__.handleLocation.apply(this, arguments); + } else { + return location.replace(this.normalizePath("" + Batman.config.pathPrefix + (this.linkTo(realPath)))); + } + }; + + return HashbangNavigator; + + })(Batman.Navigator); + +}).call(this); + +(function() { + + Batman.RouteMap = (function() { + + RouteMap.prototype.memberRoute = null; + + RouteMap.prototype.collectionRoute = null; + + function RouteMap() { + this.childrenByOrder = []; + this.childrenByName = {}; + } + + RouteMap.prototype.routeForParams = function(params) { + var route, _i, _len, _ref; + _ref = this.childrenByOrder; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + route = _ref[_i]; + if (route.test(params)) { + return route; + } + } + return void 0; + }; + + RouteMap.prototype.addRoute = function(name, route) { + var base, names, + _this = this; + this.childrenByOrder.push(route); + if (name.length > 0 && (names = name.split('.')).length > 0) { + base = names.shift(); + if (!this.childrenByName[base]) { + this.childrenByName[base] = new Batman.RouteMap; + } + this.childrenByName[base].addRoute(names.join('.'), route); + } else { + if (route.get('member')) { + Batman.developer["do"](function() { + if (_this.memberRoute) { + return Batman.developer.error("Member route with name " + name + " already exists!"); + } + }); + this.memberRoute = route; + } else { + Batman.developer["do"](function() { + if (_this.collectionRoute) { + return Batman.developer.error("Collection route with name " + name + " already exists!"); + } + }); + this.collectionRoute = route; + } + } + return true; + }; + + return RouteMap; + + })(); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.RouteMapBuilder = (function() { + + RouteMapBuilder.BUILDER_FUNCTIONS = ['resources', 'member', 'collection', 'route', 'root']; + + RouteMapBuilder.ROUTES = { + index: { + cardinality: 'collection', + path: function(resource) { + return resource; + }, + name: function(resource) { + return resource; + } + }, + "new": { + cardinality: 'collection', + path: function(resource) { + return "" + resource + "/new"; + }, + name: function(resource) { + return "" + resource + ".new"; + } + }, + show: { + cardinality: 'member', + path: function(resource) { + return "" + resource + "/:id"; + }, + name: function(resource) { + return resource; + } + }, + edit: { + cardinality: 'member', + path: function(resource) { + return "" + resource + "/:id/edit"; + }, + name: function(resource) { + return "" + resource + ".edit"; + } + }, + collection: { + cardinality: 'collection', + path: function(resource, name) { + return "" + resource + "/" + name; + }, + name: function(resource, name) { + return "" + resource + "." + name; + } + }, + member: { + cardinality: 'member', + path: function(resource, name) { + return "" + resource + "/:id/" + name; + }, + name: function(resource, name) { + return "" + resource + "." + name; + } + } + }; + + function RouteMapBuilder(app, routeMap, parent, baseOptions) { + this.app = app; + this.routeMap = routeMap; + this.parent = parent; + this.baseOptions = baseOptions != null ? baseOptions : {}; + if (this.parent) { + this.rootPath = this.parent._nestingPath(); + this.rootName = this.parent._nestingName(); + } else { + this.rootPath = ''; + this.rootName = ''; + } + } + + RouteMapBuilder.prototype.resources = function() { + var action, actions, arg, args, as, callback, childBuilder, controller, included, k, options, path, resourceName, resourceNames, resourceRoot, routeOptions, routeTemplate, v, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + resourceNames = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = args.length; _i < _len; _i++) { + arg = args[_i]; + if (typeof arg === 'string') { + _results.push(arg); + } + } + return _results; + })(); + if (typeof args[args.length - 1] === 'function') { + callback = args.pop(); + } + if (typeof args[args.length - 1] === 'object') { + options = args.pop(); + } else { + options = {}; + } + actions = { + index: true, + "new": true, + show: true, + edit: true + }; + if (options.except) { + _ref = options.except; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + actions[k] = false; + } + delete options.except; + } else if (options.only) { + for (k in actions) { + v = actions[k]; + actions[k] = false; + } + _ref1 = options.only; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + k = _ref1[_j]; + actions[k] = true; + } + delete options.only; + } + for (_k = 0, _len2 = resourceNames.length; _k < _len2; _k++) { + resourceName = resourceNames[_k]; + resourceRoot = Batman.helpers.pluralize(resourceName); + controller = Batman.helpers.camelize(resourceRoot, true); + childBuilder = this._childBuilder({ + controller: controller + }); + if (callback != null) { + callback.call(childBuilder); + } + for (action in actions) { + included = actions[action]; + if (!(included)) { + continue; + } + routeTemplate = this.constructor.ROUTES[action]; + as = routeTemplate.name(resourceRoot); + path = routeTemplate.path(resourceRoot); + routeOptions = Batman.extend({ + controller: controller, + action: action, + path: path, + as: as + }, options); + childBuilder[routeTemplate.cardinality](action, routeOptions); + } + } + return true; + }; + + RouteMapBuilder.prototype.member = function() { + return this._addRoutesWithCardinality.apply(this, ['member'].concat(__slice.call(arguments))); + }; + + RouteMapBuilder.prototype.collection = function() { + return this._addRoutesWithCardinality.apply(this, ['collection'].concat(__slice.call(arguments))); + }; + + RouteMapBuilder.prototype.root = function(signature, options) { + return this.route('/', signature, options); + }; + + RouteMapBuilder.prototype.route = function(path, signature, options, callback) { + if (!callback) { + if (typeof options === 'function') { + callback = options; + options = void 0; + } else if (typeof signature === 'function') { + callback = signature; + signature = void 0; + } + } + if (!options) { + if (typeof signature === 'string') { + options = { + signature: signature + }; + } else { + options = signature; + } + options || (options = {}); + } else { + if (signature) { + options.signature = signature; + } + } + if (callback) { + options.callback = callback; + } + options.as || (options.as = this._nameFromPath(path)); + options.path = path; + return this._addRoute(options); + }; + + RouteMapBuilder.prototype._addRoutesWithCardinality = function() { + var cardinality, name, names, options, resourceRoot, routeOptions, routeTemplate, _i, _j, _len; + cardinality = arguments[0], names = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), options = arguments[_i++]; + if (typeof options === 'string') { + names.push(options); + options = {}; + } + options = Batman.extend({}, this.baseOptions, options); + options[cardinality] = true; + routeTemplate = this.constructor.ROUTES[cardinality]; + resourceRoot = options.controller; + for (_j = 0, _len = names.length; _j < _len; _j++) { + name = names[_j]; + routeOptions = Batman.extend({ + action: name + }, options); + if (routeOptions.path == null) { + routeOptions.path = routeTemplate.path(resourceRoot, name); + } + if (routeOptions.as == null) { + routeOptions.as = routeTemplate.name(resourceRoot, name); + } + this._addRoute(routeOptions); + } + return true; + }; + + RouteMapBuilder.prototype._addRoute = function(options) { + var klass, name, path, route; + if (options == null) { + options = {}; + } + path = this.rootPath + options.path; + name = this.rootName + Batman.helpers.camelize(options.as, true); + delete options.as; + delete options.path; + klass = options.callback ? Batman.CallbackActionRoute : Batman.ControllerActionRoute; + options.app = this.app; + route = new klass(path, options); + return this.routeMap.addRoute(name, route); + }; + + RouteMapBuilder.prototype._nameFromPath = function(path) { + path = path.replace(Batman.Route.regexps.namedOrSplat, '').replace(/\/+/g, '.').replace(/(^\.)|(\.$)/g, ''); + return path; + }; + + RouteMapBuilder.prototype._nestingPath = function() { + var nestingParam, nestingSegment; + if (!this.parent) { + return ""; + } else { + nestingParam = ":" + Batman.helpers.singularize(this.baseOptions.controller) + "Id"; + nestingSegment = Batman.helpers.underscore(this.baseOptions.controller); + return "" + (this.parent._nestingPath()) + "/" + nestingSegment + "/" + nestingParam + "/"; + } + }; + + RouteMapBuilder.prototype._nestingName = function() { + if (!this.parent) { + return ""; + } else { + return this.baseOptions.controller + "."; + } + }; + + RouteMapBuilder.prototype._childBuilder = function(baseOptions) { + if (baseOptions == null) { + baseOptions = {}; + } + return new Batman.RouteMapBuilder(this.app, this.routeMap, this, baseOptions); + }; + + return RouteMapBuilder; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.App = (function(_super) { + var name, _fn, _i, _len, _ref, + _this = this; + + __extends(App, _super); + + function App() { + return App.__super__.constructor.apply(this, arguments); + } + + App.classAccessor('currentParams', { + get: function() { + return new Batman.Hash; + }, + 'final': true + }); + + App.classAccessor('paramsManager', { + get: function() { + var nav, params; + if (!(nav = this.get('navigator'))) { + return; + } + params = this.get('currentParams'); + return params.replacer = new Batman.ParamsReplacer(nav, params); + }, + 'final': true + }); + + App.classAccessor('paramsPusher', { + get: function() { + var nav, params; + if (!(nav = this.get('navigator'))) { + return; + } + params = this.get('currentParams'); + return params.pusher = new Batman.ParamsPusher(nav, params); + }, + 'final': true + }); + + App.classAccessor('routes', function() { + return new Batman.NamedRouteQuery(this.get('routeMap')); + }); + + App.classAccessor('routeMap', function() { + return new Batman.RouteMap; + }); + + App.classAccessor('routeMapBuilder', function() { + return new Batman.RouteMapBuilder(this, this.get('routeMap')); + }); + + App.classAccessor('dispatcher', function() { + return new Batman.Dispatcher(this, this.get('routeMap')); + }); + + App.classAccessor('controllers', function() { + return this.get('dispatcher.controllers'); + }); + + App.classAccessor('_renderContext', function() { + return Batman.RenderContext.base.descend(this); + }); + + App.requirePath = ''; + + Batman.developer["do"](function() { + App.require = function() { + var base, name, names, path, _i, _len, + _this = this; + path = arguments[0], names = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + base = this.requirePath + path; + for (_i = 0, _len = names.length; _i < _len; _i++) { + name = names[_i]; + this.prevent('run'); + path = base + '/' + name + '.coffee'; + new Batman.Request({ + url: path, + type: 'html', + success: function(response) { + CoffeeScript["eval"](response); + _this.allow('run'); + if (!_this.isPrevented('run')) { + _this.fire('loaded'); + } + if (_this.wantsToRun) { + return _this.run(); + } + } + }); + } + return this; + }; + App.controller = function() { + var names; + names = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + names = names.map(function(n) { + return n + '_controller'; + }); + return this.require.apply(this, ['controllers'].concat(__slice.call(names))); + }; + App.model = function() { + return this.require.apply(this, ['models'].concat(__slice.call(arguments))); + }; + return App.view = function() { + return this.require.apply(this, ['views'].concat(__slice.call(arguments))); + }; + }); + + App.layout = void 0; + + _ref = Batman.RouteMapBuilder.BUILDER_FUNCTIONS; + _fn = function(name) { + return App[name] = function() { + var _ref1; + return (_ref1 = this.get('routeMapBuilder'))[name].apply(_ref1, arguments); + }; + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + name = _ref[_i]; + _fn(name); + } + + App.event('ready').oneShot = true; + + App.event('run').oneShot = true; + + App.run = function() { + var layout, layoutClass, + _this = this; + if (Batman.currentApp) { + if (Batman.currentApp === this) { + return; + } + Batman.currentApp.stop(); + } + if (this.hasRun) { + return false; + } + if (this.isPrevented('run')) { + this.wantsToRun = true; + return false; + } else { + delete this.wantsToRun; + } + Batman.currentApp = this; + Batman.App.set('current', this); + if (this.get('dispatcher') == null) { + this.set('dispatcher', new Batman.Dispatcher(this, this.get('routeMap'))); + this.set('controllers', this.get('dispatcher.controllers')); + } + if (this.get('navigator') == null) { + this.set('navigator', Batman.Navigator.forApp(this)); + this.on('run', function() { + Batman.navigator = _this.get('navigator'); + if (Object.keys(_this.get('dispatcher').routeMap).length > 0) { + return Batman.navigator.start(); + } + }); + } + this.observe('layout', function(layout) { + return layout != null ? layout.on('ready', function() { + return _this.fire('ready'); + }) : void 0; + }); + layout = this.get('layout'); + if (layout) { + if (typeof layout === 'string') { + layoutClass = this[Batman.helpers.camelize(layout) + 'View']; + } + } else { + if (layout !== null) { + layoutClass = Batman.View; + } + } + if (layoutClass) { + layout = this.set('layout', new layoutClass({ + context: this, + node: document + })); + } + this.hasRun = true; + this.fire('run'); + return this; + }; + + App.event('ready').oneShot = true; + + App.event('stop').oneShot = true; + + App.stop = function() { + var _ref1; + if ((_ref1 = this.navigator) != null) { + _ref1.stop(); + } + Batman.navigator = null; + this.hasRun = false; + this.fire('stop'); + return this; + }; + + return App; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + + Batman.Association = (function() { + + Association.prototype.associationType = ''; + + Association.prototype.isPolymorphic = false; + + Association.prototype.defaultOptions = { + saveInline: true, + autoload: true, + nestUrl: false + }; + + function Association(model, label, options) { + var defaultOptions, encoder, getAccessor, self; + this.model = model; + this.label = label; + if (options == null) { + options = {}; + } + defaultOptions = { + namespace: Batman.currentApp, + name: Batman.helpers.camelize(Batman.helpers.singularize(this.label)) + }; + this.options = Batman.extend(defaultOptions, this.defaultOptions, options); + encoder = this.encoder(); + if (!this.options.saveInline) { + encoder.encode = false; + } + this.model.encode(label, encoder); + self = this; + getAccessor = function() { + return self.getAccessor.call(this, self, this.model, this.label); + }; + this.model.accessor(this.label, { + get: getAccessor, + set: model.defaultAccessor.set, + unset: model.defaultAccessor.unset + }); + if (this.options.nestUrl) { + if (!(this.model.urlNestsUnder != null)) { + developer.error("You must persist the the model " + this.model.constructor.name + " to use the url helpers on an association"); + } + this.model.urlNestsUnder(Batman.helpers.underscore(this.getRelatedModel().get('resourceName'))); + } + } + + Association.prototype.getRelatedModel = function() { + var className, relatedModel, scope; + scope = this.options.namespace || Batman.currentApp; + className = this.options.name; + relatedModel = scope != null ? scope[className] : void 0; + Batman.developer["do"](function() { + if ((Batman.currentApp != null) && !relatedModel) { + return Batman.developer.warn("Related model " + className + " hasn't loaded yet."); + } + }); + return relatedModel; + }; + + Association.prototype.getFromAttributes = function(record) { + return record.get("attributes." + this.label); + }; + + Association.prototype.setIntoAttributes = function(record, value) { + return record.get('attributes').set(this.label, value); + }; + + Association.prototype.encoder = function() { + return Batman.developer.error("You must override encoder in Batman.Association subclasses."); + }; + + Association.prototype.setIndex = function() { + return Batman.developer.error("You must override setIndex in Batman.Association subclasses."); + }; + + Association.prototype.inverse = function() { + var inverse, relatedAssocs, + _this = this; + if (relatedAssocs = this.getRelatedModel()._batman.get('associations')) { + if (this.options.inverseOf) { + return relatedAssocs.getByLabel(this.options.inverseOf); + } + inverse = null; + relatedAssocs.forEach(function(label, assoc) { + if (assoc.getRelatedModel() === _this.model) { + return inverse = assoc; + } + }); + return inverse; + } + }; + + Association.prototype.reset = function() { + delete this.index; + return true; + }; + + return Association; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PluralAssociation = (function(_super) { + + __extends(PluralAssociation, _super); + + function PluralAssociation() { + return PluralAssociation.__super__.constructor.apply(this, arguments); + } + + PluralAssociation.prototype.isSingular = false; + + PluralAssociation.prototype.setForRecord = Batman.Property.wrapTrackingPrevention(function(record) { + var id; + if (id = record.get(this.primaryKey)) { + return this.setIndex().get(id); + } else { + return new Batman.AssociationSet(void 0, this); + } + }); + + PluralAssociation.prototype.getAccessor = function(self, model, label) { + var relatedRecords, setInAttributes, + _this = this; + if (!self.getRelatedModel()) { + return; + } + if (setInAttributes = self.getFromAttributes(this)) { + return setInAttributes; + } else { + relatedRecords = self.setForRecord(this); + self.setIntoAttributes(this, relatedRecords); + Batman.Property.withoutTracking(function() { + if (self.options.autoload && !_this.isNew() && !relatedRecords.loaded) { + return relatedRecords.load(function(error, records) { + if (error) { + throw error; + } + }); + } + }); + return relatedRecords; + } + }; + + PluralAssociation.prototype.setIndex = function() { + this.index || (this.index = new Batman.AssociationSetIndex(this, this[this.indexRelatedModelOn])); + return this.index; + }; + + return PluralAssociation; + + })(Batman.Association); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HasManyAssociation = (function(_super) { + + __extends(HasManyAssociation, _super); + + HasManyAssociation.prototype.associationType = 'hasMany'; + + HasManyAssociation.prototype.indexRelatedModelOn = 'foreignKey'; + + function HasManyAssociation(model, label, options) { + if (options != null ? options.as : void 0) { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.PolymorphicHasManyAssociation, arguments, function(){}); + } + HasManyAssociation.__super__.constructor.apply(this, arguments); + this.primaryKey = this.options.primaryKey || "id"; + this.foreignKey = this.options.foreignKey || ("" + (Batman.helpers.underscore(model.get('resourceName'))) + "_id"); + } + + HasManyAssociation.prototype.apply = function(baseSaveError, base) { + var relations, set, + _this = this; + if (!baseSaveError) { + if (relations = this.getFromAttributes(base)) { + relations.forEach(function(model) { + return model.set(_this.foreignKey, base.get(_this.primaryKey)); + }); + } + base.set(this.label, set = this.setForRecord(base)); + if (base.lifecycle.get('state') === 'creating') { + return set.markAsLoaded(); + } + } + }; + + HasManyAssociation.prototype.encoder = function() { + var association; + association = this; + return { + encode: function(relationSet, _, __, record) { + var jsonArray; + if (!association.options.saveInline) { + return; + } + if (relationSet != null) { + jsonArray = []; + relationSet.forEach(function(relation) { + var relationJSON; + relationJSON = relation.toJSON(); + if (!association.inverse() || association.inverse().options.encodeForeignKey) { + relationJSON[association.foreignKey] = record.get(association.primaryKey); + } + return jsonArray.push(relationJSON); + }); + } + return jsonArray; + }, + decode: function(data, key, _, __, parentRecord) { + var existingRecord, existingRelations, jsonObject, newRelations, record, relatedModel, savedRecord, _i, _len; + if (relatedModel = association.getRelatedModel()) { + existingRelations = association.getFromAttributes(parentRecord) || association.setForRecord(parentRecord); + newRelations = existingRelations.filter(function(relation) { + return relation.isNew(); + }).toArray(); + for (_i = 0, _len = data.length; _i < _len; _i++) { + jsonObject = data[_i]; + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + existingRecord = relatedModel.get('loaded').indexedByUnique('id').get(record.get('id')); + if (existingRecord != null) { + existingRecord._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + record = existingRecord; + } else { + if (newRelations.length > 0) { + savedRecord = newRelations.shift(); + savedRecord._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + record = savedRecord; + } + } + record = relatedModel._mapIdentity(record); + existingRelations.add(record); + if (association.options.inverseOf) { + record.set(association.options.inverseOf, parentRecord); + } + } + existingRelations.markAsLoaded(); + } else { + Batman.developer.error("Can't decode model " + association.options.name + " because it hasn't been loaded yet!"); + } + return existingRelations; + } + }; + }; + + return HasManyAssociation; + + })(Batman.PluralAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicHasManyAssociation = (function(_super) { + + __extends(PolymorphicHasManyAssociation, _super); + + PolymorphicHasManyAssociation.prototype.isPolymorphic = true; + + function PolymorphicHasManyAssociation(model, label, options) { + options.inverseOf = this.foreignLabel = options.as; + delete options.as; + options.foreignKey || (options.foreignKey = "" + this.foreignLabel + "_id"); + PolymorphicHasManyAssociation.__super__.constructor.call(this, model, label, options); + this.foreignTypeKey = options.foreignTypeKey || ("" + this.foreignLabel + "_type"); + this.model.encode(this.foreignTypeKey); + } + + PolymorphicHasManyAssociation.prototype.apply = function(baseSaveError, base) { + var relations, + _this = this; + if (!baseSaveError) { + if (relations = this.getFromAttributes(base)) { + PolymorphicHasManyAssociation.__super__.apply.apply(this, arguments); + relations.forEach(function(model) { + return model.set(_this.foreignTypeKey, _this.modelType()); + }); + } + } + return true; + }; + + PolymorphicHasManyAssociation.prototype.getRelatedModelForType = function() { + return this.getRelatedModel(); + }; + + PolymorphicHasManyAssociation.prototype.modelType = function() { + return this.model.get('resourceName'); + }; + + PolymorphicHasManyAssociation.prototype.setIndex = function() { + if (!this.typeIndex) { + this.typeIndex = new Batman.PolymorphicAssociationSetIndex(this, this.modelType(), this[this.indexRelatedModelOn]); + } + return this.typeIndex; + }; + + PolymorphicHasManyAssociation.prototype.encoder = function() { + var association, encoder; + association = this; + encoder = PolymorphicHasManyAssociation.__super__.encoder.apply(this, arguments); + encoder.encode = function(relationSet, _, __, record) { + var jsonArray; + if (association._beingEncoded) { + return; + } + association._beingEncoded = true; + if (!association.options.saveInline) { + return; + } + if (relationSet != null) { + jsonArray = []; + relationSet.forEach(function(relation) { + var relationJSON; + relationJSON = relation.toJSON(); + relationJSON[association.foreignKey] = record.get(association.primaryKey); + relationJSON[association.foreignTypeKey] = association.modelType(); + return jsonArray.push(relationJSON); + }); + } + delete association._beingEncoded; + return jsonArray; + }; + return encoder; + }; + + return PolymorphicHasManyAssociation; + + })(Batman.HasManyAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.SingularAssociation = (function(_super) { + + __extends(SingularAssociation, _super); + + function SingularAssociation() { + return SingularAssociation.__super__.constructor.apply(this, arguments); + } + + SingularAssociation.prototype.isSingular = true; + + SingularAssociation.prototype.getAccessor = function(self, model, label) { + var proxy, recordInAttributes; + if (recordInAttributes = self.getFromAttributes(this)) { + return recordInAttributes; + } + if (self.getRelatedModel()) { + proxy = this.associationProxy(self); + Batman.Property.withoutTracking(function() { + if (!proxy.get('loaded') && self.options.autoload) { + return proxy.load(); + } + }); + return proxy; + } + }; + + SingularAssociation.prototype.setIndex = function() { + this.index || (this.index = new Batman.UniqueAssociationSetIndex(this, this[this.indexRelatedModelOn])); + return this.index; + }; + + return SingularAssociation; + + })(Batman.Association); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HasOneAssociation = (function(_super) { + + __extends(HasOneAssociation, _super); + + HasOneAssociation.prototype.associationType = 'hasOne'; + + HasOneAssociation.prototype.proxyClass = Batman.HasOneProxy; + + HasOneAssociation.prototype.indexRelatedModelOn = 'foreignKey'; + + function HasOneAssociation() { + HasOneAssociation.__super__.constructor.apply(this, arguments); + this.primaryKey = this.options.primaryKey || "id"; + this.foreignKey = this.options.foreignKey || ("" + (Batman.helpers.underscore(this.model.get('resourceName'))) + "_id"); + } + + HasOneAssociation.prototype.apply = function(baseSaveError, base) { + var relation; + if (relation = this.getFromAttributes(base)) { + return relation.set(this.foreignKey, base.get(this.primaryKey)); + } + }; + + HasOneAssociation.prototype.encoder = function() { + var association; + association = this; + return { + encode: function(val, key, object, record) { + var json; + if (!association.options.saveInline) { + return; + } + if (json = val.toJSON()) { + json[association.foreignKey] = record.get(association.primaryKey); + } + return json; + }, + decode: function(data, _, __, ___, parentRecord) { + var record, relatedModel; + relatedModel = association.getRelatedModel(); + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(data); + }); + if (association.options.inverseOf) { + record.set(association.options.inverseOf, parentRecord); + } + record = relatedModel._mapIdentity(record); + return record; + } + }; + }; + + return HasOneAssociation; + + })(Batman.SingularAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.BelongsToAssociation = (function(_super) { + + __extends(BelongsToAssociation, _super); + + BelongsToAssociation.prototype.associationType = 'belongsTo'; + + BelongsToAssociation.prototype.proxyClass = Batman.BelongsToProxy; + + BelongsToAssociation.prototype.indexRelatedModelOn = 'primaryKey'; + + BelongsToAssociation.prototype.defaultOptions = { + saveInline: false, + autoload: true, + encodeForeignKey: true + }; + + function BelongsToAssociation(model, label, options) { + if (options != null ? options.polymorphic : void 0) { + delete options.polymorphic; + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.PolymorphicBelongsToAssociation, arguments, function(){}); + } + BelongsToAssociation.__super__.constructor.apply(this, arguments); + this.foreignKey = this.options.foreignKey || ("" + this.label + "_id"); + this.primaryKey = this.options.primaryKey || "id"; + if (this.options.encodeForeignKey) { + this.model.encode(this.foreignKey); + } + } + + BelongsToAssociation.prototype.encoder = function() { + var association, encoder; + association = this; + encoder = { + encode: false, + decode: function(data, _, __, ___, childRecord) { + var inverse, record, relatedModel; + relatedModel = association.getRelatedModel(); + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(data); + }); + record = relatedModel._mapIdentity(record); + if (association.options.inverseOf) { + if (inverse = association.inverse()) { + if (inverse instanceof Batman.HasManyAssociation) { + childRecord.set(association.foreignKey, record.get(association.primaryKey)); + } else { + record.set(inverse.label, childRecord); + } + } + } + childRecord.set(association.label, record); + return record; + } + }; + if (this.options.saveInline) { + encoder.encode = function(val) { + return val.toJSON(); + }; + } + return encoder; + }; + + BelongsToAssociation.prototype.apply = function(base) { + var foreignValue, model; + if (model = base.get(this.label)) { + foreignValue = model.get(this.primaryKey); + if (foreignValue !== void 0) { + return base.set(this.foreignKey, foreignValue); + } + } + }; + + return BelongsToAssociation; + + })(Batman.SingularAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicBelongsToAssociation = (function(_super) { + + __extends(PolymorphicBelongsToAssociation, _super); + + PolymorphicBelongsToAssociation.prototype.isPolymorphic = true; + + PolymorphicBelongsToAssociation.prototype.proxyClass = Batman.PolymorphicBelongsToProxy; + + PolymorphicBelongsToAssociation.prototype.defaultOptions = Batman.mixin({}, Batman.BelongsToAssociation.prototype.defaultOptions, { + encodeForeignTypeKey: true + }); + + function PolymorphicBelongsToAssociation() { + PolymorphicBelongsToAssociation.__super__.constructor.apply(this, arguments); + this.foreignTypeKey = this.options.foreignTypeKey || ("" + this.label + "_type"); + if (this.options.encodeForeignTypeKey) { + this.model.encode(this.foreignTypeKey); + } + this.typeIndicies = {}; + } + + PolymorphicBelongsToAssociation.prototype.getRelatedModel = false; + + PolymorphicBelongsToAssociation.prototype.setIndex = false; + + PolymorphicBelongsToAssociation.prototype.inverse = false; + + PolymorphicBelongsToAssociation.prototype.apply = function(base) { + var foreignTypeValue, instanceOrProxy, model; + PolymorphicBelongsToAssociation.__super__.apply.apply(this, arguments); + if (instanceOrProxy = base.get(this.label)) { + if (instanceOrProxy instanceof Batman.AssociationProxy) { + model = instanceOrProxy.association.model; + } else { + model = instanceOrProxy.constructor; + } + foreignTypeValue = model.get('resourceName'); + return base.set(this.foreignTypeKey, foreignTypeValue); + } + }; + + PolymorphicBelongsToAssociation.prototype.getAccessor = function(self, model, label) { + var proxy, recordInAttributes; + if (recordInAttributes = self.getFromAttributes(this)) { + return recordInAttributes; + } + if (self.getRelatedModelForType(this.get(self.foreignTypeKey))) { + proxy = this.associationProxy(self); + Batman.Property.withoutTracking(function() { + if (!proxy.get('loaded') && self.options.autoload) { + return proxy.load(); + } + }); + return proxy; + } + }; + + PolymorphicBelongsToAssociation.prototype.url = function(recordOptions) { + var ending, helper, id, inverse, root, type, _ref, _ref1; + type = (_ref = recordOptions.data) != null ? _ref[this.foreignTypeKey] : void 0; + if (type && (inverse = this.inverseForType(type))) { + root = Batman.helpers.pluralize(type).toLowerCase(); + id = (_ref1 = recordOptions.data) != null ? _ref1[this.foreignKey] : void 0; + helper = inverse.isSingular ? "singularize" : "pluralize"; + ending = Batman.helpers[helper](inverse.label); + return "/" + root + "/" + id + "/" + ending; + } + }; + + PolymorphicBelongsToAssociation.prototype.getRelatedModelForType = function(type) { + var relatedModel, scope; + scope = this.options.namespace || Batman.currentApp; + if (type) { + relatedModel = scope != null ? scope[type] : void 0; + relatedModel || (relatedModel = scope != null ? scope[Batman.helpers.camelize(type)] : void 0); + } + Batman.developer["do"](function() { + if ((Batman.currentApp != null) && !relatedModel) { + return Batman.developer.warn("Related model " + type + " for polymorhic association not found."); + } + }); + return relatedModel; + }; + + PolymorphicBelongsToAssociation.prototype.setIndexForType = function(type) { + var _base; + (_base = this.typeIndicies)[type] || (_base[type] = new Batman.PolymorphicUniqueAssociationSetIndex(this, type, this.primaryKey)); + return this.typeIndicies[type]; + }; + + PolymorphicBelongsToAssociation.prototype.inverseForType = function(type) { + var inverse, relatedAssocs, _ref, + _this = this; + if (relatedAssocs = (_ref = this.getRelatedModelForType(type)) != null ? _ref._batman.get('associations') : void 0) { + if (this.options.inverseOf) { + return relatedAssocs.getByLabel(this.options.inverseOf); + } + inverse = null; + relatedAssocs.forEach(function(label, assoc) { + if (assoc.getRelatedModel() === _this.model) { + return inverse = assoc; + } + }); + return inverse; + } + }; + + PolymorphicBelongsToAssociation.prototype.encoder = function() { + var association, encoder; + association = this; + encoder = { + encode: false, + decode: function(data, key, response, ___, childRecord) { + var foreignTypeValue, inverse, record, relatedModel; + foreignTypeValue = response[association.foreignTypeKey] || childRecord.get(association.foreignTypeKey); + relatedModel = association.getRelatedModelForType(foreignTypeValue); + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(data); + }); + record = relatedModel._mapIdentity(record); + if (association.options.inverseOf) { + if (inverse = association.inverseForType(foreignTypeValue)) { + if (inverse instanceof Batman.PolymorphicHasManyAssociation) { + childRecord.set(association.foreignKey, record.get(association.primaryKey)); + childRecord.set(association.foreignTypeKey, foreignTypeValue); + } else { + record.set(inverse.label, childRecord); + } + } + } + childRecord.set(association.label, record); + return record; + } + }; + if (this.options.saveInline) { + encoder.encode = function(val) { + return val.toJSON(); + }; + } + return encoder; + }; + + return PolymorphicBelongsToAssociation; + + })(Batman.BelongsToAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.Validator = (function(_super) { + + __extends(Validator, _super); + + function Validator() { + var mixins, options; + options = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + this.options = options; + Validator.__super__.constructor.apply(this, mixins); + } + + Validator.prototype.validate = function(record) { + return Batman.developer.error("You must override validate in Batman.Validator subclasses."); + }; + + Validator.prototype.format = function(key, messageKey, interpolations) { + return Batman.t("errors.messages." + messageKey, interpolations); + }; + + Validator.options = function() { + var options; + options = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + Batman.initializeObject(this); + if (this._batman.options) { + return this._batman.options.concat(options); + } else { + return this._batman.options = options; + } + }; + + Validator.matches = function(options) { + var key, results, shouldReturn, value, _ref, _ref1; + results = {}; + shouldReturn = false; + for (key in options) { + value = options[key]; + if (~((_ref = this._batman) != null ? (_ref1 = _ref.options) != null ? _ref1.indexOf(key) : void 0 : void 0)) { + results[key] = value; + shouldReturn = true; + } + } + if (shouldReturn) { + return results; + } + }; + + return Validator; + + })(Batman.Object); + +}).call(this); + +(function() { + + Batman.Validators = []; + + Batman.extend(Batman.translate.messages, { + errors: { + format: "%{attribute} %{message}", + messages: { + too_short: "must be at least %{count} characters", + too_long: "must be less than %{count} characters", + wrong_length: "must be %{count} characters", + blank: "can't be blank", + not_numeric: "must be a number", + not_matching: "is not valid" + } + } + }); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.RegExpValidator = (function(_super) { + + __extends(RegExpValidator, _super); + + RegExpValidator.options('regexp', 'pattern'); + + function RegExpValidator(options) { + var _ref; + this.regexp = (_ref = options.regexp) != null ? _ref : options.pattern; + RegExpValidator.__super__.constructor.apply(this, arguments); + } + + RegExpValidator.prototype.validateEach = function(errors, record, key, callback) { + var value; + value = record.get(key); + if ((value != null) && value !== '') { + if (!this.regexp.test(value)) { + errors.add(key, this.format(key, 'not_matching')); + } + } + return callback(); + }; + + return RegExpValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.RegExpValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PresenceValidator = (function(_super) { + + __extends(PresenceValidator, _super); + + function PresenceValidator() { + return PresenceValidator.__super__.constructor.apply(this, arguments); + } + + PresenceValidator.options('presence'); + + PresenceValidator.prototype.validateEach = function(errors, record, key, callback) { + var value; + value = record.get(key); + if (this.options.presence && (!(value != null) || value === '')) { + errors.add(key, this.format(key, 'blank')); + } + return callback(); + }; + + return PresenceValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.PresenceValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.NumericValidator = (function(_super) { + + __extends(NumericValidator, _super); + + function NumericValidator() { + return NumericValidator.__super__.constructor.apply(this, arguments); + } + + NumericValidator.options('numeric'); + + NumericValidator.prototype.validateEach = function(errors, record, key, callback) { + var value; + value = record.get(key); + if (this.options.numeric && isNaN(parseFloat(value))) { + errors.add(key, this.format(key, 'not_numeric')); + } + return callback(); + }; + + return NumericValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.NumericValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.LengthValidator = (function(_super) { + + __extends(LengthValidator, _super); + + LengthValidator.options('minLength', 'maxLength', 'length', 'lengthWithin', 'lengthIn'); + + function LengthValidator(options) { + var range; + if (range = options.lengthIn || options.lengthWithin) { + options.minLength = range[0]; + options.maxLength = range[1] || -1; + delete options.lengthWithin; + delete options.lengthIn; + } + LengthValidator.__super__.constructor.apply(this, arguments); + } + + LengthValidator.prototype.validateEach = function(errors, record, key, callback) { + var options, value, _ref; + options = this.options; + value = (_ref = record.get(key)) != null ? _ref : []; + if (options.minLength && value.length < options.minLength) { + errors.add(key, this.format(key, 'too_short', { + count: options.minLength + })); + } + if (options.maxLength && value.length > options.maxLength) { + errors.add(key, this.format(key, 'too_long', { + count: options.maxLength + })); + } + if (options.length && value.length !== options.length) { + errors.add(key, this.format(key, 'wrong_length', { + count: options.length + })); + } + return callback(); + }; + + return LengthValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.LengthValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ControllerActionFrame = (function(_super) { + + __extends(ControllerActionFrame, _super); + + ControllerActionFrame.prototype.operationOccurred = false; + + ControllerActionFrame.prototype.remainingOperations = 0; + + ControllerActionFrame.prototype.event('complete').oneShot = true; + + function ControllerActionFrame(options, onComplete) { + ControllerActionFrame.__super__.constructor.call(this, options); + this.on('complete', onComplete); + } + + ControllerActionFrame.prototype.startOperation = function(options) { + if (options == null) { + options = {}; + } + if (!options.internal) { + this.operationOccurred = true; + } + this._changeOperationsCounter(1); + return true; + }; + + ControllerActionFrame.prototype.finishOperation = function() { + this._changeOperationsCounter(-1); + return true; + }; + + ControllerActionFrame.prototype.startAndFinishOperation = function(options) { + this.startOperation(options); + this.finishOperation(options); + return true; + }; + + ControllerActionFrame.prototype._changeOperationsCounter = function(delta) { + var _ref; + this.remainingOperations += delta; + if (this.remainingOperations === 0) { + this.fire('complete'); + } + if ((_ref = this.parentFrame) != null) { + _ref._changeOperationsCounter(delta); + } + }; + + return ControllerActionFrame; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.InsertionBinding = (function(_super) { + + __extends(InsertionBinding, _super); + + InsertionBinding.prototype.isTwoWay = false; + + InsertionBinding.prototype.bindImmediately = false; + + function InsertionBinding(node, className, key, context, parentRenderer, invert) { + var result, + _this = this; + this.invert = invert != null ? invert : false; + this.placeholderNode = document.createComment("detached node " + (this.get('_batmanID'))); + result = InsertionBinding.__super__.constructor.apply(this, arguments); + Batman.DOM.onParseExit(this.node, function() { + _this.bind(); + if (_this.placeholderNode != null) { + return Batman.DOM.trackBinding(_this, _this.placeholderNode); + } + }); + result; + + } + + InsertionBinding.prototype.dataChange = function(value) { + var parentNode; + parentNode = this.placeholderNode.parentNode || this.node.parentNode; + if (!!value === !this.invert) { + if (!(this.node.parentNode != null)) { + Batman.DOM.insertBefore(parentNode, this.node, this.placeholderNode); + return parentNode.removeChild(this.placeholderNode); + } + } else { + parentNode.insertBefore(this.placeholderNode, this.node); + return Batman.DOM.removeNode(this.node); + } + }; + + InsertionBinding.prototype.die = function() { + if (this.dead) { + return; + } + InsertionBinding.__super__.die.apply(this, arguments); + if (!!this.get('filteredValue') === !this.invert) { + return Batman.DOM.destroyNode(this.placeholderNode); + } else { + return Batman.DOM.destroyNode(this.node); + } + }; + + return InsertionBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var isEmptyDataObject; + + isEmptyDataObject = function(obj) { + var name; + for (name in obj) { + return false; + } + return true; + }; + + Batman.extend(Batman, { + cache: {}, + uuid: 0, + expando: "batman" + Math.random().toString().replace(/\D/g, ''), + canDeleteExpando: (function() { + var div; + try { + div = document.createElement('div'); + return delete div.test; + } catch (e) { + return Batman.canDeleteExpando = false; + } + })(), + noData: { + "embed": true, + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + hasData: function(elem) { + elem = (elem.nodeType ? Batman.cache[elem[Batman.expando]] : elem[Batman.expando]); + return !!elem && !isEmptyDataObject(elem); + }, + data: function(elem, name, data, pvt) { + var cache, getByName, id, internalKey, ret, thisCache; + if (!Batman.acceptData(elem)) { + return; + } + internalKey = Batman.expando; + getByName = typeof name === "string"; + cache = Batman.cache; + id = elem[Batman.expando]; + if ((!id || (pvt && id && (cache[id] && !cache[id][internalKey]))) && getByName && data === void 0) { + return; + } + if (!id) { + if (elem.nodeType !== 3) { + elem[Batman.expando] = id = ++Batman.uuid; + } else { + id = Batman.expando; + } + } + if (!cache[id]) { + cache[id] = {}; + } + if (typeof name === "object" || typeof name === "function") { + if (pvt) { + cache[id][internalKey] = Batman.extend(cache[id][internalKey], name); + } else { + cache[id] = Batman.extend(cache[id], name); + } + } + thisCache = cache[id]; + if (pvt) { + thisCache[internalKey] || (thisCache[internalKey] = {}); + thisCache = thisCache[internalKey]; + } + if (data !== void 0) { + thisCache[name] = data; + } + if (getByName) { + ret = thisCache[name]; + } else { + ret = thisCache; + } + return ret; + }, + removeData: function(elem, name, pvt) { + var cache, id, internalCache, internalKey, isNode, thisCache; + if (!Batman.acceptData(elem)) { + return; + } + internalKey = Batman.expando; + isNode = elem.nodeType; + cache = Batman.cache; + id = elem[Batman.expando]; + if (!cache[id]) { + return; + } + if (name) { + thisCache = pvt ? cache[id][internalKey] : cache[id]; + if (thisCache) { + delete thisCache[name]; + if (!isEmptyDataObject(thisCache)) { + return; + } + } + } + if (pvt) { + delete cache[id][internalKey]; + if (!isEmptyDataObject(cache[id])) { + return; + } + } + internalCache = cache[id][internalKey]; + if (Batman.canDeleteExpando || !cache.setInterval) { + delete cache[id]; + } else { + cache[id] = null; + } + if (internalCache) { + cache[id] = {}; + return cache[id][internalKey] = internalCache; + } else { + if (Batman.canDeleteExpando) { + return delete elem[Batman.expando]; + } else if (elem.removeAttribute) { + return elem.removeAttribute(Batman.expando); + } else { + return elem[Batman.expando] = null; + } + } + }, + _data: function(elem, name, data) { + return Batman.data(elem, name, data, true); + }, + acceptData: function(elem) { + var match; + if (elem.nodeName) { + match = Batman.noData[elem.nodeName.toLowerCase()]; + if (match) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + return true; + } + }); + +}).call(this); + +(function() { + var buntUndefined, defaultAndOr, + __slice = [].slice; + + buntUndefined = function(f) { + return function(value) { + if (typeof value === 'undefined') { + return void 0; + } else { + return f.apply(this, arguments); + } + }; + }; + + defaultAndOr = function(lhs, rhs) { + return lhs || rhs; + }; + + Batman.Filters = { + raw: buntUndefined(function(value, binding) { + binding.escapeValue = false; + return value; + }), + get: buntUndefined(function(value, key) { + if (value.get != null) { + return value.get(key); + } else { + return value[key]; + } + }), + equals: buntUndefined(function(lhs, rhs, binding) { + return lhs === rhs; + }), + and: function(lhs, rhs) { + return lhs && rhs; + }, + or: function(lhs, rhs, binding) { + return lhs || rhs; + }, + not: function(value, binding) { + return !!!value; + }, + matches: buntUndefined(function(value, searchFor) { + return value.indexOf(searchFor) !== -1; + }), + truncate: buntUndefined(function(value, length, end, binding) { + if (end == null) { + end = "..."; + } + if (!binding) { + binding = end; + end = "..."; + } + if (value.length > length) { + value = value.substr(0, length - end.length) + end; + } + return value; + }), + "default": function(value, defaultValue, binding) { + if ((value != null) && value !== '') { + return value; + } else { + return defaultValue; + } + }, + prepend: function(value, string, binding) { + return string + value; + }, + append: function(value, string, binding) { + return value + string; + }, + replace: buntUndefined(function(value, searchFor, replaceWith, flags, binding) { + if (!binding) { + binding = flags; + flags = void 0; + } + if (flags === void 0) { + return value.replace(searchFor, replaceWith); + } else { + return value.replace(searchFor, replaceWith, flags); + } + }), + downcase: buntUndefined(function(value) { + return value.toLowerCase(); + }), + upcase: buntUndefined(function(value) { + return value.toUpperCase(); + }), + pluralize: buntUndefined(function(string, count, includeCount, binding) { + if (!binding) { + binding = includeCount; + includeCount = true; + if (!binding) { + binding = count; + count = void 0; + } + } + if (count) { + return Batman.helpers.pluralize(count, string, void 0, includeCount); + } else { + return Batman.helpers.pluralize(string); + } + }), + humanize: buntUndefined(function(string, binding) { + return Batman.helpers.humanize(string); + }), + join: buntUndefined(function(value, withWhat, binding) { + if (withWhat == null) { + withWhat = ''; + } + if (!binding) { + binding = withWhat; + withWhat = ''; + } + return value.join(withWhat); + }), + sort: buntUndefined(function(value) { + return value.sort(); + }), + map: buntUndefined(function(value, key) { + return value.map(function(x) { + return Batman.get(x, key); + }); + }), + has: function(set, item) { + if (set == null) { + return false; + } + return Batman.contains(set, item); + }, + first: buntUndefined(function(value) { + return value[0]; + }), + meta: buntUndefined(function(value, keypath) { + Batman.developer.assert(value.meta, "Error, value doesn't have a meta to filter on!"); + return value.meta.get(keypath); + }), + interpolate: function(string, interpolationKeypaths, binding) { + var k, v, values; + if (!binding) { + binding = interpolationKeypaths; + interpolationKeypaths = void 0; + } + if (!string) { + return; + } + values = {}; + for (k in interpolationKeypaths) { + v = interpolationKeypaths[k]; + values[k] = this.get(v); + if (!(values[k] != null)) { + Batman.developer.warn("Warning! Undefined interpolation key " + k + " for interpolation", string); + values[k] = ''; + } + } + return Batman.helpers.interpolate(string, values); + }, + withArguments: function() { + var binding, block, curryArgs, _i; + block = arguments[0], curryArgs = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), binding = arguments[_i++]; + if (!block) { + return; + } + return function() { + var regularArgs; + regularArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return block.call.apply(block, [this].concat(__slice.call(curryArgs), __slice.call(regularArgs))); + }; + }, + routeToAction: buntUndefined(function(model, action) { + var params; + params = Batman.Dispatcher.paramsFromArgument(model); + params.action = action; + return params; + }), + escape: buntUndefined(Batman.escapeHTML) + }; + + (function() { + var k, _i, _len, _ref, _results; + _ref = ['capitalize', 'singularize', 'underscore', 'camelize']; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + _results.push(Batman.Filters[k] = buntUndefined(Batman.helpers[k])); + } + return _results; + })(); + + Batman.developer.addFilters(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.RenderContext = (function() { + var ContextProxy; + + RenderContext.deProxy = function(object) { + if ((object != null) && object.isContextProxy) { + return object.get('proxiedObject'); + } else { + return object; + } + }; + + RenderContext.root = function() { + var root; + if (Batman.currentApp != null) { + root = Batman.currentApp.get('_renderContext'); + } + return root != null ? root : root = this.base; + }; + + RenderContext.prototype.windowWrapper = { + window: Batman.container + }; + + function RenderContext(object, parent) { + this.object = object; + this.parent = parent; + } + + RenderContext.prototype.findKey = function(key) { + var base, currentNode, val; + base = key.split('.')[0].split('|')[0].trim(); + currentNode = this; + while (currentNode) { + val = Batman.get(currentNode.object, base); + if (typeof val !== 'undefined') { + val = Batman.get(currentNode.object, key); + return [val, currentNode.object].map(this.constructor.deProxy); + } + currentNode = currentNode.parent; + } + return [Batman.get(this.windowWrapper, key), this.windowWrapper]; + }; + + RenderContext.prototype.get = function(key) { + return this.findKey(key)[0]; + }; + + RenderContext.prototype.contextForKey = function(key) { + return this.findKey(key)[1]; + }; + + RenderContext.prototype.descend = function(object, scopedKey) { + var oldObject; + if (scopedKey) { + oldObject = object; + object = new Batman.Object(); + object[scopedKey] = oldObject; + } + return new this.constructor(object, this); + }; + + RenderContext.prototype.descendWithKey = function(key, scopedKey) { + var proxy; + proxy = new ContextProxy(this, key); + return this.descend(proxy, scopedKey); + }; + + RenderContext.prototype.chain = function() { + var parent, x; + x = []; + parent = this; + while (parent) { + x.push(parent.object); + parent = parent.parent; + } + return x; + }; + + RenderContext.ContextProxy = ContextProxy = (function(_super) { + + __extends(ContextProxy, _super); + + ContextProxy.prototype.isContextProxy = true; + + ContextProxy.accessor('proxiedObject', function() { + return this.binding.get('filteredValue'); + }); + + ContextProxy.accessor({ + get: function(key) { + return this.get("proxiedObject." + key); + }, + set: function(key, value) { + return this.set("proxiedObject." + key, value); + }, + unset: function(key) { + return this.unset("proxiedObject." + key); + } + }); + + function ContextProxy(renderContext, keyPath, localKey) { + this.renderContext = renderContext; + this.keyPath = keyPath; + this.localKey = localKey; + this.binding = new Batman.DOM.AbstractBinding(void 0, this.keyPath, this.renderContext); + } + + return ContextProxy; + + })(Batman.Object); + + return RenderContext; + + }).call(this); + + Batman.RenderContext.base = new Batman.RenderContext(Batman.RenderContext.prototype.windowWrapper); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ViewStore = (function(_super) { + + __extends(ViewStore, _super); + + ViewStore.prefix = 'views'; + + ViewStore.fetchFromRemote = true; + + function ViewStore() { + ViewStore.__super__.constructor.apply(this, arguments); + this._viewContents = {}; + this._requestedPaths = new Batman.SimpleSet; + } + + ViewStore.prototype.propertyClass = Batman.Property; + + ViewStore.prototype.fetchView = function(path) { + var _this = this; + return new Batman.Request({ + url: Batman.Navigator.normalizePath(this.constructor.prefix, "" + path + ".html"), + type: 'html', + success: function(response) { + return _this.set(path, response); + }, + error: function(response) { + throw new Error("Could not load view from " + path); + } + }); + }; + + ViewStore.accessor({ + 'final': true, + get: function(path) { + var contents; + if (path[0] !== '/') { + return this.get("/" + path); + } + if (this._viewContents[path]) { + return this._viewContents[path]; + } + if (this._requestedPaths.has(path)) { + return; + } + if (contents = this._sourceFromDOM(path)) { + return contents; + } + if (this.constructor.fetchFromRemote) { + this.fetchView(path); + } else { + throw new Error("Couldn't find view source for \'" + path + "\'!"); + } + }, + set: function(path, content) { + if (path[0] !== '/') { + return this.set("/" + path, content); + } + this._requestedPaths.add(path); + return this._viewContents[path] = content; + } + }); + + ViewStore.prototype.prefetch = function(path) { + this.get(path); + return true; + }; + + ViewStore.prototype._sourceFromDOM = function(path) { + var node, relativePath; + relativePath = path.slice(1); + if (node = Batman.DOM.querySelector(document, "[data-defineview*='" + relativePath + "']")) { + Batman.setImmediate(function() { + var _ref; + return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; + }); + return Batman.DOM.defineView(path, node); + } + }; + + return ViewStore; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.View = (function(_super) { + + __extends(View, _super); + + View.store = new Batman.ViewStore(); + + View.option = function() { + var keys, + _this = this; + keys = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + keys.forEach(function(key) { + return _this.accessor(_this.prototype._argumentBindingKey(key), function(bindingKey) { + var context, keyPath, node, _ref; + if (!((node = this.get('node')) && (context = this.get('context')))) { + return; + } + keyPath = node.getAttribute(("data-view-" + key).toLowerCase()); + if (keyPath == null) { + return; + } + if ((_ref = this[bindingKey]) != null) { + _ref.die(); + } + return this[bindingKey] = new Batman.DOM.ViewArgumentBinding(node, keyPath, context); + }); + }); + return this.accessor.apply(this, __slice.call(keys).concat([function(key) { + var _ref; + return (_ref = this.get(this._argumentBindingKey(key))) != null ? _ref.get('filteredValue') : void 0; + }])); + }; + + View.prototype.isView = true; + + View.prototype.cache = true; + + View.prototype._rendered = false; + + View.prototype.source = ''; + + View.prototype.html = ''; + + View.prototype.node = null; + + View.prototype.event('ready').oneShot = true; + + View.accessor('html', { + get: function() { + var source; + if (this.html && this.html.length > 0) { + return this.html; + } + if (!(source = this.get('source'))) { + return; + } + source = Batman.Navigator.normalizePath(source); + return this.html = this.constructor.store.get(source); + }, + set: function(_, html) { + return this.html = html; + } + }); + + View.accessor('node', { + get: function() { + var html; + if (this.node == null) { + html = this.get('html'); + if (!(html && html.length > 0)) { + return; + } + this.node = document.createElement('div'); + this._setNodeOwner(this.node); + Batman.setInnerHTML(this.node, html); + } + return this.node; + }, + set: function(_, node) { + var updateHTML, + _this = this; + this.node = node; + this._setNodeOwner(node); + updateHTML = function(html) { + if (html != null) { + Batman.setInnerHTML(_this.node, html); + return _this.forget('html', updateHTML); + } + }; + this.observeAndFire('html', updateHTML); + return node; + } + }); + + View.YieldStorage = (function(_super1) { + + __extends(YieldStorage, _super1); + + function YieldStorage() { + return YieldStorage.__super__.constructor.apply(this, arguments); + } + + YieldStorage.wrapAccessor(function(core) { + return { + get: function(key) { + var val; + val = core.get.call(this, key); + if (!(val != null)) { + val = this.set(key, []); + } + return val; + } + }; + }); + + return YieldStorage; + + })(Batman.Hash); + + View.accessor('yields', function() { + return new this.constructor.YieldStorage; + }); + + function View(options) { + var context, + _this = this; + if (options == null) { + options = {}; + } + context = options.context; + if (context) { + if (!(context instanceof Batman.RenderContext)) { + context = Batman.RenderContext.root().descend(context); + } + } else { + context = Batman.RenderContext.root(); + } + options.context = context.descend(this); + View.__super__.constructor.call(this, options); + Batman.Property.withoutTracking(function() { + var node; + if (node = _this.get('node')) { + return _this.render(node); + } else { + return _this.observeOnce('node', function(node) { + return _this.render(node); + }); + } + }); + } + + View.prototype.render = function(node) { + var _this = this; + if (this._rendered) { + return; + } + this._rendered = true; + this.event('ready').resetOneShot(); + if (node) { + this._renderer = new Batman.Renderer(node, this.context, this); + return this._renderer.on('rendered', function() { + return _this.fire('ready', node); + }); + } + }; + + View.prototype.isInDOM = function() { + var node; + if ((node = this.get('node'))) { + return (node.parentNode != null) || this.get('yields').some(function(name, nodes) { + var _i, _len; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i].node; + if (node.parentNode != null) { + return true; + } + } + return false; + }); + } else { + return false; + } + }; + + View.prototype.applyYields = function() { + return this.get('yields').forEach(function(name, nodes) { + var action, node, yieldObject, _i, _len, _ref, _results; + yieldObject = Batman.DOM.Yield.withName(name); + _results = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + _ref = nodes[_i], node = _ref.node, action = _ref.action; + _results.push(yieldObject[action](node)); + } + return _results; + }); + }; + + View.prototype.retractYields = function() { + return this.get('yields').forEach(function(name, nodes) { + var node, _i, _len, _ref, _results; + _results = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i].node; + _results.push((_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0); + } + return _results; + }); + }; + + View.prototype.pushYieldAction = function(key, action, node) { + this._setNodeYielder(node); + return this.get("yields").get(key).push({ + node: node, + action: action + }); + }; + + View.prototype._argumentBindingKey = function(key) { + return "_" + key + "ArgumentBinding"; + }; + + View.prototype._setNodeOwner = function(node) { + return Batman._data(node, 'view', this); + }; + + View.prototype._setNodeYielder = function(node) { + return Batman._data(node, 'yielder', this); + }; + + View.prototype.on('ready', function() { + return typeof this.ready === "function" ? this.ready.apply(this, arguments) : void 0; + }); + + View.prototype.on('appear', function() { + return typeof this.viewDidAppear === "function" ? this.viewDidAppear.apply(this, arguments) : void 0; + }); + + View.prototype.on('disappear', function() { + return typeof this.viewDidDisappear === "function" ? this.viewDidDisappear.apply(this, arguments) : void 0; + }); + + View.prototype.on('beforeAppear', function() { + return typeof this.viewWillAppear === "function" ? this.viewWillAppear.apply(this, arguments) : void 0; + }); + + View.prototype.on('beforeDisappear', function() { + return typeof this.viewWillDisappear === "function" ? this.viewWillDisappear.apply(this, arguments) : void 0; + }); + + return View; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var Yield, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.DOM.Yield = Yield = (function(_super) { + + __extends(Yield, _super); + + Yield.yields = {}; + + Yield.queued = function(fn) { + return function() { + var args, handler, + _this = this; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (this.containerNode != null) { + return fn.apply(this, args); + } else { + return handler = this.observe('containerNode', function() { + var result; + result = fn.apply(_this, args); + _this.forget('containerNode', handler); + return result; + }); + } + }; + }; + + Yield.reset = function() { + return this.yields = {}; + }; + + Yield.withName = function(name) { + var _base; + (_base = this.yields)[name] || (_base[name] = new this({ + name: name + })); + return this.yields[name]; + }; + + Yield.forEach = function(f) { + var name, yieldObject, _ref; + _ref = this.yields; + for (name in _ref) { + yieldObject = _ref[name]; + f(yieldObject); + } + }; + + Yield.clearAll = function() { + return this.forEach(function(yieldObject) { + return yieldObject.clear(); + }); + }; + + Yield.cycleAll = function() { + return this.forEach(function(yieldObject) { + return yieldObject.cycle(); + }); + }; + + Yield.clearAllStale = function() { + return this.forEach(function(yieldObject) { + return yieldObject.clearStale(); + }); + }; + + function Yield() { + this.cycle(); + } + + Yield.prototype.cycle = function() { + return this.currentVersionNodes = []; + }; + + Yield.prototype.clear = Yield.queued(function() { + var child, _i, _len, _ref, _results; + this.cycle(); + _ref = (function() { + var _j, _len, _ref, _results1; + _ref = this.containerNode.childNodes; + _results1 = []; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + child = _ref[_j]; + _results1.push(child); + } + return _results1; + }).call(this); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(Batman.removeOrDestroyNode(child)); + } + return _results; + }); + + Yield.prototype.clearStale = Yield.queued(function() { + var child, _i, _len, _ref, _results; + _ref = (function() { + var _j, _len, _ref, _results1; + _ref = this.containerNode.childNodes; + _results1 = []; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + child = _ref[_j]; + _results1.push(child); + } + return _results1; + }).call(this); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + if (!~this.currentVersionNodes.indexOf(child)) { + _results.push(Batman.removeOrDestroyNode(child)); + } + } + return _results; + }); + + Yield.prototype.append = Yield.queued(function(node) { + this.currentVersionNodes.push(node); + return Batman.appendChild(this.containerNode, node, true); + }); + + Yield.prototype.replace = Yield.queued(function(node) { + this.clear(); + return this.append(node); + }); + + return Yield; + + })(Batman.Object); + +}).call(this); + +(function() { + + + +}).call(this); \ No newline at end of file diff --git a/vendor/javascripts/es5-shim.js b/vendor/javascripts/es5-shim.js new file mode 100644 index 0000000..ce79780 --- /dev/null +++ b/vendor/javascripts/es5-shim.js @@ -0,0 +1,1021 @@ +// vim: ts=4 sts=4 sw=4 expandtab +// -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License +// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project) +// -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA +// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License +// -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License +// -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License +// -- kossnocorp Sasha Koss XXX TODO License or CLA +// -- bryanforbes Bryan Forbes XXX TODO License or CLA +// -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence +// -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License +// -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License +// -- bbqsrc Brendan Molloy XXX TODO License or CLA +// -- iwyg XXX TODO License or CLA +// -- DomenicDenicola Domenic Denicola XXX TODO License or CLA +// -- xavierm02 Montillet Xavier XXX TODO License or CLA +// -- Raynos Raynos XXX TODO License or CLA +// -- samsonjs Sami Samhuri XXX TODO License or CLA +// -- rwldrn Rick Waldron Copyright (C) 2011 MIT License +// -- lexer Alexey Zakharov XXX TODO License or CLA + +/*! + Copyright (c) 2009, 280 North Inc. http://280north.com/ + MIT License. http://github.com/280north/narwhal/blob/master/README.md +*/ + +// Module systems magic dance +(function (definition) { + // RequireJS + if (typeof define == "function") { + define(definition); + // CommonJS and - + + - + + + + -
+
<%= yield %>
+ + \ No newline at end of file diff --git a/templates/project/dashboards/main.erb b/templates/project/dashboards/main.erb index 3638940..71acaf2 100644 --- a/templates/project/dashboards/main.erb +++ b/templates/project/dashboards/main.erb @@ -1 +1,12 @@ -
\ No newline at end of file +<% content_for(:title) { "My super sweet dashboard" } %> +
    +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
\ No newline at end of file diff --git a/templates/project/jobs/sample.rb b/templates/project/jobs/sample.rb index 3d7bfcd..54a0e60 100644 --- a/templates/project/jobs/sample.rb +++ b/templates/project/jobs/sample.rb @@ -1,12 +1,5 @@ SCHEDULER.every '5s' do - sayings = [ - "That's one trouble with dual identities, Robin. Dual responsibilities.", - "You know your neosauruses well, Robin. Peanut butter sandwiches it is.", - "You're far from mod, Robin. And many hippies are older than you are.", - "We're still over land, Robin, and a seal is an aquatic, marine mammal.", - "True. You owe your life to dental hygiene.", - "This money goes to building better roads. We all must do our part." - ] - - send_event('sample', { quote: sayings.sample }) + send_event('synergy', { value: (rand * 1024).floor }) + send_event('convergence', { value: (rand * 1024).floor }) + send_event('paradigm_shift', { value: (rand * 1024).floor }) end \ No newline at end of file diff --git a/templates/project/public/fonts/fontawesome-webfont.eot b/templates/project/public/fonts/fontawesome-webfont.eot new file mode 100755 index 0000000..89070c1 Binary files /dev/null and b/templates/project/public/fonts/fontawesome-webfont.eot differ diff --git a/templates/project/public/fonts/fontawesome-webfont.svg b/templates/project/public/fonts/fontawesome-webfont.svg new file mode 100755 index 0000000..1245f92 --- /dev/null +++ b/templates/project/public/fonts/fontawesome-webfont.svg @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/project/public/fonts/fontawesome-webfont.ttf b/templates/project/public/fonts/fontawesome-webfont.ttf new file mode 100755 index 0000000..c17e9f8 Binary files /dev/null and b/templates/project/public/fonts/fontawesome-webfont.ttf differ diff --git a/templates/project/public/fonts/fontawesome-webfont.woff b/templates/project/public/fonts/fontawesome-webfont.woff new file mode 100755 index 0000000..09f2469 Binary files /dev/null and b/templates/project/public/fonts/fontawesome-webfont.woff differ diff --git a/templates/project/public/images/favicon.ico b/templates/project/public/images/favicon.ico new file mode 100644 index 0000000..29a408f Binary files /dev/null and b/templates/project/public/images/favicon.ico differ diff --git a/templates/project/public/javascripts/jquery.knob.js b/templates/project/public/javascripts/jquery.knob.js new file mode 100644 index 0000000..3224638 --- /dev/null +++ b/templates/project/public/javascripts/jquery.knob.js @@ -0,0 +1,646 @@ +/*!jQuery Knob*/ +/** + * Downward compatible, touchable dial + * + * Version: 1.2.0 (15/07/2012) + * Requires: jQuery v1.7+ + * + * Copyright (c) 2012 Anthony Terrien + * Under MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Thanks to vor, eskimoblood, spiffistan, FabrizioC + */ +$(function () { + + /** + * Kontrol library + */ + "use strict"; + + /** + * Definition of globals and core + */ + var k = {}, // kontrol + max = Math.max, + min = Math.min; + + k.c = {}; + k.c.d = $(document); + k.c.t = function (e) { + return e.originalEvent.touches.length - 1; + }; + + /** + * Kontrol Object + * + * Definition of an abstract UI control + * + * Each concrete component must call this one. + * + * k.o.call(this); + * + */ + k.o = function () { + var s = this; + + this.o = null; // array of options + this.$ = null; // jQuery wrapped element + this.i = null; // mixed HTMLInputElement or array of HTMLInputElement + this.g = null; // 2D graphics context for 'pre-rendering' + this.v = null; // value ; mixed array or integer + this.cv = null; // change value ; not commited value + this.x = 0; // canvas x position + this.y = 0; // canvas y position + this.$c = null; // jQuery canvas element + this.c = null; // rendered canvas context + this.t = 0; // touches index + this.isInit = false; + this.fgColor = null; // main color + this.pColor = null; // previous color + this.dH = null; // draw hook + this.cH = null; // change hook + this.eH = null; // cancel hook + this.rH = null; // release hook + + this.run = function () { + var cf = function (e, conf) { + var k; + for (k in conf) { + s.o[k] = conf[k]; + } + s.init(); + s._configure() + ._draw(); + }; + + if(this.$.data('kontroled')) return; + this.$.data('kontroled', true); + + this.extend(); + this.o = $.extend( + { + // Config + min : this.$.data('min') || 0, + max : this.$.data('max') || 100, + stopper : true, + readOnly : this.$.data('readonly'), + + // UI + cursor : (this.$.data('cursor') === true && 30) + || this.$.data('cursor') + || 0, + thickness : this.$.data('thickness') || 0.35, + width : this.$.data('width') || 200, + height : this.$.data('height') || 200, + displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'), + displayPrevious : this.$.data('displayprevious'), + fgColor : this.$.data('fgcolor') || '#87CEEB', + inline : false, + + // Hooks + draw : null, // function () {} + change : null, // function (value) {} + cancel : null, // function () {} + release : null // function (value) {} + }, this.o + ); + + // routing value + if(this.$.is('fieldset')) { + + // fieldset = array of integer + this.v = {}; + this.i = this.$.find('input') + this.i.each(function(k) { + var $this = $(this); + s.i[k] = $this; + s.v[k] = $this.val(); + + $this.bind( + 'change' + , function () { + var val = {}; + val[k] = $this.val(); + s.val(val); + } + ); + }); + this.$.find('legend').remove(); + + } else { + // input = integer + this.i = this.$; + this.v = this.$.val(); + (this.v == '') && (this.v = this.o.min); + + this.$.bind( + 'change' + , function () { + s.val(s.$.val()); + } + ); + } + + (!this.o.displayInput) && this.$.hide(); + + this.$c = $(''); + this.c = this.$c[0].getContext("2d"); + + this.$ + .wrap($('
')) + .before(this.$c); + + if (this.v instanceof Object) { + this.cv = {}; + this.copy(this.v, this.cv); + } else { + this.cv = this.v; + } + + this.$ + .bind("configure", cf) + .parent() + .bind("configure", cf); + + this._listen() + ._configure() + ._xy() + .init(); + + this.isInit = true; + + this._draw(); + + return this; + }; + + this._draw = function () { + + // canvas pre-rendering + var d = true, + c = document.createElement('canvas'); + + c.width = s.o.width; + c.height = s.o.height; + s.g = c.getContext('2d'); + + s.clear(); + + s.dH + && (d = s.dH()); + + (d !== false) && s.draw(); + + s.c.drawImage(c, 0, 0); + c = null; + }; + + this._touch = function (e) { + + var touchMove = function (e) { + + var v = s.xy2val( + e.originalEvent.touches[s.t].pageX, + e.originalEvent.touches[s.t].pageY + ); + + if (v == s.cv) return; + + if ( + s.cH + && (s.cH(v) === false) + ) return; + + + s.change(v); + s._draw(); + }; + + // get touches index + this.t = k.c.t(e); + + // First touch + touchMove(e); + + // Touch events listeners + k.c.d + .bind("touchmove.k", touchMove) + .bind( + "touchend.k" + , function () { + k.c.d.unbind('touchmove.k touchend.k'); + + if ( + s.rH + && (s.rH(s.cv) === false) + ) return; + + s.val(s.cv); + } + ); + + return this; + }; + + this._mouse = function (e) { + + var mouseMove = function (e) { + var v = s.xy2val(e.pageX, e.pageY); + if (v == s.cv) return; + + if ( + s.cH + && (s.cH(v) === false) + ) return; + + s.change(v); + s._draw(); + }; + + // First click + mouseMove(e); + + // Mouse events listeners + k.c.d + .bind("mousemove.k", mouseMove) + .bind( + // Escape key cancel current change + "keyup.k" + , function (e) { + if (e.keyCode === 27) { + k.c.d.unbind("mouseup.k mousemove.k keyup.k"); + + if ( + s.eH + && (s.eH() === false) + ) return; + + s.cancel(); + } + } + ) + .bind( + "mouseup.k" + , function (e) { + k.c.d.unbind('mousemove.k mouseup.k keyup.k'); + + if ( + s.rH + && (s.rH(s.cv) === false) + ) return; + + s.val(s.cv); + } + ); + + return this; + }; + + this._xy = function () { + var o = this.$c.offset(); + this.x = o.left; + this.y = o.top; + return this; + }; + + this._listen = function () { + + if (!this.o.readOnly) { + this.$c + .bind( + "mousedown" + , function (e) { + e.preventDefault(); + s._xy()._mouse(e); + } + ) + .bind( + "touchstart" + , function (e) { + e.preventDefault(); + s._xy()._touch(e); + } + ); + this.listen(); + } else { + this.$.attr('readonly', 'readonly'); + } + + return this; + }; + + this._configure = function () { + + // Hooks + if (this.o.draw) this.dH = this.o.draw; + if (this.o.change) this.cH = this.o.change; + if (this.o.cancel) this.eH = this.o.cancel; + if (this.o.release) this.rH = this.o.release; + + if (this.o.displayPrevious) { + this.pColor = this.h2rgba(this.o.fgColor, "0.4"); + this.fgColor = this.h2rgba(this.o.fgColor, "0.6"); + } else { + this.fgColor = this.o.fgColor; + } + + return this; + }; + + this._clear = function () { + this.$c[0].width = this.$c[0].width; + }; + + // Abstract methods + this.listen = function () {}; // on start, one time + this.extend = function () {}; // each time configure triggered + this.init = function () {}; // each time configure triggered + this.change = function (v) {}; // on change + this.val = function (v) {}; // on release + this.xy2val = function (x, y) {}; // + this.draw = function () {}; // on change / on release + this.clear = function () { this._clear(); }; + + // Utils + this.h2rgba = function (h, a) { + var rgb; + h = h.substring(1,7) + rgb = [parseInt(h.substring(0,2),16) + ,parseInt(h.substring(2,4),16) + ,parseInt(h.substring(4,6),16)]; + return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")"; + }; + + this.copy = function (f, t) { + for (var i in f) { t[i] = f[i]; } + }; + }; + + + /** + * k.Dial + */ + k.Dial = function () { + k.o.call(this); + + this.startAngle = null; + this.xy = null; + this.radius = null; + this.lineWidth = null; + this.cursorExt = null; + this.w2 = null; + this.PI2 = 2*Math.PI; + + this.extend = function () { + this.o = $.extend( + { + bgColor : this.$.data('bgcolor') || '#EEEEEE', + angleOffset : this.$.data('angleoffset') || 0, + angleArc : this.$.data('anglearc') || 360, + inline : true + }, this.o + ); + }; + + this.val = function (v) { + if (null != v) { + this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v; + this.v = this.cv; + this.$.val(this.v); + this._draw(); + } else { + return this.v; + } + }; + + this.xy2val = function (x, y) { + var a, ret; + + a = Math.atan2( + x - (this.x + this.w2) + , - (y - this.y - this.w2) + ) - this.angleOffset; + + if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) { + // if isset angleArc option, set to min if .5 under min + a = 0; + } else if (a < 0) { + a += this.PI2; + } + + ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc)) + + this.o.min; + + this.o.stopper + && (ret = max(min(ret, this.o.max), this.o.min)); + + return ret; + }; + + this.listen = function () { + // bind MouseWheel + var s = this, + mw = function (e) { + e.preventDefault(); + + var ori = e.originalEvent + ,deltaX = ori.detail || ori.wheelDeltaX + ,deltaY = ori.detail || ori.wheelDeltaY + ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? 1 : deltaX<0 || deltaY<0 ? -1 : 0); + + if ( + s.cH + && (s.cH(v) === false) + ) return; + + s.val(v); + } + , kval, to, m = 1, kv = {37:-1, 38:1, 39:1, 40:-1}; + + this.$ + .bind( + "keydown" + ,function (e) { + var kc = e.keyCode; + kval = parseInt(String.fromCharCode(kc)); + + if (isNaN(kval)) { + + (kc !== 13) // enter + && (kc !== 8) // bs + && (kc !== 9) // tab + && (kc !== 189) // - + && e.preventDefault(); + + // arrows + if ($.inArray(kc,[37,38,39,40]) > -1) { + e.preventDefault(); + + var v = parseInt(s.$.val()) + kv[kc] * m; + + s.o.stopper + && (v = max(min(v, s.o.max), s.o.min)); + + s.change(v); + s._draw(); + + // long time keydown speed-up + to = window.setTimeout( + function () { m*=2; } + ,30 + ); + } + } + } + ) + .bind( + "keyup" + ,function (e) { + if (isNaN(kval)) { + if (to) { + window.clearTimeout(to); + to = null; + m = 1; + s.val(s.$.val()); + } + } else { + // kval postcond + (s.$.val() > s.o.max && s.$.val(s.o.max)) + || (s.$.val() < s.o.min && s.$.val(s.o.min)); + } + + } + ); + + this.$c.bind("mousewheel DOMMouseScroll", mw); + this.$.bind("mousewheel DOMMouseScroll", mw) + }; + + this.init = function () { + + if ( + this.v < this.o.min + || this.v > this.o.max + ) this.v = this.o.min; + + this.$.val(this.v); + this.w2 = this.o.width / 2; + this.cursorExt = this.o.cursor / 100; + this.xy = this.w2; + this.lineWidth = this.xy * this.o.thickness; + this.radius = this.xy - this.lineWidth / 2; + + this.o.angleOffset + && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset); + + this.o.angleArc + && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc); + + // deg to rad + this.angleOffset = this.o.angleOffset * Math.PI / 180; + this.angleArc = this.o.angleArc * Math.PI / 180; + + // compute start and end angles + this.startAngle = 1.5 * Math.PI + this.angleOffset; + this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc; + + var s = max( + String(Math.abs(this.o.max)).length + , String(Math.abs(this.o.min)).length + , 2 + ) + 2; + + this.o.displayInput + && this.i.css({ + 'width' : ((this.o.width / 2 + 4) >> 0) + 'px' + ,'height' : ((this.o.width / 3) >> 0) + 'px' + ,'position' : 'absolute' + ,'vertical-align' : 'middle' + ,'margin-top' : ((this.o.width / 3) >> 0) + 'px' + ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px' + ,'border' : 0 + ,'background' : 'none' + ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial' + ,'text-align' : 'center' + ,'color' : this.o.fgColor + ,'padding' : '0px' + ,'-webkit-appearance': 'none' + }) + || this.i.css({ + 'width' : '0px' + ,'visibility' : 'hidden' + }); + }; + + this.change = function (v) { + this.cv = v; + this.$.val(v); + }; + + this.angle = function (v) { + return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min); + }; + + this.draw = function () { + + var c = this.g, // context + a = this.angle(this.cv) // Angle + , sat = this.startAngle // Start angle + , eat = sat + a // End angle + , sa, ea // Previous angles + , r = 1; + + c.lineWidth = this.lineWidth; + + this.o.cursor + && (sat = eat - this.cursorExt) + && (eat = eat + this.cursorExt); + + c.beginPath(); + c.strokeStyle = this.o.bgColor; + c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true); + c.stroke(); + + if (this.o.displayPrevious) { + ea = this.startAngle + this.angle(this.v); + sa = this.startAngle; + this.o.cursor + && (sa = ea - this.cursorExt) + && (ea = ea + this.cursorExt); + + c.beginPath(); + c.strokeStyle = this.pColor; + c.arc(this.xy, this.xy, this.radius, sa, ea, false); + c.stroke(); + r = (this.cv == this.v); + } + + c.beginPath(); + c.strokeStyle = r ? this.o.fgColor : this.fgColor ; + c.arc(this.xy, this.xy, this.radius, sat, eat, false); + c.stroke(); + }; + + this.cancel = function () { + this.val(this.v); + }; + }; + + $.fn.dial = $.fn.knob = function (o) { + return this.each( + function () { + var d = new k.Dial(); + d.o = o; + d.$ = $(this); + d.run(); + } + ).parent(); + }; + +}); \ No newline at end of file diff --git a/templates/project/public/javascripts/jquery.masonry.min.js b/templates/project/public/javascripts/jquery.masonry.min.js new file mode 100644 index 0000000..67be988 --- /dev/null +++ b/templates/project/public/javascripts/jquery.masonry.min.js @@ -0,0 +1,10 @@ +/** + * jQuery Masonry v2.1.05 + * A dynamic layout plugin for jQuery + * The flip-side of CSS Floats + * http://masonry.desandro.com + * + * Licensed under the MIT license. + * Copyright 2012 David DeSandro + */ +(function(a,b,c){"use strict";var d=b.event,e;d.special.smartresize={setup:function(){b(this).bind("resize",d.special.smartresize.handler)},teardown:function(){b(this).unbind("resize",d.special.smartresize.handler)},handler:function(a,c){var d=this,f=arguments;a.type="smartresize",e&&clearTimeout(e),e=setTimeout(function(){b.event.handle.apply(d,f)},c==="execAsap"?0:100)}},b.fn.smartresize=function(a){return a?this.bind("smartresize",a):this.trigger("smartresize",["execAsap"])},b.Mason=function(a,c){this.element=b(c),this._create(a),this._init()},b.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},b.Mason.prototype={_filterFindBricks:function(a){var b=this.options.itemSelector;return b?a.filter(b).add(a.find(b)):a},_getBricks:function(a){var b=this._filterFindBricks(a).css({position:"absolute"}).addClass("masonry-brick");return b},_create:function(c){this.options=b.extend(!0,{},b.Mason.settings,c),this.styleQueue=[];var d=this.element[0].style;this.originalStyle={height:d.height||""};var e=this.options.containerStyle;for(var f in e)this.originalStyle[f]=d[f]||"";this.element.css(e),this.horizontalDirection=this.options.isRTL?"right":"left",this.offset={x:parseInt(this.element.css("padding-"+this.horizontalDirection),10),y:parseInt(this.element.css("padding-top"),10)},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var g=this;setTimeout(function(){g.element.addClass("masonry")},0),this.options.isResizable&&b(a).bind("smartresize.masonry",function(){g.resize()}),this.reloadItems()},_init:function(a){this._getColumns(),this._reLayout(a)},option:function(a,c){b.isPlainObject(a)&&(this.options=b.extend(!0,this.options,a))},layout:function(a,b){for(var c=0,d=a.length;c + if @get('last') + if parseInt(@get('current')) > parseInt(@get('last')) then 'arrow-up' else 'arrow-down' + + ready: -> + Batman.setImmediate => + if @get('unordered') + $(@node).find('ol').remove() + else + $(@node).find('ul').remove() \ No newline at end of file diff --git a/templates/project/widgets/list/list.html b/templates/project/widgets/list/list.html new file mode 100644 index 0000000..cc90d42 --- /dev/null +++ b/templates/project/widgets/list/list.html @@ -0,0 +1,15 @@ +

+ +
    +
  1. + + +
  2. +
+ +
    +
  • + + +
  • +
\ No newline at end of file diff --git a/templates/project/widgets/list/list.scss b/templates/project/widgets/list/list.scss new file mode 100644 index 0000000..248cef8 --- /dev/null +++ b/templates/project/widgets/list/list.scss @@ -0,0 +1,50 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$widget-list_background-color: #12b0c5; +$widget-list_value-color: #fff; + +$widget-list_title-color: lighten($widget-list_background-color, 45%); +$widget-list_label-color: lighten($widget-list_background-color, 45%); + +// ---------------------------------------------------------------------------- +// Widget-list styles +// ---------------------------------------------------------------------------- +.widget-list { + + background-color: $widget-list_background-color; + + .title { + color: $widget-list_title-color; + } + + ol, ul { + margin: 0 15px; + text-align: left; + color: $widget-list_label-color; + } + + ol { + list-style-position: inside; + } + + li { + margin-bottom: 5px; + } + + .list-nostyle { + list-style: none; + } + + .label { + color: $widget-list_label-color; + } + + .value { + float: right; + margin-left: 12px; + font-weight: 600; + color: $widget-list_value-color; + } + +} \ No newline at end of file diff --git a/templates/project/widgets/meter/meter.coffee b/templates/project/widgets/meter/meter.coffee new file mode 100644 index 0000000..4dbc2da --- /dev/null +++ b/templates/project/widgets/meter/meter.coffee @@ -0,0 +1,16 @@ +class AllTheThings.Meter extends AllTheThings.Widget + source: 'meter' + + @accessor 'value', Batman.Property.EasingSetter + + constructor: -> + super + @observe 'value', (value) -> + $(@node).find(".meter").val(value).trigger('change') + + ready: -> + Batman.setImmediate => + meter = $(@node).find(".meter") + meter.attr("data-bgcolor", meter.css("background-color")) + meter.attr("data-fgcolor", meter.css("color")) + meter.knob() \ No newline at end of file diff --git a/templates/project/widgets/meter/meter.html b/templates/project/widgets/meter/meter.html new file mode 100644 index 0000000..1476ba1 --- /dev/null +++ b/templates/project/widgets/meter/meter.html @@ -0,0 +1,5 @@ +

+ + + +

\ No newline at end of file diff --git a/templates/project/widgets/meter/meter.scss b/templates/project/widgets/meter/meter.scss new file mode 100644 index 0000000..b134361 --- /dev/null +++ b/templates/project/widgets/meter/meter.scss @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$widget-meter_background-color: #9c4274; +$widget-meter_value-color: #fff; + +$widget-meter_title-color: lighten($widget-meter_background-color, 45%); +$widget-text_moreinfo-color: lighten($widget-meter_background-color, 45%); + +$widget-meter-bg: darken($widget-meter_background-color, 15%); +$widget-meter-fg: lighten($widget-meter_background-color, 75%); + +// ---------------------------------------------------------------------------- +// Widget-meter styles +// ---------------------------------------------------------------------------- +.widget-meter { + + background-color: $widget-meter_background-color; + + input.meter { + background-color: $widget-meter-bg; + color: $widget-meter-fg; + } + + .title { + color: $widget-meter_title-color; + } + + .text-moreinfo { + font-weight: 600; + font-size: 20px; + margin-top: 0; + } + +} \ No newline at end of file diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee new file mode 100644 index 0000000..aa7cf8b --- /dev/null +++ b/templates/project/widgets/number/number.coffee @@ -0,0 +1,29 @@ +class AllTheThings.Number extends AllTheThings.Widget + source: 'number' + + @accessor 'current', Batman.Property.EasingSetter + + ready: -> + + @accessor 'difference', -> + if @get('last') + last = parseInt(@get('last')) + current = parseInt(@get('current')) + if last != 0 + diff = Math.abs(Math.round((current - last) / last * 100)) + "#{diff}%" + + @accessor 'arrow', -> + if @get('last') + if parseInt(@get('current')) > parseInt(@get('last')) then 'icon-arrow-up' else 'icon-arrow-down' + + @accessor 'statusStyle', -> + "status-#{@get('status')}" + + @accessor 'needsAttention', -> + @get('status') == 'warning' || @get('status') == 'danger' + + onData: (data) -> + super + if data.status + $(@get('node')).addClass("status-#{data.status}") \ No newline at end of file diff --git a/templates/project/widgets/number/number.html b/templates/project/widgets/number/number.html new file mode 100644 index 0000000..6e9a03e --- /dev/null +++ b/templates/project/widgets/number/number.html @@ -0,0 +1,9 @@ +

+ +

+ +

+ 50% +

+ +

2012-07-26 10:59AM

\ No newline at end of file diff --git a/templates/project/widgets/number/number.scss b/templates/project/widgets/number/number.scss new file mode 100644 index 0000000..6ae7f95 --- /dev/null +++ b/templates/project/widgets/number/number.scss @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$widget-number_background-color: #00b1a4; +$widget-number_value-color: #fff; + +$widget-number_title-color: lighten($widget-number_background-color, 45%); +$widget-number_moreinfo-color: lighten($widget-number_background-color, 45%); + +// ---------------------------------------------------------------------------- +// Widget-number styles +// ---------------------------------------------------------------------------- +.widget-number { + + background-color: $widget-number_background-color; + + .title { + color: $widget-number_title-color; + } + + .value { + color: $widget-number_value-color; + } + + .change-rate { + font-weight: 300; + font-size: 30px; + color: $widget-number_value-color; + } + + .text-moreinfo { + color: $widget-number_moreinfo-color; + } + +} \ No newline at end of file diff --git a/templates/project/widgets/table/table.coffee b/templates/project/widgets/table/table.coffee new file mode 100644 index 0000000..5735316 --- /dev/null +++ b/templates/project/widgets/table/table.coffee @@ -0,0 +1,2 @@ +class AllTheThings.Table extends AllTheThings.Widget + source: 'table' \ No newline at end of file diff --git a/templates/project/widgets/table/table.html b/templates/project/widgets/table/table.html new file mode 100644 index 0000000..e5aeb99 --- /dev/null +++ b/templates/project/widgets/table/table.html @@ -0,0 +1,8 @@ +

+ + + + + + +
\ No newline at end of file diff --git a/templates/project/widgets/table/table.scss b/templates/project/widgets/table/table.scss new file mode 100644 index 0000000..0d38164 --- /dev/null +++ b/templates/project/widgets/table/table.scss @@ -0,0 +1,42 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$widget-table_background-color: #82b53d; +$widget-table_value-color: #fff; + +$widget-table_title-color: lighten($widget-table_background-color, 45%); +$widget-table_label-color: lighten($widget-table_background-color, 45%); + +// ---------------------------------------------------------------------------- +// Widget-table styles +// ---------------------------------------------------------------------------- +.widget-table { + + background-color: $widget-table_background-color; + + th { + font-weight: 400; + font-size: 16px; + } + + td.label { + vertical-align: middle; + text-align: left; + font-size: 23px; + } + + .title { + color: $widget-table_title-color; + } + + .label { + color: $widget-table_label-color; + } + + .value { + font-weight: 700; + font-size: 54px; + color: $widget-table_value-color; + } + +} \ No newline at end of file diff --git a/templates/project/widgets/text/text.coffee b/templates/project/widgets/text/text.coffee new file mode 100644 index 0000000..754644e --- /dev/null +++ b/templates/project/widgets/text/text.coffee @@ -0,0 +1,2 @@ +class AllTheThings.Text extends AllTheThings.Widget + source: 'text' \ No newline at end of file diff --git a/templates/project/widgets/text/text.html b/templates/project/widgets/text/text.html new file mode 100644 index 0000000..02bd0f7 --- /dev/null +++ b/templates/project/widgets/text/text.html @@ -0,0 +1,5 @@ +

+ +

+ +

2012-07-26 10:59AM

\ No newline at end of file diff --git a/templates/project/widgets/text/text.scss b/templates/project/widgets/text/text.scss new file mode 100644 index 0000000..591c32e --- /dev/null +++ b/templates/project/widgets/text/text.scss @@ -0,0 +1,25 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$widget-text_background-color: #ec663c; +$widget-text_value-color: #fff; + +$widget-text_title-color: lighten($widget-text_background-color, 30%); +$widget-text_moreinfo-color: lighten($widget-text_background-color, 30%); + +// ---------------------------------------------------------------------------- +// Widget-text styles +// ---------------------------------------------------------------------------- +.widget-text { + + background-color: $widget-text_background-color; + + .title { + color: $widget-text_title-color; + } + + .text-moreinfo { + color: $widget-text_moreinfo-color; + } + +} \ No newline at end of file diff --git a/templates/project/widgets/widget_sample/widget_sample.coffee b/templates/project/widgets/widget_sample/widget_sample.coffee deleted file mode 100644 index a1458df..0000000 --- a/templates/project/widgets/widget_sample/widget_sample.coffee +++ /dev/null @@ -1,2 +0,0 @@ -class AllTheThings.WidgetSample extends AllTheThings.Widget - source: 'widget_sample' \ No newline at end of file diff --git a/templates/project/widgets/widget_sample/widget_sample.html b/templates/project/widgets/widget_sample/widget_sample.html deleted file mode 100644 index eea0f1c..0000000 --- a/templates/project/widgets/widget_sample/widget_sample.html +++ /dev/null @@ -1,4 +0,0 @@ -

w00t! w00t! You've setup your first dashboard!

-

To celebrate, enjoy some of these fun Batman quotes!

- - diff --git a/templates/project/widgets/widget_sample/widget_sample.scss b/templates/project/widgets/widget_sample/widget_sample.scss deleted file mode 100644 index e69de29..0000000 diff --git a/templates/widget/%name%.coffee.tt b/templates/widget/%name%.coffee.tt deleted file mode 100644 index e3e5938..0000000 --- a/templates/widget/%name%.coffee.tt +++ /dev/null @@ -1,2 +0,0 @@ -class AllTheThings.<%= Thor::Util.camel_case(name) %> extends AllTheThings.Widget - source: '<%= name %>' \ No newline at end of file diff --git a/templates/widget/%name%.html b/templates/widget/%name%.html deleted file mode 100644 index e69de29..0000000 diff --git a/templates/widget/%name%.scss b/templates/widget/%name%.scss deleted file mode 100644 index e69de29..0000000 diff --git a/templates/widget/%name%/%name%.coffee.tt b/templates/widget/%name%/%name%.coffee.tt new file mode 100644 index 0000000..5ddfb1b --- /dev/null +++ b/templates/widget/%name%/%name%.coffee.tt @@ -0,0 +1,11 @@ +class AllTheThings.<%= Thor::Util.camel_case(name) %> extends AllTheThings.Widget + source: '<%= name %>' + + ready: -> + # This is fired when the widget is done being rendered + + onData: (data) -> + # Handle incoming data + # You can access the html node of this widget with `@node` + # Example: $(@node).effect("pulsate") will make the node flash each time data comes in. + super \ No newline at end of file diff --git a/templates/widget/%name%/%name%.html b/templates/widget/%name%/%name%.html new file mode 100644 index 0000000..e69de29 diff --git a/templates/widget/%name%/%name%.scss.tt b/templates/widget/%name%/%name%.scss.tt new file mode 100644 index 0000000..0da5c49 --- /dev/null +++ b/templates/widget/%name%/%name%.scss.tt @@ -0,0 +1,3 @@ +.widget-<%= name %> { + +} \ No newline at end of file diff --git a/vendor/javascripts/application.coffee b/vendor/javascripts/application.coffee index d311687..6704ee5 100644 --- a/vendor/javascripts/application.coffee +++ b/vendor/javascripts/application.coffee @@ -1,11 +1,22 @@ -Batman.Filters.PrettyNumber = (num) -> +Batman.Filters.prettyNumber = (num) -> num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") unless isNaN(num) Batman.Filters.dashize = (str) -> dashes_rx1 = /([A-Z]+)([A-Z][a-z])/g; dashes_rx2 = /([a-z\d])([A-Z])/g; - return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace('_', '-').toLowerCase(); + return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace('_', '-').toLowerCase() + +Batman.Filters.shortenedNumber = (num) -> + return if isNaN(num) + if num >= 1000000000 + (num / 1000000000).toFixed(1) + 'B' + else if num >= 1000000 + (num / 1000000).toFixed(1) + 'M' + else if num >= 1000 + (num / 1000).toFixed(1) + 'K' + else + num class window.AllTheThings extends Batman.App @root -> @@ -37,7 +48,7 @@ AllTheThings.widgets = widgets = {} AllTheThings.lastEvents = lastEvents = {} source = new EventSource('/events') -source.addEventListener 'open', (e)-> +source.addEventListener 'open', (e) -> console.log("Connection opened") source.addEventListener 'error', (e)-> diff --git a/vendor/javascripts/widget.coffee b/vendor/javascripts/widget.coffee index f87b9fb..5c5c1a3 100644 --- a/vendor/javascripts/widget.coffee +++ b/vendor/javascripts/widget.coffee @@ -8,7 +8,7 @@ class AllTheThings.Widget extends Batman.View @mixin(AllTheThings.lastEvents[@id]) # in case the events from the server came before the widget was rendered type = Batman.Filters.dashize(@view) - $(@node).addClass("widget #{type} #{@id}") + $(@node).addClass("widget widget-#{type} #{@id}") onData: (data) => @mixin(data) \ No newline at end of file -- cgit v1.2.3 From 4e12c8acafcdf968716d54e810c5c0c039f37581 Mon Sep 17 00:00:00 2001 From: Wesley Ellis Date: Tue, 7 Aug 2012 18:01:23 -0400 Subject: First shot at the readme --- MIT-LICENSE | 20 ++++++++ README.md | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 165 insertions(+), 6 deletions(-) create mode 100644 MIT-LICENSE diff --git a/MIT-LICENSE b/MIT-LICENSE new file mode 100644 index 0000000..ade2039 --- /dev/null +++ b/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2012 AUTHOR_NAME + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 53e34ee..d024da9 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,152 @@ +# Dashing! + + + +## Introduction + +Dashing is a framework for building web-based dashboards. + +Features: + + - Custom widgets! Built using whatever HTML/Coffeescript wizardry you posses + - Multiple dashboards! You can have many different views all hosted by the same app + - Shareable widgets! + - ... + +## Installation and Setup + + 1. Install the gem from the command line: + + ```gem install dashing``` + + 2. Generate a new project: + + ```dashing new sweet_dashboard_project``` + + 3. Change your directory to ```sweet_dashboard_project``` and start the Dashing + + ```dashing start``` + + 4. Point your browser at [localhost:3000](http://localhost:3000) + +## Building a dashboard + +```main.erb``` contains the layout for the default dashboard which is accessible at ```/```. You can add additional dashboards with ```COMMAND new_view``` which creates a ```new_view.erb``` file in ```dashboards/```. That new view will be accessible at ```localhost:3000/new_view``` + +Widgets are represented by a ```div``` with ```data-id``` and ```data-view``` attributes. For example: + +```HTML +
+``` + +represents a dashboard with a single widget. + +The ```data-id``` is used to set the widget_id which will be used when we push data to the widget. widget_ids can be shared across dashboards. + +```data-view``` specifies the type of widget what will be used. This field is case sensitive and must match the name of coffeescript class. See making your own widget. + +Getting the style and layout right when you have multiple widgets is hard, that's why we've done it for you. By default Dashing uses [masonry](http://masonry.desandro.com/) to produce a grid layout. + +#### Example +```HTML +
    +
  • +
    +
  • +
  • +
    +
  • +
  • +
    +
  • +
+``` + +## Making you own widget + +To make your own run ```dashing generate sweet_widget``` which will create template files in the ```widget/``` folder or your project. + +### sweet_widget.html + +Contains the HTML for you widget. + +#### Example +```html +

+ +

+```` + +### sweet_widget.coffee + +#### Example +```coffeescript +class Dashing.SweetWidget extends Dashing.Widget + source: 'widget_text' + + onData(data) -> + #stuff? +``` + +### sweet_widget.scss +````scss +$text_value-color: #fff; +$text_title-color: lighten($widget-text-color, 30%); + +.widget-text { + .title { + color: $text_title-color; + } + .p { + color: $text_value-color: + } +} +``` + +## Getting data into Dashing + +### Jobs + +Dashing uses [rufus-scheduler](http://rufus.rubyforge.org/rufus-scheduler/) to schedule jobs. You can make a new job with ```things job super_job``` which will create a file in the jobs folder called ```super_job.rb```. + +Use ```send_event('WIDGET_ID', {text: SAMPLE_DATUMS})``` + +#### Example + +```ruby +# :first_in sets how long it takes before the job is first run. In this case, it is run immediately +SCHEDULER.every '1m', :first_in => 0 do |job| + send_event('widget_id', {text: "I am #{%w(happy sad hungry).sample}"}) +end +``` + +### Push + +You can also push data directly to your dashboard! Post the data you want in json to ```/widgets/widget_id```. You will also have to include your auth_token (which can be found in ```config.ru```) as part of the json object. + +#### Example +```bash +curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "value": 100 }' http://localhost:3000/widgets/synergy +``` + +or + +```ruby +HTTParty.post('http://ADDRESS/widgets/widget_id', + :body => { + auth_token: "YOUR_AUTH_TOKEN", + text: "Weeeeee", + }.to_json) +``` + +## Licensing + +This code is released under the MIT license. Please read the MIT-LICENSE file for more details + TODO ==== -- fix textfield style - tests -- Create a better readme! -- Add data fetching capabilities -- Turn into its own gem -- Come up with a default style -- Create example widgets - investigate if Dir.pwd is the best approach to get the local directory - Create githubpages - Open source! -- cgit v1.2.3 From 780fe49f715c2fced88e958b02541bf8e7dca934 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 8 Aug 2012 18:02:56 -0400 Subject: Rename project to 'Dashing', and do some other cleanups --- allthethings.gemspec | 25 - bin/dashing | 82 +++ bin/things | 81 --- lib/allthethings.rb | 129 ---- lib/dashing.rb | 126 ++++ templates/project/Gemfile | 2 +- templates/project/README.md | 1 - templates/project/config.ru | 2 +- templates/project/dashboards/layout.erb | 24 +- .../project/public/javascripts/jquery.knob.js | 646 +-------------------- templates/project/widgets/list/list.coffee | 6 +- templates/project/widgets/meter/meter.coffee | 14 +- templates/project/widgets/number/number.coffee | 8 +- templates/project/widgets/table/table.coffee | 2 - templates/project/widgets/table/table.html | 8 - templates/project/widgets/table/table.scss | 42 -- templates/project/widgets/text/text.coffee | 3 +- templates/widget/%name%/%name%.coffee.tt | 5 +- templates/widget/%name%/%name%.html | 1 + vendor/javascripts/application.coffee | 10 +- vendor/javascripts/widget.coffee | 10 +- 21 files changed, 262 insertions(+), 965 deletions(-) delete mode 100644 allthethings.gemspec create mode 100755 bin/dashing delete mode 100755 bin/things delete mode 100644 lib/allthethings.rb create mode 100644 lib/dashing.rb delete mode 100644 templates/project/widgets/table/table.coffee delete mode 100644 templates/project/widgets/table/table.html delete mode 100644 templates/project/widgets/table/table.scss diff --git a/allthethings.gemspec b/allthethings.gemspec deleted file mode 100644 index 859d999..0000000 --- a/allthethings.gemspec +++ /dev/null @@ -1,25 +0,0 @@ -Gem::Specification.new do |s| - s.name = 'allthethings' - s.version = '0.1.0' - s.date = '2012-07-24' - s.executables << 'things' - - - s.summary = "A simple & flexible framework for creating dashboards." - s.description = "An elegant, simple, beautiful, & flexible framework for creating dashboards." - s.authors = ["Daniel Beauchamp"] - s.email = 'daniel.beauchamp@shopify.com' - s.files = ["lib/allthethings.rb"] - s.homepage = 'http://allthethings.shopify.com' - - s.files = Dir['README.md', 'vendor/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] - - s.add_dependency('sass') - s.add_dependency('coffee-script') - s.add_dependency('sinatra') - s.add_dependency('sinatra-contrib') - s.add_dependency('thin') - s.add_dependency('rufus-scheduler') - s.add_dependency('thor') - -end \ No newline at end of file diff --git a/bin/dashing b/bin/dashing new file mode 100755 index 0000000..32c89c8 --- /dev/null +++ b/bin/dashing @@ -0,0 +1,82 @@ +#!/usr/bin/env ruby + +require 'thor' +require 'net/http' +require 'json' + +class MockScheduler + def method_missing(*args) + yield + end +end + +def send_event(id, data) + req = Net::HTTP::Post.new("/widgets/#{id}") + req["content-type"] = "application/json" + req.body = JSON.unparse(data.merge(:auth_token => Dashing::CLI.auth_token)) + res = Net::HTTP.new('localhost', 3000).start { |http| http.request(req) } + puts "Data Sent to #{id}: #{data}" +end + +SCHEDULER = MockScheduler.new + +module Dashing + + class CLI < Thor + include Thor::Actions + + class << self + attr_accessor :auth_token + end + + attr_accessor :name + + no_tasks do + ['widget', 'dashboard', 'job'].each do |type| + define_method "generate_#{type}" do |name| + @name = Thor::Util.snake_case(name) + directory type.to_sym, File.join("#{type}s") + end + end + end + + def self.source_root + File.expand_path('../../templates', __FILE__) + end + + desc "new PROJECT_NAME", "Sets up ALL THE THINGS needed for your dashboard project structure." + def new(name) + @name = Thor::Util.snake_case(name) + directory :project, @name + end + + desc "generate GENERATOR NAME", "Creates a new widget with all the fixins'" + def generate(type, name) + send("generate_#{type}".to_sym, name) + rescue NoMethodError => e + puts "Invalid generator. Either use widget, dashboard, or job" + end + map "g" => :generate + + desc "start", "Starts the server in style!" + method_option :job_path, :desc => "Specify the directory where jobs are stored" + def start(*args) + args = args.join(" ") + command = "bundle exec thin -R config.ru start #{args}" + command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] + system(command) + end + map "s" => :start + + desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job." + def job(name, auth_token = "") + Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } + self.class.auth_token = auth_token + f = File.join(Dir.pwd, "jobs", "#{name}.rb") + require f + end + + end +end + +Dashing::CLI.start \ No newline at end of file diff --git a/bin/things b/bin/things deleted file mode 100755 index 0ad9eb3..0000000 --- a/bin/things +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env ruby - -require 'thor' -require 'net/http' -require 'json' - -class MockScheduler - def method_missing(*args) - yield - end -end - -def send_event(id, data) - req = Net::HTTP::Post.new("/widgets/#{id}") - req["content-type"] = "application/json" - req.body = JSON.unparse(data.merge(:auth_token => AllTheThings::CLI.auth_token)) - res = Net::HTTP.new('localhost', 3000).start { |http| http.request(req) } - puts "Data Sent to #{id}: #{data}" -end - -SCHEDULER = MockScheduler.new - -module AllTheThings - - class CLI < Thor - include Thor::Actions - - class << self - attr_accessor :auth_token - end - - attr_accessor :name - - no_tasks do - ['widget', 'dashboard', 'job'].each do |type| - define_method "generate_#{type}" do |name| - @name = Thor::Util.snake_case(name) - directory type.to_sym, File.join("#{type}s") - end - end - end - - def self.source_root - File.expand_path('../../templates', __FILE__) - end - - desc "new PROJECT_NAME", "Sets up ALL THE THINGS needed for your dashboard project structure." - def new(name) - @name = Thor::Util.snake_case(name) - directory :project, @name - end - - desc "generate GENERATOR NAME", "Creates a new widget with all the fixins'" - def generate(type, name) - send("generate_#{type}".to_sym, name) - rescue NoMethodError => e - puts "Invalid generator. Either use widget, dashboard, or job" - end - map "g" => :generate - - desc "start", "Starts the server in style!" - method_option :job_path, :desc => "Specify the directory where jobs are stored" - def start(*args) - args = args.join(" ") - command = "bundle exec thin -R config.ru start #{args}" - command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] - system(command) - end - - desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job." - def job(name, auth_token = "") - Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } - self.class.auth_token = auth_token - f = File.join(Dir.pwd, "jobs", "#{name}.rb") - require f - end - - end -end - -AllTheThings::CLI.start \ No newline at end of file diff --git a/lib/allthethings.rb b/lib/allthethings.rb deleted file mode 100644 index 8fbef07..0000000 --- a/lib/allthethings.rb +++ /dev/null @@ -1,129 +0,0 @@ -require 'sinatra' -require 'sinatra/content_for' -require 'rufus/scheduler' -require 'coffee-script' -require 'sass' -require 'json' - -Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } - -SCHEDULER = Rufus::Scheduler.start_new - -set server: 'thin', connections: [], history: {} -helpers Sinatra::ContentFor - -def configure(&block) - set :public_folder, Dir.pwd + '/public' - set :views, Dir.pwd + '/dashboards' - set :default_dashboard, nil - instance_eval(&block) -end - -helpers do - def protected! - # override with auth logic - end -end - -get '/events', provides: 'text/event-stream' do - protected! - stream :keep_open do |out| - settings.connections << out - out << latest_events - out.callback { settings.connections.delete(out) } - end -end - -get '/' do - begin - redirect "/" + (settings.default_dashboard || first_dashboard).to_s - rescue NoMethodError => e - raise Exception.new("There are no dashboards in your dashboard directory.") - end -end - -get '/:dashboard' do - protected! - erb params[:dashboard].to_sym -end - -get '/views/:widget?.html' do - protected! - widget = params[:widget] - send_file File.join(Dir.pwd, "widgets/#{widget}/#{widget}.html") -end - -post '/widgets/:id' do - request.body.rewind - body = JSON.parse(request.body.read) - auth_token = body.delete("auth_token") - if auth_token == settings.auth_token - send_event(params['id'], body) - 204 # response without entity body - else - status 401 - "Invalid API key\n" - end -end - -def framework_javascripts - ['jquery.js', 'es5-shim.js', 'batman.js', 'batman.jquery.js', 'application.coffee', 'widget.coffee'].collect do |f| - File.join(File.expand_path("../../vendor/javascripts", __FILE__), f) - end -end - -def widget_javascripts - asset_paths("/widgets/**/*.coffee") -end - -def javascripts - (framework_javascripts + widget_javascripts).collect do |f| - if File.extname(f) == ".coffee" - begin - CoffeeScript.compile(File.read(f)) - rescue ExecJS::ProgramError => e - message = e.message + ": in #{f}" - raise ExecJS::ProgramError.new(message) - end - else - File.read(f) - end - end.join("\n") -end - -def stylesheets - asset_paths("/public/**/*.scss", "/widgets/**/*.scss").collect do |f| - Sass.compile File.read(f) - end.join("\n") -end - -def asset_paths(*paths) - paths.inject([]) { |arr, path| arr + Dir[File.join(Dir.pwd, path)] } -end - -def send_event(id, body) - body["id"] = id - event = format_event(JSON.unparse(body)) - settings.history[id] = event - settings.connections.each { |out| out << event } -end - -def format_event(body) - "data: #{body}\n\n" -end - -def latest_events - settings.history.inject("") do |str, (id, body)| - str << body - end -end - -def first_dashboard - files = Dir[settings.views + "/*.erb"].collect { |f| f.match(/(\w*).erb/)[1] } - files -= ['layout'] - files.first -end - -job_path = ENV["JOB_PATH"] || 'jobs' -files = Dir[Dir.pwd + "/#{job_path}/*.rb"] -files.each { |job| require(job) } \ No newline at end of file diff --git a/lib/dashing.rb b/lib/dashing.rb new file mode 100644 index 0000000..8b2af2f --- /dev/null +++ b/lib/dashing.rb @@ -0,0 +1,126 @@ +require 'sinatra' +require 'sinatra/content_for' +require 'rufus/scheduler' +require 'coffee-script' +require 'sass' +require 'json' + +SCHEDULER = Rufus::Scheduler.start_new + +set server: 'thin', connections: [], history: {} +set :public_folder, File.join(Dir.pwd, 'public') +set :views, File.join(Dir.pwd, 'dashboards') +set :default_dashboard, nil +set :auth_token, nil + +helpers Sinatra::ContentFor +helpers do + def protected! + # override with auth logic + end +end + +get '/events', provides: 'text/event-stream' do + protected! + stream :keep_open do |out| + settings.connections << out + out << latest_events + out.callback { settings.connections.delete(out) } + end +end + +get '/' do + begin + redirect "/" + (settings.default_dashboard || first_dashboard).to_s + rescue NoMethodError => e + raise Exception.new("There are no dashboards in your dashboard directory.") + end +end + +get '/:dashboard' do + protected! + erb params[:dashboard].to_sym +end + +get '/views/:widget?.html' do + protected! + widget = params[:widget] + send_file File.join(Dir.pwd, 'widgets', widget, "#{widget}.html") +end + +post '/widgets/:id' do + request.body.rewind + body = JSON.parse(request.body.read) + auth_token = body.delete("auth_token") + if !settings.auth_token || settings.auth_token == auth_token + send_event(params['id'], body) + 204 # response without entity body + else + status 401 + "Invalid API key\n" + end +end + +def framework_javascripts + ['jquery.js', 'es5-shim.js', 'batman.js', 'batman.jquery.js', 'application.coffee', 'widget.coffee'].collect do |f| + File.join(File.expand_path('../../vendor/javascripts', __FILE__), f) + end +end + +def widget_javascripts + asset_paths("/widgets/**/*.coffee") +end + +def javascripts + (framework_javascripts + widget_javascripts).collect do |f| + if File.extname(f) == ".coffee" + begin + CoffeeScript.compile(File.read(f)) + rescue ExecJS::ProgramError => e + message = e.message + ": in #{f}" + raise ExecJS::ProgramError.new(message) + end + else + File.read(f) + end + end.join("\n") +end + +def stylesheets + asset_paths("/public/**/*.scss", "/widgets/**/*.scss").collect do |f| + Sass.compile File.read(f) + end.join("\n") +end + +def asset_paths(*paths) + paths.inject([]) { |arr, path| arr + Dir[File.join(Dir.pwd, path)] } +end + +def send_event(id, body) + body["id"] = id + event = format_event(JSON.unparse(body)) + settings.history[id] = event + settings.connections.each { |out| out << event } +end + +def format_event(body) + "data: #{body}\n\n" +end + +def latest_events + settings.history.inject("") do |str, (id, body)| + str << body + end +end + +def first_dashboard + files = Dir[File.join(settings.views, '*.erb')].collect { |f| f.match(/(\w*).erb/)[1] } + files -= ['layout'] + files.first +end + +Dir[File.join(Dir.pwd, 'lib', '**', '*.rb')].each {|file| require file } + +job_path = ENV["JOB_PATH"] || 'jobs' +files = Dir[File.join(Dir.pwd, job_path, '/*.rb')] +files.each { |job| require(job) } \ No newline at end of file diff --git a/templates/project/Gemfile b/templates/project/Gemfile index 66989b6..7724b81 100644 --- a/templates/project/Gemfile +++ b/templates/project/Gemfile @@ -1,3 +1,3 @@ source :rubygems -gem 'allthethings', '0.1.0', :git => 'git@github.com:Shopify/allthethings.git' \ No newline at end of file +gem 'dashing', '0.1.0', :git => 'git@github.com:Shopify/dashing.git' \ No newline at end of file diff --git a/templates/project/README.md b/templates/project/README.md index 32f36ad..e69de29 100644 --- a/templates/project/README.md +++ b/templates/project/README.md @@ -1 +0,0 @@ -Here lies instructions on how to set this thing up. \ No newline at end of file diff --git a/templates/project/config.ru b/templates/project/config.ru index acc42a0..a3a74de 100644 --- a/templates/project/config.ru +++ b/templates/project/config.ru @@ -1,4 +1,4 @@ -require 'allthethings' +require 'dashing' configure do set :auth_token, 'YOUR_AUTH_TOKEN' diff --git a/templates/project/dashboards/layout.erb b/templates/project/dashboards/layout.erb index cb1a455..1d1aeb3 100644 --- a/templates/project/dashboards/layout.erb +++ b/templates/project/dashboards/layout.erb @@ -2,7 +2,6 @@ - My Awesome Dashboard @@ -17,6 +16,19 @@ + + @@ -24,15 +36,5 @@ <%= yield %>
- - \ No newline at end of file diff --git a/templates/project/public/javascripts/jquery.knob.js b/templates/project/public/javascripts/jquery.knob.js index 3224638..0c5b8f1 100644 --- a/templates/project/public/javascripts/jquery.knob.js +++ b/templates/project/public/javascripts/jquery.knob.js @@ -12,635 +12,17 @@ * * Thanks to vor, eskimoblood, spiffistan, FabrizioC */ -$(function () { - - /** - * Kontrol library - */ - "use strict"; - - /** - * Definition of globals and core - */ - var k = {}, // kontrol - max = Math.max, - min = Math.min; - - k.c = {}; - k.c.d = $(document); - k.c.t = function (e) { - return e.originalEvent.touches.length - 1; - }; - - /** - * Kontrol Object - * - * Definition of an abstract UI control - * - * Each concrete component must call this one. - * - * k.o.call(this); - * - */ - k.o = function () { - var s = this; - - this.o = null; // array of options - this.$ = null; // jQuery wrapped element - this.i = null; // mixed HTMLInputElement or array of HTMLInputElement - this.g = null; // 2D graphics context for 'pre-rendering' - this.v = null; // value ; mixed array or integer - this.cv = null; // change value ; not commited value - this.x = 0; // canvas x position - this.y = 0; // canvas y position - this.$c = null; // jQuery canvas element - this.c = null; // rendered canvas context - this.t = 0; // touches index - this.isInit = false; - this.fgColor = null; // main color - this.pColor = null; // previous color - this.dH = null; // draw hook - this.cH = null; // change hook - this.eH = null; // cancel hook - this.rH = null; // release hook - - this.run = function () { - var cf = function (e, conf) { - var k; - for (k in conf) { - s.o[k] = conf[k]; - } - s.init(); - s._configure() - ._draw(); - }; - - if(this.$.data('kontroled')) return; - this.$.data('kontroled', true); - - this.extend(); - this.o = $.extend( - { - // Config - min : this.$.data('min') || 0, - max : this.$.data('max') || 100, - stopper : true, - readOnly : this.$.data('readonly'), - - // UI - cursor : (this.$.data('cursor') === true && 30) - || this.$.data('cursor') - || 0, - thickness : this.$.data('thickness') || 0.35, - width : this.$.data('width') || 200, - height : this.$.data('height') || 200, - displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'), - displayPrevious : this.$.data('displayprevious'), - fgColor : this.$.data('fgcolor') || '#87CEEB', - inline : false, - - // Hooks - draw : null, // function () {} - change : null, // function (value) {} - cancel : null, // function () {} - release : null // function (value) {} - }, this.o - ); - - // routing value - if(this.$.is('fieldset')) { - - // fieldset = array of integer - this.v = {}; - this.i = this.$.find('input') - this.i.each(function(k) { - var $this = $(this); - s.i[k] = $this; - s.v[k] = $this.val(); - - $this.bind( - 'change' - , function () { - var val = {}; - val[k] = $this.val(); - s.val(val); - } - ); - }); - this.$.find('legend').remove(); - - } else { - // input = integer - this.i = this.$; - this.v = this.$.val(); - (this.v == '') && (this.v = this.o.min); - - this.$.bind( - 'change' - , function () { - s.val(s.$.val()); - } - ); - } - - (!this.o.displayInput) && this.$.hide(); - - this.$c = $(''); - this.c = this.$c[0].getContext("2d"); - - this.$ - .wrap($('
')) - .before(this.$c); - - if (this.v instanceof Object) { - this.cv = {}; - this.copy(this.v, this.cv); - } else { - this.cv = this.v; - } - - this.$ - .bind("configure", cf) - .parent() - .bind("configure", cf); - - this._listen() - ._configure() - ._xy() - .init(); - - this.isInit = true; - - this._draw(); - - return this; - }; - - this._draw = function () { - - // canvas pre-rendering - var d = true, - c = document.createElement('canvas'); - - c.width = s.o.width; - c.height = s.o.height; - s.g = c.getContext('2d'); - - s.clear(); - - s.dH - && (d = s.dH()); - - (d !== false) && s.draw(); - - s.c.drawImage(c, 0, 0); - c = null; - }; - - this._touch = function (e) { - - var touchMove = function (e) { - - var v = s.xy2val( - e.originalEvent.touches[s.t].pageX, - e.originalEvent.touches[s.t].pageY - ); - - if (v == s.cv) return; - - if ( - s.cH - && (s.cH(v) === false) - ) return; - - - s.change(v); - s._draw(); - }; - - // get touches index - this.t = k.c.t(e); - - // First touch - touchMove(e); - - // Touch events listeners - k.c.d - .bind("touchmove.k", touchMove) - .bind( - "touchend.k" - , function () { - k.c.d.unbind('touchmove.k touchend.k'); - - if ( - s.rH - && (s.rH(s.cv) === false) - ) return; - - s.val(s.cv); - } - ); - - return this; - }; - - this._mouse = function (e) { - - var mouseMove = function (e) { - var v = s.xy2val(e.pageX, e.pageY); - if (v == s.cv) return; - - if ( - s.cH - && (s.cH(v) === false) - ) return; - - s.change(v); - s._draw(); - }; - - // First click - mouseMove(e); - - // Mouse events listeners - k.c.d - .bind("mousemove.k", mouseMove) - .bind( - // Escape key cancel current change - "keyup.k" - , function (e) { - if (e.keyCode === 27) { - k.c.d.unbind("mouseup.k mousemove.k keyup.k"); - - if ( - s.eH - && (s.eH() === false) - ) return; - - s.cancel(); - } - } - ) - .bind( - "mouseup.k" - , function (e) { - k.c.d.unbind('mousemove.k mouseup.k keyup.k'); - - if ( - s.rH - && (s.rH(s.cv) === false) - ) return; - - s.val(s.cv); - } - ); - - return this; - }; - - this._xy = function () { - var o = this.$c.offset(); - this.x = o.left; - this.y = o.top; - return this; - }; - - this._listen = function () { - - if (!this.o.readOnly) { - this.$c - .bind( - "mousedown" - , function (e) { - e.preventDefault(); - s._xy()._mouse(e); - } - ) - .bind( - "touchstart" - , function (e) { - e.preventDefault(); - s._xy()._touch(e); - } - ); - this.listen(); - } else { - this.$.attr('readonly', 'readonly'); - } - - return this; - }; - - this._configure = function () { - - // Hooks - if (this.o.draw) this.dH = this.o.draw; - if (this.o.change) this.cH = this.o.change; - if (this.o.cancel) this.eH = this.o.cancel; - if (this.o.release) this.rH = this.o.release; - - if (this.o.displayPrevious) { - this.pColor = this.h2rgba(this.o.fgColor, "0.4"); - this.fgColor = this.h2rgba(this.o.fgColor, "0.6"); - } else { - this.fgColor = this.o.fgColor; - } - - return this; - }; - - this._clear = function () { - this.$c[0].width = this.$c[0].width; - }; - - // Abstract methods - this.listen = function () {}; // on start, one time - this.extend = function () {}; // each time configure triggered - this.init = function () {}; // each time configure triggered - this.change = function (v) {}; // on change - this.val = function (v) {}; // on release - this.xy2val = function (x, y) {}; // - this.draw = function () {}; // on change / on release - this.clear = function () { this._clear(); }; - - // Utils - this.h2rgba = function (h, a) { - var rgb; - h = h.substring(1,7) - rgb = [parseInt(h.substring(0,2),16) - ,parseInt(h.substring(2,4),16) - ,parseInt(h.substring(4,6),16)]; - return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")"; - }; - - this.copy = function (f, t) { - for (var i in f) { t[i] = f[i]; } - }; - }; - - - /** - * k.Dial - */ - k.Dial = function () { - k.o.call(this); - - this.startAngle = null; - this.xy = null; - this.radius = null; - this.lineWidth = null; - this.cursorExt = null; - this.w2 = null; - this.PI2 = 2*Math.PI; - - this.extend = function () { - this.o = $.extend( - { - bgColor : this.$.data('bgcolor') || '#EEEEEE', - angleOffset : this.$.data('angleoffset') || 0, - angleArc : this.$.data('anglearc') || 360, - inline : true - }, this.o - ); - }; - - this.val = function (v) { - if (null != v) { - this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v; - this.v = this.cv; - this.$.val(this.v); - this._draw(); - } else { - return this.v; - } - }; - - this.xy2val = function (x, y) { - var a, ret; - - a = Math.atan2( - x - (this.x + this.w2) - , - (y - this.y - this.w2) - ) - this.angleOffset; - - if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) { - // if isset angleArc option, set to min if .5 under min - a = 0; - } else if (a < 0) { - a += this.PI2; - } - - ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc)) - + this.o.min; - - this.o.stopper - && (ret = max(min(ret, this.o.max), this.o.min)); - - return ret; - }; - - this.listen = function () { - // bind MouseWheel - var s = this, - mw = function (e) { - e.preventDefault(); - - var ori = e.originalEvent - ,deltaX = ori.detail || ori.wheelDeltaX - ,deltaY = ori.detail || ori.wheelDeltaY - ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? 1 : deltaX<0 || deltaY<0 ? -1 : 0); - - if ( - s.cH - && (s.cH(v) === false) - ) return; - - s.val(v); - } - , kval, to, m = 1, kv = {37:-1, 38:1, 39:1, 40:-1}; - - this.$ - .bind( - "keydown" - ,function (e) { - var kc = e.keyCode; - kval = parseInt(String.fromCharCode(kc)); - - if (isNaN(kval)) { - - (kc !== 13) // enter - && (kc !== 8) // bs - && (kc !== 9) // tab - && (kc !== 189) // - - && e.preventDefault(); - - // arrows - if ($.inArray(kc,[37,38,39,40]) > -1) { - e.preventDefault(); - - var v = parseInt(s.$.val()) + kv[kc] * m; - - s.o.stopper - && (v = max(min(v, s.o.max), s.o.min)); - - s.change(v); - s._draw(); - - // long time keydown speed-up - to = window.setTimeout( - function () { m*=2; } - ,30 - ); - } - } - } - ) - .bind( - "keyup" - ,function (e) { - if (isNaN(kval)) { - if (to) { - window.clearTimeout(to); - to = null; - m = 1; - s.val(s.$.val()); - } - } else { - // kval postcond - (s.$.val() > s.o.max && s.$.val(s.o.max)) - || (s.$.val() < s.o.min && s.$.val(s.o.min)); - } - - } - ); - - this.$c.bind("mousewheel DOMMouseScroll", mw); - this.$.bind("mousewheel DOMMouseScroll", mw) - }; - - this.init = function () { - - if ( - this.v < this.o.min - || this.v > this.o.max - ) this.v = this.o.min; - - this.$.val(this.v); - this.w2 = this.o.width / 2; - this.cursorExt = this.o.cursor / 100; - this.xy = this.w2; - this.lineWidth = this.xy * this.o.thickness; - this.radius = this.xy - this.lineWidth / 2; - - this.o.angleOffset - && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset); - - this.o.angleArc - && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc); - - // deg to rad - this.angleOffset = this.o.angleOffset * Math.PI / 180; - this.angleArc = this.o.angleArc * Math.PI / 180; - - // compute start and end angles - this.startAngle = 1.5 * Math.PI + this.angleOffset; - this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc; - - var s = max( - String(Math.abs(this.o.max)).length - , String(Math.abs(this.o.min)).length - , 2 - ) + 2; - - this.o.displayInput - && this.i.css({ - 'width' : ((this.o.width / 2 + 4) >> 0) + 'px' - ,'height' : ((this.o.width / 3) >> 0) + 'px' - ,'position' : 'absolute' - ,'vertical-align' : 'middle' - ,'margin-top' : ((this.o.width / 3) >> 0) + 'px' - ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px' - ,'border' : 0 - ,'background' : 'none' - ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial' - ,'text-align' : 'center' - ,'color' : this.o.fgColor - ,'padding' : '0px' - ,'-webkit-appearance': 'none' - }) - || this.i.css({ - 'width' : '0px' - ,'visibility' : 'hidden' - }); - }; - - this.change = function (v) { - this.cv = v; - this.$.val(v); - }; - - this.angle = function (v) { - return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min); - }; - - this.draw = function () { - - var c = this.g, // context - a = this.angle(this.cv) // Angle - , sat = this.startAngle // Start angle - , eat = sat + a // End angle - , sa, ea // Previous angles - , r = 1; - - c.lineWidth = this.lineWidth; - - this.o.cursor - && (sat = eat - this.cursorExt) - && (eat = eat + this.cursorExt); - - c.beginPath(); - c.strokeStyle = this.o.bgColor; - c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true); - c.stroke(); - - if (this.o.displayPrevious) { - ea = this.startAngle + this.angle(this.v); - sa = this.startAngle; - this.o.cursor - && (sa = ea - this.cursorExt) - && (ea = ea + this.cursorExt); - - c.beginPath(); - c.strokeStyle = this.pColor; - c.arc(this.xy, this.xy, this.radius, sa, ea, false); - c.stroke(); - r = (this.cv == this.v); - } - - c.beginPath(); - c.strokeStyle = r ? this.o.fgColor : this.fgColor ; - c.arc(this.xy, this.xy, this.radius, sat, eat, false); - c.stroke(); - }; - - this.cancel = function () { - this.val(this.v); - }; - }; - - $.fn.dial = $.fn.knob = function (o) { - return this.each( - function () { - var d = new k.Dial(); - d.o = o; - d.$ = $(this); - d.run(); - } - ).parent(); - }; - -}); \ No newline at end of file +$(function(){"use strict";var k={},max=Math.max,min=Math.min;k.c={};k.c.d=$(document);k.c.t=function(e){return e.originalEvent.touches.length-1;};k.o=function(){var s=this;this.o=null;this.$=null;this.i=null;this.g=null;this.v=null;this.cv=null;this.x=0;this.y=0;this.$c=null;this.c=null;this.t=0;this.isInit=false;this.fgColor=null;this.pColor=null;this.dH=null;this.cH=null;this.eH=null;this.rH=null;this.run=function(){var cf=function(e,conf){var k;for(k in conf){s.o[k]=conf[k];} +s.init();s._configure()._draw();};if(this.$.data('kontroled'))return;this.$.data('kontroled',true);this.extend();this.o=$.extend({min:this.$.data('min')||0,max:this.$.data('max')||100,stopper:true,readOnly:this.$.data('readonly'),cursor:(this.$.data('cursor')===true&&30)||this.$.data('cursor')||0,thickness:this.$.data('thickness')||0.35,width:this.$.data('width')||200,height:this.$.data('height')||200,displayInput:this.$.data('displayinput')==null||this.$.data('displayinput'),displayPrevious:this.$.data('displayprevious'),fgColor:this.$.data('fgcolor')||'#87CEEB',inline:false,draw:null,change:null,cancel:null,release:null},this.o);if(this.$.is('fieldset')){this.v={};this.i=this.$.find('input') +this.i.each(function(k){var $this=$(this);s.i[k]=$this;s.v[k]=$this.val();$this.bind('change',function(){var val={};val[k]=$this.val();s.val(val);});});this.$.find('legend').remove();}else{this.i=this.$;this.v=this.$.val();(this.v=='')&&(this.v=this.o.min);this.$.bind('change',function(){s.val(s.$.val());});} +(!this.o.displayInput)&&this.$.hide();this.$c=$('');this.c=this.$c[0].getContext("2d");this.$.wrap($('
')).before(this.$c);if(this.v instanceof Object){this.cv={};this.copy(this.v,this.cv);}else{this.cv=this.v;} +this.$.bind("configure",cf).parent().bind("configure",cf);this._listen()._configure()._xy().init();this.isInit=true;this._draw();return this;};this._draw=function(){var d=true,c=document.createElement('canvas');c.width=s.o.width;c.height=s.o.height;s.g=c.getContext('2d');s.clear();s.dH&&(d=s.dH());(d!==false)&&s.draw();s.c.drawImage(c,0,0);c=null;};this._touch=function(e){var touchMove=function(e){var v=s.xy2val(e.originalEvent.touches[s.t].pageX,e.originalEvent.touches[s.t].pageY);if(v==s.cv)return;if(s.cH&&(s.cH(v)===false))return;s.change(v);s._draw();};this.t=k.c.t(e);touchMove(e);k.c.d.bind("touchmove.k",touchMove).bind("touchend.k",function(){k.c.d.unbind('touchmove.k touchend.k');if(s.rH&&(s.rH(s.cv)===false))return;s.val(s.cv);});return this;};this._mouse=function(e){var mouseMove=function(e){var v=s.xy2val(e.pageX,e.pageY);if(v==s.cv)return;if(s.cH&&(s.cH(v)===false))return;s.change(v);s._draw();};mouseMove(e);k.c.d.bind("mousemove.k",mouseMove).bind("keyup.k",function(e){if(e.keyCode===27){k.c.d.unbind("mouseup.k mousemove.k keyup.k");if(s.eH&&(s.eH()===false))return;s.cancel();}}).bind("mouseup.k",function(e){k.c.d.unbind('mousemove.k mouseup.k keyup.k');if(s.rH&&(s.rH(s.cv)===false))return;s.val(s.cv);});return this;};this._xy=function(){var o=this.$c.offset();this.x=o.left;this.y=o.top;return this;};this._listen=function(){if(!this.o.readOnly){this.$c.bind("mousedown",function(e){e.preventDefault();s._xy()._mouse(e);}).bind("touchstart",function(e){e.preventDefault();s._xy()._touch(e);});this.listen();}else{this.$.attr('readonly','readonly');} +return this;};this._configure=function(){if(this.o.draw)this.dH=this.o.draw;if(this.o.change)this.cH=this.o.change;if(this.o.cancel)this.eH=this.o.cancel;if(this.o.release)this.rH=this.o.release;if(this.o.displayPrevious){this.pColor=this.h2rgba(this.o.fgColor,"0.4");this.fgColor=this.h2rgba(this.o.fgColor,"0.6");}else{this.fgColor=this.o.fgColor;} +return this;};this._clear=function(){this.$c[0].width=this.$c[0].width;};this.listen=function(){};this.extend=function(){};this.init=function(){};this.change=function(v){};this.val=function(v){};this.xy2val=function(x,y){};this.draw=function(){};this.clear=function(){this._clear();};this.h2rgba=function(h,a){var rgb;h=h.substring(1,7) +rgb=[parseInt(h.substring(0,2),16),parseInt(h.substring(2,4),16),parseInt(h.substring(4,6),16)];return"rgba("+rgb[0]+","+rgb[1]+","+rgb[2]+","+a+")";};this.copy=function(f,t){for(var i in f){t[i]=f[i];}};};k.Dial=function(){k.o.call(this);this.startAngle=null;this.xy=null;this.radius=null;this.lineWidth=null;this.cursorExt=null;this.w2=null;this.PI2=2*Math.PI;this.extend=function(){this.o=$.extend({bgColor:this.$.data('bgcolor')||'#EEEEEE',angleOffset:this.$.data('angleoffset')||0,angleArc:this.$.data('anglearc')||360,inline:true},this.o);};this.val=function(v){if(null!=v){this.cv=this.o.stopper?max(min(v,this.o.max),this.o.min):v;this.v=this.cv;this.$.val(this.v);this._draw();}else{return this.v;}};this.xy2val=function(x,y){var a,ret;a=Math.atan2(x-(this.x+this.w2),-(y-this.y-this.w2))-this.angleOffset;if(this.angleArc!=this.PI2&&(a<0)&&(a>-0.5)){a=0;}else if(a<0){a+=this.PI2;} +ret=~~(0.5+(a*(this.o.max-this.o.min)/this.angleArc)) ++this.o.min;this.o.stopper&&(ret=max(min(ret,this.o.max),this.o.min));return ret;};this.listen=function(){var s=this,mw=function(e){e.preventDefault();var ori=e.originalEvent,deltaX=ori.detail||ori.wheelDeltaX,deltaY=ori.detail||ori.wheelDeltaY,v=parseInt(s.$.val())+(deltaX>0||deltaY>0?1:deltaX<0||deltaY<0?-1:0);if(s.cH&&(s.cH(v)===false))return;s.val(v);},kval,to,m=1,kv={37:-1,38:1,39:1,40:-1};this.$.bind("keydown",function(e){var kc=e.keyCode;kval=parseInt(String.fromCharCode(kc));if(isNaN(kval)){(kc!==13)&&(kc!==8)&&(kc!==9)&&(kc!==189)&&e.preventDefault();if($.inArray(kc,[37,38,39,40])>-1){e.preventDefault();var v=parseInt(s.$.val())+kv[kc]*m;s.o.stopper&&(v=max(min(v,s.o.max),s.o.min));s.change(v);s._draw();to=window.setTimeout(function(){m*=2;},30);}}}).bind("keyup",function(e){if(isNaN(kval)){if(to){window.clearTimeout(to);to=null;m=1;s.val(s.$.val());}}else{(s.$.val()>s.o.max&&s.$.val(s.o.max))||(s.$.val()this.o.max)this.v=this.o.min;this.$.val(this.v);this.w2=this.o.width/2;this.cursorExt=this.o.cursor/100;this.xy=this.w2;this.lineWidth=this.xy*this.o.thickness;this.radius=this.xy-this.lineWidth/2;this.o.angleOffset&&(this.o.angleOffset=isNaN(this.o.angleOffset)?0:this.o.angleOffset);this.o.angleArc&&(this.o.angleArc=isNaN(this.o.angleArc)?this.PI2:this.o.angleArc);this.angleOffset=this.o.angleOffset*Math.PI/180;this.angleArc=this.o.angleArc*Math.PI/180;this.startAngle=1.5*Math.PI+this.angleOffset;this.endAngle=1.5*Math.PI+this.angleOffset+this.angleArc;var s=max(String(Math.abs(this.o.max)).length,String(Math.abs(this.o.min)).length,2)+2;this.o.displayInput&&this.i.css({'width':((this.o.width/2+4)>>0)+'px','height':((this.o.width/3)>>0)+'px','position':'absolute','vertical-align':'middle','margin-top':((this.o.width/3)>>0)+'px','margin-left':'-'+((this.o.width*3/4+2)>>0)+'px','border':0,'background':'none','font':'bold '+((this.o.width/s)>>0)+'px Arial','text-align':'center','color':this.o.fgColor,'padding':'0px','-webkit-appearance':'none'})||this.i.css({'width':'0px','visibility':'hidden'});};this.change=function(v){this.cv=v;this.$.val(v);};this.angle=function(v){return(v-this.o.min)*this.angleArc/(this.o.max-this.o.min);};this.draw=function(){var c=this.g,a=this.angle(this.cv),sat=this.startAngle,eat=sat+a,sa,ea,r=1;c.lineWidth=this.lineWidth;this.o.cursor&&(sat=eat-this.cursorExt)&&(eat=eat+this.cursorExt);c.beginPath();c.strokeStyle=this.o.bgColor;c.arc(this.xy,this.xy,this.radius,this.endAngle,this.startAngle,true);c.stroke();if(this.o.displayPrevious){ea=this.startAngle+this.angle(this.v);sa=this.startAngle;this.o.cursor&&(sa=ea-this.cursorExt)&&(ea=ea+this.cursorExt);c.beginPath();c.strokeStyle=this.pColor;c.arc(this.xy,this.xy,this.radius,sa,ea,false);c.stroke();r=(this.cv==this.v);} +c.beginPath();c.strokeStyle=r?this.o.fgColor:this.fgColor;c.arc(this.xy,this.xy,this.radius,sat,eat,false);c.stroke();};this.cancel=function(){this.val(this.v);};};$.fn.dial=$.fn.knob=function(o){return this.each(function(){var d=new k.Dial();d.o=o;d.$=$(this);d.run();}).parent();};}); \ No newline at end of file diff --git a/templates/project/widgets/list/list.coffee b/templates/project/widgets/list/list.coffee index 6b1cc50..3ca892b 100644 --- a/templates/project/widgets/list/list.coffee +++ b/templates/project/widgets/list/list.coffee @@ -1,7 +1,5 @@ -class AllTheThings.List extends AllTheThings.Widget - source: 'list' - - @accessor 'current', Batman.Property.EasingSetter +class Dashing.List extends Dashing.Widget + @accessor 'current', Dashing.AnimatedValue @accessor 'arrow', -> if @get('last') diff --git a/templates/project/widgets/meter/meter.coffee b/templates/project/widgets/meter/meter.coffee index 4dbc2da..0e0a8ad 100644 --- a/templates/project/widgets/meter/meter.coffee +++ b/templates/project/widgets/meter/meter.coffee @@ -1,7 +1,6 @@ -class AllTheThings.Meter extends AllTheThings.Widget - source: 'meter' +class Dashing.Meter extends Dashing.Widget - @accessor 'value', Batman.Property.EasingSetter + @accessor 'value', Dashing.AnimatedValue constructor: -> super @@ -9,8 +8,7 @@ class AllTheThings.Meter extends AllTheThings.Widget $(@node).find(".meter").val(value).trigger('change') ready: -> - Batman.setImmediate => - meter = $(@node).find(".meter") - meter.attr("data-bgcolor", meter.css("background-color")) - meter.attr("data-fgcolor", meter.css("color")) - meter.knob() \ No newline at end of file + meter = $(@node).find(".meter") + meter.attr("data-bgcolor", meter.css("background-color")) + meter.attr("data-fgcolor", meter.css("color")) + meter.knob() \ No newline at end of file diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee index aa7cf8b..cb8376e 100644 --- a/templates/project/widgets/number/number.coffee +++ b/templates/project/widgets/number/number.coffee @@ -1,9 +1,5 @@ -class AllTheThings.Number extends AllTheThings.Widget - source: 'number' - - @accessor 'current', Batman.Property.EasingSetter - - ready: -> +class Dashing.Number extends Dashing.Widget + @accessor 'current', Dashing.AnimatedValue @accessor 'difference', -> if @get('last') diff --git a/templates/project/widgets/table/table.coffee b/templates/project/widgets/table/table.coffee deleted file mode 100644 index 5735316..0000000 --- a/templates/project/widgets/table/table.coffee +++ /dev/null @@ -1,2 +0,0 @@ -class AllTheThings.Table extends AllTheThings.Widget - source: 'table' \ No newline at end of file diff --git a/templates/project/widgets/table/table.html b/templates/project/widgets/table/table.html deleted file mode 100644 index e5aeb99..0000000 --- a/templates/project/widgets/table/table.html +++ /dev/null @@ -1,8 +0,0 @@ -

- - - - - - -
\ No newline at end of file diff --git a/templates/project/widgets/table/table.scss b/templates/project/widgets/table/table.scss deleted file mode 100644 index 0d38164..0000000 --- a/templates/project/widgets/table/table.scss +++ /dev/null @@ -1,42 +0,0 @@ -// ---------------------------------------------------------------------------- -// Sass declarations -// ---------------------------------------------------------------------------- -$widget-table_background-color: #82b53d; -$widget-table_value-color: #fff; - -$widget-table_title-color: lighten($widget-table_background-color, 45%); -$widget-table_label-color: lighten($widget-table_background-color, 45%); - -// ---------------------------------------------------------------------------- -// Widget-table styles -// ---------------------------------------------------------------------------- -.widget-table { - - background-color: $widget-table_background-color; - - th { - font-weight: 400; - font-size: 16px; - } - - td.label { - vertical-align: middle; - text-align: left; - font-size: 23px; - } - - .title { - color: $widget-table_title-color; - } - - .label { - color: $widget-table_label-color; - } - - .value { - font-weight: 700; - font-size: 54px; - color: $widget-table_value-color; - } - -} \ No newline at end of file diff --git a/templates/project/widgets/text/text.coffee b/templates/project/widgets/text/text.coffee index 754644e..05974b8 100644 --- a/templates/project/widgets/text/text.coffee +++ b/templates/project/widgets/text/text.coffee @@ -1,2 +1 @@ -class AllTheThings.Text extends AllTheThings.Widget - source: 'text' \ No newline at end of file +class Dashing.Text extends Dashing.Widget \ No newline at end of file diff --git a/templates/widget/%name%/%name%.coffee.tt b/templates/widget/%name%/%name%.coffee.tt index 5ddfb1b..9105f9a 100644 --- a/templates/widget/%name%/%name%.coffee.tt +++ b/templates/widget/%name%/%name%.coffee.tt @@ -1,5 +1,4 @@ -class AllTheThings.<%= Thor::Util.camel_case(name) %> extends AllTheThings.Widget - source: '<%= name %>' +class Dashing.<%= Thor::Util.camel_case(name) %> extends Dashing.Widget ready: -> # This is fired when the widget is done being rendered @@ -7,5 +6,5 @@ class AllTheThings.<%= Thor::Util.camel_case(name) %> extends AllTheThings.Widge onData: (data) -> # Handle incoming data # You can access the html node of this widget with `@node` - # Example: $(@node).effect("pulsate") will make the node flash each time data comes in. + # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. super \ No newline at end of file diff --git a/templates/widget/%name%/%name%.html b/templates/widget/%name%/%name%.html index e69de29..789f2e3 100644 --- a/templates/widget/%name%/%name%.html +++ b/templates/widget/%name%/%name%.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/vendor/javascripts/application.coffee b/vendor/javascripts/application.coffee index 6704ee5..4302611 100644 --- a/vendor/javascripts/application.coffee +++ b/vendor/javascripts/application.coffee @@ -18,10 +18,10 @@ Batman.Filters.shortenedNumber = (num) -> else num -class window.AllTheThings extends Batman.App +class window.Dashing extends Batman.App @root -> -Batman.Property.EasingSetter = +Dashing.AnimatedValue = get: Batman.Property.defaultAccessor.get set: (k, to) -> if isNaN(to) @@ -44,8 +44,8 @@ Batman.Property.EasingSetter = @set k, to @[k] = num -AllTheThings.widgets = widgets = {} -AllTheThings.lastEvents = lastEvents = {} +Dashing.widgets = widgets = {} +Dashing.lastEvents = lastEvents = {} source = new EventSource('/events') source.addEventListener 'open', (e) -> @@ -65,4 +65,4 @@ source.addEventListener 'message', (e) => $(document).ready -> - AllTheThings.run() \ No newline at end of file + Dashing.run() \ No newline at end of file diff --git a/vendor/javascripts/widget.coffee b/vendor/javascripts/widget.coffee index 5c5c1a3..980cae3 100644 --- a/vendor/javascripts/widget.coffee +++ b/vendor/javascripts/widget.coffee @@ -1,11 +1,13 @@ -class AllTheThings.Widget extends Batman.View +class Dashing.Widget extends Batman.View constructor: -> + # Set the view path + @constructor::source = Batman.Filters.underscore(@constructor.name) super @mixin($(@node).data()) - AllTheThings.widgets[@id] ||= [] - AllTheThings.widgets[@id].push(@) - @mixin(AllTheThings.lastEvents[@id]) # in case the events from the server came before the widget was rendered + Dashing.widgets[@id] ||= [] + Dashing.widgets[@id].push(@) + @mixin(Dashing.lastEvents[@id]) # in case the events from the server came before the widget was rendered type = Batman.Filters.dashize(@view) $(@node).addClass("widget widget-#{type} #{@id}") -- cgit v1.2.3 From 57afd3fed0fb96cf664dbed4de829d1f69176b2d Mon Sep 17 00:00:00 2001 From: Wesley Ellis Date: Wed, 8 Aug 2012 18:12:33 -0400 Subject: moar readme --- README.md | 114 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index d024da9..13b00c7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Dashing! - +A handsome dashboard framework solution ## Introduction @@ -9,9 +9,10 @@ Dashing is a framework for building web-based dashboards. Features: - Custom widgets! Built using whatever HTML/Coffeescript wizardry you posses - - Multiple dashboards! You can have many different views all hosted by the same app - - Shareable widgets! - - ... + - Multiple dashboards! You can have many different views all hosted in the same location + - Shared widgets! It's easy to have have the same widget show up on different dashboards + - Push or pull data, you decide! + - Responsive grid layout! Your dashboard will look good on any sized screen ## Installation and Setup @@ -23,7 +24,7 @@ Features: ```dashing new sweet_dashboard_project``` - 3. Change your directory to ```sweet_dashboard_project``` and start the Dashing + 3. Change your directory to ```sweet_dashboard_project``` and start Dashing ```dashing start``` @@ -31,23 +32,32 @@ Features: ## Building a dashboard -```main.erb``` contains the layout for the default dashboard which is accessible at ```/```. You can add additional dashboards with ```COMMAND new_view``` which creates a ```new_view.erb``` file in ```dashboards/```. That new view will be accessible at ```localhost:3000/new_view``` +```main.erb``` contains the layout for the default dashboard which is accessible at ```/```. +You can add additional dashboards with by running ```dashing COMMAND THINGY new_view``` which creates a ```new_view.erb``` file in ```dashboards/```. +That new view will be accessible at ```localhost:3000/new_view``` -Widgets are represented by a ```div``` with ```data-id``` and ```data-view``` attributes. For example: +## Widgets + +Widgets are represented by a ```div``` element with ```data-id``` and ```data-view``` attributes. eg: ```HTML
``` -represents a dashboard with a single widget. +The ```data-id``` attribute is used to set the **widget ID** which will be used when to push data to the widget. Two widgets can have the same widget id, allowing you to have the same widget in multiple dashboards. -The ```data-id``` is used to set the widget_id which will be used when we push data to the widget. widget_ids can be shared across dashboards. +```data-view``` specifies the type of widget what will be used. This field is case sensitive and must match the coffeescript class of the widget. See making your own widget section for more details. -```data-view``` specifies the type of widget what will be used. This field is case sensitive and must match the name of coffeescript class. See making your own widget. +This ```
``` can also be used to configure your widgets. For example, the pre-bundled widgets let you set a title with ```data-title="Widget Title"```. -Getting the style and layout right when you have multiple widgets is hard, that's why we've done it for you. By default Dashing uses [masonry](http://masonry.desandro.com/) to produce a grid layout. +### Layout + +Getting the style and layout right when you have multiple widgets is hard, that's why we've done it for you. By default Dashing uses [masonry](http://masonry.desandro.com/) to produce a grid layout. If it can, your dashboard will fill the screen with 5 columns. If there isn't enough room though, widgets will be reorganized to fit into fewer columns until you are left with a single column + +Examples here? + +Masonry requires that your widgets be contained within a ```
    ``` element as follows: -#### Example ```HTML
    • @@ -62,33 +72,51 @@ Getting the style and layout right when you have multiple widgets is hard, that'
    ``` -## Making you own widget +### Making you own widget -To make your own run ```dashing generate sweet_widget``` which will create template files in the ```widget/``` folder or your project. +A widget consists of three parts: -### sweet_widget.html + - an html file used for layout and bindings + - a scss file for style + - a coffeescript file which allows you to operate on the data + +To make your own run ```dashing generate sweet_widget``` which will create scaffolding files in the ```widget/``` folder or your project. + +#### sweet_widget.html Contains the HTML for you widget. +We use [batman bindings](http://batmanjs.org/docs/batman.html#batman-view-bindings-how-to-use-bindings) in order to update the content of a widget. +In the example below, updating the title attribute of the coffeescript object representing that widget will set the innerHTML of the ```

    ``` element. +Dashing provides a simple way to update your widgets attributes through a push interface and a pull interface. See the Getting Data into Dashing section. -#### Example +##### Example ```html

    ```` -### sweet_widget.coffee +#### sweet_widget.coffee -#### Example +This coffee script file allows you to perform any operations you wish on your widget. In the example below we can initialize things with the constructor method. +We can also manipulate the data we recieve from data updates. Data will be the JSON object you pass in. + +##### Example ```coffeescript class Dashing.SweetWidget extends Dashing.Widget - source: 'widget_text' - onData(data) -> - #stuff? + constructor: -> + super + @set('attr', 'wooo') + + onData: (data) -> + super + @set('cool_thing', data.massage.split(',')[2] ``` -### sweet_widget.scss +#### sweet_widget.scss + +##### Example ````scss $text_value-color: #fff; $text_title-color: lighten($widget-text-color, 30%); @@ -105,11 +133,14 @@ $text_title-color: lighten($widget-text-color, 30%); ## Getting data into Dashing -### Jobs +Providing data to widgets is easy. You specify which widget you want using a widget id. Dashing expects the data you send to be in JSON format. +Upon getting data, dashing mixes the json into the widget object. So it's easy to update multiple attributes within the same object. -Dashing uses [rufus-scheduler](http://rufus.rubyforge.org/rufus-scheduler/) to schedule jobs. You can make a new job with ```things job super_job``` which will create a file in the jobs folder called ```super_job.rb```. +### Jobs (poll) -Use ```send_event('WIDGET_ID', {text: SAMPLE_DATUMS})``` +Dashing uses [rufus-scheduler](http://rufus.rubyforge.org/rufus-scheduler/) to schedule jobs. +You can make a new job with ```dashing job super_job``` which will create a file in the jobs folder called ```super_job.rb```. +Data is sent to a widget using the ```send_event(widget_id, json_formatted_data)``` method. #### Example @@ -122,7 +153,8 @@ end ### Push -You can also push data directly to your dashboard! Post the data you want in json to ```/widgets/widget_id```. You will also have to include your auth_token (which can be found in ```config.ru```) as part of the json object. +You can also push data directly to your dashboard! Post the data you want in json to ```/widgets/widget_id```. +For security, you will also have to include your auth_token (which can be found in ```config.ru```) as part of the json object. #### Example ```bash @@ -133,20 +165,26 @@ or ```ruby HTTParty.post('http://ADDRESS/widgets/widget_id', - :body => { - auth_token: "YOUR_AUTH_TOKEN", - text: "Weeeeee", - }.to_json) + :body => { auth_token: "YOUR_AUTH_TOKEN", text: "Weeeeee"}.to_json) ``` -## Licensing +## Misc -This code is released under the MIT license. Please read the MIT-LICENSE file for more details +### Deploying to heroku -TODO -==== +### Using omni-auth + +## Dependencies + + - [Sinatra](http://www.sinatrarb.com/) + - [batman.js](http://batmanjs.org/) + - [rufus-scheduler](http://rufus.rubyforge.org/rufus-scheduler/) + - [Thor](https://github.com/wycats/thor/) + - [jQuery-knob](http://anthonyterrien.com/knob/) + - [masonry](http://masonry.desandro.com/) + - [thin](http://code.macournoyer.com/thin/) + - [Sass](http://sass-lang.com/) + +## Licensing -- tests -- investigate if Dir.pwd is the best approach to get the local directory -- Create githubpages -- Open source! +This code is released under the MIT license. See ```MIT-LICENSE``` file for more details \ No newline at end of file -- cgit v1.2.3 From 0aa550c75b38f0694efcb0fa452b08ddd200632c Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 8 Aug 2012 18:41:26 -0400 Subject: Including gem spec. --- dashing.gemspec | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 dashing.gemspec diff --git a/dashing.gemspec b/dashing.gemspec new file mode 100644 index 0000000..a1a8cbc --- /dev/null +++ b/dashing.gemspec @@ -0,0 +1,25 @@ +Gem::Specification.new do |s| + s.name = 'dashing' + s.version = '0.1.0' + s.date = '2012-07-24' + s.executables << 'dashing' + + + s.summary = "A simple & flexible framework for creating dashboards." + s.description = "An elegant, simple, beautiful, & flexible framework for creating dashboards." + s.authors = ["Daniel Beauchamp"] + s.email = 'daniel.beauchamp@shopify.com' + s.files = ["lib/Dashing.rb"] + s.homepage = 'http://Dashing.shopify.com' + + s.files = Dir['README.md', 'vendor/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] + + s.add_dependency('sass') + s.add_dependency('coffee-script') + s.add_dependency('sinatra') + s.add_dependency('sinatra-contrib') + s.add_dependency('thin') + s.add_dependency('rufus-scheduler') + s.add_dependency('thor') + +end \ No newline at end of file -- cgit v1.2.3 From 41d8c33a6b87c948a7fe4ae5e53483d42fead422 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Thu, 9 Aug 2012 13:54:46 -0400 Subject: Re-layout with masonry whenever a widget is ready. --- templates/project/dashboards/layout.erb | 7 ++++--- vendor/javascripts/widget.coffee | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/templates/project/dashboards/layout.erb b/templates/project/dashboards/layout.erb index 1d1aeb3..97cb96d 100644 --- a/templates/project/dashboards/layout.erb +++ b/templates/project/dashboards/layout.erb @@ -22,12 +22,13 @@ $('#container ul').masonry({ itemSelector: '.widget-container' }); } - Dashing.on('ready', function() { - setTimeout(relayout, 0); + Dashing.Widget.on('ready', function(){ + setTimeout(function(){ + relayout(); + }, 0); }); $(window).resize(relayout); - diff --git a/vendor/javascripts/widget.coffee b/vendor/javascripts/widget.coffee index 980cae3..7be3a5d 100644 --- a/vendor/javascripts/widget.coffee +++ b/vendor/javascripts/widget.coffee @@ -12,5 +12,9 @@ class Dashing.Widget extends Batman.View type = Batman.Filters.dashize(@view) $(@node).addClass("widget widget-#{type} #{@id}") + + @::on 'ready', -> + Dashing.Widget.fire 'ready' + onData: (data) => @mixin(data) \ No newline at end of file -- cgit v1.2.3 From 16f51fd9dc454b26d9866b080caa17ffe2f8ce27 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 13 Aug 2012 23:36:38 -0400 Subject: Updated to use sprockets! Ah, much cleaner. --- bin/dashing | 2 +- dashing.gemspec | 3 +- javascripts/batman.jquery.js | 109 + javascripts/batman.js | 11811 +++++++++++++++++++ javascripts/dashing.coffee | 96 + javascripts/es5-shim.js | 1021 ++ javascripts/jquery.js | 4 + lib/dashing.rb | 57 +- .../project/assets/fonts/fontawesome-webfont.eot | Bin 0 -> 38708 bytes .../project/assets/fonts/fontawesome-webfont.svg | 255 + .../project/assets/fonts/fontawesome-webfont.ttf | Bin 0 -> 68476 bytes .../project/assets/fonts/fontawesome-webfont.woff | Bin 0 -> 41752 bytes templates/project/assets/images/.empty_directory | 1 + templates/project/assets/images/favicon.ico | Bin 0 -> 5430 bytes .../project/assets/javascripts/.empty_directory | 1 + .../project/assets/javascripts/application.coffee | 25 + .../assets/javascripts/dashing.gridster.coffee | 32 + .../javascripts/gridster/jquery.collision.js | 224 + .../assets/javascripts/gridster/jquery.coords.js | 108 + .../javascripts/gridster/jquery.draggable.js | 327 + .../assets/javascripts/gridster/jquery.gridster.js | 2890 +++++ .../javascripts/gridster/jquery.leanModal.min.js | 5 + .../project/assets/javascripts/gridster/utils.js | 41 + .../project/assets/javascripts/jquery.knob.js | 646 + .../project/assets/stylesheets/application.scss | 227 + .../project/assets/stylesheets/font-awesome.css | 303 + .../project/assets/stylesheets/jquery.gridster.css | 57 + templates/project/config.ru | 11 + templates/project/dashboards/layout.erb | 43 +- templates/project/public/.empty_directory | 1 + .../project/public/fonts/fontawesome-webfont.eot | Bin 38708 -> 0 bytes .../project/public/fonts/fontawesome-webfont.svg | 255 - .../project/public/fonts/fontawesome-webfont.ttf | Bin 68476 -> 0 bytes .../project/public/fonts/fontawesome-webfont.woff | Bin 41752 -> 0 bytes templates/project/public/images/.empty_directory | 1 - templates/project/public/images/favicon.ico | Bin 5430 -> 0 bytes .../project/public/javascripts/.empty_directory | 1 - .../project/public/javascripts/jquery.knob.js | 28 - .../public/javascripts/jquery.masonry.min.js | 10 - .../project/public/stylesheets/application.scss | 238 - .../project/public/stylesheets/font-awesome.css | 303 - vendor/javascripts/application.coffee | 68 - vendor/javascripts/batman.jquery.js | 109 - vendor/javascripts/batman.js | 11811 ------------------- vendor/javascripts/es5-shim.js | 1021 -- vendor/javascripts/jquery.js | 4 - vendor/javascripts/widget.coffee | 20 - 47 files changed, 18235 insertions(+), 13934 deletions(-) create mode 100644 javascripts/batman.jquery.js create mode 100644 javascripts/batman.js create mode 100644 javascripts/dashing.coffee create mode 100644 javascripts/es5-shim.js create mode 100644 javascripts/jquery.js create mode 100755 templates/project/assets/fonts/fontawesome-webfont.eot create mode 100755 templates/project/assets/fonts/fontawesome-webfont.svg create mode 100755 templates/project/assets/fonts/fontawesome-webfont.ttf create mode 100755 templates/project/assets/fonts/fontawesome-webfont.woff create mode 100644 templates/project/assets/images/.empty_directory create mode 100644 templates/project/assets/images/favicon.ico create mode 100644 templates/project/assets/javascripts/.empty_directory create mode 100644 templates/project/assets/javascripts/application.coffee create mode 100644 templates/project/assets/javascripts/dashing.gridster.coffee create mode 100755 templates/project/assets/javascripts/gridster/jquery.collision.js create mode 100755 templates/project/assets/javascripts/gridster/jquery.coords.js create mode 100755 templates/project/assets/javascripts/gridster/jquery.draggable.js create mode 100755 templates/project/assets/javascripts/gridster/jquery.gridster.js create mode 100644 templates/project/assets/javascripts/gridster/jquery.leanModal.min.js create mode 100755 templates/project/assets/javascripts/gridster/utils.js create mode 100644 templates/project/assets/javascripts/jquery.knob.js create mode 100644 templates/project/assets/stylesheets/application.scss create mode 100644 templates/project/assets/stylesheets/font-awesome.css create mode 100755 templates/project/assets/stylesheets/jquery.gridster.css create mode 100644 templates/project/public/.empty_directory delete mode 100755 templates/project/public/fonts/fontawesome-webfont.eot delete mode 100755 templates/project/public/fonts/fontawesome-webfont.svg delete mode 100755 templates/project/public/fonts/fontawesome-webfont.ttf delete mode 100755 templates/project/public/fonts/fontawesome-webfont.woff delete mode 100644 templates/project/public/images/.empty_directory delete mode 100644 templates/project/public/images/favicon.ico delete mode 100644 templates/project/public/javascripts/.empty_directory delete mode 100644 templates/project/public/javascripts/jquery.knob.js delete mode 100644 templates/project/public/javascripts/jquery.masonry.min.js delete mode 100644 templates/project/public/stylesheets/application.scss delete mode 100644 templates/project/public/stylesheets/font-awesome.css delete mode 100644 vendor/javascripts/application.coffee delete mode 100644 vendor/javascripts/batman.jquery.js delete mode 100644 vendor/javascripts/batman.js delete mode 100644 vendor/javascripts/es5-shim.js delete mode 100644 vendor/javascripts/jquery.js delete mode 100644 vendor/javascripts/widget.coffee diff --git a/bin/dashing b/bin/dashing index 32c89c8..a9e6022 100755 --- a/bin/dashing +++ b/bin/dashing @@ -50,7 +50,7 @@ module Dashing directory :project, @name end - desc "generate GENERATOR NAME", "Creates a new widget with all the fixins'" + desc "generate GENERATOR NAME", "Creates a new wigdget, dashboard, or job." def generate(type, name) send("generate_#{type}".to_sym, name) rescue NoMethodError => e diff --git a/dashing.gemspec b/dashing.gemspec index a1a8cbc..5bacdfa 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new do |s| s.files = ["lib/Dashing.rb"] s.homepage = 'http://Dashing.shopify.com' - s.files = Dir['README.md', 'vendor/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] + s.files = Dir['README.md', 'javascripts/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] s.add_dependency('sass') s.add_dependency('coffee-script') @@ -21,5 +21,6 @@ Gem::Specification.new do |s| s.add_dependency('thin') s.add_dependency('rufus-scheduler') s.add_dependency('thor') + s.add_dependency('sprockets') end \ No newline at end of file diff --git a/javascripts/batman.jquery.js b/javascripts/batman.jquery.js new file mode 100644 index 0000000..6407098 --- /dev/null +++ b/javascripts/batman.jquery.js @@ -0,0 +1,109 @@ +(function() { + + Batman.Request.prototype._parseResponseHeaders = function(xhr) { + var headers; + return headers = xhr.getAllResponseHeaders().split('\n').reduce(function(acc, header) { + var key, matches, value; + if (matches = header.match(/([^:]*):\s*(.*)/)) { + key = matches[1]; + value = matches[2]; + acc[key] = value; + } + return acc; + }, {}); + }; + + Batman.Request.prototype._prepareOptions = function(data) { + var options, _ref, + _this = this; + options = { + url: this.get('url'), + type: this.get('method'), + dataType: this.get('type'), + data: data || this.get('data'), + username: this.get('username'), + password: this.get('password'), + headers: this.get('headers'), + beforeSend: function() { + return _this.fire('loading'); + }, + success: function(response, textStatus, xhr) { + _this.mixin({ + xhr: xhr, + status: xhr.status, + response: response, + responseHeaders: _this._parseResponseHeaders(xhr) + }); + return _this.fire('success', response); + }, + error: function(xhr, status, error) { + _this.mixin({ + xhr: xhr, + status: xhr.status, + response: xhr.responseText, + responseHeaders: _this._parseResponseHeaders(xhr) + }); + xhr.request = _this; + return _this.fire('error', xhr); + }, + complete: function() { + return _this.fire('loaded'); + } + }; + if ((_ref = this.get('method')) === 'PUT' || _ref === 'POST') { + if (!this.hasFileUploads()) { + options.contentType = this.get('contentType'); + if (typeof options.data === 'object') { + options.processData = false; + options.data = Batman.URI.queryFromParams(options.data); + } + } else { + options.contentType = false; + options.processData = false; + options.data = this.constructor.objectToFormData(options.data); + } + } + return options; + }; + + Batman.Request.prototype.send = function(data) { + return jQuery.ajax(this._prepareOptions(data)); + }; + + Batman.mixins.animation = { + show: function(addToParent) { + var jq, show, _ref, _ref1; + jq = $(this); + show = function() { + return jq.show(600); + }; + if (addToParent) { + if ((_ref = addToParent.append) != null) { + _ref.appendChild(this); + } + if ((_ref1 = addToParent.before) != null) { + _ref1.parentNode.insertBefore(this, addToParent.before); + } + jq.hide(); + setTimeout(show, 0); + } else { + show(); + } + return this; + }, + hide: function(removeFromParent) { + var _this = this; + $(this).hide(600, function() { + var _ref; + if (removeFromParent) { + if ((_ref = _this.parentNode) != null) { + _ref.removeChild(_this); + } + } + return Batman.DOM.didRemoveNode(_this); + }); + return this; + } + }; + +}).call(this); \ No newline at end of file diff --git a/javascripts/batman.js b/javascripts/batman.js new file mode 100644 index 0000000..22c7b3a --- /dev/null +++ b/javascripts/batman.js @@ -0,0 +1,11811 @@ +(function() { + var Batman, + __slice = [].slice; + + Batman = function() { + var mixins; + mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.Object, mixins, function(){}); + }; + + Batman.version = '0.10.0'; + + Batman.config = { + pathPrefix: '/', + usePushState: false, + minificationErrors: true + }; + + (Batman.container = (function() { + return this; + })()).Batman = Batman; + + if (typeof define === 'function') { + define('batman', [], function() { + return Batman; + }); + } + + Batman.exportHelpers = function(onto) { + var k, _i, _len, _ref; + _ref = ['mixin', 'extend', 'unmixin', 'redirect', 'typeOf', 'redirect', 'setImmediate', 'clearImmediate']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + onto["$" + k] = Batman[k]; + } + return onto; + }; + + Batman.exportGlobals = function() { + return Batman.exportHelpers(Batman.container); + }; + +}).call(this); + +(function() { + var __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.Inflector = (function() { + + Inflector.prototype.plural = function(regex, replacement) { + return this._plural.unshift([regex, replacement]); + }; + + Inflector.prototype.singular = function(regex, replacement) { + return this._singular.unshift([regex, replacement]); + }; + + Inflector.prototype.human = function(regex, replacement) { + return this._human.unshift([regex, replacement]); + }; + + Inflector.prototype.uncountable = function() { + var strings; + strings = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return this._uncountable = this._uncountable.concat(strings.map(function(x) { + return new RegExp("" + x + "$", 'i'); + })); + }; + + Inflector.prototype.irregular = function(singular, plural) { + if (singular.charAt(0) === plural.charAt(0)) { + this.plural(new RegExp("(" + (singular.charAt(0)) + ")" + (singular.slice(1)) + "$", "i"), "$1" + plural.slice(1)); + this.plural(new RegExp("(" + (singular.charAt(0)) + ")" + (plural.slice(1)) + "$", "i"), "$1" + plural.slice(1)); + return this.singular(new RegExp("(" + (plural.charAt(0)) + ")" + (plural.slice(1)) + "$", "i"), "$1" + singular.slice(1)); + } else { + this.plural(new RegExp("" + singular + "$", 'i'), plural); + this.plural(new RegExp("" + plural + "$", 'i'), plural); + return this.singular(new RegExp("" + plural + "$", 'i'), singular); + } + }; + + function Inflector() { + this._plural = []; + this._singular = []; + this._uncountable = []; + this._human = []; + } + + Inflector.prototype.ordinalize = function(number) { + var absNumber, _ref; + absNumber = Math.abs(parseInt(number)); + if (_ref = absNumber % 100, __indexOf.call([11, 12, 13], _ref) >= 0) { + return number + "th"; + } else { + switch (absNumber % 10) { + case 1: + return number + "st"; + case 2: + return number + "nd"; + case 3: + return number + "rd"; + default: + return number + "th"; + } + } + }; + + Inflector.prototype.pluralize = function(word) { + var regex, replace_string, uncountableRegex, _i, _j, _len, _len1, _ref, _ref1, _ref2; + _ref = this._uncountable; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + uncountableRegex = _ref[_i]; + if (uncountableRegex.test(word)) { + return word; + } + } + _ref1 = this._plural; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + _ref2 = _ref1[_j], regex = _ref2[0], replace_string = _ref2[1]; + if (regex.test(word)) { + return word.replace(regex, replace_string); + } + } + return word; + }; + + Inflector.prototype.singularize = function(word) { + var regex, replace_string, uncountableRegex, _i, _j, _len, _len1, _ref, _ref1, _ref2; + _ref = this._uncountable; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + uncountableRegex = _ref[_i]; + if (uncountableRegex.test(word)) { + return word; + } + } + _ref1 = this._singular; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + _ref2 = _ref1[_j], regex = _ref2[0], replace_string = _ref2[1]; + if (regex.test(word)) { + return word.replace(regex, replace_string); + } + } + return word; + }; + + Inflector.prototype.humanize = function(word) { + var regex, replace_string, _i, _len, _ref, _ref1; + _ref = this._human; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + _ref1 = _ref[_i], regex = _ref1[0], replace_string = _ref1[1]; + if (regex.test(word)) { + return word.replace(regex, replace_string); + } + } + return word; + }; + + return Inflector; + + })(); + +}).call(this); + +(function() { + var Inflector, camelize_rx, capitalize_rx, humanize_rx1, humanize_rx2, humanize_rx3, underscore_rx1, underscore_rx2; + + camelize_rx = /(?:^|_|\-)(.)/g; + + capitalize_rx = /(^|\s)([a-z])/g; + + underscore_rx1 = /([A-Z]+)([A-Z][a-z])/g; + + underscore_rx2 = /([a-z\d])([A-Z])/g; + + humanize_rx1 = /_id$/; + + humanize_rx2 = /_|-/g; + + humanize_rx3 = /^\w/g; + + Batman.helpers = { + ordinalize: function() { + return Batman.helpers.inflector.ordinalize.apply(Batman.helpers.inflector, arguments); + }, + singularize: function() { + return Batman.helpers.inflector.singularize.apply(Batman.helpers.inflector, arguments); + }, + pluralize: function(count, singular, plural, includeCount) { + var result; + if (includeCount == null) { + includeCount = true; + } + if (arguments.length < 2) { + return Batman.helpers.inflector.pluralize(count); + } else { + result = +count === 1 ? singular : plural || Batman.helpers.inflector.pluralize(singular); + if (includeCount) { + result = ("" + (count || 0) + " ") + result; + } + return result; + } + }, + camelize: function(string, firstLetterLower) { + string = string.replace(camelize_rx, function(str, p1) { + return p1.toUpperCase(); + }); + if (firstLetterLower) { + return string.substr(0, 1).toLowerCase() + string.substr(1); + } else { + return string; + } + }, + underscore: function(string) { + return string.replace(underscore_rx1, '$1_$2').replace(underscore_rx2, '$1_$2').replace('-', '_').toLowerCase(); + }, + capitalize: function(string) { + return string.replace(capitalize_rx, function(m, p1, p2) { + return p1 + p2.toUpperCase(); + }); + }, + trim: function(string) { + if (string) { + return string.trim(); + } else { + return ""; + } + }, + interpolate: function(stringOrObject, keys) { + var key, string, value; + if (typeof stringOrObject === 'object') { + string = stringOrObject[keys.count]; + if (!string) { + string = stringOrObject['other']; + } + } else { + string = stringOrObject; + } + for (key in keys) { + value = keys[key]; + string = string.replace(new RegExp("%\\{" + key + "\\}", "g"), value); + } + return string; + }, + humanize: function(string) { + string = Batman.helpers.underscore(string); + string = Batman.helpers.inflector.humanize(string); + return string.replace(humanize_rx1, '').replace(humanize_rx2, ' ').replace(humanize_rx3, function(match) { + return match.toUpperCase(); + }); + } + }; + + Inflector = new Batman.Inflector; + + Batman.helpers.inflector = Inflector; + + Inflector.plural(/$/, 's'); + + Inflector.plural(/s$/i, 's'); + + Inflector.plural(/(ax|test)is$/i, '$1es'); + + Inflector.plural(/(octop|vir)us$/i, '$1i'); + + Inflector.plural(/(octop|vir)i$/i, '$1i'); + + Inflector.plural(/(alias|status)$/i, '$1es'); + + Inflector.plural(/(bu)s$/i, '$1ses'); + + Inflector.plural(/(buffal|tomat)o$/i, '$1oes'); + + Inflector.plural(/([ti])um$/i, '$1a'); + + Inflector.plural(/([ti])a$/i, '$1a'); + + Inflector.plural(/sis$/i, 'ses'); + + Inflector.plural(/(?:([^f])fe|([lr])f)$/i, '$1$2ves'); + + Inflector.plural(/(hive)$/i, '$1s'); + + Inflector.plural(/([^aeiouy]|qu)y$/i, '$1ies'); + + Inflector.plural(/(x|ch|ss|sh)$/i, '$1es'); + + Inflector.plural(/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'); + + Inflector.plural(/([m|l])ouse$/i, '$1ice'); + + Inflector.plural(/([m|l])ice$/i, '$1ice'); + + Inflector.plural(/^(ox)$/i, '$1en'); + + Inflector.plural(/^(oxen)$/i, '$1'); + + Inflector.plural(/(quiz)$/i, '$1zes'); + + Inflector.singular(/s$/i, ''); + + Inflector.singular(/(n)ews$/i, '$1ews'); + + Inflector.singular(/([ti])a$/i, '$1um'); + + Inflector.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '$1$2sis'); + + Inflector.singular(/(^analy)ses$/i, '$1sis'); + + Inflector.singular(/([^f])ves$/i, '$1fe'); + + Inflector.singular(/(hive)s$/i, '$1'); + + Inflector.singular(/(tive)s$/i, '$1'); + + Inflector.singular(/([lr])ves$/i, '$1f'); + + Inflector.singular(/([^aeiouy]|qu)ies$/i, '$1y'); + + Inflector.singular(/(s)eries$/i, '$1eries'); + + Inflector.singular(/(m)ovies$/i, '$1ovie'); + + Inflector.singular(/(x|ch|ss|sh)es$/i, '$1'); + + Inflector.singular(/([m|l])ice$/i, '$1ouse'); + + Inflector.singular(/(bus)es$/i, '$1'); + + Inflector.singular(/(o)es$/i, '$1'); + + Inflector.singular(/(shoe)s$/i, '$1'); + + Inflector.singular(/(cris|ax|test)es$/i, '$1is'); + + Inflector.singular(/(octop|vir)i$/i, '$1us'); + + Inflector.singular(/(alias|status)es$/i, '$1'); + + Inflector.singular(/^(ox)en/i, '$1'); + + Inflector.singular(/(vert|ind)ices$/i, '$1ex'); + + Inflector.singular(/(matr)ices$/i, '$1ix'); + + Inflector.singular(/(quiz)zes$/i, '$1'); + + Inflector.singular(/(database)s$/i, '$1'); + + Inflector.irregular('person', 'people'); + + Inflector.irregular('man', 'men'); + + Inflector.irregular('child', 'children'); + + Inflector.irregular('sex', 'sexes'); + + Inflector.irregular('move', 'moves'); + + Inflector.irregular('cow', 'kine'); + + Inflector.irregular('zombie', 'zombies'); + + Inflector.uncountable('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep', 'jeans'); + +}).call(this); + +(function() { + var _implementImmediates, _objectToString, + __slice = [].slice, + __hasProp = {}.hasOwnProperty, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.typeOf = function(object) { + if (typeof object === 'undefined') { + return "Undefined"; + } + return _objectToString.call(object).slice(8, -1); + }; + + _objectToString = Object.prototype.toString; + + Batman.extend = function() { + var key, object, objects, to, value, _i, _len; + to = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + for (_i = 0, _len = objects.length; _i < _len; _i++) { + object = objects[_i]; + for (key in object) { + value = object[key]; + to[key] = value; + } + } + return to; + }; + + Batman.mixin = function() { + var hasSet, key, mixin, mixins, to, value, _i, _len; + to = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + hasSet = typeof to.set === 'function'; + for (_i = 0, _len = mixins.length; _i < _len; _i++) { + mixin = mixins[_i]; + if (Batman.typeOf(mixin) !== 'Object') { + continue; + } + for (key in mixin) { + if (!__hasProp.call(mixin, key)) continue; + value = mixin[key]; + if (key === 'initialize' || key === 'uninitialize' || key === 'prototype') { + continue; + } + if (hasSet) { + to.set(key, value); + } else if (to.nodeName != null) { + Batman.data(to, key, value); + } else { + to[key] = value; + } + } + if (typeof mixin.initialize === 'function') { + mixin.initialize.call(to); + } + } + return to; + }; + + Batman.unmixin = function() { + var from, key, mixin, mixins, _i, _len; + from = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + for (_i = 0, _len = mixins.length; _i < _len; _i++) { + mixin = mixins[_i]; + for (key in mixin) { + if (key === 'initialize' || key === 'uninitialize') { + continue; + } + delete from[key]; + } + if (typeof mixin.uninitialize === 'function') { + mixin.uninitialize.call(from); + } + } + return from; + }; + + Batman._functionName = Batman.functionName = function(f) { + var _ref; + if (f.__name__) { + return f.__name__; + } + if (f.name) { + return f.name; + } + return (_ref = f.toString().match(/\W*function\s+([\w\$]+)\(/)) != null ? _ref[1] : void 0; + }; + + Batman._isChildOf = Batman.isChildOf = function(parentNode, childNode) { + var node; + node = childNode.parentNode; + while (node) { + if (node === parentNode) { + return true; + } + node = node.parentNode; + } + return false; + }; + + Batman.setImmediate = Batman.clearImmediate = null; + + _implementImmediates = function(container) { + var canUsePostMessage, count, functions, getHandle, handler, prefix, tasks; + canUsePostMessage = function() { + var async, oldMessage; + if (!container.postMessage) { + return false; + } + async = true; + oldMessage = container.onmessage; + container.onmessage = function() { + return async = false; + }; + container.postMessage("", "*"); + container.onmessage = oldMessage; + return async; + }; + tasks = new Batman.SimpleHash; + count = 0; + getHandle = function() { + return "go" + (++count); + }; + if (container.setImmediate) { + Batman.setImmediate = container.setImmediate; + Batman.clearImmediate = container.clearImmediate; + } else if (container.msSetImmediate) { + Batman.setImmediate = msSetImmediate; + Batman.clearImmediate = msClearImmediate; + } else if (canUsePostMessage()) { + prefix = 'com.batman.'; + functions = new Batman.SimpleHash; + handler = function(e) { + var handle, _base; + if (!~e.data.search(prefix)) { + return; + } + handle = e.data.substring(prefix.length); + return typeof (_base = tasks.unset(handle)) === "function" ? _base() : void 0; + }; + if (container.addEventListener) { + container.addEventListener('message', handler, false); + } else { + container.attachEvent('onmessage', handler); + } + Batman.setImmediate = function(f) { + var handle; + tasks.set(handle = getHandle(), f); + container.postMessage(prefix + handle, "*"); + return handle; + }; + Batman.clearImmediate = function(handle) { + return tasks.unset(handle); + }; + } else if (typeof document !== 'undefined' && __indexOf.call(document.createElement("script"), "onreadystatechange") >= 0) { + Batman.setImmediate = function(f) { + var handle, script; + handle = getHandle(); + script = document.createElement("script"); + script.onreadystatechange = function() { + var _base; + if (typeof (_base = tasks.get(handle)) === "function") { + _base(); + } + script.onreadystatechange = null; + script.parentNode.removeChild(script); + return script = null; + }; + document.documentElement.appendChild(script); + return handle; + }; + Batman.clearImmediate = function(handle) { + return tasks.unset(handle); + }; + } else if (typeof process !== "undefined" && process !== null ? process.nextTick : void 0) { + functions = {}; + Batman.setImmediate = function(f) { + var handle; + handle = getHandle(); + functions[handle] = f; + process.nextTick(function() { + if (typeof functions[handle] === "function") { + functions[handle](); + } + return delete functions[handle]; + }); + return handle; + }; + Batman.clearImmediate = function(handle) { + return delete functions[handle]; + }; + } else { + Batman.setImmediate = function(f) { + return setTimeout(f, 0); + }; + Batman.clearImmediate = function(handle) { + return clearTimeout(handle); + }; + } + Batman.setImmediate = Batman.setImmediate; + return Batman.clearImmediate = Batman.clearImmediate; + }; + + Batman.setImmediate = function() { + _implementImmediates(Batman.container); + return Batman.setImmediate.apply(this, arguments); + }; + + Batman.clearImmediate = function() { + _implementImmediates(Batman.container); + return Batman.clearImmediate.apply(this, arguments); + }; + + Batman.forEach = function(container, iterator, ctx) { + var e, i, k, v, _i, _len, _results, _results1; + if (container.forEach) { + return container.forEach(iterator, ctx); + } else if (container.indexOf) { + _results = []; + for (i = _i = 0, _len = container.length; _i < _len; i = ++_i) { + e = container[i]; + _results.push(iterator.call(ctx, e, i, container)); + } + return _results; + } else { + _results1 = []; + for (k in container) { + v = container[k]; + _results1.push(iterator.call(ctx, k, v, container)); + } + return _results1; + } + }; + + Batman.objectHasKey = function(object, key) { + if (typeof object.hasKey === 'function') { + return object.hasKey(key); + } else { + return key in object; + } + }; + + Batman.contains = function(container, item) { + if (container.indexOf) { + return __indexOf.call(container, item) >= 0; + } else if (typeof container.has === 'function') { + return container.has(item); + } else { + return Batman.objectHasKey(container, item); + } + }; + + Batman.get = function(base, key) { + if (typeof base.get === 'function') { + return base.get(key); + } else { + return Batman.Property.forBaseAndKey(base, key).getValue(); + } + }; + + Batman.getPath = function(base, segments) { + var segment, _i, _len; + for (_i = 0, _len = segments.length; _i < _len; _i++) { + segment = segments[_i]; + if (base != null) { + base = Batman.get(base, segment); + if (base == null) { + return base; + } + } else { + return void 0; + } + } + return base; + }; + + Batman.escapeHTML = (function() { + var replacements; + replacements = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" + }; + return function(s) { + return ("" + s).replace(/[&<>'"]/g, function(c) { + return replacements[c]; + }); + }; + })(); + + Batman.translate = function(x, values) { + if (values == null) { + values = {}; + } + return Batman.helpers.interpolate(Batman.get(Batman.translate.messages, x), values); + }; + + Batman.translate.messages = {}; + + Batman.t = function() { + return Batman.translate.apply(Batman, arguments); + }; + + Batman.redirect = function(url) { + var _ref; + return (_ref = Batman.navigator) != null ? _ref.redirect(url) : void 0; + }; + + Batman.initializeObject = function(object) { + if (object._batman != null) { + return object._batman.check(object); + } else { + return object._batman = new Batman._Batman(object); + } + }; + +}).call(this); + +(function() { + var developer; + + Batman.developer = { + suppressed: false, + DevelopmentError: (function() { + var DevelopmentError; + DevelopmentError = function(message) { + this.message = message; + return this.name = "DevelopmentError"; + }; + DevelopmentError.prototype = Error.prototype; + return DevelopmentError; + })(), + _ie_console: function(f, args) { + var arg, _i, _len, _results; + if (args.length !== 1) { + if (typeof console !== "undefined" && console !== null) { + console[f]("..." + f + " of " + args.length + " items..."); + } + } + _results = []; + for (_i = 0, _len = args.length; _i < _len; _i++) { + arg = args[_i]; + _results.push(typeof console !== "undefined" && console !== null ? console[f](arg) : void 0); + } + return _results; + }, + suppress: function(f) { + developer.suppressed = true; + if (f) { + f(); + return developer.suppressed = false; + } + }, + unsuppress: function() { + return developer.suppressed = false; + }, + log: function() { + if (developer.suppressed || !((typeof console !== "undefined" && console !== null ? console.log : void 0) != null)) { + return; + } + if (console.log.apply) { + return console.log.apply(console, arguments); + } else { + return developer._ie_console("log", arguments); + } + }, + warn: function() { + if (developer.suppressed || !((typeof console !== "undefined" && console !== null ? console.warn : void 0) != null)) { + return; + } + if (console.warn.apply) { + return console.warn.apply(console, arguments); + } else { + return developer._ie_console("warn", arguments); + } + }, + error: function(message) { + throw new developer.DevelopmentError(message); + }, + assert: function(result, message) { + if (!result) { + return developer.error(message); + } + }, + "do": function(f) { + if (!developer.suppressed) { + return f(); + } + }, + addFilters: function() { + return Batman.extend(Batman.Filters, { + log: function(value, key) { + if (typeof console !== "undefined" && console !== null) { + if (typeof console.log === "function") { + console.log(arguments); + } + } + return value; + }, + logStack: function(value) { + if (typeof console !== "undefined" && console !== null) { + if (typeof console.log === "function") { + console.log(developer.currentFilterStack); + } + } + return value; + } + }); + } + }; + + developer = Batman.developer; + + Batman.developer.assert((function() {}).bind, "Error! Batman needs Function.bind to work! Please shim it using something like es5-shim or augmentjs!"); + +}).call(this); + +(function() { + var _Batman; + + Batman._Batman = _Batman = (function() { + + function _Batman(object) { + this.object = object; + } + + _Batman.prototype.check = function(object) { + if (object !== this.object) { + object._batman = new Batman._Batman(object); + return false; + } + return true; + }; + + _Batman.prototype.get = function(key) { + var reduction, results; + results = this.getAll(key); + switch (results.length) { + case 0: + return void 0; + case 1: + return results[0]; + default: + reduction = results[0].concat != null ? function(a, b) { + return a.concat(b); + } : results[0].merge != null ? function(a, b) { + return a.merge(b); + } : results.every(function(x) { + return typeof x === 'object'; + }) ? (results.unshift({}), function(a, b) { + return Batman.extend(a, b); + }) : void 0; + if (reduction) { + return results.reduceRight(reduction); + } else { + return results; + } + } + }; + + _Batman.prototype.getFirst = function(key) { + var results; + results = this.getAll(key); + return results[0]; + }; + + _Batman.prototype.getAll = function(keyOrGetter) { + var getter, results, val; + if (typeof keyOrGetter === 'function') { + getter = keyOrGetter; + } else { + getter = function(ancestor) { + var _ref; + return (_ref = ancestor._batman) != null ? _ref[keyOrGetter] : void 0; + }; + } + results = this.ancestors(getter); + if (val = getter(this.object)) { + results.unshift(val); + } + return results; + }; + + _Batman.prototype.ancestors = function(getter) { + var isClass, parent, proto, results, val, _ref, _ref1; + if (getter == null) { + getter = function(x) { + return x; + }; + } + results = []; + isClass = !!this.object.prototype; + parent = isClass ? (_ref = this.object.__super__) != null ? _ref.constructor : void 0 : (proto = Object.getPrototypeOf(this.object)) === this.object ? this.object.constructor.__super__ : proto; + if (parent != null) { + if ((_ref1 = parent._batman) != null) { + _ref1.check(parent); + } + val = getter(parent); + if (val != null) { + results.push(val); + } + if (parent._batman != null) { + results = results.concat(parent._batman.ancestors(getter)); + } + } + return results; + }; + + _Batman.prototype.set = function(key, value) { + return this[key] = value; + }; + + return _Batman; + + })(); + +}).call(this); + +(function() { + + Batman.Event = (function() { + + Event.forBaseAndKey = function(base, key) { + if (base.isEventEmitter) { + return base.event(key); + } else { + return new Batman.Event(base, key); + } + }; + + function Event(base, key) { + this.base = base; + this.key = key; + this.handlers = []; + this._preventCount = 0; + } + + Event.prototype.isEvent = true; + + Event.prototype.isEqual = function(other) { + return this.constructor === other.constructor && this.base === other.base && this.key === other.key; + }; + + Event.prototype.hashKey = function() { + var key; + this.hashKey = function() { + return key; + }; + return key = ""; + }; + + Event.prototype.addHandler = function(handler) { + if (this.handlers.indexOf(handler) === -1) { + this.handlers.push(handler); + } + if (this.oneShot) { + this.autofireHandler(handler); + } + return this; + }; + + Event.prototype.removeHandler = function(handler) { + var index; + if ((index = this.handlers.indexOf(handler)) !== -1) { + this.handlers.splice(index, 1); + } + return this; + }; + + Event.prototype.eachHandler = function(iterator) { + var key, _ref, _ref1; + this.handlers.slice().forEach(iterator); + if ((_ref = this.base) != null ? _ref.isEventEmitter : void 0) { + key = this.key; + return (_ref1 = this.base._batman) != null ? _ref1.ancestors(function(ancestor) { + var handlers, _ref2, _ref3; + if (ancestor.isEventEmitter && ((_ref2 = ancestor._batman) != null ? (_ref3 = _ref2.events) != null ? _ref3.hasOwnProperty(key) : void 0 : void 0)) { + handlers = ancestor.event(key).handlers; + return handlers.slice().forEach(iterator); + } + }) : void 0; + } + }; + + Event.prototype.clearHandlers = function() { + return this.handlers = []; + }; + + Event.prototype.handlerContext = function() { + return this.base; + }; + + Event.prototype.prevent = function() { + return ++this._preventCount; + }; + + Event.prototype.allow = function() { + if (this._preventCount) { + --this._preventCount; + } + return this._preventCount; + }; + + Event.prototype.isPrevented = function() { + return this._preventCount > 0; + }; + + Event.prototype.autofireHandler = function(handler) { + if (this._oneShotFired && (this._oneShotArgs != null)) { + return handler.apply(this.handlerContext(), this._oneShotArgs); + } + }; + + Event.prototype.resetOneShot = function() { + this._oneShotFired = false; + return this._oneShotArgs = null; + }; + + Event.prototype.fire = function() { + var args, context; + if (this.isPrevented() || this._oneShotFired) { + return false; + } + context = this.handlerContext(); + args = arguments; + if (this.oneShot) { + this._oneShotFired = true; + this._oneShotArgs = arguments; + } + return this.eachHandler(function(handler) { + return handler.apply(context, args); + }); + }; + + Event.prototype.allowAndFire = function() { + this.allow(); + return this.fire.apply(this, arguments); + }; + + return Event; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PropertyEvent = (function(_super) { + + __extends(PropertyEvent, _super); + + function PropertyEvent() { + return PropertyEvent.__super__.constructor.apply(this, arguments); + } + + PropertyEvent.prototype.eachHandler = function(iterator) { + return this.base.eachObserver(iterator); + }; + + PropertyEvent.prototype.handlerContext = function() { + return this.base.base; + }; + + return PropertyEvent; + + })(Batman.Event); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.EventEmitter = { + isEventEmitter: true, + hasEvent: function(key) { + var _ref, _ref1; + return (_ref = this._batman) != null ? typeof _ref.get === "function" ? (_ref1 = _ref.get('events')) != null ? _ref1.hasOwnProperty(key) : void 0 : void 0 : void 0; + }, + event: function(key) { + var eventClass, events, existingEvent, newEvent, _base; + Batman.initializeObject(this); + eventClass = this.eventClass || Batman.Event; + events = (_base = this._batman).events || (_base.events = {}); + if (events.hasOwnProperty(key)) { + return existingEvent = events[key]; + } else { + this._batman.ancestors(function(ancestor) { + var _ref, _ref1; + return existingEvent || (existingEvent = (_ref = ancestor._batman) != null ? (_ref1 = _ref.events) != null ? _ref1[key] : void 0 : void 0); + }); + newEvent = events[key] = new eventClass(this, key); + newEvent.oneShot = existingEvent != null ? existingEvent.oneShot : void 0; + return newEvent; + } + }, + on: function(key, handler) { + return this.event(key).addHandler(handler); + }, + once: function(key, originalHandler) { + var event, handler; + event = this.event(key); + handler = function() { + originalHandler.apply(this, arguments); + return event.removeHandler(handler); + }; + return event.addHandler(handler); + }, + registerAsMutableSource: function() { + return Batman.Property.registerSource(this); + }, + mutation: function(wrappedFunction) { + return function() { + var result; + result = wrappedFunction.apply(this, arguments); + this.event('change').fire(this, this); + return result; + }; + }, + prevent: function(key) { + this.event(key).prevent(); + return this; + }, + allow: function(key) { + this.event(key).allow(); + return this; + }, + isPrevented: function(key) { + return this.event(key).isPrevented(); + }, + fire: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + return (_ref = this.event(key)).fire.apply(_ref, args); + }, + allowAndFire: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + return (_ref = this.event(key)).allowAndFire.apply(_ref, args); + } + }; + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.Enumerable = { + isEnumerable: true, + map: function(f, ctx) { + var r; + if (ctx == null) { + ctx = Batman.container; + } + r = []; + this.forEach(function() { + return r.push(f.apply(ctx, arguments)); + }); + return r; + }, + mapToProperty: function(key) { + var r; + r = []; + this.forEach(function(item) { + return r.push(item.get(key)); + }); + return r; + }, + every: function(f, ctx) { + var r; + if (ctx == null) { + ctx = Batman.container; + } + r = true; + this.forEach(function() { + return r = r && f.apply(ctx, arguments); + }); + return r; + }, + some: function(f, ctx) { + var r; + if (ctx == null) { + ctx = Batman.container; + } + r = false; + this.forEach(function() { + return r = r || f.apply(ctx, arguments); + }); + return r; + }, + reduce: function(f, r) { + var count, self; + count = 0; + self = this; + this.forEach(function() { + if (r != null) { + return r = f.apply(null, [r].concat(__slice.call(arguments), [count], [self])); + } else { + return r = arguments[0]; + } + }); + return r; + }, + filter: function(f) { + var r, wrap; + r = new this.constructor; + if (r.add) { + wrap = function(r, e) { + if (f(e)) { + r.add(e); + } + return r; + }; + } else if (r.set) { + wrap = function(r, k, v) { + if (f(k, v)) { + r.set(k, v); + } + return r; + }; + } else { + if (!r.push) { + r = []; + } + wrap = function(r, e) { + if (f(e)) { + r.push(e); + } + return r; + }; + } + return this.reduce(wrap, r); + }, + inGroupsOf: function(n) { + var current, i, r; + r = []; + current = false; + i = 0; + this.forEach(function(x) { + if (i++ % n === 0) { + current = []; + r.push(current); + } + return current.push(x); + }); + return r; + } + }; + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.SimpleHash = (function() { + + function SimpleHash(obj) { + this._storage = {}; + this.length = 0; + if (obj != null) { + this.update(obj); + } + } + + Batman.extend(SimpleHash.prototype, Batman.Enumerable); + + SimpleHash.prototype.propertyClass = Batman.Property; + + SimpleHash.prototype.hasKey = function(key) { + var pair, pairs, _i, _len; + if (this.objectKey(key)) { + if (!this._objectStorage) { + return false; + } + if (pairs = this._objectStorage[this.hashKeyFor(key)]) { + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + if (this.equality(pair[0], key)) { + return true; + } + } + } + return false; + } else { + key = this.prefixedKey(key); + return this._storage.hasOwnProperty(key); + } + }; + + SimpleHash.prototype.get = function(key) { + var pair, pairs, _i, _len; + if (this.objectKey(key)) { + if (!this._objectStorage) { + return void 0; + } + if (pairs = this._objectStorage[this.hashKeyFor(key)]) { + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + if (this.equality(pair[0], key)) { + return pair[1]; + } + } + } + } else { + return this._storage[this.prefixedKey(key)]; + } + }; + + SimpleHash.prototype.set = function(key, val) { + var pair, pairs, _base, _i, _len, _name; + if (this.objectKey(key)) { + this._objectStorage || (this._objectStorage = {}); + pairs = (_base = this._objectStorage)[_name = this.hashKeyFor(key)] || (_base[_name] = []); + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + if (this.equality(pair[0], key)) { + return pair[1] = val; + } + } + this.length++; + pairs.push([key, val]); + return val; + } else { + key = this.prefixedKey(key); + if (this._storage[key] == null) { + this.length++; + } + return this._storage[key] = val; + } + }; + + SimpleHash.prototype.unset = function(key) { + var hashKey, index, obj, pair, pairs, val, value, _i, _len, _ref; + if (this.objectKey(key)) { + if (!this._objectStorage) { + return void 0; + } + hashKey = this.hashKeyFor(key); + if (pairs = this._objectStorage[hashKey]) { + for (index = _i = 0, _len = pairs.length; _i < _len; index = ++_i) { + _ref = pairs[index], obj = _ref[0], value = _ref[1]; + if (this.equality(obj, key)) { + pair = pairs.splice(index, 1); + if (!pairs.length) { + delete this._objectStorage[hashKey]; + } + this.length--; + return pair[0][1]; + } + } + } + } else { + key = this.prefixedKey(key); + val = this._storage[key]; + if (this._storage[key] != null) { + this.length--; + delete this._storage[key]; + } + return val; + } + }; + + SimpleHash.prototype.getOrSet = function(key, valueFunction) { + var currentValue; + currentValue = this.get(key); + if (!currentValue) { + currentValue = valueFunction(); + this.set(key, currentValue); + } + return currentValue; + }; + + SimpleHash.prototype.prefixedKey = function(key) { + return "_" + key; + }; + + SimpleHash.prototype.unprefixedKey = function(key) { + return key.slice(1); + }; + + SimpleHash.prototype.hashKeyFor = function(obj) { + return (obj != null ? typeof obj.hashKey === "function" ? obj.hashKey() : void 0 : void 0) || obj; + }; + + SimpleHash.prototype.equality = function(lhs, rhs) { + if (lhs === rhs) { + return true; + } + if (lhs !== lhs && rhs !== rhs) { + return true; + } + if ((lhs != null ? typeof lhs.isEqual === "function" ? lhs.isEqual(rhs) : void 0 : void 0) && (rhs != null ? typeof rhs.isEqual === "function" ? rhs.isEqual(lhs) : void 0 : void 0)) { + return true; + } + return false; + }; + + SimpleHash.prototype.objectKey = function(key) { + return typeof key !== 'string'; + }; + + SimpleHash.prototype.forEach = function(iterator, ctx) { + var key, obj, results, value, values, _i, _len, _ref, _ref1, _ref2, _ref3; + results = []; + if (this._objectStorage) { + _ref = this._objectStorage; + for (key in _ref) { + values = _ref[key]; + _ref1 = values.slice(); + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + _ref2 = _ref1[_i], obj = _ref2[0], value = _ref2[1]; + results.push(iterator.call(ctx, obj, value, this)); + } + } + } + _ref3 = this._storage; + for (key in _ref3) { + value = _ref3[key]; + results.push(iterator.call(ctx, this.unprefixedKey(key), value, this)); + } + return results; + }; + + SimpleHash.prototype.keys = function() { + var result; + result = []; + Batman.SimpleHash.prototype.forEach.call(this, function(key) { + return result.push(key); + }); + return result; + }; + + SimpleHash.prototype.toArray = SimpleHash.prototype.keys; + + SimpleHash.prototype.clear = function() { + this._storage = {}; + delete this._objectStorage; + return this.length = 0; + }; + + SimpleHash.prototype.isEmpty = function() { + return this.length === 0; + }; + + SimpleHash.prototype.merge = function() { + var hash, merged, others, _i, _len; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + merged = new this.constructor; + others.unshift(this); + for (_i = 0, _len = others.length; _i < _len; _i++) { + hash = others[_i]; + hash.forEach(function(obj, value) { + return merged.set(obj, value); + }); + } + return merged; + }; + + SimpleHash.prototype.update = function(object) { + var k, v, _results; + _results = []; + for (k in object) { + v = object[k]; + _results.push(this.set(k, v)); + } + return _results; + }; + + SimpleHash.prototype.replace = function(object) { + var _this = this; + this.forEach(function(key, value) { + if (!(key in object)) { + return _this.unset(key); + } + }); + return this.update(object); + }; + + SimpleHash.prototype.toObject = function() { + var key, obj, pair, value, _ref, _ref1; + obj = {}; + _ref = this._storage; + for (key in _ref) { + value = _ref[key]; + obj[this.unprefixedKey(key)] = value; + } + if (this._objectStorage) { + _ref1 = this._objectStorage; + for (key in _ref1) { + pair = _ref1[key]; + obj[key] = pair[0][1]; + } + } + return obj; + }; + + SimpleHash.prototype.toJSON = SimpleHash.prototype.toObject; + + return SimpleHash; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.AssociationCurator = (function(_super) { + + __extends(AssociationCurator, _super); + + AssociationCurator.availableAssociations = ['belongsTo', 'hasOne', 'hasMany']; + + function AssociationCurator(model) { + this.model = model; + AssociationCurator.__super__.constructor.call(this); + this._byTypeStorage = new Batman.SimpleHash; + } + + AssociationCurator.prototype.add = function(association) { + var associationTypeSet; + this.set(association.label, association); + if (!(associationTypeSet = this._byTypeStorage.get(association.associationType))) { + associationTypeSet = new Batman.SimpleSet; + this._byTypeStorage.set(association.associationType, associationTypeSet); + } + return associationTypeSet.add(association); + }; + + AssociationCurator.prototype.getByType = function(type) { + return this._byTypeStorage.get(type); + }; + + AssociationCurator.prototype.getByLabel = function(label) { + return this.get(label); + }; + + AssociationCurator.prototype.reset = function() { + this.forEach(function(label, association) { + return association.reset(); + }); + return true; + }; + + AssociationCurator.prototype.merge = function() { + var others, result; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + result = AssociationCurator.__super__.merge.apply(this, arguments); + result._byTypeStorage = this._byTypeStorage.merge(others.map(function(other) { + return other._byTypeStorage; + })); + return result; + }; + + AssociationCurator.prototype._markDirtyAttribute = function(key, oldValue) { + var _ref; + if ((_ref = this.lifecycle.get('state')) !== 'loading' && _ref !== 'creating' && _ref !== 'saving' && _ref !== 'saved') { + if (this.lifecycle.startTransition('set')) { + return this.dirtyKeys.set(key, oldValue); + } else { + throw new Batman.StateMachine.InvalidTransitionError("Can't set while in state " + (this.lifecycle.get('state'))); + } + } + }; + + return AssociationCurator; + + })(Batman.SimpleHash); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.SimpleSet = (function() { + + function SimpleSet() { + this._storage = []; + this.length = 0; + if (arguments.length > 0) { + this.add.apply(this, arguments); + } + } + + Batman.extend(SimpleSet.prototype, Batman.Enumerable); + + SimpleSet.prototype.has = function(item) { + return !!(~this._indexOfItem(item)); + }; + + SimpleSet.prototype.add = function() { + var addedItems, item, items, _i, _len; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + addedItems = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!(!~this._indexOfItem(item))) { + continue; + } + this._storage.push(item); + addedItems.push(item); + } + this.length = this._storage.length; + if (this.fire && addedItems.length !== 0) { + this.fire('change', this, this); + this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedItems))); + } + return addedItems; + }; + + SimpleSet.prototype.remove = function() { + var index, item, items, removedItems, _i, _len; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + removedItems = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!(~(index = this._indexOfItem(item)))) { + continue; + } + this._storage.splice(index, 1); + removedItems.push(item); + } + this.length = this._storage.length; + if (this.fire && removedItems.length !== 0) { + this.fire('change', this, this); + this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(removedItems))); + } + return removedItems; + }; + + SimpleSet.prototype.find = function(f) { + var item, _i, _len, _ref; + _ref = this._storage; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + item = _ref[_i]; + if (f(item)) { + return item; + } + } + }; + + SimpleSet.prototype.forEach = function(iterator, ctx) { + var container; + container = this; + return this._storage.slice().forEach(function(key) { + return iterator.call(ctx, key, null, container); + }); + }; + + SimpleSet.prototype.isEmpty = function() { + return this.length === 0; + }; + + SimpleSet.prototype.clear = function() { + var items; + items = this._storage; + this._storage = []; + this.length = 0; + if (this.fire && items.length !== 0) { + this.fire('change', this, this); + this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(items))); + } + return items; + }; + + SimpleSet.prototype.replace = function(other) { + try { + if (typeof this.prevent === "function") { + this.prevent('change'); + } + this.clear(); + return this.add.apply(this, other.toArray()); + } finally { + if (typeof this.allowAndFire === "function") { + this.allowAndFire('change', this, this); + } + } + }; + + SimpleSet.prototype.toArray = function() { + return this._storage.slice(); + }; + + SimpleSet.prototype.merge = function() { + var merged, others, set, _i, _len; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + merged = new this.constructor; + others.unshift(this); + for (_i = 0, _len = others.length; _i < _len; _i++) { + set = others[_i]; + set.forEach(function(v) { + return merged.add(v); + }); + } + return merged; + }; + + SimpleSet.prototype.indexedBy = function(key) { + this._indexes || (this._indexes = new Batman.SimpleHash); + return this._indexes.get(key) || this._indexes.set(key, new Batman.SetIndex(this, key)); + }; + + SimpleSet.prototype.indexedByUnique = function(key) { + this._uniqueIndexes || (this._uniqueIndexes = new Batman.SimpleHash); + return this._uniqueIndexes.get(key) || this._uniqueIndexes.set(key, new Batman.UniqueSetIndex(this, key)); + }; + + SimpleSet.prototype.sortedBy = function(key, order) { + var sortsForKey; + if (order == null) { + order = "asc"; + } + order = order.toLowerCase() === "desc" ? "desc" : "asc"; + this._sorts || (this._sorts = new Batman.SimpleHash); + sortsForKey = this._sorts.get(key) || this._sorts.set(key, new Batman.Object); + return sortsForKey.get(order) || sortsForKey.set(order, new Batman.SetSort(this, key, order)); + }; + + SimpleSet.prototype.equality = Batman.SimpleHash.prototype.equality; + + SimpleSet.prototype._indexOfItem = function(givenItem) { + var index, item, _i, _len, _ref; + _ref = this._storage; + for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { + item = _ref[index]; + if (this.equality(givenItem, item)) { + return index; + } + } + return -1; + }; + + return SimpleSet; + + })(); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.Property = (function() { + + Batman.mixin(Property.prototype, Batman.EventEmitter); + + Property._sourceTrackerStack = []; + + Property.sourceTracker = function() { + var stack; + return (stack = this._sourceTrackerStack)[stack.length - 1]; + }; + + Property.defaultAccessor = { + get: function(key) { + return this[key]; + }, + set: function(key, val) { + return this[key] = val; + }, + unset: function(key) { + var x; + x = this[key]; + delete this[key]; + return x; + }, + cache: false + }; + + Property.defaultAccessorForBase = function(base) { + var _ref; + return ((_ref = base._batman) != null ? _ref.getFirst('defaultAccessor') : void 0) || Batman.Property.defaultAccessor; + }; + + Property.accessorForBaseAndKey = function(base, key) { + var accessor, _bm, _ref, + _this = this; + if ((_bm = base._batman) != null) { + accessor = (_ref = _bm.keyAccessors) != null ? _ref.get(key) : void 0; + if (!accessor) { + _bm.ancestors(function(ancestor) { + var _ref1, _ref2; + return accessor || (accessor = (_ref1 = ancestor._batman) != null ? (_ref2 = _ref1.keyAccessors) != null ? _ref2.get(key) : void 0 : void 0); + }); + } + } + return accessor || this.defaultAccessorForBase(base); + }; + + Property.forBaseAndKey = function(base, key) { + if (base.isObservable) { + return base.property(key); + } else { + return new Batman.Keypath(base, key); + } + }; + + Property.withoutTracking = function(block) { + return this.wrapTrackingPrevention(block)(); + }; + + Property.wrapTrackingPrevention = function(block) { + return function() { + Batman.Property.pushDummySourceTracker(); + try { + return block.apply(this, arguments); + } finally { + Batman.Property.popSourceTracker(); + } + }; + }; + + Property.registerSource = function(obj) { + var _ref; + if (!obj.isEventEmitter) { + return; + } + return (_ref = this.sourceTracker()) != null ? _ref.add(obj) : void 0; + }; + + Property.pushSourceTracker = function() { + return Batman.Property._sourceTrackerStack.push(new Batman.SimpleSet); + }; + + Property.pushDummySourceTracker = function() { + return Batman.Property._sourceTrackerStack.push(null); + }; + + Property.popSourceTracker = function() { + return Batman.Property._sourceTrackerStack.pop(); + }; + + function Property(base, key) { + this.base = base; + this.key = key; + } + + Property.prototype._isolationCount = 0; + + Property.prototype.cached = false; + + Property.prototype.value = null; + + Property.prototype.sources = null; + + Property.prototype.isProperty = true; + + Property.prototype.isDead = false; + + Property.prototype.eventClass = Batman.PropertyEvent; + + Property.prototype.isEqual = function(other) { + return this.constructor === other.constructor && this.base === other.base && this.key === other.key; + }; + + Property.prototype.hashKey = function() { + var key; + this.hashKey = function() { + return key; + }; + return key = ""; + }; + + Property.prototype.event = function(key) { + var eventClass, _base; + eventClass = this.eventClass || Batman.Event; + this.events || (this.events = {}); + (_base = this.events)[key] || (_base[key] = new eventClass(this, key)); + return this.events[key]; + }; + + Property.prototype.changeEvent = function() { + var event; + event = this.event('change'); + this.changeEvent = function() { + return event; + }; + return event; + }; + + Property.prototype.accessor = function() { + var accessor; + accessor = this.constructor.accessorForBaseAndKey(this.base, this.key); + this.accessor = function() { + return accessor; + }; + return accessor; + }; + + Property.prototype.eachObserver = function(iterator) { + var key; + key = this.key; + this.changeEvent().handlers.slice().forEach(iterator); + if (this.base.isObservable) { + return this.base._batman.ancestors(function(ancestor) { + var handlers, property; + if (ancestor.isObservable && ancestor.hasProperty(key)) { + property = ancestor.property(key); + handlers = property.changeEvent().handlers; + return handlers.slice().forEach(iterator); + } + }); + } + }; + + Property.prototype.observers = function() { + var results; + results = []; + this.eachObserver(function(observer) { + return results.push(observer); + }); + return results; + }; + + Property.prototype.hasObservers = function() { + return this.observers().length > 0; + }; + + Property.prototype.updateSourcesFromTracker = function() { + var handler, newSources; + newSources = this.constructor.popSourceTracker(); + handler = this.sourceChangeHandler(); + this._eachSourceChangeEvent(function(e) { + return e.removeHandler(handler); + }); + this.sources = newSources; + return this._eachSourceChangeEvent(function(e) { + return e.addHandler(handler); + }); + }; + + Property.prototype._eachSourceChangeEvent = function(iterator) { + if (this.sources == null) { + return; + } + return this.sources.forEach(function(source) { + return iterator(source.event('change')); + }); + }; + + Property.prototype.getValue = function() { + this.registerAsMutableSource(); + if (!this.isCached()) { + this.constructor.pushSourceTracker(); + try { + this.value = this.valueFromAccessor(); + this.cached = true; + } finally { + this.updateSourcesFromTracker(); + } + } + return this.value; + }; + + Property.prototype.isCachable = function() { + var cacheable; + if (this.isFinal()) { + return true; + } + cacheable = this.accessor().cache; + if (cacheable != null) { + return !!cacheable; + } else { + return true; + } + }; + + Property.prototype.isCached = function() { + return this.isCachable() && this.cached; + }; + + Property.prototype.isFinal = function() { + return !!this.accessor()['final']; + }; + + Property.prototype.refresh = function() { + var previousValue, value; + this.cached = false; + previousValue = this.value; + value = this.getValue(); + if (value !== previousValue && !this.isIsolated()) { + this.fire(value, previousValue); + } + if (this.value !== void 0 && this.isFinal()) { + return this.lockValue(); + } + }; + + Property.prototype.sourceChangeHandler = function() { + var handler, + _this = this; + handler = this._handleSourceChange.bind(this); + Batman.developer["do"](function() { + return handler.property = _this; + }); + this.sourceChangeHandler = function() { + return handler; + }; + return handler; + }; + + Property.prototype._handleSourceChange = function() { + if (this.isIsolated()) { + return this._needsRefresh = true; + } else if (!this.isFinal() && !this.hasObservers()) { + return this.cached = false; + } else { + return this.refresh(); + } + }; + + Property.prototype.valueFromAccessor = function() { + var _ref; + return (_ref = this.accessor().get) != null ? _ref.call(this.base, this.key) : void 0; + }; + + Property.prototype.setValue = function(val) { + var set; + if (!(set = this.accessor().set)) { + return; + } + return this._changeValue(function() { + return set.call(this.base, this.key, val); + }); + }; + + Property.prototype.unsetValue = function() { + var unset; + if (!(unset = this.accessor().unset)) { + return; + } + return this._changeValue(function() { + return unset.call(this.base, this.key); + }); + }; + + Property.prototype._changeValue = function(block) { + var result; + this.cached = false; + this.constructor.pushDummySourceTracker(); + try { + result = block.apply(this); + this.refresh(); + } finally { + this.constructor.popSourceTracker(); + } + if (!(this.isCached() || this.hasObservers())) { + this.die(); + } + return result; + }; + + Property.prototype.forget = function(handler) { + if (handler != null) { + return this.changeEvent().removeHandler(handler); + } else { + return this.changeEvent().clearHandlers(); + } + }; + + Property.prototype.observeAndFire = function(handler) { + this.observe(handler); + return handler.call(this.base, this.value, this.value, this.key); + }; + + Property.prototype.observe = function(handler) { + this.changeEvent().addHandler(handler); + if (this.sources == null) { + this.getValue(); + } + return this; + }; + + Property.prototype.observeOnce = function(originalHandler) { + var event, handler; + event = this.changeEvent(); + handler = function() { + originalHandler.apply(this, arguments); + return event.removeHandler(handler); + }; + event.addHandler(handler); + if (this.sources == null) { + this.getValue(); + } + return this; + }; + + Property.prototype._removeHandlers = function() { + var handler; + handler = this.sourceChangeHandler(); + this._eachSourceChangeEvent(function(e) { + return e.removeHandler(handler); + }); + delete this.sources; + return this.changeEvent().clearHandlers(); + }; + + Property.prototype.lockValue = function() { + this._removeHandlers(); + this.getValue = function() { + return this.value; + }; + return this.setValue = this.unsetValue = this.refresh = this.observe = function() {}; + }; + + Property.prototype.die = function() { + var _ref, _ref1; + this._removeHandlers(); + if ((_ref = this.base._batman) != null) { + if ((_ref1 = _ref.properties) != null) { + _ref1.unset(this.key); + } + } + return this.isDead = true; + }; + + Property.prototype.fire = function() { + var _ref; + return (_ref = this.changeEvent()).fire.apply(_ref, __slice.call(arguments).concat([this.key])); + }; + + Property.prototype.isolate = function() { + if (this._isolationCount === 0) { + this._preIsolationValue = this.getValue(); + } + return this._isolationCount++; + }; + + Property.prototype.expose = function() { + if (this._isolationCount === 1) { + this._isolationCount--; + if (this._needsRefresh) { + this.value = this._preIsolationValue; + this.refresh(); + } else if (this.value !== this._preIsolationValue) { + this.fire(this.value, this._preIsolationValue); + } + return this._preIsolationValue = null; + } else if (this._isolationCount > 0) { + return this._isolationCount--; + } + }; + + Property.prototype.isIsolated = function() { + return this._isolationCount > 0; + }; + + return Property; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Keypath = (function(_super) { + + __extends(Keypath, _super); + + function Keypath(base, key) { + if (typeof key === 'string') { + this.segments = key.split('.'); + this.depth = this.segments.length; + } else { + this.segments = [key]; + this.depth = 1; + } + Keypath.__super__.constructor.apply(this, arguments); + } + + Keypath.prototype.isCachable = function() { + if (this.depth === 1) { + return Keypath.__super__.isCachable.apply(this, arguments); + } else { + return true; + } + }; + + Keypath.prototype.terminalProperty = function() { + var base; + base = Batman.getPath(this.base, this.segments.slice(0, -1)); + if (base == null) { + return; + } + return Batman.Keypath.forBaseAndKey(base, this.segments[this.depth - 1]); + }; + + Keypath.prototype.valueFromAccessor = function() { + if (this.depth === 1) { + return Keypath.__super__.valueFromAccessor.apply(this, arguments); + } else { + return Batman.getPath(this.base, this.segments); + } + }; + + Keypath.prototype.setValue = function(val) { + var _ref; + if (this.depth === 1) { + return Keypath.__super__.setValue.apply(this, arguments); + } else { + return (_ref = this.terminalProperty()) != null ? _ref.setValue(val) : void 0; + } + }; + + Keypath.prototype.unsetValue = function() { + var _ref; + if (this.depth === 1) { + return Keypath.__super__.unsetValue.apply(this, arguments); + } else { + return (_ref = this.terminalProperty()) != null ? _ref.unsetValue() : void 0; + } + }; + + return Keypath; + + })(Batman.Property); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.Observable = { + isObservable: true, + hasProperty: function(key) { + var _ref, _ref1; + return (_ref = this._batman) != null ? (_ref1 = _ref.properties) != null ? typeof _ref1.hasKey === "function" ? _ref1.hasKey(key) : void 0 : void 0 : void 0; + }, + property: function(key) { + var properties, propertyClass, _base; + Batman.initializeObject(this); + propertyClass = this.propertyClass || Batman.Keypath; + properties = (_base = this._batman).properties || (_base.properties = new Batman.SimpleHash); + return properties.get(key) || properties.set(key, new propertyClass(this, key)); + }, + get: function(key) { + return this.property(key).getValue(); + }, + set: function(key, val) { + return this.property(key).setValue(val); + }, + unset: function(key) { + return this.property(key).unsetValue(); + }, + getOrSet: Batman.SimpleHash.prototype.getOrSet, + forget: function(key, observer) { + var _ref; + if (key) { + this.property(key).forget(observer); + } else { + if ((_ref = this._batman.properties) != null) { + _ref.forEach(function(key, property) { + return property.forget(); + }); + } + } + return this; + }, + observe: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + (_ref = this.property(key)).observe.apply(_ref, args); + return this; + }, + observeAndFire: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + (_ref = this.property(key)).observeAndFire.apply(_ref, args); + return this; + }, + observeOnce: function() { + var args, key, _ref; + key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + (_ref = this.property(key)).observeOnce.apply(_ref, args); + return this; + } + }; + +}).call(this); + +(function() { + + Batman.DOM = { + textInputTypes: ['text', 'search', 'tel', 'url', 'email', 'password'], + scrollIntoView: function(elementID) { + var _ref; + return (_ref = document.getElementById(elementID)) != null ? typeof _ref.scrollIntoView === "function" ? _ref.scrollIntoView() : void 0 : void 0; + }, + querySelectorAll: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) { + return jQuery(selector, node); + } : (typeof document !== "undefined" && document !== null ? document.querySelectorAll : void 0) != null ? function(node, selector) { + return node.querySelectorAll(selector); + } : function() { + return Batman.developer.error("Please include either jQuery or a querySelectorAll polyfill, or set Batman.DOM.querySelectorAll to return an empty array."); + }, + querySelector: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) { + return jQuery(selector, node)[0]; + } : (typeof document !== "undefined" && document !== null ? document.querySelector : void 0) != null ? function(node, selector) { + return node.querySelector(selector); + } : function() { + return Batman.developer.error("Please include either jQuery or a querySelector polyfill, or set Batman.DOM.querySelector to an empty function."); + }, + partial: function(container, path, context, renderer) { + var view; + renderer.prevent('rendered'); + view = new Batman.View({ + source: path, + context: context + }); + return view.on('ready', function() { + Batman.setInnerHTML(container, ''); + Batman.appendChild(container, view.get('node')); + return renderer.allowAndFire('rendered'); + }); + }, + propagateBindingEvent: Batman.propagateBindingEvent = function(binding, node) { + var current, parentBinding, parentBindings, _i, _len; + while ((current = (current || node).parentNode)) { + parentBindings = Batman._data(current, 'bindings'); + if (parentBindings != null) { + for (_i = 0, _len = parentBindings.length; _i < _len; _i++) { + parentBinding = parentBindings[_i]; + if (typeof parentBinding.childBindingAdded === "function") { + parentBinding.childBindingAdded(binding); + } + } + } + } + }, + propagateBindingEvents: Batman.propagateBindingEvents = function(newNode) { + var binding, bindings, child, _i, _j, _len, _len1, _ref; + _ref = newNode.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.propagateBindingEvents(child); + } + if (bindings = Batman._data(newNode, 'bindings')) { + for (_j = 0, _len1 = bindings.length; _j < _len1; _j++) { + binding = bindings[_j]; + Batman.propagateBindingEvent(binding, newNode); + } + } + }, + trackBinding: Batman.trackBinding = function(binding, node) { + var bindings; + if (bindings = Batman._data(node, 'bindings')) { + bindings.push(binding); + } else { + Batman._data(node, 'bindings', [binding]); + } + Batman.DOM.fire('bindingAdded', binding); + Batman.propagateBindingEvent(binding, node); + return true; + }, + onParseExit: Batman.onParseExit = function(node, callback) { + var set; + set = Batman._data(node, 'onParseExit') || Batman._data(node, 'onParseExit', new Batman.SimpleSet); + if (callback != null) { + set.add(callback); + } + return set; + }, + forgetParseExit: Batman.forgetParseExit = function(node, callback) { + return Batman.removeData(node, 'onParseExit', true); + }, + defineView: function(name, node) { + var contents; + contents = node.innerHTML; + Batman.View.store.set(Batman.Navigator.normalizePath(name), contents); + return contents; + }, + setInnerHTML: Batman.setInnerHTML = function(node, html) { + var child, childNodes, result, _i, _j, _len, _len1; + childNodes = (function() { + var _i, _len, _ref, _results; + _ref = node.childNodes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(child); + } + return _results; + })(); + for (_i = 0, _len = childNodes.length; _i < _len; _i++) { + child = childNodes[_i]; + Batman.DOM.willRemoveNode(child); + } + result = node.innerHTML = html; + for (_j = 0, _len1 = childNodes.length; _j < _len1; _j++) { + child = childNodes[_j]; + Batman.DOM.didRemoveNode(child); + } + return result; + }, + setStyleProperty: Batman.setStyleProperty = function(node, property, value, importance) { + if (node.style.setAttribute) { + return node.style.setAttribute(property, value, importance); + } else { + return node.style.setProperty(property, value, importance); + } + }, + removeNode: Batman.removeNode = function(node) { + var _ref; + Batman.DOM.willRemoveNode(node); + if ((_ref = node.parentNode) != null) { + _ref.removeChild(node); + } + return Batman.DOM.didRemoveNode(node); + }, + destroyNode: Batman.destroyNode = function(node) { + Batman.DOM.willDestroyNode(node); + Batman.removeNode(node); + return Batman.DOM.didDestroyNode(node); + }, + appendChild: Batman.appendChild = function(parent, child) { + Batman.DOM.willInsertNode(child); + parent.appendChild(child); + return Batman.DOM.didInsertNode(child); + }, + removeOrDestroyNode: Batman.removeOrDestroyNode = function(node) { + var view; + view = Batman._data(node, 'view'); + view || (view = Batman._data(node, 'yielder')); + if ((view != null) && view.get('cached')) { + return Batman.DOM.removeNode(node); + } else { + return Batman.DOM.destroyNode(node); + } + }, + insertBefore: Batman.insertBefore = function(parentNode, newNode, referenceNode) { + if (referenceNode == null) { + referenceNode = null; + } + if (!referenceNode || parentNode.childNodes.length <= 0) { + return Batman.appendChild(parentNode, newNode); + } else { + Batman.DOM.willInsertNode(newNode); + parentNode.insertBefore(newNode, referenceNode); + return Batman.DOM.didInsertNode(newNode); + } + }, + valueForNode: function(node, value, escapeValue) { + var isSetting; + if (value == null) { + value = ''; + } + if (escapeValue == null) { + escapeValue = true; + } + isSetting = arguments.length > 1; + switch (node.nodeName.toUpperCase()) { + case 'INPUT': + case 'TEXTAREA': + if (isSetting) { + return node.value = value; + } else { + return node.value; + } + break; + case 'SELECT': + if (isSetting) { + return node.value = value; + } + break; + default: + if (isSetting) { + return Batman.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value); + } else { + return node.innerHTML; + } + } + }, + nodeIsEditable: function(node) { + var _ref; + return (_ref = node.nodeName.toUpperCase()) === 'INPUT' || _ref === 'TEXTAREA' || _ref === 'SELECT'; + }, + addEventListener: Batman.addEventListener = function(node, eventName, callback) { + var listeners; + if (!(listeners = Batman._data(node, 'listeners'))) { + listeners = Batman._data(node, 'listeners', {}); + } + if (!listeners[eventName]) { + listeners[eventName] = []; + } + listeners[eventName].push(callback); + if (Batman.hasAddEventListener) { + return node.addEventListener(eventName, callback, false); + } else { + return node.attachEvent("on" + eventName, callback); + } + }, + removeEventListener: Batman.removeEventListener = function(node, eventName, callback) { + var eventListeners, index, listeners; + if (listeners = Batman._data(node, 'listeners')) { + if (eventListeners = listeners[eventName]) { + index = eventListeners.indexOf(callback); + if (index !== -1) { + eventListeners.splice(index, 1); + } + } + } + if (Batman.hasAddEventListener) { + return node.removeEventListener(eventName, callback, false); + } else { + return node.detachEvent('on' + eventName, callback); + } + }, + hasAddEventListener: Batman.hasAddEventListener = !!(typeof window !== "undefined" && window !== null ? window.addEventListener : void 0), + preventDefault: Batman.preventDefault = function(e) { + if (typeof e.preventDefault === "function") { + return e.preventDefault(); + } else { + return e.returnValue = false; + } + }, + stopPropagation: Batman.stopPropagation = function(e) { + if (e.stopPropagation) { + return e.stopPropagation(); + } else { + return e.cancelBubble = true; + } + }, + willInsertNode: function(node) { + var child, view, _i, _len, _ref, _ref1; + view = Batman._data(node, 'view'); + if (view != null) { + view.fire('beforeAppear', node); + } + if ((_ref = Batman.data(node, 'show')) != null) { + _ref.call(node); + } + _ref1 = node.childNodes; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + child = _ref1[_i]; + Batman.DOM.willInsertNode(child); + } + return true; + }, + didInsertNode: function(node) { + var child, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.fire('appear', node); + view.applyYields(); + } + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.didInsertNode(child); + } + return true; + }, + willRemoveNode: function(node) { + var child, view, _i, _len, _ref, _ref1; + view = Batman._data(node, 'view'); + if (view) { + view.fire('beforeDisappear', node); + } + if ((_ref = Batman.data(node, 'hide')) != null) { + _ref.call(node); + } + _ref1 = node.childNodes; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + child = _ref1[_i]; + Batman.DOM.willRemoveNode(child); + } + return true; + }, + didRemoveNode: function(node) { + var child, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.retractYields(); + view.fire('disappear', node); + } + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.didRemoveNode(child); + } + return true; + }, + willDestroyNode: function(node) { + var child, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.fire('beforeDestroy', node); + view.get('yields').forEach(function(name, actions) { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = actions.length; _i < _len; _i++) { + node = actions[_i].node; + _results.push(Batman.DOM.willDestroyNode(node)); + } + return _results; + }); + } + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.willDestroyNode(child); + } + return true; + }, + didDestroyNode: function(node) { + var bindings, child, eventListeners, eventName, listeners, view, _i, _len, _ref; + view = Batman._data(node, 'view'); + if (view) { + view.fire('destroy', node); + view.get('yields').forEach(function(name, actions) { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = actions.length; _i < _len; _i++) { + node = actions[_i].node; + _results.push(Batman.DOM.didDestroyNode(node)); + } + return _results; + }); + } + if (bindings = Batman._data(node, 'bindings')) { + bindings.forEach(function(binding) { + return binding.die(); + }); + } + if (listeners = Batman._data(node, 'listeners')) { + for (eventName in listeners) { + eventListeners = listeners[eventName]; + eventListeners.forEach(function(listener) { + return Batman.removeEventListener(node, eventName, listener); + }); + } + } + Batman.removeData(node); + Batman.removeData(node, void 0, true); + _ref = node.childNodes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + Batman.DOM.didDestroyNode(child); + } + return true; + } + }; + + Batman.mixin(Batman.DOM, Batman.EventEmitter, Batman.Observable); + + Batman.DOM.event('bindingAdded'); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.DOM.readers = { + target: function(node, key, context, renderer) { + Batman.DOM.readers.bind(node, key, context, renderer, 'nodeChange'); + return true; + }, + source: function(node, key, context, renderer) { + Batman.DOM.readers.bind(node, key, context, renderer, 'dataChange'); + return true; + }, + bind: function(node, key, context, renderer, only) { + var bindingClass; + bindingClass = false; + switch (node.nodeName.toLowerCase()) { + case 'input': + switch (node.getAttribute('type')) { + case 'checkbox': + Batman.DOM.attrReaders.bind(node, 'checked', key, context, renderer, only); + return true; + case 'radio': + bindingClass = Batman.DOM.RadioBinding; + break; + case 'file': + bindingClass = Batman.DOM.FileBinding; + } + break; + case 'select': + bindingClass = Batman.DOM.SelectBinding; + } + bindingClass || (bindingClass = Batman.DOM.Binding); + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(bindingClass, arguments, function(){}); + return true; + }, + context: function(node, key, context, renderer) { + return context.descendWithKey(key); + }, + mixin: function(node, key, context, renderer) { + new Batman.DOM.MixinBinding(node, key, context.descend(Batman.mixins), renderer); + return true; + }, + showif: function(node, key, context, parentRenderer, invert) { + new Batman.DOM.ShowHideBinding(node, key, context, parentRenderer, false, invert); + return true; + }, + hideif: function() { + var _ref; + return (_ref = Batman.DOM.readers).showif.apply(_ref, __slice.call(arguments).concat([true])); + }, + insertif: function(node, key, context, parentRenderer, invert) { + new Batman.DOM.InsertionBinding(node, key, context, parentRenderer, false, invert); + return true; + }, + removeif: function() { + var _ref; + return (_ref = Batman.DOM.readers).insertif.apply(_ref, __slice.call(arguments).concat([true])); + }, + route: function() { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.RouteBinding, arguments, function(){}); + return true; + }, + view: function() { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.ViewBinding, arguments, function(){}); + return false; + }, + partial: function(node, path, context, renderer) { + Batman.DOM.partial(node, path, context, renderer); + return true; + }, + defineview: function(node, name, context, renderer) { + Batman.onParseExit(node, function() { + var _ref; + return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; + }); + Batman.DOM.defineView(name, node); + return false; + }, + renderif: function(node, key, context, renderer) { + new Batman.DOM.DeferredRenderingBinding(node, key, context, renderer); + return false; + }, + "yield": function(node, key) { + Batman.onParseExit(node, function() { + return Batman.DOM.Yield.withName(key).set('containerNode', node); + }); + return true; + }, + contentfor: function(node, key, context, renderer, action) { + if (action == null) { + action = 'append'; + } + Batman.onParseExit(node, function() { + var _ref; + if ((_ref = node.parentNode) != null) { + _ref.removeChild(node); + } + return renderer.view.pushYieldAction(key, action, node); + }); + return true; + }, + replace: function(node, key, context, renderer) { + Batman.DOM.readers.contentfor(node, key, context, renderer, 'replace'); + return true; + } + }; + +}).call(this); + +(function() { + var __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.DOM.events = { + click: function(node, callback, context, eventName) { + if (eventName == null) { + eventName = 'click'; + } + Batman.addEventListener(node, eventName, function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + callback.apply(null, [node].concat(__slice.call(args), [context])); + return Batman.preventDefault(args[0]); + }); + if (node.nodeName.toUpperCase() === 'A' && !node.href) { + node.href = '#'; + } + return node; + }, + doubleclick: function(node, callback, context) { + return Batman.DOM.events.click(node, callback, context, 'dblclick'); + }, + change: function(node, callback, context) { + var eventName, eventNames, oldCallback, _i, _len, _results; + eventNames = (function() { + var _ref; + switch (node.nodeName.toUpperCase()) { + case 'TEXTAREA': + return ['input', 'keyup', 'change']; + case 'INPUT': + if (_ref = node.type.toLowerCase(), __indexOf.call(Batman.DOM.textInputTypes, _ref) >= 0) { + oldCallback = callback; + callback = function(node, event) { + if (event.type === 'keyup' && Batman.DOM.events.isEnter(event)) { + return; + } + return oldCallback.apply(null, arguments); + }; + return ['input', 'keyup', 'change']; + } else { + return ['input', 'change']; + } + break; + default: + return ['change']; + } + })(); + _results = []; + for (_i = 0, _len = eventNames.length; _i < _len; _i++) { + eventName = eventNames[_i]; + _results.push(Batman.addEventListener(node, eventName, function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return callback.apply(null, [node].concat(__slice.call(args), [context])); + })); + } + return _results; + }, + isEnter: function(ev) { + var _ref, _ref1; + return ((13 <= (_ref = ev.keyCode) && _ref <= 14)) || ((13 <= (_ref1 = ev.which) && _ref1 <= 14)) || ev.keyIdentifier === 'Enter' || ev.key === 'Enter'; + }, + submit: function(node, callback, context) { + if (Batman.DOM.nodeIsEditable(node)) { + Batman.addEventListener(node, 'keydown', function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (Batman.DOM.events.isEnter(args[0])) { + return Batman.DOM._keyCapturingNode = node; + } + }); + Batman.addEventListener(node, 'keyup', function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (Batman.DOM.events.isEnter(args[0])) { + if (Batman.DOM._keyCapturingNode === node) { + Batman.preventDefault(args[0]); + callback.apply(null, [node].concat(__slice.call(args), [context])); + } + return Batman.DOM._keyCapturingNode = null; + } + }); + } else { + Batman.addEventListener(node, 'submit', function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + Batman.preventDefault(args[0]); + return callback.apply(null, [node].concat(__slice.call(args), [context])); + }); + } + return node; + }, + other: function(node, eventName, callback, context) { + return Batman.addEventListener(node, eventName, function() { + var args; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return callback.apply(null, [node].concat(__slice.call(args), [context])); + }); + } + }; + +}).call(this); + +(function() { + + Batman.DOM.attrReaders = { + _parseAttribute: function(value) { + if (value === 'false') { + value = false; + } + if (value === 'true') { + value = true; + } + return value; + }, + source: function(node, attr, key, context, renderer) { + return Batman.DOM.attrReaders.bind(node, attr, key, context, renderer, 'dataChange'); + }, + bind: function(node, attr, key, context, renderer, only) { + var bindingClass; + bindingClass = (function() { + switch (attr) { + case 'checked': + case 'disabled': + case 'selected': + return Batman.DOM.CheckedBinding; + case 'value': + case 'href': + case 'src': + case 'size': + return Batman.DOM.NodeAttributeBinding; + case 'class': + return Batman.DOM.ClassBinding; + case 'style': + return Batman.DOM.StyleBinding; + default: + return Batman.DOM.AttributeBinding; + } + })(); + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(bindingClass, arguments, function(){}); + return true; + }, + context: function(node, contextName, key, context) { + return context.descendWithKey(key, contextName); + }, + event: function(node, eventName, key, context) { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.EventBinding, arguments, function(){}); + return true; + }, + addclass: function(node, className, key, context, parentRenderer, invert) { + new Batman.DOM.AddClassBinding(node, className, key, context, parentRenderer, false, invert); + return true; + }, + removeclass: function(node, className, key, context, parentRenderer) { + return Batman.DOM.attrReaders.addclass(node, className, key, context, parentRenderer, true); + }, + foreach: function(node, iteratorName, key, context, parentRenderer) { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.IteratorBinding, arguments, function(){}); + return false; + }, + formfor: function(node, localName, key, context) { + (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.DOM.FormBinding, arguments, function(){}); + return context.descendWithKey(key, localName); + } + }; + +}).call(this); + +(function() { + var BatmanObject, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + BatmanObject = (function(_super) { + var counter, getAccessorObject, promiseWrapper, wrapSingleAccessor; + + __extends(BatmanObject, _super); + + Batman.initializeObject(BatmanObject); + + Batman.initializeObject(BatmanObject.prototype); + + BatmanObject.classMixin = function() { + return Batman.mixin.apply(Batman, [this].concat(__slice.call(arguments))); + }; + + BatmanObject.mixin = function() { + return this.classMixin.apply(this.prototype, arguments); + }; + + BatmanObject.prototype.mixin = BatmanObject.classMixin; + + counter = 0; + + BatmanObject.prototype._batmanID = function() { + var c; + this._batmanID = function() { + return c; + }; + return c = counter++; + }; + + BatmanObject.prototype.hashKey = function() { + var key; + if (typeof this.isEqual === 'function') { + return; + } + this.hashKey = function() { + return key; + }; + return key = ""; + }; + + BatmanObject.prototype.toJSON = function() { + var key, obj, value; + obj = {}; + for (key in this) { + if (!__hasProp.call(this, key)) continue; + value = this[key]; + if (key !== "_batman" && key !== "hashKey" && key !== "_batmanID") { + obj[key] = (value != null ? value.toJSON : void 0) ? value.toJSON() : value; + } + } + return obj; + }; + + getAccessorObject = function(base, accessor) { + var deprecated, _i, _len, _ref; + if (typeof accessor === 'function') { + accessor = { + get: accessor + }; + } + _ref = ['cachable', 'cacheable']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + deprecated = _ref[_i]; + if (deprecated in accessor) { + Batman.developer.warn("Property accessor option \"" + deprecated + "\" is deprecated. Use \"cache\" instead."); + if (!('cache' in accessor)) { + accessor.cache = accessor[deprecated]; + } + } + } + return accessor; + }; + + promiseWrapper = function(fetcher) { + return function(core) { + return { + get: function(key) { + var deliver, returned, val, + _this = this; + val = core.get.apply(this, arguments); + if (typeof val !== 'undefined') { + return val; + } + returned = false; + deliver = function(err, result) { + if (returned) { + _this.set(key, result); + } + return val = result; + }; + fetcher.call(this, deliver, key); + returned = true; + return val; + }, + cache: true + }; + }; + }; + + wrapSingleAccessor = function(core, wrapper) { + var k, v; + wrapper = (typeof wrapper === "function" ? wrapper(core) : void 0) || wrapper; + for (k in core) { + v = core[k]; + if (!(k in wrapper)) { + wrapper[k] = v; + } + } + return wrapper; + }; + + BatmanObject._defineAccessor = function() { + var accessor, key, keys, _base, _i, _j, _len, _ref, _results; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), accessor = arguments[_i++]; + if (!(accessor != null)) { + return Batman.Property.defaultAccessorForBase(this); + } else if (keys.length === 0 && ((_ref = Batman.typeOf(accessor)) !== 'Object' && _ref !== 'Function')) { + return Batman.Property.accessorForBaseAndKey(this, accessor); + } else if (typeof accessor.promise === 'function') { + return this._defineWrapAccessor.apply(this, __slice.call(keys).concat([promiseWrapper(accessor.promise)])); + } + Batman.initializeObject(this); + if (keys.length === 0) { + return this._batman.defaultAccessor = getAccessorObject(this, accessor); + } else { + (_base = this._batman).keyAccessors || (_base.keyAccessors = new Batman.SimpleHash); + _results = []; + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + _results.push(this._batman.keyAccessors.set(key, getAccessorObject(this, accessor))); + } + return _results; + } + }; + + BatmanObject.prototype._defineAccessor = BatmanObject._defineAccessor; + + BatmanObject._defineWrapAccessor = function() { + var key, keys, wrapper, _i, _j, _len, _results; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), wrapper = arguments[_i++]; + Batman.initializeObject(this); + if (keys.length === 0) { + return this._defineAccessor(wrapSingleAccessor(this._defineAccessor(), wrapper)); + } else { + _results = []; + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + _results.push(this._defineAccessor(key, wrapSingleAccessor(this._defineAccessor(key), wrapper))); + } + return _results; + } + }; + + BatmanObject.prototype._defineWrapAccessor = BatmanObject._defineWrapAccessor; + + BatmanObject.classAccessor = BatmanObject._defineAccessor; + + BatmanObject.accessor = function() { + var _ref; + return (_ref = this.prototype)._defineAccessor.apply(_ref, arguments); + }; + + BatmanObject.prototype.accessor = BatmanObject._defineAccessor; + + BatmanObject.wrapClassAccessor = BatmanObject._defineWrapAccessor; + + BatmanObject.wrapAccessor = function() { + var _ref; + return (_ref = this.prototype)._defineWrapAccessor.apply(_ref, arguments); + }; + + BatmanObject.prototype.wrapAccessor = BatmanObject._defineWrapAccessor; + + function BatmanObject() { + var mixins; + mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + this._batman = new Batman._Batman(this); + this.mixin.apply(this, mixins); + } + + BatmanObject.classMixin(Batman.EventEmitter, Batman.Observable); + + BatmanObject.mixin(Batman.EventEmitter, Batman.Observable); + + BatmanObject.observeAll = function() { + return this.prototype.observe.apply(this.prototype, arguments); + }; + + BatmanObject.singleton = function(singletonMethodName) { + if (singletonMethodName == null) { + singletonMethodName = "sharedInstance"; + } + return this.classAccessor(singletonMethodName, { + get: function() { + var _name; + return this[_name = "_" + singletonMethodName] || (this[_name] = new this); + } + }); + }; + + BatmanObject.accessor('_batmanID', function() { + return this._batmanID(); + }); + + return BatmanObject; + + })(Object); + + Batman.Object = BatmanObject; + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Renderer = (function(_super) { + var bindingRegexp, bindingSortOrder, bindingSortPositions, k, name, pos, _i, _j, _len, _len1, _ref; + + __extends(Renderer, _super); + + Renderer.prototype.deferEvery = 50; + + function Renderer(node, context, view) { + this.node = node; + this.context = context; + this.view = view; + this.resume = __bind(this.resume, this); + + this.start = __bind(this.start, this); + + Renderer.__super__.constructor.call(this); + if (!(this.context instanceof Batman.RenderContext)) { + Batman.developer.error("Must pass a RenderContext to a renderer for rendering"); + } + this.immediate = Batman.setImmediate(this.start); + } + + Renderer.prototype.start = function() { + this.startTime = new Date; + return this.parseNode(this.node); + }; + + Renderer.prototype.resume = function() { + this.startTime = new Date; + return this.parseNode(this.resumeNode); + }; + + Renderer.prototype.finish = function() { + this.startTime = null; + this.prevent('stopped'); + this.fire('parsed'); + return this.fire('rendered'); + }; + + Renderer.prototype.stop = function() { + Batman.clearImmediate(this.immediate); + return this.fire('stopped'); + }; + + _ref = ['parsed', 'rendered', 'stopped']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + Renderer.prototype.event(k).oneShot = true; + } + + bindingRegexp = /^data\-(.*)/; + + bindingSortOrder = ["view", "renderif", "foreach", "formfor", "context", "bind", "source", "target"]; + + bindingSortPositions = {}; + + for (pos = _j = 0, _len1 = bindingSortOrder.length; _j < _len1; pos = ++_j) { + name = bindingSortOrder[pos]; + bindingSortPositions[name] = pos; + } + + Renderer.prototype._sortBindings = function(a, b) { + var aindex, bindex; + aindex = bindingSortPositions[a[0]]; + bindex = bindingSortPositions[b[0]]; + if (aindex == null) { + aindex = bindingSortOrder.length; + } + if (bindex == null) { + bindex = bindingSortOrder.length; + } + if (aindex > bindex) { + return 1; + } else if (bindex > aindex) { + return -1; + } else if (a[0] > b[0]) { + return 1; + } else if (b[0] > a[0]) { + return -1; + } else { + return 0; + } + }; + + Renderer.prototype.parseNode = function(node) { + var argument, attribute, bindings, keypath, names, nextNode, oldContext, result, skipChildren, _base, _base1, _k, _l, _len2, _len3, _ref1, _ref2, _ref3, _ref4, + _this = this; + if (this.deferEvery && (new Date - this.startTime) > this.deferEvery) { + this.resumeNode = node; + this.timeout = Batman.setImmediate(this.resume); + return; + } + if (node.getAttribute && node.attributes) { + bindings = []; + _ref1 = node.attributes; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + attribute = _ref1[_k]; + name = (_ref2 = attribute.nodeName.match(bindingRegexp)) != null ? _ref2[1] : void 0; + if (!name) { + continue; + } + bindings.push((names = name.split('-')).length > 1 ? [names[0], names.slice(1, names.length + 1 || 9e9).join('-'), attribute.value] : [name, void 0, attribute.value]); + } + _ref3 = bindings.sort(this._sortBindings); + for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { + _ref4 = _ref3[_l], name = _ref4[0], argument = _ref4[1], keypath = _ref4[2]; + result = argument ? typeof (_base = Batman.DOM.attrReaders)[name] === "function" ? _base[name](node, argument, keypath, this.context, this) : void 0 : typeof (_base1 = Batman.DOM.readers)[name] === "function" ? _base1[name](node, keypath, this.context, this) : void 0; + if (result === false) { + skipChildren = true; + break; + } else if (result instanceof Batman.RenderContext) { + oldContext = this.context; + this.context = result; + Batman.onParseExit(node, function() { + return _this.context = oldContext; + }); + } + } + } + if ((nextNode = this.nextNode(node, skipChildren))) { + return this.parseNode(nextNode); + } else { + return this.finish(); + } + }; + + Renderer.prototype.nextNode = function(node, skipChildren) { + var children, nextParent, parentSibling, sibling, _ref1, _ref2; + if (!skipChildren) { + children = node.childNodes; + if (children != null ? children.length : void 0) { + return children[0]; + } + } + sibling = node.nextSibling; + if ((_ref1 = Batman.onParseExit(node)) != null) { + _ref1.forEach(function(callback) { + return callback(); + }); + } + Batman.forgetParseExit(node); + if (this.node === node) { + return; + } + if (sibling) { + return sibling; + } + nextParent = node; + while (nextParent = nextParent.parentNode) { + parentSibling = nextParent.nextSibling; + if ((_ref2 = Batman.onParseExit(nextParent)) != null) { + _ref2.forEach(function(callback) { + return callback(); + }); + } + Batman.forgetParseExit(nextParent); + if (this.node === nextParent) { + return; + } + if (parentSibling) { + return parentSibling; + } + } + }; + + return Renderer; + + })(Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AbstractBinding = (function(_super) { + var get_dot_rx, get_rx, keypath_rx; + + __extends(AbstractBinding, _super); + + keypath_rx = /(^|,)\s*(?:(true|false)|("[^"]*")|(\{[^\}]*\})|([a-zA-Z][\w\-\.]*[\?\!]?))\s*(?=$|,)/g; + + get_dot_rx = /(?:\]\.)(.+?)(?=[\[\.]|\s*\||$)/; + + get_rx = /(?!^\s*)\[(.*?)\]/g; + + AbstractBinding.accessor('filteredValue', { + get: function() { + var renderContext, result, self, unfilteredValue; + unfilteredValue = this.get('unfilteredValue'); + self = this; + renderContext = this.get('renderContext'); + if (this.filterFunctions.length > 0) { + Batman.developer.currentFilterStack = renderContext; + result = this.filterFunctions.reduce(function(value, fn, i) { + var args; + args = self.filterArguments[i].map(function(argument) { + if (argument._keypath) { + return self.renderContext.get(argument._keypath); + } else { + return argument; + } + }); + args.unshift(value); + while (args.length < (fn.length - 1)) { + args.push(void 0); + } + args.push(self); + return fn.apply(renderContext, args); + }, unfilteredValue); + Batman.developer.currentFilterStack = null; + return result; + } else { + return unfilteredValue; + } + }, + set: function(_, newValue) { + return this.set('unfilteredValue', newValue); + } + }); + + AbstractBinding.accessor('unfilteredValue', { + get: function() { + var k; + if (k = this.get('key')) { + return Batman.RenderContext.deProxy(Batman.getPath(this, ['keyContext', k])); + } else { + return this.get('value'); + } + }, + set: function(_, value) { + var k, keyContext, prop; + if (k = this.get('key')) { + keyContext = this.get('keyContext'); + if (keyContext && keyContext !== Batman.container) { + prop = Batman.Property.forBaseAndKey(keyContext, k); + return prop.setValue(value); + } + } else { + return this.set('value', value); + } + } + }); + + AbstractBinding.accessor('keyContext', function() { + return this.renderContext.contextForKey(this.key); + }); + + AbstractBinding.prototype.bindImmediately = true; + + AbstractBinding.prototype.shouldSet = true; + + AbstractBinding.prototype.isInputBinding = false; + + AbstractBinding.prototype.escapeValue = true; + + function AbstractBinding(node, keyPath, renderContext, renderer, only) { + this.node = node; + this.keyPath = keyPath; + this.renderContext = renderContext; + this.renderer = renderer; + this.only = only != null ? only : false; + this._fireDataChange = __bind(this._fireDataChange, this); + + this._fireNodeChange = __bind(this._fireNodeChange, this); + + this.parseFilter(); + if (this.bindImmediately) { + this.bind(); + } + } + + AbstractBinding.prototype.isTwoWay = function() { + return (this.key != null) && this.filterFunctions.length === 0; + }; + + AbstractBinding.prototype.bind = function() { + var _ref, _ref1; + if ((this.node != null) && ((_ref = this.only) === false || _ref === 'nodeChange') && Batman.DOM.nodeIsEditable(this.node)) { + Batman.DOM.events.change(this.node, this._fireNodeChange); + if (this.only === 'nodeChange') { + this._fireNodeChange(); + } + } + if ((_ref1 = this.only) === false || _ref1 === 'dataChange') { + this.observeAndFire('filteredValue', this._fireDataChange); + } + if (this.node != null) { + return Batman.DOM.trackBinding(this, this.node); + } + }; + + AbstractBinding.prototype._fireNodeChange = function(event) { + var val; + this.shouldSet = false; + val = this.value || this.get('keyContext'); + if (typeof this.nodeChange === "function") { + this.nodeChange(this.node, val, event); + } + this.fire('nodeChange', this.node, val); + return this.shouldSet = true; + }; + + AbstractBinding.prototype._fireDataChange = function(value) { + if (this.shouldSet) { + if (typeof this.dataChange === "function") { + this.dataChange(value, this.node); + } + return this.fire('dataChange', value, this.node); + } + }; + + AbstractBinding.prototype.die = function() { + var _ref; + this.forget(); + if ((_ref = this._batman.properties) != null) { + _ref.forEach(function(key, property) { + return property.die(); + }); + } + this.fire('die'); + this.dead = true; + return true; + }; + + AbstractBinding.prototype.parseFilter = function() { + var args, filter, filterName, filterString, filters, key, keyPath, orig, split; + this.filterFunctions = []; + this.filterArguments = []; + keyPath = this.keyPath; + while (get_dot_rx.test(keyPath)) { + keyPath = keyPath.replace(get_dot_rx, "]['$1']"); + } + filters = keyPath.replace(get_rx, " | get $1 ").replace(/'/g, '"').split(/(?!")\s+\|\s+(?!")/); + try { + key = this.parseSegment(orig = filters.shift())[0]; + } catch (e) { + Batman.developer.warn(e); + Batman.developer.error("Error! Couldn't parse keypath in \"" + orig + "\". Parsing error above."); + } + if (key && key._keypath) { + this.key = key._keypath; + } else { + this.value = key; + } + if (filters.length) { + while (filterString = filters.shift()) { + split = filterString.indexOf(' '); + if (split === -1) { + split = filterString.length; + } + filterName = filterString.substr(0, split); + args = filterString.substr(split); + if (!(filter = Batman.Filters[filterName])) { + return Batman.developer.error("Unrecognized filter '" + filterName + "' in key \"" + this.keyPath + "\"!"); + } + this.filterFunctions.push(filter); + try { + this.filterArguments.push(this.parseSegment(args)); + } catch (e) { + Batman.developer.error("Bad filter arguments \"" + args + "\"!"); + } + } + return true; + } + }; + + AbstractBinding.prototype.parseSegment = function(segment) { + segment = segment.replace(keypath_rx, function(match, start, bool, string, object, keypath, offset) { + var replacement; + if (start == null) { + start = ''; + } + replacement = keypath ? '{"_keypath": "' + keypath + '"}' : bool || string || object; + return start + replacement; + }); + return JSON.parse("[" + segment + "]"); + }; + + return AbstractBinding; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ViewBinding = (function(_super) { + + __extends(ViewBinding, _super); + + function ViewBinding() { + ViewBinding.__super__.constructor.apply(this, arguments); + this.renderer.prevent('rendered'); + this.node.removeAttribute('data-view'); + } + + ViewBinding.prototype.dataChange = function(viewClassOrInstance) { + var _this = this; + if (viewClassOrInstance == null) { + return; + } + if (viewClassOrInstance.isView) { + this.view = viewClassOrInstance; + this.view.set('context', this.renderContext); + this.view.set('node', this.node); + } else { + this.view = new viewClassOrInstance({ + node: this.node, + context: this.renderContext, + parentView: this.renderer.view + }); + } + this.view.on('ready', function() { + return _this.renderer.allowAndFire('rendered'); + }); + return this.die(); + }; + + return ViewBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ViewArgumentBinding = (function(_super) { + + __extends(ViewArgumentBinding, _super); + + function ViewArgumentBinding() { + return ViewArgumentBinding.__super__.constructor.apply(this, arguments); + } + + return ViewArgumentBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ShowHideBinding = (function(_super) { + + __extends(ShowHideBinding, _super); + + function ShowHideBinding(node, className, key, context, parentRenderer, invert) { + var display; + this.invert = invert != null ? invert : false; + display = node.style.display; + if (!display || display === 'none') { + display = ''; + } + this.originalDisplay = display; + ShowHideBinding.__super__.constructor.apply(this, arguments); + } + + ShowHideBinding.prototype.dataChange = function(value) { + var hide, view, _ref; + view = Batman._data(this.node, 'view'); + if (!!value === !this.invert) { + if (view != null) { + view.fire('beforeAppear', this.node); + } + if ((_ref = Batman.data(this.node, 'show')) != null) { + _ref.call(this.node); + } + this.node.style.display = this.originalDisplay; + return view != null ? view.fire('appear', this.node) : void 0; + } else { + if (view != null) { + view.fire('beforeDisappear', this.node); + } + if (typeof (hide = Batman.data(this.node, 'hide')) === 'function') { + hide.call(this.node); + } else { + Batman.setStyleProperty(this.node, 'display', 'none', 'important'); + } + return view != null ? view.fire('disappear', this.node) : void 0; + } + }; + + return ShowHideBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.SelectBinding = (function(_super) { + + __extends(SelectBinding, _super); + + SelectBinding.prototype.isInputBinding = true; + + SelectBinding.prototype.firstBind = true; + + function SelectBinding() { + this.updateOptionBindings = __bind(this.updateOptionBindings, this); + + this.nodeChange = __bind(this.nodeChange, this); + + this.dataChange = __bind(this.dataChange, this); + + this.childBindingAdded = __bind(this.childBindingAdded, this); + this.selectedBindings = new Batman.SimpleSet; + SelectBinding.__super__.constructor.apply(this, arguments); + } + + SelectBinding.prototype.childBindingAdded = function(binding) { + var dataChangeHandler, + _this = this; + if (binding instanceof Batman.DOM.CheckedBinding) { + binding.on('dataChange', dataChangeHandler = function() { + return _this.nodeChange(); + }); + binding.on('die', function() { + binding.forget('dataChange', dataChangeHandler); + return _this.selectedBindings.remove(binding); + }); + this.selectedBindings.add(binding); + } else if (binding instanceof Batman.DOM.IteratorBinding) { + binding.on('nodeAdded', dataChangeHandler = function() { + return _this._fireDataChange(_this.get('filteredValue')); + }); + binding.on('nodeRemoved', dataChangeHandler); + binding.on('die', function() { + binding.forget('nodeAdded', dataChangeHandler); + return binding.forget('nodeRemoved', dataChangeHandler); + }); + } else { + return; + } + return this._fireDataChange(this.get('filteredValue')); + }; + + SelectBinding.prototype.dataChange = function(newValue) { + var child, matches, valueToChild, _i, _len, _name, _ref, + _this = this; + if (newValue != null ? newValue.forEach : void 0) { + valueToChild = {}; + _ref = this.node.children; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + child.selected = false; + matches = valueToChild[_name = child.value] || (valueToChild[_name] = []); + matches.push(child); + } + newValue.forEach(function(value) { + var children, node, _j, _len1, _results; + if (children = valueToChild[value]) { + _results = []; + for (_j = 0, _len1 = children.length; _j < _len1; _j++) { + node = children[_j]; + _results.push(node.selected = true); + } + return _results; + } + }); + } else { + if (typeof newValue === 'undefined' && this.firstBind) { + this.set('unfilteredValue', this.node.value); + } else { + Batman.DOM.valueForNode(this.node, newValue, this.escapeValue); + } + this.firstBind = false; + } + this.updateOptionBindings(); + }; + + SelectBinding.prototype.nodeChange = function() { + var c, selections; + if (this.isTwoWay()) { + selections = this.node.multiple ? (function() { + var _i, _len, _ref, _results; + _ref = this.node.children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + c = _ref[_i]; + if (c.selected) { + _results.push(c.value); + } + } + return _results; + }).call(this) : this.node.value; + if (typeof selections === Array && selections.length === 1) { + selections = selections[0]; + } + this.set('unfilteredValue', selections); + this.updateOptionBindings(); + } + }; + + SelectBinding.prototype.updateOptionBindings = function() { + return this.selectedBindings.forEach(function(binding) { + return binding._fireNodeChange(); + }); + }; + + return SelectBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.RouteBinding = (function(_super) { + + __extends(RouteBinding, _super); + + function RouteBinding() { + return RouteBinding.__super__.constructor.apply(this, arguments); + } + + RouteBinding.prototype.onATag = false; + + RouteBinding.accessor('dispatcher', function() { + return this.renderContext.get('dispatcher') || Batman.App.get('current.dispatcher'); + }); + + RouteBinding.prototype.bind = function() { + var _this = this; + if (this.node.nodeName.toUpperCase() === 'A') { + this.onATag = true; + } + RouteBinding.__super__.bind.apply(this, arguments); + return Batman.DOM.events.click(this.node, function(node, event) { + var params; + if (event.__batmanActionTaken) { + return; + } + event.__batmanActionTaken = true; + params = _this.pathFromValue(_this.get('filteredValue')); + if (params != null) { + return Batman.redirect(params); + } + }); + }; + + RouteBinding.prototype.dataChange = function(value) { + var path; + if (value != null) { + path = this.pathFromValue(value); + } + if (this.onATag) { + if ((path != null) && (Batman.navigator != null)) { + path = Batman.navigator.linkTo(path); + } else { + path = "#"; + } + return this.node.href = path; + } + }; + + RouteBinding.prototype.pathFromValue = function(value) { + var _ref; + if (value != null) { + if (value.isNamedRouteQuery) { + return value.get('path'); + } else { + return (_ref = this.get('dispatcher')) != null ? _ref.pathFromParams(value) : void 0; + } + } + }; + + return RouteBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.RadioBinding = (function(_super) { + + __extends(RadioBinding, _super); + + function RadioBinding() { + return RadioBinding.__super__.constructor.apply(this, arguments); + } + + RadioBinding.accessor('parsedNodeValue', function() { + return Batman.DOM.attrReaders._parseAttribute(this.node.value); + }); + + RadioBinding.prototype.firstBind = true; + + RadioBinding.prototype.dataChange = function(value) { + var boundValue; + boundValue = this.get('filteredValue'); + if (boundValue != null) { + this.node.checked = boundValue === Batman.DOM.attrReaders._parseAttribute(this.node.value); + } else { + if (this.firstBind && this.node.checked) { + this.set('filteredValue', this.get('parsedNodeValue')); + } + } + return this.firstBind = false; + }; + + RadioBinding.prototype.nodeChange = function(node) { + if (this.isTwoWay()) { + return this.set('filteredValue', this.get('parsedNodeValue')); + } + }; + + return RadioBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.MixinBinding = (function(_super) { + + __extends(MixinBinding, _super); + + function MixinBinding() { + return MixinBinding.__super__.constructor.apply(this, arguments); + } + + MixinBinding.prototype.dataChange = function(value) { + if (value != null) { + return Batman.mixin(this.node, value); + } + }; + + return MixinBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.FileBinding = (function(_super) { + + __extends(FileBinding, _super); + + function FileBinding() { + return FileBinding.__super__.constructor.apply(this, arguments); + } + + FileBinding.prototype.isInputBinding = true; + + FileBinding.prototype.nodeChange = function(node, subContext) { + if (!this.isTwoWay()) { + return; + } + if (node.hasAttribute('multiple')) { + return this.set('filteredValue', Array.prototype.slice.call(node.files)); + } else { + return this.set('filteredValue', node.files[0]); + } + }; + + return FileBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.DeferredRenderingBinding = (function(_super) { + + __extends(DeferredRenderingBinding, _super); + + DeferredRenderingBinding.prototype.rendered = false; + + function DeferredRenderingBinding() { + DeferredRenderingBinding.__super__.constructor.apply(this, arguments); + this.node.removeAttribute("data-renderif"); + } + + DeferredRenderingBinding.prototype.nodeChange = function() {}; + + DeferredRenderingBinding.prototype.dataChange = function(value) { + if (value && !this.rendered) { + return this.render(); + } + }; + + DeferredRenderingBinding.prototype.render = function() { + new Batman.Renderer(this.node, this.renderContext, this.renderer.view); + return this.rendered = true; + }; + + return DeferredRenderingBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.Binding = (function(_super) { + + __extends(Binding, _super); + + function Binding(node) { + var _ref; + this.isInputBinding = (_ref = node.nodeName.toLowerCase()) === 'input' || _ref === 'textarea'; + Binding.__super__.constructor.apply(this, arguments); + } + + Binding.prototype.nodeChange = function(node, context) { + if (this.isTwoWay()) { + return this.set('filteredValue', this.node.value); + } + }; + + Binding.prototype.dataChange = function(value, node) { + return Batman.DOM.valueForNode(this.node, value, this.escapeValue); + }; + + return Binding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.DOM.AbstractAttributeBinding = (function(_super) { + + __extends(AbstractAttributeBinding, _super); + + function AbstractAttributeBinding() { + var args, attributeName, node; + node = arguments[0], attributeName = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + this.attributeName = attributeName; + AbstractAttributeBinding.__super__.constructor.apply(this, [node].concat(__slice.call(args))); + } + + return AbstractAttributeBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.FormBinding = (function(_super) { + + __extends(FormBinding, _super); + + FormBinding.current = null; + + FormBinding.prototype.errorClass = 'error'; + + FormBinding.prototype.defaultErrorsListSelector = 'div.errors'; + + FormBinding.accessor('errorsListSelector', function() { + return this.get('node').getAttribute('data-errors-list') || this.defaultErrorsListSelector; + }); + + function FormBinding(node, contextName, keyPath, renderContext, renderer, only) { + this.childBindingAdded = __bind(this.childBindingAdded, this); + FormBinding.__super__.constructor.apply(this, arguments); + this.contextName = contextName; + delete this.attributeName; + Batman.DOM.events.submit(this.get('node'), function(node, e) { + return Batman.preventDefault(e); + }); + this.setupErrorsList(); + } + + FormBinding.prototype.childBindingAdded = function(binding) { + var field, index, node; + if (binding.isInputBinding && Batman.isChildOf(this.get('node'), binding.get('node'))) { + if (~(index = binding.get('key').indexOf(this.contextName))) { + node = binding.get('node'); + field = binding.get('key').slice(index + this.contextName.length + 1); + return new Batman.DOM.AddClassBinding(node, this.errorClass, this.get('keyPath') + (" | get 'errors." + field + ".length'"), this.renderContext, this.renderer); + } + } + }; + + FormBinding.prototype.setupErrorsList = function() { + if (this.errorsListNode = Batman.DOM.querySelector(this.get('node'), this.get('errorsListSelector'))) { + Batman.setInnerHTML(this.errorsListNode, this.errorsListHTML()); + if (!this.errorsListNode.getAttribute('data-showif')) { + return this.errorsListNode.setAttribute('data-showif', "" + this.contextName + ".errors.length"); + } + } + }; + + FormBinding.prototype.errorsListHTML = function() { + return "
      \n
    • \n
    "; + }; + + return FormBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.EventBinding = (function(_super) { + + __extends(EventBinding, _super); + + EventBinding.prototype.bindImmediately = false; + + function EventBinding(node, eventName, key, context) { + var attacher, callback, confirmText, + _this = this; + EventBinding.__super__.constructor.apply(this, arguments); + confirmText = this.node.getAttribute('data-confirm'); + callback = function() { + var _ref; + if (confirmText && !confirm(confirmText)) { + return; + } + return (_ref = _this.get('filteredValue')) != null ? _ref.apply(_this.get('callbackContext'), arguments) : void 0; + }; + if (attacher = Batman.DOM.events[this.attributeName]) { + attacher(this.node, callback, context); + } else { + Batman.DOM.events.other(this.node, this.attributeName, callback, context); + } + this.bind(); + } + + EventBinding.accessor('callbackContext', function() { + var contextKeySegments; + contextKeySegments = this.key.split('.'); + contextKeySegments.pop(); + if (contextKeySegments.length > 0) { + return this.get('keyContext').get(contextKeySegments.join('.')); + } else { + return this.get('keyContext'); + } + }); + + EventBinding.wrapAccessor('unfilteredValue', function(core) { + return { + get: function() { + var functionKey, k, keyContext, keys; + if (k = this.get('key')) { + keys = k.split('.'); + if (keys.length > 1) { + functionKey = keys.pop(); + keyContext = Batman.getPath(this, ['keyContext'].concat(keys)); + if (keyContext != null) { + keyContext = Batman.RenderContext.deProxy(keyContext); + return keyContext[functionKey]; + } + } + } + return core.get.apply(this, arguments); + } + }; + }); + + return EventBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.NodeAttributeBinding = (function(_super) { + + __extends(NodeAttributeBinding, _super); + + function NodeAttributeBinding() { + return NodeAttributeBinding.__super__.constructor.apply(this, arguments); + } + + NodeAttributeBinding.prototype.dataChange = function(value) { + if (value == null) { + value = ""; + } + return this.node[this.attributeName] = value; + }; + + NodeAttributeBinding.prototype.nodeChange = function(node) { + if (this.isTwoWay()) { + return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node[this.attributeName])); + } + }; + + return NodeAttributeBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.CheckedBinding = (function(_super) { + + __extends(CheckedBinding, _super); + + function CheckedBinding() { + return CheckedBinding.__super__.constructor.apply(this, arguments); + } + + CheckedBinding.prototype.isInputBinding = true; + + CheckedBinding.prototype.dataChange = function(value) { + return this.node[this.attributeName] = !!value; + }; + + return CheckedBinding; + + })(Batman.DOM.NodeAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AttributeBinding = (function(_super) { + + __extends(AttributeBinding, _super); + + function AttributeBinding() { + return AttributeBinding.__super__.constructor.apply(this, arguments); + } + + AttributeBinding.prototype.dataChange = function(value) { + return this.node.setAttribute(this.attributeName, value); + }; + + AttributeBinding.prototype.nodeChange = function(node) { + if (this.isTwoWay()) { + return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node.getAttribute(this.attributeName))); + } + }; + + return AttributeBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AddClassBinding = (function(_super) { + + __extends(AddClassBinding, _super); + + function AddClassBinding(node, className, keyPath, renderContext, renderer, only, invert) { + var name, names; + this.invert = invert != null ? invert : false; + names = className.split('|'); + this.classes = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = names.length; _i < _len; _i++) { + name = names[_i]; + _results.push({ + name: name, + pattern: new RegExp("(?:^|\\s)" + name + "(?:$|\\s)", 'i') + }); + } + return _results; + })(); + AddClassBinding.__super__.constructor.apply(this, arguments); + delete this.attributeName; + } + + AddClassBinding.prototype.dataChange = function(value) { + var currentName, includesClassName, name, pattern, _i, _len, _ref, _ref1; + currentName = this.node.className; + _ref = this.classes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + _ref1 = _ref[_i], name = _ref1.name, pattern = _ref1.pattern; + includesClassName = pattern.test(currentName); + if (!!value === !this.invert) { + if (!includesClassName) { + this.node.className = "" + currentName + " " + name; + } + } else { + if (includesClassName) { + this.node.className = currentName.replace(pattern, ' '); + } + } + } + return true; + }; + + return AddClassBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.AbstractCollectionBinding = (function(_super) { + + __extends(AbstractCollectionBinding, _super); + + function AbstractCollectionBinding() { + return AbstractCollectionBinding.__super__.constructor.apply(this, arguments); + } + + AbstractCollectionBinding.prototype.bindCollection = function(newCollection) { + var _ref; + if (newCollection instanceof Batman.Hash) { + newCollection = newCollection.meta; + } + if (newCollection === this.collection) { + return true; + } else { + this.unbindCollection(); + this.collection = newCollection; + if ((_ref = this.collection) != null ? _ref.isObservable : void 0) { + this.collection.observeAndFire('toArray', this.handleArrayChanged); + return true; + } + } + return false; + }; + + AbstractCollectionBinding.prototype.unbindCollection = function() { + var _ref; + if ((_ref = this.collection) != null ? _ref.isObservable : void 0) { + return this.collection.forget('toArray', this.handleArrayChanged); + } + }; + + AbstractCollectionBinding.prototype.handleArrayChanged = function() {}; + + AbstractCollectionBinding.prototype.die = function() { + this.unbindCollection(); + return AbstractCollectionBinding.__super__.die.apply(this, arguments); + }; + + return AbstractCollectionBinding; + + })(Batman.DOM.AbstractAttributeBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.DOM.StyleBinding = (function(_super) { + + __extends(StyleBinding, _super); + + StyleBinding.SingleStyleBinding = (function(_super1) { + + __extends(SingleStyleBinding, _super1); + + SingleStyleBinding.prototype.isTwoWay = function() { + return false; + }; + + function SingleStyleBinding() { + var args, parent, _i; + args = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), parent = arguments[_i++]; + this.parent = parent; + SingleStyleBinding.__super__.constructor.apply(this, args); + } + + SingleStyleBinding.prototype.dataChange = function(value) { + return this.parent.setStyle(this.attributeName, value); + }; + + return SingleStyleBinding; + + })(Batman.DOM.AbstractAttributeBinding); + + function StyleBinding() { + this.setStyle = __bind(this.setStyle, this); + + this.handleArrayChanged = __bind(this.handleArrayChanged, this); + this.oldStyles = {}; + this.styleBindings = {}; + StyleBinding.__super__.constructor.apply(this, arguments); + } + + StyleBinding.prototype.dataChange = function(value) { + var colonSplitCSSValues, cssName, key, style, _i, _len, _ref, _ref1, _results; + if (!value) { + this.resetStyles(); + return; + } + this.unbindCollection(); + if (typeof value === 'string') { + this.resetStyles(); + _ref = value.split(';'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + style = _ref[_i]; + _ref1 = style.split(":"), cssName = _ref1[0], colonSplitCSSValues = 2 <= _ref1.length ? __slice.call(_ref1, 1) : []; + this.setStyle(cssName, colonSplitCSSValues.join(":")); + } + return; + } + if (value instanceof Batman.Hash) { + return this.bindCollection(value); + } else { + if (value instanceof Batman.Object) { + value = value.toJSON(); + } + this.resetStyles(); + _results = []; + for (key in value) { + if (!__hasProp.call(value, key)) continue; + _results.push(this.bindSingleAttribute(key, "" + this.keyPath + "." + key)); + } + return _results; + } + }; + + StyleBinding.prototype.handleArrayChanged = function(array) { + var _this = this; + return this.collection.forEach(function(key, value) { + return _this.bindSingleAttribute(key, "" + _this.keyPath + "." + key); + }); + }; + + StyleBinding.prototype.bindSingleAttribute = function(attr, keyPath) { + return this.styleBindings[attr] = new this.constructor.SingleStyleBinding(this.node, attr, keyPath, this.renderContext, this.renderer, this.only, this); + }; + + StyleBinding.prototype.setStyle = function(key, value) { + key = Batman.helpers.camelize(key.trim(), true); + if (this.oldStyles[key] == null) { + this.oldStyles[key] = this.node.style[key] || ""; + } + if (value != null ? value.trim : void 0) { + value = value.trim(); + } + if (value == null) { + value = ""; + } + return this.node.style[key] = value; + }; + + StyleBinding.prototype.resetStyles = function() { + var cssName, cssValue, _ref, _results; + _ref = this.oldStyles; + _results = []; + for (cssName in _ref) { + if (!__hasProp.call(_ref, cssName)) continue; + cssValue = _ref[cssName]; + _results.push(this.setStyle(cssName, cssValue)); + } + return _results; + }; + + StyleBinding.prototype.resetBindings = function() { + var attribute, binding, _ref; + _ref = this.styleBindings; + for (attribute in _ref) { + binding = _ref[attribute]; + binding._fireDataChange(''); + binding.die(); + } + return this.styleBindings = {}; + }; + + StyleBinding.prototype.unbindCollection = function() { + this.resetBindings(); + return StyleBinding.__super__.unbindCollection.apply(this, arguments); + }; + + return StyleBinding; + + })(Batman.DOM.AbstractCollectionBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.IteratorBinding = (function(_super) { + + __extends(IteratorBinding, _super); + + IteratorBinding.prototype.currentActionNumber = 0; + + IteratorBinding.prototype.queuedActionNumber = 0; + + IteratorBinding.prototype.bindImmediately = false; + + function IteratorBinding(sourceNode, iteratorName, key, context, parentRenderer) { + var previousSiblingNode, + _this = this; + this.iteratorName = iteratorName; + this.key = key; + this.context = context; + this.parentRenderer = parentRenderer; + this.handleArrayChanged = __bind(this.handleArrayChanged, this); + + this.nodeMap = new Batman.SimpleHash; + this.rendererMap = new Batman.SimpleHash; + this.fragment = document.createDocumentFragment(); + this.prototypeNode = sourceNode.cloneNode(true); + this.prototypeNode.removeAttribute("data-foreach-" + this.iteratorName); + previousSiblingNode = sourceNode.nextSibling; + this.startNode = document.createComment("start " + this.iteratorName + "-" + (this.get('_batmanID'))); + this.endNode = document.createComment("end " + this.iteratorName + "-" + (this.get('_batmanID'))); + this.endNode[Batman.expando] = sourceNode[Batman.expando]; + if (Batman.canDeleteExpando) { + delete sourceNode[Batman.expando]; + } + Batman.insertBefore(sourceNode.parentNode, this.startNode, previousSiblingNode); + Batman.insertBefore(sourceNode.parentNode, this.endNode, previousSiblingNode); + this.parentRenderer.prevent('rendered'); + Batman.DOM.onParseExit(sourceNode.parentNode, function() { + Batman.destroyNode(sourceNode); + _this.bind(); + return _this.parentRenderer.allowAndFire('rendered'); + }); + IteratorBinding.__super__.constructor.call(this, this.endNode, this.iteratorName, this.key, this.context, this.parentRenderer); + } + + IteratorBinding.prototype.parentNode = function() { + return this.endNode.parentNode; + }; + + IteratorBinding.prototype.die = function() { + this.dead = true; + return IteratorBinding.__super__.die.apply(this, arguments); + }; + + IteratorBinding.prototype.dataChange = function(collection) { + var items, _items; + if (collection != null) { + if (!this.bindCollection(collection)) { + items = (collection != null ? collection.forEach : void 0) ? (_items = [], collection.forEach(function(item) { + return _items.push(item); + }), _items) : Object.keys(collection); + return this.handleArrayChanged(items); + } + } else { + return this.handleArrayChanged([]); + } + }; + + IteratorBinding.prototype.handleArrayChanged = function(newItems) { + var existingNode, index, newItem, node, nodeAtIndex, parentNode, startIndex, unseenNodeMap, _i, _len, + _this = this; + parentNode = this.parentNode(); + startIndex = this._getStartNodeIndex() + 1; + unseenNodeMap = this.nodeMap.merge(); + for (index = _i = 0, _len = newItems.length; _i < _len; index = ++_i) { + newItem = newItems[index]; + nodeAtIndex = parentNode.childNodes[startIndex + index]; + if ((nodeAtIndex != null) && this._itemForNode(nodeAtIndex) === newItem) { + unseenNodeMap.unset(newItem); + continue; + } else { + node = (existingNode = this.nodeMap.get(newItem)) ? (unseenNodeMap.unset(newItem), existingNode) : this._newNodeForItem(newItem); + Batman.insertBefore(this.parentNode(), node, nodeAtIndex); + } + } + unseenNodeMap.forEach(function(item, node) { + return _this._removeItem(item); + }); + }; + + IteratorBinding.prototype._itemForNode = function(node) { + return Batman._data(node, "" + this.iteratorName + "Item"); + }; + + IteratorBinding.prototype._newNodeForItem = function(newItem) { + var newNode, renderer, + _this = this; + newNode = this.prototypeNode.cloneNode(true); + Batman._data(newNode, "" + this.iteratorName + "Item", newItem); + this.nodeMap.set(newItem, newNode); + this.parentRenderer.prevent('rendered'); + renderer = new Batman.Renderer(newNode, this.renderContext.descend(newItem, this.iteratorName), this.parentRenderer.view); + renderer.on('rendered', function() { + Batman.propagateBindingEvents(newNode); + _this.fire('nodeAdded', newNode, newItem); + return _this.parentRenderer.allowAndFire('rendered'); + }); + return newNode; + }; + + IteratorBinding.prototype._getStartNodeIndex = function() { + var index, node, _i, _len, _ref; + _ref = this.parentNode().childNodes; + for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { + node = _ref[index]; + if (node === this.startNode) { + return index; + } + } + return 0; + }; + + IteratorBinding.prototype._removeItem = function(item) { + var node; + node = this.nodeMap.unset(item); + Batman.destroyNode(node); + return this.fire('nodeRemoved', node, item); + }; + + return IteratorBinding; + + })(Batman.DOM.AbstractCollectionBinding); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.ClassBinding = (function(_super) { + + __extends(ClassBinding, _super); + + function ClassBinding() { + this.handleArrayChanged = __bind(this.handleArrayChanged, this); + return ClassBinding.__super__.constructor.apply(this, arguments); + } + + ClassBinding.prototype.dataChange = function(value) { + if (value != null) { + this.unbindCollection(); + if (typeof value === 'string') { + return this.node.className = value; + } else { + this.bindCollection(value); + return this.updateFromCollection(); + } + } + }; + + ClassBinding.prototype.updateFromCollection = function() { + var array, k, v; + if (this.collection) { + array = this.collection.map ? this.collection.map(function(x) { + return x; + }) : (function() { + var _ref, _results; + _ref = this.collection; + _results = []; + for (k in _ref) { + if (!__hasProp.call(_ref, k)) continue; + v = _ref[k]; + _results.push(k); + } + return _results; + }).call(this); + if (array.toArray != null) { + array = array.toArray(); + } + return this.node.className = array.join(' '); + } + }; + + ClassBinding.prototype.handleArrayChanged = function() { + return this.updateFromCollection(); + }; + + return ClassBinding; + + })(Batman.DOM.AbstractCollectionBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ValidationError = (function(_super) { + + __extends(ValidationError, _super); + + ValidationError.accessor('fullMessage', function() { + return Batman.t('errors.format', { + attribute: Batman.helpers.humanize(this.attribute), + message: this.message + }); + }); + + function ValidationError(attribute, message) { + ValidationError.__super__.constructor.call(this, { + attribute: attribute, + message: message + }); + } + + return ValidationError; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.StorageAdapter = (function(_super) { + + __extends(StorageAdapter, _super); + + StorageAdapter.StorageError = (function(_super1) { + + __extends(StorageError, _super1); + + StorageError.prototype.name = "StorageError"; + + function StorageError(message) { + StorageError.__super__.constructor.apply(this, arguments); + this.message = message; + } + + return StorageError; + + })(Error); + + StorageAdapter.RecordExistsError = (function(_super1) { + + __extends(RecordExistsError, _super1); + + RecordExistsError.prototype.name = 'RecordExistsError'; + + function RecordExistsError(message) { + RecordExistsError.__super__.constructor.call(this, message || "Can't create this record because it already exists in the store!"); + } + + return RecordExistsError; + + })(StorageAdapter.StorageError); + + StorageAdapter.NotFoundError = (function(_super1) { + + __extends(NotFoundError, _super1); + + NotFoundError.prototype.name = 'NotFoundError'; + + function NotFoundError(message) { + NotFoundError.__super__.constructor.call(this, message || "Record couldn't be found in storage!"); + } + + return NotFoundError; + + })(StorageAdapter.StorageError); + + function StorageAdapter(model) { + var constructor; + StorageAdapter.__super__.constructor.call(this, { + model: model + }); + constructor = this.constructor; + if (constructor.ModelMixin) { + Batman.extend(model, constructor.ModelMixin); + } + if (constructor.RecordMixin) { + Batman.extend(model.prototype, constructor.RecordMixin); + } + } + + StorageAdapter.prototype.isStorageAdapter = true; + + StorageAdapter.prototype.storageKey = function(record) { + var model; + model = (record != null ? record.constructor : void 0) || this.model; + return model.get('storageKey') || Batman.helpers.pluralize(Batman.helpers.underscore(model.get('resourceName'))); + }; + + StorageAdapter.prototype.getRecordFromData = function(attributes, constructor) { + var record; + if (constructor == null) { + constructor = this.model; + } + record = new constructor(); + record._withoutDirtyTracking(function() { + return this.fromJSON(attributes); + }); + return record; + }; + + StorageAdapter.skipIfError = function(f) { + return function(env, next) { + if (env.error != null) { + return next(); + } else { + return f.call(this, env, next); + } + }; + }; + + StorageAdapter.prototype.before = function() { + return this._addFilter.apply(this, ['before'].concat(__slice.call(arguments))); + }; + + StorageAdapter.prototype.after = function() { + return this._addFilter.apply(this, ['after'].concat(__slice.call(arguments))); + }; + + StorageAdapter.prototype._inheritFilters = function() { + var filtersByKey, filtersList, key, oldFilters, position, _results; + if (!this._batman.check(this) || !this._batman.filters) { + oldFilters = this._batman.getFirst('filters'); + this._batman.filters = { + before: {}, + after: {} + }; + if (oldFilters != null) { + _results = []; + for (position in oldFilters) { + filtersByKey = oldFilters[position]; + _results.push((function() { + var _results1; + _results1 = []; + for (key in filtersByKey) { + filtersList = filtersByKey[key]; + _results1.push(this._batman.filters[position][key] = filtersList.slice(0)); + } + return _results1; + }).call(this)); + } + return _results; + } + } + }; + + StorageAdapter.prototype._addFilter = function() { + var filter, key, keys, position, _base, _i, _j, _len; + position = arguments[0], keys = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), filter = arguments[_i++]; + this._inheritFilters(); + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + (_base = this._batman.filters[position])[key] || (_base[key] = []); + this._batman.filters[position][key].push(filter); + } + return true; + }; + + StorageAdapter.prototype.runFilter = function(position, action, env, callback) { + var actionFilters, allFilters, filters, next, + _this = this; + this._inheritFilters(); + allFilters = this._batman.filters[position].all || []; + actionFilters = this._batman.filters[position][action] || []; + env.action = action; + filters = position === 'before' ? actionFilters.concat(allFilters) : allFilters.concat(actionFilters); + next = function(newEnv) { + var nextFilter; + if (newEnv != null) { + env = newEnv; + } + if ((nextFilter = filters.shift()) != null) { + return nextFilter.call(_this, env, next); + } else { + return callback.call(_this, env); + } + }; + return next(); + }; + + StorageAdapter.prototype.runBeforeFilter = function() { + return this.runFilter.apply(this, ['before'].concat(__slice.call(arguments))); + }; + + StorageAdapter.prototype.runAfterFilter = function(action, env, callback) { + return this.runFilter('after', action, env, this.exportResult(callback)); + }; + + StorageAdapter.prototype.exportResult = function(callback) { + return function(env) { + return callback(env.error, env.result, env); + }; + }; + + StorageAdapter.prototype._jsonToAttributes = function(json) { + return JSON.parse(json); + }; + + StorageAdapter.prototype.perform = function(key, subject, options, callback) { + var env, next, + _this = this; + options || (options = {}); + env = { + options: options, + subject: subject + }; + next = function(newEnv) { + if (newEnv != null) { + env = newEnv; + } + return _this.runAfterFilter(key, env, callback); + }; + return this.runBeforeFilter(key, env, function(env) { + return this[key](env, next); + }); + }; + + return StorageAdapter; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.RestStorage = (function(_super) { + var key, _fn, _i, _len, _ref, + _this = this; + + __extends(RestStorage, _super); + + RestStorage.JSONContentType = 'application/json'; + + RestStorage.PostBodyContentType = 'application/x-www-form-urlencoded'; + + RestStorage.BaseMixin = { + request: function(action, options, callback) { + if (!callback) { + callback = options; + options = {}; + } + options.method || (options.method = 'GET'); + options.action = action; + return this._doStorageOperation(options.method.toLowerCase(), options, callback); + } + }; + + RestStorage.ModelMixin = Batman.extend({}, RestStorage.BaseMixin, { + urlNestsUnder: function() { + var key, keys, parents, _i, _len; + keys = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + parents = {}; + for (_i = 0, _len = keys.length; _i < _len; _i++) { + key = keys[_i]; + parents[key + '_id'] = Batman.helpers.pluralize(key); + } + this.url = function(options) { + var childSegment, parentID, plural; + childSegment = Batman.helpers.pluralize(this.get('resourceName').toLowerCase()); + for (key in parents) { + plural = parents[key]; + parentID = options.data[key]; + if (parentID) { + delete options.data[key]; + return "" + plural + "/" + parentID + "/" + childSegment; + } + } + return childSegment; + }; + return this.prototype.url = function() { + var childSegment, id, parentID, plural, url; + childSegment = Batman.helpers.pluralize(this.constructor.get('resourceName').toLowerCase()); + for (key in parents) { + plural = parents[key]; + parentID = this.get('dirtyKeys').get(key); + if (parentID === void 0) { + parentID = this.get(key); + } + if (parentID) { + url = "" + plural + "/" + parentID + "/" + childSegment; + break; + } + } + url || (url = childSegment); + if (id = this.get('id')) { + url += '/' + id; + } + return url; + }; + } + }); + + RestStorage.RecordMixin = Batman.extend({}, RestStorage.BaseMixin); + + RestStorage.prototype.defaultRequestOptions = { + type: 'json' + }; + + RestStorage.prototype._implicitActionNames = ['create', 'read', 'update', 'destroy', 'readAll']; + + RestStorage.prototype.serializeAsForm = true; + + function RestStorage() { + RestStorage.__super__.constructor.apply(this, arguments); + this.defaultRequestOptions = Batman.extend({}, this.defaultRequestOptions); + } + + RestStorage.prototype.recordJsonNamespace = function(record) { + return Batman.helpers.singularize(this.storageKey(record)); + }; + + RestStorage.prototype.collectionJsonNamespace = function(constructor) { + return Batman.helpers.pluralize(this.storageKey(constructor.prototype)); + }; + + RestStorage.prototype._execWithOptions = function(object, key, options) { + if (typeof object[key] === 'function') { + return object[key](options); + } else { + return object[key]; + } + }; + + RestStorage.prototype._defaultCollectionUrl = function(model) { + return "/" + (this.storageKey(model.prototype)); + }; + + RestStorage.prototype._addParams = function(url, options) { + var _ref; + if (options && options.action && !(_ref = options.action, __indexOf.call(this._implicitActionNames, _ref) >= 0)) { + url += '/' + options.action.toLowerCase(); + } + return url; + }; + + RestStorage.prototype.urlForRecord = function(record, env) { + var id, url; + if (record.url) { + url = this._execWithOptions(record, 'url', env.options); + } else { + url = record.constructor.url ? this._execWithOptions(record.constructor, 'url', env.options) : this._defaultCollectionUrl(record.constructor); + if (env.action !== 'create') { + if ((id = record.get('id')) != null) { + url = url + "/" + id; + } else { + throw new this.constructor.StorageError("Couldn't get/set record primary key on " + env.action + "!"); + } + } + } + url = this._addParams(url, env.options); + return this.urlPrefix(record, env) + url + this.urlSuffix(record, env); + }; + + RestStorage.prototype.urlForCollection = function(model, env) { + var url; + url = model.url ? this._execWithOptions(model, 'url', env.options) : this._defaultCollectionUrl(model, env.options); + url = this._addParams(url, env.options); + return this.urlPrefix(model, env) + url + this.urlSuffix(model, env); + }; + + RestStorage.prototype.urlPrefix = function(object, env) { + return this._execWithOptions(object, 'urlPrefix', env.options) || ''; + }; + + RestStorage.prototype.urlSuffix = function(object, env) { + return this._execWithOptions(object, 'urlSuffix', env.options) || ''; + }; + + RestStorage.prototype.request = function(env, next) { + var options; + options = Batman.extend(env.options, { + autosend: false, + success: function(data) { + return env.data = data; + }, + error: function(error) { + return env.error = error; + }, + loaded: function() { + env.response = env.request.get('response'); + return next(); + } + }); + env.request = new Batman.Request(options); + return env.request.send(); + }; + + RestStorage.prototype.perform = function(key, record, options, callback) { + options || (options = {}); + Batman.extend(options, this.defaultRequestOptions); + return RestStorage.__super__.perform.call(this, key, record, options, callback); + }; + + RestStorage.prototype.before('all', RestStorage.skipIfError(function(env, next) { + if (!env.options.url) { + try { + env.options.url = env.subject.prototype ? this.urlForCollection(env.subject, env) : this.urlForRecord(env.subject, env); + } catch (error) { + env.error = error; + } + } + return next(); + })); + + RestStorage.prototype.before('get', 'put', 'post', 'delete', RestStorage.skipIfError(function(env, next) { + env.options.method = env.action.toUpperCase(); + return next(); + })); + + RestStorage.prototype.before('create', 'update', RestStorage.skipIfError(function(env, next) { + var data, json, namespace; + json = env.subject.toJSON(); + if (namespace = this.recordJsonNamespace(env.subject)) { + data = {}; + data[namespace] = json; + } else { + data = json; + } + env.options.data = data; + return next(); + })); + + RestStorage.prototype.before('create', 'update', 'put', 'post', RestStorage.skipIfError(function(env, next) { + if (this.serializeAsForm) { + env.options.contentType = this.constructor.PostBodyContentType; + } else { + if (env.options.data != null) { + env.options.data = JSON.stringify(env.options.data); + env.options.contentType = this.constructor.JSONContentType; + } + } + return next(); + })); + + RestStorage.prototype.after('all', RestStorage.skipIfError(function(env, next) { + var json; + if (!(env.data != null)) { + return next(); + } + if (typeof env.data === 'string') { + if (env.data.length > 0) { + try { + json = this._jsonToAttributes(env.data); + } catch (error) { + env.error = error; + return next(); + } + } + } else if (typeof env.data === 'object') { + json = env.data; + } + if (json != null) { + env.json = json; + } + return next(); + })); + + RestStorage.prototype.extractFromNamespace = function(data, namespace) { + if (namespace && (data[namespace] != null)) { + return data[namespace]; + } else { + return data; + } + }; + + RestStorage.prototype.after('create', 'read', 'update', RestStorage.skipIfError(function(env, next) { + var json; + if (env.json != null) { + json = this.extractFromNamespace(env.json, this.recordJsonNamespace(env.subject)); + env.subject._withoutDirtyTracking(function() { + return this.fromJSON(json); + }); + } + env.result = env.subject; + return next(); + })); + + RestStorage.prototype.after('readAll', RestStorage.skipIfError(function(env, next) { + var jsonRecordAttributes, namespace; + namespace = this.collectionJsonNamespace(env.subject); + env.recordsAttributes = this.extractFromNamespace(env.json, namespace); + if (Batman.typeOf(env.recordsAttributes) !== 'Array') { + namespace = this.recordJsonNamespace(env.subject.prototype); + env.recordsAttributes = [this.extractFromNamespace(env.json, namespace)]; + } + env.result = env.records = (function() { + var _i, _len, _ref, _results; + _ref = env.recordsAttributes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + jsonRecordAttributes = _ref[_i]; + _results.push(this.getRecordFromData(jsonRecordAttributes, env.subject)); + } + return _results; + }).call(this); + return next(); + })); + + RestStorage.prototype.after('get', 'put', 'post', 'delete', RestStorage.skipIfError(function(env, next) { + var json, namespace; + if (env.json != null) { + json = env.json; + namespace = env.subject.prototype ? this.collectionJsonNamespace(env.subject) : this.recordJsonNamespace(env.subject); + env.result = namespace && (env.json[namespace] != null) ? env.json[namespace] : env.json; + } + return next(); + })); + + RestStorage.HTTPMethods = { + create: 'POST', + update: 'PUT', + read: 'GET', + readAll: 'GET', + destroy: 'DELETE' + }; + + _ref = ['create', 'read', 'update', 'destroy', 'readAll', 'get', 'post', 'put', 'delete']; + _fn = function(key) { + return RestStorage.prototype[key] = RestStorage.skipIfError(function(env, next) { + var _base; + (_base = env.options).method || (_base.method = this.constructor.HTTPMethods[key]); + return this.request(env, next); + }); + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _fn(key); + } + + return RestStorage; + + }).call(this, Batman.StorageAdapter); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.LocalStorage = (function(_super) { + + __extends(LocalStorage, _super); + + function LocalStorage() { + if (typeof window.localStorage === 'undefined') { + return null; + } + LocalStorage.__super__.constructor.apply(this, arguments); + this.storage = localStorage; + } + + LocalStorage.prototype.storageRegExpForRecord = function(record) { + return new RegExp("^" + (this.storageKey(record)) + "(\\d+)$"); + }; + + LocalStorage.prototype.nextIdForRecord = function(record) { + var nextId, re; + re = this.storageRegExpForRecord(record); + nextId = 1; + this._forAllStorageEntries(function(k, v) { + var matches; + if (matches = re.exec(k)) { + return nextId = Math.max(nextId, parseInt(matches[1], 10) + 1); + } + }); + return nextId; + }; + + LocalStorage.prototype._forAllStorageEntries = function(iterator) { + var i, key, _i, _ref; + for (i = _i = 0, _ref = this.storage.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { + key = this.storage.key(i); + iterator.call(this, key, this.storage.getItem(key)); + } + return true; + }; + + LocalStorage.prototype._storageEntriesMatching = function(constructor, options) { + var re, records; + re = this.storageRegExpForRecord(constructor.prototype); + records = []; + this._forAllStorageEntries(function(storageKey, storageString) { + var data, keyMatches; + if (keyMatches = re.exec(storageKey)) { + data = this._jsonToAttributes(storageString); + data[constructor.primaryKey] = keyMatches[1]; + if (this._dataMatches(options, data)) { + return records.push(data); + } + } + }); + return records; + }; + + LocalStorage.prototype._dataMatches = function(conditions, data) { + var k, match, v; + match = true; + for (k in conditions) { + v = conditions[k]; + if (data[k] !== v) { + match = false; + break; + } + } + return match; + }; + + LocalStorage.prototype.before('read', 'create', 'update', 'destroy', LocalStorage.skipIfError(function(env, next) { + var _this = this; + if (env.action === 'create') { + env.id = env.subject.get('id') || env.subject._withoutDirtyTracking(function() { + return env.subject.set('id', _this.nextIdForRecord(env.subject)); + }); + } else { + env.id = env.subject.get('id'); + } + if (env.id == null) { + env.error = new this.constructor.StorageError("Couldn't get/set record primary key on " + env.action + "!"); + } else { + env.key = this.storageKey(env.subject) + env.id; + } + return next(); + })); + + LocalStorage.prototype.before('create', 'update', LocalStorage.skipIfError(function(env, next) { + env.recordAttributes = JSON.stringify(env.subject); + return next(); + })); + + LocalStorage.prototype.after('read', LocalStorage.skipIfError(function(env, next) { + if (typeof env.recordAttributes === 'string') { + try { + env.recordAttributes = this._jsonToAttributes(env.recordAttributes); + } catch (error) { + env.error = error; + return next(); + } + } + env.subject._withoutDirtyTracking(function() { + return this.fromJSON(env.recordAttributes); + }); + return next(); + })); + + LocalStorage.prototype.after('read', 'create', 'update', 'destroy', LocalStorage.skipIfError(function(env, next) { + env.result = env.subject; + return next(); + })); + + LocalStorage.prototype.after('readAll', LocalStorage.skipIfError(function(env, next) { + var recordAttributes; + env.result = env.records = (function() { + var _i, _len, _ref, _results; + _ref = env.recordsAttributes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + recordAttributes = _ref[_i]; + _results.push(this.getRecordFromData(recordAttributes, env.subject)); + } + return _results; + }).call(this); + return next(); + })); + + LocalStorage.prototype.read = LocalStorage.skipIfError(function(env, next) { + env.recordAttributes = this.storage.getItem(env.key); + if (!env.recordAttributes) { + env.error = new this.constructor.NotFoundError(); + } + return next(); + }); + + LocalStorage.prototype.create = LocalStorage.skipIfError(function(_arg, next) { + var key, recordAttributes; + key = _arg.key, recordAttributes = _arg.recordAttributes; + if (this.storage.getItem(key)) { + arguments[0].error = new this.constructor.RecordExistsError; + } else { + this.storage.setItem(key, recordAttributes); + } + return next(); + }); + + LocalStorage.prototype.update = LocalStorage.skipIfError(function(_arg, next) { + var key, recordAttributes; + key = _arg.key, recordAttributes = _arg.recordAttributes; + this.storage.setItem(key, recordAttributes); + return next(); + }); + + LocalStorage.prototype.destroy = LocalStorage.skipIfError(function(_arg, next) { + var key; + key = _arg.key; + this.storage.removeItem(key); + return next(); + }); + + LocalStorage.prototype.readAll = LocalStorage.skipIfError(function(env, next) { + try { + arguments[0].recordsAttributes = this._storageEntriesMatching(env.subject, env.options.data); + } catch (error) { + arguments[0].error = error; + } + return next(); + }); + + return LocalStorage; + + })(Batman.StorageAdapter); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.SessionStorage = (function(_super) { + + __extends(SessionStorage, _super); + + function SessionStorage() { + if (typeof window.sessionStorage === 'undefined') { + return null; + } + SessionStorage.__super__.constructor.apply(this, arguments); + this.storage = sessionStorage; + } + + return SessionStorage; + + })(Batman.LocalStorage); + +}).call(this); + +(function() { + + Batman.Encoders = new Batman.Object; + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.AssociationProxy = (function(_super) { + + __extends(AssociationProxy, _super); + + AssociationProxy.prototype.isProxy = true; + + function AssociationProxy(association, model) { + this.association = association; + this.model = model; + } + + AssociationProxy.prototype.loaded = false; + + AssociationProxy.prototype.toJSON = function() { + var target; + target = this.get('target'); + if (target != null) { + return this.get('target').toJSON(); + } + }; + + AssociationProxy.prototype.load = function(callback) { + var _this = this; + this.fetch(function(err, proxiedRecord) { + if (!err) { + _this.set('loaded', true); + _this.set('target', proxiedRecord); + } + return typeof callback === "function" ? callback(err, proxiedRecord) : void 0; + }); + return this.get('target'); + }; + + AssociationProxy.prototype.fetch = function(callback) { + var record; + if ((this.get('foreignValue') || this.get('primaryValue')) == null) { + return callback(void 0, void 0); + } + record = this.fetchFromLocal(); + if (record) { + return callback(void 0, record); + } else { + return this.fetchFromRemote(callback); + } + }; + + AssociationProxy.accessor('loaded', Batman.Property.defaultAccessor); + + AssociationProxy.accessor('target', { + get: function() { + return this.fetchFromLocal(); + }, + set: function(_, v) { + return v; + } + }); + + AssociationProxy.accessor({ + get: function(k) { + var _ref; + return (_ref = this.get('target')) != null ? _ref.get(k) : void 0; + }, + set: function(k, v) { + var _ref; + return (_ref = this.get('target')) != null ? _ref.set(k, v) : void 0; + } + }); + + return AssociationProxy; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HasOneProxy = (function(_super) { + + __extends(HasOneProxy, _super); + + function HasOneProxy() { + return HasOneProxy.__super__.constructor.apply(this, arguments); + } + + HasOneProxy.accessor('primaryValue', function() { + return this.model.get(this.association.primaryKey); + }); + + HasOneProxy.prototype.fetchFromLocal = function() { + return this.association.setIndex().get(this.get('primaryValue')); + }; + + HasOneProxy.prototype.fetchFromRemote = function(callback) { + var loadOptions, + _this = this; + loadOptions = {}; + loadOptions[this.association.foreignKey] = this.get('primaryValue'); + return this.association.getRelatedModel().load(loadOptions, function(error, loadedRecords) { + if (error) { + throw error; + } + if (!loadedRecords || loadedRecords.length <= 0) { + return callback(new Error("Couldn't find related record!"), void 0); + } else { + return callback(void 0, loadedRecords[0]); + } + }); + }; + + return HasOneProxy; + + })(Batman.AssociationProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.BelongsToProxy = (function(_super) { + + __extends(BelongsToProxy, _super); + + function BelongsToProxy() { + return BelongsToProxy.__super__.constructor.apply(this, arguments); + } + + BelongsToProxy.accessor('foreignValue', function() { + return this.model.get(this.association.foreignKey); + }); + + BelongsToProxy.prototype.fetchFromLocal = function() { + return this.association.setIndex().get(this.get('foreignValue')); + }; + + BelongsToProxy.prototype.fetchFromRemote = function(callback) { + var _this = this; + return this.association.getRelatedModel().find(this.get('foreignValue'), function(error, loadedRecord) { + if (error) { + throw error; + } + return callback(void 0, loadedRecord); + }); + }; + + return BelongsToProxy; + + })(Batman.AssociationProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicBelongsToProxy = (function(_super) { + + __extends(PolymorphicBelongsToProxy, _super); + + function PolymorphicBelongsToProxy() { + return PolymorphicBelongsToProxy.__super__.constructor.apply(this, arguments); + } + + PolymorphicBelongsToProxy.accessor('foreignTypeValue', function() { + return this.model.get(this.association.foreignTypeKey); + }); + + PolymorphicBelongsToProxy.prototype.fetchFromLocal = function() { + return this.association.setIndexForType(this.get('foreignTypeValue')).get(this.get('foreignValue')); + }; + + PolymorphicBelongsToProxy.prototype.fetchFromRemote = function(callback) { + var _this = this; + return this.association.getRelatedModelForType(this.get('foreignTypeValue')).find(this.get('foreignValue'), function(error, loadedRecord) { + if (error) { + throw error; + } + return callback(void 0, loadedRecord); + }); + }; + + return PolymorphicBelongsToProxy; + + })(Batman.BelongsToProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.StateMachine = (function(_super) { + + __extends(StateMachine, _super); + + StateMachine.InvalidTransitionError = function(message) { + this.message = message != null ? message : ""; + }; + + StateMachine.InvalidTransitionError.prototype = new Error; + + StateMachine.transitions = function(table) { + var definePredicate, fromState, k, object, predicateKeys, toState, transitions, v, _fn, _ref, + _this = this; + for (k in table) { + v = table[k]; + if (!(v.from && v.to)) { + continue; + } + object = {}; + if (v.from.forEach) { + v.from.forEach(function(fromKey) { + return object[fromKey] = v.to; + }); + } else { + object[v.from] = v.to; + } + table[k] = object; + } + this.prototype.transitionTable = Batman.extend({}, this.prototype.transitionTable, table); + predicateKeys = []; + definePredicate = function(state) { + var key; + key = "is" + (Batman.helpers.capitalize(state)); + if (_this.prototype[key] != null) { + return; + } + predicateKeys.push(key); + return _this.prototype[key] = function() { + return this.get('state') === state; + }; + }; + _ref = this.prototype.transitionTable; + _fn = function(k) { + return _this.prototype[k] = function() { + return this.startTransition(k); + }; + }; + for (k in _ref) { + transitions = _ref[k]; + if (!(!this.prototype[k])) { + continue; + } + _fn(k); + for (fromState in transitions) { + toState = transitions[fromState]; + definePredicate(fromState); + definePredicate(toState); + } + } + if (predicateKeys.length) { + this.accessor.apply(this, __slice.call(predicateKeys).concat([function(key) { + return this[key](); + }])); + } + return this; + }; + + function StateMachine(startState) { + this.nextEvents = []; + this.set('_state', startState); + } + + StateMachine.accessor('state', function() { + return this.get('_state'); + }); + + StateMachine.prototype.isTransitioning = false; + + StateMachine.prototype.transitionTable = {}; + + StateMachine.prototype.onTransition = function(from, into, callback) { + return this.on("" + from + "->" + into, callback); + }; + + StateMachine.prototype.onEnter = function(into, callback) { + return this.on("enter " + into, callback); + }; + + StateMachine.prototype.onExit = function(from, callback) { + return this.on("exit " + from, callback); + }; + + StateMachine.prototype.startTransition = Batman.Property.wrapTrackingPrevention(function(event) { + var nextState, previousState; + if (this.isTransitioning) { + this.nextEvents.push(event); + return; + } + previousState = this.get('state'); + nextState = this.nextStateForEvent(event); + if (!nextState) { + return false; + } + this.isTransitioning = true; + this.fire("exit " + previousState); + this.set('_state', nextState); + this.fire("" + previousState + "->" + nextState); + this.fire("enter " + nextState); + this.fire(event); + this.isTransitioning = false; + if (this.nextEvents.length > 0) { + this.startTransition(this.nextEvents.shift()); + } + return true; + }); + + StateMachine.prototype.canStartTransition = function(event, fromState) { + if (fromState == null) { + fromState = this.get('state'); + } + return !!this.nextStateForEvent(event, fromState); + }; + + StateMachine.prototype.nextStateForEvent = function(event, fromState) { + var _ref; + if (fromState == null) { + fromState = this.get('state'); + } + return (_ref = this.transitionTable[event]) != null ? _ref[fromState] : void 0; + }; + + return StateMachine; + + })(Batman.Object); + + Batman.DelegatingStateMachine = (function(_super) { + + __extends(DelegatingStateMachine, _super); + + function DelegatingStateMachine(startState, base) { + this.base = base; + DelegatingStateMachine.__super__.constructor.call(this, startState); + } + + DelegatingStateMachine.prototype.fire = function() { + var result, _ref; + result = DelegatingStateMachine.__super__.fire.apply(this, arguments); + (_ref = this.base).fire.apply(_ref, arguments); + return result; + }; + + return DelegatingStateMachine; + + })(Batman.StateMachine); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.Model = (function(_super) { + var functionName, _i, _j, _len, _len1, _ref, _ref1; + + __extends(Model, _super); + + Model.primaryKey = 'id'; + + Model.storageKey = null; + + Model.persist = function(mechanism, options) { + Batman.initializeObject(this.prototype); + mechanism = mechanism.isStorageAdapter ? mechanism : new mechanism(this); + if (options) { + Batman.mixin(mechanism, options); + } + this.prototype._batman.storage = mechanism; + return mechanism; + }; + + Model.storageAdapter = function() { + Batman.initializeObject(this.prototype); + return this.prototype._batman.storage; + }; + + Model.encode = function() { + var encoder, encoderForKey, encoderOrLastKey, key, keys, _base, _i, _j, _len; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), encoderOrLastKey = arguments[_i++]; + Batman.initializeObject(this.prototype); + (_base = this.prototype._batman).encoders || (_base.encoders = new Batman.SimpleHash); + encoder = {}; + switch (Batman.typeOf(encoderOrLastKey)) { + case 'String': + keys.push(encoderOrLastKey); + break; + case 'Function': + encoder.encode = encoderOrLastKey; + break; + default: + encoder = encoderOrLastKey; + } + for (_j = 0, _len = keys.length; _j < _len; _j++) { + key = keys[_j]; + encoderForKey = Batman.extend({ + as: key + }, this.defaultEncoder, encoder); + this.prototype._batman.encoders.set(key, encoderForKey); + } + }; + + Model.defaultEncoder = { + encode: function(x) { + return x; + }, + decode: function(x) { + return x; + } + }; + + Model.observeAndFire('primaryKey', function(newPrimaryKey, oldPrimaryKey) { + this.encode(oldPrimaryKey, { + encode: false, + decode: false + }); + return this.encode(newPrimaryKey, { + encode: false, + decode: this.defaultEncoder.decode + }); + }); + + Model.validate = function() { + var keys, match, matches, options, optionsOrFunction, validator, validators, _base, _i, _j, _k, _len, _len1, _ref, _results; + keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), optionsOrFunction = arguments[_i++]; + Batman.initializeObject(this.prototype); + validators = (_base = this.prototype._batman).validators || (_base.validators = []); + if (typeof optionsOrFunction === 'function') { + return validators.push({ + keys: keys, + callback: optionsOrFunction + }); + } else { + options = optionsOrFunction; + _ref = Batman.Validators; + _results = []; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + validator = _ref[_j]; + if ((matches = validator.matches(options))) { + for (_k = 0, _len1 = matches.length; _k < _len1; _k++) { + match = matches[_k]; + delete options[match]; + } + _results.push(validators.push({ + keys: keys, + validator: new validator(matches) + })); + } else { + _results.push(void 0); + } + } + return _results; + } + }; + + Model.LifecycleStateMachine = (function(_super1) { + + __extends(LifecycleStateMachine, _super1); + + function LifecycleStateMachine() { + return LifecycleStateMachine.__super__.constructor.apply(this, arguments); + } + + LifecycleStateMachine.transitions({ + load: { + empty: 'loading', + loaded: 'loading', + loading: 'loading' + }, + loaded: { + loading: 'loaded' + }, + error: { + loading: 'error' + } + }); + + return LifecycleStateMachine; + + })(Batman.DelegatingStateMachine); + + Model.classAccessor('lifecycle', function() { + var _base; + this._batman.check(this); + return (_base = this._batman).lifecycle || (_base.lifecycle = new this.LifecycleStateMachine('empty', this)); + }); + + Model.classAccessor('resourceName', { + get: function() { + if (this.resourceName != null) { + return this.resourceName; + } else { + if (Batman.config.minificationErrors) { + Batman.developer.error("Please define " + (Batman.functionName(this)) + ".resourceName in order for your model to be minification safe."); + } + return Batman.helpers.underscore(Batman.functionName(this)); + } + } + }); + + Model.classAccessor('all', { + get: function() { + this._batman.check(this); + if (this.prototype.hasStorage() && !this._batman.allLoadTriggered) { + this.load(); + this._batman.allLoadTriggered = true; + } + return this.get('loaded'); + }, + set: function(k, v) { + return this.set('loaded', v); + } + }); + + Model.classAccessor('loaded', { + get: function() { + return this._loaded || (this._loaded = new Batman.Set); + }, + set: function(k, v) { + return this._loaded = v; + } + }); + + Model.classAccessor('first', function() { + return this.get('all').toArray()[0]; + }); + + Model.classAccessor('last', function() { + var x; + x = this.get('all').toArray(); + return x[x.length - 1]; + }); + + Model.clear = function() { + var result, _ref; + Batman.initializeObject(this); + result = this.get('loaded').clear(); + if ((_ref = this._batman.get('associations')) != null) { + _ref.reset(); + } + return result; + }; + + Model.find = function(id, callback) { + var record; + Batman.developer.assert(callback, "Must call find with a callback!"); + record = new this(); + record._withoutDirtyTracking(function() { + return this.set('id', id); + }); + record.load(callback); + return record; + }; + + Model.load = function(options, callback) { + var lifecycle, _ref, + _this = this; + if ((_ref = typeof options) === 'function' || _ref === 'undefined') { + callback = options; + options = {}; + } + lifecycle = this.get('lifecycle'); + if (lifecycle.load()) { + return this._doStorageOperation('readAll', { + data: options + }, function(err, records, env) { + var mappedRecords, record; + if (err != null) { + lifecycle.error(); + return typeof callback === "function" ? callback(err, []) : void 0; + } else { + mappedRecords = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = records.length; _i < _len; _i++) { + record = records[_i]; + _results.push(this._mapIdentity(record)); + } + return _results; + }).call(_this); + lifecycle.loaded(); + return typeof callback === "function" ? callback(err, mappedRecords, env) : void 0; + } + }); + } else { + return callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (lifecycle.get('state')))); + } + }; + + Model.create = function(attrs, callback) { + var obj, _ref; + if (!callback) { + _ref = [{}, attrs], attrs = _ref[0], callback = _ref[1]; + } + obj = new this(attrs); + obj.save(callback); + return obj; + }; + + Model.findOrCreate = function(attrs, callback) { + var foundRecord, record; + record = new this(attrs); + if (record.isNew()) { + record.save(callback); + } else { + foundRecord = this._mapIdentity(record); + callback(void 0, foundRecord); + } + return record; + }; + + Model._mapIdentity = function(record) { + var existing, id, _ref; + if (typeof (id = record.get('id')) === 'undefined' || id === '') { + return record; + } else { + existing = (_ref = this.get("loaded.indexedBy.id").get(id)) != null ? _ref.toArray()[0] : void 0; + if (existing) { + existing._withoutDirtyTracking(function() { + var _ref1; + return this.updateAttributes(((_ref1 = record.get('attributes')) != null ? _ref1.toObject() : void 0) || {}); + }); + return existing; + } else { + this.get('loaded').add(record); + return record; + } + } + }; + + Model._doStorageOperation = function(operation, options, callback) { + var adapter; + Batman.developer.assert(this.prototype.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); + adapter = this.prototype._batman.get('storage'); + return adapter.perform(operation, this, options, callback); + }; + + _ref = ['find', 'load', 'create']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + functionName = _ref[_i]; + Model[functionName] = Batman.Property.wrapTrackingPrevention(Model[functionName]); + } + + Model.InstanceLifecycleStateMachine = (function(_super1) { + + __extends(InstanceLifecycleStateMachine, _super1); + + function InstanceLifecycleStateMachine() { + return InstanceLifecycleStateMachine.__super__.constructor.apply(this, arguments); + } + + InstanceLifecycleStateMachine.transitions({ + load: { + from: ['dirty', 'clean'], + to: 'loading' + }, + create: { + from: ['dirty', 'clean'], + to: 'creating' + }, + save: { + from: ['dirty', 'clean'], + to: 'saving' + }, + destroy: { + from: ['dirty', 'clean'], + to: 'destroying' + }, + failedValidation: { + from: ['saving', 'creating'], + to: 'dirty' + }, + loaded: { + loading: 'clean' + }, + created: { + creating: 'clean' + }, + saved: { + saving: 'clean' + }, + destroyed: { + destroying: 'destroyed' + }, + set: { + from: ['dirty', 'clean'], + to: 'dirty' + }, + error: { + from: ['saving', 'creating', 'loading', 'destroying'], + to: 'error' + } + }); + + return InstanceLifecycleStateMachine; + + })(Batman.DelegatingStateMachine); + + function Model(idOrAttributes) { + if (idOrAttributes == null) { + idOrAttributes = {}; + } + this.destroy = __bind(this.destroy, this); + + this.save = __bind(this.save, this); + + this.load = __bind(this.load, this); + + Batman.developer.assert(this instanceof Batman.Object, "constructors must be called with new"); + if (Batman.typeOf(idOrAttributes) === 'Object') { + Model.__super__.constructor.call(this, idOrAttributes); + } else { + Model.__super__.constructor.call(this); + this.set('id', idOrAttributes); + } + } + + Model.accessor('lifecycle', function() { + return this.lifecycle || (this.lifecycle = new Batman.Model.InstanceLifecycleStateMachine('clean', this)); + }); + + Model.accessor('attributes', function() { + return this.attributes || (this.attributes = new Batman.Hash); + }); + + Model.accessor('dirtyKeys', function() { + return this.dirtyKeys || (this.dirtyKeys = new Batman.Hash); + }); + + Model.accessor('_dirtiedKeys', function() { + return this._dirtiedKeys || (this._dirtiedKeys = new Batman.SimpleSet); + }); + + Model.accessor('errors', function() { + return this.errors || (this.errors = new Batman.ErrorsSet); + }); + + Model.accessor('isNew', function() { + return this.isNew(); + }); + + Model.accessor(Model.defaultAccessor = { + get: function(k) { + return Batman.getPath(this, ['attributes', k]); + }, + set: function(k, v) { + if (this._willSet(k)) { + return this.get('attributes').set(k, v); + } else { + return this.get(k); + } + }, + unset: function(k) { + return this.get('attributes').unset(k); + } + }); + + Model.wrapAccessor('id', function(core) { + return { + get: function() { + var primaryKey; + primaryKey = this.constructor.primaryKey; + if (primaryKey === 'id') { + return core.get.apply(this, arguments); + } else { + return this.get(primaryKey); + } + }, + set: function(key, value) { + var parsedValue, primaryKey; + if ((typeof value === "string") && (value.match(/[^0-9]/) === null) && (("" + (parsedValue = parseInt(value, 10))) === value)) { + value = parsedValue; + } + primaryKey = this.constructor.primaryKey; + if (primaryKey === 'id') { + this._willSet(key); + return core.set.apply(this, arguments); + } else { + return this.set(primaryKey, value); + } + } + }; + }); + + Model.prototype.isNew = function() { + return typeof this.get('id') === 'undefined'; + }; + + Model.prototype.updateAttributes = function(attrs) { + this.mixin(attrs); + return this; + }; + + Model.prototype.toString = function() { + return "" + (this.constructor.get('resourceName')) + ": " + (this.get('id')); + }; + + Model.prototype.toParam = function() { + return this.get('id'); + }; + + Model.prototype.toJSON = function() { + var encoders, obj, + _this = this; + obj = {}; + encoders = this._batman.get('encoders'); + if (!(!encoders || encoders.isEmpty())) { + encoders.forEach(function(key, encoder) { + var encodedVal, val; + if (encoder.encode) { + val = _this.get(key); + if (typeof val !== 'undefined') { + encodedVal = encoder.encode(val, key, obj, _this); + if (typeof encodedVal !== 'undefined') { + return obj[encoder.as] = encodedVal; + } + } + } + }); + } + return obj; + }; + + Model.prototype.fromJSON = function(data) { + var encoders, key, obj, value, + _this = this; + obj = {}; + encoders = this._batman.get('encoders'); + if (!encoders || encoders.isEmpty() || !encoders.some(function(key, encoder) { + return encoder.decode != null; + })) { + for (key in data) { + value = data[key]; + obj[key] = value; + } + } else { + encoders.forEach(function(key, encoder) { + if (encoder.decode && typeof data[encoder.as] !== 'undefined') { + return obj[key] = encoder.decode(data[encoder.as], encoder.as, data, obj, _this); + } + }); + } + if (this.constructor.primaryKey !== 'id') { + obj.id = data[this.constructor.primaryKey]; + } + Batman.developer["do"](function() { + if ((!encoders) || encoders.length <= 1) { + return Batman.developer.warn("Warning: Model " + (Batman.functionName(_this.constructor)) + " has suspiciously few decoders!"); + } + }); + return this.mixin(obj); + }; + + Model.prototype.hasStorage = function() { + return this._batman.get('storage') != null; + }; + + Model.prototype.load = function(options, callback) { + var callbackQueue, hasOptions, _ref1, _ref2, + _this = this; + if (!callback) { + _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + } + hasOptions = Object.keys(options).length !== 0; + if ((_ref2 = this.get('lifecycle.state')) === 'destroying' || _ref2 === 'destroyed') { + if (typeof callback === "function") { + callback(new Error("Can't load a destroyed record!")); + } + return; + } + if (this.get('lifecycle').load()) { + callbackQueue = []; + if (callback != null) { + callbackQueue.push(callback); + } + if (!hasOptions) { + this._currentLoad = callbackQueue; + } + return this._doStorageOperation('read', { + data: options + }, function(err, record, env) { + var _j, _len1; + if (!err) { + _this.get('lifecycle').loaded(); + record = _this.constructor._mapIdentity(record); + } else { + _this.get('lifecycle').error(); + } + if (!hasOptions) { + _this._currentLoad = null; + } + for (_j = 0, _len1 = callbackQueue.length; _j < _len1; _j++) { + callback = callbackQueue[_j]; + callback(err, record, env); + } + }); + } else { + if (this.get('lifecycle.state') === 'loading' && !hasOptions) { + if (callback != null) { + return this._currentLoad.push(callback); + } + } else { + return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (this.get('lifecycle.state')))) : void 0; + } + } + }; + + Model.prototype.save = function(options, callback) { + var endState, isNew, startState, storageOperation, _ref1, _ref2, _ref3, + _this = this; + if (!callback) { + _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + } + if ((_ref2 = this.get('lifecycle').get('state')) === 'destroying' || _ref2 === 'destroyed') { + if (typeof callback === "function") { + callback(new Error("Can't save a destroyed record!")); + } + return; + } + isNew = this.isNew(); + _ref3 = isNew ? ['create', 'create', 'created'] : ['save', 'update', 'saved'], startState = _ref3[0], storageOperation = _ref3[1], endState = _ref3[2]; + return this.validate(function(error, errors) { + var associations, creating; + if (error || errors.length) { + _this.get('lifecycle').failedValidation(); + if (typeof callback === "function") { + callback(error || errors, _this); + } + return; + } + creating = _this.isNew(); + if (_this.get('lifecycle').startTransition(startState)) { + associations = _this.constructor._batman.get('associations'); + _this._withoutDirtyTracking(function() { + var _ref4, + _this = this; + return associations != null ? (_ref4 = associations.getByType('belongsTo')) != null ? _ref4.forEach(function(association, label) { + return association.apply(_this); + }) : void 0 : void 0; + }); + return _this._doStorageOperation(storageOperation, { + data: options + }, function(err, record, env) { + if (!err) { + _this.get('dirtyKeys').clear(); + _this.get('_dirtiedKeys').clear(); + if (associations) { + record._withoutDirtyTracking(function() { + var _ref4, _ref5; + if ((_ref4 = associations.getByType('hasOne')) != null) { + _ref4.forEach(function(association, label) { + return association.apply(err, record); + }); + } + return (_ref5 = associations.getByType('hasMany')) != null ? _ref5.forEach(function(association, label) { + return association.apply(err, record); + }) : void 0; + }); + } + record = _this.constructor._mapIdentity(record); + _this.get('lifecycle').startTransition(endState); + } else { + if (err instanceof Batman.ErrorsSet) { + _this.get('lifecycle').failedValidation(); + } else { + _this.get('lifecycle').error(); + } + } + return typeof callback === "function" ? callback(err, record || _this, env) : void 0; + }); + } else { + return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't save while in state " + (_this.get('lifecycle.state')))) : void 0; + } + }); + }; + + Model.prototype.destroy = function(options, callback) { + var _ref1, + _this = this; + if (!callback) { + _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + } + if (this.get('lifecycle').destroy()) { + return this._doStorageOperation('destroy', { + data: options + }, function(err, record, env) { + if (!err) { + _this.constructor.get('loaded').remove(_this); + _this.get('lifecycle').destroyed(); + } else { + _this.get('lifecycle').error(); + } + return typeof callback === "function" ? callback(err, record, env) : void 0; + }); + } else { + return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't destroy while in state " + (this.get('lifecycle.state')))) : void 0; + } + }; + + Model.prototype.validate = function(callback) { + var args, count, errors, finishedValidation, key, validator, validators, _j, _k, _len1, _len2, _ref1; + errors = this.get('errors'); + errors.clear(); + validators = this._batman.get('validators') || []; + if (!validators || validators.length === 0) { + if (typeof callback === "function") { + callback(void 0, errors); + } + return true; + } + count = validators.reduce((function(acc, validator) { + return acc + validator.keys.length; + }), 0); + finishedValidation = function() { + if (--count === 0) { + return typeof callback === "function" ? callback(void 0, errors) : void 0; + } + }; + for (_j = 0, _len1 = validators.length; _j < _len1; _j++) { + validator = validators[_j]; + _ref1 = validator.keys; + for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { + key = _ref1[_k]; + args = [errors, this, key, finishedValidation]; + try { + if (validator.validator) { + validator.validator.validateEach.apply(validator.validator, args); + } else { + validator.callback.apply(validator, args); + } + } catch (e) { + if (typeof callback === "function") { + callback(e, errors); + } + } + } + } + }; + + Model.prototype.associationProxy = function(association) { + var proxies, _base, _name; + Batman.initializeObject(this); + proxies = (_base = this._batman).associationProxies || (_base.associationProxies = {}); + proxies[_name = association.label] || (proxies[_name] = new association.proxyClass(association, this)); + return proxies[association.label]; + }; + + Model.prototype._willSet = function(key) { + if (this._pauseDirtyTracking) { + return true; + } + if (this.get('lifecycle').startTransition('set')) { + if (!this.get('_dirtiedKeys').has(key)) { + this.set("dirtyKeys." + key, this.get(key)); + this.get('_dirtiedKeys').add(key); + } + return true; + } else { + return false; + } + }; + + Model.prototype._doStorageOperation = function(operation, options, callback) { + var adapter, + _this = this; + Batman.developer.assert(this.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); + adapter = this._batman.get('storage'); + return adapter.perform(operation, this, options, function() { + return callback.apply(null, arguments); + }); + }; + + Model.prototype._withoutDirtyTracking = function(block) { + var result; + this._pauseDirtyTracking = true; + result = block.call(this); + this._pauseDirtyTracking = false; + return result; + }; + + _ref1 = ['load', 'save', 'validate', 'destroy']; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + functionName = _ref1[_j]; + Model.prototype[functionName] = Batman.Property.wrapTrackingPrevention(Model.prototype[functionName]); + } + + return Model; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var k, _fn, _i, _len, _ref, + _this = this; + + _ref = Batman.AssociationCurator.availableAssociations; + _fn = function(k) { + return Batman.Model[k] = function(label, scope) { + var collection, _base; + Batman.initializeObject(this); + collection = (_base = this._batman).associations || (_base.associations = new Batman.AssociationCurator(this)); + return collection.add(new Batman["" + (Batman.helpers.capitalize(k)) + "Association"](this, label, scope)); + }; + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + _fn(k); + } + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ParamsReplacer = (function(_super) { + + __extends(ParamsReplacer, _super); + + function ParamsReplacer(navigator, params) { + this.navigator = navigator; + this.params = params; + } + + ParamsReplacer.prototype.redirect = function() { + return this.navigator.replace(this.toObject()); + }; + + ParamsReplacer.prototype.replace = function(params) { + this.params.replace(params); + return this.redirect(); + }; + + ParamsReplacer.prototype.update = function(params) { + this.params.update(params); + return this.redirect(); + }; + + ParamsReplacer.prototype.clear = function() { + this.params.clear(); + return this.redirect(); + }; + + ParamsReplacer.prototype.toObject = function() { + return this.params.toObject(); + }; + + ParamsReplacer.accessor({ + get: function(k) { + return this.params.get(k); + }, + set: function(k, v) { + var oldValue, result; + oldValue = this.params.get(k); + result = this.params.set(k, v); + if (oldValue !== v) { + this.redirect(); + } + return result; + }, + unset: function(k) { + var hadKey, result; + hadKey = this.params.hasKey(k); + result = this.params.unset(k); + if (hadKey) { + this.redirect(); + } + return result; + } + }); + + return ParamsReplacer; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ParamsPusher = (function(_super) { + + __extends(ParamsPusher, _super); + + function ParamsPusher() { + return ParamsPusher.__super__.constructor.apply(this, arguments); + } + + ParamsPusher.prototype.redirect = function() { + return this.navigator.push(this.toObject()); + }; + + return ParamsPusher; + + })(Batman.ParamsReplacer); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.NamedRouteQuery = (function(_super) { + + __extends(NamedRouteQuery, _super); + + NamedRouteQuery.prototype.isNamedRouteQuery = true; + + function NamedRouteQuery(routeMap, args) { + var key; + if (args == null) { + args = []; + } + NamedRouteQuery.__super__.constructor.call(this, { + routeMap: routeMap, + args: args + }); + for (key in this.get('routeMap').childrenByName) { + this[key] = this._queryAccess.bind(this, key); + } + } + + NamedRouteQuery.accessor('route', function() { + var collectionRoute, memberRoute, route, _i, _len, _ref, _ref1; + _ref = this.get('routeMap'), memberRoute = _ref.memberRoute, collectionRoute = _ref.collectionRoute; + _ref1 = [memberRoute, collectionRoute]; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + route = _ref1[_i]; + if (route != null) { + if (route.namedArguments.length === this.get('args').length) { + return route; + } + } + } + return collectionRoute || memberRoute; + }); + + NamedRouteQuery.accessor('path', function() { + return this.path(); + }); + + NamedRouteQuery.accessor('routeMap', 'args', 'cardinality', 'hashValue', Batman.Property.defaultAccessor); + + NamedRouteQuery.accessor({ + get: function(key) { + if (key == null) { + return; + } + if (typeof key === 'string') { + return this.nextQueryForName(key); + } else { + return this.nextQueryWithArgument(key); + } + }, + cache: false + }); + + NamedRouteQuery.accessor('withHash', function() { + var _this = this; + return new Batman.Accessible(function(hashValue) { + return _this.withHash(hashValue); + }); + }); + + NamedRouteQuery.prototype.withHash = function(hashValue) { + var clone; + clone = this.clone(); + clone.set('hashValue', hashValue); + return clone; + }; + + NamedRouteQuery.prototype.nextQueryForName = function(key) { + var map; + if (map = this.get('routeMap').childrenByName[key]) { + return new Batman.NamedRouteQuery(map, this.args); + } else { + return Batman.developer.error("Couldn't find a route for the name " + key + "!"); + } + }; + + NamedRouteQuery.prototype.nextQueryWithArgument = function(arg) { + var args; + args = this.args.slice(0); + args.push(arg); + return this.clone(args); + }; + + NamedRouteQuery.prototype.path = function() { + var argumentName, argumentValue, index, namedArguments, params, _i, _len; + params = {}; + namedArguments = this.get('route.namedArguments'); + for (index = _i = 0, _len = namedArguments.length; _i < _len; index = ++_i) { + argumentName = namedArguments[index]; + if ((argumentValue = this.get('args')[index]) != null) { + params[argumentName] = this._toParam(argumentValue); + } + } + if (this.get('hashValue') != null) { + params['#'] = this.get('hashValue'); + } + return this.get('route').pathFromParams(params); + }; + + NamedRouteQuery.prototype.toString = function() { + return this.path(); + }; + + NamedRouteQuery.prototype.clone = function(args) { + if (args == null) { + args = this.args; + } + return new Batman.NamedRouteQuery(this.routeMap, args); + }; + + NamedRouteQuery.prototype._toParam = function(arg) { + if (arg instanceof Batman.AssociationProxy) { + arg = arg.get('target'); + } + if ((arg != null ? arg.toParam : void 0) != null) { + return arg.toParam(); + } else { + return arg; + } + }; + + NamedRouteQuery.prototype._queryAccess = function(key, arg) { + var query; + query = this.nextQueryForName(key); + if (arg != null) { + query = query.nextQueryWithArgument(arg); + } + return query; + }; + + return NamedRouteQuery; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Dispatcher = (function(_super) { + var ControllerDirectory; + + __extends(Dispatcher, _super); + + Dispatcher.canInferRoute = function(argument) { + return argument instanceof Batman.Model || argument instanceof Batman.AssociationProxy || argument.prototype instanceof Batman.Model; + }; + + Dispatcher.paramsFromArgument = function(argument) { + var resourceNameFromModel; + resourceNameFromModel = function(model) { + return Batman.helpers.camelize(Batman.helpers.pluralize(model.get('resourceName')), true); + }; + if (!this.canInferRoute(argument)) { + return argument; + } + if (argument instanceof Batman.Model || argument instanceof Batman.AssociationProxy) { + if (argument.isProxy) { + argument = argument.get('target'); + } + if (argument != null) { + return { + controller: resourceNameFromModel(argument.constructor), + action: 'show', + id: argument.get('id') + }; + } else { + return {}; + } + } else if (argument.prototype instanceof Batman.Model) { + return { + controller: resourceNameFromModel(argument), + action: 'index' + }; + } else { + return argument; + } + }; + + ControllerDirectory = (function(_super1) { + + __extends(ControllerDirectory, _super1); + + function ControllerDirectory() { + return ControllerDirectory.__super__.constructor.apply(this, arguments); + } + + ControllerDirectory.accessor('__app', Batman.Property.defaultAccessor); + + ControllerDirectory.accessor(function(key) { + return this.get("__app." + (Batman.helpers.capitalize(key)) + "Controller.sharedController"); + }); + + return ControllerDirectory; + + })(Batman.Object); + + Dispatcher.accessor('controllers', function() { + return new ControllerDirectory({ + __app: this.get('app') + }); + }); + + function Dispatcher(app, routeMap) { + Dispatcher.__super__.constructor.call(this, { + app: app, + routeMap: routeMap + }); + } + + Dispatcher.prototype.routeForParams = function(params) { + params = this.constructor.paramsFromArgument(params); + return this.get('routeMap').routeForParams(params); + }; + + Dispatcher.prototype.pathFromParams = function(params) { + var _ref; + if (typeof params === 'string') { + return params; + } + params = this.constructor.paramsFromArgument(params); + return (_ref = this.routeForParams(params)) != null ? _ref.pathFromParams(params) : void 0; + }; + + Dispatcher.prototype.dispatch = function(params) { + var inferredParams, path, route, _ref; + inferredParams = this.constructor.paramsFromArgument(params); + route = this.routeForParams(inferredParams); + if (route) { + _ref = route.pathAndParamsFromArgument(inferredParams), path = _ref[0], params = _ref[1]; + this.set('app.currentRoute', route); + this.set('app.currentURL', path); + this.get('app.currentParams').replace(params || {}); + route.dispatch(params); + } else { + if (Batman.typeOf(params) === 'Object' && !this.constructor.canInferRoute(params)) { + return this.get('app.currentParams').replace(params); + } else { + this.get('app.currentParams').clear(); + } + if (params !== '/404') { + return Batman.redirect('/404'); + } + } + return path; + }; + + return Dispatcher; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Route = (function(_super) { + + __extends(Route, _super); + + Route.regexps = { + namedParam: /:([\w\d]+)/g, + splatParam: /\*([\w\d]+)/g, + queryParam: '(?:\\?.+)?', + namedOrSplat: /[:|\*]([\w\d]+)/g, + namePrefix: '[:|\*]', + escapeRegExp: /[-[\]{}+?.,\\^$|#\s]/g, + openOptParam: /\(/g, + closeOptParam: /\)/g + }; + + Route.prototype.optionKeys = ['member', 'collection']; + + Route.prototype.testKeys = ['controller', 'action']; + + Route.prototype.isRoute = true; + + function Route(templatePath, baseParams) { + var k, matches, namedArguments, pattern, properties, regexp, regexps, _i, _len, _ref; + regexps = this.constructor.regexps; + if (templatePath.indexOf('/') !== 0) { + templatePath = "/" + templatePath; + } + pattern = templatePath.replace(regexps.escapeRegExp, '\\$&'); + regexp = RegExp("^" + (pattern.replace(regexps.openOptParam, '(?:').replace(regexps.closeOptParam, ')?').replace(regexps.namedParam, '([^\/]+)').replace(regexps.splatParam, '(.*?)')) + regexps.queryParam + "$"); + namedArguments = ((function() { + var _results; + _results = []; + while (matches = regexps.namedOrSplat.exec(pattern)) { + _results.push(matches[1]); + } + return _results; + })()); + properties = { + templatePath: templatePath, + pattern: pattern, + regexp: regexp, + namedArguments: namedArguments, + baseParams: baseParams + }; + _ref = this.optionKeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + properties[k] = baseParams[k]; + delete baseParams[k]; + } + Route.__super__.constructor.call(this, properties); + } + + Route.prototype.paramsFromPath = function(pathAndQuery) { + var index, match, matches, name, namedArguments, params, uri, _i, _len; + uri = new Batman.URI(pathAndQuery); + namedArguments = this.get('namedArguments'); + params = Batman.extend({ + path: uri.path + }, this.get('baseParams')); + matches = this.get('regexp').exec(uri.path).slice(1); + for (index = _i = 0, _len = matches.length; _i < _len; index = ++_i) { + match = matches[index]; + name = namedArguments[index]; + params[name] = match; + } + return Batman.extend(params, uri.queryParams); + }; + + Route.prototype.pathFromParams = function(argumentParams) { + var hash, key, name, newPath, params, path, query, regexp, regexps, _i, _j, _len, _len1, _ref, _ref1; + params = Batman.extend({}, argumentParams); + path = this.get('templatePath'); + regexps = this.constructor.regexps; + _ref = this.get('namedArguments'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + name = _ref[_i]; + regexp = RegExp("" + regexps.namePrefix + name); + newPath = path.replace(regexp, (params[name] != null ? params[name] : '')); + if (newPath !== path) { + delete params[name]; + path = newPath; + } + } + path = path.replace(regexps.openOptParam, '').replace(regexps.closeOptParam, '').replace(/([^\/])\/+$/, '$1'); + _ref1 = this.testKeys; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + key = _ref1[_j]; + delete params[key]; + } + if (params['#']) { + hash = params['#']; + delete params['#']; + } + query = Batman.URI.queryFromParams(params); + if (query) { + path += "?" + query; + } + if (hash) { + path += "#" + hash; + } + return path; + }; + + Route.prototype.test = function(pathOrParams) { + var key, path, value, _i, _len, _ref; + if (typeof pathOrParams === 'string') { + path = pathOrParams; + } else if (pathOrParams.path != null) { + path = pathOrParams.path; + } else { + path = this.pathFromParams(pathOrParams); + _ref = this.testKeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + if ((value = this.get(key)) != null) { + if (pathOrParams[key] !== value) { + return false; + } + } + } + } + return this.get('regexp').test(path); + }; + + Route.prototype.pathAndParamsFromArgument = function(pathOrParams) { + var params, path; + if (typeof pathOrParams === 'string') { + params = this.paramsFromPath(pathOrParams); + path = pathOrParams; + } else { + params = pathOrParams; + path = this.pathFromParams(pathOrParams); + } + return [path, params]; + }; + + Route.prototype.dispatch = function(params) { + if (!this.test(params)) { + return false; + } + return this.get('callback')(params); + }; + + Route.prototype.callback = function() { + throw new Batman.DevelopmentError("Override callback in a Route subclass"); + }; + + return Route; + + })(Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ControllerActionRoute = (function(_super) { + + __extends(ControllerActionRoute, _super); + + ControllerActionRoute.prototype.optionKeys = ['member', 'collection', 'app', 'controller', 'action']; + + function ControllerActionRoute(templatePath, options) { + this.callback = __bind(this.callback, this); + + var action, controller, _ref; + if (options.signature) { + _ref = options.signature.split('#'), controller = _ref[0], action = _ref[1]; + action || (action = 'index'); + options.controller = controller; + options.action = action; + delete options.signature; + } + ControllerActionRoute.__super__.constructor.call(this, templatePath, options); + } + + ControllerActionRoute.prototype.callback = function(params) { + var controller; + controller = this.get("app.dispatcher.controllers." + (this.get('controller'))); + return controller.dispatch(this.get('action'), params); + }; + + return ControllerActionRoute; + + })(Batman.Route); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.CallbackActionRoute = (function(_super) { + + __extends(CallbackActionRoute, _super); + + function CallbackActionRoute() { + return CallbackActionRoute.__super__.constructor.apply(this, arguments); + } + + CallbackActionRoute.prototype.optionKeys = ['member', 'collection', 'callback', 'app']; + + CallbackActionRoute.prototype.controller = false; + + CallbackActionRoute.prototype.action = false; + + return CallbackActionRoute; + + })(Batman.Route); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.Hash = (function(_super) { + var k, _fn, _i, _j, _len, _len1, _ref, _ref1, + _this = this; + + __extends(Hash, _super); + + Hash.Metadata = (function(_super1) { + + __extends(Metadata, _super1); + + Batman.extend(Metadata.prototype, Batman.Enumerable); + + function Metadata(hash) { + this.hash = hash; + } + + Metadata.accessor('length', function() { + this.hash.registerAsMutableSource(); + return this.hash.length; + }); + + Metadata.accessor('isEmpty', 'keys', 'toArray', function(key) { + this.hash.registerAsMutableSource(); + return this.hash[key](); + }); + + Metadata.prototype.forEach = function() { + var _ref; + return (_ref = this.hash).forEach.apply(_ref, arguments); + }; + + return Metadata; + + })(Batman.Object); + + function Hash() { + this.meta = new this.constructor.Metadata(this); + Batman.SimpleHash.apply(this, arguments); + Hash.__super__.constructor.apply(this, arguments); + } + + Batman.extend(Hash.prototype, Batman.Enumerable); + + Hash.prototype.propertyClass = Batman.Property; + + Hash.defaultAccessor = { + get: Batman.SimpleHash.prototype.get, + set: Hash.mutation(function(key, value) { + var result; + result = Batman.SimpleHash.prototype.set.call(this, key, value); + this.fire('itemsWereAdded', key); + return result; + }), + unset: Hash.mutation(function(key) { + var result; + result = Batman.SimpleHash.prototype.unset.call(this, key); + if (result != null) { + this.fire('itemsWereRemoved', key); + } + return result; + }), + cache: false + }; + + Hash.accessor(Hash.defaultAccessor); + + Hash.prototype._preventMutationEvents = function(block) { + this.prevent('change'); + this.prevent('itemsWereAdded'); + this.prevent('itemsWereRemoved'); + try { + return block.call(this); + } finally { + this.allow('change'); + this.allow('itemsWereAdded'); + this.allow('itemsWereRemoved'); + } + }; + + Hash.prototype.clear = Hash.mutation(function() { + var keys, result; + keys = this.keys(); + this._preventMutationEvents(function() { + var _this = this; + return this.forEach(function(k) { + return _this.unset(k); + }); + }); + result = Batman.SimpleHash.prototype.clear.call(this); + this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(keys))); + return result; + }); + + Hash.prototype.update = Hash.mutation(function(object) { + var addedKeys; + addedKeys = []; + this._preventMutationEvents(function() { + var _this = this; + return Batman.forEach(object, function(k, v) { + if (!_this.hasKey(k)) { + addedKeys.push(k); + } + return _this.set(k, v); + }); + }); + if (addedKeys.length > 0) { + return this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedKeys))); + } + }); + + Hash.prototype.replace = Hash.mutation(function(object) { + var addedKeys, removedKeys; + addedKeys = []; + removedKeys = []; + this._preventMutationEvents(function() { + var _this = this; + this.forEach(function(k, _) { + if (!Batman.objectHasKey(object, k)) { + _this.unset(k); + return removedKeys.push(k); + } + }); + return Batman.forEach(object, function(k, v) { + if (!_this.hasKey(k)) { + addedKeys.push(k); + } + return _this.set(k, v); + }); + }); + if (addedKeys.length > 0) { + this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedKeys))); + } + if (removedKeys.length > 0) { + return this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(removedKeys))); + } + }); + + _ref = ['equality', 'hashKeyFor', 'objectKey', 'prefixedKey', 'unprefixedKey']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + Hash.prototype[k] = Batman.SimpleHash.prototype[k]; + } + + _ref1 = ['hasKey', 'forEach', 'isEmpty', 'keys', 'toArray', 'merge', 'toJSON', 'toObject']; + _fn = function(k) { + return Hash.prototype[k] = function() { + this.registerAsMutableSource(); + return Batman.SimpleHash.prototype[k].apply(this, arguments); + }; + }; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + k = _ref1[_j]; + _fn(k); + } + + return Hash; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.RenderCache = (function(_super) { + + __extends(RenderCache, _super); + + RenderCache.prototype.maximumLength = 4; + + function RenderCache() { + RenderCache.__super__.constructor.apply(this, arguments); + this.keyQueue = []; + } + + RenderCache.prototype.viewForOptions = function(options) { + var _this = this; + if (options.cache === false || options.viewClass.prototype.cache === false) { + return this._newViewFromOptions(options); + } + return this.getOrSet(options, function() { + return _this._newViewFromOptions(Batman.extend({}, options)); + }); + }; + + RenderCache.prototype._newViewFromOptions = function(options) { + return new options.viewClass(options); + }; + + RenderCache.wrapAccessor(function(core) { + return { + cache: false, + get: function(key) { + var result; + result = core.get.call(this, key); + if (result) { + this._addOrBubbleKey(key); + } + return result; + }, + set: function(key, value) { + var result; + result = core.set.apply(this, arguments); + result.set('cached', true); + this._addOrBubbleKey(key); + this._evictExpiredKeys(); + return result; + }, + unset: function(key) { + var result; + result = core.unset.apply(this, arguments); + result.set('cached', false); + this._removeKeyFromQueue(key); + return result; + } + }; + }); + + RenderCache.prototype.equality = function(incomingOptions, storageOptions) { + var key; + if (Object.keys(incomingOptions).length !== Object.keys(storageOptions).length) { + return false; + } + for (key in incomingOptions) { + if (!(key === 'view')) { + if (incomingOptions[key] !== storageOptions[key]) { + return false; + } + } + } + return true; + }; + + RenderCache.prototype.reset = function() { + var key, _i, _len, _ref, _results; + _ref = this.keyQueue.slice(0); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push(this.unset(key)); + } + return _results; + }; + + RenderCache.prototype._addOrBubbleKey = function(key) { + this._removeKeyFromQueue(key); + return this.keyQueue.unshift(key); + }; + + RenderCache.prototype._removeKeyFromQueue = function(key) { + var index, queuedKey, _i, _len, _ref; + _ref = this.keyQueue; + for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { + queuedKey = _ref[index]; + if (this.equality(queuedKey, key)) { + this.keyQueue.splice(index, 1); + break; + } + } + return key; + }; + + RenderCache.prototype._evictExpiredKeys = function() { + var currentKeys, i, key, _i, _ref, _ref1; + if (this.length > this.maximumLength) { + currentKeys = this.keyQueue.slice(0); + for (i = _i = _ref = this.maximumLength, _ref1 = currentKeys.length; _ref <= _ref1 ? _i < _ref1 : _i > _ref1; i = _ref <= _ref1 ? ++_i : --_i) { + key = currentKeys[i]; + if (!this.get(key).isInDOM()) { + this.unset(key); + } + } + } + }; + + return RenderCache; + + })(Batman.Hash); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + Batman.Controller = (function(_super) { + var _optionsFromFilterArguments; + + __extends(Controller, _super); + + Controller.singleton('sharedController'); + + Controller.wrapAccessor('routingKey', function(core) { + return { + get: function() { + if (this.routingKey != null) { + return this.routingKey; + } else { + if (Batman.config.minificationErrors) { + Batman.developer.error("Please define `routingKey` on the prototype of " + (Batman.functionName(this.constructor)) + " in order for your controller to be minification safe."); + } + return Batman.functionName(this.constructor).replace(/Controller$/, ''); + } + } + }; + }); + + Controller.accessor('_renderContext', function() { + return Batman.RenderContext.root().descend(this); + }); + + _optionsFromFilterArguments = function(options, nameOrFunction) { + if (!nameOrFunction) { + nameOrFunction = options; + options = {}; + } else { + if (typeof options === 'string') { + options = { + only: [options] + }; + } else { + if (options.only && Batman.typeOf(options.only) !== 'Array') { + options.only = [options.only]; + } + if (options.except && Batman.typeOf(options.except) !== 'Array') { + options.except = [options.except]; + } + } + } + options.block = nameOrFunction; + return options; + }; + + Controller.beforeFilter = function() { + var filters, options, _base; + Batman.initializeObject(this); + options = _optionsFromFilterArguments.apply(null, arguments); + filters = (_base = this._batman).beforeFilters || (_base.beforeFilters = new Batman.SimpleHash); + return filters.set(options.block, options); + }; + + Controller.afterFilter = function() { + var filters, options, _base; + Batman.initializeObject(this); + options = _optionsFromFilterArguments.apply(null, arguments); + filters = (_base = this._batman).afterFilters || (_base.afterFilters = new Batman.SimpleHash); + return filters.set(options.block, options); + }; + + Controller.afterFilter(function(params) { + if (this.autoScrollToHash && (params['#'] != null)) { + return this.scrollToHash(params['#']); + } + }); + + function Controller() { + this.redirect = __bind(this.redirect, this); + Controller.__super__.constructor.apply(this, arguments); + this._resetActionFrames(); + } + + Controller.prototype.renderCache = new Batman.RenderCache; + + Controller.prototype.defaultRenderYield = 'main'; + + Controller.prototype.autoScrollToHash = true; + + Controller.prototype.dispatch = function(action, params) { + var redirectTo; + if (params == null) { + params = {}; + } + params.controller || (params.controller = this.get('routingKey')); + params.action || (params.action = action); + params.target || (params.target = this); + this._resetActionFrames(); + this.set('action', action); + this.set('params', params); + Batman.DOM.Yield.cycleAll(); + this.executeAction(action, params); + Batman.DOM.Yield.clearAllStale(); + redirectTo = this._afterFilterRedirect; + delete this._afterFilterRedirect; + if (redirectTo) { + return Batman.redirect(redirectTo); + } + }; + + Controller.prototype.executeAction = function(action, params) { + var frame, oldRedirect, parentFrame, result, _ref, _ref1, + _this = this; + if (params == null) { + params = this.get('params'); + } + Batman.developer.assert(this[action], "Error! Controller action " + (this.get('routingKey')) + "." + action + " couldn't be found!"); + parentFrame = this._actionFrames[this._actionFrames.length - 1]; + frame = new Batman.ControllerActionFrame({ + parentFrame: parentFrame, + action: action + }, function() { + var _ref; + _this._runFilters(action, params, 'afterFilters'); + _this._resetActionFrames(); + return (_ref = Batman.navigator) != null ? _ref.redirect = oldRedirect : void 0; + }); + this._actionFrames.push(frame); + frame.startOperation({ + internal: true + }); + oldRedirect = (_ref = Batman.navigator) != null ? _ref.redirect : void 0; + if ((_ref1 = Batman.navigator) != null) { + _ref1.redirect = this.redirect; + } + this._runFilters(action, params, 'beforeFilters'); + result = this[action](params); + if (!frame.operationOccurred) { + this.render(); + } + frame.finishOperation(); + return result; + }; + + Controller.prototype.redirect = function(url) { + var frame; + frame = this._actionFrames[this._actionFrames.length - 1]; + if (frame) { + if (frame.operationOccurred) { + Batman.developer.warn("Warning! Trying to redirect but an action has already been taken during " + (this.get('routingKey')) + "." + (frame.action || this.get('action'))); + } + frame.startAndFinishOperation(); + if (this._afterFilterRedirect != null) { + return Batman.developer.warn("Warning! Multiple actions trying to redirect!"); + } else { + return this._afterFilterRedirect = url; + } + } else { + if (Batman.typeOf(url) === 'Object') { + if (!url.controller) { + url.controller = this; + } + } + return Batman.redirect(url); + } + }; + + Controller.prototype.render = function(options) { + var action, frame, view, _ref, _ref1, + _this = this; + if (options == null) { + options = {}; + } + if (frame = (_ref = this._actionFrames) != null ? _ref[this._actionFrames.length - 1] : void 0) { + frame.startOperation(); + } + if (options === false) { + frame.finishOperation(); + return; + } + action = (frame != null ? frame.action : void 0) || this.get('action'); + if (options) { + options.into || (options.into = this.defaultRenderYield); + } + if (!options.view) { + options.viewClass || (options.viewClass = this._viewClassForAction(action)); + options.context || (options.context = this.get('_renderContext')); + options.source || (options.source = Batman.helpers.underscore(this.get('routingKey') + '/' + action)); + view = this.renderCache.viewForOptions(options); + } else { + view = options.view; + options.view = null; + } + if (view) { + if ((_ref1 = Batman.currentApp) != null) { + _ref1.prevent('ready'); + } + view.on('ready', function() { + var _ref2; + Batman.DOM.Yield.withName(options.into).replace(view.get('node')); + if ((_ref2 = Batman.currentApp) != null) { + _ref2.allowAndFire('ready'); + } + return frame != null ? frame.finishOperation() : void 0; + }); + } + return view; + }; + + Controller.prototype.scrollToHash = function(hash) { + if (hash == null) { + hash = this.get('params')['#']; + } + return Batman.DOM.scrollIntoView(hash); + }; + + Controller.prototype._resetActionFrames = function() { + return this._actionFrames = []; + }; + + Controller.prototype._viewClassForAction = function(action) { + var classPrefix, _ref; + classPrefix = this.get('routingKey').replace('/', '_'); + return ((_ref = Batman.currentApp) != null ? _ref[Batman.helpers.camelize("" + classPrefix + "_" + action + "_view")] : void 0) || Batman.View; + }; + + Controller.prototype._runFilters = function(action, params, filters) { + var _ref, + _this = this; + if (filters = (_ref = this.constructor._batman) != null ? _ref.get(filters) : void 0) { + return filters.forEach(function(_, options) { + var block; + if (options.only && __indexOf.call(options.only, action) < 0) { + return; + } + if (options.except && __indexOf.call(options.except, action) >= 0) { + return; + } + block = options.block; + if (typeof block === 'function') { + return block.call(_this, params); + } else { + return typeof _this[block] === "function" ? _this[block](params) : void 0; + } + }); + } + }; + + return Controller; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Set = (function(_super) { + var k, _fn, _i, _j, _len, _len1, _ref, _ref1, + _this = this; + + __extends(Set, _super); + + function Set() { + Batman.SimpleSet.apply(this, arguments); + } + + Batman.extend(Set.prototype, Batman.Enumerable); + + Set._applySetAccessors = function(klass) { + var accessor, accessors, key, _results; + accessors = { + first: function() { + return this.toArray()[0]; + }, + last: function() { + return this.toArray()[this.length - 1]; + }, + isEmpty: function() { + return this.isEmpty(); + }, + toArray: function() { + return this.toArray(); + }, + length: function() { + this.registerAsMutableSource(); + return this.length; + }, + indexedBy: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.indexedBy(key); + }); + }, + indexedByUnique: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.indexedByUnique(key); + }); + }, + sortedBy: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.sortedBy(key); + }); + }, + sortedByDescending: function() { + var _this = this; + return new Batman.TerminalAccessible(function(key) { + return _this.sortedBy(key, 'desc'); + }); + } + }; + _results = []; + for (key in accessors) { + accessor = accessors[key]; + _results.push(klass.accessor(key, accessor)); + } + return _results; + }; + + Set._applySetAccessors(Set); + + _ref = ['add', 'remove', 'clear', 'replace', 'indexedBy', 'indexedByUnique', 'sortedBy', 'equality', '_indexOfItem']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + Set.prototype[k] = Batman.SimpleSet.prototype[k]; + } + + _ref1 = ['find', 'merge', 'forEach', 'toArray', 'isEmpty', 'has']; + _fn = function(k) { + return Set.prototype[k] = function() { + this.registerAsMutableSource(); + return Batman.SimpleSet.prototype[k].apply(this, arguments); + }; + }; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + k = _ref1[_j]; + _fn(k); + } + + Set.prototype.toJSON = Set.prototype.toArray; + + return Set; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ErrorsSet = (function(_super) { + + __extends(ErrorsSet, _super); + + function ErrorsSet() { + return ErrorsSet.__super__.constructor.apply(this, arguments); + } + + ErrorsSet.accessor(function(key) { + return this.indexedBy('attribute').get(key); + }); + + ErrorsSet.prototype.add = function(key, error) { + return ErrorsSet.__super__.add.call(this, new Batman.ValidationError(key, error)); + }; + + return ErrorsSet; + + })(Batman.Set); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetProxy = (function(_super) { + var k, _fn, _i, _len, _ref, + _this = this; + + __extends(SetProxy, _super); + + function SetProxy(base) { + var _this = this; + this.base = base; + SetProxy.__super__.constructor.call(this); + this.length = this.base.length; + this.base.on('itemsWereAdded', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _this.set('length', _this.base.length); + return _this.fire.apply(_this, ['itemsWereAdded'].concat(__slice.call(items))); + }); + this.base.on('itemsWereRemoved', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _this.set('length', _this.base.length); + return _this.fire.apply(_this, ['itemsWereRemoved'].concat(__slice.call(items))); + }); + } + + Batman.extend(SetProxy.prototype, Batman.Enumerable); + + SetProxy.prototype.filter = function(f) { + var r; + r = new Batman.Set(); + return this.reduce((function(r, e) { + if (f(e)) { + r.add(e); + } + return r; + }), r); + }; + + SetProxy.prototype.replace = function() { + var length, result; + length = this.property('length'); + length.isolate(); + result = this.base.replace.apply(this, arguments); + length.expose(); + return result; + }; + + _ref = ['add', 'remove', 'find', 'clear', 'has', 'merge', 'toArray', 'isEmpty', 'indexedBy', 'indexedByUnique', 'sortedBy']; + _fn = function(k) { + return SetProxy.prototype[k] = function() { + var _ref1; + return (_ref1 = this.base)[k].apply(_ref1, arguments); + }; + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + _fn(k); + } + + Batman.Set._applySetAccessors(SetProxy); + + SetProxy.accessor('length', { + get: function() { + this.registerAsMutableSource(); + return this.length; + }, + set: function(_, v) { + return this.length = v; + } + }); + + return SetProxy; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.BinarySetOperation = (function(_super) { + + __extends(BinarySetOperation, _super); + + function BinarySetOperation(left, right) { + this.left = left; + this.right = right; + this._setup = __bind(this._setup, this); + + BinarySetOperation.__super__.constructor.call(this); + this._setup(this.left, this.right); + this._setup(this.right, this.left); + } + + BinarySetOperation.prototype._setup = function(set, opposite) { + var _this = this; + set.on('itemsWereAdded', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return _this._itemsWereAddedToSource.apply(_this, [set, opposite].concat(__slice.call(items))); + }); + set.on('itemsWereRemoved', function() { + var items; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return _this._itemsWereRemovedFromSource.apply(_this, [set, opposite].concat(__slice.call(items))); + }); + return this._itemsWereAddedToSource.apply(this, [set, opposite].concat(__slice.call(set.toArray()))); + }; + + BinarySetOperation.prototype.merge = function() { + var merged, others, set, _i, _len; + others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + merged = new Batman.Set; + others.unshift(this); + for (_i = 0, _len = others.length; _i < _len; _i++) { + set = others[_i]; + set.forEach(function(v) { + return merged.add(v); + }); + } + return merged; + }; + + BinarySetOperation.prototype.filter = Batman.SetProxy.prototype.filter; + + return BinarySetOperation; + + })(Batman.Set); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetUnion = (function(_super) { + + __extends(SetUnion, _super); + + function SetUnion() { + return SetUnion.__super__.constructor.apply(this, arguments); + } + + SetUnion.prototype._itemsWereAddedToSource = function() { + var items, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + return this.add.apply(this, items); + }; + + SetUnion.prototype._itemsWereRemovedFromSource = function() { + var item, items, itemsToRemove, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + itemsToRemove = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.remove.apply(this, itemsToRemove); + }; + + return SetUnion; + + })(Batman.BinarySetOperation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetIntersection = (function(_super) { + + __extends(SetIntersection, _super); + + function SetIntersection() { + return SetIntersection.__super__.constructor.apply(this, arguments); + } + + SetIntersection.prototype._itemsWereAddedToSource = function() { + var item, items, itemsToAdd, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.add.apply(this, itemsToAdd); + }; + + SetIntersection.prototype._itemsWereRemovedFromSource = function() { + var items, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + return this.remove.apply(this, items); + }; + + return SetIntersection; + + })(Batman.BinarySetOperation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetComplement = (function(_super) { + + __extends(SetComplement, _super); + + function SetComplement() { + return SetComplement.__super__.constructor.apply(this, arguments); + } + + SetComplement.prototype._itemsWereAddedToSource = function() { + var item, items, itemsToAdd, itemsToRemove, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + if (source === this.left) { + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (!opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.add.apply(this, itemsToAdd); + } else { + itemsToRemove = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.remove.apply(this, itemsToRemove); + } + }; + + SetComplement.prototype._itemsWereRemovedFromSource = function() { + var item, items, itemsToAdd, opposite, source; + source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; + if (source === this.left) { + return this.remove.apply(this, items); + } else { + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })(); + return this.add.apply(this, itemsToAdd); + } + }; + + SetComplement.prototype._addComplement = function(items, opposite) { + var item; + return this.add.apply(this, (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + if (opposite.has(item)) { + _results.push(item); + } + } + return _results; + })()); + }; + + return SetComplement; + + })(Batman.BinarySetOperation); + +}).call(this); + +(function() { + + Batman.mixins = new Batman.Object; + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Accessible = (function(_super) { + + __extends(Accessible, _super); + + function Accessible() { + this.accessor.apply(this, arguments); + } + + return Accessible; + + })(Batman.Object); + + Batman.TerminalAccessible = (function(_super) { + + __extends(TerminalAccessible, _super); + + function TerminalAccessible() { + return TerminalAccessible.__super__.constructor.apply(this, arguments); + } + + TerminalAccessible.prototype.propertyClass = Batman.Property; + + return TerminalAccessible; + + })(Batman.Accessible); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetObserver = (function(_super) { + + __extends(SetObserver, _super); + + function SetObserver(base) { + var _this = this; + this.base = base; + this._itemObservers = new Batman.SimpleHash; + this._setObservers = new Batman.SimpleHash; + this._setObservers.set("itemsWereAdded", function() { + return _this.fire.apply(_this, ['itemsWereAdded'].concat(__slice.call(arguments))); + }); + this._setObservers.set("itemsWereRemoved", function() { + return _this.fire.apply(_this, ['itemsWereRemoved'].concat(__slice.call(arguments))); + }); + this.on('itemsWereAdded', this.startObservingItems.bind(this)); + this.on('itemsWereRemoved', this.stopObservingItems.bind(this)); + } + + SetObserver.prototype.observedItemKeys = []; + + SetObserver.prototype.observerForItemAndKey = function(item, key) {}; + + SetObserver.prototype._getOrSetObserverForItemAndKey = function(item, key) { + var _this = this; + return this._itemObservers.getOrSet(item, function() { + var observersByKey; + observersByKey = new Batman.SimpleHash; + return observersByKey.getOrSet(key, function() { + return _this.observerForItemAndKey(item, key); + }); + }); + }; + + SetObserver.prototype.startObserving = function() { + this._manageItemObservers("observe"); + return this._manageSetObservers("addHandler"); + }; + + SetObserver.prototype.stopObserving = function() { + this._manageItemObservers("forget"); + return this._manageSetObservers("removeHandler"); + }; + + SetObserver.prototype.startObservingItems = function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(this._manageObserversForItem(item, "observe")); + } + return _results; + }; + + SetObserver.prototype.stopObservingItems = function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(this._manageObserversForItem(item, "forget")); + } + return _results; + }; + + SetObserver.prototype._manageObserversForItem = function(item, method) { + var key, _i, _len, _ref; + if (!item.isObservable) { + return; + } + _ref = this.observedItemKeys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + item[method](key, this._getOrSetObserverForItemAndKey(item, key)); + } + if (method === "forget") { + return this._itemObservers.unset(item); + } + }; + + SetObserver.prototype._manageItemObservers = function(method) { + var _this = this; + return this.base.forEach(function(item) { + return _this._manageObserversForItem(item, method); + }); + }; + + SetObserver.prototype._manageSetObservers = function(method) { + var _this = this; + if (!this.base.isObservable) { + return; + } + return this._setObservers.forEach(function(key, observer) { + return _this.base.event(key)[method](observer); + }); + }; + + return SetObserver; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.SetSort = (function(_super) { + + __extends(SetSort, _super); + + function SetSort(base, key, order) { + var boundReIndex; + this.key = key; + if (order == null) { + order = "asc"; + } + SetSort.__super__.constructor.call(this, base); + this.descending = order.toLowerCase() === "desc"; + if (this.base.isObservable) { + this._setObserver = new Batman.SetObserver(this.base); + this._setObserver.observedItemKeys = [this.key]; + boundReIndex = this._reIndex.bind(this); + this._setObserver.observerForItemAndKey = function() { + return boundReIndex; + }; + this._setObserver.on('itemsWereAdded', boundReIndex); + this._setObserver.on('itemsWereRemoved', boundReIndex); + this.startObserving(); + } + this._reIndex(); + } + + SetSort.prototype.startObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.startObserving() : void 0; + }; + + SetSort.prototype.stopObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.stopObserving() : void 0; + }; + + SetSort.prototype.toArray = function() { + return this.get('_storage'); + }; + + SetSort.prototype.forEach = function(iterator, ctx) { + var e, i, _i, _len, _ref, _results; + _ref = this.get('_storage'); + _results = []; + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { + e = _ref[i]; + _results.push(iterator.call(ctx, e, i, this)); + } + return _results; + }; + + SetSort.prototype.compare = function(a, b) { + if (a === b) { + return 0; + } + if (a === void 0) { + return 1; + } + if (b === void 0) { + return -1; + } + if (a === null) { + return 1; + } + if (b === null) { + return -1; + } + if (a === false) { + return 1; + } + if (b === false) { + return -1; + } + if (a === true) { + return 1; + } + if (b === true) { + return -1; + } + if (a !== a) { + if (b !== b) { + return 0; + } else { + return 1; + } + } + if (b !== b) { + return -1; + } + if (a > b) { + return 1; + } + if (a < b) { + return -1; + } + return 0; + }; + + SetSort.prototype._reIndex = function() { + var newOrder, _ref, + _this = this; + newOrder = this.base.toArray().sort(function(a, b) { + var multiple, valueA, valueB; + valueA = Batman.get(a, _this.key); + if (typeof valueA === 'function') { + valueA = valueA.call(a); + } + if (valueA != null) { + valueA = valueA.valueOf(); + } + valueB = Batman.get(b, _this.key); + if (typeof valueB === 'function') { + valueB = valueB.call(b); + } + if (valueB != null) { + valueB = valueB.valueOf(); + } + multiple = _this.descending ? -1 : 1; + return _this.compare.call(_this, valueA, valueB) * multiple; + }); + if ((_ref = this._setObserver) != null) { + _ref.startObservingItems.apply(_ref, newOrder); + } + return this.set('_storage', newOrder); + }; + + return SetSort; + + })(Batman.SetProxy); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.AssociationSet = (function(_super) { + + __extends(AssociationSet, _super); + + function AssociationSet(foreignKeyValue, association) { + var base; + this.foreignKeyValue = foreignKeyValue; + this.association = association; + base = new Batman.Set; + AssociationSet.__super__.constructor.call(this, base, '_batmanID'); + } + + AssociationSet.prototype.loaded = false; + + AssociationSet.prototype.load = function(callback) { + var _this = this; + if (this.foreignKeyValue == null) { + return callback(void 0, this); + } + return this.association.getRelatedModel().load(this._getLoadOptions(), function(err, records) { + if (!err) { + _this.markAsLoaded(); + } + return callback(err, _this); + }); + }; + + AssociationSet.prototype._getLoadOptions = function() { + var loadOptions; + loadOptions = {}; + loadOptions[this.association.foreignKey] = this.foreignKeyValue; + return loadOptions; + }; + + AssociationSet.accessor('loaded', Batman.Property.defaultAccessor); + + AssociationSet.prototype.markAsLoaded = function() { + this.set('loaded', true); + return this.fire('loaded'); + }; + + return AssociationSet; + + })(Batman.SetSort); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicAssociationSet = (function(_super) { + + __extends(PolymorphicAssociationSet, _super); + + function PolymorphicAssociationSet(foreignKeyValue, foreignTypeKeyValue, association) { + this.foreignKeyValue = foreignKeyValue; + this.foreignTypeKeyValue = foreignTypeKeyValue; + this.association = association; + PolymorphicAssociationSet.__super__.constructor.call(this, this.foreignKeyValue, this.association); + } + + PolymorphicAssociationSet.prototype._getLoadOptions = function() { + var loadOptions; + loadOptions = {}; + loadOptions[this.association.foreignKey] = this.foreignKeyValue; + loadOptions[this.association.foreignTypeKey] = this.foreignTypeKeyValue; + return loadOptions; + }; + + return PolymorphicAssociationSet; + + })(Batman.AssociationSet); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.SetIndex = (function(_super) { + + __extends(SetIndex, _super); + + SetIndex.accessor('toArray', function() { + return this.toArray(); + }); + + Batman.extend(SetIndex.prototype, Batman.Enumerable); + + SetIndex.prototype.propertyClass = Batman.Property; + + function SetIndex(base, key) { + var _this = this; + this.base = base; + this.key = key; + SetIndex.__super__.constructor.call(this); + this._storage = new Batman.Hash; + if (this.base.isEventEmitter) { + this._setObserver = new Batman.SetObserver(this.base); + this._setObserver.observedItemKeys = [this.key]; + this._setObserver.observerForItemAndKey = this.observerForItemAndKey.bind(this); + this._setObserver.on('itemsWereAdded', function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(_this._addItem(item)); + } + return _results; + }); + this._setObserver.on('itemsWereRemoved', function() { + var item, items, _i, _len, _results; + items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + _results = []; + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + _results.push(_this._removeItem(item)); + } + return _results; + }); + } + this.base.forEach(this._addItem.bind(this)); + this.startObserving(); + } + + SetIndex.accessor(function(key) { + return this._resultSetForKey(key); + }); + + SetIndex.prototype.startObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.startObserving() : void 0; + }; + + SetIndex.prototype.stopObserving = function() { + var _ref; + return (_ref = this._setObserver) != null ? _ref.stopObserving() : void 0; + }; + + SetIndex.prototype.observerForItemAndKey = function(item, key) { + var _this = this; + return function(newValue, oldValue) { + _this._removeItemFromKey(item, oldValue); + return _this._addItemToKey(item, newValue); + }; + }; + + SetIndex.prototype.forEach = function(iterator, ctx) { + var _this = this; + return this._storage.forEach(function(key, set) { + if (set.get('length') > 0) { + return iterator.call(ctx, key, set, _this); + } + }); + }; + + SetIndex.prototype.toArray = function() { + var results; + results = []; + this._storage.forEach(function(key, set) { + if (set.get('length') > 0) { + return results.push(key); + } + }); + return results; + }; + + SetIndex.prototype._addItem = function(item) { + return this._addItemToKey(item, this._keyForItem(item)); + }; + + SetIndex.prototype._addItemToKey = function(item, key) { + return this._resultSetForKey(key).add(item); + }; + + SetIndex.prototype._removeItem = function(item) { + return this._removeItemFromKey(item, this._keyForItem(item)); + }; + + SetIndex.prototype._removeItemFromKey = function(item, key) { + return this._resultSetForKey(key).remove(item); + }; + + SetIndex.prototype._resultSetForKey = function(key) { + return this._storage.getOrSet(key, function() { + return new Batman.Set; + }); + }; + + SetIndex.prototype._keyForItem = function(item) { + return Batman.Keypath.forBaseAndKey(item, this.key).getValue(); + }; + + return SetIndex; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicAssociationSetIndex = (function(_super) { + + __extends(PolymorphicAssociationSetIndex, _super); + + function PolymorphicAssociationSetIndex(association, type, key) { + this.association = association; + this.type = type; + PolymorphicAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); + } + + PolymorphicAssociationSetIndex.prototype._resultSetForKey = function(key) { + var _this = this; + return this._storage.getOrSet(key, function() { + return new _this.association.proxyClass(key, _this.type, _this.association); + }); + }; + + return PolymorphicAssociationSetIndex; + + })(Batman.SetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.AssociationSetIndex = (function(_super) { + + __extends(AssociationSetIndex, _super); + + function AssociationSetIndex(association, key) { + this.association = association; + AssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); + } + + AssociationSetIndex.prototype._resultSetForKey = function(key) { + var _this = this; + return this._storage.getOrSet(key, function() { + return new _this.association.proxyClass(key, _this.association); + }); + }; + + AssociationSetIndex.prototype._setResultSet = function(key, set) { + return this._storage.set(key, set); + }; + + return AssociationSetIndex; + + })(Batman.SetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.UniqueSetIndex = (function(_super) { + + __extends(UniqueSetIndex, _super); + + function UniqueSetIndex() { + this._uniqueIndex = new Batman.Hash; + UniqueSetIndex.__super__.constructor.apply(this, arguments); + } + + UniqueSetIndex.accessor(function(key) { + return this._uniqueIndex.get(key); + }); + + UniqueSetIndex.prototype._addItemToKey = function(item, key) { + this._resultSetForKey(key).add(item); + if (!this._uniqueIndex.hasKey(key)) { + return this._uniqueIndex.set(key, item); + } + }; + + UniqueSetIndex.prototype._removeItemFromKey = function(item, key) { + var resultSet; + resultSet = this._resultSetForKey(key); + UniqueSetIndex.__super__._removeItemFromKey.apply(this, arguments); + if (resultSet.isEmpty()) { + return this._uniqueIndex.unset(key); + } else { + return this._uniqueIndex.set(key, resultSet.toArray()[0]); + } + }; + + return UniqueSetIndex; + + })(Batman.SetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.UniqueAssociationSetIndex = (function(_super) { + + __extends(UniqueAssociationSetIndex, _super); + + function UniqueAssociationSetIndex(association, key) { + this.association = association; + UniqueAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); + } + + return UniqueAssociationSetIndex; + + })(Batman.UniqueSetIndex); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicUniqueAssociationSetIndex = (function(_super) { + + __extends(PolymorphicUniqueAssociationSetIndex, _super); + + function PolymorphicUniqueAssociationSetIndex(association, type, key) { + this.association = association; + this.type = type; + PolymorphicUniqueAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); + } + + return PolymorphicUniqueAssociationSetIndex; + + })(Batman.UniqueSetIndex); + +}).call(this); + +(function() { + + Batman.URI = (function() { + /* + # URI parsing + */ + + var attributes, childKeyMatchers, decodeQueryComponent, encodeComponent, encodeQueryComponent, keyVal, nameParser, normalizeParams, plus, queryFromParams, r20, strictParser; + + strictParser = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/; + + attributes = ["source", "protocol", "authority", "userInfo", "user", "password", "hostname", "port", "relative", "path", "directory", "file", "query", "hash"]; + + function URI(str) { + var i, matches; + matches = strictParser.exec(str); + i = 14; + while (i--) { + this[attributes[i]] = matches[i] || ''; + } + this.queryParams = this.constructor.paramsFromQuery(this.query); + delete this.authority; + delete this.userInfo; + delete this.relative; + delete this.directory; + delete this.file; + delete this.query; + } + + URI.prototype.queryString = function() { + return this.constructor.queryFromParams(this.queryParams); + }; + + URI.prototype.toString = function() { + return [this.protocol ? "" + this.protocol + ":" : void 0, this.authority() ? "//" : void 0, this.authority(), this.relative()].join(""); + }; + + URI.prototype.userInfo = function() { + return [this.user, this.password ? ":" + this.password : void 0].join(""); + }; + + URI.prototype.authority = function() { + return [this.userInfo(), this.user || this.password ? "@" : void 0, this.hostname, this.port ? ":" + this.port : void 0].join(""); + }; + + URI.prototype.relative = function() { + var query; + query = this.queryString(); + return [this.path, query ? "?" + query : void 0, this.hash ? "#" + this.hash : void 0].join(""); + }; + + URI.prototype.directory = function() { + var splitPath; + splitPath = this.path.split('/'); + if (splitPath.length > 1) { + return splitPath.slice(0, splitPath.length - 1).join('/') + "/"; + } else { + return ""; + } + }; + + URI.prototype.file = function() { + var splitPath; + splitPath = this.path.split("/"); + return splitPath[splitPath.length - 1]; + }; + + /* + # query parsing + */ + + + URI.paramsFromQuery = function(query) { + var matches, params, segment, _i, _len, _ref; + params = {}; + _ref = query.split('&'); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + segment = _ref[_i]; + if (matches = segment.match(keyVal)) { + normalizeParams(params, decodeQueryComponent(matches[1]), decodeQueryComponent(matches[2])); + } else { + normalizeParams(params, decodeQueryComponent(segment), null); + } + } + return params; + }; + + URI.decodeQueryComponent = decodeQueryComponent = function(str) { + return decodeURIComponent(str.replace(plus, '%20')); + }; + + nameParser = /^[\[\]]*([^\[\]]+)\]*(.*)/; + + childKeyMatchers = [/^\[\]\[([^\[\]]+)\]$/, /^\[\](.+)$/]; + + plus = /\+/g; + + r20 = /%20/g; + + keyVal = /^([^=]*)=(.*)/; + + normalizeParams = function(params, name, v) { + var after, childKey, k, last, matches, _ref, _ref1, _ref2; + if (matches = name.match(nameParser)) { + k = matches[1]; + after = matches[2]; + } else { + return; + } + if (after === '') { + params[k] = v; + } else if (after === '[]') { + if ((_ref = params[k]) == null) { + params[k] = []; + } + if (Batman.typeOf(params[k]) !== 'Array') { + throw new Error("expected Array (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); + } + params[k].push(v); + } else if (matches = after.match(childKeyMatchers[0]) || after.match(childKeyMatchers[1])) { + childKey = matches[1]; + if ((_ref1 = params[k]) == null) { + params[k] = []; + } + if (Batman.typeOf(params[k]) !== 'Array') { + throw new Error("expected Array (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); + } + last = params[k][params[k].length - 1]; + if (Batman.typeOf(last) === 'Object' && !(childKey in last)) { + normalizeParams(last, childKey, v); + } else { + params[k].push(normalizeParams({}, childKey, v)); + } + } else { + if ((_ref2 = params[k]) == null) { + params[k] = {}; + } + if (Batman.typeOf(params[k]) !== 'Object') { + throw new Error("expected Object (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); + } + params[k] = normalizeParams(params[k], after, v); + } + return params; + }; + + /* + # query building + */ + + + URI.queryFromParams = queryFromParams = function(value, prefix) { + var arrayResults, k, v, valueType; + if (value == null) { + return prefix; + } + valueType = Batman.typeOf(value); + if (!((prefix != null) || valueType === 'Object')) { + throw new Error("value must be an Object"); + } + switch (valueType) { + case 'Array': + return ((function() { + var _i, _len; + arrayResults = []; + if (value.length === 0) { + arrayResults.push(queryFromParams(null, "" + prefix + "[]")); + } else { + for (_i = 0, _len = value.length; _i < _len; _i++) { + v = value[_i]; + arrayResults.push(queryFromParams(v, "" + prefix + "[]")); + } + } + return arrayResults; + })()).join("&"); + case 'Object': + return ((function() { + var _results; + _results = []; + for (k in value) { + v = value[k]; + _results.push(queryFromParams(v, prefix ? "" + prefix + "[" + (encodeQueryComponent(k)) + "]" : encodeQueryComponent(k))); + } + return _results; + })()).join("&"); + default: + if (prefix != null) { + return "" + prefix + "=" + (encodeQueryComponent(value)); + } else { + return encodeQueryComponent(value); + } + } + }; + + URI.encodeComponent = encodeComponent = function(str) { + if (str != null) { + return encodeURIComponent(str); + } else { + return ''; + } + }; + + URI.encodeQueryComponent = encodeQueryComponent = function(str) { + return encodeComponent(str).replace(r20, '+'); + }; + + return URI; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.Request = (function(_super) { + var dataHasFileUploads; + + __extends(Request, _super); + + Request.objectToFormData = function(data) { + var formData, key, pairForList, val, _i, _len, _ref, _ref1; + pairForList = function(key, object, first) { + var k, list, v; + if (first == null) { + first = false; + } + return list = (function() { + switch (Batman.typeOf(object)) { + case 'Object': + list = (function() { + var _results; + _results = []; + for (k in object) { + v = object[k]; + _results.push(pairForList((first ? k : "" + key + "[" + k + "]"), v)); + } + return _results; + })(); + return list.reduce(function(acc, list) { + return acc.concat(list); + }, []); + case 'Array': + return object.reduce(function(acc, element) { + return acc.concat(pairForList("" + key + "[]", element)); + }, []); + default: + return [[key, object != null ? object : ""]]; + } + })(); + }; + formData = new Batman.container.FormData(); + _ref = pairForList("", data, true); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + _ref1 = _ref[_i], key = _ref1[0], val = _ref1[1]; + formData.append(key, val); + } + return formData; + }; + + Request.dataHasFileUploads = dataHasFileUploads = function(data) { + var k, type, v, _i, _len; + if ((typeof File !== "undefined" && File !== null) && data instanceof File) { + return true; + } + type = Batman.typeOf(data); + switch (type) { + case 'Object': + for (k in data) { + v = data[k]; + if (dataHasFileUploads(v)) { + return true; + } + } + break; + case 'Array': + for (_i = 0, _len = data.length; _i < _len; _i++) { + v = data[_i]; + if (dataHasFileUploads(v)) { + return true; + } + } + } + return false; + }; + + Request.wrapAccessor('method', function(core) { + return { + set: function(k, val) { + return core.set.call(this, k, val != null ? typeof val.toUpperCase === "function" ? val.toUpperCase() : void 0 : void 0); + } + }; + }); + + Request.prototype.method = 'GET'; + + Request.prototype.hasFileUploads = function() { + return dataHasFileUploads(this.data); + }; + + Request.prototype.contentType = 'application/x-www-form-urlencoded'; + + Request.prototype.autosend = true; + + function Request(options) { + var handler, handlers, k, _ref; + handlers = {}; + for (k in options) { + handler = options[k]; + if (!(k === 'success' || k === 'error' || k === 'loading' || k === 'loaded')) { + continue; + } + handlers[k] = handler; + delete options[k]; + } + Request.__super__.constructor.call(this, options); + for (k in handlers) { + handler = handlers[k]; + this.on(k, handler); + } + if (((_ref = this.get('url')) != null ? _ref.length : void 0) > 0) { + if (this.autosend) { + this.send(); + } + } else { + this.observe('url', function(url) { + if (url != null) { + return this.send(); + } + }); + } + } + + Request.prototype.send = function() { + return Batman.developer.error("Please source a dependency file for a request implementation"); + }; + + return Request; + + })(Batman.Object); + +}).call(this); + +(function() { + var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + __slice = [].slice; + + Batman.Navigator = (function() { + + Navigator.defaultClass = function() { + if (Batman.config.usePushState && Batman.PushStateNavigator.isSupported()) { + return Batman.PushStateNavigator; + } else { + return Batman.HashbangNavigator; + } + }; + + Navigator.forApp = function(app) { + return new (this.defaultClass())(app); + }; + + function Navigator(app) { + this.app = app; + this.handleCurrentLocation = __bind(this.handleCurrentLocation, this); + + } + + Navigator.prototype.start = function() { + var _this = this; + if (typeof window === 'undefined') { + return; + } + if (this.started) { + return; + } + this.started = true; + this.startWatching(); + Batman.currentApp.prevent('ready'); + return Batman.setImmediate(function() { + if (_this.started && Batman.currentApp) { + _this.handleCurrentLocation(); + return Batman.currentApp.allowAndFire('ready'); + } + }); + }; + + Navigator.prototype.stop = function() { + this.stopWatching(); + return this.started = false; + }; + + Navigator.prototype.handleLocation = function(location) { + var path; + path = this.pathFromLocation(location); + if (path === this.cachedPath) { + return; + } + return this.dispatch(path); + }; + + Navigator.prototype.handleCurrentLocation = function() { + return this.handleLocation(window.location); + }; + + Navigator.prototype.dispatch = function(params) { + return this.cachedPath = this.app.get('dispatcher').dispatch(params); + }; + + Navigator.prototype.push = function(params) { + var path; + path = this.dispatch(params); + this.pushState(null, '', path); + return path; + }; + + Navigator.prototype.replace = function(params) { + var path; + path = this.dispatch(params); + this.replaceState(null, '', path); + return path; + }; + + Navigator.prototype.redirect = Navigator.prototype.push; + + Navigator.prototype.normalizePath = function() { + var i, seg, segments; + segments = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + segments = (function() { + var _i, _len, _results; + _results = []; + for (i = _i = 0, _len = segments.length; _i < _len; i = ++_i) { + seg = segments[i]; + _results.push(("" + seg).replace(/^(?!\/)/, '/').replace(/\/+$/, '')); + } + return _results; + })(); + return segments.join('') || '/'; + }; + + Navigator.normalizePath = Navigator.prototype.normalizePath; + + return Navigator; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PushStateNavigator = (function(_super) { + + __extends(PushStateNavigator, _super); + + function PushStateNavigator() { + return PushStateNavigator.__super__.constructor.apply(this, arguments); + } + + PushStateNavigator.isSupported = function() { + var _ref; + return (typeof window !== "undefined" && window !== null ? (_ref = window.history) != null ? _ref.pushState : void 0 : void 0) != null; + }; + + PushStateNavigator.prototype.startWatching = function() { + return Batman.addEventListener(window, 'popstate', this.handleCurrentLocation); + }; + + PushStateNavigator.prototype.stopWatching = function() { + return Batman.removeEventListener(window, 'popstate', this.handleCurrentLocation); + }; + + PushStateNavigator.prototype.pushState = function(stateObject, title, path) { + return window.history.pushState(stateObject, title, this.linkTo(path)); + }; + + PushStateNavigator.prototype.replaceState = function(stateObject, title, path) { + return window.history.replaceState(stateObject, title, this.linkTo(path)); + }; + + PushStateNavigator.prototype.linkTo = function(url) { + return this.normalizePath(Batman.config.pathPrefix, url); + }; + + PushStateNavigator.prototype.pathFromLocation = function(location) { + var fullPath, prefixPattern; + fullPath = "" + (location.pathname || '') + (location.search || ''); + prefixPattern = new RegExp("^" + (this.normalizePath(Batman.config.pathPrefix))); + return this.normalizePath(fullPath.replace(prefixPattern, '')); + }; + + PushStateNavigator.prototype.handleLocation = function(location) { + var hashbangPath, path; + path = this.pathFromLocation(location); + if (path === '/' && (hashbangPath = Batman.HashbangNavigator.prototype.pathFromLocation(location)) !== '/') { + return this.replace(hashbangPath); + } else { + return PushStateNavigator.__super__.handleLocation.apply(this, arguments); + } + }; + + return PushStateNavigator; + + })(Batman.Navigator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HashbangNavigator = (function(_super) { + + __extends(HashbangNavigator, _super); + + function HashbangNavigator() { + return HashbangNavigator.__super__.constructor.apply(this, arguments); + } + + HashbangNavigator.prototype.HASH_PREFIX = '#!'; + + if ((typeof window !== "undefined" && window !== null) && 'onhashchange' in window) { + HashbangNavigator.prototype.startWatching = function() { + return Batman.addEventListener(window, 'hashchange', this.handleCurrentLocation); + }; + HashbangNavigator.prototype.stopWatching = function() { + return Batman.removeEventListener(window, 'hashchange', this.handleCurrentLocation); + }; + } else { + HashbangNavigator.prototype.startWatching = function() { + return this.interval = setInterval(this.handleCurrentLocation, 100); + }; + HashbangNavigator.prototype.stopWatching = function() { + return this.interval = clearInterval(this.interval); + }; + } + + HashbangNavigator.prototype.pushState = function(stateObject, title, path) { + return window.location.hash = this.linkTo(path); + }; + + HashbangNavigator.prototype.replaceState = function(stateObject, title, path) { + var loc; + loc = window.location; + return loc.replace("" + loc.pathname + loc.search + (this.linkTo(path))); + }; + + HashbangNavigator.prototype.linkTo = function(url) { + return this.HASH_PREFIX + url; + }; + + HashbangNavigator.prototype.pathFromLocation = function(location) { + var hash; + hash = location.hash; + if ((hash != null ? hash.substr(0, 2) : void 0) === this.HASH_PREFIX) { + return this.normalizePath(hash.substr(2)); + } else { + return '/'; + } + }; + + HashbangNavigator.prototype.handleLocation = function(location) { + var realPath; + if (!Batman.config.usePushState) { + return HashbangNavigator.__super__.handleLocation.apply(this, arguments); + } + realPath = Batman.PushStateNavigator.prototype.pathFromLocation(location); + if (realPath === '/') { + return HashbangNavigator.__super__.handleLocation.apply(this, arguments); + } else { + return location.replace(this.normalizePath("" + Batman.config.pathPrefix + (this.linkTo(realPath)))); + } + }; + + return HashbangNavigator; + + })(Batman.Navigator); + +}).call(this); + +(function() { + + Batman.RouteMap = (function() { + + RouteMap.prototype.memberRoute = null; + + RouteMap.prototype.collectionRoute = null; + + function RouteMap() { + this.childrenByOrder = []; + this.childrenByName = {}; + } + + RouteMap.prototype.routeForParams = function(params) { + var route, _i, _len, _ref; + _ref = this.childrenByOrder; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + route = _ref[_i]; + if (route.test(params)) { + return route; + } + } + return void 0; + }; + + RouteMap.prototype.addRoute = function(name, route) { + var base, names, + _this = this; + this.childrenByOrder.push(route); + if (name.length > 0 && (names = name.split('.')).length > 0) { + base = names.shift(); + if (!this.childrenByName[base]) { + this.childrenByName[base] = new Batman.RouteMap; + } + this.childrenByName[base].addRoute(names.join('.'), route); + } else { + if (route.get('member')) { + Batman.developer["do"](function() { + if (_this.memberRoute) { + return Batman.developer.error("Member route with name " + name + " already exists!"); + } + }); + this.memberRoute = route; + } else { + Batman.developer["do"](function() { + if (_this.collectionRoute) { + return Batman.developer.error("Collection route with name " + name + " already exists!"); + } + }); + this.collectionRoute = route; + } + } + return true; + }; + + return RouteMap; + + })(); + +}).call(this); + +(function() { + var __slice = [].slice; + + Batman.RouteMapBuilder = (function() { + + RouteMapBuilder.BUILDER_FUNCTIONS = ['resources', 'member', 'collection', 'route', 'root']; + + RouteMapBuilder.ROUTES = { + index: { + cardinality: 'collection', + path: function(resource) { + return resource; + }, + name: function(resource) { + return resource; + } + }, + "new": { + cardinality: 'collection', + path: function(resource) { + return "" + resource + "/new"; + }, + name: function(resource) { + return "" + resource + ".new"; + } + }, + show: { + cardinality: 'member', + path: function(resource) { + return "" + resource + "/:id"; + }, + name: function(resource) { + return resource; + } + }, + edit: { + cardinality: 'member', + path: function(resource) { + return "" + resource + "/:id/edit"; + }, + name: function(resource) { + return "" + resource + ".edit"; + } + }, + collection: { + cardinality: 'collection', + path: function(resource, name) { + return "" + resource + "/" + name; + }, + name: function(resource, name) { + return "" + resource + "." + name; + } + }, + member: { + cardinality: 'member', + path: function(resource, name) { + return "" + resource + "/:id/" + name; + }, + name: function(resource, name) { + return "" + resource + "." + name; + } + } + }; + + function RouteMapBuilder(app, routeMap, parent, baseOptions) { + this.app = app; + this.routeMap = routeMap; + this.parent = parent; + this.baseOptions = baseOptions != null ? baseOptions : {}; + if (this.parent) { + this.rootPath = this.parent._nestingPath(); + this.rootName = this.parent._nestingName(); + } else { + this.rootPath = ''; + this.rootName = ''; + } + } + + RouteMapBuilder.prototype.resources = function() { + var action, actions, arg, args, as, callback, childBuilder, controller, included, k, options, path, resourceName, resourceNames, resourceRoot, routeOptions, routeTemplate, v, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + resourceNames = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = args.length; _i < _len; _i++) { + arg = args[_i]; + if (typeof arg === 'string') { + _results.push(arg); + } + } + return _results; + })(); + if (typeof args[args.length - 1] === 'function') { + callback = args.pop(); + } + if (typeof args[args.length - 1] === 'object') { + options = args.pop(); + } else { + options = {}; + } + actions = { + index: true, + "new": true, + show: true, + edit: true + }; + if (options.except) { + _ref = options.except; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + actions[k] = false; + } + delete options.except; + } else if (options.only) { + for (k in actions) { + v = actions[k]; + actions[k] = false; + } + _ref1 = options.only; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + k = _ref1[_j]; + actions[k] = true; + } + delete options.only; + } + for (_k = 0, _len2 = resourceNames.length; _k < _len2; _k++) { + resourceName = resourceNames[_k]; + resourceRoot = Batman.helpers.pluralize(resourceName); + controller = Batman.helpers.camelize(resourceRoot, true); + childBuilder = this._childBuilder({ + controller: controller + }); + if (callback != null) { + callback.call(childBuilder); + } + for (action in actions) { + included = actions[action]; + if (!(included)) { + continue; + } + routeTemplate = this.constructor.ROUTES[action]; + as = routeTemplate.name(resourceRoot); + path = routeTemplate.path(resourceRoot); + routeOptions = Batman.extend({ + controller: controller, + action: action, + path: path, + as: as + }, options); + childBuilder[routeTemplate.cardinality](action, routeOptions); + } + } + return true; + }; + + RouteMapBuilder.prototype.member = function() { + return this._addRoutesWithCardinality.apply(this, ['member'].concat(__slice.call(arguments))); + }; + + RouteMapBuilder.prototype.collection = function() { + return this._addRoutesWithCardinality.apply(this, ['collection'].concat(__slice.call(arguments))); + }; + + RouteMapBuilder.prototype.root = function(signature, options) { + return this.route('/', signature, options); + }; + + RouteMapBuilder.prototype.route = function(path, signature, options, callback) { + if (!callback) { + if (typeof options === 'function') { + callback = options; + options = void 0; + } else if (typeof signature === 'function') { + callback = signature; + signature = void 0; + } + } + if (!options) { + if (typeof signature === 'string') { + options = { + signature: signature + }; + } else { + options = signature; + } + options || (options = {}); + } else { + if (signature) { + options.signature = signature; + } + } + if (callback) { + options.callback = callback; + } + options.as || (options.as = this._nameFromPath(path)); + options.path = path; + return this._addRoute(options); + }; + + RouteMapBuilder.prototype._addRoutesWithCardinality = function() { + var cardinality, name, names, options, resourceRoot, routeOptions, routeTemplate, _i, _j, _len; + cardinality = arguments[0], names = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), options = arguments[_i++]; + if (typeof options === 'string') { + names.push(options); + options = {}; + } + options = Batman.extend({}, this.baseOptions, options); + options[cardinality] = true; + routeTemplate = this.constructor.ROUTES[cardinality]; + resourceRoot = options.controller; + for (_j = 0, _len = names.length; _j < _len; _j++) { + name = names[_j]; + routeOptions = Batman.extend({ + action: name + }, options); + if (routeOptions.path == null) { + routeOptions.path = routeTemplate.path(resourceRoot, name); + } + if (routeOptions.as == null) { + routeOptions.as = routeTemplate.name(resourceRoot, name); + } + this._addRoute(routeOptions); + } + return true; + }; + + RouteMapBuilder.prototype._addRoute = function(options) { + var klass, name, path, route; + if (options == null) { + options = {}; + } + path = this.rootPath + options.path; + name = this.rootName + Batman.helpers.camelize(options.as, true); + delete options.as; + delete options.path; + klass = options.callback ? Batman.CallbackActionRoute : Batman.ControllerActionRoute; + options.app = this.app; + route = new klass(path, options); + return this.routeMap.addRoute(name, route); + }; + + RouteMapBuilder.prototype._nameFromPath = function(path) { + path = path.replace(Batman.Route.regexps.namedOrSplat, '').replace(/\/+/g, '.').replace(/(^\.)|(\.$)/g, ''); + return path; + }; + + RouteMapBuilder.prototype._nestingPath = function() { + var nestingParam, nestingSegment; + if (!this.parent) { + return ""; + } else { + nestingParam = ":" + Batman.helpers.singularize(this.baseOptions.controller) + "Id"; + nestingSegment = Batman.helpers.underscore(this.baseOptions.controller); + return "" + (this.parent._nestingPath()) + "/" + nestingSegment + "/" + nestingParam + "/"; + } + }; + + RouteMapBuilder.prototype._nestingName = function() { + if (!this.parent) { + return ""; + } else { + return this.baseOptions.controller + "."; + } + }; + + RouteMapBuilder.prototype._childBuilder = function(baseOptions) { + if (baseOptions == null) { + baseOptions = {}; + } + return new Batman.RouteMapBuilder(this.app, this.routeMap, this, baseOptions); + }; + + return RouteMapBuilder; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.App = (function(_super) { + var name, _fn, _i, _len, _ref, + _this = this; + + __extends(App, _super); + + function App() { + return App.__super__.constructor.apply(this, arguments); + } + + App.classAccessor('currentParams', { + get: function() { + return new Batman.Hash; + }, + 'final': true + }); + + App.classAccessor('paramsManager', { + get: function() { + var nav, params; + if (!(nav = this.get('navigator'))) { + return; + } + params = this.get('currentParams'); + return params.replacer = new Batman.ParamsReplacer(nav, params); + }, + 'final': true + }); + + App.classAccessor('paramsPusher', { + get: function() { + var nav, params; + if (!(nav = this.get('navigator'))) { + return; + } + params = this.get('currentParams'); + return params.pusher = new Batman.ParamsPusher(nav, params); + }, + 'final': true + }); + + App.classAccessor('routes', function() { + return new Batman.NamedRouteQuery(this.get('routeMap')); + }); + + App.classAccessor('routeMap', function() { + return new Batman.RouteMap; + }); + + App.classAccessor('routeMapBuilder', function() { + return new Batman.RouteMapBuilder(this, this.get('routeMap')); + }); + + App.classAccessor('dispatcher', function() { + return new Batman.Dispatcher(this, this.get('routeMap')); + }); + + App.classAccessor('controllers', function() { + return this.get('dispatcher.controllers'); + }); + + App.classAccessor('_renderContext', function() { + return Batman.RenderContext.base.descend(this); + }); + + App.requirePath = ''; + + Batman.developer["do"](function() { + App.require = function() { + var base, name, names, path, _i, _len, + _this = this; + path = arguments[0], names = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + base = this.requirePath + path; + for (_i = 0, _len = names.length; _i < _len; _i++) { + name = names[_i]; + this.prevent('run'); + path = base + '/' + name + '.coffee'; + new Batman.Request({ + url: path, + type: 'html', + success: function(response) { + CoffeeScript["eval"](response); + _this.allow('run'); + if (!_this.isPrevented('run')) { + _this.fire('loaded'); + } + if (_this.wantsToRun) { + return _this.run(); + } + } + }); + } + return this; + }; + App.controller = function() { + var names; + names = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + names = names.map(function(n) { + return n + '_controller'; + }); + return this.require.apply(this, ['controllers'].concat(__slice.call(names))); + }; + App.model = function() { + return this.require.apply(this, ['models'].concat(__slice.call(arguments))); + }; + return App.view = function() { + return this.require.apply(this, ['views'].concat(__slice.call(arguments))); + }; + }); + + App.layout = void 0; + + _ref = Batman.RouteMapBuilder.BUILDER_FUNCTIONS; + _fn = function(name) { + return App[name] = function() { + var _ref1; + return (_ref1 = this.get('routeMapBuilder'))[name].apply(_ref1, arguments); + }; + }; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + name = _ref[_i]; + _fn(name); + } + + App.event('ready').oneShot = true; + + App.event('run').oneShot = true; + + App.run = function() { + var layout, layoutClass, + _this = this; + if (Batman.currentApp) { + if (Batman.currentApp === this) { + return; + } + Batman.currentApp.stop(); + } + if (this.hasRun) { + return false; + } + if (this.isPrevented('run')) { + this.wantsToRun = true; + return false; + } else { + delete this.wantsToRun; + } + Batman.currentApp = this; + Batman.App.set('current', this); + if (this.get('dispatcher') == null) { + this.set('dispatcher', new Batman.Dispatcher(this, this.get('routeMap'))); + this.set('controllers', this.get('dispatcher.controllers')); + } + if (this.get('navigator') == null) { + this.set('navigator', Batman.Navigator.forApp(this)); + this.on('run', function() { + Batman.navigator = _this.get('navigator'); + if (Object.keys(_this.get('dispatcher').routeMap).length > 0) { + return Batman.navigator.start(); + } + }); + } + this.observe('layout', function(layout) { + return layout != null ? layout.on('ready', function() { + return _this.fire('ready'); + }) : void 0; + }); + layout = this.get('layout'); + if (layout) { + if (typeof layout === 'string') { + layoutClass = this[Batman.helpers.camelize(layout) + 'View']; + } + } else { + if (layout !== null) { + layoutClass = Batman.View; + } + } + if (layoutClass) { + layout = this.set('layout', new layoutClass({ + context: this, + node: document + })); + } + this.hasRun = true; + this.fire('run'); + return this; + }; + + App.event('ready').oneShot = true; + + App.event('stop').oneShot = true; + + App.stop = function() { + var _ref1; + if ((_ref1 = this.navigator) != null) { + _ref1.stop(); + } + Batman.navigator = null; + this.hasRun = false; + this.fire('stop'); + return this; + }; + + return App; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + + Batman.Association = (function() { + + Association.prototype.associationType = ''; + + Association.prototype.isPolymorphic = false; + + Association.prototype.defaultOptions = { + saveInline: true, + autoload: true, + nestUrl: false + }; + + function Association(model, label, options) { + var defaultOptions, encoder, getAccessor, self; + this.model = model; + this.label = label; + if (options == null) { + options = {}; + } + defaultOptions = { + namespace: Batman.currentApp, + name: Batman.helpers.camelize(Batman.helpers.singularize(this.label)) + }; + this.options = Batman.extend(defaultOptions, this.defaultOptions, options); + if (this.options.nestUrl) { + if (!(this.model.urlNestsUnder != null)) { + developer.error("You must persist the the model " + this.model.constructor.name + " to use the url helpers on an association"); + } + this.model.urlNestsUnder(Batman.helpers.underscore(this.getRelatedModel().get('resourceName'))); + } + if (this.options.extend != null) { + Batman.extend(this, this.options.extend); + } + encoder = { + encode: this.options.saveInline ? this.encoder() : false, + decode: this.decoder() + }; + this.model.encode(this.label, encoder); + self = this; + getAccessor = function() { + return self.getAccessor.call(this, self, this.model, this.label); + }; + this.model.accessor(this.label, { + get: getAccessor, + set: model.defaultAccessor.set, + unset: model.defaultAccessor.unset + }); + } + + Association.prototype.getRelatedModel = function() { + var className, relatedModel, scope; + scope = this.options.namespace || Batman.currentApp; + className = this.options.name; + relatedModel = scope != null ? scope[className] : void 0; + Batman.developer["do"](function() { + if ((Batman.currentApp != null) && !relatedModel) { + return Batman.developer.warn("Related model " + className + " hasn't loaded yet."); + } + }); + return relatedModel; + }; + + Association.prototype.getFromAttributes = function(record) { + return record.get("attributes." + this.label); + }; + + Association.prototype.setIntoAttributes = function(record, value) { + return record.get('attributes').set(this.label, value); + }; + + Association.prototype.inverse = function() { + var inverse, relatedAssocs, + _this = this; + if (relatedAssocs = this.getRelatedModel()._batman.get('associations')) { + if (this.options.inverseOf) { + return relatedAssocs.getByLabel(this.options.inverseOf); + } + inverse = null; + relatedAssocs.forEach(function(label, assoc) { + if (assoc.getRelatedModel() === _this.model) { + return inverse = assoc; + } + }); + return inverse; + } + }; + + Association.prototype.reset = function() { + delete this.index; + return true; + }; + + return Association; + + })(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PluralAssociation = (function(_super) { + + __extends(PluralAssociation, _super); + + function PluralAssociation() { + return PluralAssociation.__super__.constructor.apply(this, arguments); + } + + PluralAssociation.prototype.proxyClass = Batman.AssociationSet; + + PluralAssociation.prototype.isSingular = false; + + PluralAssociation.prototype.setForRecord = Batman.Property.wrapTrackingPrevention(function(record) { + var id; + if (id = record.get(this.primaryKey)) { + return this.setIndex().get(id); + } else { + return new this.proxyClass(void 0, this); + } + }); + + PluralAssociation.prototype.getAccessor = function(self, model, label) { + var relatedRecords, setInAttributes, + _this = this; + if (!self.getRelatedModel()) { + return; + } + if (setInAttributes = self.getFromAttributes(this)) { + return setInAttributes; + } else { + relatedRecords = self.setForRecord(this); + self.setIntoAttributes(this, relatedRecords); + Batman.Property.withoutTracking(function() { + if (self.options.autoload && !_this.isNew() && !relatedRecords.loaded) { + return relatedRecords.load(function(error, records) { + if (error) { + throw error; + } + }); + } + }); + return relatedRecords; + } + }; + + PluralAssociation.prototype.setIndex = function() { + this.index || (this.index = new Batman.AssociationSetIndex(this, this[this.indexRelatedModelOn])); + return this.index; + }; + + return PluralAssociation; + + })(Batman.Association); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HasManyAssociation = (function(_super) { + + __extends(HasManyAssociation, _super); + + HasManyAssociation.prototype.associationType = 'hasMany'; + + HasManyAssociation.prototype.indexRelatedModelOn = 'foreignKey'; + + function HasManyAssociation(model, label, options) { + if (options != null ? options.as : void 0) { + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.PolymorphicHasManyAssociation, arguments, function(){}); + } + HasManyAssociation.__super__.constructor.apply(this, arguments); + this.primaryKey = this.options.primaryKey || "id"; + this.foreignKey = this.options.foreignKey || ("" + (Batman.helpers.underscore(model.get('resourceName'))) + "_id"); + } + + HasManyAssociation.prototype.apply = function(baseSaveError, base) { + var relations, set, + _this = this; + if (!baseSaveError) { + if (relations = this.getFromAttributes(base)) { + relations.forEach(function(model) { + return model.set(_this.foreignKey, base.get(_this.primaryKey)); + }); + } + base.set(this.label, set = this.setForRecord(base)); + if (base.lifecycle.get('state') === 'creating') { + return set.markAsLoaded(); + } + } + }; + + HasManyAssociation.prototype.encoder = function() { + var association; + association = this; + return function(relationSet, _, __, record) { + var jsonArray; + if (relationSet != null) { + jsonArray = []; + relationSet.forEach(function(relation) { + var relationJSON; + relationJSON = relation.toJSON(); + if (!association.inverse() || association.inverse().options.encodeForeignKey) { + relationJSON[association.foreignKey] = record.get(association.primaryKey); + } + return jsonArray.push(relationJSON); + }); + } + return jsonArray; + }; + }; + + HasManyAssociation.prototype.decoder = function() { + var association; + association = this; + return function(data, key, _, __, parentRecord) { + var existingRecord, existingRelations, jsonObject, newRelations, record, relatedModel, savedRecord, _i, _len; + if (relatedModel = association.getRelatedModel()) { + existingRelations = association.getFromAttributes(parentRecord) || association.setForRecord(parentRecord); + newRelations = existingRelations.filter(function(relation) { + return relation.isNew(); + }).toArray(); + for (_i = 0, _len = data.length; _i < _len; _i++) { + jsonObject = data[_i]; + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + existingRecord = relatedModel.get('loaded').indexedByUnique('id').get(record.get('id')); + if (existingRecord != null) { + existingRecord._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + record = existingRecord; + } else { + if (newRelations.length > 0) { + savedRecord = newRelations.shift(); + savedRecord._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + record = savedRecord; + } + } + record = relatedModel._mapIdentity(record); + existingRelations.add(record); + if (association.options.inverseOf) { + record.set(association.options.inverseOf, parentRecord); + } + } + existingRelations.markAsLoaded(); + } else { + Batman.developer.error("Can't decode model " + association.options.name + " because it hasn't been loaded yet!"); + } + return existingRelations; + }; + }; + + return HasManyAssociation; + + })(Batman.PluralAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicHasManyAssociation = (function(_super) { + + __extends(PolymorphicHasManyAssociation, _super); + + PolymorphicHasManyAssociation.prototype.proxyClass = Batman.PolymorphicAssociationSet; + + PolymorphicHasManyAssociation.prototype.isPolymorphic = true; + + function PolymorphicHasManyAssociation(model, label, options) { + options.inverseOf = this.foreignLabel = options.as; + delete options.as; + options.foreignKey || (options.foreignKey = "" + this.foreignLabel + "_id"); + PolymorphicHasManyAssociation.__super__.constructor.call(this, model, label, options); + this.foreignTypeKey = options.foreignTypeKey || ("" + this.foreignLabel + "_type"); + this.model.encode(this.foreignTypeKey); + } + + PolymorphicHasManyAssociation.prototype.apply = function(baseSaveError, base) { + var relations, + _this = this; + if (!baseSaveError) { + if (relations = this.getFromAttributes(base)) { + PolymorphicHasManyAssociation.__super__.apply.apply(this, arguments); + relations.forEach(function(model) { + return model.set(_this.foreignTypeKey, _this.modelType()); + }); + } + } + return true; + }; + + PolymorphicHasManyAssociation.prototype.getRelatedModelForType = function() { + return this.getRelatedModel(); + }; + + PolymorphicHasManyAssociation.prototype.modelType = function() { + return this.model.get('resourceName'); + }; + + PolymorphicHasManyAssociation.prototype.setIndex = function() { + if (!this.typeIndex) { + this.typeIndex = new Batman.PolymorphicAssociationSetIndex(this, this.modelType(), this[this.indexRelatedModelOn]); + } + return this.typeIndex; + }; + + PolymorphicHasManyAssociation.prototype.encoder = function() { + var association; + association = this; + return function(relationSet, _, __, record) { + var jsonArray; + if (relationSet != null) { + jsonArray = []; + relationSet.forEach(function(relation) { + var relationJSON; + relationJSON = relation.toJSON(); + relationJSON[association.foreignKey] = record.get(association.primaryKey); + relationJSON[association.foreignTypeKey] = association.modelType(); + return jsonArray.push(relationJSON); + }); + } + return jsonArray; + }; + }; + + return PolymorphicHasManyAssociation; + + })(Batman.HasManyAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.SingularAssociation = (function(_super) { + + __extends(SingularAssociation, _super); + + function SingularAssociation() { + return SingularAssociation.__super__.constructor.apply(this, arguments); + } + + SingularAssociation.prototype.isSingular = true; + + SingularAssociation.prototype.getAccessor = function(self, model, label) { + var proxy, recordInAttributes; + if (recordInAttributes = self.getFromAttributes(this)) { + return recordInAttributes; + } + if (self.getRelatedModel()) { + proxy = this.associationProxy(self); + Batman.Property.withoutTracking(function() { + if (!proxy.get('loaded') && self.options.autoload) { + return proxy.load(); + } + }); + return proxy; + } + }; + + SingularAssociation.prototype.setIndex = function() { + this.index || (this.index = new Batman.UniqueAssociationSetIndex(this, this[this.indexRelatedModelOn])); + return this.index; + }; + + return SingularAssociation; + + })(Batman.Association); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.HasOneAssociation = (function(_super) { + + __extends(HasOneAssociation, _super); + + HasOneAssociation.prototype.associationType = 'hasOne'; + + HasOneAssociation.prototype.proxyClass = Batman.HasOneProxy; + + HasOneAssociation.prototype.indexRelatedModelOn = 'foreignKey'; + + function HasOneAssociation() { + HasOneAssociation.__super__.constructor.apply(this, arguments); + this.primaryKey = this.options.primaryKey || "id"; + this.foreignKey = this.options.foreignKey || ("" + (Batman.helpers.underscore(this.model.get('resourceName'))) + "_id"); + } + + HasOneAssociation.prototype.apply = function(baseSaveError, base) { + var relation; + if (relation = this.getFromAttributes(base)) { + return relation.set(this.foreignKey, base.get(this.primaryKey)); + } + }; + + HasOneAssociation.prototype.encoder = function() { + var association; + association = this; + return function(val, key, object, record) { + var json; + if (!association.options.saveInline) { + return; + } + if (json = val.toJSON()) { + json[association.foreignKey] = record.get(association.primaryKey); + } + return json; + }; + }; + + HasOneAssociation.prototype.decoder = function() { + var association; + association = this; + return function(data, _, __, ___, parentRecord) { + var record, relatedModel; + relatedModel = association.getRelatedModel(); + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(data); + }); + if (association.options.inverseOf) { + record.set(association.options.inverseOf, parentRecord); + } + record = relatedModel._mapIdentity(record); + return record; + }; + }; + + return HasOneAssociation; + + })(Batman.SingularAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.BelongsToAssociation = (function(_super) { + + __extends(BelongsToAssociation, _super); + + BelongsToAssociation.prototype.associationType = 'belongsTo'; + + BelongsToAssociation.prototype.proxyClass = Batman.BelongsToProxy; + + BelongsToAssociation.prototype.indexRelatedModelOn = 'primaryKey'; + + BelongsToAssociation.prototype.defaultOptions = { + saveInline: false, + autoload: true, + encodeForeignKey: true + }; + + function BelongsToAssociation(model, label, options) { + if (options != null ? options.polymorphic : void 0) { + delete options.polymorphic; + return (function(func, args, ctor) { + ctor.prototype = func.prototype; + var child = new ctor, result = func.apply(child, args), t = typeof result; + return t == "object" || t == "function" ? result || child : child; + })(Batman.PolymorphicBelongsToAssociation, arguments, function(){}); + } + BelongsToAssociation.__super__.constructor.apply(this, arguments); + this.foreignKey = this.options.foreignKey || ("" + this.label + "_id"); + this.primaryKey = this.options.primaryKey || "id"; + if (this.options.encodeForeignKey) { + this.model.encode(this.foreignKey); + } + } + + BelongsToAssociation.prototype.encoder = function() { + return function(val) { + return val.toJSON(); + }; + }; + + BelongsToAssociation.prototype.decoder = function() { + var association; + association = this; + return function(data, _, __, ___, childRecord) { + var inverse, record, relatedModel; + relatedModel = association.getRelatedModel(); + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(data); + }); + record = relatedModel._mapIdentity(record); + if (association.options.inverseOf) { + if (inverse = association.inverse()) { + if (inverse instanceof Batman.HasManyAssociation) { + childRecord.set(association.foreignKey, record.get(association.primaryKey)); + } else { + record.set(inverse.label, childRecord); + } + } + } + childRecord.set(association.label, record); + return record; + }; + }; + + BelongsToAssociation.prototype.apply = function(base) { + var foreignValue, model; + if (model = base.get(this.label)) { + foreignValue = model.get(this.primaryKey); + if (foreignValue !== void 0) { + return base.set(this.foreignKey, foreignValue); + } + } + }; + + return BelongsToAssociation; + + })(Batman.SingularAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PolymorphicBelongsToAssociation = (function(_super) { + + __extends(PolymorphicBelongsToAssociation, _super); + + PolymorphicBelongsToAssociation.prototype.isPolymorphic = true; + + PolymorphicBelongsToAssociation.prototype.proxyClass = Batman.PolymorphicBelongsToProxy; + + PolymorphicBelongsToAssociation.prototype.defaultOptions = Batman.mixin({}, Batman.BelongsToAssociation.prototype.defaultOptions, { + encodeForeignTypeKey: true + }); + + function PolymorphicBelongsToAssociation() { + PolymorphicBelongsToAssociation.__super__.constructor.apply(this, arguments); + this.foreignTypeKey = this.options.foreignTypeKey || ("" + this.label + "_type"); + if (this.options.encodeForeignTypeKey) { + this.model.encode(this.foreignTypeKey); + } + this.typeIndicies = {}; + } + + PolymorphicBelongsToAssociation.prototype.getRelatedModel = false; + + PolymorphicBelongsToAssociation.prototype.setIndex = false; + + PolymorphicBelongsToAssociation.prototype.inverse = false; + + PolymorphicBelongsToAssociation.prototype.apply = function(base) { + var foreignTypeValue, instanceOrProxy, model; + PolymorphicBelongsToAssociation.__super__.apply.apply(this, arguments); + if (instanceOrProxy = base.get(this.label)) { + if (instanceOrProxy instanceof Batman.AssociationProxy) { + model = instanceOrProxy.association.model; + } else { + model = instanceOrProxy.constructor; + } + foreignTypeValue = model.get('resourceName'); + return base.set(this.foreignTypeKey, foreignTypeValue); + } + }; + + PolymorphicBelongsToAssociation.prototype.getAccessor = function(self, model, label) { + var proxy, recordInAttributes; + if (recordInAttributes = self.getFromAttributes(this)) { + return recordInAttributes; + } + if (self.getRelatedModelForType(this.get(self.foreignTypeKey))) { + proxy = this.associationProxy(self); + Batman.Property.withoutTracking(function() { + if (!proxy.get('loaded') && self.options.autoload) { + return proxy.load(); + } + }); + return proxy; + } + }; + + PolymorphicBelongsToAssociation.prototype.url = function(recordOptions) { + var ending, helper, id, inverse, root, type, _ref, _ref1; + type = (_ref = recordOptions.data) != null ? _ref[this.foreignTypeKey] : void 0; + if (type && (inverse = this.inverseForType(type))) { + root = Batman.helpers.pluralize(type).toLowerCase(); + id = (_ref1 = recordOptions.data) != null ? _ref1[this.foreignKey] : void 0; + helper = inverse.isSingular ? "singularize" : "pluralize"; + ending = Batman.helpers[helper](inverse.label); + return "/" + root + "/" + id + "/" + ending; + } + }; + + PolymorphicBelongsToAssociation.prototype.getRelatedModelForType = function(type) { + var relatedModel, scope; + scope = this.options.namespace || Batman.currentApp; + if (type) { + relatedModel = scope != null ? scope[type] : void 0; + relatedModel || (relatedModel = scope != null ? scope[Batman.helpers.camelize(type)] : void 0); + } + Batman.developer["do"](function() { + if ((Batman.currentApp != null) && !relatedModel) { + return Batman.developer.warn("Related model " + type + " for polymorphic association not found."); + } + }); + return relatedModel; + }; + + PolymorphicBelongsToAssociation.prototype.setIndexForType = function(type) { + var _base; + (_base = this.typeIndicies)[type] || (_base[type] = new Batman.PolymorphicUniqueAssociationSetIndex(this, type, this.primaryKey)); + return this.typeIndicies[type]; + }; + + PolymorphicBelongsToAssociation.prototype.inverseForType = function(type) { + var inverse, relatedAssocs, _ref, + _this = this; + if (relatedAssocs = (_ref = this.getRelatedModelForType(type)) != null ? _ref._batman.get('associations') : void 0) { + if (this.options.inverseOf) { + return relatedAssocs.getByLabel(this.options.inverseOf); + } + inverse = null; + relatedAssocs.forEach(function(label, assoc) { + if (assoc.getRelatedModel() === _this.model) { + return inverse = assoc; + } + }); + return inverse; + } + }; + + PolymorphicBelongsToAssociation.prototype.decoder = function() { + var association; + association = this; + return function(data, key, response, ___, childRecord) { + var foreignTypeValue, inverse, record, relatedModel; + foreignTypeValue = response[association.foreignTypeKey] || childRecord.get(association.foreignTypeKey); + relatedModel = association.getRelatedModelForType(foreignTypeValue); + record = new relatedModel(); + record._withoutDirtyTracking(function() { + return this.fromJSON(data); + }); + record = relatedModel._mapIdentity(record); + if (association.options.inverseOf) { + if (inverse = association.inverseForType(foreignTypeValue)) { + if (inverse instanceof Batman.PolymorphicHasManyAssociation) { + childRecord.set(association.foreignKey, record.get(association.primaryKey)); + childRecord.set(association.foreignTypeKey, foreignTypeValue); + } else { + record.set(inverse.label, childRecord); + } + } + } + childRecord.set(association.label, record); + return record; + }; + }; + + return PolymorphicBelongsToAssociation; + + })(Batman.BelongsToAssociation); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.Validator = (function(_super) { + + __extends(Validator, _super); + + function Validator() { + var mixins, options; + options = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + this.options = options; + Validator.__super__.constructor.apply(this, mixins); + } + + Validator.prototype.validate = function(record) { + return Batman.developer.error("You must override validate in Batman.Validator subclasses."); + }; + + Validator.prototype.format = function(key, messageKey, interpolations) { + return Batman.t("errors.messages." + messageKey, interpolations); + }; + + Validator.options = function() { + var options; + options = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + Batman.initializeObject(this); + if (this._batman.options) { + return this._batman.options.concat(options); + } else { + return this._batman.options = options; + } + }; + + Validator.matches = function(options) { + var key, results, shouldReturn, value, _ref, _ref1; + results = {}; + shouldReturn = false; + for (key in options) { + value = options[key]; + if (~((_ref = this._batman) != null ? (_ref1 = _ref.options) != null ? _ref1.indexOf(key) : void 0 : void 0)) { + results[key] = value; + shouldReturn = true; + } + } + if (shouldReturn) { + return results; + } + }; + + return Validator; + + })(Batman.Object); + +}).call(this); + +(function() { + + Batman.Validators = []; + + Batman.extend(Batman.translate.messages, { + errors: { + format: "%{attribute} %{message}", + messages: { + too_short: "must be at least %{count} characters", + too_long: "must be less than %{count} characters", + wrong_length: "must be %{count} characters", + blank: "can't be blank", + not_numeric: "must be a number", + not_matching: "is not valid" + } + } + }); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.RegExpValidator = (function(_super) { + + __extends(RegExpValidator, _super); + + RegExpValidator.options('regexp', 'pattern'); + + function RegExpValidator(options) { + var _ref; + this.regexp = (_ref = options.regexp) != null ? _ref : options.pattern; + RegExpValidator.__super__.constructor.apply(this, arguments); + } + + RegExpValidator.prototype.validateEach = function(errors, record, key, callback) { + var value; + value = record.get(key); + if ((value != null) && value !== '') { + if (!this.regexp.test(value)) { + errors.add(key, this.format(key, 'not_matching')); + } + } + return callback(); + }; + + return RegExpValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.RegExpValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.PresenceValidator = (function(_super) { + + __extends(PresenceValidator, _super); + + function PresenceValidator() { + return PresenceValidator.__super__.constructor.apply(this, arguments); + } + + PresenceValidator.options('presence'); + + PresenceValidator.prototype.validateEach = function(errors, record, key, callback) { + var value; + value = record.get(key); + if (this.options.presence && (!(value != null) || value === '')) { + errors.add(key, this.format(key, 'blank')); + } + return callback(); + }; + + return PresenceValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.PresenceValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.NumericValidator = (function(_super) { + + __extends(NumericValidator, _super); + + function NumericValidator() { + return NumericValidator.__super__.constructor.apply(this, arguments); + } + + NumericValidator.options('numeric'); + + NumericValidator.prototype.validateEach = function(errors, record, key, callback) { + var value; + value = record.get(key); + if (this.options.numeric && isNaN(parseFloat(value))) { + errors.add(key, this.format(key, 'not_numeric')); + } + return callback(); + }; + + return NumericValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.NumericValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.LengthValidator = (function(_super) { + + __extends(LengthValidator, _super); + + LengthValidator.options('minLength', 'maxLength', 'length', 'lengthWithin', 'lengthIn'); + + function LengthValidator(options) { + var range; + if (range = options.lengthIn || options.lengthWithin) { + options.minLength = range[0]; + options.maxLength = range[1] || -1; + delete options.lengthWithin; + delete options.lengthIn; + } + LengthValidator.__super__.constructor.apply(this, arguments); + } + + LengthValidator.prototype.validateEach = function(errors, record, key, callback) { + var options, value, _ref; + options = this.options; + value = (_ref = record.get(key)) != null ? _ref : []; + if (options.minLength && value.length < options.minLength) { + errors.add(key, this.format(key, 'too_short', { + count: options.minLength + })); + } + if (options.maxLength && value.length > options.maxLength) { + errors.add(key, this.format(key, 'too_long', { + count: options.maxLength + })); + } + if (options.length && value.length !== options.length) { + errors.add(key, this.format(key, 'wrong_length', { + count: options.length + })); + } + return callback(); + }; + + return LengthValidator; + + })(Batman.Validator); + + Batman.Validators.push(Batman.LengthValidator); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ControllerActionFrame = (function(_super) { + + __extends(ControllerActionFrame, _super); + + ControllerActionFrame.prototype.operationOccurred = false; + + ControllerActionFrame.prototype.remainingOperations = 0; + + ControllerActionFrame.prototype.event('complete').oneShot = true; + + function ControllerActionFrame(options, onComplete) { + ControllerActionFrame.__super__.constructor.call(this, options); + this.on('complete', onComplete); + } + + ControllerActionFrame.prototype.startOperation = function(options) { + if (options == null) { + options = {}; + } + if (!options.internal) { + this.operationOccurred = true; + } + this._changeOperationsCounter(1); + return true; + }; + + ControllerActionFrame.prototype.finishOperation = function() { + this._changeOperationsCounter(-1); + return true; + }; + + ControllerActionFrame.prototype.startAndFinishOperation = function(options) { + this.startOperation(options); + this.finishOperation(options); + return true; + }; + + ControllerActionFrame.prototype._changeOperationsCounter = function(delta) { + var _ref; + this.remainingOperations += delta; + if (this.remainingOperations === 0) { + this.fire('complete'); + } + if ((_ref = this.parentFrame) != null) { + _ref._changeOperationsCounter(delta); + } + }; + + return ControllerActionFrame; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.DOM.InsertionBinding = (function(_super) { + + __extends(InsertionBinding, _super); + + InsertionBinding.prototype.isTwoWay = false; + + InsertionBinding.prototype.bindImmediately = false; + + function InsertionBinding(node, className, key, context, parentRenderer, invert) { + var result, + _this = this; + this.invert = invert != null ? invert : false; + this.placeholderNode = document.createComment("detached node " + (this.get('_batmanID'))); + result = InsertionBinding.__super__.constructor.apply(this, arguments); + Batman.DOM.onParseExit(this.node, function() { + _this.bind(); + if (_this.placeholderNode != null) { + return Batman.DOM.trackBinding(_this, _this.placeholderNode); + } + }); + result; + + } + + InsertionBinding.prototype.dataChange = function(value) { + var parentNode; + parentNode = this.placeholderNode.parentNode || this.node.parentNode; + if (!!value === !this.invert) { + if (!(this.node.parentNode != null)) { + Batman.DOM.insertBefore(parentNode, this.node, this.placeholderNode); + return parentNode.removeChild(this.placeholderNode); + } + } else { + parentNode.insertBefore(this.placeholderNode, this.node); + return Batman.DOM.removeNode(this.node); + } + }; + + InsertionBinding.prototype.die = function() { + if (this.dead) { + return; + } + InsertionBinding.__super__.die.apply(this, arguments); + if (!!this.get('filteredValue') === !this.invert) { + return Batman.DOM.destroyNode(this.placeholderNode); + } else { + return Batman.DOM.destroyNode(this.node); + } + }; + + return InsertionBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var isEmptyDataObject; + + isEmptyDataObject = function(obj) { + var name; + for (name in obj) { + return false; + } + return true; + }; + + Batman.extend(Batman, { + cache: {}, + uuid: 0, + expando: "batman" + Math.random().toString().replace(/\D/g, ''), + canDeleteExpando: (function() { + var div; + try { + div = document.createElement('div'); + return delete div.test; + } catch (e) { + return Batman.canDeleteExpando = false; + } + })(), + noData: { + "embed": true, + "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", + "applet": true + }, + hasData: function(elem) { + elem = (elem.nodeType ? Batman.cache[elem[Batman.expando]] : elem[Batman.expando]); + return !!elem && !isEmptyDataObject(elem); + }, + data: function(elem, name, data, pvt) { + var cache, getByName, id, internalKey, ret, thisCache; + if (!Batman.acceptData(elem)) { + return; + } + internalKey = Batman.expando; + getByName = typeof name === "string"; + cache = Batman.cache; + id = elem[Batman.expando]; + if ((!id || (pvt && id && (cache[id] && !cache[id][internalKey]))) && getByName && data === void 0) { + return; + } + if (!id) { + if (elem.nodeType !== 3) { + elem[Batman.expando] = id = ++Batman.uuid; + } else { + id = Batman.expando; + } + } + if (!cache[id]) { + cache[id] = {}; + } + if (typeof name === "object" || typeof name === "function") { + if (pvt) { + cache[id][internalKey] = Batman.extend(cache[id][internalKey], name); + } else { + cache[id] = Batman.extend(cache[id], name); + } + } + thisCache = cache[id]; + if (pvt) { + thisCache[internalKey] || (thisCache[internalKey] = {}); + thisCache = thisCache[internalKey]; + } + if (data !== void 0) { + thisCache[name] = data; + } + if (getByName) { + ret = thisCache[name]; + } else { + ret = thisCache; + } + return ret; + }, + removeData: function(elem, name, pvt) { + var cache, id, internalCache, internalKey, isNode, thisCache; + if (!Batman.acceptData(elem)) { + return; + } + internalKey = Batman.expando; + isNode = elem.nodeType; + cache = Batman.cache; + id = elem[Batman.expando]; + if (!cache[id]) { + return; + } + if (name) { + thisCache = pvt ? cache[id][internalKey] : cache[id]; + if (thisCache) { + delete thisCache[name]; + if (!isEmptyDataObject(thisCache)) { + return; + } + } + } + if (pvt) { + delete cache[id][internalKey]; + if (!isEmptyDataObject(cache[id])) { + return; + } + } + internalCache = cache[id][internalKey]; + if (Batman.canDeleteExpando || !cache.setInterval) { + delete cache[id]; + } else { + cache[id] = null; + } + if (internalCache) { + cache[id] = {}; + return cache[id][internalKey] = internalCache; + } else { + if (Batman.canDeleteExpando) { + return delete elem[Batman.expando]; + } else if (elem.removeAttribute) { + return elem.removeAttribute(Batman.expando); + } else { + return elem[Batman.expando] = null; + } + } + }, + _data: function(elem, name, data) { + return Batman.data(elem, name, data, true); + }, + acceptData: function(elem) { + var match; + if (elem.nodeName) { + match = Batman.noData[elem.nodeName.toLowerCase()]; + if (match) { + return !(match === true || elem.getAttribute("classid") !== match); + } + } + return true; + } + }); + +}).call(this); + +(function() { + var buntUndefined, defaultAndOr, + __slice = [].slice; + + buntUndefined = function(f) { + return function(value) { + if (typeof value === 'undefined') { + return void 0; + } else { + return f.apply(this, arguments); + } + }; + }; + + defaultAndOr = function(lhs, rhs) { + return lhs || rhs; + }; + + Batman.Filters = { + raw: buntUndefined(function(value, binding) { + binding.escapeValue = false; + return value; + }), + get: buntUndefined(function(value, key) { + if (value.get != null) { + return value.get(key); + } else { + return value[key]; + } + }), + equals: buntUndefined(function(lhs, rhs, binding) { + return lhs === rhs; + }), + and: function(lhs, rhs) { + return lhs && rhs; + }, + or: function(lhs, rhs, binding) { + return lhs || rhs; + }, + not: function(value, binding) { + return !!!value; + }, + matches: buntUndefined(function(value, searchFor) { + return value.indexOf(searchFor) !== -1; + }), + truncate: buntUndefined(function(value, length, end, binding) { + if (end == null) { + end = "..."; + } + if (!binding) { + binding = end; + end = "..."; + } + if (value.length > length) { + value = value.substr(0, length - end.length) + end; + } + return value; + }), + "default": function(value, defaultValue, binding) { + if ((value != null) && value !== '') { + return value; + } else { + return defaultValue; + } + }, + prepend: function(value, string, binding) { + return string + value; + }, + append: function(value, string, binding) { + return value + string; + }, + replace: buntUndefined(function(value, searchFor, replaceWith, flags, binding) { + if (!binding) { + binding = flags; + flags = void 0; + } + if (flags === void 0) { + return value.replace(searchFor, replaceWith); + } else { + return value.replace(searchFor, replaceWith, flags); + } + }), + downcase: buntUndefined(function(value) { + return value.toLowerCase(); + }), + upcase: buntUndefined(function(value) { + return value.toUpperCase(); + }), + pluralize: buntUndefined(function(string, count, includeCount, binding) { + if (!binding) { + binding = includeCount; + includeCount = true; + if (!binding) { + binding = count; + count = void 0; + } + } + if (count) { + return Batman.helpers.pluralize(count, string, void 0, includeCount); + } else { + return Batman.helpers.pluralize(string); + } + }), + humanize: buntUndefined(function(string, binding) { + return Batman.helpers.humanize(string); + }), + join: buntUndefined(function(value, withWhat, binding) { + if (withWhat == null) { + withWhat = ''; + } + if (!binding) { + binding = withWhat; + withWhat = ''; + } + return value.join(withWhat); + }), + sort: buntUndefined(function(value) { + return value.sort(); + }), + map: buntUndefined(function(value, key) { + return value.map(function(x) { + return Batman.get(x, key); + }); + }), + has: function(set, item) { + if (set == null) { + return false; + } + return Batman.contains(set, item); + }, + first: buntUndefined(function(value) { + return value[0]; + }), + meta: buntUndefined(function(value, keypath) { + Batman.developer.assert(value.meta, "Error, value doesn't have a meta to filter on!"); + return value.meta.get(keypath); + }), + interpolate: function(string, interpolationKeypaths, binding) { + var k, v, values; + if (!binding) { + binding = interpolationKeypaths; + interpolationKeypaths = void 0; + } + if (!string) { + return; + } + values = {}; + for (k in interpolationKeypaths) { + v = interpolationKeypaths[k]; + values[k] = this.get(v); + if (!(values[k] != null)) { + Batman.developer.warn("Warning! Undefined interpolation key " + k + " for interpolation", string); + values[k] = ''; + } + } + return Batman.helpers.interpolate(string, values); + }, + withArguments: function() { + var binding, block, curryArgs, _i; + block = arguments[0], curryArgs = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), binding = arguments[_i++]; + if (!block) { + return; + } + return function() { + var regularArgs; + regularArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + return block.call.apply(block, [this].concat(__slice.call(curryArgs), __slice.call(regularArgs))); + }; + }, + routeToAction: buntUndefined(function(model, action) { + var params; + params = Batman.Dispatcher.paramsFromArgument(model); + params.action = action; + return params; + }), + escape: buntUndefined(Batman.escapeHTML) + }; + + (function() { + var k, _i, _len, _ref, _results; + _ref = ['capitalize', 'singularize', 'underscore', 'camelize']; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + k = _ref[_i]; + _results.push(Batman.Filters[k] = buntUndefined(Batman.helpers[k])); + } + return _results; + })(); + + Batman.developer.addFilters(); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.RenderContext = (function() { + var ContextProxy; + + RenderContext.deProxy = function(object) { + if ((object != null) && object.isContextProxy) { + return object.get('proxiedObject'); + } else { + return object; + } + }; + + RenderContext.root = function() { + var root; + if (Batman.currentApp != null) { + root = Batman.currentApp.get('_renderContext'); + } + return root != null ? root : root = this.base; + }; + + RenderContext.prototype.windowWrapper = { + window: Batman.container + }; + + function RenderContext(object, parent) { + this.object = object; + this.parent = parent; + } + + RenderContext.prototype.findKey = function(key) { + var base, currentNode, val; + base = key.split('.')[0].split('|')[0].trim(); + currentNode = this; + while (currentNode) { + val = Batman.get(currentNode.object, base); + if (typeof val !== 'undefined') { + val = Batman.get(currentNode.object, key); + return [val, currentNode.object].map(this.constructor.deProxy); + } + currentNode = currentNode.parent; + } + return [Batman.get(this.windowWrapper, key), this.windowWrapper]; + }; + + RenderContext.prototype.get = function(key) { + return this.findKey(key)[0]; + }; + + RenderContext.prototype.contextForKey = function(key) { + return this.findKey(key)[1]; + }; + + RenderContext.prototype.descend = function(object, scopedKey) { + var oldObject; + if (scopedKey) { + oldObject = object; + object = new Batman.Object(); + object[scopedKey] = oldObject; + } + return new this.constructor(object, this); + }; + + RenderContext.prototype.descendWithKey = function(key, scopedKey) { + var proxy; + proxy = new ContextProxy(this, key); + return this.descend(proxy, scopedKey); + }; + + RenderContext.prototype.chain = function() { + var parent, x; + x = []; + parent = this; + while (parent) { + x.push(parent.object); + parent = parent.parent; + } + return x; + }; + + RenderContext.ContextProxy = ContextProxy = (function(_super) { + + __extends(ContextProxy, _super); + + ContextProxy.prototype.isContextProxy = true; + + ContextProxy.accessor('proxiedObject', function() { + return this.binding.get('filteredValue'); + }); + + ContextProxy.accessor({ + get: function(key) { + return this.get("proxiedObject." + key); + }, + set: function(key, value) { + return this.set("proxiedObject." + key, value); + }, + unset: function(key) { + return this.unset("proxiedObject." + key); + } + }); + + function ContextProxy(renderContext, keyPath, localKey) { + this.renderContext = renderContext; + this.keyPath = keyPath; + this.localKey = localKey; + this.binding = new Batman.DOM.AbstractBinding(void 0, this.keyPath, this.renderContext); + } + + return ContextProxy; + + })(Batman.Object); + + return RenderContext; + + }).call(this); + + Batman.RenderContext.base = new Batman.RenderContext(Batman.RenderContext.prototype.windowWrapper); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }; + + Batman.ViewStore = (function(_super) { + + __extends(ViewStore, _super); + + ViewStore.prefix = 'views'; + + ViewStore.fetchFromRemote = true; + + function ViewStore() { + ViewStore.__super__.constructor.apply(this, arguments); + this._viewContents = {}; + this._requestedPaths = new Batman.SimpleSet; + } + + ViewStore.prototype.propertyClass = Batman.Property; + + ViewStore.prototype.fetchView = function(path) { + var _this = this; + return new Batman.Request({ + url: Batman.Navigator.normalizePath(this.constructor.prefix, "" + path + ".html"), + type: 'html', + success: function(response) { + return _this.set(path, response); + }, + error: function(response) { + throw new Error("Could not load view from " + path); + } + }); + }; + + ViewStore.accessor({ + 'final': true, + get: function(path) { + var contents; + if (path[0] !== '/') { + return this.get("/" + path); + } + if (this._viewContents[path]) { + return this._viewContents[path]; + } + if (this._requestedPaths.has(path)) { + return; + } + if (contents = this._sourceFromDOM(path)) { + return contents; + } + if (this.constructor.fetchFromRemote) { + this.fetchView(path); + } else { + throw new Error("Couldn't find view source for \'" + path + "\'!"); + } + }, + set: function(path, content) { + if (path[0] !== '/') { + return this.set("/" + path, content); + } + this._requestedPaths.add(path); + return this._viewContents[path] = content; + } + }); + + ViewStore.prototype.prefetch = function(path) { + this.get(path); + return true; + }; + + ViewStore.prototype._sourceFromDOM = function(path) { + var node, relativePath; + relativePath = path.slice(1); + if (node = Batman.DOM.querySelector(document, "[data-defineview*='" + relativePath + "']")) { + Batman.setImmediate(function() { + var _ref; + return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; + }); + return Batman.DOM.defineView(path, node); + } + }; + + return ViewStore; + + })(Batman.Object); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.View = (function(_super) { + + __extends(View, _super); + + View.YieldStorage = (function(_super1) { + + __extends(YieldStorage, _super1); + + function YieldStorage() { + return YieldStorage.__super__.constructor.apply(this, arguments); + } + + YieldStorage.wrapAccessor(function(core) { + return { + get: function(key) { + var val; + val = core.get.call(this, key); + if (!(val != null)) { + val = this.set(key, []); + } + return val; + } + }; + }); + + return YieldStorage; + + })(Batman.Hash); + + View.store = new Batman.ViewStore(); + + View.option = function() { + var keys, + _this = this; + keys = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + keys.forEach(function(key) { + return _this.accessor(_this.prototype._argumentBindingKey(key), function(bindingKey) { + var context, keyPath, node, _ref; + if (!((node = this.get('node')) && (context = this.get('context')))) { + return; + } + keyPath = node.getAttribute(("data-view-" + key).toLowerCase()); + if (keyPath == null) { + return; + } + if ((_ref = this[bindingKey]) != null) { + _ref.die(); + } + return this[bindingKey] = new Batman.DOM.ViewArgumentBinding(node, keyPath, context); + }); + }); + return this.accessor.apply(this, __slice.call(keys).concat([function(key) { + var _ref; + return (_ref = this.get(this._argumentBindingKey(key))) != null ? _ref.get('filteredValue') : void 0; + }])); + }; + + View.prototype.isView = true; + + View.prototype.cache = true; + + View.prototype._rendered = false; + + View.prototype.node = null; + + View.prototype.event('ready').oneShot = true; + + View.accessor('html', { + get: function() { + var source; + if (this.html && this.html.length > 0) { + return this.html; + } + if (!(source = this.get('source'))) { + return; + } + source = Batman.Navigator.normalizePath(source); + return this.html = this.constructor.store.get(source); + }, + set: function(_, html) { + return this.html = html; + } + }); + + View.accessor('node', { + get: function() { + var html; + if (this.node == null) { + html = this.get('html'); + if (!(html && html.length > 0)) { + return; + } + this.node = document.createElement('div'); + this._setNodeOwner(this.node); + Batman.setInnerHTML(this.node, html); + } + return this.node; + }, + set: function(_, node) { + var updateHTML, + _this = this; + this.node = node; + this._setNodeOwner(node); + updateHTML = function(html) { + if (html != null) { + Batman.setInnerHTML(_this.node, html); + return _this.forget('html', updateHTML); + } + }; + this.observeAndFire('html', updateHTML); + return node; + } + }); + + View.accessor('yields', function() { + return new this.constructor.YieldStorage; + }); + + View.accessor('fetched?', function() { + return this.get('source') != null; + }); + + View.accessor('readyToRender', function() { + var _ref; + return this.get('node') && (this.get('fetched?') ? ((_ref = this.get('html')) != null ? _ref.length : void 0) > 0 : true); + }); + + function View(options) { + var context, + _this = this; + if (options == null) { + options = {}; + } + context = options.context; + if (context) { + if (!(context instanceof Batman.RenderContext)) { + context = Batman.RenderContext.root().descend(context); + } + } else { + context = Batman.RenderContext.root(); + } + options.context = context.descend(this); + View.__super__.constructor.call(this, options); + Batman.Property.withoutTracking(function() { + return _this.observeAndFire('readyToRender', function(ready) { + if (ready) { + return _this.render(); + } + }); + }); + } + + View.prototype.render = function() { + var node, + _this = this; + if (this._rendered) { + return; + } + this._rendered = true; + this._renderer = new Batman.Renderer(node = this.get('node'), this.get('context'), this); + return this._renderer.on('rendered', function() { + return _this.fire('ready', node); + }); + }; + + View.prototype.isInDOM = function() { + var node; + if ((node = this.get('node'))) { + return (node.parentNode != null) || this.get('yields').some(function(name, nodes) { + var _i, _len; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i].node; + if (node.parentNode != null) { + return true; + } + } + return false; + }); + } else { + return false; + } + }; + + View.prototype.applyYields = function() { + return this.get('yields').forEach(function(name, nodes) { + var action, node, yieldObject, _i, _len, _ref, _results; + yieldObject = Batman.DOM.Yield.withName(name); + _results = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + _ref = nodes[_i], node = _ref.node, action = _ref.action; + _results.push(yieldObject[action](node)); + } + return _results; + }); + }; + + View.prototype.retractYields = function() { + return this.get('yields').forEach(function(name, nodes) { + var node, _i, _len, _ref, _results; + _results = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i].node; + _results.push((_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0); + } + return _results; + }); + }; + + View.prototype.pushYieldAction = function(key, action, node) { + this._setNodeYielder(node); + return this.get("yields").get(key).push({ + node: node, + action: action + }); + }; + + View.prototype._argumentBindingKey = function(key) { + return "_" + key + "ArgumentBinding"; + }; + + View.prototype._setNodeOwner = function(node) { + return Batman._data(node, 'view', this); + }; + + View.prototype._setNodeYielder = function(node) { + return Batman._data(node, 'yielder', this); + }; + + View.prototype.on('ready', function() { + return typeof this.ready === "function" ? this.ready.apply(this, arguments) : void 0; + }); + + View.prototype.on('appear', function() { + return typeof this.viewDidAppear === "function" ? this.viewDidAppear.apply(this, arguments) : void 0; + }); + + View.prototype.on('disappear', function() { + return typeof this.viewDidDisappear === "function" ? this.viewDidDisappear.apply(this, arguments) : void 0; + }); + + View.prototype.on('beforeAppear', function() { + return typeof this.viewWillAppear === "function" ? this.viewWillAppear.apply(this, arguments) : void 0; + }); + + View.prototype.on('beforeDisappear', function() { + return typeof this.viewWillDisappear === "function" ? this.viewWillDisappear.apply(this, arguments) : void 0; + }); + + return View; + + }).call(this, Batman.Object); + +}).call(this); + +(function() { + var Yield, + __hasProp = {}.hasOwnProperty, + __extends = 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; }, + __slice = [].slice; + + Batman.DOM.Yield = Yield = (function(_super) { + + __extends(Yield, _super); + + Yield.yields = {}; + + Yield.queued = function(fn) { + return function() { + var args, handler, + _this = this; + args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + if (this.containerNode != null) { + return fn.apply(this, args); + } else { + return handler = this.observe('containerNode', function() { + var result; + result = fn.apply(_this, args); + _this.forget('containerNode', handler); + return result; + }); + } + }; + }; + + Yield.reset = function() { + return this.yields = {}; + }; + + Yield.withName = function(name) { + var _base; + (_base = this.yields)[name] || (_base[name] = new this({ + name: name + })); + return this.yields[name]; + }; + + Yield.forEach = function(f) { + var name, yieldObject, _ref; + _ref = this.yields; + for (name in _ref) { + yieldObject = _ref[name]; + f(yieldObject); + } + }; + + Yield.clearAll = function() { + return this.forEach(function(yieldObject) { + return yieldObject.clear(); + }); + }; + + Yield.cycleAll = function() { + return this.forEach(function(yieldObject) { + return yieldObject.cycle(); + }); + }; + + Yield.clearAllStale = function() { + return this.forEach(function(yieldObject) { + return yieldObject.clearStale(); + }); + }; + + function Yield() { + this.cycle(); + } + + Yield.prototype.cycle = function() { + return this.currentVersionNodes = []; + }; + + Yield.prototype.clear = Yield.queued(function() { + var child, _i, _len, _ref, _results; + this.cycle(); + _ref = (function() { + var _j, _len, _ref, _results1; + _ref = this.containerNode.childNodes; + _results1 = []; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + child = _ref[_j]; + _results1.push(child); + } + return _results1; + }).call(this); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(Batman.removeOrDestroyNode(child)); + } + return _results; + }); + + Yield.prototype.clearStale = Yield.queued(function() { + var child, _i, _len, _ref, _results; + _ref = (function() { + var _j, _len, _ref, _results1; + _ref = this.containerNode.childNodes; + _results1 = []; + for (_j = 0, _len = _ref.length; _j < _len; _j++) { + child = _ref[_j]; + _results1.push(child); + } + return _results1; + }).call(this); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + if (!~this.currentVersionNodes.indexOf(child)) { + _results.push(Batman.removeOrDestroyNode(child)); + } + } + return _results; + }); + + Yield.prototype.append = Yield.queued(function(node) { + this.currentVersionNodes.push(node); + return Batman.appendChild(this.containerNode, node, true); + }); + + Yield.prototype.replace = Yield.queued(function(node) { + this.clear(); + return this.append(node); + }); + + return Yield; + + })(Batman.Object); + +}).call(this); + +(function() { + + + +}).call(this); \ No newline at end of file diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee new file mode 100644 index 0000000..2d9953d --- /dev/null +++ b/javascripts/dashing.coffee @@ -0,0 +1,96 @@ +#= require jquery +#= require es5-shim +#= require batman +#= require batman.jquery + + +Batman.Filters.prettyNumber = (num) -> + num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") unless isNaN(num) + +Batman.Filters.dashize = (str) -> + dashes_rx1 = /([A-Z]+)([A-Z][a-z])/g; + dashes_rx2 = /([a-z\d])([A-Z])/g; + + return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace('_', '-').toLowerCase() + +Batman.Filters.shortenedNumber = (num) -> + return if isNaN(num) + if num >= 1000000000 + (num / 1000000000).toFixed(1) + 'B' + else if num >= 1000000 + (num / 1000000).toFixed(1) + 'M' + else if num >= 1000 + (num / 1000).toFixed(1) + 'K' + else + num + +class window.Dashing extends Batman.App + @root -> + +class Dashing.Widget extends Batman.View + constructor: -> + # Set the view path + @constructor::source = Batman.Filters.underscore(@constructor.name) + super + + @mixin($(@node).data()) + Dashing.widgets[@id] ||= [] + Dashing.widgets[@id].push(@) + @mixin(Dashing.lastEvents[@id]) # in case the events from the server came before the widget was rendered + + type = Batman.Filters.dashize(@view) + $(@node).addClass("widget widget-#{type} #{@id}") + + + @::on 'ready', -> + Dashing.Widget.fire 'ready' + + onData: (data) => + @mixin(data) + + +Dashing.AnimatedValue = + get: Batman.Property.defaultAccessor.get + set: (k, to) -> + if isNaN(to) + @[k] = to + else + timer = "interval_#{k}" + num = if !isNaN(@[k]) then @[k] else 0 + unless @[timer] || num == to + up = to > num + num_interval = Math.abs(num - to) / 90 + @[timer] = + setInterval => + num = if up then Math.ceil(num+num_interval) else Math.floor(num-num_interval) + if (up && num > to) || (!up && num < to) + num = to + clearInterval(@[timer]) + @[timer] = null + delete @[timer] + @[k] = num + @set k, to + @[k] = num + +Dashing.widgets = widgets = {} +Dashing.lastEvents = lastEvents = {} + +source = new EventSource('/events') +source.addEventListener 'open', (e) -> + console.log("Connection opened") + +source.addEventListener 'error', (e)-> + console.log("Connection error") + if (e.readyState == EventSource.CLOSED) + console.log("Connection closed") + +source.addEventListener 'message', (e) => + data = JSON.parse(e.data) + lastEvents[data.id] = data + if widgets[data.id]?.length > 0 + for widget in widgets[data.id] + widget.onData(data) + + +$(document).ready -> + Dashing.run() diff --git a/javascripts/es5-shim.js b/javascripts/es5-shim.js new file mode 100644 index 0000000..ce79780 --- /dev/null +++ b/javascripts/es5-shim.js @@ -0,0 +1,1021 @@ +// vim: ts=4 sts=4 sw=4 expandtab +// -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License +// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project) +// -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA +// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License +// -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License +// -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License +// -- kossnocorp Sasha Koss XXX TODO License or CLA +// -- bryanforbes Bryan Forbes XXX TODO License or CLA +// -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence +// -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License +// -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License +// -- bbqsrc Brendan Molloy XXX TODO License or CLA +// -- iwyg XXX TODO License or CLA +// -- DomenicDenicola Domenic Denicola XXX TODO License or CLA +// -- xavierm02 Montillet Xavier XXX TODO License or CLA +// -- Raynos Raynos XXX TODO License or CLA +// -- samsonjs Sami Samhuri XXX TODO License or CLA +// -- rwldrn Rick Waldron Copyright (C) 2011 MIT License +// -- lexer Alexey Zakharov XXX TODO License or CLA + +/*! + Copyright (c) 2009, 280 North Inc. http://280north.com/ + MIT License. http://github.com/280north/narwhal/blob/master/README.md +*/ + +// Module systems magic dance +(function (definition) { + // RequireJS + if (typeof define == "function") { + define(definition); + // CommonJS and + ") + + +$ -> + $('#save-gridster').leanModal() + + $('#save-gridster').click -> + $('#save-gridster').slideUp() \ No newline at end of file diff --git a/templates/project/assets/javascripts/gridster/jquery.collision.js b/templates/project/assets/javascripts/gridster/jquery.collision.js new file mode 100755 index 0000000..5d37c61 --- /dev/null +++ b/templates/project/assets/javascripts/gridster/jquery.collision.js @@ -0,0 +1,224 @@ +/* + * jquery.collision + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function($, window, document, undefined){ + + var defaults = { + colliders_context: document.body + // ,on_overlap: function(collider_data){}, + // on_overlap_start : function(collider_data){}, + // on_overlap_stop : function(collider_data){} + }; + + + /** + * Detects collisions between a DOM element against other DOM elements or + * Coords objects. + * + * @class Collision + * @uses Coords + * @param {HTMLElement} el The jQuery wrapped HTMLElement. + * @param {HTMLElement|Array} colliders Can be a jQuery collection + * of HTMLElements or an Array of Coords instances. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {Function} [options.on_overlap_start] Executes a function the first + * time each `collider ` is overlapped. + * @param {Function} [options.on_overlap_stop] Executes a function when a + * `collider` is no longer collided. + * @param {Function} [options.on_overlap] Executes a function when the + * mouse is moved during the collision. + * @return {Object} Collision instance. + * @constructor + */ + function Collision(el, colliders, options) { + this.options = $.extend(defaults, options); + this.$element = el; + this.last_colliders = []; + this.last_colliders_coords = []; + if (typeof colliders === 'string' || colliders instanceof jQuery) { + this.$colliders = $(colliders, + this.options.colliders_context).not(this.$element); + }else{ + this.colliders = $(colliders); + } + + this.init(); + } + + + var fn = Collision.prototype; + + + fn.init = function() { + this.find_collisions(); + }; + + + fn.overlaps = function(a, b) { + var x = false; + var y = false; + + if ((b.x1 >= a.x1 && b.x1 <= a.x2) || + (b.x2 >= a.x1 && b.x2 <= a.x2) || + (a.x1 >= b.x1 && a.x2 <= b.x2) + ) { x = true; } + + if ((b.y1 >= a.y1 && b.y1 <= a.y2) || + (b.y2 >= a.y1 && b.y2 <= a.y2) || + (a.y1 >= b.y1 && a.y2 <= b.y2) + ) { y = true; } + + return (x && y); + }; + + + fn.detect_overlapping_region = function(a, b){ + var regionX = ''; + var regionY = ''; + + if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } + if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } + if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } + if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } + + return (regionX + regionY) || 'C'; + }; + + + fn.calculate_overlapped_area_coords = function(a, b){ + var x1 = Math.max(a.x1, b.x1); + var y1 = Math.max(a.y1, b.y1); + var x2 = Math.min(a.x2, b.x2); + var y2 = Math.min(a.y2, b.y2); + + return $({ + left: x1, + top: y1, + width : (x2 - x1), + height: (y2 - y1) + }).coords().get(); + }; + + + fn.calculate_overlapped_area = function(coords){ + return (coords.width * coords.height); + }; + + + fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ + var last = this.last_colliders_coords; + + for (var i = 0, il = last.length; i < il; i++) { + if ($.inArray(last[i], new_colliders_coords) === -1) { + start_callback.call(this, last[i]); + } + } + + for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { + if ($.inArray(new_colliders_coords[j], last) === -1) { + stop_callback.call(this, new_colliders_coords[j]); + } + + } + }; + + + fn.find_collisions = function(player_data_coords){ + var self = this; + var colliders_coords = []; + var colliders_data = []; + var $colliders = (this.colliders || this.$colliders); + var count = $colliders.length; + var player_coords = self.$element.coords() + .update(player_data_coords || false).get(); + + while(count--){ + var $collider = self.$colliders ? + $($colliders[count]) : $colliders[count]; + var $collider_coords_ins = ($collider.isCoords) ? + $collider : $collider.coords(); + var collider_coords = $collider_coords_ins.get(); + var overlaps = self.overlaps(player_coords, collider_coords); + + if (!overlaps) { + continue; + } + + var region = self.detect_overlapping_region( + player_coords, collider_coords); + + //todo: make this an option + if (region === 'C'){ + var area_coords = self.calculate_overlapped_area_coords( + player_coords, collider_coords); + var area = self.calculate_overlapped_area(area_coords); + var collider_data = { + area: area, + area_coords : area_coords, + region: region, + coords: collider_coords, + player_coords: player_coords, + el: $collider + }; + + if (self.options.on_overlap) { + self.options.on_overlap.call(this, collider_data); + } + colliders_coords.push($collider_coords_ins); + colliders_data.push(collider_data); + } + } + + if (self.options.on_overlap_stop || self.options.on_overlap_start) { + this.manage_colliders_start_stop(colliders_coords, + self.options.on_overlap_stop, self.options.on_overlap_start); + } + + this.last_colliders_coords = colliders_coords; + + return colliders_data; + }; + + + fn.get_closest_colliders = function(player_data_coords){ + var colliders = this.find_collisions(player_data_coords); + var min_area = 100; + colliders.sort(function(a, b){ + if (a.area <= min_area) { + return 1; + } + + /* if colliders are being overlapped by the "C" (center) region, + * we have to set a lower index in the array to which they are placed + * above in the grid. */ + if (a.region === 'C' && b.region === 'C') { + if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { + return - 1; + }else{ + return 1; + } + } + + if (a.area < b.area){ + return 1; + } + + return 1; + }); + return colliders; + }; + + + //jQuery adapter + $.fn.collision = function(collider, options) { + return new Collision( this, collider, options ); + }; + + +}(jQuery, window, document)); diff --git a/templates/project/assets/javascripts/gridster/jquery.coords.js b/templates/project/assets/javascripts/gridster/jquery.coords.js new file mode 100755 index 0000000..e3bd5e6 --- /dev/null +++ b/templates/project/assets/javascripts/gridster/jquery.coords.js @@ -0,0 +1,108 @@ +/* + * jquery.coords + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function($, window, document, undefined){ + /** + * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) + * to simulate DOM elements on the screen. + * Coords is used by Gridster to create a faux grid with any DOM element can + * collide. + * + * @class Coords + * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, + * top, width and height properties. + * @return {Object} Coords instance. + * @constructor + */ + function Coords(obj) { + if (obj[0] && $.isPlainObject(obj[0])) { + this.data = obj[0]; + }else { + this.el = obj; + } + + this.isCoords = true; + this.coords = {}; + this.init(); + return this; + } + + + var fn = Coords.prototype; + + + fn.init = function(){ + this.set(); + this.original_coords = this.get(); + }; + + + fn.set = function(update, not_update_offsets) { + var el = this.el; + + if (el && !update) { + this.data = el.offset(); + this.data.width = el.width(); + this.data.height = el.height(); + } + + if (el && update && !not_update_offsets) { + var offset = el.offset(); + this.data.top = offset.top; + this.data.left = offset.left; + } + + var d = this.data; + + this.coords.x1 = d.left; + this.coords.y1 = d.top; + this.coords.x2 = d.left + d.width; + this.coords.y2 = d.top + d.height; + this.coords.cx = d.left + (d.width / 2); + this.coords.cy = d.top + (d.height / 2); + this.coords.width = d.width; + this.coords.height = d.height; + this.coords.el = el || false ; + + return this; + }; + + + fn.update = function(data){ + if (!data && !this.el) { + return this; + } + + if (data) { + var new_data = $.extend({}, this.data, data); + this.data = new_data; + return this.set(true, true); + } + + this.set(true); + return this; + }; + + + fn.get = function(){ + return this.coords; + }; + + + //jQuery adapter + $.fn.coords = function() { + if (this.data('coords') ) { + return this.data('coords'); + } + + var ins = new Coords(this, arguments[0]); + this.data('coords', ins); + return ins; + }; + +}(jQuery, window, document)); diff --git a/templates/project/assets/javascripts/gridster/jquery.draggable.js b/templates/project/assets/javascripts/gridster/jquery.draggable.js new file mode 100755 index 0000000..52a18d4 --- /dev/null +++ b/templates/project/assets/javascripts/gridster/jquery.draggable.js @@ -0,0 +1,327 @@ +/* + * jquery.draggable + * https://github.com/ducksboard/gridster.js + * + * Copyright (c) 2012 ducksboard + * Licensed under the MIT licenses. + */ + +;(function($, window, document, undefined){ + + var defaults = { + items: '.gs_w', + distance: 1, + limit: true, + offset_left: 0, + autoscroll: true + // ,drag: function(e){}, + // start : function(e, ui){}, + // stop : function(e){} + }; + + var $window = $(window); + var isTouch = !!('ontouchstart' in window); + var pointer_events = { + start: isTouch ? 'touchstart' : 'mousedown.draggable', + move: isTouch ? 'touchmove' : 'mousemove.draggable', + end: isTouch ? 'touchend' : 'mouseup.draggable' + }; + + /** + * Basic drag implementation for DOM elements inside a container. + * Provide start/stop/drag callbacks. + * + * @class Draggable + * @param {HTMLElement} el The HTMLelement that contains all the widgets + * to be dragged. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.items] Define who will + * be the draggable items. Can be a CSS Selector String or a + * collection of HTMLElements. + * @param {Number} [options.distance] Distance in pixels after mousedown + * the mouse must move before dragging should start. + * @param {Boolean} [options.limit] Constrains dragging to the width of + * the container + * @param {offset_left} [options.offset_left] Offset added to the item + * that is being dragged. + * @param {Number} [options.drag] Executes a callback when the mouse is + * moved during the dragging. + * @param {Number} [options.start] Executes a callback when the drag + * starts. + * @param {Number} [options.stop] Executes a callback when the drag stops. + * @return {Object} Returns `el`. + * @constructor + */ + function Draggable(el, options) { + this.options = $.extend({}, defaults, options); + this.$body = $(document.body); + this.$container = $(el); + this.$dragitems = $(this.options.items, this.$container); + this.is_dragging = false; + this.player_min_left = 0 + this.options.offset_left; + this.init(); + } + + var fn = Draggable.prototype; + + fn.init = function() { + this.calculate_positions(); + this.$container.css('position', 'relative'); + this.enable(); + + $(window).bind('resize', + throttle($.proxy(this.calculate_positions, this), 200)); + }; + + + fn.get_actual_pos = function($el) { + var pos = $el.position(); + return pos; + }; + + + fn.get_mouse_pos = function(e) { + if (isTouch) { + var oe = e.originalEvent; + e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; + }; + + return { + left: e.clientX, + top: e.clientY + }; + }; + + + fn.get_offset = function(e) { + e.preventDefault(); + var mouse_actual_pos = this.get_mouse_pos(e); + var diff_x = Math.round( + mouse_actual_pos.left - this.mouse_init_pos.left); + var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); + + var left = Math.round(this.el_init_offset.left + diff_x - this.baseX); + var top = Math.round( + this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset); + + if (this.options.limit) { + if (left > this.player_max_left) { + left = this.player_max_left; + }else if(left < this.player_min_left) { + left = this.player_min_left; + } + } + + return { + left: left, + top: top, + mouse_left: mouse_actual_pos.left, + mouse_top: mouse_actual_pos.top + }; + }; + + + fn.manage_scroll = function(offset) { + /* scroll document */ + var nextScrollTop; + var scrollTop = $window.scrollTop(); + var min_window_y = scrollTop; + var max_window_y = min_window_y + this.window_height; + + var mouse_down_zone = max_window_y - 50; + var mouse_up_zone = min_window_y + 50; + + var abs_mouse_left = offset.mouse_left; + var abs_mouse_top = min_window_y + offset.mouse_top; + + var max_player_y = (this.doc_height - this.window_height + + this.player_height); + + if (abs_mouse_top >= mouse_down_zone) { + nextScrollTop = scrollTop + 30; + if (nextScrollTop < max_player_y) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset + 30; + } + }; + + if (abs_mouse_top <= mouse_up_zone) { + nextScrollTop = scrollTop - 30; + if (nextScrollTop > 0) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset - 30; + } + }; + } + + + fn.calculate_positions = function(e) { + this.window_height = $window.height(); + } + + + fn.drag_handler = function(e) { + var node = e.target.nodeName; + + if (e.which !== 1 && !isTouch) { + return; + } + + if (node === 'INPUT' || node === 'TEXTAREA' || node === 'SELECT' || + node === 'BUTTON') { + return; + }; + + var self = this; + var first = true; + this.$player = $(e.currentTarget); + + this.el_init_pos = this.get_actual_pos(this.$player); + this.mouse_init_pos = this.get_mouse_pos(e); + this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; + + this.$body.on(pointer_events.move, function(mme){ + var mouse_actual_pos = self.get_mouse_pos(mme); + var diff_x = Math.abs( + mouse_actual_pos.left - self.mouse_init_pos.left); + var diff_y = Math.abs( + mouse_actual_pos.top - self.mouse_init_pos.top); + if (!(diff_x > self.options.distance || + diff_y > self.options.distance) + ) { + return false; + } + + if (first) { + first = false; + self.on_dragstart.call(self, mme); + return false; + } + + if (self.is_dragging == true) { + self.on_dragmove.call(self, mme); + } + + return false; + }); + }; + + + fn.on_dragstart = function(e) { + e.preventDefault(); + this.drag_start = true; + this.is_dragging = true; + var offset = this.$container.offset(); + this.baseX = Math.round(offset.left); + this.baseY = Math.round(offset.top); + this.doc_height = $(document).height(); + + if (this.options.helper === 'clone') { + this.$helper = this.$player.clone() + .appendTo(this.$container).addClass('helper'); + this.helper = true; + }else{ + this.helper = false; + } + this.scrollOffset = 0; + this.el_init_offset = this.$player.offset(); + this.player_width = this.$player.width(); + this.player_height = this.$player.height(); + this.player_max_left = (this.$container.width() - this.player_width + + this.options.offset_left); + + if (this.options.start) { + this.options.start.call(this.$player, e, { + helper: this.helper ? this.$helper : this.$player + }); + } + return false; + }; + + + fn.on_dragmove = function(e) { + var offset = this.get_offset(e); + + this.options.autoscroll && this.manage_scroll(offset); + + (this.helper ? this.$helper : this.$player).css({ + 'position': 'absolute', + 'left' : offset.left, + 'top' : offset.top + }); + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.drag) { + this.options.drag.call(this.$player, e, ui); + } + return false; + }; + + + fn.on_dragstop = function(e) { + var offset = this.get_offset(e); + this.drag_start = false; + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.stop) { + this.options.stop.call(this.$player, e, ui); + } + + if (this.helper) { + this.$helper.remove(); + } + + return false; + }; + + + fn.enable = function(){ + this.$container.on(pointer_events.start, this.options.items, $.proxy( + this.drag_handler, this)); + + this.$body.on(pointer_events.end, $.proxy(function(e) { + this.is_dragging = false; + this.$body.off(pointer_events.move); + if (this.drag_start) { + this.on_dragstop(e); + } + }, this)); + }; + + + fn.disable = function(){ + this.$container.off(pointer_events.start); + this.$body.off(pointer_events.end); + }; + + + fn.destroy = function(){ + this.disable(); + $.removeData(this.$container, 'draggable'); + }; + + + //jQuery adapter + $.fn.drag = function ( options ) { + return this.each(function () { + if (!$.data(this, 'drag')) { + $.data(this, 'drag', new Draggable( this, options )); + } + }); + }; + + +}(jQuery, window, document)); diff --git a/templates/project/assets/javascripts/gridster/jquery.gridster.js b/templates/project/assets/javascripts/gridster/jquery.gridster.js new file mode 100755 index 0000000..9099177 --- /dev/null +++ b/templates/project/assets/javascripts/gridster/jquery.gridster.js @@ -0,0 +1,2890 @@ +/*! gridster.js - v0.1.0 - 2012-08-14 +* http://gridster.net/ +* Copyright (c) 2012 ducksboard; Licensed MIT */ + +;(function($, window, document, undefined){ + /** + * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) + * to simulate DOM elements on the screen. + * Coords is used by Gridster to create a faux grid with any DOM element can + * collide. + * + * @class Coords + * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, + * top, width and height properties. + * @return {Object} Coords instance. + * @constructor + */ + function Coords(obj) { + if (obj[0] && $.isPlainObject(obj[0])) { + this.data = obj[0]; + }else { + this.el = obj; + } + + this.isCoords = true; + this.coords = {}; + this.init(); + return this; + } + + + var fn = Coords.prototype; + + + fn.init = function(){ + this.set(); + this.original_coords = this.get(); + }; + + + fn.set = function(update, not_update_offsets) { + var el = this.el; + + if (el && !update) { + this.data = el.offset(); + this.data.width = el.width(); + this.data.height = el.height(); + } + + if (el && update && !not_update_offsets) { + var offset = el.offset(); + this.data.top = offset.top; + this.data.left = offset.left; + } + + var d = this.data; + + this.coords.x1 = d.left; + this.coords.y1 = d.top; + this.coords.x2 = d.left + d.width; + this.coords.y2 = d.top + d.height; + this.coords.cx = d.left + (d.width / 2); + this.coords.cy = d.top + (d.height / 2); + this.coords.width = d.width; + this.coords.height = d.height; + this.coords.el = el || false ; + + return this; + }; + + + fn.update = function(data){ + if (!data && !this.el) { + return this; + } + + if (data) { + var new_data = $.extend({}, this.data, data); + this.data = new_data; + return this.set(true, true); + } + + this.set(true); + return this; + }; + + + fn.get = function(){ + return this.coords; + }; + + + //jQuery adapter + $.fn.coords = function() { + if (this.data('coords') ) { + return this.data('coords'); + } + + var ins = new Coords(this, arguments[0]); + this.data('coords', ins); + return ins; + }; + +}(jQuery, window, document)); + +;(function($, window, document, undefined){ + + var defaults = { + colliders_context: document.body + // ,on_overlap: function(collider_data){}, + // on_overlap_start : function(collider_data){}, + // on_overlap_stop : function(collider_data){} + }; + + + /** + * Detects collisions between a DOM element against other DOM elements or + * Coords objects. + * + * @class Collision + * @uses Coords + * @param {HTMLElement} el The jQuery wrapped HTMLElement. + * @param {HTMLElement|Array} colliders Can be a jQuery collection + * of HTMLElements or an Array of Coords instances. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {Function} [options.on_overlap_start] Executes a function the first + * time each `collider ` is overlapped. + * @param {Function} [options.on_overlap_stop] Executes a function when a + * `collider` is no longer collided. + * @param {Function} [options.on_overlap] Executes a function when the + * mouse is moved during the collision. + * @return {Object} Collision instance. + * @constructor + */ + function Collision(el, colliders, options) { + this.options = $.extend(defaults, options); + this.$element = el; + this.last_colliders = []; + this.last_colliders_coords = []; + if (typeof colliders === 'string' || colliders instanceof jQuery) { + this.$colliders = $(colliders, + this.options.colliders_context).not(this.$element); + }else{ + this.colliders = $(colliders); + } + + this.init(); + } + + + var fn = Collision.prototype; + + + fn.init = function() { + this.find_collisions(); + }; + + + fn.overlaps = function(a, b) { + var x = false; + var y = false; + + if ((b.x1 >= a.x1 && b.x1 <= a.x2) || + (b.x2 >= a.x1 && b.x2 <= a.x2) || + (a.x1 >= b.x1 && a.x2 <= b.x2) + ) { x = true; } + + if ((b.y1 >= a.y1 && b.y1 <= a.y2) || + (b.y2 >= a.y1 && b.y2 <= a.y2) || + (a.y1 >= b.y1 && a.y2 <= b.y2) + ) { y = true; } + + return (x && y); + }; + + + fn.detect_overlapping_region = function(a, b){ + var regionX = ''; + var regionY = ''; + + if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } + if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } + if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } + if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } + + return (regionX + regionY) || 'C'; + }; + + + fn.calculate_overlapped_area_coords = function(a, b){ + var x1 = Math.max(a.x1, b.x1); + var y1 = Math.max(a.y1, b.y1); + var x2 = Math.min(a.x2, b.x2); + var y2 = Math.min(a.y2, b.y2); + + return $({ + left: x1, + top: y1, + width : (x2 - x1), + height: (y2 - y1) + }).coords().get(); + }; + + + fn.calculate_overlapped_area = function(coords){ + return (coords.width * coords.height); + }; + + + fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ + var last = this.last_colliders_coords; + + for (var i = 0, il = last.length; i < il; i++) { + if ($.inArray(last[i], new_colliders_coords) === -1) { + start_callback.call(this, last[i]); + } + } + + for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { + if ($.inArray(new_colliders_coords[j], last) === -1) { + stop_callback.call(this, new_colliders_coords[j]); + } + + } + }; + + + fn.find_collisions = function(player_data_coords){ + var self = this; + var colliders_coords = []; + var colliders_data = []; + var $colliders = (this.colliders || this.$colliders); + var count = $colliders.length; + var player_coords = self.$element.coords() + .update(player_data_coords || false).get(); + + while(count--){ + var $collider = self.$colliders ? + $($colliders[count]) : $colliders[count]; + var $collider_coords_ins = ($collider.isCoords) ? + $collider : $collider.coords(); + var collider_coords = $collider_coords_ins.get(); + var overlaps = self.overlaps(player_coords, collider_coords); + + if (!overlaps) { + continue; + } + + var region = self.detect_overlapping_region( + player_coords, collider_coords); + + //todo: make this an option + if (region === 'C'){ + var area_coords = self.calculate_overlapped_area_coords( + player_coords, collider_coords); + var area = self.calculate_overlapped_area(area_coords); + var collider_data = { + area: area, + area_coords : area_coords, + region: region, + coords: collider_coords, + player_coords: player_coords, + el: $collider + }; + + if (self.options.on_overlap) { + self.options.on_overlap.call(this, collider_data); + } + colliders_coords.push($collider_coords_ins); + colliders_data.push(collider_data); + } + } + + if (self.options.on_overlap_stop || self.options.on_overlap_start) { + this.manage_colliders_start_stop(colliders_coords, + self.options.on_overlap_stop, self.options.on_overlap_start); + } + + this.last_colliders_coords = colliders_coords; + + return colliders_data; + }; + + + fn.get_closest_colliders = function(player_data_coords){ + var colliders = this.find_collisions(player_data_coords); + var min_area = 100; + colliders.sort(function(a, b){ + if (a.area <= min_area) { + return 1; + } + + /* if colliders are being overlapped by the "C" (center) region, + * we have to set a lower index in the array to which they are placed + * above in the grid. */ + if (a.region === 'C' && b.region === 'C') { + if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { + return - 1; + }else{ + return 1; + } + } + + if (a.area < b.area){ + return 1; + } + + return 1; + }); + return colliders; + }; + + + //jQuery adapter + $.fn.collision = function(collider, options) { + return new Collision( this, collider, options ); + }; + + +}(jQuery, window, document)); + +;(function(window, undefined) { + /* Debounce and throttle functions taken from underscore.js */ + window.debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + if (immediate && !timeout) func.apply(context, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + + window.throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = debounce( + function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(context, args); + } + whenDone(); + throttling = true; + return result; + }; + }; + +})(window); + +;(function($, window, document, undefined){ + + var defaults = { + items: '.gs_w', + distance: 1, + limit: true, + offset_left: 0, + autoscroll: true + // ,drag: function(e){}, + // start : function(e, ui){}, + // stop : function(e){} + }; + + var $window = $(window); + var isTouch = !!('ontouchstart' in window); + var pointer_events = { + start: isTouch ? 'touchstart' : 'mousedown.draggable', + move: isTouch ? 'touchmove' : 'mousemove.draggable', + end: isTouch ? 'touchend' : 'mouseup.draggable' + }; + + /** + * Basic drag implementation for DOM elements inside a container. + * Provide start/stop/drag callbacks. + * + * @class Draggable + * @param {HTMLElement} el The HTMLelement that contains all the widgets + * to be dragged. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.items] Define who will + * be the draggable items. Can be a CSS Selector String or a + * collection of HTMLElements. + * @param {Number} [options.distance] Distance in pixels after mousedown + * the mouse must move before dragging should start. + * @param {Boolean} [options.limit] Constrains dragging to the width of + * the container + * @param {offset_left} [options.offset_left] Offset added to the item + * that is being dragged. + * @param {Number} [options.drag] Executes a callback when the mouse is + * moved during the dragging. + * @param {Number} [options.start] Executes a callback when the drag + * starts. + * @param {Number} [options.stop] Executes a callback when the drag stops. + * @return {Object} Returns `el`. + * @constructor + */ + function Draggable(el, options) { + this.options = $.extend({}, defaults, options); + this.$body = $(document.body); + this.$container = $(el); + this.$dragitems = $(this.options.items, this.$container); + this.is_dragging = false; + this.player_min_left = 0 + this.options.offset_left; + this.init(); + } + + var fn = Draggable.prototype; + + fn.init = function() { + this.calculate_positions(); + this.$container.css('position', 'relative'); + this.enable(); + + $(window).bind('resize', + throttle($.proxy(this.calculate_positions, this), 200)); + }; + + + fn.get_actual_pos = function($el) { + var pos = $el.position(); + return pos; + }; + + + fn.get_mouse_pos = function(e) { + if (isTouch) { + var oe = e.originalEvent; + e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; + }; + + return { + left: e.clientX, + top: e.clientY + }; + }; + + + fn.get_offset = function(e) { + e.preventDefault(); + var mouse_actual_pos = this.get_mouse_pos(e); + var diff_x = Math.round( + mouse_actual_pos.left - this.mouse_init_pos.left); + var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); + + var left = Math.round(this.el_init_offset.left + diff_x - this.baseX); + var top = Math.round( + this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset); + + if (this.options.limit) { + if (left > this.player_max_left) { + left = this.player_max_left; + }else if(left < this.player_min_left) { + left = this.player_min_left; + } + } + + return { + left: left, + top: top, + mouse_left: mouse_actual_pos.left, + mouse_top: mouse_actual_pos.top + }; + }; + + + fn.manage_scroll = function(offset) { + /* scroll document */ + var nextScrollTop; + var scrollTop = $window.scrollTop(); + var min_window_y = scrollTop; + var max_window_y = min_window_y + this.window_height; + + var mouse_down_zone = max_window_y - 50; + var mouse_up_zone = min_window_y + 50; + + var abs_mouse_left = offset.mouse_left; + var abs_mouse_top = min_window_y + offset.mouse_top; + + var max_player_y = (this.doc_height - this.window_height + + this.player_height); + + if (abs_mouse_top >= mouse_down_zone) { + nextScrollTop = scrollTop + 30; + if (nextScrollTop < max_player_y) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset + 30; + } + }; + + if (abs_mouse_top <= mouse_up_zone) { + nextScrollTop = scrollTop - 30; + if (nextScrollTop > 0) { + $window.scrollTop(nextScrollTop); + this.scrollOffset = this.scrollOffset - 30; + } + }; + } + + + fn.calculate_positions = function(e) { + this.window_height = $window.height(); + } + + + fn.drag_handler = function(e) { + var node = e.target.nodeName; + + if (e.which !== 1 && !isTouch) { + return; + } + + if (node === 'INPUT' || node === 'TEXTAREA' || node === 'SELECT' || + node === 'BUTTON') { + return; + }; + + var self = this; + var first = true; + this.$player = $(e.currentTarget); + + this.el_init_pos = this.get_actual_pos(this.$player); + this.mouse_init_pos = this.get_mouse_pos(e); + this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; + + this.$body.on(pointer_events.move, function(mme){ + var mouse_actual_pos = self.get_mouse_pos(mme); + var diff_x = Math.abs( + mouse_actual_pos.left - self.mouse_init_pos.left); + var diff_y = Math.abs( + mouse_actual_pos.top - self.mouse_init_pos.top); + if (!(diff_x > self.options.distance || + diff_y > self.options.distance) + ) { + return false; + } + + if (first) { + first = false; + self.on_dragstart.call(self, mme); + return false; + } + + if (self.is_dragging == true) { + self.on_dragmove.call(self, mme); + } + + return false; + }); + + return false; + }; + + + fn.on_dragstart = function(e) { + e.preventDefault(); + this.drag_start = true; + this.is_dragging = true; + var offset = this.$container.offset(); + this.baseX = Math.round(offset.left); + this.baseY = Math.round(offset.top); + this.doc_height = $(document).height(); + + if (this.options.helper === 'clone') { + this.$helper = this.$player.clone() + .appendTo(this.$container).addClass('helper'); + this.helper = true; + }else{ + this.helper = false; + } + this.scrollOffset = 0; + this.el_init_offset = this.$player.offset(); + this.player_width = this.$player.width(); + this.player_height = this.$player.height(); + this.player_max_left = (this.$container.width() - this.player_width + + this.options.offset_left); + + if (this.options.start) { + this.options.start.call(this.$player, e, { + helper: this.helper ? this.$helper : this.$player + }); + } + return false; + }; + + + fn.on_dragmove = function(e) { + var offset = this.get_offset(e); + + this.options.autoscroll && this.manage_scroll(offset); + + (this.helper ? this.$helper : this.$player).css({ + 'position': 'absolute', + 'left' : offset.left, + 'top' : offset.top + }); + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.drag) { + this.options.drag.call(this.$player, e, ui); + } + return false; + }; + + + fn.on_dragstop = function(e) { + var offset = this.get_offset(e); + this.drag_start = false; + + var ui = { + 'position': { + 'left': offset.left, + 'top': offset.top + } + }; + + if (this.options.stop) { + this.options.stop.call(this.$player, e, ui); + } + + if (this.helper) { + this.$helper.remove(); + } + + return false; + }; + + fn.on_select_start = function(e) { + return false; + } + + + fn.enable = function(){ + this.$container.on('selectstart', this.on_select_start); + + this.$container.on(pointer_events.start, this.options.items, $.proxy( + this.drag_handler, this)); + + this.$body.on(pointer_events.end, $.proxy(function(e) { + this.is_dragging = false; + this.$body.off(pointer_events.move); + if (this.drag_start) { + this.on_dragstop(e); + } + }, this)); + }; + + + fn.disable = function(){ + this.$container.off(pointer_events.start); + this.$body.off(pointer_events.end); + this.$container.off('selectstart', this.on_select_start); + }; + + + fn.destroy = function(){ + this.disable(); + $.removeData(this.$container, 'drag'); + }; + + + //jQuery adapter + $.fn.drag = function ( options ) { + return this.each(function () { + if (!$.data(this, 'drag')) { + $.data(this, 'drag', new Draggable( this, options )); + } + }); + }; + + +}(jQuery, window, document)); + +;(function($, window, document, undefined) { + + var defaults = { + widget_selector: '> li', + widget_margins: [10, 10], + widget_base_dimensions: [400, 225], + extra_rows: 0, + extra_cols: 0, + min_cols: 1, + min_rows: 15, + max_size_x: 6, + max_size_y: 6, + autogenerate_stylesheet: true, + avoid_overlapped_widgets: true, + serialize_params: function($w, wgd) { + return { + col: wgd.col, + row: wgd.row + }; + }, + collision: {}, + draggable: { + distance: 4 + } + }; + + + /** + * @class Gridster + * @uses Draggable + * @uses Collision + * @param {HTMLElement} el The HTMLelement that contains all the widgets. + * @param {Object} [options] An Object with all options you want to + * overwrite: + * @param {HTMLElement|String} [options.widget_selector] Define who will + * be the draggable widgets. Can be a CSS Selector String or a + * collection of HTMLElements + * @param {Array} [options.widget_margins] Margin between widgets. + * The first index for the horizontal margin (left, right) and + * the second for the vertical margin (top, bottom). + * @param {Array} [options.widget_base_dimensions] Base widget dimensions + * in pixels. The first index for the width and the second for the + * height. + * @param {Number} [options.extra_cols] Add more columns in addition to + * those that have been calculated. + * @param {Number} [options.extra_rows] Add more rows in addition to + * those that have been calculated. + * @param {Number} [options.min_cols] The minimum required columns. + * @param {Number} [options.min_rows] The minimum required rows. + * @param {Number} [options.max_size_x] The maximum number of columns + * that a widget can span. + * @param {Number} [options.max_size_y] The maximum number of rows + * that a widget can span. + * @param {Boolean} [options.autogenerate_stylesheet] If true, all the + * CSS required to position all widgets in their respective columns + * and rows will be generated automatically and injected to the + * `` of the document. You can set this to false, and write + * your own CSS targeting rows and cols via data-attributes like so: + * `[data-col="1"] { left: 10px; }` + * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded + * from the DOM can be overlapped. It is helpful if the positions were + * bad stored in the database or if there was any conflict. + * @param {Function} [options.serialize_params] Return the data you want + * for each widget in the serialization. Two arguments are passed: + * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid + * coords object (`col`, `row`, `size_x`, `size_y`). + * @param {Object} [options.collision] An Object with all options for + * Collision class you want to overwrite. See Collision docs for + * more info. + * @param {Object} [options.draggable] An Object with all options for + * Draggable class you want to overwrite. See Draggable docs for more + * info. + * + * @constructor + */ + function Gridster(el, options) { + this.options = $.extend(true, defaults, options); + this.$el = $(el); + this.$wrapper = this.$el.parent(); + this.$widgets = $(this.options.widget_selector, this.$el).addClass('gs_w'); + this.widgets = []; + this.$changed = $([]); + this.wrapper_width = this.$wrapper.width(); + this.min_widget_width = (this.options.widget_margins[0] * 2) + + this.options.widget_base_dimensions[0]; + this.min_widget_height = (this.options.widget_margins[1] * 2) + + this.options.widget_base_dimensions[1]; + this.init(); + } + + Gridster.generated_stylesheets = []; + + var fn = Gridster.prototype; + + fn.init = function() { + this.generate_grid_and_stylesheet(); + this.get_widgets_from_DOM(); + this.set_dom_grid_height(); + this.$wrapper.addClass('ready'); + this.draggable(); + + $(window).bind( + 'resize', throttle($.proxy(this.recalculate_faux_grid, this), 200)); + }; + + + /** + * Disables dragging. + * + * @method disable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.disable = function() { + this.$wrapper.find('.player-revert').removeClass('player-revert'); + this.drag_api.disable(); + return this; + }; + + + /** + * Enables dragging. + * + * @method enable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.enable = function() { + this.drag_api.enable(); + return this; + }; + + + /** + * Add a new widget to the grid. + * + * @method add_widget + * @param {String} html The string representing the HTML of the widget. + * @param {Number} size_x The nº of rows the widget occupies horizontally. + * @param {Number} size_y The nº of columns the widget occupies vertically. + * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. + * the widget that was just created. + */ + fn.add_widget = function(html, size_x, size_y) { + var next_pos = this.next_position(size_x, size_y); + + var $w = $(html).attr({ + 'data-col': next_pos.col, + 'data-row': next_pos.row, + 'data-sizex' : next_pos.size_x, + 'data-sizey' : next_pos.size_y + }).addClass('gs_w').appendTo(this.$el).hide(); + + this.$widgets = this.$widgets.add($w); + + this.register_widget($w); + + this.set_dom_grid_height(); + + return $w.fadeIn(); + }; + + + /** + * Get the most left column below to add a new widget. + * + * @method next_position + * @param {Number} size_x The nº of rows the widget occupies horizontally. + * @param {Number} size_y The nº of columns the widget occupies vertically. + * @return {Object} Returns a grid coords object representing the future + * widget coords. + */ + fn.next_position = function(size_x, size_y) { + size_x || (size_x = 1); + size_y || (size_y = 1); + var ga = this.gridmap; + var cols_l = ga.length; + var valid_pos = []; + + for (var c = 1; c < cols_l; c++) { + var rows_l = ga[c].length; + for (var r = 1; r <= rows_l; r++) { + var can_move_to = this.can_move_to({ + size_x: size_x, + size_y: size_y + }, c, r); + + if (can_move_to) { + valid_pos.push({ + col: c, + row: r, + size_y: size_y, + size_x: size_x + }); + } + } + } + + if (valid_pos.length) { + return this.sort_by_row_and_col_asc(valid_pos)[0]; + } + return false; + }; + + + /** + * Remove a widget from the grid. + * + * @method remove_widget + * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_widget = function(el, callback) { + var $el = el instanceof jQuery ? el : $(el); + var wgd = $el.coords().grid; + + this.cells_occupied_by_placeholder = {}; + this.$widgets = this.$widgets.not($el); + + var $nexts = this.widgets_below($el); + + this.remove_from_gridmap(wgd); + + $el.fadeOut($.proxy(function() { + $el.remove(); + + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), wgd.size_y ); + }, this)); + + this.set_dom_grid_height(); + + if (callback) { + callback.call(this, el); + } + }, this)); + }; + + + /** + * Returns a serialized array of the widgets in the grid. + * + * @method serialize + * @param {HTMLElement} [$widgets] The collection of jQuery wrapped + * HTMLElements you want to serialize. If no argument is passed all widgets + * will be serialized. + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize = function($widgets) { + $widgets || ($widgets = this.$widgets); + var result = []; + $widgets.each($.proxy(function(i, widget) { + result.push(this.options.serialize_params( + $(widget), $(widget).coords().grid ) ); + }, this)); + + return result; + }; + + + /** + * Returns a serialized array of the widgets that have changed their + * position. + * + * @method serialize_changed + * @return {Array} Returns an Array of Objects with the data specified in + * the serialize_params option. + */ + fn.serialize_changed = function() { + return this.serialize(this.$changed); + }; + + + /** + * Creates the grid coords object representing the widget a add it to the + * mapped array of positions. + * + * @method register_widget + * @return {Array} Returns the instance of the Gridster class. + */ + fn.register_widget = function($el) { + + var wgd = { + 'col': parseInt($el.attr('data-col'), 10), + 'row': parseInt($el.attr('data-row'), 10), + 'size_x': parseInt($el.attr('data-sizex'), 10), + 'size_y': parseInt($el.attr('data-sizey'), 10), + 'el': $el + }; + + if (this.options.avoid_overlapped_widgets && + !this.can_move_to( + {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) + ) { + wgd = this.next_position(wgd.size_x, wgd.size_y); + wgd.el = $el; + $el.attr({ + 'data-col': wgd.col, + 'data-row': wgd.row, + 'data-sizex': wgd.size_x, + 'data-sizey': wgd.size_y + }); + } + + // attach Coord object to player data-coord attribute + $el.data('coords', $el.coords()); + + // Extend Coord object with grid position info + $el.data('coords').grid = wgd; + + this.add_to_gridmap(wgd, $el); + this.widgets.push($el); + return this; + }; + + + /** + * Update in the mapped array of positions the value of cells represented by + * the grid coords object passed in the `grid_data` param. + * + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped + * HTMLElement, depends if you want to delete an existing position or add + * a new one. + * @method update_widget_position + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.update_widget_position = function(grid_data, value) { + this.for_each_cell_occupied(grid_data, function(col, row) { + if (!this.gridmap[col]) { return this; } + this.gridmap[col][row] = value; + }); + return this; + }; + + + /** + * Remove a widget from the mapped array of positions. + * + * @method remove_from_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_from_gridmap = function(grid_data) { + return this.update_widget_position(grid_data, false); + }; + + + /** + * Add a widget to the mapped array of positions. + * + * @method add_to_gridmap + * @param {Object} grid_data The grid coords object representing the cells + * to update in the mapped array. + * @param {HTMLElement|Boolean} value The value to set in the specified + * position . + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.add_to_gridmap = function(grid_data, value) { + this.update_widget_position(grid_data, value || grid_data.el); + + if (grid_data.el) { + var $widgets = this.widgets_below(grid_data.el); + $widgets.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget)); + }, this)); + } + }; + + + /** + * Make widgets draggable. + * + * @uses Draggable + * @method draggable + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.draggable = function() { + var self = this; + var draggable_options = $.extend(true, {}, this.options.draggable, { + offset_left: this.options.widget_margins[0], + items: '.gs_w', + start: function(event, ui) { + self.$widgets.filter('.player-revert') + .removeClass('player-revert'); + + self.$player = $(this); + self.$helper = self.options.draggable.helper === 'clone' ? + $(ui.helper) : self.$player; + self.helper = !self.$helper.is(self.$player); + + self.on_start_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstart'); + }, + stop: function(event, ui) { + self.on_stop_drag.call(self, event, ui); + self.$el.trigger('gridster:dragstop'); + }, + drag: throttle(function(event, ui) { + self.on_drag.call(self, event, ui); + self.$el.trigger('gridster:drag'); + }, 60) + }); + + this.drag_api = this.$el.drag(draggable_options).data('drag'); + return this; + }; + + + /** + * This function is executed when the player begins to be dragged. + * + * @method on_start_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_start_drag = function(event, ui) { + + this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); + + this.$player.addClass('player'); + this.player_grid_data = this.$player.coords().grid; + this.placeholder_grid_data = $.extend({}, this.player_grid_data); + + //set new grid height along the dragging period + this.$el.css('height', this.$el.height() + + (this.player_grid_data.size_y * this.min_widget_height)); + + var colliders = this.faux_grid; + var coords = this.$player.data('coords').coords; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.last_cols = []; + this.last_rows = []; + + + // see jquery.collision.js + this.collision_api = this.$helper.collision( + colliders, this.options.collision); + + this.$preview_holder = $('
  • ', { + 'class': 'preview-holder', + 'data-row': this.$player.attr('data-row'), + 'data-col': this.$player.attr('data-col'), + css: { + width: coords.width, + height: coords.height + } + }).appendTo(this.$el); + + if (this.options.draggable.start) { + this.options.draggable.start.call(this, event, ui); + } + }; + + + /** + * This function is executed when the player is being dragged. + * + * @method on_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_drag = function(event, ui) { + //break if dragstop has been fired + if (this.$player === null) { + return false; + }; + + var abs_offset = { + left: ui.position.left + this.baseX, + top: ui.position.top + this.baseY + }; + + this.colliders_data = this.collision_api.get_closest_colliders( + abs_offset); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + if (this.helper && this.$player) { + this.$player.css({ + 'left': ui.position.left, + 'top': ui.position.top + }); + } + + if (this.options.draggable.drag) { + this.options.draggable.drag.call(this, event, ui); + } + }; + + /** + * This function is executed when the player stops being dragged. + * + * @method on_stop_drag + * @param {Event} The original browser event + * @param {Object} A prepared ui object. + */ + fn.on_stop_drag = function(event, ui) { + this.$helper.add(this.$player).add(this.$wrapper) + .removeClass('dragging'); + + ui.position.left = ui.position.left + this.baseX; + ui.position.top = ui.position.top + this.baseY; + this.colliders_data = this.collision_api.get_closest_colliders(ui.position); + + this.on_overlapped_column_change( + this.on_start_overlapping_column, + this.on_stop_overlapping_column + ); + + this.on_overlapped_row_change( + this.on_start_overlapping_row, + this.on_stop_overlapping_row + ); + + this.$player.addClass('player-revert').removeClass('player') + .attr({ + 'data-col': this.placeholder_grid_data.col, + 'data-row': this.placeholder_grid_data.row + }).css({ + 'left': '', + 'top': '' + }); + + this.$changed = this.$changed.add(this.$player); + + this.cells_occupied_by_player = this.get_cells_occupied( + this.placeholder_grid_data); + this.set_cells_player_occupies( + this.placeholder_grid_data.col, this.placeholder_grid_data.row); + + this.$player.coords().grid.row = this.placeholder_grid_data.row; + this.$player.coords().grid.col = this.placeholder_grid_data.col; + + if (this.options.draggable.stop) { + this.options.draggable.stop.call(this, event, ui); + } + + this.$preview_holder.remove(); + this.$player = null; + + this.set_dom_grid_height(); + }; + + + /** + * Executes the callbacks passed as arguments when a column begins to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new column + * begins to be overlapped. The column is passed as first argument. + * @param {Function} stop_callback Function executed when a column stops + * being overlapped. The column is passed as first argument. + * @method on_overlapped_column_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_column_change = function(start_callback, stop_callback) { + if (!this.colliders_data.length) { + return; + } + var cols = this.get_targeted_columns( + this.colliders_data[0].el.data.col); + + var last_n_cols = this.last_cols.length; + var n_cols = cols.length; + var i; + + for (i = 0; i < n_cols; i++) { + if ($.inArray(cols[i], this.last_cols) === -1) { + (start_callback || $.noop).call(this, cols[i]); + } + } + + for (i = 0; i< last_n_cols; i++) { + if ($.inArray(this.last_cols[i], cols) === -1) { + (stop_callback || $.noop).call(this, this.last_cols[i]); + } + } + + this.last_cols = cols; + + return this; + }; + + + /** + * Executes the callbacks passed as arguments when a row starts to be + * overlapped or stops being overlapped. + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} stop_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method on_overlapped_row_change + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.on_overlapped_row_change = function(start_callback, end_callback) { + if (!this.colliders_data.length) { + return; + } + var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); + var last_n_rows = this.last_rows.length; + var n_rows = rows.length; + var i; + + for (i = 0; i < n_rows; i++) { + if ($.inArray(rows[i], this.last_rows) === -1) { + (start_callback || $.noop).call(this, rows[i]); + } + } + + for (i = 0; i < last_n_rows; i++) { + if ($.inArray(this.last_rows[i], rows) === -1) { + (end_callback || $.noop).call(this, this.last_rows[i]); + } + } + + this.last_rows = rows; + }; + + + /** + * Sets the current position of the player + * + * @param {Function} start_callback Function executed when a new row begins + * to be overlapped. The row is passed as first argument. + * @param {Function} stop_callback Function executed when a row stops being + * overlapped. The row is passed as first argument. + * @method set_player + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_player = function(col, row) { + this.empty_cells_player_occupies(); + + var self = this; + var cell = self.colliders_data[0].el.data; + var to_col = cell.col; + var to_row = row || cell.row; + + this.player_grid_data = { + col: to_col, + row: to_row, + size_y : this.player_grid_data.size_y, + size_x : this.player_grid_data.size_x + }; + + this.cells_occupied_by_player = this.get_cells_occupied( + this.player_grid_data); + + var $overlapped_widgets = this.get_widgets_overlapped( + this.player_grid_data); + + var constraints = this.widgets_constraints($overlapped_widgets); + + this.manage_movements(constraints.can_go_up, to_col, to_row); + this.manage_movements(constraints.can_not_go_up, to_col, to_row); + + /* if there is not widgets overlapping in the new player position, + * update the new placeholder position. */ + if (!$overlapped_widgets.length) { + var pp = this.can_go_player_up(this.player_grid_data); + if (pp !== false) { + to_row = pp; + } + this.set_placeholder(to_col, to_row); + } + + return { + col: to_col, + row: to_row + }; + }; + + + /** + * See which of the widgets in the $widgets param collection can go to + * a upper row and which not. + * + * @method widgets_contraints + * @param {HTMLElements} $widgets A jQuery wrapped collection of + * HTMLElements. + * @return {Array} Returns a literal Object with two keys: `can_go_up` & + * `can_not_go_up`. Each contains a set of HTMLElements. + */ + fn.widgets_constraints = function($widgets) { + var $widgets_can_go_up = $([]); + var $widgets_can_not_go_up; + var wgd_can_go_up = []; + var wgd_can_not_go_up = []; + + $widgets.each($.proxy(function(i, w) { + var $w = $(w); + var wgd = $w.coords().grid; + if (this.can_go_widget_up(wgd)) { + $widgets_can_go_up = $widgets_can_go_up.add($w); + wgd_can_go_up.push(wgd); + }else{ + wgd_can_not_go_up.push(wgd); + } + }, this)); + + $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); + + return { + can_go_up: this.sort_by_row_asc(wgd_can_go_up), + can_not_go_up: this.sort_by_row_desc(wgd_can_not_go_up) + }; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in ascending way. + * + * @method sort_by_row_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row > b.row) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) placing first the empty cells upper left. + * + * @method sort_by_row_and_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_and_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row > b.row || a.row == b.row && a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects by column (representing the grid + * coords of each widget) in ascending way. + * + * @method sort_by_col_asc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_col_asc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.col > b.col) { + return 1; + } + return -1; + }); + + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method sort_by_row_desc + * @param {Array} widgets Array of grid coords objects + * @return {Array} Returns the array sorted. + */ + fn.sort_by_row_desc = function(widgets) { + widgets = widgets.sort(function(a, b) { + if (a.row + a.size_y < b.row + b.size_y) { + return 1; + } + return -1; + }); + return widgets; + }; + + + /** + * Sorts an Array of grid coords objects (representing the grid coords of + * each widget) in descending way. + * + * @method manage_movements + * @param {HTMLElements} $widgets A jQuery collection of HTMLElements + * representing the widgets you want to move. + * @param {Number} to_col The column to which we want to move the widgets. + * @param {Number} to_row The row to which we want to move the widgets. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.manage_movements = function($widgets, to_col, to_row) { + $.each($widgets, $.proxy(function(i, w) { + var wgd = w; + var $w = wgd.el; + + var can_go_widget_up = this.can_go_widget_up(wgd); + + if (can_go_widget_up) { + //target CAN go up + //so move widget up + this.move_widget_to($w, can_go_widget_up); + this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); + + } else { + //target can't go up + var can_go_player_up = this.can_go_player_up( + this.player_grid_data); + + if (!can_go_player_up) { + // target can't go up + // player cant't go up + // so we need to move widget down to a position that dont + // overlaps player + var y = (to_row + this.player_grid_data.size_y) - wgd.row; + + this.move_widget_down($w, y); + this.set_placeholder(to_col, to_row); + } + } + }, this)); + + return this; + }; + + /** + * Determines if there is a widget in the row and col given. Or if the + * HTMLElement passed as first argument is the player. + * + * @method is_player + * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of + * HTMLElements. + * @param {Number} [row] The column to which we want to move the widgets. + * @return {Boolean} Returns true or false. + */ + fn.is_player = function(col_or_el, row) { + if (row && !this.gridmap[col_or_el]) { return false; } + var $w = row ? this.gridmap[col_or_el][row] : col_or_el; + return $w && ($w.is(this.$player) || $w.is(this.$helper)); + }; + + + /** + * Determines if the widget that is being dragged is currently over the row + * and col given. + * + * @method is_player_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_player_in = function(col, row) { + var c = this.cells_occupied_by_player || {}; + return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the row and col given. + * + * @method is_placeholder_in + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in = function(col, row) { + var c = this.cells_occupied_by_placeholder || {}; + return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; + }; + + + /** + * Determines if the placeholder is currently over the column given. + * + * @method is_placeholder_in_col + * @param {Number} col The column to check. + * @return {Boolean} Returns true or false. + */ + fn.is_placeholder_in_col = function(col) { + var c = this.cells_occupied_by_placeholder || []; + return $.inArray(col, c.cols) >= 0; + }; + + + /** + * Determines if the cell represented by col and row params is empty. + * + * @method is_empty + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_empty = function(col, row) { + if (typeof this.gridmap[col] !== 'undefined' && + typeof this.gridmap[col][row] !== 'undefined' && + this.gridmap[col][row] === false + ) { + return true; + } + return false; + }; + + + /** + * Determines if the cell represented by col and row params is occupied. + * + * @method is_occupied + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_occupied = function(col, row) { + if (!this.gridmap[col]) { + return false; + } + + if (this.gridmap[col][row]) { + return true; + } + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row params. + * + * @method is_widget + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean|HTMLElement} Returns false if there is no widget, + * else returns the jQuery HTMLElement + */ + fn.is_widget = function(col, row) { + var cell = this.gridmap[col]; + if (!cell) { + return false; + } + + cell = cell[row]; + + if (cell) { + return cell; + } + + return false; + }; + + + /** + * Determines if there is a widget in the cell represented by col/row + * params and if this is under the widget that is being dragged. + * + * @method is_widget_under_player + * @param {Number} col The column to check. + * @param {Number} row The row to check. + * @return {Boolean} Returns true or false. + */ + fn.is_widget_under_player = function(col, row) { + if (this.is_widget(col, row)) { + return this.is_player_in(col, row); + } + return false; + }; + + + /** + * Get widgets overlapping with the player. + * + * @method get_widgets_under_player + * @return {HTMLElement} Returns a jQuery collection of HTMLElements + */ + fn.get_widgets_under_player = function() { + var cells = this.cells_occupied_by_player; + var $widgets = $([]); + + $.each(cells.cols, $.proxy(function(i, col) { + $.each(cells.rows, $.proxy(function(i, row) { + if(this.is_widget(col, row)) { + $widgets = $widgets.add(this.gridmap[col][row]); + } + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * Put placeholder at the row and column specified. + * + * @method set_placeholder + * @param {Number} col The column to which we want to move the + * placeholder. + * @param {Number} row The row to which we want to move the + * placeholder. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_placeholder = function(col, row) { + var phgd = $.extend({}, this.placeholder_grid_data); + var $nexts = this.widgets_below({ + col: phgd.col, + row: phgd.row, + size_y: phgd.size_y, + size_x: phgd.size_x + }); + + //Prevents widgets go out of the grid + var right_col = (col + phgd.size_x - 1); + if (right_col > this.cols) { + col = col - (right_col - col); + } + + var moved_down = this.placeholder_grid_data.row < row; + var changed_column = this.placeholder_grid_data.col !== col; + + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + + this.cells_occupied_by_placeholder = this.get_cells_occupied( + this.placeholder_grid_data); + + this.$preview_holder.attr({ + 'data-row' : row, + 'data-col' : col + }); + + if (moved_down || changed_column) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( + $(widget), this.placeholder_grid_data.col - col + phgd.size_y); + }, this)); + } + + }; + + + /** + * Determines whether the player can move to a position above. + * + * @method can_go_player_up + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @return {Number|Boolean} If the player can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_player_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + var $widgets_under_player = this.get_widgets_under_player(); + + /* generate an array with columns as index and array with upper rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + var r = p_bottom_row + 1; + upper_rows[tcol] = []; + + while (--r > 0) { + if (this.is_empty(tcol, r) || this.is_player(tcol, r) || + this.is_widget(tcol, r) && + grid_col[r].is($widgets_under_player) + ) { + upper_rows[tcol].push(r); + min_row = r < min_row ? r : min_row; + }else{ + break; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Determines whether a widget can move to a position above. + * + * @method can_go_widget_up + * @param {Object} widget_grid_data The actual grid coords object of the + * widget we want to check. + * @return {Number|Boolean} If the widget can be moved to an upper row + * returns the row number, else returns false. + */ + fn.can_go_widget_up = function(widget_grid_data) { + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var result = true; + var upper_rows = []; + var min_row = 10000; + + if (widget_grid_data.col < this.player_grid_data.col && + (widget_grid_data.col + widget_grid_data.size_y - 1) > + (this.player_grid_data.col + this.player_grid_data.size_y - 1) + ) { + return false; + }; + + /* generate an array with columns as index and array with upper rows + * empty as value */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = this.gridmap[tcol]; + upper_rows[tcol] = []; + + var r = p_bottom_row + 1; + + while (--r > 0) { + if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { + if (!grid_col[r].is(widget_grid_data.el)) { + break; + }; + } + + if (!this.is_player(tcol, r) && + !this.is_placeholder_in(tcol, r) && + !this.is_player_in(tcol, r)) { + upper_rows[tcol].push(r); + }; + + if (r < min_row) { + min_row = r; + } + } + + if (upper_rows[tcol].length === 0) { + result = false; + return true; //break + } + + upper_rows[tcol].sort(); + }); + + if (!result) { return false; } + + return this.get_valid_rows(widget_grid_data, upper_rows, min_row); + }; + + + /** + * Search a valid row for the widget represented by `widget_grid_data' in + * the `upper_rows` array. Iteration starts from row specified in `min_row`. + * + * @method get_valid_rows + * @param {Object} widget_grid_data The actual grid coords object of the + * player. + * @param {Array} upper_rows An array with columns as index and arrays + * of valid rows as values. + * @param {Number} min_row The upper row from which the iteration will start. + * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` + * for the widget in question. + */ + fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { + var p_top_row = widget_grid_data.row; + var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; + var size_y = widget_grid_data.size_y; + var r = min_row - 1; + var valid_rows = []; + + while (++r <= p_bottom_row ) { + var common = true; + $.each(upper_rows, function(col, rows) { + if ($.isArray(rows) && $.inArray(r, rows) === -1) { + common = false; + } + }); + + if (common === true) { + valid_rows.push(r); + if (valid_rows.length === size_y) { + break; + } + } + } + + var new_row = false; + if (size_y === 1) { + if (valid_rows[0] !== p_top_row) { + new_row = valid_rows[0] || false; + } + }else{ + if (valid_rows[0] !== p_top_row) { + new_row = this.get_consecutive_numbers_index( + valid_rows, size_y); + } + } + + return new_row; + }; + + + fn.get_consecutive_numbers_index = function(arr, size_y) { + var max = arr.length; + var result = []; + var first = true; + var prev = -1; // or null? + + for (var i=0; i < max; i++) { + if (first || arr[i] === prev + 1) { + result.push(i); + if (result.length === size_y) { + break; + } + first = false; + }else{ + result = []; + first = true; + } + + prev = arr[i]; + } + + return result.length >= size_y ? arr[result[0]] : false; + }; + + + /** + * Get widgets overlapping with the player. + * + * @method get_widgets_overlapped + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.get_widgets_overlapped = function() { + var $w; + var $widgets = $([]); + var used = []; + var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); + rows_from_bottom.reverse(); + + $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { + $.each(rows_from_bottom, $.proxy(function(i, row) { + // if there is a widget in the player position + if (!this.gridmap[col]) { return true; } //next iteration + var $w = this.gridmap[col][row]; + + if (this.is_occupied(col, row) && !this.is_player($w) && + $.inArray($w, used) === -1 + ) { + $widgets = $widgets.add($w); + used.push($w); + } + + }, this)); + }, this)); + + return $widgets; + }; + + + /** + * This callback is executed when the player begins to collide with a column. + * + * @method on_start_overlapping_column + * @param {Number} col The collided column. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_column = function(col) { + this.set_player(col, false); + }; + + + /** + * A callback executed when the player begins to collide with a row. + * + * @method on_start_overlapping_row + * @param {Number} col The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_start_overlapping_row = function(row) { + this.set_player(false, row); + }; + + + /** + * A callback executed when the the player ends to collide with a column. + * + * @method on_stop_overlapping_column + * @param {Number} col The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_column = function(col) { + this.set_player(col, false); + + var self = this; + this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], + function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + }; + + + /** + * This callback is executed when the player ends to collide with a row. + * + * @method on_stop_overlapping_row + * @param {Number} row The collided row. + * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + */ + fn.on_stop_overlapping_row = function(row) { + this.set_player(false, row); + + var self = this; + var cols = this.cells_occupied_by_player.cols; + for (var c = 0, cl = cols.length; c < cl; c++) { + this.for_each_widget_below(cols[c], row, function(tcol, trow) { + self.move_widget_up(this, self.player_grid_data.size_y); + }); + } + }; + + + /** + * Move a widget to a specific row. The cell or cells must be empty. + * If the widget has widgets below, all of these widgets will be moved also + * if they can. + * + * @method move_widget_to + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the + * widget is going to be moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_to = function($widget, row) { + var self = this; + var widget_grid_data = $widget.coords().grid; + var diff = row - widget_grid_data.row; + var $next_widgets = this.widgets_below($widget); + + var can_move_to_new_cell = this.can_move_to( + widget_grid_data, widget_grid_data.col, row, $widget); + + if (can_move_to_new_cell === false) { + return false; + } + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', row); + this.$changed = this.$changed.add($widget); + + + $next_widgets.each(function(i, widget) { + var $w = $(widget); + var wgd = $w.coords().grid; + var can_go_up = self.can_go_widget_up(wgd); + if (can_go_up && can_go_up !== wgd.row) { + self.move_widget_to($w, can_go_up); + } + }); + + return this; + }; + + + /** + * Move up the specified widget and all below it. + * + * @method move_widget_up + * @param {HTMLElement} $widget The widget you want to move. + * @param {Number} [y_units] The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_up = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var can_go_up = true; + y_units || (y_units = 1); + + if (!this.can_go_up($widget)) { return false; } //break; + + this.for_each_column_occupied(el_grid_data, function(col) { + // can_go_up + if ($.inArray($widget, moved) === -1) { + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row - y_units; + next_row = this.can_go_up_to_row( + widget_grid_data, col, next_row); + + if (!next_row) { + return true; + } + + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + widget_grid_data.row = next_row; + this.add_to_gridmap(widget_grid_data); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + + $next_widgets.each($.proxy(function(i, widget) { + this.move_widget_up($(widget), y_units); + }, this)); + } + }); + + }; + + + /** + * Move down the specified widget and all below it. + * + * @method move_widget_down + * @param {HTMLElement} $widget The jQuery object representing the widget + * you want to move. + * @param {Number} The number of cells that the widget has to move. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.move_widget_down = function($widget, y_units) { + var el_grid_data = $widget.coords().grid; + var actual_row = el_grid_data.row; + var moved = []; + var y_diff = y_units; + + if (!$widget) { return false; } + + if ($.inArray($widget, moved) === -1) { + + var widget_grid_data = $widget.coords().grid; + var next_row = actual_row + y_units; + var $next_widgets = this.widgets_below($widget); + + this.remove_from_gridmap(widget_grid_data); + + $next_widgets.each($.proxy(function(i, widget) { + var $w = $(widget); + var wd = $w.coords().grid; + var tmp_y = this.displacement_diff( + wd, widget_grid_data, y_diff); + + if (tmp_y > 0) { + this.move_widget_down($w, tmp_y); + } + }, this)); + + widget_grid_data.row = next_row; + this.update_widget_position(widget_grid_data, $widget); + $widget.attr('data-row', widget_grid_data.row); + this.$changed = this.$changed.add($widget); + + moved.push($widget); + } + }; + + + /** + * Check if the widget can move to the specified row, else returns the + * upper row possible. + * + * @method can_go_up_to_row + * @param {Number} widget_grid_data The current grid coords object of the + * widget. + * @param {Number} col The target column. + * @param {Number} row The target row. + * @return {Boolean|Number} Returns the row number if the widget can move + * to the target position, else returns false. + */ + fn.can_go_up_to_row = function(widget_grid_data, col, row) { + var ga = this.gridmap; + var result = true; + var urc = []; // upper_rows_in_columns + var actual_row = widget_grid_data.row; + var r; + + /* generate an array with columns as index and array with + * upper rows empty in the column */ + this.for_each_column_occupied(widget_grid_data, function(tcol) { + var grid_col = ga[tcol]; + urc[tcol] = []; + + r = actual_row; + while (r--) { + if (this.is_empty(tcol, r) && + !this.is_placeholder_in(tcol, r) + ) { + urc[tcol].push(r); + }else{ + break; + } + } + + if (!urc[tcol].length) { + result = false; + return true; + } + + }); + + if (!result) { return false; } + + /* get common rows starting from upper position in all the columns + * that widget occupies */ + r = row; + for (r = 1; r < actual_row; r++) { + var common = true; + + for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { + if (urc[uc] && $.inArray(r, urc[uc]) === -1) { + common = false; + } + } + + if (common === true) { + result = r; + break; + } + } + + return result; + }; + + + fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { + var actual_row = widget_grid_data.row; + var diffs = []; + var parent_max_y = parent_bgd.row + parent_bgd.size_y; + + this.for_each_column_occupied(widget_grid_data, function(col) { + var temp_y_units = 0; + + for (var r = parent_max_y; r < actual_row; r++) { + if (this.is_empty(col, r)) { + temp_y_units = temp_y_units + 1; + } + } + + diffs.push(temp_y_units); + }); + + var max_diff = Math.max.apply(Math, diffs); + y_units = (y_units - max_diff); + + return y_units > 0 ? y_units : 0; + }; + + + /** + * Get widgets below a widget. + * + * @method widgets_below + * @param {HTMLElement} $el The jQuery wrapped HTMLElement. + * @return {HTMLElements} A jQuery collection of HTMLElements. + */ + fn.widgets_below = function($el) { + var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; + var self = this; + var ga = this.gridmap; + var next_row = el_grid_data.row + el_grid_data.size_y - 1; + var $nexts = $([]); + + this.for_each_column_occupied(el_grid_data, function(col) { + self.for_each_widget_below(col, next_row, + function(tcol, trow) { + if (!self.is_player(this) && + $.inArray(this, $nexts) === -1) { + $nexts = $nexts.add(this); + return true; // break + } + }); + }); + + return this.sort_by_row_asc($nexts); + }; + + + /** + * Update the array of mapped positions with the new player position. + * + * @method set_cells_player_occupies + * @param {Number} col The new player col. + * @param {Number} col The new player row. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.set_cells_player_occupies = function(col, row) { + this.remove_from_gridmap(this.placeholder_grid_data); + this.placeholder_grid_data.col = col; + this.placeholder_grid_data.row = row; + this.add_to_gridmap(this.placeholder_grid_data, this.$player); + return this; + }; + + + /** + * Remove from the array of mapped positions the reference to the player. + * + * @method empty_cells_player_occupies + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells_player_occupies = function() { + this.remove_from_gridmap(this.placeholder_grid_data); + return this; + }; + + + fn.can_go_up = function($el) { + var el_grid_data = $el.coords().grid; + var initial_row = el_grid_data.row; + var prev_row = initial_row - 1; + var ga = this.gridmap; + var upper_rows_by_column = []; + + var result = true; + if (initial_row === 1) { return false; } + + this.for_each_column_occupied(el_grid_data, function(col) { + var $w = this.is_widget(col, prev_row); + if (this.is_occupied(col, prev_row) || + this.is_player(col, prev_row) || + this.is_placeholder_in(col, prev_row) || + this.is_player_in(col, prev_row) + ) { + result = false; + return true; //break + } + }); + + return result; + }; + + + + /** + * Check if it's possible to move a widget to a specific col/row. It takes + * into account the dimensions (`size_y` and `size_x` attrs. of the grid + * coords object) the widget occupies. + * + * @method can_move_to + * @param {Object} widget_grid_data The grid coords object that represents + * the widget. + * @param {Object} col The col to check. + * @param {Object} row The row to check. + * @return {Boolean} Returns true if all cells are empty, else return false. + */ + fn.can_move_to = function(widget_grid_data, col, row) { + var ga = this.gridmap; + var $w = widget_grid_data.el; + var future_wd = { + size_y: widget_grid_data.size_y, + size_x: widget_grid_data.size_x, + col: col, + row: row + }; + var result = true; + + //Prevents widgets go out of the grid + var right_col = col + widget_grid_data.size_x - 1; + if (right_col > this.cols) { + return false; + }; + + this.for_each_cell_occupied(future_wd, function(tcol, trow) { + var $tw = this.is_widget(tcol, trow); + if ($tw && (!widget_grid_data.el || $tw.is($w))) { + result = false; + } + }); + + return result; + }; + + + /** + * Given the leftmost column returns all columns that are overlapping + * with the player. + * + * @method get_targeted_columns + * @param {Number} [from_col] The leftmost column. + * @return {Array} Returns an array with column numbers. + */ + fn.get_targeted_columns = function(from_col) { + var max = (from_col || this.player_grid_data.col) + + (this.player_grid_data.size_x - 1); + var cols = []; + for (var col = from_col; col <= max; col++) { + cols.push(col); + } + return cols; + }; + + + /** + * Given the upper row returns all rows that are overlapping with the player. + * + * @method get_targeted_rows + * @param {Number} [from_row] The upper row. + * @return {Array} Returns an array with row numbers. + */ + fn.get_targeted_rows = function(from_row) { + var max = (from_row || this.player_grid_data.row) + + (this.player_grid_data.size_y - 1); + var rows = []; + for (var row = from_row; row <= max; row++) { + rows.push(row); + } + return rows; + }; + + /** + * Get all columns and rows that a widget occupies. + * + * @method get_cells_occupied + * @param {Object} el_grid_data The grid coords object of the widget. + * @return {Object} Returns an object like `{ cols: [], rows: []}`. + */ + fn.get_cells_occupied = function(el_grid_data) { + var cells = { cols: [], rows: []}; + var i; + if (arguments[1] instanceof jQuery) { + el_grid_data = arguments[1].coords().grid; + } + + for (i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + cells.cols.push(col); + } + + for (i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + cells.rows.push(row); + } + + return cells; + }; + + + /** + * Iterate over the cells occupied by a widget executing a function for + * each one. + * + * @method for_each_cell_occupied + * @param {Object} el_grid_data The grid coords object that represents the + * widget. + * @param {Function} callback The function to execute on each column + * iteration. Column and row are passed as arguments. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_cell_occupied = function(grid_data, callback) { + this.for_each_column_occupied(grid_data, function(col) { + this.for_each_row_occupied(grid_data, function(row) { + callback.call(this, col, row); + }); + }); + return this; + }; + + + /** + * Iterate over the columns occupied by a widget executing a function for + * each one. + * + * @method for_each_column_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The column number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_column_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_x; i++) { + var col = el_grid_data.col + i; + callback.call(this, col, el_grid_data); + } + }; + + + /** + * Iterate over the rows occupied by a widget executing a function for + * each one. + * + * @method for_each_row_occupied + * @param {Object} el_grid_data The grid coords object that represents + * the widget. + * @param {Function} callback The function to execute on each column + * iteration. The row number is passed as first argument. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_row_occupied = function(el_grid_data, callback) { + for (var i = 0; i < el_grid_data.size_y; i++) { + var row = el_grid_data.row + i; + callback.call(this, row, el_grid_data); + } + }; + + + + fn._traversing_widgets = function(type, direction, col, row, callback) { + var ga = this.gridmap; + if (!ga[col]) { return; } + + var cr, max; + var action = type + '/' + direction; + if (arguments[2] instanceof jQuery) { + var el_grid_data = arguments[2].coords().grid; + col = el_grid_data.col; + row = el_grid_data.row; + callback = arguments[3]; + } + var matched = []; + var trow = row; + + + var methods = { + 'for_each/above': function() { + while (trow--) { + if (trow > 0 && this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + }, + 'for_each/below': function() { + for (trow = row + 1, max = ga[col].length; trow < max; trow++) { + if (this.is_widget(col, trow) && + $.inArray(ga[col][trow], matched) === -1 + ) { + cr = callback.call(ga[col][trow], col, trow); + matched.push(ga[col][trow]); + if (cr) { break; } + } + } + } + }; + + if (methods[action]) { + methods[action].call(this); + } + }; + + + /** + * Iterate over each widget above the column and row specified. + * + * @method for_each_widget_above + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery + * wrapped HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_above = function(col, row, callback) { + this._traversing_widgets('for_each', 'above', col, row, callback); + return this; + }; + + + /** + * Iterate over each widget below the column and row specified. + * + * @method for_each_widget_below + * @param {Number} col The column to start iterating. + * @param {Number} row The row to start iterating. + * @param {Function} callback The function to execute on each widget + * iteration. The value of `this` inside the function is the jQuery wrapped + * HTMLElement. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.for_each_widget_below = function(col, row, callback) { + this._traversing_widgets('for_each', 'below', col, row, callback); + return this; + }; + + + /** + * Returns the highest occupied cell in the grid. + * + * @method get_highest_occupied_cell + * @return {Object} Returns an object with `col` and `row` numbers. + */ + fn.get_highest_occupied_cell = function() { + var r; + var gm = this.gridmap; + var rows = []; + var row_in_col = []; + for (var c = gm.length - 1; c >= 1; c--) { + for (r = gm[c].length - 1; r >= 1; r--) { + if (this.is_widget(c, r)) { + rows.push(r); + row_in_col[r] = c; + break; + } + } + } + + var highest_row = Math.max.apply(Math, rows); + + this.highest_occupied_cell = { + col: row_in_col[highest_row], + row: highest_row + }; + + return this.highest_occupied_cell; + }; + + + fn.get_widgets_from = function(col, row) { + var ga = this.gridmap; + var $widgets = $(); + + if (col) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var tcol = $(this).attr('data-col'); + return (tcol === col || tcol > col); + }) + ); + } + + if (row) { + $widgets = $widgets.add( + this.$widgets.filter(function() { + var trow = $(this).attr('data-row'); + return (trow === row || trow > row); + }) + ); + } + + return $widgets; + } + + + /** + * Set the current height of the parent grid. + * + * @method set_dom_grid_height + * @return {Object} Returns the instance of the Gridster class. + */ + fn.set_dom_grid_height = function() { + var r = this.get_highest_occupied_cell().row; + this.$el.css('height', r * this.min_widget_height); + return this; + }; + + + /** + * It generates the neccessary styles to position the widgets. + * + * @method generate_stylesheet + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_stylesheet = function(opts) { + var styles = ''; + var extra_cells = 10; + var max_size_y = this.options.max_size_y; + var max_size_x = this.options.max_size_x; + var i; + var rules; + + opts || (opts = {}); + opts.cols || (opts.cols = this.cols); + opts.rows || (opts.rows = this.rows); + opts.namespace || (opts.namespace = ''); + opts.widget_base_dimensions || + (opts.widget_base_dimensions = this.options.widget_base_dimensions); + opts.widget_margins || + (opts.widget_margins = this.options.widget_margins); + opts.min_widget_width = (opts.widget_margins[0] * 2) + + opts.widget_base_dimensions[0]; + opts.min_widget_height = (opts.widget_margins[1] * 2) + + opts.widget_base_dimensions[1]; + + var serialized_opts = $.param(opts); + // don't duplicate stylesheets for the same configuration + if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { + return false; + } + + Gridster.generated_stylesheets.push(serialized_opts); + + /* generate CSS styles for cols */ + for (i = opts.cols + extra_cells; i >= 0; i--) { + styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + + ((i * opts.widget_base_dimensions[0]) + + (i * opts.widget_margins[0]) + + ((i + 1) * opts.widget_margins[0])) + 'px;} '); + } + + /* generate CSS styles for rows */ + for (i = opts.rows + extra_cells; i >= 0; i--) { + styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + + ((i * opts.widget_base_dimensions[1]) + + (i * opts.widget_margins[1]) + + ((i + 1) * opts.widget_margins[1]) ) + 'px;} '); + } + + for (var y = 1; y <= max_size_y; y++) { + styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + + (y * opts.widget_base_dimensions[1] + + (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}'); + } + + for (var x = 1; x <= max_size_x; x++) { + styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + + (x * opts.widget_base_dimensions[0] + + (x - 1) * (opts.widget_margins[0] * 2)) + 'px;}'); + } + + return this.add_style_tag(styles); + }; + + + /** + * Injects the given CSS as string to the head of the document. + * + * @method add_style_tag + * @param {String} css The styles to apply. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_style_tag = function(css) { + var d = document; + var tag = d.createElement('style'); + + d.getElementsByTagName('head')[0].appendChild(tag); + tag.setAttribute('type', 'text/css'); + + if (tag.styleSheet) { + tag.styleSheet.cssText = css; + }else{ + tag.appendChild(document.createTextNode(css)); + } + return this; + }; + + + /** + * Generates a faux grid to collide with it when a widget is dragged and + * detect row or column that we want to go. + * + * @method generate_faux_grid + * @param {Number} rows Number of columns. + * @param {Number} cols Number of rows. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_faux_grid = function(rows, cols) { + this.faux_grid = []; + this.gridmap = []; + var col; + var row; + for (col = cols; col > 0; col--) { + this.gridmap[col] = []; + for (row = rows; row > 0; row--) { + var coords = $({ + left: this.baseX + ((col - 1) * this.min_widget_width), + top: this.baseY + (row -1) * this.min_widget_height, + width: this.min_widget_width, + height: this.min_widget_height, + col: col, + row: row, + original_col: col, + original_row: row + }).coords(); + + this.gridmap[col][row] = false; + this.faux_grid.push(coords); + } + } + return this; + }; + + + /** + * Recalculates the offsets for the faux grid. You need to use it when + * the browser is resized. + * + * @method recalculate_faux_grid + * @return {Object} Returns the instance of the Gridster class. + */ + fn.recalculate_faux_grid = function() { + var aw = this.$wrapper.width(); + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + $.each(this.faux_grid, $.proxy(function(i, coords) { + this.faux_grid[i] = coords.update({ + left: this.baseX + (coords.data.col -1) * this.min_widget_width, + top: this.baseY + (coords.data.row -1) * this.min_widget_height + }); + + }, this)); + + return this; + }; + + + /** + * Get all widgets in the DOM and register them. + * + * @method get_widgets_from_DOM + * @return {Object} Returns the instance of the Gridster class. + */ + fn.get_widgets_from_DOM = function() { + this.$widgets.each($.proxy(function(i, widget) { + this.register_widget($(widget)); + }, this)); + return this; + }; + + + /** + * Calculate columns and rows to be set based on the configuration + * parameters, grid dimensions, etc ... + * + * @method generate_grid_and_stylesheet + * @return {Object} Returns the instance of the Gridster class. + */ + fn.generate_grid_and_stylesheet = function() { + var aw = this.$wrapper.width(); + var ah = this.$wrapper.height(); + + var cols = Math.floor(aw / this.min_widget_width) + + this.options.extra_cols; + var rows = Math.floor(ah / this.min_widget_height) + + this.options.extra_rows; + + var actual_cols = this.$widgets.map(function() { + return $(this).attr('data-col'); + }); + actual_cols = Array.prototype.slice.call(actual_cols, 0); + //needed to pass tests with phantomjs + actual_cols.length || (actual_cols = [0]); + + var actual_rows = this.$widgets.map(function() { + return $(this).attr('data-row'); + }); + actual_rows = Array.prototype.slice.call(actual_rows, 0); + //needed to pass tests with phantomjs + actual_rows.length || (actual_rows = [0]); + + var min_cols = Math.max.apply(Math, actual_cols); + var min_rows = Math.max.apply(Math, actual_rows); + + this.cols = Math.max(min_cols, cols, this.options.min_cols); + this.rows = Math.max(min_rows, rows, this.options.min_rows); + + this.baseX = ($(window).width() - aw) / 2; + this.baseY = this.$wrapper.offset().top; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + /* more faux rows that needed are created so that there are cells + * where drag beyond the limits */ + return this.generate_faux_grid(this.rows, this.cols); + }; + + + //jQuery adapter + $.fn.gridster = function(options) { + return this.each(function() { + if (!$(this).data('gridster')) { + $(this).data('gridster', new Gridster( this, options )); + } + }); + }; + + +}(jQuery, window, document)); \ No newline at end of file diff --git a/templates/project/assets/javascripts/gridster/jquery.leanModal.min.js b/templates/project/assets/javascripts/gridster/jquery.leanModal.min.js new file mode 100644 index 0000000..a5772dd --- /dev/null +++ b/templates/project/assets/javascripts/gridster/jquery.leanModal.min.js @@ -0,0 +1,5 @@ +// leanModal v1.1 by Ray Stone - http://finelysliced.com.au +// Dual licensed under the MIT and GPL + +(function($){$.fn.extend({leanModal:function(options){var defaults={top:100,overlay:0.5,closeButton:null};var overlay=$("
    ");$("body").append(overlay);options=$.extend(defaults,options);return this.each(function(){var o=options;$(this).click(function(e){var modal_id=$(this).attr("href");$("#lean_overlay").click(function(){close_modal(modal_id)});$(o.closeButton).click(function(){close_modal(modal_id)});var modal_height=$(modal_id).outerHeight();var modal_width=$(modal_id).outerWidth(); +$("#lean_overlay").css({"display":"block",opacity:0});$("#lean_overlay").fadeTo(200,o.overlay);$(modal_id).css({"display":"block","position":"fixed","opacity":0,"z-index":11000,"left":50+"%","margin-left":-(modal_width/2)+"px","top":o.top+"px"});$(modal_id).fadeTo(200,1);e.preventDefault()})});function close_modal(modal_id){$("#lean_overlay").fadeOut(200);$(modal_id).css({"display":"none"})}}})})(jQuery); diff --git a/templates/project/assets/javascripts/gridster/utils.js b/templates/project/assets/javascripts/gridster/utils.js new file mode 100755 index 0000000..5f340b3 --- /dev/null +++ b/templates/project/assets/javascripts/gridster/utils.js @@ -0,0 +1,41 @@ +;(function(window, undefined) { + /* Debounce and throttle functions taken from underscore.js */ + window.debounce = function(func, wait, immediate) { + var timeout; + return function() { + var context = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(context, args); + }; + if (immediate && !timeout) func.apply(context, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + + window.throttle = function(func, wait) { + var context, args, timeout, throttling, more, result; + var whenDone = debounce( + function(){ more = throttling = false; }, wait); + return function() { + context = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(context, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(context, args); + } + whenDone(); + throttling = true; + return result; + }; + }; + +})(window); diff --git a/templates/project/assets/javascripts/jquery.knob.js b/templates/project/assets/javascripts/jquery.knob.js new file mode 100644 index 0000000..3224638 --- /dev/null +++ b/templates/project/assets/javascripts/jquery.knob.js @@ -0,0 +1,646 @@ +/*!jQuery Knob*/ +/** + * Downward compatible, touchable dial + * + * Version: 1.2.0 (15/07/2012) + * Requires: jQuery v1.7+ + * + * Copyright (c) 2012 Anthony Terrien + * Under MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Thanks to vor, eskimoblood, spiffistan, FabrizioC + */ +$(function () { + + /** + * Kontrol library + */ + "use strict"; + + /** + * Definition of globals and core + */ + var k = {}, // kontrol + max = Math.max, + min = Math.min; + + k.c = {}; + k.c.d = $(document); + k.c.t = function (e) { + return e.originalEvent.touches.length - 1; + }; + + /** + * Kontrol Object + * + * Definition of an abstract UI control + * + * Each concrete component must call this one. + * + * k.o.call(this); + * + */ + k.o = function () { + var s = this; + + this.o = null; // array of options + this.$ = null; // jQuery wrapped element + this.i = null; // mixed HTMLInputElement or array of HTMLInputElement + this.g = null; // 2D graphics context for 'pre-rendering' + this.v = null; // value ; mixed array or integer + this.cv = null; // change value ; not commited value + this.x = 0; // canvas x position + this.y = 0; // canvas y position + this.$c = null; // jQuery canvas element + this.c = null; // rendered canvas context + this.t = 0; // touches index + this.isInit = false; + this.fgColor = null; // main color + this.pColor = null; // previous color + this.dH = null; // draw hook + this.cH = null; // change hook + this.eH = null; // cancel hook + this.rH = null; // release hook + + this.run = function () { + var cf = function (e, conf) { + var k; + for (k in conf) { + s.o[k] = conf[k]; + } + s.init(); + s._configure() + ._draw(); + }; + + if(this.$.data('kontroled')) return; + this.$.data('kontroled', true); + + this.extend(); + this.o = $.extend( + { + // Config + min : this.$.data('min') || 0, + max : this.$.data('max') || 100, + stopper : true, + readOnly : this.$.data('readonly'), + + // UI + cursor : (this.$.data('cursor') === true && 30) + || this.$.data('cursor') + || 0, + thickness : this.$.data('thickness') || 0.35, + width : this.$.data('width') || 200, + height : this.$.data('height') || 200, + displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'), + displayPrevious : this.$.data('displayprevious'), + fgColor : this.$.data('fgcolor') || '#87CEEB', + inline : false, + + // Hooks + draw : null, // function () {} + change : null, // function (value) {} + cancel : null, // function () {} + release : null // function (value) {} + }, this.o + ); + + // routing value + if(this.$.is('fieldset')) { + + // fieldset = array of integer + this.v = {}; + this.i = this.$.find('input') + this.i.each(function(k) { + var $this = $(this); + s.i[k] = $this; + s.v[k] = $this.val(); + + $this.bind( + 'change' + , function () { + var val = {}; + val[k] = $this.val(); + s.val(val); + } + ); + }); + this.$.find('legend').remove(); + + } else { + // input = integer + this.i = this.$; + this.v = this.$.val(); + (this.v == '') && (this.v = this.o.min); + + this.$.bind( + 'change' + , function () { + s.val(s.$.val()); + } + ); + } + + (!this.o.displayInput) && this.$.hide(); + + this.$c = $(''); + this.c = this.$c[0].getContext("2d"); + + this.$ + .wrap($('
    ')) + .before(this.$c); + + if (this.v instanceof Object) { + this.cv = {}; + this.copy(this.v, this.cv); + } else { + this.cv = this.v; + } + + this.$ + .bind("configure", cf) + .parent() + .bind("configure", cf); + + this._listen() + ._configure() + ._xy() + .init(); + + this.isInit = true; + + this._draw(); + + return this; + }; + + this._draw = function () { + + // canvas pre-rendering + var d = true, + c = document.createElement('canvas'); + + c.width = s.o.width; + c.height = s.o.height; + s.g = c.getContext('2d'); + + s.clear(); + + s.dH + && (d = s.dH()); + + (d !== false) && s.draw(); + + s.c.drawImage(c, 0, 0); + c = null; + }; + + this._touch = function (e) { + + var touchMove = function (e) { + + var v = s.xy2val( + e.originalEvent.touches[s.t].pageX, + e.originalEvent.touches[s.t].pageY + ); + + if (v == s.cv) return; + + if ( + s.cH + && (s.cH(v) === false) + ) return; + + + s.change(v); + s._draw(); + }; + + // get touches index + this.t = k.c.t(e); + + // First touch + touchMove(e); + + // Touch events listeners + k.c.d + .bind("touchmove.k", touchMove) + .bind( + "touchend.k" + , function () { + k.c.d.unbind('touchmove.k touchend.k'); + + if ( + s.rH + && (s.rH(s.cv) === false) + ) return; + + s.val(s.cv); + } + ); + + return this; + }; + + this._mouse = function (e) { + + var mouseMove = function (e) { + var v = s.xy2val(e.pageX, e.pageY); + if (v == s.cv) return; + + if ( + s.cH + && (s.cH(v) === false) + ) return; + + s.change(v); + s._draw(); + }; + + // First click + mouseMove(e); + + // Mouse events listeners + k.c.d + .bind("mousemove.k", mouseMove) + .bind( + // Escape key cancel current change + "keyup.k" + , function (e) { + if (e.keyCode === 27) { + k.c.d.unbind("mouseup.k mousemove.k keyup.k"); + + if ( + s.eH + && (s.eH() === false) + ) return; + + s.cancel(); + } + } + ) + .bind( + "mouseup.k" + , function (e) { + k.c.d.unbind('mousemove.k mouseup.k keyup.k'); + + if ( + s.rH + && (s.rH(s.cv) === false) + ) return; + + s.val(s.cv); + } + ); + + return this; + }; + + this._xy = function () { + var o = this.$c.offset(); + this.x = o.left; + this.y = o.top; + return this; + }; + + this._listen = function () { + + if (!this.o.readOnly) { + this.$c + .bind( + "mousedown" + , function (e) { + e.preventDefault(); + s._xy()._mouse(e); + } + ) + .bind( + "touchstart" + , function (e) { + e.preventDefault(); + s._xy()._touch(e); + } + ); + this.listen(); + } else { + this.$.attr('readonly', 'readonly'); + } + + return this; + }; + + this._configure = function () { + + // Hooks + if (this.o.draw) this.dH = this.o.draw; + if (this.o.change) this.cH = this.o.change; + if (this.o.cancel) this.eH = this.o.cancel; + if (this.o.release) this.rH = this.o.release; + + if (this.o.displayPrevious) { + this.pColor = this.h2rgba(this.o.fgColor, "0.4"); + this.fgColor = this.h2rgba(this.o.fgColor, "0.6"); + } else { + this.fgColor = this.o.fgColor; + } + + return this; + }; + + this._clear = function () { + this.$c[0].width = this.$c[0].width; + }; + + // Abstract methods + this.listen = function () {}; // on start, one time + this.extend = function () {}; // each time configure triggered + this.init = function () {}; // each time configure triggered + this.change = function (v) {}; // on change + this.val = function (v) {}; // on release + this.xy2val = function (x, y) {}; // + this.draw = function () {}; // on change / on release + this.clear = function () { this._clear(); }; + + // Utils + this.h2rgba = function (h, a) { + var rgb; + h = h.substring(1,7) + rgb = [parseInt(h.substring(0,2),16) + ,parseInt(h.substring(2,4),16) + ,parseInt(h.substring(4,6),16)]; + return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")"; + }; + + this.copy = function (f, t) { + for (var i in f) { t[i] = f[i]; } + }; + }; + + + /** + * k.Dial + */ + k.Dial = function () { + k.o.call(this); + + this.startAngle = null; + this.xy = null; + this.radius = null; + this.lineWidth = null; + this.cursorExt = null; + this.w2 = null; + this.PI2 = 2*Math.PI; + + this.extend = function () { + this.o = $.extend( + { + bgColor : this.$.data('bgcolor') || '#EEEEEE', + angleOffset : this.$.data('angleoffset') || 0, + angleArc : this.$.data('anglearc') || 360, + inline : true + }, this.o + ); + }; + + this.val = function (v) { + if (null != v) { + this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v; + this.v = this.cv; + this.$.val(this.v); + this._draw(); + } else { + return this.v; + } + }; + + this.xy2val = function (x, y) { + var a, ret; + + a = Math.atan2( + x - (this.x + this.w2) + , - (y - this.y - this.w2) + ) - this.angleOffset; + + if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) { + // if isset angleArc option, set to min if .5 under min + a = 0; + } else if (a < 0) { + a += this.PI2; + } + + ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc)) + + this.o.min; + + this.o.stopper + && (ret = max(min(ret, this.o.max), this.o.min)); + + return ret; + }; + + this.listen = function () { + // bind MouseWheel + var s = this, + mw = function (e) { + e.preventDefault(); + + var ori = e.originalEvent + ,deltaX = ori.detail || ori.wheelDeltaX + ,deltaY = ori.detail || ori.wheelDeltaY + ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? 1 : deltaX<0 || deltaY<0 ? -1 : 0); + + if ( + s.cH + && (s.cH(v) === false) + ) return; + + s.val(v); + } + , kval, to, m = 1, kv = {37:-1, 38:1, 39:1, 40:-1}; + + this.$ + .bind( + "keydown" + ,function (e) { + var kc = e.keyCode; + kval = parseInt(String.fromCharCode(kc)); + + if (isNaN(kval)) { + + (kc !== 13) // enter + && (kc !== 8) // bs + && (kc !== 9) // tab + && (kc !== 189) // - + && e.preventDefault(); + + // arrows + if ($.inArray(kc,[37,38,39,40]) > -1) { + e.preventDefault(); + + var v = parseInt(s.$.val()) + kv[kc] * m; + + s.o.stopper + && (v = max(min(v, s.o.max), s.o.min)); + + s.change(v); + s._draw(); + + // long time keydown speed-up + to = window.setTimeout( + function () { m*=2; } + ,30 + ); + } + } + } + ) + .bind( + "keyup" + ,function (e) { + if (isNaN(kval)) { + if (to) { + window.clearTimeout(to); + to = null; + m = 1; + s.val(s.$.val()); + } + } else { + // kval postcond + (s.$.val() > s.o.max && s.$.val(s.o.max)) + || (s.$.val() < s.o.min && s.$.val(s.o.min)); + } + + } + ); + + this.$c.bind("mousewheel DOMMouseScroll", mw); + this.$.bind("mousewheel DOMMouseScroll", mw) + }; + + this.init = function () { + + if ( + this.v < this.o.min + || this.v > this.o.max + ) this.v = this.o.min; + + this.$.val(this.v); + this.w2 = this.o.width / 2; + this.cursorExt = this.o.cursor / 100; + this.xy = this.w2; + this.lineWidth = this.xy * this.o.thickness; + this.radius = this.xy - this.lineWidth / 2; + + this.o.angleOffset + && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset); + + this.o.angleArc + && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc); + + // deg to rad + this.angleOffset = this.o.angleOffset * Math.PI / 180; + this.angleArc = this.o.angleArc * Math.PI / 180; + + // compute start and end angles + this.startAngle = 1.5 * Math.PI + this.angleOffset; + this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc; + + var s = max( + String(Math.abs(this.o.max)).length + , String(Math.abs(this.o.min)).length + , 2 + ) + 2; + + this.o.displayInput + && this.i.css({ + 'width' : ((this.o.width / 2 + 4) >> 0) + 'px' + ,'height' : ((this.o.width / 3) >> 0) + 'px' + ,'position' : 'absolute' + ,'vertical-align' : 'middle' + ,'margin-top' : ((this.o.width / 3) >> 0) + 'px' + ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px' + ,'border' : 0 + ,'background' : 'none' + ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial' + ,'text-align' : 'center' + ,'color' : this.o.fgColor + ,'padding' : '0px' + ,'-webkit-appearance': 'none' + }) + || this.i.css({ + 'width' : '0px' + ,'visibility' : 'hidden' + }); + }; + + this.change = function (v) { + this.cv = v; + this.$.val(v); + }; + + this.angle = function (v) { + return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min); + }; + + this.draw = function () { + + var c = this.g, // context + a = this.angle(this.cv) // Angle + , sat = this.startAngle // Start angle + , eat = sat + a // End angle + , sa, ea // Previous angles + , r = 1; + + c.lineWidth = this.lineWidth; + + this.o.cursor + && (sat = eat - this.cursorExt) + && (eat = eat + this.cursorExt); + + c.beginPath(); + c.strokeStyle = this.o.bgColor; + c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true); + c.stroke(); + + if (this.o.displayPrevious) { + ea = this.startAngle + this.angle(this.v); + sa = this.startAngle; + this.o.cursor + && (sa = ea - this.cursorExt) + && (ea = ea + this.cursorExt); + + c.beginPath(); + c.strokeStyle = this.pColor; + c.arc(this.xy, this.xy, this.radius, sa, ea, false); + c.stroke(); + r = (this.cv == this.v); + } + + c.beginPath(); + c.strokeStyle = r ? this.o.fgColor : this.fgColor ; + c.arc(this.xy, this.xy, this.radius, sat, eat, false); + c.stroke(); + }; + + this.cancel = function () { + this.val(this.v); + }; + }; + + $.fn.dial = $.fn.knob = function (o) { + return this.each( + function () { + var d = new k.Dial(); + d.o = o; + d.$ = $(this); + d.run(); + } + ).parent(); + }; + +}); \ No newline at end of file diff --git a/templates/project/assets/stylesheets/application.scss b/templates/project/assets/stylesheets/application.scss new file mode 100644 index 0000000..c3b2a67 --- /dev/null +++ b/templates/project/assets/stylesheets/application.scss @@ -0,0 +1,227 @@ +/* + //=require_directory . + //=require_tree ../../widgets +*/ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$background-color: #222; +$text-color: #fff; + +$background-warning-color-1: #e82711; +$background-warning-color-2: #9b2d23; +$text-warning-color: #fff; + +$background-danger-color-1: #eeae32; +$background-danger-color-2: #ff9618; +$text-danger-color: #fff; + +@-webkit-keyframes status-warning-background { + 0% { background-color: $background-warning-color-1; } + 50% { background-color: $background-warning-color-2; } + 100% { background-color: $background-warning-color-1; } +} +@-webkit-keyframes status-danger-background { + 0% { background-color: $background-danger-color-1; } + 50% { background-color: $background-danger-color-2; } + 100% { background-color: $background-danger-color-1; } +} +@mixin animation($animation-name, $duration, $function, $animation-iteration-count:""){ + -webkit-animation: $animation-name $duration $function #{$animation-iteration-count}; + -moz-animation: $animation-name $duration $function #{$animation-iteration-count}; + -ms-animation: $animation-name $duration $function #{$animation-iteration-count}; +} + +// ---------------------------------------------------------------------------- +// Base styles +// ---------------------------------------------------------------------------- +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +body { + margin: 0; + background-color: $background-color; + font-size: 20px; + color: $text-color; + font-family: 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +b, strong { + font-weight: bold; +} + +a { + text-decoration: none; + color: inherit; +} + +img { + border: 0; + -ms-interpolation-mode: bicubic; + vertical-align: middle; +} + +img, object { + max-width: 100%; +} + +iframe { + max-width: 100%; +} + +table { + border-collapse: collapse; + border-spacing: 0; + width: 100%; +} + +td { + vertical-align: middle; +} + +ul, ol { + padding: 0; + margin: 0; +} + +h1, h2, h3, h4, h5, p { + padding: 0; + margin: 0; +} +h1 { + margin-bottom: 12px; + text-align: center; + font-size: 30px; + font-weight: 300; +} +h2 { + text-transform: uppercase; + font-size: 80px; + font-weight: 700; + color: $text-color; +} +h3 { + font-size: 25px; + font-weight: 600; + color: $text-color; +} + +// ---------------------------------------------------------------------------- +// Base widget styles +// ---------------------------------------------------------------------------- +.gridster { + margin: 0px auto; +} + +.list-nostyle { + list-style: none; +} + +.gridster ul { + list-style: none; +} + +.gs_w { + width: 100%; + display: table; + cursor: pointer; +} + +.widget { + padding: 25px 12px; + text-align: center; + width: 100%; + display: table-cell; + vertical-align: middle; +} + +.widget.status-warning { + background-color: $background-warning-color-1; + @include animation(status-warning-background, 2s, ease, infinite); + + .icon-warning-sign { + display: inline-block; + } + + .title, .text-moreinfo { + color: $text-warning-color; + } +} + +.widget.status-danger { + color: $text-danger-color; + background-color: $background-danger-color-1; + @include animation(status-danger-background, 2s, ease, infinite); + + .icon-warning-sign { + display: inline-block; + } + + .title, .text-moreinfo { + color: $text-danger-color; + } +} + +.text-moreinfo { + margin-top: 12px; + font-size: 15px; +} + +#save-gridster { + display: none; + position: fixed; + top: 0; + margin: 0px auto; + left: 50%; + z-index: 1000; + background: black; + width: 190px; + text-align: center; + border: 1px solid white; + border-top: 0px; + margin-left: -95px; + padding: 15px; +} + +#save-gridster:hover { + padding-top: 25px; +} + +#saving-instructions { + display: none; + padding: 10px; + width: 500px; + height: 122px; + z-index: 1000; + background: white; + top: 100px; + color: black; + + textarea { + white-space: nowrap; + width: 494px; + height: 80px; + } +} + +#lean_overlay { + position: fixed; + z-index:100; + top: 0px; + left: 0px; + height:100%; + width:100%; + background: #000; + display: none; +} + + +// ---------------------------------------------------------------------------- +// Clearfix +// ---------------------------------------------------------------------------- +.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; } +.clearfix:after { clear: both; } +.clearfix { zoom: 1; } \ No newline at end of file diff --git a/templates/project/assets/stylesheets/font-awesome.css b/templates/project/assets/stylesheets/font-awesome.css new file mode 100644 index 0000000..c642925 --- /dev/null +++ b/templates/project/assets/stylesheets/font-awesome.css @@ -0,0 +1,303 @@ +/* Font Awesome + the iconic font designed for use with Twitter Bootstrap + ------------------------------------------------------- + The full suite of pictographic icons, examples, and documentation + can be found at: http://fortawesome.github.com/Font-Awesome/ + + License + ------------------------------------------------------- + The Font Awesome webfont, CSS, and LESS files are licensed under CC BY 3.0: + http://creativecommons.org/licenses/by/3.0/ A mention of + 'Font Awesome - http://fortawesome.github.com/Font-Awesome' in human-readable + source code is considered acceptable attribution (most common on the web). + If human readable source code is not available to the end user, a mention in + an 'About' or 'Credits' screen is considered acceptable (most common in desktop + or mobile software). + + Contact + ------------------------------------------------------- + Email: dave@davegandy.com + Twitter: http://twitter.com/fortaweso_me + Work: http://lemonwi.se co-founder + + */ +@font-face { + font-family: "FontAwesome"; + src: url('/assets/fontawesome-webfont.eot'); + src: url('/assets/fontawesome-webfont.eot?#iefix') format('eot'), url('/assets/fontawesome-webfont.woff') format('woff'), url('/assets/fontawesome-webfont.ttf') format('truetype'), url('/assets/fontawesome-webfont.svg#FontAwesome') format('svg'); + font-weight: normal; + font-style: normal; +} + +/* Font Awesome styles + ------------------------------------------------------- */ +[class^="icon-"]:before, [class*=" icon-"]:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + display: inline-block; + text-decoration: inherit; +} +a [class^="icon-"], a [class*=" icon-"] { + display: inline-block; + text-decoration: inherit; +} +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: top; + font-size: 1.3333333333333333em; +} +.btn [class^="icon-"], .btn [class*=" icon-"] { + /* keeps button heights with and without icons the same */ + + line-height: .9em; +} +li [class^="icon-"], li [class*=" icon-"] { + display: inline-block; + width: 1.25em; + text-align: center; +} +li .icon-large[class^="icon-"], li .icon-large[class*=" icon-"] { + /* 1.5 increased font size for icon-large * 1.25 width */ + + width: 1.875em; +} +li[class^="icon-"], li[class*=" icon-"] { + margin-left: 0; + list-style-type: none; +} +li[class^="icon-"]:before, li[class*=" icon-"]:before { + text-indent: -2em; + text-align: center; +} +li[class^="icon-"].icon-large:before, li[class*=" icon-"].icon-large:before { + text-indent: -1.3333333333333333em; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { content: "\f000"; } +.icon-music:before { content: "\f001"; } +.icon-search:before { content: "\f002"; } +.icon-envelope:before { content: "\f003"; } +.icon-heart:before { content: "\f004"; } +.icon-star:before { content: "\f005"; } +.icon-star-empty:before { content: "\f006"; } +.icon-user:before { content: "\f007"; } +.icon-film:before { content: "\f008"; } +.icon-th-large:before { content: "\f009"; } +.icon-th:before { content: "\f00a"; } +.icon-th-list:before { content: "\f00b"; } +.icon-ok:before { content: "\f00c"; } +.icon-remove:before { content: "\f00d"; } +.icon-zoom-in:before { content: "\f00e"; } + +.icon-zoom-out:before { content: "\f010"; } +.icon-off:before { content: "\f011"; } +.icon-signal:before { content: "\f012"; } +.icon-cog:before { content: "\f013"; } +.icon-trash:before { content: "\f014"; } +.icon-home:before { content: "\f015"; } +.icon-file:before { content: "\f016"; } +.icon-time:before { content: "\f017"; } +.icon-road:before { content: "\f018"; } +.icon-download-alt:before { content: "\f019"; } +.icon-download:before { content: "\f01a"; } +.icon-upload:before { content: "\f01b"; } +.icon-inbox:before { content: "\f01c"; } +.icon-play-circle:before { content: "\f01d"; } +.icon-repeat:before { content: "\f01e"; } + +/* \f020 doesn't work in Safari. all shifted one down */ +.icon-refresh:before { content: "\f021"; } +.icon-list-alt:before { content: "\f022"; } +.icon-lock:before { content: "\f023"; } +.icon-flag:before { content: "\f024"; } +.icon-headphones:before { content: "\f025"; } +.icon-volume-off:before { content: "\f026"; } +.icon-volume-down:before { content: "\f027"; } +.icon-volume-up:before { content: "\f028"; } +.icon-qrcode:before { content: "\f029"; } +.icon-barcode:before { content: "\f02a"; } +.icon-tag:before { content: "\f02b"; } +.icon-tags:before { content: "\f02c"; } +.icon-book:before { content: "\f02d"; } +.icon-bookmark:before { content: "\f02e"; } +.icon-print:before { content: "\f02f"; } + +.icon-camera:before { content: "\f030"; } +.icon-font:before { content: "\f031"; } +.icon-bold:before { content: "\f032"; } +.icon-italic:before { content: "\f033"; } +.icon-text-height:before { content: "\f034"; } +.icon-text-width:before { content: "\f035"; } +.icon-align-left:before { content: "\f036"; } +.icon-align-center:before { content: "\f037"; } +.icon-align-right:before { content: "\f038"; } +.icon-align-justify:before { content: "\f039"; } +.icon-list:before { content: "\f03a"; } +.icon-indent-left:before { content: "\f03b"; } +.icon-indent-right:before { content: "\f03c"; } +.icon-facetime-video:before { content: "\f03d"; } +.icon-picture:before { content: "\f03e"; } + +.icon-pencil:before { content: "\f040"; } +.icon-map-marker:before { content: "\f041"; } +.icon-adjust:before { content: "\f042"; } +.icon-tint:before { content: "\f043"; } +.icon-edit:before { content: "\f044"; } +.icon-share:before { content: "\f045"; } +.icon-check:before { content: "\f046"; } +.icon-move:before { content: "\f047"; } +.icon-step-backward:before { content: "\f048"; } +.icon-fast-backward:before { content: "\f049"; } +.icon-backward:before { content: "\f04a"; } +.icon-play:before { content: "\f04b"; } +.icon-pause:before { content: "\f04c"; } +.icon-stop:before { content: "\f04d"; } +.icon-forward:before { content: "\f04e"; } + +.icon-fast-forward:before { content: "\f050"; } +.icon-step-forward:before { content: "\f051"; } +.icon-eject:before { content: "\f052"; } +.icon-chevron-left:before { content: "\f053"; } +.icon-chevron-right:before { content: "\f054"; } +.icon-plus-sign:before { content: "\f055"; } +.icon-minus-sign:before { content: "\f056"; } +.icon-remove-sign:before { content: "\f057"; } +.icon-ok-sign:before { content: "\f058"; } +.icon-question-sign:before { content: "\f059"; } +.icon-info-sign:before { content: "\f05a"; } +.icon-screenshot:before { content: "\f05b"; } +.icon-remove-circle:before { content: "\f05c"; } +.icon-ok-circle:before { content: "\f05d"; } +.icon-ban-circle:before { content: "\f05e"; } + +.icon-arrow-left:before { content: "\f060"; } +.icon-arrow-right:before { content: "\f061"; } +.icon-arrow-up:before { content: "\f062"; } +.icon-arrow-down:before { content: "\f063"; } +.icon-share-alt:before { content: "\f064"; } +.icon-resize-full:before { content: "\f065"; } +.icon-resize-small:before { content: "\f066"; } +.icon-plus:before { content: "\f067"; } +.icon-minus:before { content: "\f068"; } +.icon-asterisk:before { content: "\f069"; } +.icon-exclamation-sign:before { content: "\f06a"; } +.icon-gift:before { content: "\f06b"; } +.icon-leaf:before { content: "\f06c"; } +.icon-fire:before { content: "\f06d"; } +.icon-eye-open:before { content: "\f06e"; } + +.icon-eye-close:before { content: "\f070"; } +.icon-warning-sign:before { content: "\f071"; } +.icon-plane:before { content: "\f072"; } +.icon-calendar:before { content: "\f073"; } +.icon-random:before { content: "\f074"; } +.icon-comment:before { content: "\f075"; } +.icon-magnet:before { content: "\f076"; } +.icon-chevron-up:before { content: "\f077"; } +.icon-chevron-down:before { content: "\f078"; } +.icon-retweet:before { content: "\f079"; } +.icon-shopping-cart:before { content: "\f07a"; } +.icon-folder-close:before { content: "\f07b"; } +.icon-folder-open:before { content: "\f07c"; } +.icon-resize-vertical:before { content: "\f07d"; } +.icon-resize-horizontal:before { content: "\f07e"; } + +.icon-bar-chart:before { content: "\f080"; } +.icon-twitter-sign:before { content: "\f081"; } +.icon-facebook-sign:before { content: "\f082"; } +.icon-camera-retro:before { content: "\f083"; } +.icon-key:before { content: "\f084"; } +.icon-cogs:before { content: "\f085"; } +.icon-comments:before { content: "\f086"; } +.icon-thumbs-up:before { content: "\f087"; } +.icon-thumbs-down:before { content: "\f088"; } +.icon-star-half:before { content: "\f089"; } +.icon-heart-empty:before { content: "\f08a"; } +.icon-signout:before { content: "\f08b"; } +.icon-linkedin-sign:before { content: "\f08c"; } +.icon-pushpin:before { content: "\f08d"; } +.icon-external-link:before { content: "\f08e"; } + +.icon-signin:before { content: "\f090"; } +.icon-trophy:before { content: "\f091"; } +.icon-github-sign:before { content: "\f092"; } +.icon-upload-alt:before { content: "\f093"; } +.icon-lemon:before { content: "\f094"; } +.icon-phone:before { content: "\f095"; } +.icon-check-empty:before { content: "\f096"; } +.icon-bookmark-empty:before { content: "\f097"; } +.icon-phone-sign:before { content: "\f098"; } +.icon-twitter:before { content: "\f099"; } +.icon-facebook:before { content: "\f09a"; } +.icon-github:before { content: "\f09b"; } +.icon-unlock:before { content: "\f09c"; } +.icon-credit-card:before { content: "\f09d"; } +.icon-rss:before { content: "\f09e"; } + +.icon-hdd:before { content: "\f0a0"; } +.icon-bullhorn:before { content: "\f0a1"; } +.icon-bell:before { content: "\f0a2"; } +.icon-certificate:before { content: "\f0a3"; } +.icon-hand-right:before { content: "\f0a4"; } +.icon-hand-left:before { content: "\f0a5"; } +.icon-hand-up:before { content: "\f0a6"; } +.icon-hand-down:before { content: "\f0a7"; } +.icon-circle-arrow-left:before { content: "\f0a8"; } +.icon-circle-arrow-right:before { content: "\f0a9"; } +.icon-circle-arrow-up:before { content: "\f0aa"; } +.icon-circle-arrow-down:before { content: "\f0ab"; } +.icon-globe:before { content: "\f0ac"; } +.icon-wrench:before { content: "\f0ad"; } +.icon-tasks:before { content: "\f0ae"; } + +.icon-filter:before { content: "\f0b0"; } +.icon-briefcase:before { content: "\f0b1"; } +.icon-fullscreen:before { content: "\f0b2"; } + +.icon-group:before { content: "\f0c0"; } +.icon-link:before { content: "\f0c1"; } +.icon-cloud:before { content: "\f0c2"; } +.icon-beaker:before { content: "\f0c3"; } +.icon-cut:before { content: "\f0c4"; } +.icon-copy:before { content: "\f0c5"; } +.icon-paper-clip:before { content: "\f0c6"; } +.icon-save:before { content: "\f0c7"; } +.icon-sign-blank:before { content: "\f0c8"; } +.icon-reorder:before { content: "\f0c9"; } +.icon-list-ul:before { content: "\f0ca"; } +.icon-list-ol:before { content: "\f0cb"; } +.icon-strikethrough:before { content: "\f0cc"; } +.icon-underline:before { content: "\f0cd"; } +.icon-table:before { content: "\f0ce"; } + +.icon-magic:before { content: "\f0d0"; } +.icon-truck:before { content: "\f0d1"; } +.icon-pinterest:before { content: "\f0d2"; } +.icon-pinterest-sign:before { content: "\f0d3"; } +.icon-google-plus-sign:before { content: "\f0d4"; } +.icon-google-plus:before { content: "\f0d5"; } +.icon-money:before { content: "\f0d6"; } +.icon-caret-down:before { content: "\f0d7"; } +.icon-caret-up:before { content: "\f0d8"; } +.icon-caret-left:before { content: "\f0d9"; } +.icon-caret-right:before { content: "\f0da"; } +.icon-columns:before { content: "\f0db"; } +.icon-sort:before { content: "\f0dc"; } +.icon-sort-down:before { content: "\f0dd"; } +.icon-sort-up:before { content: "\f0de"; } + +.icon-envelope-alt:before { content: "\f0e0"; } +.icon-linkedin:before { content: "\f0e1"; } +.icon-undo:before { content: "\f0e2"; } +.icon-legal:before { content: "\f0e3"; } +.icon-dashboard:before { content: "\f0e4"; } +.icon-comment-alt:before { content: "\f0e5"; } +.icon-comments-alt:before { content: "\f0e6"; } +.icon-bolt:before { content: "\f0e7"; } +.icon-sitemap:before { content: "\f0e8"; } +.icon-umbrella:before { content: "\f0e9"; } +.icon-paste:before { content: "\f0ea"; } + +.icon-user-md:before { content: "\f200"; } diff --git a/templates/project/assets/stylesheets/jquery.gridster.css b/templates/project/assets/stylesheets/jquery.gridster.css new file mode 100755 index 0000000..d512484 --- /dev/null +++ b/templates/project/assets/stylesheets/jquery.gridster.css @@ -0,0 +1,57 @@ +/*! gridster.js - v0.1.0 - 2012-08-14 +* http://gridster.net/ +* Copyright (c) 2012 ducksboard; Licensed MIT */ + +.gridster { + position:relative; +} + +.gridster > * { + margin: 0 auto; + -webkit-transition: height .4s; + -moz-transition: height .4s; + -o-transition: height .4s; + -ms-transition: height .4s; + transition: height .4s; +} + +.gridster .gs_w{ + z-index: 2; + position: absolute; +} + +.ready .gs_w:not(.preview-holder) { + -webkit-transition: opacity .3s, left .3s, top .3s; + -moz-transition: opacity .3s, left .3s, top .3s; + -o-transition: opacity .3s, left .3s, top .3s; + transition: opacity .3s, left .3s, top .3s; +} + +.gridster .preview-holder { + z-index: 1; + position: absolute; + background-color: #fff; + border-color: #fff; + opacity: 0.3; +} + +.gridster .player-revert { + z-index: 10!important; + -webkit-transition: left .3s, top .3s!important; + -moz-transition: left .3s, top .3s!important; + -o-transition: left .3s, top .3s!important; + transition: left .3s, top .3s!important; +} + +.gridster .dragging { + z-index: 10!important; + -webkit-transition: all 0s !important; + -moz-transition: all 0s !important; + -o-transition: all 0s !important; + transition: all 0s !important; +} + +/* Uncomment this if you set helper : "clone" in draggable options */ +/*.gridster .player { + opacity:0; +}*/ \ No newline at end of file diff --git a/templates/project/config.ru b/templates/project/config.ru index a3a74de..6e1076a 100644 --- a/templates/project/config.ru +++ b/templates/project/config.ru @@ -2,6 +2,17 @@ require 'dashing' configure do set :auth_token, 'YOUR_AUTH_TOKEN' + + helpers do + def protected! + # Put any authentication code you want in here. + # This method is run before accessing any resource. + end + end +end + +map Sinatra::Application.assets_prefix do + run Sinatra::Application.sprockets end run Sinatra::Application \ No newline at end of file diff --git a/templates/project/dashboards/layout.erb b/templates/project/dashboards/layout.erb index 97cb96d..23d3c9a 100644 --- a/templates/project/dashboards/layout.erb +++ b/templates/project/dashboards/layout.erb @@ -8,34 +8,25 @@ <%= yield_content(:title) %> - - - + + + - - - + - - - -
    - <%= yield %> -
    - - + +
    + <%= yield %> +
    + + <% if development? %> +
    +

    Paste the following at the top of <%= params[:dashboard] %>.erb

    + +
    + Save this layout + <% end %> + \ No newline at end of file diff --git a/templates/project/public/.empty_directory b/templates/project/public/.empty_directory new file mode 100644 index 0000000..3da7f49 --- /dev/null +++ b/templates/project/public/.empty_directory @@ -0,0 +1 @@ +.empty_directory \ No newline at end of file diff --git a/templates/project/public/fonts/fontawesome-webfont.eot b/templates/project/public/fonts/fontawesome-webfont.eot deleted file mode 100755 index 89070c1..0000000 Binary files a/templates/project/public/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/templates/project/public/fonts/fontawesome-webfont.svg b/templates/project/public/fonts/fontawesome-webfont.svg deleted file mode 100755 index 1245f92..0000000 --- a/templates/project/public/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/templates/project/public/fonts/fontawesome-webfont.ttf b/templates/project/public/fonts/fontawesome-webfont.ttf deleted file mode 100755 index c17e9f8..0000000 Binary files a/templates/project/public/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/templates/project/public/fonts/fontawesome-webfont.woff b/templates/project/public/fonts/fontawesome-webfont.woff deleted file mode 100755 index 09f2469..0000000 Binary files a/templates/project/public/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/templates/project/public/images/.empty_directory b/templates/project/public/images/.empty_directory deleted file mode 100644 index 3da7f49..0000000 --- a/templates/project/public/images/.empty_directory +++ /dev/null @@ -1 +0,0 @@ -.empty_directory \ No newline at end of file diff --git a/templates/project/public/images/favicon.ico b/templates/project/public/images/favicon.ico deleted file mode 100644 index 29a408f..0000000 Binary files a/templates/project/public/images/favicon.ico and /dev/null differ diff --git a/templates/project/public/javascripts/.empty_directory b/templates/project/public/javascripts/.empty_directory deleted file mode 100644 index 3da7f49..0000000 --- a/templates/project/public/javascripts/.empty_directory +++ /dev/null @@ -1 +0,0 @@ -.empty_directory \ No newline at end of file diff --git a/templates/project/public/javascripts/jquery.knob.js b/templates/project/public/javascripts/jquery.knob.js deleted file mode 100644 index 0c5b8f1..0000000 --- a/templates/project/public/javascripts/jquery.knob.js +++ /dev/null @@ -1,28 +0,0 @@ -/*!jQuery Knob*/ -/** - * Downward compatible, touchable dial - * - * Version: 1.2.0 (15/07/2012) - * Requires: jQuery v1.7+ - * - * Copyright (c) 2012 Anthony Terrien - * Under MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - * Thanks to vor, eskimoblood, spiffistan, FabrizioC - */ -$(function(){"use strict";var k={},max=Math.max,min=Math.min;k.c={};k.c.d=$(document);k.c.t=function(e){return e.originalEvent.touches.length-1;};k.o=function(){var s=this;this.o=null;this.$=null;this.i=null;this.g=null;this.v=null;this.cv=null;this.x=0;this.y=0;this.$c=null;this.c=null;this.t=0;this.isInit=false;this.fgColor=null;this.pColor=null;this.dH=null;this.cH=null;this.eH=null;this.rH=null;this.run=function(){var cf=function(e,conf){var k;for(k in conf){s.o[k]=conf[k];} -s.init();s._configure()._draw();};if(this.$.data('kontroled'))return;this.$.data('kontroled',true);this.extend();this.o=$.extend({min:this.$.data('min')||0,max:this.$.data('max')||100,stopper:true,readOnly:this.$.data('readonly'),cursor:(this.$.data('cursor')===true&&30)||this.$.data('cursor')||0,thickness:this.$.data('thickness')||0.35,width:this.$.data('width')||200,height:this.$.data('height')||200,displayInput:this.$.data('displayinput')==null||this.$.data('displayinput'),displayPrevious:this.$.data('displayprevious'),fgColor:this.$.data('fgcolor')||'#87CEEB',inline:false,draw:null,change:null,cancel:null,release:null},this.o);if(this.$.is('fieldset')){this.v={};this.i=this.$.find('input') -this.i.each(function(k){var $this=$(this);s.i[k]=$this;s.v[k]=$this.val();$this.bind('change',function(){var val={};val[k]=$this.val();s.val(val);});});this.$.find('legend').remove();}else{this.i=this.$;this.v=this.$.val();(this.v=='')&&(this.v=this.o.min);this.$.bind('change',function(){s.val(s.$.val());});} -(!this.o.displayInput)&&this.$.hide();this.$c=$('');this.c=this.$c[0].getContext("2d");this.$.wrap($('
    ')).before(this.$c);if(this.v instanceof Object){this.cv={};this.copy(this.v,this.cv);}else{this.cv=this.v;} -this.$.bind("configure",cf).parent().bind("configure",cf);this._listen()._configure()._xy().init();this.isInit=true;this._draw();return this;};this._draw=function(){var d=true,c=document.createElement('canvas');c.width=s.o.width;c.height=s.o.height;s.g=c.getContext('2d');s.clear();s.dH&&(d=s.dH());(d!==false)&&s.draw();s.c.drawImage(c,0,0);c=null;};this._touch=function(e){var touchMove=function(e){var v=s.xy2val(e.originalEvent.touches[s.t].pageX,e.originalEvent.touches[s.t].pageY);if(v==s.cv)return;if(s.cH&&(s.cH(v)===false))return;s.change(v);s._draw();};this.t=k.c.t(e);touchMove(e);k.c.d.bind("touchmove.k",touchMove).bind("touchend.k",function(){k.c.d.unbind('touchmove.k touchend.k');if(s.rH&&(s.rH(s.cv)===false))return;s.val(s.cv);});return this;};this._mouse=function(e){var mouseMove=function(e){var v=s.xy2val(e.pageX,e.pageY);if(v==s.cv)return;if(s.cH&&(s.cH(v)===false))return;s.change(v);s._draw();};mouseMove(e);k.c.d.bind("mousemove.k",mouseMove).bind("keyup.k",function(e){if(e.keyCode===27){k.c.d.unbind("mouseup.k mousemove.k keyup.k");if(s.eH&&(s.eH()===false))return;s.cancel();}}).bind("mouseup.k",function(e){k.c.d.unbind('mousemove.k mouseup.k keyup.k');if(s.rH&&(s.rH(s.cv)===false))return;s.val(s.cv);});return this;};this._xy=function(){var o=this.$c.offset();this.x=o.left;this.y=o.top;return this;};this._listen=function(){if(!this.o.readOnly){this.$c.bind("mousedown",function(e){e.preventDefault();s._xy()._mouse(e);}).bind("touchstart",function(e){e.preventDefault();s._xy()._touch(e);});this.listen();}else{this.$.attr('readonly','readonly');} -return this;};this._configure=function(){if(this.o.draw)this.dH=this.o.draw;if(this.o.change)this.cH=this.o.change;if(this.o.cancel)this.eH=this.o.cancel;if(this.o.release)this.rH=this.o.release;if(this.o.displayPrevious){this.pColor=this.h2rgba(this.o.fgColor,"0.4");this.fgColor=this.h2rgba(this.o.fgColor,"0.6");}else{this.fgColor=this.o.fgColor;} -return this;};this._clear=function(){this.$c[0].width=this.$c[0].width;};this.listen=function(){};this.extend=function(){};this.init=function(){};this.change=function(v){};this.val=function(v){};this.xy2val=function(x,y){};this.draw=function(){};this.clear=function(){this._clear();};this.h2rgba=function(h,a){var rgb;h=h.substring(1,7) -rgb=[parseInt(h.substring(0,2),16),parseInt(h.substring(2,4),16),parseInt(h.substring(4,6),16)];return"rgba("+rgb[0]+","+rgb[1]+","+rgb[2]+","+a+")";};this.copy=function(f,t){for(var i in f){t[i]=f[i];}};};k.Dial=function(){k.o.call(this);this.startAngle=null;this.xy=null;this.radius=null;this.lineWidth=null;this.cursorExt=null;this.w2=null;this.PI2=2*Math.PI;this.extend=function(){this.o=$.extend({bgColor:this.$.data('bgcolor')||'#EEEEEE',angleOffset:this.$.data('angleoffset')||0,angleArc:this.$.data('anglearc')||360,inline:true},this.o);};this.val=function(v){if(null!=v){this.cv=this.o.stopper?max(min(v,this.o.max),this.o.min):v;this.v=this.cv;this.$.val(this.v);this._draw();}else{return this.v;}};this.xy2val=function(x,y){var a,ret;a=Math.atan2(x-(this.x+this.w2),-(y-this.y-this.w2))-this.angleOffset;if(this.angleArc!=this.PI2&&(a<0)&&(a>-0.5)){a=0;}else if(a<0){a+=this.PI2;} -ret=~~(0.5+(a*(this.o.max-this.o.min)/this.angleArc)) -+this.o.min;this.o.stopper&&(ret=max(min(ret,this.o.max),this.o.min));return ret;};this.listen=function(){var s=this,mw=function(e){e.preventDefault();var ori=e.originalEvent,deltaX=ori.detail||ori.wheelDeltaX,deltaY=ori.detail||ori.wheelDeltaY,v=parseInt(s.$.val())+(deltaX>0||deltaY>0?1:deltaX<0||deltaY<0?-1:0);if(s.cH&&(s.cH(v)===false))return;s.val(v);},kval,to,m=1,kv={37:-1,38:1,39:1,40:-1};this.$.bind("keydown",function(e){var kc=e.keyCode;kval=parseInt(String.fromCharCode(kc));if(isNaN(kval)){(kc!==13)&&(kc!==8)&&(kc!==9)&&(kc!==189)&&e.preventDefault();if($.inArray(kc,[37,38,39,40])>-1){e.preventDefault();var v=parseInt(s.$.val())+kv[kc]*m;s.o.stopper&&(v=max(min(v,s.o.max),s.o.min));s.change(v);s._draw();to=window.setTimeout(function(){m*=2;},30);}}}).bind("keyup",function(e){if(isNaN(kval)){if(to){window.clearTimeout(to);to=null;m=1;s.val(s.$.val());}}else{(s.$.val()>s.o.max&&s.$.val(s.o.max))||(s.$.val()this.o.max)this.v=this.o.min;this.$.val(this.v);this.w2=this.o.width/2;this.cursorExt=this.o.cursor/100;this.xy=this.w2;this.lineWidth=this.xy*this.o.thickness;this.radius=this.xy-this.lineWidth/2;this.o.angleOffset&&(this.o.angleOffset=isNaN(this.o.angleOffset)?0:this.o.angleOffset);this.o.angleArc&&(this.o.angleArc=isNaN(this.o.angleArc)?this.PI2:this.o.angleArc);this.angleOffset=this.o.angleOffset*Math.PI/180;this.angleArc=this.o.angleArc*Math.PI/180;this.startAngle=1.5*Math.PI+this.angleOffset;this.endAngle=1.5*Math.PI+this.angleOffset+this.angleArc;var s=max(String(Math.abs(this.o.max)).length,String(Math.abs(this.o.min)).length,2)+2;this.o.displayInput&&this.i.css({'width':((this.o.width/2+4)>>0)+'px','height':((this.o.width/3)>>0)+'px','position':'absolute','vertical-align':'middle','margin-top':((this.o.width/3)>>0)+'px','margin-left':'-'+((this.o.width*3/4+2)>>0)+'px','border':0,'background':'none','font':'bold '+((this.o.width/s)>>0)+'px Arial','text-align':'center','color':this.o.fgColor,'padding':'0px','-webkit-appearance':'none'})||this.i.css({'width':'0px','visibility':'hidden'});};this.change=function(v){this.cv=v;this.$.val(v);};this.angle=function(v){return(v-this.o.min)*this.angleArc/(this.o.max-this.o.min);};this.draw=function(){var c=this.g,a=this.angle(this.cv),sat=this.startAngle,eat=sat+a,sa,ea,r=1;c.lineWidth=this.lineWidth;this.o.cursor&&(sat=eat-this.cursorExt)&&(eat=eat+this.cursorExt);c.beginPath();c.strokeStyle=this.o.bgColor;c.arc(this.xy,this.xy,this.radius,this.endAngle,this.startAngle,true);c.stroke();if(this.o.displayPrevious){ea=this.startAngle+this.angle(this.v);sa=this.startAngle;this.o.cursor&&(sa=ea-this.cursorExt)&&(ea=ea+this.cursorExt);c.beginPath();c.strokeStyle=this.pColor;c.arc(this.xy,this.xy,this.radius,sa,ea,false);c.stroke();r=(this.cv==this.v);} -c.beginPath();c.strokeStyle=r?this.o.fgColor:this.fgColor;c.arc(this.xy,this.xy,this.radius,sat,eat,false);c.stroke();};this.cancel=function(){this.val(this.v);};};$.fn.dial=$.fn.knob=function(o){return this.each(function(){var d=new k.Dial();d.o=o;d.$=$(this);d.run();}).parent();};}); \ No newline at end of file diff --git a/templates/project/public/javascripts/jquery.masonry.min.js b/templates/project/public/javascripts/jquery.masonry.min.js deleted file mode 100644 index 67be988..0000000 --- a/templates/project/public/javascripts/jquery.masonry.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * jQuery Masonry v2.1.05 - * A dynamic layout plugin for jQuery - * The flip-side of CSS Floats - * http://masonry.desandro.com - * - * Licensed under the MIT license. - * Copyright 2012 David DeSandro - */ -(function(a,b,c){"use strict";var d=b.event,e;d.special.smartresize={setup:function(){b(this).bind("resize",d.special.smartresize.handler)},teardown:function(){b(this).unbind("resize",d.special.smartresize.handler)},handler:function(a,c){var d=this,f=arguments;a.type="smartresize",e&&clearTimeout(e),e=setTimeout(function(){b.event.handle.apply(d,f)},c==="execAsap"?0:100)}},b.fn.smartresize=function(a){return a?this.bind("smartresize",a):this.trigger("smartresize",["execAsap"])},b.Mason=function(a,c){this.element=b(c),this._create(a),this._init()},b.Mason.settings={isResizable:!0,isAnimated:!1,animationOptions:{queue:!1,duration:500},gutterWidth:0,isRTL:!1,isFitWidth:!1,containerStyle:{position:"relative"}},b.Mason.prototype={_filterFindBricks:function(a){var b=this.options.itemSelector;return b?a.filter(b).add(a.find(b)):a},_getBricks:function(a){var b=this._filterFindBricks(a).css({position:"absolute"}).addClass("masonry-brick");return b},_create:function(c){this.options=b.extend(!0,{},b.Mason.settings,c),this.styleQueue=[];var d=this.element[0].style;this.originalStyle={height:d.height||""};var e=this.options.containerStyle;for(var f in e)this.originalStyle[f]=d[f]||"";this.element.css(e),this.horizontalDirection=this.options.isRTL?"right":"left",this.offset={x:parseInt(this.element.css("padding-"+this.horizontalDirection),10),y:parseInt(this.element.css("padding-top"),10)},this.isFluid=this.options.columnWidth&&typeof this.options.columnWidth=="function";var g=this;setTimeout(function(){g.element.addClass("masonry")},0),this.options.isResizable&&b(a).bind("smartresize.masonry",function(){g.resize()}),this.reloadItems()},_init:function(a){this._getColumns(),this._reLayout(a)},option:function(a,c){b.isPlainObject(a)&&(this.options=b.extend(!0,this.options,a))},layout:function(a,b){for(var c=0,d=a.length;c - num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") unless isNaN(num) - -Batman.Filters.dashize = (str) -> - dashes_rx1 = /([A-Z]+)([A-Z][a-z])/g; - dashes_rx2 = /([a-z\d])([A-Z])/g; - - return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace('_', '-').toLowerCase() - -Batman.Filters.shortenedNumber = (num) -> - return if isNaN(num) - if num >= 1000000000 - (num / 1000000000).toFixed(1) + 'B' - else if num >= 1000000 - (num / 1000000).toFixed(1) + 'M' - else if num >= 1000 - (num / 1000).toFixed(1) + 'K' - else - num - -class window.Dashing extends Batman.App - @root -> - -Dashing.AnimatedValue = - get: Batman.Property.defaultAccessor.get - set: (k, to) -> - if isNaN(to) - @[k] = to - else - timer = "interval_#{k}" - num = if !isNaN(@[k]) then @[k] else 0 - unless @[timer] || num == to - up = to > num - num_interval = Math.abs(num - to) / 90 - @[timer] = - setInterval => - num = if up then Math.ceil(num+num_interval) else Math.floor(num-num_interval) - if (up && num > to) || (!up && num < to) - num = to - clearInterval(@[timer]) - @[timer] = null - delete @[timer] - @[k] = num - @set k, to - @[k] = num - -Dashing.widgets = widgets = {} -Dashing.lastEvents = lastEvents = {} - -source = new EventSource('/events') -source.addEventListener 'open', (e) -> - console.log("Connection opened") - -source.addEventListener 'error', (e)-> - console.log("Connection error") - if (e.readyState == EventSource.CLOSED) - console.log("Connection closed") - -source.addEventListener 'message', (e) => - data = JSON.parse(e.data) - lastEvents[data.id] = data - if widgets[data.id]?.length > 0 - for widget in widgets[data.id] - widget.onData(data) - - -$(document).ready -> - Dashing.run() \ No newline at end of file diff --git a/vendor/javascripts/batman.jquery.js b/vendor/javascripts/batman.jquery.js deleted file mode 100644 index 6407098..0000000 --- a/vendor/javascripts/batman.jquery.js +++ /dev/null @@ -1,109 +0,0 @@ -(function() { - - Batman.Request.prototype._parseResponseHeaders = function(xhr) { - var headers; - return headers = xhr.getAllResponseHeaders().split('\n').reduce(function(acc, header) { - var key, matches, value; - if (matches = header.match(/([^:]*):\s*(.*)/)) { - key = matches[1]; - value = matches[2]; - acc[key] = value; - } - return acc; - }, {}); - }; - - Batman.Request.prototype._prepareOptions = function(data) { - var options, _ref, - _this = this; - options = { - url: this.get('url'), - type: this.get('method'), - dataType: this.get('type'), - data: data || this.get('data'), - username: this.get('username'), - password: this.get('password'), - headers: this.get('headers'), - beforeSend: function() { - return _this.fire('loading'); - }, - success: function(response, textStatus, xhr) { - _this.mixin({ - xhr: xhr, - status: xhr.status, - response: response, - responseHeaders: _this._parseResponseHeaders(xhr) - }); - return _this.fire('success', response); - }, - error: function(xhr, status, error) { - _this.mixin({ - xhr: xhr, - status: xhr.status, - response: xhr.responseText, - responseHeaders: _this._parseResponseHeaders(xhr) - }); - xhr.request = _this; - return _this.fire('error', xhr); - }, - complete: function() { - return _this.fire('loaded'); - } - }; - if ((_ref = this.get('method')) === 'PUT' || _ref === 'POST') { - if (!this.hasFileUploads()) { - options.contentType = this.get('contentType'); - if (typeof options.data === 'object') { - options.processData = false; - options.data = Batman.URI.queryFromParams(options.data); - } - } else { - options.contentType = false; - options.processData = false; - options.data = this.constructor.objectToFormData(options.data); - } - } - return options; - }; - - Batman.Request.prototype.send = function(data) { - return jQuery.ajax(this._prepareOptions(data)); - }; - - Batman.mixins.animation = { - show: function(addToParent) { - var jq, show, _ref, _ref1; - jq = $(this); - show = function() { - return jq.show(600); - }; - if (addToParent) { - if ((_ref = addToParent.append) != null) { - _ref.appendChild(this); - } - if ((_ref1 = addToParent.before) != null) { - _ref1.parentNode.insertBefore(this, addToParent.before); - } - jq.hide(); - setTimeout(show, 0); - } else { - show(); - } - return this; - }, - hide: function(removeFromParent) { - var _this = this; - $(this).hide(600, function() { - var _ref; - if (removeFromParent) { - if ((_ref = _this.parentNode) != null) { - _ref.removeChild(_this); - } - } - return Batman.DOM.didRemoveNode(_this); - }); - return this; - } - }; - -}).call(this); \ No newline at end of file diff --git a/vendor/javascripts/batman.js b/vendor/javascripts/batman.js deleted file mode 100644 index 22c7b3a..0000000 --- a/vendor/javascripts/batman.js +++ /dev/null @@ -1,11811 +0,0 @@ -(function() { - var Batman, - __slice = [].slice; - - Batman = function() { - var mixins; - mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.Object, mixins, function(){}); - }; - - Batman.version = '0.10.0'; - - Batman.config = { - pathPrefix: '/', - usePushState: false, - minificationErrors: true - }; - - (Batman.container = (function() { - return this; - })()).Batman = Batman; - - if (typeof define === 'function') { - define('batman', [], function() { - return Batman; - }); - } - - Batman.exportHelpers = function(onto) { - var k, _i, _len, _ref; - _ref = ['mixin', 'extend', 'unmixin', 'redirect', 'typeOf', 'redirect', 'setImmediate', 'clearImmediate']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - onto["$" + k] = Batman[k]; - } - return onto; - }; - - Batman.exportGlobals = function() { - return Batman.exportHelpers(Batman.container); - }; - -}).call(this); - -(function() { - var __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - Batman.Inflector = (function() { - - Inflector.prototype.plural = function(regex, replacement) { - return this._plural.unshift([regex, replacement]); - }; - - Inflector.prototype.singular = function(regex, replacement) { - return this._singular.unshift([regex, replacement]); - }; - - Inflector.prototype.human = function(regex, replacement) { - return this._human.unshift([regex, replacement]); - }; - - Inflector.prototype.uncountable = function() { - var strings; - strings = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return this._uncountable = this._uncountable.concat(strings.map(function(x) { - return new RegExp("" + x + "$", 'i'); - })); - }; - - Inflector.prototype.irregular = function(singular, plural) { - if (singular.charAt(0) === plural.charAt(0)) { - this.plural(new RegExp("(" + (singular.charAt(0)) + ")" + (singular.slice(1)) + "$", "i"), "$1" + plural.slice(1)); - this.plural(new RegExp("(" + (singular.charAt(0)) + ")" + (plural.slice(1)) + "$", "i"), "$1" + plural.slice(1)); - return this.singular(new RegExp("(" + (plural.charAt(0)) + ")" + (plural.slice(1)) + "$", "i"), "$1" + singular.slice(1)); - } else { - this.plural(new RegExp("" + singular + "$", 'i'), plural); - this.plural(new RegExp("" + plural + "$", 'i'), plural); - return this.singular(new RegExp("" + plural + "$", 'i'), singular); - } - }; - - function Inflector() { - this._plural = []; - this._singular = []; - this._uncountable = []; - this._human = []; - } - - Inflector.prototype.ordinalize = function(number) { - var absNumber, _ref; - absNumber = Math.abs(parseInt(number)); - if (_ref = absNumber % 100, __indexOf.call([11, 12, 13], _ref) >= 0) { - return number + "th"; - } else { - switch (absNumber % 10) { - case 1: - return number + "st"; - case 2: - return number + "nd"; - case 3: - return number + "rd"; - default: - return number + "th"; - } - } - }; - - Inflector.prototype.pluralize = function(word) { - var regex, replace_string, uncountableRegex, _i, _j, _len, _len1, _ref, _ref1, _ref2; - _ref = this._uncountable; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - uncountableRegex = _ref[_i]; - if (uncountableRegex.test(word)) { - return word; - } - } - _ref1 = this._plural; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - _ref2 = _ref1[_j], regex = _ref2[0], replace_string = _ref2[1]; - if (regex.test(word)) { - return word.replace(regex, replace_string); - } - } - return word; - }; - - Inflector.prototype.singularize = function(word) { - var regex, replace_string, uncountableRegex, _i, _j, _len, _len1, _ref, _ref1, _ref2; - _ref = this._uncountable; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - uncountableRegex = _ref[_i]; - if (uncountableRegex.test(word)) { - return word; - } - } - _ref1 = this._singular; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - _ref2 = _ref1[_j], regex = _ref2[0], replace_string = _ref2[1]; - if (regex.test(word)) { - return word.replace(regex, replace_string); - } - } - return word; - }; - - Inflector.prototype.humanize = function(word) { - var regex, replace_string, _i, _len, _ref, _ref1; - _ref = this._human; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - _ref1 = _ref[_i], regex = _ref1[0], replace_string = _ref1[1]; - if (regex.test(word)) { - return word.replace(regex, replace_string); - } - } - return word; - }; - - return Inflector; - - })(); - -}).call(this); - -(function() { - var Inflector, camelize_rx, capitalize_rx, humanize_rx1, humanize_rx2, humanize_rx3, underscore_rx1, underscore_rx2; - - camelize_rx = /(?:^|_|\-)(.)/g; - - capitalize_rx = /(^|\s)([a-z])/g; - - underscore_rx1 = /([A-Z]+)([A-Z][a-z])/g; - - underscore_rx2 = /([a-z\d])([A-Z])/g; - - humanize_rx1 = /_id$/; - - humanize_rx2 = /_|-/g; - - humanize_rx3 = /^\w/g; - - Batman.helpers = { - ordinalize: function() { - return Batman.helpers.inflector.ordinalize.apply(Batman.helpers.inflector, arguments); - }, - singularize: function() { - return Batman.helpers.inflector.singularize.apply(Batman.helpers.inflector, arguments); - }, - pluralize: function(count, singular, plural, includeCount) { - var result; - if (includeCount == null) { - includeCount = true; - } - if (arguments.length < 2) { - return Batman.helpers.inflector.pluralize(count); - } else { - result = +count === 1 ? singular : plural || Batman.helpers.inflector.pluralize(singular); - if (includeCount) { - result = ("" + (count || 0) + " ") + result; - } - return result; - } - }, - camelize: function(string, firstLetterLower) { - string = string.replace(camelize_rx, function(str, p1) { - return p1.toUpperCase(); - }); - if (firstLetterLower) { - return string.substr(0, 1).toLowerCase() + string.substr(1); - } else { - return string; - } - }, - underscore: function(string) { - return string.replace(underscore_rx1, '$1_$2').replace(underscore_rx2, '$1_$2').replace('-', '_').toLowerCase(); - }, - capitalize: function(string) { - return string.replace(capitalize_rx, function(m, p1, p2) { - return p1 + p2.toUpperCase(); - }); - }, - trim: function(string) { - if (string) { - return string.trim(); - } else { - return ""; - } - }, - interpolate: function(stringOrObject, keys) { - var key, string, value; - if (typeof stringOrObject === 'object') { - string = stringOrObject[keys.count]; - if (!string) { - string = stringOrObject['other']; - } - } else { - string = stringOrObject; - } - for (key in keys) { - value = keys[key]; - string = string.replace(new RegExp("%\\{" + key + "\\}", "g"), value); - } - return string; - }, - humanize: function(string) { - string = Batman.helpers.underscore(string); - string = Batman.helpers.inflector.humanize(string); - return string.replace(humanize_rx1, '').replace(humanize_rx2, ' ').replace(humanize_rx3, function(match) { - return match.toUpperCase(); - }); - } - }; - - Inflector = new Batman.Inflector; - - Batman.helpers.inflector = Inflector; - - Inflector.plural(/$/, 's'); - - Inflector.plural(/s$/i, 's'); - - Inflector.plural(/(ax|test)is$/i, '$1es'); - - Inflector.plural(/(octop|vir)us$/i, '$1i'); - - Inflector.plural(/(octop|vir)i$/i, '$1i'); - - Inflector.plural(/(alias|status)$/i, '$1es'); - - Inflector.plural(/(bu)s$/i, '$1ses'); - - Inflector.plural(/(buffal|tomat)o$/i, '$1oes'); - - Inflector.plural(/([ti])um$/i, '$1a'); - - Inflector.plural(/([ti])a$/i, '$1a'); - - Inflector.plural(/sis$/i, 'ses'); - - Inflector.plural(/(?:([^f])fe|([lr])f)$/i, '$1$2ves'); - - Inflector.plural(/(hive)$/i, '$1s'); - - Inflector.plural(/([^aeiouy]|qu)y$/i, '$1ies'); - - Inflector.plural(/(x|ch|ss|sh)$/i, '$1es'); - - Inflector.plural(/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'); - - Inflector.plural(/([m|l])ouse$/i, '$1ice'); - - Inflector.plural(/([m|l])ice$/i, '$1ice'); - - Inflector.plural(/^(ox)$/i, '$1en'); - - Inflector.plural(/^(oxen)$/i, '$1'); - - Inflector.plural(/(quiz)$/i, '$1zes'); - - Inflector.singular(/s$/i, ''); - - Inflector.singular(/(n)ews$/i, '$1ews'); - - Inflector.singular(/([ti])a$/i, '$1um'); - - Inflector.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '$1$2sis'); - - Inflector.singular(/(^analy)ses$/i, '$1sis'); - - Inflector.singular(/([^f])ves$/i, '$1fe'); - - Inflector.singular(/(hive)s$/i, '$1'); - - Inflector.singular(/(tive)s$/i, '$1'); - - Inflector.singular(/([lr])ves$/i, '$1f'); - - Inflector.singular(/([^aeiouy]|qu)ies$/i, '$1y'); - - Inflector.singular(/(s)eries$/i, '$1eries'); - - Inflector.singular(/(m)ovies$/i, '$1ovie'); - - Inflector.singular(/(x|ch|ss|sh)es$/i, '$1'); - - Inflector.singular(/([m|l])ice$/i, '$1ouse'); - - Inflector.singular(/(bus)es$/i, '$1'); - - Inflector.singular(/(o)es$/i, '$1'); - - Inflector.singular(/(shoe)s$/i, '$1'); - - Inflector.singular(/(cris|ax|test)es$/i, '$1is'); - - Inflector.singular(/(octop|vir)i$/i, '$1us'); - - Inflector.singular(/(alias|status)es$/i, '$1'); - - Inflector.singular(/^(ox)en/i, '$1'); - - Inflector.singular(/(vert|ind)ices$/i, '$1ex'); - - Inflector.singular(/(matr)ices$/i, '$1ix'); - - Inflector.singular(/(quiz)zes$/i, '$1'); - - Inflector.singular(/(database)s$/i, '$1'); - - Inflector.irregular('person', 'people'); - - Inflector.irregular('man', 'men'); - - Inflector.irregular('child', 'children'); - - Inflector.irregular('sex', 'sexes'); - - Inflector.irregular('move', 'moves'); - - Inflector.irregular('cow', 'kine'); - - Inflector.irregular('zombie', 'zombies'); - - Inflector.uncountable('equipment', 'information', 'rice', 'money', 'species', 'series', 'fish', 'sheep', 'jeans'); - -}).call(this); - -(function() { - var _implementImmediates, _objectToString, - __slice = [].slice, - __hasProp = {}.hasOwnProperty, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - Batman.typeOf = function(object) { - if (typeof object === 'undefined') { - return "Undefined"; - } - return _objectToString.call(object).slice(8, -1); - }; - - _objectToString = Object.prototype.toString; - - Batman.extend = function() { - var key, object, objects, to, value, _i, _len; - to = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - for (_i = 0, _len = objects.length; _i < _len; _i++) { - object = objects[_i]; - for (key in object) { - value = object[key]; - to[key] = value; - } - } - return to; - }; - - Batman.mixin = function() { - var hasSet, key, mixin, mixins, to, value, _i, _len; - to = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - hasSet = typeof to.set === 'function'; - for (_i = 0, _len = mixins.length; _i < _len; _i++) { - mixin = mixins[_i]; - if (Batman.typeOf(mixin) !== 'Object') { - continue; - } - for (key in mixin) { - if (!__hasProp.call(mixin, key)) continue; - value = mixin[key]; - if (key === 'initialize' || key === 'uninitialize' || key === 'prototype') { - continue; - } - if (hasSet) { - to.set(key, value); - } else if (to.nodeName != null) { - Batman.data(to, key, value); - } else { - to[key] = value; - } - } - if (typeof mixin.initialize === 'function') { - mixin.initialize.call(to); - } - } - return to; - }; - - Batman.unmixin = function() { - var from, key, mixin, mixins, _i, _len; - from = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - for (_i = 0, _len = mixins.length; _i < _len; _i++) { - mixin = mixins[_i]; - for (key in mixin) { - if (key === 'initialize' || key === 'uninitialize') { - continue; - } - delete from[key]; - } - if (typeof mixin.uninitialize === 'function') { - mixin.uninitialize.call(from); - } - } - return from; - }; - - Batman._functionName = Batman.functionName = function(f) { - var _ref; - if (f.__name__) { - return f.__name__; - } - if (f.name) { - return f.name; - } - return (_ref = f.toString().match(/\W*function\s+([\w\$]+)\(/)) != null ? _ref[1] : void 0; - }; - - Batman._isChildOf = Batman.isChildOf = function(parentNode, childNode) { - var node; - node = childNode.parentNode; - while (node) { - if (node === parentNode) { - return true; - } - node = node.parentNode; - } - return false; - }; - - Batman.setImmediate = Batman.clearImmediate = null; - - _implementImmediates = function(container) { - var canUsePostMessage, count, functions, getHandle, handler, prefix, tasks; - canUsePostMessage = function() { - var async, oldMessage; - if (!container.postMessage) { - return false; - } - async = true; - oldMessage = container.onmessage; - container.onmessage = function() { - return async = false; - }; - container.postMessage("", "*"); - container.onmessage = oldMessage; - return async; - }; - tasks = new Batman.SimpleHash; - count = 0; - getHandle = function() { - return "go" + (++count); - }; - if (container.setImmediate) { - Batman.setImmediate = container.setImmediate; - Batman.clearImmediate = container.clearImmediate; - } else if (container.msSetImmediate) { - Batman.setImmediate = msSetImmediate; - Batman.clearImmediate = msClearImmediate; - } else if (canUsePostMessage()) { - prefix = 'com.batman.'; - functions = new Batman.SimpleHash; - handler = function(e) { - var handle, _base; - if (!~e.data.search(prefix)) { - return; - } - handle = e.data.substring(prefix.length); - return typeof (_base = tasks.unset(handle)) === "function" ? _base() : void 0; - }; - if (container.addEventListener) { - container.addEventListener('message', handler, false); - } else { - container.attachEvent('onmessage', handler); - } - Batman.setImmediate = function(f) { - var handle; - tasks.set(handle = getHandle(), f); - container.postMessage(prefix + handle, "*"); - return handle; - }; - Batman.clearImmediate = function(handle) { - return tasks.unset(handle); - }; - } else if (typeof document !== 'undefined' && __indexOf.call(document.createElement("script"), "onreadystatechange") >= 0) { - Batman.setImmediate = function(f) { - var handle, script; - handle = getHandle(); - script = document.createElement("script"); - script.onreadystatechange = function() { - var _base; - if (typeof (_base = tasks.get(handle)) === "function") { - _base(); - } - script.onreadystatechange = null; - script.parentNode.removeChild(script); - return script = null; - }; - document.documentElement.appendChild(script); - return handle; - }; - Batman.clearImmediate = function(handle) { - return tasks.unset(handle); - }; - } else if (typeof process !== "undefined" && process !== null ? process.nextTick : void 0) { - functions = {}; - Batman.setImmediate = function(f) { - var handle; - handle = getHandle(); - functions[handle] = f; - process.nextTick(function() { - if (typeof functions[handle] === "function") { - functions[handle](); - } - return delete functions[handle]; - }); - return handle; - }; - Batman.clearImmediate = function(handle) { - return delete functions[handle]; - }; - } else { - Batman.setImmediate = function(f) { - return setTimeout(f, 0); - }; - Batman.clearImmediate = function(handle) { - return clearTimeout(handle); - }; - } - Batman.setImmediate = Batman.setImmediate; - return Batman.clearImmediate = Batman.clearImmediate; - }; - - Batman.setImmediate = function() { - _implementImmediates(Batman.container); - return Batman.setImmediate.apply(this, arguments); - }; - - Batman.clearImmediate = function() { - _implementImmediates(Batman.container); - return Batman.clearImmediate.apply(this, arguments); - }; - - Batman.forEach = function(container, iterator, ctx) { - var e, i, k, v, _i, _len, _results, _results1; - if (container.forEach) { - return container.forEach(iterator, ctx); - } else if (container.indexOf) { - _results = []; - for (i = _i = 0, _len = container.length; _i < _len; i = ++_i) { - e = container[i]; - _results.push(iterator.call(ctx, e, i, container)); - } - return _results; - } else { - _results1 = []; - for (k in container) { - v = container[k]; - _results1.push(iterator.call(ctx, k, v, container)); - } - return _results1; - } - }; - - Batman.objectHasKey = function(object, key) { - if (typeof object.hasKey === 'function') { - return object.hasKey(key); - } else { - return key in object; - } - }; - - Batman.contains = function(container, item) { - if (container.indexOf) { - return __indexOf.call(container, item) >= 0; - } else if (typeof container.has === 'function') { - return container.has(item); - } else { - return Batman.objectHasKey(container, item); - } - }; - - Batman.get = function(base, key) { - if (typeof base.get === 'function') { - return base.get(key); - } else { - return Batman.Property.forBaseAndKey(base, key).getValue(); - } - }; - - Batman.getPath = function(base, segments) { - var segment, _i, _len; - for (_i = 0, _len = segments.length; _i < _len; _i++) { - segment = segments[_i]; - if (base != null) { - base = Batman.get(base, segment); - if (base == null) { - return base; - } - } else { - return void 0; - } - } - return base; - }; - - Batman.escapeHTML = (function() { - var replacements; - replacements = { - "&": "&", - "<": "<", - ">": ">", - "\"": """, - "'": "'" - }; - return function(s) { - return ("" + s).replace(/[&<>'"]/g, function(c) { - return replacements[c]; - }); - }; - })(); - - Batman.translate = function(x, values) { - if (values == null) { - values = {}; - } - return Batman.helpers.interpolate(Batman.get(Batman.translate.messages, x), values); - }; - - Batman.translate.messages = {}; - - Batman.t = function() { - return Batman.translate.apply(Batman, arguments); - }; - - Batman.redirect = function(url) { - var _ref; - return (_ref = Batman.navigator) != null ? _ref.redirect(url) : void 0; - }; - - Batman.initializeObject = function(object) { - if (object._batman != null) { - return object._batman.check(object); - } else { - return object._batman = new Batman._Batman(object); - } - }; - -}).call(this); - -(function() { - var developer; - - Batman.developer = { - suppressed: false, - DevelopmentError: (function() { - var DevelopmentError; - DevelopmentError = function(message) { - this.message = message; - return this.name = "DevelopmentError"; - }; - DevelopmentError.prototype = Error.prototype; - return DevelopmentError; - })(), - _ie_console: function(f, args) { - var arg, _i, _len, _results; - if (args.length !== 1) { - if (typeof console !== "undefined" && console !== null) { - console[f]("..." + f + " of " + args.length + " items..."); - } - } - _results = []; - for (_i = 0, _len = args.length; _i < _len; _i++) { - arg = args[_i]; - _results.push(typeof console !== "undefined" && console !== null ? console[f](arg) : void 0); - } - return _results; - }, - suppress: function(f) { - developer.suppressed = true; - if (f) { - f(); - return developer.suppressed = false; - } - }, - unsuppress: function() { - return developer.suppressed = false; - }, - log: function() { - if (developer.suppressed || !((typeof console !== "undefined" && console !== null ? console.log : void 0) != null)) { - return; - } - if (console.log.apply) { - return console.log.apply(console, arguments); - } else { - return developer._ie_console("log", arguments); - } - }, - warn: function() { - if (developer.suppressed || !((typeof console !== "undefined" && console !== null ? console.warn : void 0) != null)) { - return; - } - if (console.warn.apply) { - return console.warn.apply(console, arguments); - } else { - return developer._ie_console("warn", arguments); - } - }, - error: function(message) { - throw new developer.DevelopmentError(message); - }, - assert: function(result, message) { - if (!result) { - return developer.error(message); - } - }, - "do": function(f) { - if (!developer.suppressed) { - return f(); - } - }, - addFilters: function() { - return Batman.extend(Batman.Filters, { - log: function(value, key) { - if (typeof console !== "undefined" && console !== null) { - if (typeof console.log === "function") { - console.log(arguments); - } - } - return value; - }, - logStack: function(value) { - if (typeof console !== "undefined" && console !== null) { - if (typeof console.log === "function") { - console.log(developer.currentFilterStack); - } - } - return value; - } - }); - } - }; - - developer = Batman.developer; - - Batman.developer.assert((function() {}).bind, "Error! Batman needs Function.bind to work! Please shim it using something like es5-shim or augmentjs!"); - -}).call(this); - -(function() { - var _Batman; - - Batman._Batman = _Batman = (function() { - - function _Batman(object) { - this.object = object; - } - - _Batman.prototype.check = function(object) { - if (object !== this.object) { - object._batman = new Batman._Batman(object); - return false; - } - return true; - }; - - _Batman.prototype.get = function(key) { - var reduction, results; - results = this.getAll(key); - switch (results.length) { - case 0: - return void 0; - case 1: - return results[0]; - default: - reduction = results[0].concat != null ? function(a, b) { - return a.concat(b); - } : results[0].merge != null ? function(a, b) { - return a.merge(b); - } : results.every(function(x) { - return typeof x === 'object'; - }) ? (results.unshift({}), function(a, b) { - return Batman.extend(a, b); - }) : void 0; - if (reduction) { - return results.reduceRight(reduction); - } else { - return results; - } - } - }; - - _Batman.prototype.getFirst = function(key) { - var results; - results = this.getAll(key); - return results[0]; - }; - - _Batman.prototype.getAll = function(keyOrGetter) { - var getter, results, val; - if (typeof keyOrGetter === 'function') { - getter = keyOrGetter; - } else { - getter = function(ancestor) { - var _ref; - return (_ref = ancestor._batman) != null ? _ref[keyOrGetter] : void 0; - }; - } - results = this.ancestors(getter); - if (val = getter(this.object)) { - results.unshift(val); - } - return results; - }; - - _Batman.prototype.ancestors = function(getter) { - var isClass, parent, proto, results, val, _ref, _ref1; - if (getter == null) { - getter = function(x) { - return x; - }; - } - results = []; - isClass = !!this.object.prototype; - parent = isClass ? (_ref = this.object.__super__) != null ? _ref.constructor : void 0 : (proto = Object.getPrototypeOf(this.object)) === this.object ? this.object.constructor.__super__ : proto; - if (parent != null) { - if ((_ref1 = parent._batman) != null) { - _ref1.check(parent); - } - val = getter(parent); - if (val != null) { - results.push(val); - } - if (parent._batman != null) { - results = results.concat(parent._batman.ancestors(getter)); - } - } - return results; - }; - - _Batman.prototype.set = function(key, value) { - return this[key] = value; - }; - - return _Batman; - - })(); - -}).call(this); - -(function() { - - Batman.Event = (function() { - - Event.forBaseAndKey = function(base, key) { - if (base.isEventEmitter) { - return base.event(key); - } else { - return new Batman.Event(base, key); - } - }; - - function Event(base, key) { - this.base = base; - this.key = key; - this.handlers = []; - this._preventCount = 0; - } - - Event.prototype.isEvent = true; - - Event.prototype.isEqual = function(other) { - return this.constructor === other.constructor && this.base === other.base && this.key === other.key; - }; - - Event.prototype.hashKey = function() { - var key; - this.hashKey = function() { - return key; - }; - return key = ""; - }; - - Event.prototype.addHandler = function(handler) { - if (this.handlers.indexOf(handler) === -1) { - this.handlers.push(handler); - } - if (this.oneShot) { - this.autofireHandler(handler); - } - return this; - }; - - Event.prototype.removeHandler = function(handler) { - var index; - if ((index = this.handlers.indexOf(handler)) !== -1) { - this.handlers.splice(index, 1); - } - return this; - }; - - Event.prototype.eachHandler = function(iterator) { - var key, _ref, _ref1; - this.handlers.slice().forEach(iterator); - if ((_ref = this.base) != null ? _ref.isEventEmitter : void 0) { - key = this.key; - return (_ref1 = this.base._batman) != null ? _ref1.ancestors(function(ancestor) { - var handlers, _ref2, _ref3; - if (ancestor.isEventEmitter && ((_ref2 = ancestor._batman) != null ? (_ref3 = _ref2.events) != null ? _ref3.hasOwnProperty(key) : void 0 : void 0)) { - handlers = ancestor.event(key).handlers; - return handlers.slice().forEach(iterator); - } - }) : void 0; - } - }; - - Event.prototype.clearHandlers = function() { - return this.handlers = []; - }; - - Event.prototype.handlerContext = function() { - return this.base; - }; - - Event.prototype.prevent = function() { - return ++this._preventCount; - }; - - Event.prototype.allow = function() { - if (this._preventCount) { - --this._preventCount; - } - return this._preventCount; - }; - - Event.prototype.isPrevented = function() { - return this._preventCount > 0; - }; - - Event.prototype.autofireHandler = function(handler) { - if (this._oneShotFired && (this._oneShotArgs != null)) { - return handler.apply(this.handlerContext(), this._oneShotArgs); - } - }; - - Event.prototype.resetOneShot = function() { - this._oneShotFired = false; - return this._oneShotArgs = null; - }; - - Event.prototype.fire = function() { - var args, context; - if (this.isPrevented() || this._oneShotFired) { - return false; - } - context = this.handlerContext(); - args = arguments; - if (this.oneShot) { - this._oneShotFired = true; - this._oneShotArgs = arguments; - } - return this.eachHandler(function(handler) { - return handler.apply(context, args); - }); - }; - - Event.prototype.allowAndFire = function() { - this.allow(); - return this.fire.apply(this, arguments); - }; - - return Event; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PropertyEvent = (function(_super) { - - __extends(PropertyEvent, _super); - - function PropertyEvent() { - return PropertyEvent.__super__.constructor.apply(this, arguments); - } - - PropertyEvent.prototype.eachHandler = function(iterator) { - return this.base.eachObserver(iterator); - }; - - PropertyEvent.prototype.handlerContext = function() { - return this.base.base; - }; - - return PropertyEvent; - - })(Batman.Event); - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.EventEmitter = { - isEventEmitter: true, - hasEvent: function(key) { - var _ref, _ref1; - return (_ref = this._batman) != null ? typeof _ref.get === "function" ? (_ref1 = _ref.get('events')) != null ? _ref1.hasOwnProperty(key) : void 0 : void 0 : void 0; - }, - event: function(key) { - var eventClass, events, existingEvent, newEvent, _base; - Batman.initializeObject(this); - eventClass = this.eventClass || Batman.Event; - events = (_base = this._batman).events || (_base.events = {}); - if (events.hasOwnProperty(key)) { - return existingEvent = events[key]; - } else { - this._batman.ancestors(function(ancestor) { - var _ref, _ref1; - return existingEvent || (existingEvent = (_ref = ancestor._batman) != null ? (_ref1 = _ref.events) != null ? _ref1[key] : void 0 : void 0); - }); - newEvent = events[key] = new eventClass(this, key); - newEvent.oneShot = existingEvent != null ? existingEvent.oneShot : void 0; - return newEvent; - } - }, - on: function(key, handler) { - return this.event(key).addHandler(handler); - }, - once: function(key, originalHandler) { - var event, handler; - event = this.event(key); - handler = function() { - originalHandler.apply(this, arguments); - return event.removeHandler(handler); - }; - return event.addHandler(handler); - }, - registerAsMutableSource: function() { - return Batman.Property.registerSource(this); - }, - mutation: function(wrappedFunction) { - return function() { - var result; - result = wrappedFunction.apply(this, arguments); - this.event('change').fire(this, this); - return result; - }; - }, - prevent: function(key) { - this.event(key).prevent(); - return this; - }, - allow: function(key) { - this.event(key).allow(); - return this; - }, - isPrevented: function(key) { - return this.event(key).isPrevented(); - }, - fire: function() { - var args, key, _ref; - key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - return (_ref = this.event(key)).fire.apply(_ref, args); - }, - allowAndFire: function() { - var args, key, _ref; - key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - return (_ref = this.event(key)).allowAndFire.apply(_ref, args); - } - }; - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.Enumerable = { - isEnumerable: true, - map: function(f, ctx) { - var r; - if (ctx == null) { - ctx = Batman.container; - } - r = []; - this.forEach(function() { - return r.push(f.apply(ctx, arguments)); - }); - return r; - }, - mapToProperty: function(key) { - var r; - r = []; - this.forEach(function(item) { - return r.push(item.get(key)); - }); - return r; - }, - every: function(f, ctx) { - var r; - if (ctx == null) { - ctx = Batman.container; - } - r = true; - this.forEach(function() { - return r = r && f.apply(ctx, arguments); - }); - return r; - }, - some: function(f, ctx) { - var r; - if (ctx == null) { - ctx = Batman.container; - } - r = false; - this.forEach(function() { - return r = r || f.apply(ctx, arguments); - }); - return r; - }, - reduce: function(f, r) { - var count, self; - count = 0; - self = this; - this.forEach(function() { - if (r != null) { - return r = f.apply(null, [r].concat(__slice.call(arguments), [count], [self])); - } else { - return r = arguments[0]; - } - }); - return r; - }, - filter: function(f) { - var r, wrap; - r = new this.constructor; - if (r.add) { - wrap = function(r, e) { - if (f(e)) { - r.add(e); - } - return r; - }; - } else if (r.set) { - wrap = function(r, k, v) { - if (f(k, v)) { - r.set(k, v); - } - return r; - }; - } else { - if (!r.push) { - r = []; - } - wrap = function(r, e) { - if (f(e)) { - r.push(e); - } - return r; - }; - } - return this.reduce(wrap, r); - }, - inGroupsOf: function(n) { - var current, i, r; - r = []; - current = false; - i = 0; - this.forEach(function(x) { - if (i++ % n === 0) { - current = []; - r.push(current); - } - return current.push(x); - }); - return r; - } - }; - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.SimpleHash = (function() { - - function SimpleHash(obj) { - this._storage = {}; - this.length = 0; - if (obj != null) { - this.update(obj); - } - } - - Batman.extend(SimpleHash.prototype, Batman.Enumerable); - - SimpleHash.prototype.propertyClass = Batman.Property; - - SimpleHash.prototype.hasKey = function(key) { - var pair, pairs, _i, _len; - if (this.objectKey(key)) { - if (!this._objectStorage) { - return false; - } - if (pairs = this._objectStorage[this.hashKeyFor(key)]) { - for (_i = 0, _len = pairs.length; _i < _len; _i++) { - pair = pairs[_i]; - if (this.equality(pair[0], key)) { - return true; - } - } - } - return false; - } else { - key = this.prefixedKey(key); - return this._storage.hasOwnProperty(key); - } - }; - - SimpleHash.prototype.get = function(key) { - var pair, pairs, _i, _len; - if (this.objectKey(key)) { - if (!this._objectStorage) { - return void 0; - } - if (pairs = this._objectStorage[this.hashKeyFor(key)]) { - for (_i = 0, _len = pairs.length; _i < _len; _i++) { - pair = pairs[_i]; - if (this.equality(pair[0], key)) { - return pair[1]; - } - } - } - } else { - return this._storage[this.prefixedKey(key)]; - } - }; - - SimpleHash.prototype.set = function(key, val) { - var pair, pairs, _base, _i, _len, _name; - if (this.objectKey(key)) { - this._objectStorage || (this._objectStorage = {}); - pairs = (_base = this._objectStorage)[_name = this.hashKeyFor(key)] || (_base[_name] = []); - for (_i = 0, _len = pairs.length; _i < _len; _i++) { - pair = pairs[_i]; - if (this.equality(pair[0], key)) { - return pair[1] = val; - } - } - this.length++; - pairs.push([key, val]); - return val; - } else { - key = this.prefixedKey(key); - if (this._storage[key] == null) { - this.length++; - } - return this._storage[key] = val; - } - }; - - SimpleHash.prototype.unset = function(key) { - var hashKey, index, obj, pair, pairs, val, value, _i, _len, _ref; - if (this.objectKey(key)) { - if (!this._objectStorage) { - return void 0; - } - hashKey = this.hashKeyFor(key); - if (pairs = this._objectStorage[hashKey]) { - for (index = _i = 0, _len = pairs.length; _i < _len; index = ++_i) { - _ref = pairs[index], obj = _ref[0], value = _ref[1]; - if (this.equality(obj, key)) { - pair = pairs.splice(index, 1); - if (!pairs.length) { - delete this._objectStorage[hashKey]; - } - this.length--; - return pair[0][1]; - } - } - } - } else { - key = this.prefixedKey(key); - val = this._storage[key]; - if (this._storage[key] != null) { - this.length--; - delete this._storage[key]; - } - return val; - } - }; - - SimpleHash.prototype.getOrSet = function(key, valueFunction) { - var currentValue; - currentValue = this.get(key); - if (!currentValue) { - currentValue = valueFunction(); - this.set(key, currentValue); - } - return currentValue; - }; - - SimpleHash.prototype.prefixedKey = function(key) { - return "_" + key; - }; - - SimpleHash.prototype.unprefixedKey = function(key) { - return key.slice(1); - }; - - SimpleHash.prototype.hashKeyFor = function(obj) { - return (obj != null ? typeof obj.hashKey === "function" ? obj.hashKey() : void 0 : void 0) || obj; - }; - - SimpleHash.prototype.equality = function(lhs, rhs) { - if (lhs === rhs) { - return true; - } - if (lhs !== lhs && rhs !== rhs) { - return true; - } - if ((lhs != null ? typeof lhs.isEqual === "function" ? lhs.isEqual(rhs) : void 0 : void 0) && (rhs != null ? typeof rhs.isEqual === "function" ? rhs.isEqual(lhs) : void 0 : void 0)) { - return true; - } - return false; - }; - - SimpleHash.prototype.objectKey = function(key) { - return typeof key !== 'string'; - }; - - SimpleHash.prototype.forEach = function(iterator, ctx) { - var key, obj, results, value, values, _i, _len, _ref, _ref1, _ref2, _ref3; - results = []; - if (this._objectStorage) { - _ref = this._objectStorage; - for (key in _ref) { - values = _ref[key]; - _ref1 = values.slice(); - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - _ref2 = _ref1[_i], obj = _ref2[0], value = _ref2[1]; - results.push(iterator.call(ctx, obj, value, this)); - } - } - } - _ref3 = this._storage; - for (key in _ref3) { - value = _ref3[key]; - results.push(iterator.call(ctx, this.unprefixedKey(key), value, this)); - } - return results; - }; - - SimpleHash.prototype.keys = function() { - var result; - result = []; - Batman.SimpleHash.prototype.forEach.call(this, function(key) { - return result.push(key); - }); - return result; - }; - - SimpleHash.prototype.toArray = SimpleHash.prototype.keys; - - SimpleHash.prototype.clear = function() { - this._storage = {}; - delete this._objectStorage; - return this.length = 0; - }; - - SimpleHash.prototype.isEmpty = function() { - return this.length === 0; - }; - - SimpleHash.prototype.merge = function() { - var hash, merged, others, _i, _len; - others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - merged = new this.constructor; - others.unshift(this); - for (_i = 0, _len = others.length; _i < _len; _i++) { - hash = others[_i]; - hash.forEach(function(obj, value) { - return merged.set(obj, value); - }); - } - return merged; - }; - - SimpleHash.prototype.update = function(object) { - var k, v, _results; - _results = []; - for (k in object) { - v = object[k]; - _results.push(this.set(k, v)); - } - return _results; - }; - - SimpleHash.prototype.replace = function(object) { - var _this = this; - this.forEach(function(key, value) { - if (!(key in object)) { - return _this.unset(key); - } - }); - return this.update(object); - }; - - SimpleHash.prototype.toObject = function() { - var key, obj, pair, value, _ref, _ref1; - obj = {}; - _ref = this._storage; - for (key in _ref) { - value = _ref[key]; - obj[this.unprefixedKey(key)] = value; - } - if (this._objectStorage) { - _ref1 = this._objectStorage; - for (key in _ref1) { - pair = _ref1[key]; - obj[key] = pair[0][1]; - } - } - return obj; - }; - - SimpleHash.prototype.toJSON = SimpleHash.prototype.toObject; - - return SimpleHash; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.AssociationCurator = (function(_super) { - - __extends(AssociationCurator, _super); - - AssociationCurator.availableAssociations = ['belongsTo', 'hasOne', 'hasMany']; - - function AssociationCurator(model) { - this.model = model; - AssociationCurator.__super__.constructor.call(this); - this._byTypeStorage = new Batman.SimpleHash; - } - - AssociationCurator.prototype.add = function(association) { - var associationTypeSet; - this.set(association.label, association); - if (!(associationTypeSet = this._byTypeStorage.get(association.associationType))) { - associationTypeSet = new Batman.SimpleSet; - this._byTypeStorage.set(association.associationType, associationTypeSet); - } - return associationTypeSet.add(association); - }; - - AssociationCurator.prototype.getByType = function(type) { - return this._byTypeStorage.get(type); - }; - - AssociationCurator.prototype.getByLabel = function(label) { - return this.get(label); - }; - - AssociationCurator.prototype.reset = function() { - this.forEach(function(label, association) { - return association.reset(); - }); - return true; - }; - - AssociationCurator.prototype.merge = function() { - var others, result; - others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - result = AssociationCurator.__super__.merge.apply(this, arguments); - result._byTypeStorage = this._byTypeStorage.merge(others.map(function(other) { - return other._byTypeStorage; - })); - return result; - }; - - AssociationCurator.prototype._markDirtyAttribute = function(key, oldValue) { - var _ref; - if ((_ref = this.lifecycle.get('state')) !== 'loading' && _ref !== 'creating' && _ref !== 'saving' && _ref !== 'saved') { - if (this.lifecycle.startTransition('set')) { - return this.dirtyKeys.set(key, oldValue); - } else { - throw new Batman.StateMachine.InvalidTransitionError("Can't set while in state " + (this.lifecycle.get('state'))); - } - } - }; - - return AssociationCurator; - - })(Batman.SimpleHash); - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.SimpleSet = (function() { - - function SimpleSet() { - this._storage = []; - this.length = 0; - if (arguments.length > 0) { - this.add.apply(this, arguments); - } - } - - Batman.extend(SimpleSet.prototype, Batman.Enumerable); - - SimpleSet.prototype.has = function(item) { - return !!(~this._indexOfItem(item)); - }; - - SimpleSet.prototype.add = function() { - var addedItems, item, items, _i, _len; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - addedItems = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (!(!~this._indexOfItem(item))) { - continue; - } - this._storage.push(item); - addedItems.push(item); - } - this.length = this._storage.length; - if (this.fire && addedItems.length !== 0) { - this.fire('change', this, this); - this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedItems))); - } - return addedItems; - }; - - SimpleSet.prototype.remove = function() { - var index, item, items, removedItems, _i, _len; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - removedItems = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (!(~(index = this._indexOfItem(item)))) { - continue; - } - this._storage.splice(index, 1); - removedItems.push(item); - } - this.length = this._storage.length; - if (this.fire && removedItems.length !== 0) { - this.fire('change', this, this); - this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(removedItems))); - } - return removedItems; - }; - - SimpleSet.prototype.find = function(f) { - var item, _i, _len, _ref; - _ref = this._storage; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - item = _ref[_i]; - if (f(item)) { - return item; - } - } - }; - - SimpleSet.prototype.forEach = function(iterator, ctx) { - var container; - container = this; - return this._storage.slice().forEach(function(key) { - return iterator.call(ctx, key, null, container); - }); - }; - - SimpleSet.prototype.isEmpty = function() { - return this.length === 0; - }; - - SimpleSet.prototype.clear = function() { - var items; - items = this._storage; - this._storage = []; - this.length = 0; - if (this.fire && items.length !== 0) { - this.fire('change', this, this); - this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(items))); - } - return items; - }; - - SimpleSet.prototype.replace = function(other) { - try { - if (typeof this.prevent === "function") { - this.prevent('change'); - } - this.clear(); - return this.add.apply(this, other.toArray()); - } finally { - if (typeof this.allowAndFire === "function") { - this.allowAndFire('change', this, this); - } - } - }; - - SimpleSet.prototype.toArray = function() { - return this._storage.slice(); - }; - - SimpleSet.prototype.merge = function() { - var merged, others, set, _i, _len; - others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - merged = new this.constructor; - others.unshift(this); - for (_i = 0, _len = others.length; _i < _len; _i++) { - set = others[_i]; - set.forEach(function(v) { - return merged.add(v); - }); - } - return merged; - }; - - SimpleSet.prototype.indexedBy = function(key) { - this._indexes || (this._indexes = new Batman.SimpleHash); - return this._indexes.get(key) || this._indexes.set(key, new Batman.SetIndex(this, key)); - }; - - SimpleSet.prototype.indexedByUnique = function(key) { - this._uniqueIndexes || (this._uniqueIndexes = new Batman.SimpleHash); - return this._uniqueIndexes.get(key) || this._uniqueIndexes.set(key, new Batman.UniqueSetIndex(this, key)); - }; - - SimpleSet.prototype.sortedBy = function(key, order) { - var sortsForKey; - if (order == null) { - order = "asc"; - } - order = order.toLowerCase() === "desc" ? "desc" : "asc"; - this._sorts || (this._sorts = new Batman.SimpleHash); - sortsForKey = this._sorts.get(key) || this._sorts.set(key, new Batman.Object); - return sortsForKey.get(order) || sortsForKey.set(order, new Batman.SetSort(this, key, order)); - }; - - SimpleSet.prototype.equality = Batman.SimpleHash.prototype.equality; - - SimpleSet.prototype._indexOfItem = function(givenItem) { - var index, item, _i, _len, _ref; - _ref = this._storage; - for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { - item = _ref[index]; - if (this.equality(givenItem, item)) { - return index; - } - } - return -1; - }; - - return SimpleSet; - - })(); - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.Property = (function() { - - Batman.mixin(Property.prototype, Batman.EventEmitter); - - Property._sourceTrackerStack = []; - - Property.sourceTracker = function() { - var stack; - return (stack = this._sourceTrackerStack)[stack.length - 1]; - }; - - Property.defaultAccessor = { - get: function(key) { - return this[key]; - }, - set: function(key, val) { - return this[key] = val; - }, - unset: function(key) { - var x; - x = this[key]; - delete this[key]; - return x; - }, - cache: false - }; - - Property.defaultAccessorForBase = function(base) { - var _ref; - return ((_ref = base._batman) != null ? _ref.getFirst('defaultAccessor') : void 0) || Batman.Property.defaultAccessor; - }; - - Property.accessorForBaseAndKey = function(base, key) { - var accessor, _bm, _ref, - _this = this; - if ((_bm = base._batman) != null) { - accessor = (_ref = _bm.keyAccessors) != null ? _ref.get(key) : void 0; - if (!accessor) { - _bm.ancestors(function(ancestor) { - var _ref1, _ref2; - return accessor || (accessor = (_ref1 = ancestor._batman) != null ? (_ref2 = _ref1.keyAccessors) != null ? _ref2.get(key) : void 0 : void 0); - }); - } - } - return accessor || this.defaultAccessorForBase(base); - }; - - Property.forBaseAndKey = function(base, key) { - if (base.isObservable) { - return base.property(key); - } else { - return new Batman.Keypath(base, key); - } - }; - - Property.withoutTracking = function(block) { - return this.wrapTrackingPrevention(block)(); - }; - - Property.wrapTrackingPrevention = function(block) { - return function() { - Batman.Property.pushDummySourceTracker(); - try { - return block.apply(this, arguments); - } finally { - Batman.Property.popSourceTracker(); - } - }; - }; - - Property.registerSource = function(obj) { - var _ref; - if (!obj.isEventEmitter) { - return; - } - return (_ref = this.sourceTracker()) != null ? _ref.add(obj) : void 0; - }; - - Property.pushSourceTracker = function() { - return Batman.Property._sourceTrackerStack.push(new Batman.SimpleSet); - }; - - Property.pushDummySourceTracker = function() { - return Batman.Property._sourceTrackerStack.push(null); - }; - - Property.popSourceTracker = function() { - return Batman.Property._sourceTrackerStack.pop(); - }; - - function Property(base, key) { - this.base = base; - this.key = key; - } - - Property.prototype._isolationCount = 0; - - Property.prototype.cached = false; - - Property.prototype.value = null; - - Property.prototype.sources = null; - - Property.prototype.isProperty = true; - - Property.prototype.isDead = false; - - Property.prototype.eventClass = Batman.PropertyEvent; - - Property.prototype.isEqual = function(other) { - return this.constructor === other.constructor && this.base === other.base && this.key === other.key; - }; - - Property.prototype.hashKey = function() { - var key; - this.hashKey = function() { - return key; - }; - return key = ""; - }; - - Property.prototype.event = function(key) { - var eventClass, _base; - eventClass = this.eventClass || Batman.Event; - this.events || (this.events = {}); - (_base = this.events)[key] || (_base[key] = new eventClass(this, key)); - return this.events[key]; - }; - - Property.prototype.changeEvent = function() { - var event; - event = this.event('change'); - this.changeEvent = function() { - return event; - }; - return event; - }; - - Property.prototype.accessor = function() { - var accessor; - accessor = this.constructor.accessorForBaseAndKey(this.base, this.key); - this.accessor = function() { - return accessor; - }; - return accessor; - }; - - Property.prototype.eachObserver = function(iterator) { - var key; - key = this.key; - this.changeEvent().handlers.slice().forEach(iterator); - if (this.base.isObservable) { - return this.base._batman.ancestors(function(ancestor) { - var handlers, property; - if (ancestor.isObservable && ancestor.hasProperty(key)) { - property = ancestor.property(key); - handlers = property.changeEvent().handlers; - return handlers.slice().forEach(iterator); - } - }); - } - }; - - Property.prototype.observers = function() { - var results; - results = []; - this.eachObserver(function(observer) { - return results.push(observer); - }); - return results; - }; - - Property.prototype.hasObservers = function() { - return this.observers().length > 0; - }; - - Property.prototype.updateSourcesFromTracker = function() { - var handler, newSources; - newSources = this.constructor.popSourceTracker(); - handler = this.sourceChangeHandler(); - this._eachSourceChangeEvent(function(e) { - return e.removeHandler(handler); - }); - this.sources = newSources; - return this._eachSourceChangeEvent(function(e) { - return e.addHandler(handler); - }); - }; - - Property.prototype._eachSourceChangeEvent = function(iterator) { - if (this.sources == null) { - return; - } - return this.sources.forEach(function(source) { - return iterator(source.event('change')); - }); - }; - - Property.prototype.getValue = function() { - this.registerAsMutableSource(); - if (!this.isCached()) { - this.constructor.pushSourceTracker(); - try { - this.value = this.valueFromAccessor(); - this.cached = true; - } finally { - this.updateSourcesFromTracker(); - } - } - return this.value; - }; - - Property.prototype.isCachable = function() { - var cacheable; - if (this.isFinal()) { - return true; - } - cacheable = this.accessor().cache; - if (cacheable != null) { - return !!cacheable; - } else { - return true; - } - }; - - Property.prototype.isCached = function() { - return this.isCachable() && this.cached; - }; - - Property.prototype.isFinal = function() { - return !!this.accessor()['final']; - }; - - Property.prototype.refresh = function() { - var previousValue, value; - this.cached = false; - previousValue = this.value; - value = this.getValue(); - if (value !== previousValue && !this.isIsolated()) { - this.fire(value, previousValue); - } - if (this.value !== void 0 && this.isFinal()) { - return this.lockValue(); - } - }; - - Property.prototype.sourceChangeHandler = function() { - var handler, - _this = this; - handler = this._handleSourceChange.bind(this); - Batman.developer["do"](function() { - return handler.property = _this; - }); - this.sourceChangeHandler = function() { - return handler; - }; - return handler; - }; - - Property.prototype._handleSourceChange = function() { - if (this.isIsolated()) { - return this._needsRefresh = true; - } else if (!this.isFinal() && !this.hasObservers()) { - return this.cached = false; - } else { - return this.refresh(); - } - }; - - Property.prototype.valueFromAccessor = function() { - var _ref; - return (_ref = this.accessor().get) != null ? _ref.call(this.base, this.key) : void 0; - }; - - Property.prototype.setValue = function(val) { - var set; - if (!(set = this.accessor().set)) { - return; - } - return this._changeValue(function() { - return set.call(this.base, this.key, val); - }); - }; - - Property.prototype.unsetValue = function() { - var unset; - if (!(unset = this.accessor().unset)) { - return; - } - return this._changeValue(function() { - return unset.call(this.base, this.key); - }); - }; - - Property.prototype._changeValue = function(block) { - var result; - this.cached = false; - this.constructor.pushDummySourceTracker(); - try { - result = block.apply(this); - this.refresh(); - } finally { - this.constructor.popSourceTracker(); - } - if (!(this.isCached() || this.hasObservers())) { - this.die(); - } - return result; - }; - - Property.prototype.forget = function(handler) { - if (handler != null) { - return this.changeEvent().removeHandler(handler); - } else { - return this.changeEvent().clearHandlers(); - } - }; - - Property.prototype.observeAndFire = function(handler) { - this.observe(handler); - return handler.call(this.base, this.value, this.value, this.key); - }; - - Property.prototype.observe = function(handler) { - this.changeEvent().addHandler(handler); - if (this.sources == null) { - this.getValue(); - } - return this; - }; - - Property.prototype.observeOnce = function(originalHandler) { - var event, handler; - event = this.changeEvent(); - handler = function() { - originalHandler.apply(this, arguments); - return event.removeHandler(handler); - }; - event.addHandler(handler); - if (this.sources == null) { - this.getValue(); - } - return this; - }; - - Property.prototype._removeHandlers = function() { - var handler; - handler = this.sourceChangeHandler(); - this._eachSourceChangeEvent(function(e) { - return e.removeHandler(handler); - }); - delete this.sources; - return this.changeEvent().clearHandlers(); - }; - - Property.prototype.lockValue = function() { - this._removeHandlers(); - this.getValue = function() { - return this.value; - }; - return this.setValue = this.unsetValue = this.refresh = this.observe = function() {}; - }; - - Property.prototype.die = function() { - var _ref, _ref1; - this._removeHandlers(); - if ((_ref = this.base._batman) != null) { - if ((_ref1 = _ref.properties) != null) { - _ref1.unset(this.key); - } - } - return this.isDead = true; - }; - - Property.prototype.fire = function() { - var _ref; - return (_ref = this.changeEvent()).fire.apply(_ref, __slice.call(arguments).concat([this.key])); - }; - - Property.prototype.isolate = function() { - if (this._isolationCount === 0) { - this._preIsolationValue = this.getValue(); - } - return this._isolationCount++; - }; - - Property.prototype.expose = function() { - if (this._isolationCount === 1) { - this._isolationCount--; - if (this._needsRefresh) { - this.value = this._preIsolationValue; - this.refresh(); - } else if (this.value !== this._preIsolationValue) { - this.fire(this.value, this._preIsolationValue); - } - return this._preIsolationValue = null; - } else if (this._isolationCount > 0) { - return this._isolationCount--; - } - }; - - Property.prototype.isIsolated = function() { - return this._isolationCount > 0; - }; - - return Property; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Keypath = (function(_super) { - - __extends(Keypath, _super); - - function Keypath(base, key) { - if (typeof key === 'string') { - this.segments = key.split('.'); - this.depth = this.segments.length; - } else { - this.segments = [key]; - this.depth = 1; - } - Keypath.__super__.constructor.apply(this, arguments); - } - - Keypath.prototype.isCachable = function() { - if (this.depth === 1) { - return Keypath.__super__.isCachable.apply(this, arguments); - } else { - return true; - } - }; - - Keypath.prototype.terminalProperty = function() { - var base; - base = Batman.getPath(this.base, this.segments.slice(0, -1)); - if (base == null) { - return; - } - return Batman.Keypath.forBaseAndKey(base, this.segments[this.depth - 1]); - }; - - Keypath.prototype.valueFromAccessor = function() { - if (this.depth === 1) { - return Keypath.__super__.valueFromAccessor.apply(this, arguments); - } else { - return Batman.getPath(this.base, this.segments); - } - }; - - Keypath.prototype.setValue = function(val) { - var _ref; - if (this.depth === 1) { - return Keypath.__super__.setValue.apply(this, arguments); - } else { - return (_ref = this.terminalProperty()) != null ? _ref.setValue(val) : void 0; - } - }; - - Keypath.prototype.unsetValue = function() { - var _ref; - if (this.depth === 1) { - return Keypath.__super__.unsetValue.apply(this, arguments); - } else { - return (_ref = this.terminalProperty()) != null ? _ref.unsetValue() : void 0; - } - }; - - return Keypath; - - })(Batman.Property); - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.Observable = { - isObservable: true, - hasProperty: function(key) { - var _ref, _ref1; - return (_ref = this._batman) != null ? (_ref1 = _ref.properties) != null ? typeof _ref1.hasKey === "function" ? _ref1.hasKey(key) : void 0 : void 0 : void 0; - }, - property: function(key) { - var properties, propertyClass, _base; - Batman.initializeObject(this); - propertyClass = this.propertyClass || Batman.Keypath; - properties = (_base = this._batman).properties || (_base.properties = new Batman.SimpleHash); - return properties.get(key) || properties.set(key, new propertyClass(this, key)); - }, - get: function(key) { - return this.property(key).getValue(); - }, - set: function(key, val) { - return this.property(key).setValue(val); - }, - unset: function(key) { - return this.property(key).unsetValue(); - }, - getOrSet: Batman.SimpleHash.prototype.getOrSet, - forget: function(key, observer) { - var _ref; - if (key) { - this.property(key).forget(observer); - } else { - if ((_ref = this._batman.properties) != null) { - _ref.forEach(function(key, property) { - return property.forget(); - }); - } - } - return this; - }, - observe: function() { - var args, key, _ref; - key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - (_ref = this.property(key)).observe.apply(_ref, args); - return this; - }, - observeAndFire: function() { - var args, key, _ref; - key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - (_ref = this.property(key)).observeAndFire.apply(_ref, args); - return this; - }, - observeOnce: function() { - var args, key, _ref; - key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - (_ref = this.property(key)).observeOnce.apply(_ref, args); - return this; - } - }; - -}).call(this); - -(function() { - - Batman.DOM = { - textInputTypes: ['text', 'search', 'tel', 'url', 'email', 'password'], - scrollIntoView: function(elementID) { - var _ref; - return (_ref = document.getElementById(elementID)) != null ? typeof _ref.scrollIntoView === "function" ? _ref.scrollIntoView() : void 0 : void 0; - }, - querySelectorAll: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) { - return jQuery(selector, node); - } : (typeof document !== "undefined" && document !== null ? document.querySelectorAll : void 0) != null ? function(node, selector) { - return node.querySelectorAll(selector); - } : function() { - return Batman.developer.error("Please include either jQuery or a querySelectorAll polyfill, or set Batman.DOM.querySelectorAll to return an empty array."); - }, - querySelector: (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) != null ? function(node, selector) { - return jQuery(selector, node)[0]; - } : (typeof document !== "undefined" && document !== null ? document.querySelector : void 0) != null ? function(node, selector) { - return node.querySelector(selector); - } : function() { - return Batman.developer.error("Please include either jQuery or a querySelector polyfill, or set Batman.DOM.querySelector to an empty function."); - }, - partial: function(container, path, context, renderer) { - var view; - renderer.prevent('rendered'); - view = new Batman.View({ - source: path, - context: context - }); - return view.on('ready', function() { - Batman.setInnerHTML(container, ''); - Batman.appendChild(container, view.get('node')); - return renderer.allowAndFire('rendered'); - }); - }, - propagateBindingEvent: Batman.propagateBindingEvent = function(binding, node) { - var current, parentBinding, parentBindings, _i, _len; - while ((current = (current || node).parentNode)) { - parentBindings = Batman._data(current, 'bindings'); - if (parentBindings != null) { - for (_i = 0, _len = parentBindings.length; _i < _len; _i++) { - parentBinding = parentBindings[_i]; - if (typeof parentBinding.childBindingAdded === "function") { - parentBinding.childBindingAdded(binding); - } - } - } - } - }, - propagateBindingEvents: Batman.propagateBindingEvents = function(newNode) { - var binding, bindings, child, _i, _j, _len, _len1, _ref; - _ref = newNode.childNodes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - Batman.propagateBindingEvents(child); - } - if (bindings = Batman._data(newNode, 'bindings')) { - for (_j = 0, _len1 = bindings.length; _j < _len1; _j++) { - binding = bindings[_j]; - Batman.propagateBindingEvent(binding, newNode); - } - } - }, - trackBinding: Batman.trackBinding = function(binding, node) { - var bindings; - if (bindings = Batman._data(node, 'bindings')) { - bindings.push(binding); - } else { - Batman._data(node, 'bindings', [binding]); - } - Batman.DOM.fire('bindingAdded', binding); - Batman.propagateBindingEvent(binding, node); - return true; - }, - onParseExit: Batman.onParseExit = function(node, callback) { - var set; - set = Batman._data(node, 'onParseExit') || Batman._data(node, 'onParseExit', new Batman.SimpleSet); - if (callback != null) { - set.add(callback); - } - return set; - }, - forgetParseExit: Batman.forgetParseExit = function(node, callback) { - return Batman.removeData(node, 'onParseExit', true); - }, - defineView: function(name, node) { - var contents; - contents = node.innerHTML; - Batman.View.store.set(Batman.Navigator.normalizePath(name), contents); - return contents; - }, - setInnerHTML: Batman.setInnerHTML = function(node, html) { - var child, childNodes, result, _i, _j, _len, _len1; - childNodes = (function() { - var _i, _len, _ref, _results; - _ref = node.childNodes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - _results.push(child); - } - return _results; - })(); - for (_i = 0, _len = childNodes.length; _i < _len; _i++) { - child = childNodes[_i]; - Batman.DOM.willRemoveNode(child); - } - result = node.innerHTML = html; - for (_j = 0, _len1 = childNodes.length; _j < _len1; _j++) { - child = childNodes[_j]; - Batman.DOM.didRemoveNode(child); - } - return result; - }, - setStyleProperty: Batman.setStyleProperty = function(node, property, value, importance) { - if (node.style.setAttribute) { - return node.style.setAttribute(property, value, importance); - } else { - return node.style.setProperty(property, value, importance); - } - }, - removeNode: Batman.removeNode = function(node) { - var _ref; - Batman.DOM.willRemoveNode(node); - if ((_ref = node.parentNode) != null) { - _ref.removeChild(node); - } - return Batman.DOM.didRemoveNode(node); - }, - destroyNode: Batman.destroyNode = function(node) { - Batman.DOM.willDestroyNode(node); - Batman.removeNode(node); - return Batman.DOM.didDestroyNode(node); - }, - appendChild: Batman.appendChild = function(parent, child) { - Batman.DOM.willInsertNode(child); - parent.appendChild(child); - return Batman.DOM.didInsertNode(child); - }, - removeOrDestroyNode: Batman.removeOrDestroyNode = function(node) { - var view; - view = Batman._data(node, 'view'); - view || (view = Batman._data(node, 'yielder')); - if ((view != null) && view.get('cached')) { - return Batman.DOM.removeNode(node); - } else { - return Batman.DOM.destroyNode(node); - } - }, - insertBefore: Batman.insertBefore = function(parentNode, newNode, referenceNode) { - if (referenceNode == null) { - referenceNode = null; - } - if (!referenceNode || parentNode.childNodes.length <= 0) { - return Batman.appendChild(parentNode, newNode); - } else { - Batman.DOM.willInsertNode(newNode); - parentNode.insertBefore(newNode, referenceNode); - return Batman.DOM.didInsertNode(newNode); - } - }, - valueForNode: function(node, value, escapeValue) { - var isSetting; - if (value == null) { - value = ''; - } - if (escapeValue == null) { - escapeValue = true; - } - isSetting = arguments.length > 1; - switch (node.nodeName.toUpperCase()) { - case 'INPUT': - case 'TEXTAREA': - if (isSetting) { - return node.value = value; - } else { - return node.value; - } - break; - case 'SELECT': - if (isSetting) { - return node.value = value; - } - break; - default: - if (isSetting) { - return Batman.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value); - } else { - return node.innerHTML; - } - } - }, - nodeIsEditable: function(node) { - var _ref; - return (_ref = node.nodeName.toUpperCase()) === 'INPUT' || _ref === 'TEXTAREA' || _ref === 'SELECT'; - }, - addEventListener: Batman.addEventListener = function(node, eventName, callback) { - var listeners; - if (!(listeners = Batman._data(node, 'listeners'))) { - listeners = Batman._data(node, 'listeners', {}); - } - if (!listeners[eventName]) { - listeners[eventName] = []; - } - listeners[eventName].push(callback); - if (Batman.hasAddEventListener) { - return node.addEventListener(eventName, callback, false); - } else { - return node.attachEvent("on" + eventName, callback); - } - }, - removeEventListener: Batman.removeEventListener = function(node, eventName, callback) { - var eventListeners, index, listeners; - if (listeners = Batman._data(node, 'listeners')) { - if (eventListeners = listeners[eventName]) { - index = eventListeners.indexOf(callback); - if (index !== -1) { - eventListeners.splice(index, 1); - } - } - } - if (Batman.hasAddEventListener) { - return node.removeEventListener(eventName, callback, false); - } else { - return node.detachEvent('on' + eventName, callback); - } - }, - hasAddEventListener: Batman.hasAddEventListener = !!(typeof window !== "undefined" && window !== null ? window.addEventListener : void 0), - preventDefault: Batman.preventDefault = function(e) { - if (typeof e.preventDefault === "function") { - return e.preventDefault(); - } else { - return e.returnValue = false; - } - }, - stopPropagation: Batman.stopPropagation = function(e) { - if (e.stopPropagation) { - return e.stopPropagation(); - } else { - return e.cancelBubble = true; - } - }, - willInsertNode: function(node) { - var child, view, _i, _len, _ref, _ref1; - view = Batman._data(node, 'view'); - if (view != null) { - view.fire('beforeAppear', node); - } - if ((_ref = Batman.data(node, 'show')) != null) { - _ref.call(node); - } - _ref1 = node.childNodes; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - child = _ref1[_i]; - Batman.DOM.willInsertNode(child); - } - return true; - }, - didInsertNode: function(node) { - var child, view, _i, _len, _ref; - view = Batman._data(node, 'view'); - if (view) { - view.fire('appear', node); - view.applyYields(); - } - _ref = node.childNodes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - Batman.DOM.didInsertNode(child); - } - return true; - }, - willRemoveNode: function(node) { - var child, view, _i, _len, _ref, _ref1; - view = Batman._data(node, 'view'); - if (view) { - view.fire('beforeDisappear', node); - } - if ((_ref = Batman.data(node, 'hide')) != null) { - _ref.call(node); - } - _ref1 = node.childNodes; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - child = _ref1[_i]; - Batman.DOM.willRemoveNode(child); - } - return true; - }, - didRemoveNode: function(node) { - var child, view, _i, _len, _ref; - view = Batman._data(node, 'view'); - if (view) { - view.retractYields(); - view.fire('disappear', node); - } - _ref = node.childNodes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - Batman.DOM.didRemoveNode(child); - } - return true; - }, - willDestroyNode: function(node) { - var child, view, _i, _len, _ref; - view = Batman._data(node, 'view'); - if (view) { - view.fire('beforeDestroy', node); - view.get('yields').forEach(function(name, actions) { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = actions.length; _i < _len; _i++) { - node = actions[_i].node; - _results.push(Batman.DOM.willDestroyNode(node)); - } - return _results; - }); - } - _ref = node.childNodes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - Batman.DOM.willDestroyNode(child); - } - return true; - }, - didDestroyNode: function(node) { - var bindings, child, eventListeners, eventName, listeners, view, _i, _len, _ref; - view = Batman._data(node, 'view'); - if (view) { - view.fire('destroy', node); - view.get('yields').forEach(function(name, actions) { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = actions.length; _i < _len; _i++) { - node = actions[_i].node; - _results.push(Batman.DOM.didDestroyNode(node)); - } - return _results; - }); - } - if (bindings = Batman._data(node, 'bindings')) { - bindings.forEach(function(binding) { - return binding.die(); - }); - } - if (listeners = Batman._data(node, 'listeners')) { - for (eventName in listeners) { - eventListeners = listeners[eventName]; - eventListeners.forEach(function(listener) { - return Batman.removeEventListener(node, eventName, listener); - }); - } - } - Batman.removeData(node); - Batman.removeData(node, void 0, true); - _ref = node.childNodes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - Batman.DOM.didDestroyNode(child); - } - return true; - } - }; - - Batman.mixin(Batman.DOM, Batman.EventEmitter, Batman.Observable); - - Batman.DOM.event('bindingAdded'); - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.DOM.readers = { - target: function(node, key, context, renderer) { - Batman.DOM.readers.bind(node, key, context, renderer, 'nodeChange'); - return true; - }, - source: function(node, key, context, renderer) { - Batman.DOM.readers.bind(node, key, context, renderer, 'dataChange'); - return true; - }, - bind: function(node, key, context, renderer, only) { - var bindingClass; - bindingClass = false; - switch (node.nodeName.toLowerCase()) { - case 'input': - switch (node.getAttribute('type')) { - case 'checkbox': - Batman.DOM.attrReaders.bind(node, 'checked', key, context, renderer, only); - return true; - case 'radio': - bindingClass = Batman.DOM.RadioBinding; - break; - case 'file': - bindingClass = Batman.DOM.FileBinding; - } - break; - case 'select': - bindingClass = Batman.DOM.SelectBinding; - } - bindingClass || (bindingClass = Batman.DOM.Binding); - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(bindingClass, arguments, function(){}); - return true; - }, - context: function(node, key, context, renderer) { - return context.descendWithKey(key); - }, - mixin: function(node, key, context, renderer) { - new Batman.DOM.MixinBinding(node, key, context.descend(Batman.mixins), renderer); - return true; - }, - showif: function(node, key, context, parentRenderer, invert) { - new Batman.DOM.ShowHideBinding(node, key, context, parentRenderer, false, invert); - return true; - }, - hideif: function() { - var _ref; - return (_ref = Batman.DOM.readers).showif.apply(_ref, __slice.call(arguments).concat([true])); - }, - insertif: function(node, key, context, parentRenderer, invert) { - new Batman.DOM.InsertionBinding(node, key, context, parentRenderer, false, invert); - return true; - }, - removeif: function() { - var _ref; - return (_ref = Batman.DOM.readers).insertif.apply(_ref, __slice.call(arguments).concat([true])); - }, - route: function() { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.RouteBinding, arguments, function(){}); - return true; - }, - view: function() { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.ViewBinding, arguments, function(){}); - return false; - }, - partial: function(node, path, context, renderer) { - Batman.DOM.partial(node, path, context, renderer); - return true; - }, - defineview: function(node, name, context, renderer) { - Batman.onParseExit(node, function() { - var _ref; - return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; - }); - Batman.DOM.defineView(name, node); - return false; - }, - renderif: function(node, key, context, renderer) { - new Batman.DOM.DeferredRenderingBinding(node, key, context, renderer); - return false; - }, - "yield": function(node, key) { - Batman.onParseExit(node, function() { - return Batman.DOM.Yield.withName(key).set('containerNode', node); - }); - return true; - }, - contentfor: function(node, key, context, renderer, action) { - if (action == null) { - action = 'append'; - } - Batman.onParseExit(node, function() { - var _ref; - if ((_ref = node.parentNode) != null) { - _ref.removeChild(node); - } - return renderer.view.pushYieldAction(key, action, node); - }); - return true; - }, - replace: function(node, key, context, renderer) { - Batman.DOM.readers.contentfor(node, key, context, renderer, 'replace'); - return true; - } - }; - -}).call(this); - -(function() { - var __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - Batman.DOM.events = { - click: function(node, callback, context, eventName) { - if (eventName == null) { - eventName = 'click'; - } - Batman.addEventListener(node, eventName, function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - callback.apply(null, [node].concat(__slice.call(args), [context])); - return Batman.preventDefault(args[0]); - }); - if (node.nodeName.toUpperCase() === 'A' && !node.href) { - node.href = '#'; - } - return node; - }, - doubleclick: function(node, callback, context) { - return Batman.DOM.events.click(node, callback, context, 'dblclick'); - }, - change: function(node, callback, context) { - var eventName, eventNames, oldCallback, _i, _len, _results; - eventNames = (function() { - var _ref; - switch (node.nodeName.toUpperCase()) { - case 'TEXTAREA': - return ['input', 'keyup', 'change']; - case 'INPUT': - if (_ref = node.type.toLowerCase(), __indexOf.call(Batman.DOM.textInputTypes, _ref) >= 0) { - oldCallback = callback; - callback = function(node, event) { - if (event.type === 'keyup' && Batman.DOM.events.isEnter(event)) { - return; - } - return oldCallback.apply(null, arguments); - }; - return ['input', 'keyup', 'change']; - } else { - return ['input', 'change']; - } - break; - default: - return ['change']; - } - })(); - _results = []; - for (_i = 0, _len = eventNames.length; _i < _len; _i++) { - eventName = eventNames[_i]; - _results.push(Batman.addEventListener(node, eventName, function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return callback.apply(null, [node].concat(__slice.call(args), [context])); - })); - } - return _results; - }, - isEnter: function(ev) { - var _ref, _ref1; - return ((13 <= (_ref = ev.keyCode) && _ref <= 14)) || ((13 <= (_ref1 = ev.which) && _ref1 <= 14)) || ev.keyIdentifier === 'Enter' || ev.key === 'Enter'; - }, - submit: function(node, callback, context) { - if (Batman.DOM.nodeIsEditable(node)) { - Batman.addEventListener(node, 'keydown', function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - if (Batman.DOM.events.isEnter(args[0])) { - return Batman.DOM._keyCapturingNode = node; - } - }); - Batman.addEventListener(node, 'keyup', function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - if (Batman.DOM.events.isEnter(args[0])) { - if (Batman.DOM._keyCapturingNode === node) { - Batman.preventDefault(args[0]); - callback.apply(null, [node].concat(__slice.call(args), [context])); - } - return Batman.DOM._keyCapturingNode = null; - } - }); - } else { - Batman.addEventListener(node, 'submit', function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - Batman.preventDefault(args[0]); - return callback.apply(null, [node].concat(__slice.call(args), [context])); - }); - } - return node; - }, - other: function(node, eventName, callback, context) { - return Batman.addEventListener(node, eventName, function() { - var args; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return callback.apply(null, [node].concat(__slice.call(args), [context])); - }); - } - }; - -}).call(this); - -(function() { - - Batman.DOM.attrReaders = { - _parseAttribute: function(value) { - if (value === 'false') { - value = false; - } - if (value === 'true') { - value = true; - } - return value; - }, - source: function(node, attr, key, context, renderer) { - return Batman.DOM.attrReaders.bind(node, attr, key, context, renderer, 'dataChange'); - }, - bind: function(node, attr, key, context, renderer, only) { - var bindingClass; - bindingClass = (function() { - switch (attr) { - case 'checked': - case 'disabled': - case 'selected': - return Batman.DOM.CheckedBinding; - case 'value': - case 'href': - case 'src': - case 'size': - return Batman.DOM.NodeAttributeBinding; - case 'class': - return Batman.DOM.ClassBinding; - case 'style': - return Batman.DOM.StyleBinding; - default: - return Batman.DOM.AttributeBinding; - } - })(); - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(bindingClass, arguments, function(){}); - return true; - }, - context: function(node, contextName, key, context) { - return context.descendWithKey(key, contextName); - }, - event: function(node, eventName, key, context) { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.EventBinding, arguments, function(){}); - return true; - }, - addclass: function(node, className, key, context, parentRenderer, invert) { - new Batman.DOM.AddClassBinding(node, className, key, context, parentRenderer, false, invert); - return true; - }, - removeclass: function(node, className, key, context, parentRenderer) { - return Batman.DOM.attrReaders.addclass(node, className, key, context, parentRenderer, true); - }, - foreach: function(node, iteratorName, key, context, parentRenderer) { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.IteratorBinding, arguments, function(){}); - return false; - }, - formfor: function(node, localName, key, context) { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.FormBinding, arguments, function(){}); - return context.descendWithKey(key, localName); - } - }; - -}).call(this); - -(function() { - var BatmanObject, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - BatmanObject = (function(_super) { - var counter, getAccessorObject, promiseWrapper, wrapSingleAccessor; - - __extends(BatmanObject, _super); - - Batman.initializeObject(BatmanObject); - - Batman.initializeObject(BatmanObject.prototype); - - BatmanObject.classMixin = function() { - return Batman.mixin.apply(Batman, [this].concat(__slice.call(arguments))); - }; - - BatmanObject.mixin = function() { - return this.classMixin.apply(this.prototype, arguments); - }; - - BatmanObject.prototype.mixin = BatmanObject.classMixin; - - counter = 0; - - BatmanObject.prototype._batmanID = function() { - var c; - this._batmanID = function() { - return c; - }; - return c = counter++; - }; - - BatmanObject.prototype.hashKey = function() { - var key; - if (typeof this.isEqual === 'function') { - return; - } - this.hashKey = function() { - return key; - }; - return key = ""; - }; - - BatmanObject.prototype.toJSON = function() { - var key, obj, value; - obj = {}; - for (key in this) { - if (!__hasProp.call(this, key)) continue; - value = this[key]; - if (key !== "_batman" && key !== "hashKey" && key !== "_batmanID") { - obj[key] = (value != null ? value.toJSON : void 0) ? value.toJSON() : value; - } - } - return obj; - }; - - getAccessorObject = function(base, accessor) { - var deprecated, _i, _len, _ref; - if (typeof accessor === 'function') { - accessor = { - get: accessor - }; - } - _ref = ['cachable', 'cacheable']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - deprecated = _ref[_i]; - if (deprecated in accessor) { - Batman.developer.warn("Property accessor option \"" + deprecated + "\" is deprecated. Use \"cache\" instead."); - if (!('cache' in accessor)) { - accessor.cache = accessor[deprecated]; - } - } - } - return accessor; - }; - - promiseWrapper = function(fetcher) { - return function(core) { - return { - get: function(key) { - var deliver, returned, val, - _this = this; - val = core.get.apply(this, arguments); - if (typeof val !== 'undefined') { - return val; - } - returned = false; - deliver = function(err, result) { - if (returned) { - _this.set(key, result); - } - return val = result; - }; - fetcher.call(this, deliver, key); - returned = true; - return val; - }, - cache: true - }; - }; - }; - - wrapSingleAccessor = function(core, wrapper) { - var k, v; - wrapper = (typeof wrapper === "function" ? wrapper(core) : void 0) || wrapper; - for (k in core) { - v = core[k]; - if (!(k in wrapper)) { - wrapper[k] = v; - } - } - return wrapper; - }; - - BatmanObject._defineAccessor = function() { - var accessor, key, keys, _base, _i, _j, _len, _ref, _results; - keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), accessor = arguments[_i++]; - if (!(accessor != null)) { - return Batman.Property.defaultAccessorForBase(this); - } else if (keys.length === 0 && ((_ref = Batman.typeOf(accessor)) !== 'Object' && _ref !== 'Function')) { - return Batman.Property.accessorForBaseAndKey(this, accessor); - } else if (typeof accessor.promise === 'function') { - return this._defineWrapAccessor.apply(this, __slice.call(keys).concat([promiseWrapper(accessor.promise)])); - } - Batman.initializeObject(this); - if (keys.length === 0) { - return this._batman.defaultAccessor = getAccessorObject(this, accessor); - } else { - (_base = this._batman).keyAccessors || (_base.keyAccessors = new Batman.SimpleHash); - _results = []; - for (_j = 0, _len = keys.length; _j < _len; _j++) { - key = keys[_j]; - _results.push(this._batman.keyAccessors.set(key, getAccessorObject(this, accessor))); - } - return _results; - } - }; - - BatmanObject.prototype._defineAccessor = BatmanObject._defineAccessor; - - BatmanObject._defineWrapAccessor = function() { - var key, keys, wrapper, _i, _j, _len, _results; - keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), wrapper = arguments[_i++]; - Batman.initializeObject(this); - if (keys.length === 0) { - return this._defineAccessor(wrapSingleAccessor(this._defineAccessor(), wrapper)); - } else { - _results = []; - for (_j = 0, _len = keys.length; _j < _len; _j++) { - key = keys[_j]; - _results.push(this._defineAccessor(key, wrapSingleAccessor(this._defineAccessor(key), wrapper))); - } - return _results; - } - }; - - BatmanObject.prototype._defineWrapAccessor = BatmanObject._defineWrapAccessor; - - BatmanObject.classAccessor = BatmanObject._defineAccessor; - - BatmanObject.accessor = function() { - var _ref; - return (_ref = this.prototype)._defineAccessor.apply(_ref, arguments); - }; - - BatmanObject.prototype.accessor = BatmanObject._defineAccessor; - - BatmanObject.wrapClassAccessor = BatmanObject._defineWrapAccessor; - - BatmanObject.wrapAccessor = function() { - var _ref; - return (_ref = this.prototype)._defineWrapAccessor.apply(_ref, arguments); - }; - - BatmanObject.prototype.wrapAccessor = BatmanObject._defineWrapAccessor; - - function BatmanObject() { - var mixins; - mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - this._batman = new Batman._Batman(this); - this.mixin.apply(this, mixins); - } - - BatmanObject.classMixin(Batman.EventEmitter, Batman.Observable); - - BatmanObject.mixin(Batman.EventEmitter, Batman.Observable); - - BatmanObject.observeAll = function() { - return this.prototype.observe.apply(this.prototype, arguments); - }; - - BatmanObject.singleton = function(singletonMethodName) { - if (singletonMethodName == null) { - singletonMethodName = "sharedInstance"; - } - return this.classAccessor(singletonMethodName, { - get: function() { - var _name; - return this[_name = "_" + singletonMethodName] || (this[_name] = new this); - } - }); - }; - - BatmanObject.accessor('_batmanID', function() { - return this._batmanID(); - }); - - return BatmanObject; - - })(Object); - - Batman.Object = BatmanObject; - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Renderer = (function(_super) { - var bindingRegexp, bindingSortOrder, bindingSortPositions, k, name, pos, _i, _j, _len, _len1, _ref; - - __extends(Renderer, _super); - - Renderer.prototype.deferEvery = 50; - - function Renderer(node, context, view) { - this.node = node; - this.context = context; - this.view = view; - this.resume = __bind(this.resume, this); - - this.start = __bind(this.start, this); - - Renderer.__super__.constructor.call(this); - if (!(this.context instanceof Batman.RenderContext)) { - Batman.developer.error("Must pass a RenderContext to a renderer for rendering"); - } - this.immediate = Batman.setImmediate(this.start); - } - - Renderer.prototype.start = function() { - this.startTime = new Date; - return this.parseNode(this.node); - }; - - Renderer.prototype.resume = function() { - this.startTime = new Date; - return this.parseNode(this.resumeNode); - }; - - Renderer.prototype.finish = function() { - this.startTime = null; - this.prevent('stopped'); - this.fire('parsed'); - return this.fire('rendered'); - }; - - Renderer.prototype.stop = function() { - Batman.clearImmediate(this.immediate); - return this.fire('stopped'); - }; - - _ref = ['parsed', 'rendered', 'stopped']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - Renderer.prototype.event(k).oneShot = true; - } - - bindingRegexp = /^data\-(.*)/; - - bindingSortOrder = ["view", "renderif", "foreach", "formfor", "context", "bind", "source", "target"]; - - bindingSortPositions = {}; - - for (pos = _j = 0, _len1 = bindingSortOrder.length; _j < _len1; pos = ++_j) { - name = bindingSortOrder[pos]; - bindingSortPositions[name] = pos; - } - - Renderer.prototype._sortBindings = function(a, b) { - var aindex, bindex; - aindex = bindingSortPositions[a[0]]; - bindex = bindingSortPositions[b[0]]; - if (aindex == null) { - aindex = bindingSortOrder.length; - } - if (bindex == null) { - bindex = bindingSortOrder.length; - } - if (aindex > bindex) { - return 1; - } else if (bindex > aindex) { - return -1; - } else if (a[0] > b[0]) { - return 1; - } else if (b[0] > a[0]) { - return -1; - } else { - return 0; - } - }; - - Renderer.prototype.parseNode = function(node) { - var argument, attribute, bindings, keypath, names, nextNode, oldContext, result, skipChildren, _base, _base1, _k, _l, _len2, _len3, _ref1, _ref2, _ref3, _ref4, - _this = this; - if (this.deferEvery && (new Date - this.startTime) > this.deferEvery) { - this.resumeNode = node; - this.timeout = Batman.setImmediate(this.resume); - return; - } - if (node.getAttribute && node.attributes) { - bindings = []; - _ref1 = node.attributes; - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - attribute = _ref1[_k]; - name = (_ref2 = attribute.nodeName.match(bindingRegexp)) != null ? _ref2[1] : void 0; - if (!name) { - continue; - } - bindings.push((names = name.split('-')).length > 1 ? [names[0], names.slice(1, names.length + 1 || 9e9).join('-'), attribute.value] : [name, void 0, attribute.value]); - } - _ref3 = bindings.sort(this._sortBindings); - for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { - _ref4 = _ref3[_l], name = _ref4[0], argument = _ref4[1], keypath = _ref4[2]; - result = argument ? typeof (_base = Batman.DOM.attrReaders)[name] === "function" ? _base[name](node, argument, keypath, this.context, this) : void 0 : typeof (_base1 = Batman.DOM.readers)[name] === "function" ? _base1[name](node, keypath, this.context, this) : void 0; - if (result === false) { - skipChildren = true; - break; - } else if (result instanceof Batman.RenderContext) { - oldContext = this.context; - this.context = result; - Batman.onParseExit(node, function() { - return _this.context = oldContext; - }); - } - } - } - if ((nextNode = this.nextNode(node, skipChildren))) { - return this.parseNode(nextNode); - } else { - return this.finish(); - } - }; - - Renderer.prototype.nextNode = function(node, skipChildren) { - var children, nextParent, parentSibling, sibling, _ref1, _ref2; - if (!skipChildren) { - children = node.childNodes; - if (children != null ? children.length : void 0) { - return children[0]; - } - } - sibling = node.nextSibling; - if ((_ref1 = Batman.onParseExit(node)) != null) { - _ref1.forEach(function(callback) { - return callback(); - }); - } - Batman.forgetParseExit(node); - if (this.node === node) { - return; - } - if (sibling) { - return sibling; - } - nextParent = node; - while (nextParent = nextParent.parentNode) { - parentSibling = nextParent.nextSibling; - if ((_ref2 = Batman.onParseExit(nextParent)) != null) { - _ref2.forEach(function(callback) { - return callback(); - }); - } - Batman.forgetParseExit(nextParent); - if (this.node === nextParent) { - return; - } - if (parentSibling) { - return parentSibling; - } - } - }; - - return Renderer; - - })(Batman.Object); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.AbstractBinding = (function(_super) { - var get_dot_rx, get_rx, keypath_rx; - - __extends(AbstractBinding, _super); - - keypath_rx = /(^|,)\s*(?:(true|false)|("[^"]*")|(\{[^\}]*\})|([a-zA-Z][\w\-\.]*[\?\!]?))\s*(?=$|,)/g; - - get_dot_rx = /(?:\]\.)(.+?)(?=[\[\.]|\s*\||$)/; - - get_rx = /(?!^\s*)\[(.*?)\]/g; - - AbstractBinding.accessor('filteredValue', { - get: function() { - var renderContext, result, self, unfilteredValue; - unfilteredValue = this.get('unfilteredValue'); - self = this; - renderContext = this.get('renderContext'); - if (this.filterFunctions.length > 0) { - Batman.developer.currentFilterStack = renderContext; - result = this.filterFunctions.reduce(function(value, fn, i) { - var args; - args = self.filterArguments[i].map(function(argument) { - if (argument._keypath) { - return self.renderContext.get(argument._keypath); - } else { - return argument; - } - }); - args.unshift(value); - while (args.length < (fn.length - 1)) { - args.push(void 0); - } - args.push(self); - return fn.apply(renderContext, args); - }, unfilteredValue); - Batman.developer.currentFilterStack = null; - return result; - } else { - return unfilteredValue; - } - }, - set: function(_, newValue) { - return this.set('unfilteredValue', newValue); - } - }); - - AbstractBinding.accessor('unfilteredValue', { - get: function() { - var k; - if (k = this.get('key')) { - return Batman.RenderContext.deProxy(Batman.getPath(this, ['keyContext', k])); - } else { - return this.get('value'); - } - }, - set: function(_, value) { - var k, keyContext, prop; - if (k = this.get('key')) { - keyContext = this.get('keyContext'); - if (keyContext && keyContext !== Batman.container) { - prop = Batman.Property.forBaseAndKey(keyContext, k); - return prop.setValue(value); - } - } else { - return this.set('value', value); - } - } - }); - - AbstractBinding.accessor('keyContext', function() { - return this.renderContext.contextForKey(this.key); - }); - - AbstractBinding.prototype.bindImmediately = true; - - AbstractBinding.prototype.shouldSet = true; - - AbstractBinding.prototype.isInputBinding = false; - - AbstractBinding.prototype.escapeValue = true; - - function AbstractBinding(node, keyPath, renderContext, renderer, only) { - this.node = node; - this.keyPath = keyPath; - this.renderContext = renderContext; - this.renderer = renderer; - this.only = only != null ? only : false; - this._fireDataChange = __bind(this._fireDataChange, this); - - this._fireNodeChange = __bind(this._fireNodeChange, this); - - this.parseFilter(); - if (this.bindImmediately) { - this.bind(); - } - } - - AbstractBinding.prototype.isTwoWay = function() { - return (this.key != null) && this.filterFunctions.length === 0; - }; - - AbstractBinding.prototype.bind = function() { - var _ref, _ref1; - if ((this.node != null) && ((_ref = this.only) === false || _ref === 'nodeChange') && Batman.DOM.nodeIsEditable(this.node)) { - Batman.DOM.events.change(this.node, this._fireNodeChange); - if (this.only === 'nodeChange') { - this._fireNodeChange(); - } - } - if ((_ref1 = this.only) === false || _ref1 === 'dataChange') { - this.observeAndFire('filteredValue', this._fireDataChange); - } - if (this.node != null) { - return Batman.DOM.trackBinding(this, this.node); - } - }; - - AbstractBinding.prototype._fireNodeChange = function(event) { - var val; - this.shouldSet = false; - val = this.value || this.get('keyContext'); - if (typeof this.nodeChange === "function") { - this.nodeChange(this.node, val, event); - } - this.fire('nodeChange', this.node, val); - return this.shouldSet = true; - }; - - AbstractBinding.prototype._fireDataChange = function(value) { - if (this.shouldSet) { - if (typeof this.dataChange === "function") { - this.dataChange(value, this.node); - } - return this.fire('dataChange', value, this.node); - } - }; - - AbstractBinding.prototype.die = function() { - var _ref; - this.forget(); - if ((_ref = this._batman.properties) != null) { - _ref.forEach(function(key, property) { - return property.die(); - }); - } - this.fire('die'); - this.dead = true; - return true; - }; - - AbstractBinding.prototype.parseFilter = function() { - var args, filter, filterName, filterString, filters, key, keyPath, orig, split; - this.filterFunctions = []; - this.filterArguments = []; - keyPath = this.keyPath; - while (get_dot_rx.test(keyPath)) { - keyPath = keyPath.replace(get_dot_rx, "]['$1']"); - } - filters = keyPath.replace(get_rx, " | get $1 ").replace(/'/g, '"').split(/(?!")\s+\|\s+(?!")/); - try { - key = this.parseSegment(orig = filters.shift())[0]; - } catch (e) { - Batman.developer.warn(e); - Batman.developer.error("Error! Couldn't parse keypath in \"" + orig + "\". Parsing error above."); - } - if (key && key._keypath) { - this.key = key._keypath; - } else { - this.value = key; - } - if (filters.length) { - while (filterString = filters.shift()) { - split = filterString.indexOf(' '); - if (split === -1) { - split = filterString.length; - } - filterName = filterString.substr(0, split); - args = filterString.substr(split); - if (!(filter = Batman.Filters[filterName])) { - return Batman.developer.error("Unrecognized filter '" + filterName + "' in key \"" + this.keyPath + "\"!"); - } - this.filterFunctions.push(filter); - try { - this.filterArguments.push(this.parseSegment(args)); - } catch (e) { - Batman.developer.error("Bad filter arguments \"" + args + "\"!"); - } - } - return true; - } - }; - - AbstractBinding.prototype.parseSegment = function(segment) { - segment = segment.replace(keypath_rx, function(match, start, bool, string, object, keypath, offset) { - var replacement; - if (start == null) { - start = ''; - } - replacement = keypath ? '{"_keypath": "' + keypath + '"}' : bool || string || object; - return start + replacement; - }); - return JSON.parse("[" + segment + "]"); - }; - - return AbstractBinding; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.ViewBinding = (function(_super) { - - __extends(ViewBinding, _super); - - function ViewBinding() { - ViewBinding.__super__.constructor.apply(this, arguments); - this.renderer.prevent('rendered'); - this.node.removeAttribute('data-view'); - } - - ViewBinding.prototype.dataChange = function(viewClassOrInstance) { - var _this = this; - if (viewClassOrInstance == null) { - return; - } - if (viewClassOrInstance.isView) { - this.view = viewClassOrInstance; - this.view.set('context', this.renderContext); - this.view.set('node', this.node); - } else { - this.view = new viewClassOrInstance({ - node: this.node, - context: this.renderContext, - parentView: this.renderer.view - }); - } - this.view.on('ready', function() { - return _this.renderer.allowAndFire('rendered'); - }); - return this.die(); - }; - - return ViewBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.ViewArgumentBinding = (function(_super) { - - __extends(ViewArgumentBinding, _super); - - function ViewArgumentBinding() { - return ViewArgumentBinding.__super__.constructor.apply(this, arguments); - } - - return ViewArgumentBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.ShowHideBinding = (function(_super) { - - __extends(ShowHideBinding, _super); - - function ShowHideBinding(node, className, key, context, parentRenderer, invert) { - var display; - this.invert = invert != null ? invert : false; - display = node.style.display; - if (!display || display === 'none') { - display = ''; - } - this.originalDisplay = display; - ShowHideBinding.__super__.constructor.apply(this, arguments); - } - - ShowHideBinding.prototype.dataChange = function(value) { - var hide, view, _ref; - view = Batman._data(this.node, 'view'); - if (!!value === !this.invert) { - if (view != null) { - view.fire('beforeAppear', this.node); - } - if ((_ref = Batman.data(this.node, 'show')) != null) { - _ref.call(this.node); - } - this.node.style.display = this.originalDisplay; - return view != null ? view.fire('appear', this.node) : void 0; - } else { - if (view != null) { - view.fire('beforeDisappear', this.node); - } - if (typeof (hide = Batman.data(this.node, 'hide')) === 'function') { - hide.call(this.node); - } else { - Batman.setStyleProperty(this.node, 'display', 'none', 'important'); - } - return view != null ? view.fire('disappear', this.node) : void 0; - } - }; - - return ShowHideBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.SelectBinding = (function(_super) { - - __extends(SelectBinding, _super); - - SelectBinding.prototype.isInputBinding = true; - - SelectBinding.prototype.firstBind = true; - - function SelectBinding() { - this.updateOptionBindings = __bind(this.updateOptionBindings, this); - - this.nodeChange = __bind(this.nodeChange, this); - - this.dataChange = __bind(this.dataChange, this); - - this.childBindingAdded = __bind(this.childBindingAdded, this); - this.selectedBindings = new Batman.SimpleSet; - SelectBinding.__super__.constructor.apply(this, arguments); - } - - SelectBinding.prototype.childBindingAdded = function(binding) { - var dataChangeHandler, - _this = this; - if (binding instanceof Batman.DOM.CheckedBinding) { - binding.on('dataChange', dataChangeHandler = function() { - return _this.nodeChange(); - }); - binding.on('die', function() { - binding.forget('dataChange', dataChangeHandler); - return _this.selectedBindings.remove(binding); - }); - this.selectedBindings.add(binding); - } else if (binding instanceof Batman.DOM.IteratorBinding) { - binding.on('nodeAdded', dataChangeHandler = function() { - return _this._fireDataChange(_this.get('filteredValue')); - }); - binding.on('nodeRemoved', dataChangeHandler); - binding.on('die', function() { - binding.forget('nodeAdded', dataChangeHandler); - return binding.forget('nodeRemoved', dataChangeHandler); - }); - } else { - return; - } - return this._fireDataChange(this.get('filteredValue')); - }; - - SelectBinding.prototype.dataChange = function(newValue) { - var child, matches, valueToChild, _i, _len, _name, _ref, - _this = this; - if (newValue != null ? newValue.forEach : void 0) { - valueToChild = {}; - _ref = this.node.children; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - child.selected = false; - matches = valueToChild[_name = child.value] || (valueToChild[_name] = []); - matches.push(child); - } - newValue.forEach(function(value) { - var children, node, _j, _len1, _results; - if (children = valueToChild[value]) { - _results = []; - for (_j = 0, _len1 = children.length; _j < _len1; _j++) { - node = children[_j]; - _results.push(node.selected = true); - } - return _results; - } - }); - } else { - if (typeof newValue === 'undefined' && this.firstBind) { - this.set('unfilteredValue', this.node.value); - } else { - Batman.DOM.valueForNode(this.node, newValue, this.escapeValue); - } - this.firstBind = false; - } - this.updateOptionBindings(); - }; - - SelectBinding.prototype.nodeChange = function() { - var c, selections; - if (this.isTwoWay()) { - selections = this.node.multiple ? (function() { - var _i, _len, _ref, _results; - _ref = this.node.children; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - c = _ref[_i]; - if (c.selected) { - _results.push(c.value); - } - } - return _results; - }).call(this) : this.node.value; - if (typeof selections === Array && selections.length === 1) { - selections = selections[0]; - } - this.set('unfilteredValue', selections); - this.updateOptionBindings(); - } - }; - - SelectBinding.prototype.updateOptionBindings = function() { - return this.selectedBindings.forEach(function(binding) { - return binding._fireNodeChange(); - }); - }; - - return SelectBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.RouteBinding = (function(_super) { - - __extends(RouteBinding, _super); - - function RouteBinding() { - return RouteBinding.__super__.constructor.apply(this, arguments); - } - - RouteBinding.prototype.onATag = false; - - RouteBinding.accessor('dispatcher', function() { - return this.renderContext.get('dispatcher') || Batman.App.get('current.dispatcher'); - }); - - RouteBinding.prototype.bind = function() { - var _this = this; - if (this.node.nodeName.toUpperCase() === 'A') { - this.onATag = true; - } - RouteBinding.__super__.bind.apply(this, arguments); - return Batman.DOM.events.click(this.node, function(node, event) { - var params; - if (event.__batmanActionTaken) { - return; - } - event.__batmanActionTaken = true; - params = _this.pathFromValue(_this.get('filteredValue')); - if (params != null) { - return Batman.redirect(params); - } - }); - }; - - RouteBinding.prototype.dataChange = function(value) { - var path; - if (value != null) { - path = this.pathFromValue(value); - } - if (this.onATag) { - if ((path != null) && (Batman.navigator != null)) { - path = Batman.navigator.linkTo(path); - } else { - path = "#"; - } - return this.node.href = path; - } - }; - - RouteBinding.prototype.pathFromValue = function(value) { - var _ref; - if (value != null) { - if (value.isNamedRouteQuery) { - return value.get('path'); - } else { - return (_ref = this.get('dispatcher')) != null ? _ref.pathFromParams(value) : void 0; - } - } - }; - - return RouteBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.RadioBinding = (function(_super) { - - __extends(RadioBinding, _super); - - function RadioBinding() { - return RadioBinding.__super__.constructor.apply(this, arguments); - } - - RadioBinding.accessor('parsedNodeValue', function() { - return Batman.DOM.attrReaders._parseAttribute(this.node.value); - }); - - RadioBinding.prototype.firstBind = true; - - RadioBinding.prototype.dataChange = function(value) { - var boundValue; - boundValue = this.get('filteredValue'); - if (boundValue != null) { - this.node.checked = boundValue === Batman.DOM.attrReaders._parseAttribute(this.node.value); - } else { - if (this.firstBind && this.node.checked) { - this.set('filteredValue', this.get('parsedNodeValue')); - } - } - return this.firstBind = false; - }; - - RadioBinding.prototype.nodeChange = function(node) { - if (this.isTwoWay()) { - return this.set('filteredValue', this.get('parsedNodeValue')); - } - }; - - return RadioBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.MixinBinding = (function(_super) { - - __extends(MixinBinding, _super); - - function MixinBinding() { - return MixinBinding.__super__.constructor.apply(this, arguments); - } - - MixinBinding.prototype.dataChange = function(value) { - if (value != null) { - return Batman.mixin(this.node, value); - } - }; - - return MixinBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.FileBinding = (function(_super) { - - __extends(FileBinding, _super); - - function FileBinding() { - return FileBinding.__super__.constructor.apply(this, arguments); - } - - FileBinding.prototype.isInputBinding = true; - - FileBinding.prototype.nodeChange = function(node, subContext) { - if (!this.isTwoWay()) { - return; - } - if (node.hasAttribute('multiple')) { - return this.set('filteredValue', Array.prototype.slice.call(node.files)); - } else { - return this.set('filteredValue', node.files[0]); - } - }; - - return FileBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.DeferredRenderingBinding = (function(_super) { - - __extends(DeferredRenderingBinding, _super); - - DeferredRenderingBinding.prototype.rendered = false; - - function DeferredRenderingBinding() { - DeferredRenderingBinding.__super__.constructor.apply(this, arguments); - this.node.removeAttribute("data-renderif"); - } - - DeferredRenderingBinding.prototype.nodeChange = function() {}; - - DeferredRenderingBinding.prototype.dataChange = function(value) { - if (value && !this.rendered) { - return this.render(); - } - }; - - DeferredRenderingBinding.prototype.render = function() { - new Batman.Renderer(this.node, this.renderContext, this.renderer.view); - return this.rendered = true; - }; - - return DeferredRenderingBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.Binding = (function(_super) { - - __extends(Binding, _super); - - function Binding(node) { - var _ref; - this.isInputBinding = (_ref = node.nodeName.toLowerCase()) === 'input' || _ref === 'textarea'; - Binding.__super__.constructor.apply(this, arguments); - } - - Binding.prototype.nodeChange = function(node, context) { - if (this.isTwoWay()) { - return this.set('filteredValue', this.node.value); - } - }; - - Binding.prototype.dataChange = function(value, node) { - return Batman.DOM.valueForNode(this.node, value, this.escapeValue); - }; - - return Binding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.DOM.AbstractAttributeBinding = (function(_super) { - - __extends(AbstractAttributeBinding, _super); - - function AbstractAttributeBinding() { - var args, attributeName, node; - node = arguments[0], attributeName = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - this.attributeName = attributeName; - AbstractAttributeBinding.__super__.constructor.apply(this, [node].concat(__slice.call(args))); - } - - return AbstractAttributeBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.FormBinding = (function(_super) { - - __extends(FormBinding, _super); - - FormBinding.current = null; - - FormBinding.prototype.errorClass = 'error'; - - FormBinding.prototype.defaultErrorsListSelector = 'div.errors'; - - FormBinding.accessor('errorsListSelector', function() { - return this.get('node').getAttribute('data-errors-list') || this.defaultErrorsListSelector; - }); - - function FormBinding(node, contextName, keyPath, renderContext, renderer, only) { - this.childBindingAdded = __bind(this.childBindingAdded, this); - FormBinding.__super__.constructor.apply(this, arguments); - this.contextName = contextName; - delete this.attributeName; - Batman.DOM.events.submit(this.get('node'), function(node, e) { - return Batman.preventDefault(e); - }); - this.setupErrorsList(); - } - - FormBinding.prototype.childBindingAdded = function(binding) { - var field, index, node; - if (binding.isInputBinding && Batman.isChildOf(this.get('node'), binding.get('node'))) { - if (~(index = binding.get('key').indexOf(this.contextName))) { - node = binding.get('node'); - field = binding.get('key').slice(index + this.contextName.length + 1); - return new Batman.DOM.AddClassBinding(node, this.errorClass, this.get('keyPath') + (" | get 'errors." + field + ".length'"), this.renderContext, this.renderer); - } - } - }; - - FormBinding.prototype.setupErrorsList = function() { - if (this.errorsListNode = Batman.DOM.querySelector(this.get('node'), this.get('errorsListSelector'))) { - Batman.setInnerHTML(this.errorsListNode, this.errorsListHTML()); - if (!this.errorsListNode.getAttribute('data-showif')) { - return this.errorsListNode.setAttribute('data-showif', "" + this.contextName + ".errors.length"); - } - } - }; - - FormBinding.prototype.errorsListHTML = function() { - return "
      \n
    • \n
    "; - }; - - return FormBinding; - - })(Batman.DOM.AbstractAttributeBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.EventBinding = (function(_super) { - - __extends(EventBinding, _super); - - EventBinding.prototype.bindImmediately = false; - - function EventBinding(node, eventName, key, context) { - var attacher, callback, confirmText, - _this = this; - EventBinding.__super__.constructor.apply(this, arguments); - confirmText = this.node.getAttribute('data-confirm'); - callback = function() { - var _ref; - if (confirmText && !confirm(confirmText)) { - return; - } - return (_ref = _this.get('filteredValue')) != null ? _ref.apply(_this.get('callbackContext'), arguments) : void 0; - }; - if (attacher = Batman.DOM.events[this.attributeName]) { - attacher(this.node, callback, context); - } else { - Batman.DOM.events.other(this.node, this.attributeName, callback, context); - } - this.bind(); - } - - EventBinding.accessor('callbackContext', function() { - var contextKeySegments; - contextKeySegments = this.key.split('.'); - contextKeySegments.pop(); - if (contextKeySegments.length > 0) { - return this.get('keyContext').get(contextKeySegments.join('.')); - } else { - return this.get('keyContext'); - } - }); - - EventBinding.wrapAccessor('unfilteredValue', function(core) { - return { - get: function() { - var functionKey, k, keyContext, keys; - if (k = this.get('key')) { - keys = k.split('.'); - if (keys.length > 1) { - functionKey = keys.pop(); - keyContext = Batman.getPath(this, ['keyContext'].concat(keys)); - if (keyContext != null) { - keyContext = Batman.RenderContext.deProxy(keyContext); - return keyContext[functionKey]; - } - } - } - return core.get.apply(this, arguments); - } - }; - }); - - return EventBinding; - - })(Batman.DOM.AbstractAttributeBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.NodeAttributeBinding = (function(_super) { - - __extends(NodeAttributeBinding, _super); - - function NodeAttributeBinding() { - return NodeAttributeBinding.__super__.constructor.apply(this, arguments); - } - - NodeAttributeBinding.prototype.dataChange = function(value) { - if (value == null) { - value = ""; - } - return this.node[this.attributeName] = value; - }; - - NodeAttributeBinding.prototype.nodeChange = function(node) { - if (this.isTwoWay()) { - return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node[this.attributeName])); - } - }; - - return NodeAttributeBinding; - - })(Batman.DOM.AbstractAttributeBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.CheckedBinding = (function(_super) { - - __extends(CheckedBinding, _super); - - function CheckedBinding() { - return CheckedBinding.__super__.constructor.apply(this, arguments); - } - - CheckedBinding.prototype.isInputBinding = true; - - CheckedBinding.prototype.dataChange = function(value) { - return this.node[this.attributeName] = !!value; - }; - - return CheckedBinding; - - })(Batman.DOM.NodeAttributeBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.AttributeBinding = (function(_super) { - - __extends(AttributeBinding, _super); - - function AttributeBinding() { - return AttributeBinding.__super__.constructor.apply(this, arguments); - } - - AttributeBinding.prototype.dataChange = function(value) { - return this.node.setAttribute(this.attributeName, value); - }; - - AttributeBinding.prototype.nodeChange = function(node) { - if (this.isTwoWay()) { - return this.set('filteredValue', Batman.DOM.attrReaders._parseAttribute(node.getAttribute(this.attributeName))); - } - }; - - return AttributeBinding; - - })(Batman.DOM.AbstractAttributeBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.AddClassBinding = (function(_super) { - - __extends(AddClassBinding, _super); - - function AddClassBinding(node, className, keyPath, renderContext, renderer, only, invert) { - var name, names; - this.invert = invert != null ? invert : false; - names = className.split('|'); - this.classes = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = names.length; _i < _len; _i++) { - name = names[_i]; - _results.push({ - name: name, - pattern: new RegExp("(?:^|\\s)" + name + "(?:$|\\s)", 'i') - }); - } - return _results; - })(); - AddClassBinding.__super__.constructor.apply(this, arguments); - delete this.attributeName; - } - - AddClassBinding.prototype.dataChange = function(value) { - var currentName, includesClassName, name, pattern, _i, _len, _ref, _ref1; - currentName = this.node.className; - _ref = this.classes; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - _ref1 = _ref[_i], name = _ref1.name, pattern = _ref1.pattern; - includesClassName = pattern.test(currentName); - if (!!value === !this.invert) { - if (!includesClassName) { - this.node.className = "" + currentName + " " + name; - } - } else { - if (includesClassName) { - this.node.className = currentName.replace(pattern, ' '); - } - } - } - return true; - }; - - return AddClassBinding; - - })(Batman.DOM.AbstractAttributeBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.AbstractCollectionBinding = (function(_super) { - - __extends(AbstractCollectionBinding, _super); - - function AbstractCollectionBinding() { - return AbstractCollectionBinding.__super__.constructor.apply(this, arguments); - } - - AbstractCollectionBinding.prototype.bindCollection = function(newCollection) { - var _ref; - if (newCollection instanceof Batman.Hash) { - newCollection = newCollection.meta; - } - if (newCollection === this.collection) { - return true; - } else { - this.unbindCollection(); - this.collection = newCollection; - if ((_ref = this.collection) != null ? _ref.isObservable : void 0) { - this.collection.observeAndFire('toArray', this.handleArrayChanged); - return true; - } - } - return false; - }; - - AbstractCollectionBinding.prototype.unbindCollection = function() { - var _ref; - if ((_ref = this.collection) != null ? _ref.isObservable : void 0) { - return this.collection.forget('toArray', this.handleArrayChanged); - } - }; - - AbstractCollectionBinding.prototype.handleArrayChanged = function() {}; - - AbstractCollectionBinding.prototype.die = function() { - this.unbindCollection(); - return AbstractCollectionBinding.__super__.die.apply(this, arguments); - }; - - return AbstractCollectionBinding; - - })(Batman.DOM.AbstractAttributeBinding); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.DOM.StyleBinding = (function(_super) { - - __extends(StyleBinding, _super); - - StyleBinding.SingleStyleBinding = (function(_super1) { - - __extends(SingleStyleBinding, _super1); - - SingleStyleBinding.prototype.isTwoWay = function() { - return false; - }; - - function SingleStyleBinding() { - var args, parent, _i; - args = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), parent = arguments[_i++]; - this.parent = parent; - SingleStyleBinding.__super__.constructor.apply(this, args); - } - - SingleStyleBinding.prototype.dataChange = function(value) { - return this.parent.setStyle(this.attributeName, value); - }; - - return SingleStyleBinding; - - })(Batman.DOM.AbstractAttributeBinding); - - function StyleBinding() { - this.setStyle = __bind(this.setStyle, this); - - this.handleArrayChanged = __bind(this.handleArrayChanged, this); - this.oldStyles = {}; - this.styleBindings = {}; - StyleBinding.__super__.constructor.apply(this, arguments); - } - - StyleBinding.prototype.dataChange = function(value) { - var colonSplitCSSValues, cssName, key, style, _i, _len, _ref, _ref1, _results; - if (!value) { - this.resetStyles(); - return; - } - this.unbindCollection(); - if (typeof value === 'string') { - this.resetStyles(); - _ref = value.split(';'); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - style = _ref[_i]; - _ref1 = style.split(":"), cssName = _ref1[0], colonSplitCSSValues = 2 <= _ref1.length ? __slice.call(_ref1, 1) : []; - this.setStyle(cssName, colonSplitCSSValues.join(":")); - } - return; - } - if (value instanceof Batman.Hash) { - return this.bindCollection(value); - } else { - if (value instanceof Batman.Object) { - value = value.toJSON(); - } - this.resetStyles(); - _results = []; - for (key in value) { - if (!__hasProp.call(value, key)) continue; - _results.push(this.bindSingleAttribute(key, "" + this.keyPath + "." + key)); - } - return _results; - } - }; - - StyleBinding.prototype.handleArrayChanged = function(array) { - var _this = this; - return this.collection.forEach(function(key, value) { - return _this.bindSingleAttribute(key, "" + _this.keyPath + "." + key); - }); - }; - - StyleBinding.prototype.bindSingleAttribute = function(attr, keyPath) { - return this.styleBindings[attr] = new this.constructor.SingleStyleBinding(this.node, attr, keyPath, this.renderContext, this.renderer, this.only, this); - }; - - StyleBinding.prototype.setStyle = function(key, value) { - key = Batman.helpers.camelize(key.trim(), true); - if (this.oldStyles[key] == null) { - this.oldStyles[key] = this.node.style[key] || ""; - } - if (value != null ? value.trim : void 0) { - value = value.trim(); - } - if (value == null) { - value = ""; - } - return this.node.style[key] = value; - }; - - StyleBinding.prototype.resetStyles = function() { - var cssName, cssValue, _ref, _results; - _ref = this.oldStyles; - _results = []; - for (cssName in _ref) { - if (!__hasProp.call(_ref, cssName)) continue; - cssValue = _ref[cssName]; - _results.push(this.setStyle(cssName, cssValue)); - } - return _results; - }; - - StyleBinding.prototype.resetBindings = function() { - var attribute, binding, _ref; - _ref = this.styleBindings; - for (attribute in _ref) { - binding = _ref[attribute]; - binding._fireDataChange(''); - binding.die(); - } - return this.styleBindings = {}; - }; - - StyleBinding.prototype.unbindCollection = function() { - this.resetBindings(); - return StyleBinding.__super__.unbindCollection.apply(this, arguments); - }; - - return StyleBinding; - - })(Batman.DOM.AbstractCollectionBinding); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.IteratorBinding = (function(_super) { - - __extends(IteratorBinding, _super); - - IteratorBinding.prototype.currentActionNumber = 0; - - IteratorBinding.prototype.queuedActionNumber = 0; - - IteratorBinding.prototype.bindImmediately = false; - - function IteratorBinding(sourceNode, iteratorName, key, context, parentRenderer) { - var previousSiblingNode, - _this = this; - this.iteratorName = iteratorName; - this.key = key; - this.context = context; - this.parentRenderer = parentRenderer; - this.handleArrayChanged = __bind(this.handleArrayChanged, this); - - this.nodeMap = new Batman.SimpleHash; - this.rendererMap = new Batman.SimpleHash; - this.fragment = document.createDocumentFragment(); - this.prototypeNode = sourceNode.cloneNode(true); - this.prototypeNode.removeAttribute("data-foreach-" + this.iteratorName); - previousSiblingNode = sourceNode.nextSibling; - this.startNode = document.createComment("start " + this.iteratorName + "-" + (this.get('_batmanID'))); - this.endNode = document.createComment("end " + this.iteratorName + "-" + (this.get('_batmanID'))); - this.endNode[Batman.expando] = sourceNode[Batman.expando]; - if (Batman.canDeleteExpando) { - delete sourceNode[Batman.expando]; - } - Batman.insertBefore(sourceNode.parentNode, this.startNode, previousSiblingNode); - Batman.insertBefore(sourceNode.parentNode, this.endNode, previousSiblingNode); - this.parentRenderer.prevent('rendered'); - Batman.DOM.onParseExit(sourceNode.parentNode, function() { - Batman.destroyNode(sourceNode); - _this.bind(); - return _this.parentRenderer.allowAndFire('rendered'); - }); - IteratorBinding.__super__.constructor.call(this, this.endNode, this.iteratorName, this.key, this.context, this.parentRenderer); - } - - IteratorBinding.prototype.parentNode = function() { - return this.endNode.parentNode; - }; - - IteratorBinding.prototype.die = function() { - this.dead = true; - return IteratorBinding.__super__.die.apply(this, arguments); - }; - - IteratorBinding.prototype.dataChange = function(collection) { - var items, _items; - if (collection != null) { - if (!this.bindCollection(collection)) { - items = (collection != null ? collection.forEach : void 0) ? (_items = [], collection.forEach(function(item) { - return _items.push(item); - }), _items) : Object.keys(collection); - return this.handleArrayChanged(items); - } - } else { - return this.handleArrayChanged([]); - } - }; - - IteratorBinding.prototype.handleArrayChanged = function(newItems) { - var existingNode, index, newItem, node, nodeAtIndex, parentNode, startIndex, unseenNodeMap, _i, _len, - _this = this; - parentNode = this.parentNode(); - startIndex = this._getStartNodeIndex() + 1; - unseenNodeMap = this.nodeMap.merge(); - for (index = _i = 0, _len = newItems.length; _i < _len; index = ++_i) { - newItem = newItems[index]; - nodeAtIndex = parentNode.childNodes[startIndex + index]; - if ((nodeAtIndex != null) && this._itemForNode(nodeAtIndex) === newItem) { - unseenNodeMap.unset(newItem); - continue; - } else { - node = (existingNode = this.nodeMap.get(newItem)) ? (unseenNodeMap.unset(newItem), existingNode) : this._newNodeForItem(newItem); - Batman.insertBefore(this.parentNode(), node, nodeAtIndex); - } - } - unseenNodeMap.forEach(function(item, node) { - return _this._removeItem(item); - }); - }; - - IteratorBinding.prototype._itemForNode = function(node) { - return Batman._data(node, "" + this.iteratorName + "Item"); - }; - - IteratorBinding.prototype._newNodeForItem = function(newItem) { - var newNode, renderer, - _this = this; - newNode = this.prototypeNode.cloneNode(true); - Batman._data(newNode, "" + this.iteratorName + "Item", newItem); - this.nodeMap.set(newItem, newNode); - this.parentRenderer.prevent('rendered'); - renderer = new Batman.Renderer(newNode, this.renderContext.descend(newItem, this.iteratorName), this.parentRenderer.view); - renderer.on('rendered', function() { - Batman.propagateBindingEvents(newNode); - _this.fire('nodeAdded', newNode, newItem); - return _this.parentRenderer.allowAndFire('rendered'); - }); - return newNode; - }; - - IteratorBinding.prototype._getStartNodeIndex = function() { - var index, node, _i, _len, _ref; - _ref = this.parentNode().childNodes; - for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { - node = _ref[index]; - if (node === this.startNode) { - return index; - } - } - return 0; - }; - - IteratorBinding.prototype._removeItem = function(item) { - var node; - node = this.nodeMap.unset(item); - Batman.destroyNode(node); - return this.fire('nodeRemoved', node, item); - }; - - return IteratorBinding; - - })(Batman.DOM.AbstractCollectionBinding); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.ClassBinding = (function(_super) { - - __extends(ClassBinding, _super); - - function ClassBinding() { - this.handleArrayChanged = __bind(this.handleArrayChanged, this); - return ClassBinding.__super__.constructor.apply(this, arguments); - } - - ClassBinding.prototype.dataChange = function(value) { - if (value != null) { - this.unbindCollection(); - if (typeof value === 'string') { - return this.node.className = value; - } else { - this.bindCollection(value); - return this.updateFromCollection(); - } - } - }; - - ClassBinding.prototype.updateFromCollection = function() { - var array, k, v; - if (this.collection) { - array = this.collection.map ? this.collection.map(function(x) { - return x; - }) : (function() { - var _ref, _results; - _ref = this.collection; - _results = []; - for (k in _ref) { - if (!__hasProp.call(_ref, k)) continue; - v = _ref[k]; - _results.push(k); - } - return _results; - }).call(this); - if (array.toArray != null) { - array = array.toArray(); - } - return this.node.className = array.join(' '); - } - }; - - ClassBinding.prototype.handleArrayChanged = function() { - return this.updateFromCollection(); - }; - - return ClassBinding; - - })(Batman.DOM.AbstractCollectionBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ValidationError = (function(_super) { - - __extends(ValidationError, _super); - - ValidationError.accessor('fullMessage', function() { - return Batman.t('errors.format', { - attribute: Batman.helpers.humanize(this.attribute), - message: this.message - }); - }); - - function ValidationError(attribute, message) { - ValidationError.__super__.constructor.call(this, { - attribute: attribute, - message: message - }); - } - - return ValidationError; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.StorageAdapter = (function(_super) { - - __extends(StorageAdapter, _super); - - StorageAdapter.StorageError = (function(_super1) { - - __extends(StorageError, _super1); - - StorageError.prototype.name = "StorageError"; - - function StorageError(message) { - StorageError.__super__.constructor.apply(this, arguments); - this.message = message; - } - - return StorageError; - - })(Error); - - StorageAdapter.RecordExistsError = (function(_super1) { - - __extends(RecordExistsError, _super1); - - RecordExistsError.prototype.name = 'RecordExistsError'; - - function RecordExistsError(message) { - RecordExistsError.__super__.constructor.call(this, message || "Can't create this record because it already exists in the store!"); - } - - return RecordExistsError; - - })(StorageAdapter.StorageError); - - StorageAdapter.NotFoundError = (function(_super1) { - - __extends(NotFoundError, _super1); - - NotFoundError.prototype.name = 'NotFoundError'; - - function NotFoundError(message) { - NotFoundError.__super__.constructor.call(this, message || "Record couldn't be found in storage!"); - } - - return NotFoundError; - - })(StorageAdapter.StorageError); - - function StorageAdapter(model) { - var constructor; - StorageAdapter.__super__.constructor.call(this, { - model: model - }); - constructor = this.constructor; - if (constructor.ModelMixin) { - Batman.extend(model, constructor.ModelMixin); - } - if (constructor.RecordMixin) { - Batman.extend(model.prototype, constructor.RecordMixin); - } - } - - StorageAdapter.prototype.isStorageAdapter = true; - - StorageAdapter.prototype.storageKey = function(record) { - var model; - model = (record != null ? record.constructor : void 0) || this.model; - return model.get('storageKey') || Batman.helpers.pluralize(Batman.helpers.underscore(model.get('resourceName'))); - }; - - StorageAdapter.prototype.getRecordFromData = function(attributes, constructor) { - var record; - if (constructor == null) { - constructor = this.model; - } - record = new constructor(); - record._withoutDirtyTracking(function() { - return this.fromJSON(attributes); - }); - return record; - }; - - StorageAdapter.skipIfError = function(f) { - return function(env, next) { - if (env.error != null) { - return next(); - } else { - return f.call(this, env, next); - } - }; - }; - - StorageAdapter.prototype.before = function() { - return this._addFilter.apply(this, ['before'].concat(__slice.call(arguments))); - }; - - StorageAdapter.prototype.after = function() { - return this._addFilter.apply(this, ['after'].concat(__slice.call(arguments))); - }; - - StorageAdapter.prototype._inheritFilters = function() { - var filtersByKey, filtersList, key, oldFilters, position, _results; - if (!this._batman.check(this) || !this._batman.filters) { - oldFilters = this._batman.getFirst('filters'); - this._batman.filters = { - before: {}, - after: {} - }; - if (oldFilters != null) { - _results = []; - for (position in oldFilters) { - filtersByKey = oldFilters[position]; - _results.push((function() { - var _results1; - _results1 = []; - for (key in filtersByKey) { - filtersList = filtersByKey[key]; - _results1.push(this._batman.filters[position][key] = filtersList.slice(0)); - } - return _results1; - }).call(this)); - } - return _results; - } - } - }; - - StorageAdapter.prototype._addFilter = function() { - var filter, key, keys, position, _base, _i, _j, _len; - position = arguments[0], keys = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), filter = arguments[_i++]; - this._inheritFilters(); - for (_j = 0, _len = keys.length; _j < _len; _j++) { - key = keys[_j]; - (_base = this._batman.filters[position])[key] || (_base[key] = []); - this._batman.filters[position][key].push(filter); - } - return true; - }; - - StorageAdapter.prototype.runFilter = function(position, action, env, callback) { - var actionFilters, allFilters, filters, next, - _this = this; - this._inheritFilters(); - allFilters = this._batman.filters[position].all || []; - actionFilters = this._batman.filters[position][action] || []; - env.action = action; - filters = position === 'before' ? actionFilters.concat(allFilters) : allFilters.concat(actionFilters); - next = function(newEnv) { - var nextFilter; - if (newEnv != null) { - env = newEnv; - } - if ((nextFilter = filters.shift()) != null) { - return nextFilter.call(_this, env, next); - } else { - return callback.call(_this, env); - } - }; - return next(); - }; - - StorageAdapter.prototype.runBeforeFilter = function() { - return this.runFilter.apply(this, ['before'].concat(__slice.call(arguments))); - }; - - StorageAdapter.prototype.runAfterFilter = function(action, env, callback) { - return this.runFilter('after', action, env, this.exportResult(callback)); - }; - - StorageAdapter.prototype.exportResult = function(callback) { - return function(env) { - return callback(env.error, env.result, env); - }; - }; - - StorageAdapter.prototype._jsonToAttributes = function(json) { - return JSON.parse(json); - }; - - StorageAdapter.prototype.perform = function(key, subject, options, callback) { - var env, next, - _this = this; - options || (options = {}); - env = { - options: options, - subject: subject - }; - next = function(newEnv) { - if (newEnv != null) { - env = newEnv; - } - return _this.runAfterFilter(key, env, callback); - }; - return this.runBeforeFilter(key, env, function(env) { - return this[key](env, next); - }); - }; - - return StorageAdapter; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - Batman.RestStorage = (function(_super) { - var key, _fn, _i, _len, _ref, - _this = this; - - __extends(RestStorage, _super); - - RestStorage.JSONContentType = 'application/json'; - - RestStorage.PostBodyContentType = 'application/x-www-form-urlencoded'; - - RestStorage.BaseMixin = { - request: function(action, options, callback) { - if (!callback) { - callback = options; - options = {}; - } - options.method || (options.method = 'GET'); - options.action = action; - return this._doStorageOperation(options.method.toLowerCase(), options, callback); - } - }; - - RestStorage.ModelMixin = Batman.extend({}, RestStorage.BaseMixin, { - urlNestsUnder: function() { - var key, keys, parents, _i, _len; - keys = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - parents = {}; - for (_i = 0, _len = keys.length; _i < _len; _i++) { - key = keys[_i]; - parents[key + '_id'] = Batman.helpers.pluralize(key); - } - this.url = function(options) { - var childSegment, parentID, plural; - childSegment = Batman.helpers.pluralize(this.get('resourceName').toLowerCase()); - for (key in parents) { - plural = parents[key]; - parentID = options.data[key]; - if (parentID) { - delete options.data[key]; - return "" + plural + "/" + parentID + "/" + childSegment; - } - } - return childSegment; - }; - return this.prototype.url = function() { - var childSegment, id, parentID, plural, url; - childSegment = Batman.helpers.pluralize(this.constructor.get('resourceName').toLowerCase()); - for (key in parents) { - plural = parents[key]; - parentID = this.get('dirtyKeys').get(key); - if (parentID === void 0) { - parentID = this.get(key); - } - if (parentID) { - url = "" + plural + "/" + parentID + "/" + childSegment; - break; - } - } - url || (url = childSegment); - if (id = this.get('id')) { - url += '/' + id; - } - return url; - }; - } - }); - - RestStorage.RecordMixin = Batman.extend({}, RestStorage.BaseMixin); - - RestStorage.prototype.defaultRequestOptions = { - type: 'json' - }; - - RestStorage.prototype._implicitActionNames = ['create', 'read', 'update', 'destroy', 'readAll']; - - RestStorage.prototype.serializeAsForm = true; - - function RestStorage() { - RestStorage.__super__.constructor.apply(this, arguments); - this.defaultRequestOptions = Batman.extend({}, this.defaultRequestOptions); - } - - RestStorage.prototype.recordJsonNamespace = function(record) { - return Batman.helpers.singularize(this.storageKey(record)); - }; - - RestStorage.prototype.collectionJsonNamespace = function(constructor) { - return Batman.helpers.pluralize(this.storageKey(constructor.prototype)); - }; - - RestStorage.prototype._execWithOptions = function(object, key, options) { - if (typeof object[key] === 'function') { - return object[key](options); - } else { - return object[key]; - } - }; - - RestStorage.prototype._defaultCollectionUrl = function(model) { - return "/" + (this.storageKey(model.prototype)); - }; - - RestStorage.prototype._addParams = function(url, options) { - var _ref; - if (options && options.action && !(_ref = options.action, __indexOf.call(this._implicitActionNames, _ref) >= 0)) { - url += '/' + options.action.toLowerCase(); - } - return url; - }; - - RestStorage.prototype.urlForRecord = function(record, env) { - var id, url; - if (record.url) { - url = this._execWithOptions(record, 'url', env.options); - } else { - url = record.constructor.url ? this._execWithOptions(record.constructor, 'url', env.options) : this._defaultCollectionUrl(record.constructor); - if (env.action !== 'create') { - if ((id = record.get('id')) != null) { - url = url + "/" + id; - } else { - throw new this.constructor.StorageError("Couldn't get/set record primary key on " + env.action + "!"); - } - } - } - url = this._addParams(url, env.options); - return this.urlPrefix(record, env) + url + this.urlSuffix(record, env); - }; - - RestStorage.prototype.urlForCollection = function(model, env) { - var url; - url = model.url ? this._execWithOptions(model, 'url', env.options) : this._defaultCollectionUrl(model, env.options); - url = this._addParams(url, env.options); - return this.urlPrefix(model, env) + url + this.urlSuffix(model, env); - }; - - RestStorage.prototype.urlPrefix = function(object, env) { - return this._execWithOptions(object, 'urlPrefix', env.options) || ''; - }; - - RestStorage.prototype.urlSuffix = function(object, env) { - return this._execWithOptions(object, 'urlSuffix', env.options) || ''; - }; - - RestStorage.prototype.request = function(env, next) { - var options; - options = Batman.extend(env.options, { - autosend: false, - success: function(data) { - return env.data = data; - }, - error: function(error) { - return env.error = error; - }, - loaded: function() { - env.response = env.request.get('response'); - return next(); - } - }); - env.request = new Batman.Request(options); - return env.request.send(); - }; - - RestStorage.prototype.perform = function(key, record, options, callback) { - options || (options = {}); - Batman.extend(options, this.defaultRequestOptions); - return RestStorage.__super__.perform.call(this, key, record, options, callback); - }; - - RestStorage.prototype.before('all', RestStorage.skipIfError(function(env, next) { - if (!env.options.url) { - try { - env.options.url = env.subject.prototype ? this.urlForCollection(env.subject, env) : this.urlForRecord(env.subject, env); - } catch (error) { - env.error = error; - } - } - return next(); - })); - - RestStorage.prototype.before('get', 'put', 'post', 'delete', RestStorage.skipIfError(function(env, next) { - env.options.method = env.action.toUpperCase(); - return next(); - })); - - RestStorage.prototype.before('create', 'update', RestStorage.skipIfError(function(env, next) { - var data, json, namespace; - json = env.subject.toJSON(); - if (namespace = this.recordJsonNamespace(env.subject)) { - data = {}; - data[namespace] = json; - } else { - data = json; - } - env.options.data = data; - return next(); - })); - - RestStorage.prototype.before('create', 'update', 'put', 'post', RestStorage.skipIfError(function(env, next) { - if (this.serializeAsForm) { - env.options.contentType = this.constructor.PostBodyContentType; - } else { - if (env.options.data != null) { - env.options.data = JSON.stringify(env.options.data); - env.options.contentType = this.constructor.JSONContentType; - } - } - return next(); - })); - - RestStorage.prototype.after('all', RestStorage.skipIfError(function(env, next) { - var json; - if (!(env.data != null)) { - return next(); - } - if (typeof env.data === 'string') { - if (env.data.length > 0) { - try { - json = this._jsonToAttributes(env.data); - } catch (error) { - env.error = error; - return next(); - } - } - } else if (typeof env.data === 'object') { - json = env.data; - } - if (json != null) { - env.json = json; - } - return next(); - })); - - RestStorage.prototype.extractFromNamespace = function(data, namespace) { - if (namespace && (data[namespace] != null)) { - return data[namespace]; - } else { - return data; - } - }; - - RestStorage.prototype.after('create', 'read', 'update', RestStorage.skipIfError(function(env, next) { - var json; - if (env.json != null) { - json = this.extractFromNamespace(env.json, this.recordJsonNamespace(env.subject)); - env.subject._withoutDirtyTracking(function() { - return this.fromJSON(json); - }); - } - env.result = env.subject; - return next(); - })); - - RestStorage.prototype.after('readAll', RestStorage.skipIfError(function(env, next) { - var jsonRecordAttributes, namespace; - namespace = this.collectionJsonNamespace(env.subject); - env.recordsAttributes = this.extractFromNamespace(env.json, namespace); - if (Batman.typeOf(env.recordsAttributes) !== 'Array') { - namespace = this.recordJsonNamespace(env.subject.prototype); - env.recordsAttributes = [this.extractFromNamespace(env.json, namespace)]; - } - env.result = env.records = (function() { - var _i, _len, _ref, _results; - _ref = env.recordsAttributes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - jsonRecordAttributes = _ref[_i]; - _results.push(this.getRecordFromData(jsonRecordAttributes, env.subject)); - } - return _results; - }).call(this); - return next(); - })); - - RestStorage.prototype.after('get', 'put', 'post', 'delete', RestStorage.skipIfError(function(env, next) { - var json, namespace; - if (env.json != null) { - json = env.json; - namespace = env.subject.prototype ? this.collectionJsonNamespace(env.subject) : this.recordJsonNamespace(env.subject); - env.result = namespace && (env.json[namespace] != null) ? env.json[namespace] : env.json; - } - return next(); - })); - - RestStorage.HTTPMethods = { - create: 'POST', - update: 'PUT', - read: 'GET', - readAll: 'GET', - destroy: 'DELETE' - }; - - _ref = ['create', 'read', 'update', 'destroy', 'readAll', 'get', 'post', 'put', 'delete']; - _fn = function(key) { - return RestStorage.prototype[key] = RestStorage.skipIfError(function(env, next) { - var _base; - (_base = env.options).method || (_base.method = this.constructor.HTTPMethods[key]); - return this.request(env, next); - }); - }; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - key = _ref[_i]; - _fn(key); - } - - return RestStorage; - - }).call(this, Batman.StorageAdapter); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.LocalStorage = (function(_super) { - - __extends(LocalStorage, _super); - - function LocalStorage() { - if (typeof window.localStorage === 'undefined') { - return null; - } - LocalStorage.__super__.constructor.apply(this, arguments); - this.storage = localStorage; - } - - LocalStorage.prototype.storageRegExpForRecord = function(record) { - return new RegExp("^" + (this.storageKey(record)) + "(\\d+)$"); - }; - - LocalStorage.prototype.nextIdForRecord = function(record) { - var nextId, re; - re = this.storageRegExpForRecord(record); - nextId = 1; - this._forAllStorageEntries(function(k, v) { - var matches; - if (matches = re.exec(k)) { - return nextId = Math.max(nextId, parseInt(matches[1], 10) + 1); - } - }); - return nextId; - }; - - LocalStorage.prototype._forAllStorageEntries = function(iterator) { - var i, key, _i, _ref; - for (i = _i = 0, _ref = this.storage.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) { - key = this.storage.key(i); - iterator.call(this, key, this.storage.getItem(key)); - } - return true; - }; - - LocalStorage.prototype._storageEntriesMatching = function(constructor, options) { - var re, records; - re = this.storageRegExpForRecord(constructor.prototype); - records = []; - this._forAllStorageEntries(function(storageKey, storageString) { - var data, keyMatches; - if (keyMatches = re.exec(storageKey)) { - data = this._jsonToAttributes(storageString); - data[constructor.primaryKey] = keyMatches[1]; - if (this._dataMatches(options, data)) { - return records.push(data); - } - } - }); - return records; - }; - - LocalStorage.prototype._dataMatches = function(conditions, data) { - var k, match, v; - match = true; - for (k in conditions) { - v = conditions[k]; - if (data[k] !== v) { - match = false; - break; - } - } - return match; - }; - - LocalStorage.prototype.before('read', 'create', 'update', 'destroy', LocalStorage.skipIfError(function(env, next) { - var _this = this; - if (env.action === 'create') { - env.id = env.subject.get('id') || env.subject._withoutDirtyTracking(function() { - return env.subject.set('id', _this.nextIdForRecord(env.subject)); - }); - } else { - env.id = env.subject.get('id'); - } - if (env.id == null) { - env.error = new this.constructor.StorageError("Couldn't get/set record primary key on " + env.action + "!"); - } else { - env.key = this.storageKey(env.subject) + env.id; - } - return next(); - })); - - LocalStorage.prototype.before('create', 'update', LocalStorage.skipIfError(function(env, next) { - env.recordAttributes = JSON.stringify(env.subject); - return next(); - })); - - LocalStorage.prototype.after('read', LocalStorage.skipIfError(function(env, next) { - if (typeof env.recordAttributes === 'string') { - try { - env.recordAttributes = this._jsonToAttributes(env.recordAttributes); - } catch (error) { - env.error = error; - return next(); - } - } - env.subject._withoutDirtyTracking(function() { - return this.fromJSON(env.recordAttributes); - }); - return next(); - })); - - LocalStorage.prototype.after('read', 'create', 'update', 'destroy', LocalStorage.skipIfError(function(env, next) { - env.result = env.subject; - return next(); - })); - - LocalStorage.prototype.after('readAll', LocalStorage.skipIfError(function(env, next) { - var recordAttributes; - env.result = env.records = (function() { - var _i, _len, _ref, _results; - _ref = env.recordsAttributes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - recordAttributes = _ref[_i]; - _results.push(this.getRecordFromData(recordAttributes, env.subject)); - } - return _results; - }).call(this); - return next(); - })); - - LocalStorage.prototype.read = LocalStorage.skipIfError(function(env, next) { - env.recordAttributes = this.storage.getItem(env.key); - if (!env.recordAttributes) { - env.error = new this.constructor.NotFoundError(); - } - return next(); - }); - - LocalStorage.prototype.create = LocalStorage.skipIfError(function(_arg, next) { - var key, recordAttributes; - key = _arg.key, recordAttributes = _arg.recordAttributes; - if (this.storage.getItem(key)) { - arguments[0].error = new this.constructor.RecordExistsError; - } else { - this.storage.setItem(key, recordAttributes); - } - return next(); - }); - - LocalStorage.prototype.update = LocalStorage.skipIfError(function(_arg, next) { - var key, recordAttributes; - key = _arg.key, recordAttributes = _arg.recordAttributes; - this.storage.setItem(key, recordAttributes); - return next(); - }); - - LocalStorage.prototype.destroy = LocalStorage.skipIfError(function(_arg, next) { - var key; - key = _arg.key; - this.storage.removeItem(key); - return next(); - }); - - LocalStorage.prototype.readAll = LocalStorage.skipIfError(function(env, next) { - try { - arguments[0].recordsAttributes = this._storageEntriesMatching(env.subject, env.options.data); - } catch (error) { - arguments[0].error = error; - } - return next(); - }); - - return LocalStorage; - - })(Batman.StorageAdapter); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.SessionStorage = (function(_super) { - - __extends(SessionStorage, _super); - - function SessionStorage() { - if (typeof window.sessionStorage === 'undefined') { - return null; - } - SessionStorage.__super__.constructor.apply(this, arguments); - this.storage = sessionStorage; - } - - return SessionStorage; - - })(Batman.LocalStorage); - -}).call(this); - -(function() { - - Batman.Encoders = new Batman.Object; - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.AssociationProxy = (function(_super) { - - __extends(AssociationProxy, _super); - - AssociationProxy.prototype.isProxy = true; - - function AssociationProxy(association, model) { - this.association = association; - this.model = model; - } - - AssociationProxy.prototype.loaded = false; - - AssociationProxy.prototype.toJSON = function() { - var target; - target = this.get('target'); - if (target != null) { - return this.get('target').toJSON(); - } - }; - - AssociationProxy.prototype.load = function(callback) { - var _this = this; - this.fetch(function(err, proxiedRecord) { - if (!err) { - _this.set('loaded', true); - _this.set('target', proxiedRecord); - } - return typeof callback === "function" ? callback(err, proxiedRecord) : void 0; - }); - return this.get('target'); - }; - - AssociationProxy.prototype.fetch = function(callback) { - var record; - if ((this.get('foreignValue') || this.get('primaryValue')) == null) { - return callback(void 0, void 0); - } - record = this.fetchFromLocal(); - if (record) { - return callback(void 0, record); - } else { - return this.fetchFromRemote(callback); - } - }; - - AssociationProxy.accessor('loaded', Batman.Property.defaultAccessor); - - AssociationProxy.accessor('target', { - get: function() { - return this.fetchFromLocal(); - }, - set: function(_, v) { - return v; - } - }); - - AssociationProxy.accessor({ - get: function(k) { - var _ref; - return (_ref = this.get('target')) != null ? _ref.get(k) : void 0; - }, - set: function(k, v) { - var _ref; - return (_ref = this.get('target')) != null ? _ref.set(k, v) : void 0; - } - }); - - return AssociationProxy; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.HasOneProxy = (function(_super) { - - __extends(HasOneProxy, _super); - - function HasOneProxy() { - return HasOneProxy.__super__.constructor.apply(this, arguments); - } - - HasOneProxy.accessor('primaryValue', function() { - return this.model.get(this.association.primaryKey); - }); - - HasOneProxy.prototype.fetchFromLocal = function() { - return this.association.setIndex().get(this.get('primaryValue')); - }; - - HasOneProxy.prototype.fetchFromRemote = function(callback) { - var loadOptions, - _this = this; - loadOptions = {}; - loadOptions[this.association.foreignKey] = this.get('primaryValue'); - return this.association.getRelatedModel().load(loadOptions, function(error, loadedRecords) { - if (error) { - throw error; - } - if (!loadedRecords || loadedRecords.length <= 0) { - return callback(new Error("Couldn't find related record!"), void 0); - } else { - return callback(void 0, loadedRecords[0]); - } - }); - }; - - return HasOneProxy; - - })(Batman.AssociationProxy); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.BelongsToProxy = (function(_super) { - - __extends(BelongsToProxy, _super); - - function BelongsToProxy() { - return BelongsToProxy.__super__.constructor.apply(this, arguments); - } - - BelongsToProxy.accessor('foreignValue', function() { - return this.model.get(this.association.foreignKey); - }); - - BelongsToProxy.prototype.fetchFromLocal = function() { - return this.association.setIndex().get(this.get('foreignValue')); - }; - - BelongsToProxy.prototype.fetchFromRemote = function(callback) { - var _this = this; - return this.association.getRelatedModel().find(this.get('foreignValue'), function(error, loadedRecord) { - if (error) { - throw error; - } - return callback(void 0, loadedRecord); - }); - }; - - return BelongsToProxy; - - })(Batman.AssociationProxy); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PolymorphicBelongsToProxy = (function(_super) { - - __extends(PolymorphicBelongsToProxy, _super); - - function PolymorphicBelongsToProxy() { - return PolymorphicBelongsToProxy.__super__.constructor.apply(this, arguments); - } - - PolymorphicBelongsToProxy.accessor('foreignTypeValue', function() { - return this.model.get(this.association.foreignTypeKey); - }); - - PolymorphicBelongsToProxy.prototype.fetchFromLocal = function() { - return this.association.setIndexForType(this.get('foreignTypeValue')).get(this.get('foreignValue')); - }; - - PolymorphicBelongsToProxy.prototype.fetchFromRemote = function(callback) { - var _this = this; - return this.association.getRelatedModelForType(this.get('foreignTypeValue')).find(this.get('foreignValue'), function(error, loadedRecord) { - if (error) { - throw error; - } - return callback(void 0, loadedRecord); - }); - }; - - return PolymorphicBelongsToProxy; - - })(Batman.BelongsToProxy); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.StateMachine = (function(_super) { - - __extends(StateMachine, _super); - - StateMachine.InvalidTransitionError = function(message) { - this.message = message != null ? message : ""; - }; - - StateMachine.InvalidTransitionError.prototype = new Error; - - StateMachine.transitions = function(table) { - var definePredicate, fromState, k, object, predicateKeys, toState, transitions, v, _fn, _ref, - _this = this; - for (k in table) { - v = table[k]; - if (!(v.from && v.to)) { - continue; - } - object = {}; - if (v.from.forEach) { - v.from.forEach(function(fromKey) { - return object[fromKey] = v.to; - }); - } else { - object[v.from] = v.to; - } - table[k] = object; - } - this.prototype.transitionTable = Batman.extend({}, this.prototype.transitionTable, table); - predicateKeys = []; - definePredicate = function(state) { - var key; - key = "is" + (Batman.helpers.capitalize(state)); - if (_this.prototype[key] != null) { - return; - } - predicateKeys.push(key); - return _this.prototype[key] = function() { - return this.get('state') === state; - }; - }; - _ref = this.prototype.transitionTable; - _fn = function(k) { - return _this.prototype[k] = function() { - return this.startTransition(k); - }; - }; - for (k in _ref) { - transitions = _ref[k]; - if (!(!this.prototype[k])) { - continue; - } - _fn(k); - for (fromState in transitions) { - toState = transitions[fromState]; - definePredicate(fromState); - definePredicate(toState); - } - } - if (predicateKeys.length) { - this.accessor.apply(this, __slice.call(predicateKeys).concat([function(key) { - return this[key](); - }])); - } - return this; - }; - - function StateMachine(startState) { - this.nextEvents = []; - this.set('_state', startState); - } - - StateMachine.accessor('state', function() { - return this.get('_state'); - }); - - StateMachine.prototype.isTransitioning = false; - - StateMachine.prototype.transitionTable = {}; - - StateMachine.prototype.onTransition = function(from, into, callback) { - return this.on("" + from + "->" + into, callback); - }; - - StateMachine.prototype.onEnter = function(into, callback) { - return this.on("enter " + into, callback); - }; - - StateMachine.prototype.onExit = function(from, callback) { - return this.on("exit " + from, callback); - }; - - StateMachine.prototype.startTransition = Batman.Property.wrapTrackingPrevention(function(event) { - var nextState, previousState; - if (this.isTransitioning) { - this.nextEvents.push(event); - return; - } - previousState = this.get('state'); - nextState = this.nextStateForEvent(event); - if (!nextState) { - return false; - } - this.isTransitioning = true; - this.fire("exit " + previousState); - this.set('_state', nextState); - this.fire("" + previousState + "->" + nextState); - this.fire("enter " + nextState); - this.fire(event); - this.isTransitioning = false; - if (this.nextEvents.length > 0) { - this.startTransition(this.nextEvents.shift()); - } - return true; - }); - - StateMachine.prototype.canStartTransition = function(event, fromState) { - if (fromState == null) { - fromState = this.get('state'); - } - return !!this.nextStateForEvent(event, fromState); - }; - - StateMachine.prototype.nextStateForEvent = function(event, fromState) { - var _ref; - if (fromState == null) { - fromState = this.get('state'); - } - return (_ref = this.transitionTable[event]) != null ? _ref[fromState] : void 0; - }; - - return StateMachine; - - })(Batman.Object); - - Batman.DelegatingStateMachine = (function(_super) { - - __extends(DelegatingStateMachine, _super); - - function DelegatingStateMachine(startState, base) { - this.base = base; - DelegatingStateMachine.__super__.constructor.call(this, startState); - } - - DelegatingStateMachine.prototype.fire = function() { - var result, _ref; - result = DelegatingStateMachine.__super__.fire.apply(this, arguments); - (_ref = this.base).fire.apply(_ref, arguments); - return result; - }; - - return DelegatingStateMachine; - - })(Batman.StateMachine); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.Model = (function(_super) { - var functionName, _i, _j, _len, _len1, _ref, _ref1; - - __extends(Model, _super); - - Model.primaryKey = 'id'; - - Model.storageKey = null; - - Model.persist = function(mechanism, options) { - Batman.initializeObject(this.prototype); - mechanism = mechanism.isStorageAdapter ? mechanism : new mechanism(this); - if (options) { - Batman.mixin(mechanism, options); - } - this.prototype._batman.storage = mechanism; - return mechanism; - }; - - Model.storageAdapter = function() { - Batman.initializeObject(this.prototype); - return this.prototype._batman.storage; - }; - - Model.encode = function() { - var encoder, encoderForKey, encoderOrLastKey, key, keys, _base, _i, _j, _len; - keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), encoderOrLastKey = arguments[_i++]; - Batman.initializeObject(this.prototype); - (_base = this.prototype._batman).encoders || (_base.encoders = new Batman.SimpleHash); - encoder = {}; - switch (Batman.typeOf(encoderOrLastKey)) { - case 'String': - keys.push(encoderOrLastKey); - break; - case 'Function': - encoder.encode = encoderOrLastKey; - break; - default: - encoder = encoderOrLastKey; - } - for (_j = 0, _len = keys.length; _j < _len; _j++) { - key = keys[_j]; - encoderForKey = Batman.extend({ - as: key - }, this.defaultEncoder, encoder); - this.prototype._batman.encoders.set(key, encoderForKey); - } - }; - - Model.defaultEncoder = { - encode: function(x) { - return x; - }, - decode: function(x) { - return x; - } - }; - - Model.observeAndFire('primaryKey', function(newPrimaryKey, oldPrimaryKey) { - this.encode(oldPrimaryKey, { - encode: false, - decode: false - }); - return this.encode(newPrimaryKey, { - encode: false, - decode: this.defaultEncoder.decode - }); - }); - - Model.validate = function() { - var keys, match, matches, options, optionsOrFunction, validator, validators, _base, _i, _j, _k, _len, _len1, _ref, _results; - keys = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), optionsOrFunction = arguments[_i++]; - Batman.initializeObject(this.prototype); - validators = (_base = this.prototype._batman).validators || (_base.validators = []); - if (typeof optionsOrFunction === 'function') { - return validators.push({ - keys: keys, - callback: optionsOrFunction - }); - } else { - options = optionsOrFunction; - _ref = Batman.Validators; - _results = []; - for (_j = 0, _len = _ref.length; _j < _len; _j++) { - validator = _ref[_j]; - if ((matches = validator.matches(options))) { - for (_k = 0, _len1 = matches.length; _k < _len1; _k++) { - match = matches[_k]; - delete options[match]; - } - _results.push(validators.push({ - keys: keys, - validator: new validator(matches) - })); - } else { - _results.push(void 0); - } - } - return _results; - } - }; - - Model.LifecycleStateMachine = (function(_super1) { - - __extends(LifecycleStateMachine, _super1); - - function LifecycleStateMachine() { - return LifecycleStateMachine.__super__.constructor.apply(this, arguments); - } - - LifecycleStateMachine.transitions({ - load: { - empty: 'loading', - loaded: 'loading', - loading: 'loading' - }, - loaded: { - loading: 'loaded' - }, - error: { - loading: 'error' - } - }); - - return LifecycleStateMachine; - - })(Batman.DelegatingStateMachine); - - Model.classAccessor('lifecycle', function() { - var _base; - this._batman.check(this); - return (_base = this._batman).lifecycle || (_base.lifecycle = new this.LifecycleStateMachine('empty', this)); - }); - - Model.classAccessor('resourceName', { - get: function() { - if (this.resourceName != null) { - return this.resourceName; - } else { - if (Batman.config.minificationErrors) { - Batman.developer.error("Please define " + (Batman.functionName(this)) + ".resourceName in order for your model to be minification safe."); - } - return Batman.helpers.underscore(Batman.functionName(this)); - } - } - }); - - Model.classAccessor('all', { - get: function() { - this._batman.check(this); - if (this.prototype.hasStorage() && !this._batman.allLoadTriggered) { - this.load(); - this._batman.allLoadTriggered = true; - } - return this.get('loaded'); - }, - set: function(k, v) { - return this.set('loaded', v); - } - }); - - Model.classAccessor('loaded', { - get: function() { - return this._loaded || (this._loaded = new Batman.Set); - }, - set: function(k, v) { - return this._loaded = v; - } - }); - - Model.classAccessor('first', function() { - return this.get('all').toArray()[0]; - }); - - Model.classAccessor('last', function() { - var x; - x = this.get('all').toArray(); - return x[x.length - 1]; - }); - - Model.clear = function() { - var result, _ref; - Batman.initializeObject(this); - result = this.get('loaded').clear(); - if ((_ref = this._batman.get('associations')) != null) { - _ref.reset(); - } - return result; - }; - - Model.find = function(id, callback) { - var record; - Batman.developer.assert(callback, "Must call find with a callback!"); - record = new this(); - record._withoutDirtyTracking(function() { - return this.set('id', id); - }); - record.load(callback); - return record; - }; - - Model.load = function(options, callback) { - var lifecycle, _ref, - _this = this; - if ((_ref = typeof options) === 'function' || _ref === 'undefined') { - callback = options; - options = {}; - } - lifecycle = this.get('lifecycle'); - if (lifecycle.load()) { - return this._doStorageOperation('readAll', { - data: options - }, function(err, records, env) { - var mappedRecords, record; - if (err != null) { - lifecycle.error(); - return typeof callback === "function" ? callback(err, []) : void 0; - } else { - mappedRecords = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = records.length; _i < _len; _i++) { - record = records[_i]; - _results.push(this._mapIdentity(record)); - } - return _results; - }).call(_this); - lifecycle.loaded(); - return typeof callback === "function" ? callback(err, mappedRecords, env) : void 0; - } - }); - } else { - return callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (lifecycle.get('state')))); - } - }; - - Model.create = function(attrs, callback) { - var obj, _ref; - if (!callback) { - _ref = [{}, attrs], attrs = _ref[0], callback = _ref[1]; - } - obj = new this(attrs); - obj.save(callback); - return obj; - }; - - Model.findOrCreate = function(attrs, callback) { - var foundRecord, record; - record = new this(attrs); - if (record.isNew()) { - record.save(callback); - } else { - foundRecord = this._mapIdentity(record); - callback(void 0, foundRecord); - } - return record; - }; - - Model._mapIdentity = function(record) { - var existing, id, _ref; - if (typeof (id = record.get('id')) === 'undefined' || id === '') { - return record; - } else { - existing = (_ref = this.get("loaded.indexedBy.id").get(id)) != null ? _ref.toArray()[0] : void 0; - if (existing) { - existing._withoutDirtyTracking(function() { - var _ref1; - return this.updateAttributes(((_ref1 = record.get('attributes')) != null ? _ref1.toObject() : void 0) || {}); - }); - return existing; - } else { - this.get('loaded').add(record); - return record; - } - } - }; - - Model._doStorageOperation = function(operation, options, callback) { - var adapter; - Batman.developer.assert(this.prototype.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); - adapter = this.prototype._batman.get('storage'); - return adapter.perform(operation, this, options, callback); - }; - - _ref = ['find', 'load', 'create']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - functionName = _ref[_i]; - Model[functionName] = Batman.Property.wrapTrackingPrevention(Model[functionName]); - } - - Model.InstanceLifecycleStateMachine = (function(_super1) { - - __extends(InstanceLifecycleStateMachine, _super1); - - function InstanceLifecycleStateMachine() { - return InstanceLifecycleStateMachine.__super__.constructor.apply(this, arguments); - } - - InstanceLifecycleStateMachine.transitions({ - load: { - from: ['dirty', 'clean'], - to: 'loading' - }, - create: { - from: ['dirty', 'clean'], - to: 'creating' - }, - save: { - from: ['dirty', 'clean'], - to: 'saving' - }, - destroy: { - from: ['dirty', 'clean'], - to: 'destroying' - }, - failedValidation: { - from: ['saving', 'creating'], - to: 'dirty' - }, - loaded: { - loading: 'clean' - }, - created: { - creating: 'clean' - }, - saved: { - saving: 'clean' - }, - destroyed: { - destroying: 'destroyed' - }, - set: { - from: ['dirty', 'clean'], - to: 'dirty' - }, - error: { - from: ['saving', 'creating', 'loading', 'destroying'], - to: 'error' - } - }); - - return InstanceLifecycleStateMachine; - - })(Batman.DelegatingStateMachine); - - function Model(idOrAttributes) { - if (idOrAttributes == null) { - idOrAttributes = {}; - } - this.destroy = __bind(this.destroy, this); - - this.save = __bind(this.save, this); - - this.load = __bind(this.load, this); - - Batman.developer.assert(this instanceof Batman.Object, "constructors must be called with new"); - if (Batman.typeOf(idOrAttributes) === 'Object') { - Model.__super__.constructor.call(this, idOrAttributes); - } else { - Model.__super__.constructor.call(this); - this.set('id', idOrAttributes); - } - } - - Model.accessor('lifecycle', function() { - return this.lifecycle || (this.lifecycle = new Batman.Model.InstanceLifecycleStateMachine('clean', this)); - }); - - Model.accessor('attributes', function() { - return this.attributes || (this.attributes = new Batman.Hash); - }); - - Model.accessor('dirtyKeys', function() { - return this.dirtyKeys || (this.dirtyKeys = new Batman.Hash); - }); - - Model.accessor('_dirtiedKeys', function() { - return this._dirtiedKeys || (this._dirtiedKeys = new Batman.SimpleSet); - }); - - Model.accessor('errors', function() { - return this.errors || (this.errors = new Batman.ErrorsSet); - }); - - Model.accessor('isNew', function() { - return this.isNew(); - }); - - Model.accessor(Model.defaultAccessor = { - get: function(k) { - return Batman.getPath(this, ['attributes', k]); - }, - set: function(k, v) { - if (this._willSet(k)) { - return this.get('attributes').set(k, v); - } else { - return this.get(k); - } - }, - unset: function(k) { - return this.get('attributes').unset(k); - } - }); - - Model.wrapAccessor('id', function(core) { - return { - get: function() { - var primaryKey; - primaryKey = this.constructor.primaryKey; - if (primaryKey === 'id') { - return core.get.apply(this, arguments); - } else { - return this.get(primaryKey); - } - }, - set: function(key, value) { - var parsedValue, primaryKey; - if ((typeof value === "string") && (value.match(/[^0-9]/) === null) && (("" + (parsedValue = parseInt(value, 10))) === value)) { - value = parsedValue; - } - primaryKey = this.constructor.primaryKey; - if (primaryKey === 'id') { - this._willSet(key); - return core.set.apply(this, arguments); - } else { - return this.set(primaryKey, value); - } - } - }; - }); - - Model.prototype.isNew = function() { - return typeof this.get('id') === 'undefined'; - }; - - Model.prototype.updateAttributes = function(attrs) { - this.mixin(attrs); - return this; - }; - - Model.prototype.toString = function() { - return "" + (this.constructor.get('resourceName')) + ": " + (this.get('id')); - }; - - Model.prototype.toParam = function() { - return this.get('id'); - }; - - Model.prototype.toJSON = function() { - var encoders, obj, - _this = this; - obj = {}; - encoders = this._batman.get('encoders'); - if (!(!encoders || encoders.isEmpty())) { - encoders.forEach(function(key, encoder) { - var encodedVal, val; - if (encoder.encode) { - val = _this.get(key); - if (typeof val !== 'undefined') { - encodedVal = encoder.encode(val, key, obj, _this); - if (typeof encodedVal !== 'undefined') { - return obj[encoder.as] = encodedVal; - } - } - } - }); - } - return obj; - }; - - Model.prototype.fromJSON = function(data) { - var encoders, key, obj, value, - _this = this; - obj = {}; - encoders = this._batman.get('encoders'); - if (!encoders || encoders.isEmpty() || !encoders.some(function(key, encoder) { - return encoder.decode != null; - })) { - for (key in data) { - value = data[key]; - obj[key] = value; - } - } else { - encoders.forEach(function(key, encoder) { - if (encoder.decode && typeof data[encoder.as] !== 'undefined') { - return obj[key] = encoder.decode(data[encoder.as], encoder.as, data, obj, _this); - } - }); - } - if (this.constructor.primaryKey !== 'id') { - obj.id = data[this.constructor.primaryKey]; - } - Batman.developer["do"](function() { - if ((!encoders) || encoders.length <= 1) { - return Batman.developer.warn("Warning: Model " + (Batman.functionName(_this.constructor)) + " has suspiciously few decoders!"); - } - }); - return this.mixin(obj); - }; - - Model.prototype.hasStorage = function() { - return this._batman.get('storage') != null; - }; - - Model.prototype.load = function(options, callback) { - var callbackQueue, hasOptions, _ref1, _ref2, - _this = this; - if (!callback) { - _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; - } - hasOptions = Object.keys(options).length !== 0; - if ((_ref2 = this.get('lifecycle.state')) === 'destroying' || _ref2 === 'destroyed') { - if (typeof callback === "function") { - callback(new Error("Can't load a destroyed record!")); - } - return; - } - if (this.get('lifecycle').load()) { - callbackQueue = []; - if (callback != null) { - callbackQueue.push(callback); - } - if (!hasOptions) { - this._currentLoad = callbackQueue; - } - return this._doStorageOperation('read', { - data: options - }, function(err, record, env) { - var _j, _len1; - if (!err) { - _this.get('lifecycle').loaded(); - record = _this.constructor._mapIdentity(record); - } else { - _this.get('lifecycle').error(); - } - if (!hasOptions) { - _this._currentLoad = null; - } - for (_j = 0, _len1 = callbackQueue.length; _j < _len1; _j++) { - callback = callbackQueue[_j]; - callback(err, record, env); - } - }); - } else { - if (this.get('lifecycle.state') === 'loading' && !hasOptions) { - if (callback != null) { - return this._currentLoad.push(callback); - } - } else { - return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't load while in state " + (this.get('lifecycle.state')))) : void 0; - } - } - }; - - Model.prototype.save = function(options, callback) { - var endState, isNew, startState, storageOperation, _ref1, _ref2, _ref3, - _this = this; - if (!callback) { - _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; - } - if ((_ref2 = this.get('lifecycle').get('state')) === 'destroying' || _ref2 === 'destroyed') { - if (typeof callback === "function") { - callback(new Error("Can't save a destroyed record!")); - } - return; - } - isNew = this.isNew(); - _ref3 = isNew ? ['create', 'create', 'created'] : ['save', 'update', 'saved'], startState = _ref3[0], storageOperation = _ref3[1], endState = _ref3[2]; - return this.validate(function(error, errors) { - var associations, creating; - if (error || errors.length) { - _this.get('lifecycle').failedValidation(); - if (typeof callback === "function") { - callback(error || errors, _this); - } - return; - } - creating = _this.isNew(); - if (_this.get('lifecycle').startTransition(startState)) { - associations = _this.constructor._batman.get('associations'); - _this._withoutDirtyTracking(function() { - var _ref4, - _this = this; - return associations != null ? (_ref4 = associations.getByType('belongsTo')) != null ? _ref4.forEach(function(association, label) { - return association.apply(_this); - }) : void 0 : void 0; - }); - return _this._doStorageOperation(storageOperation, { - data: options - }, function(err, record, env) { - if (!err) { - _this.get('dirtyKeys').clear(); - _this.get('_dirtiedKeys').clear(); - if (associations) { - record._withoutDirtyTracking(function() { - var _ref4, _ref5; - if ((_ref4 = associations.getByType('hasOne')) != null) { - _ref4.forEach(function(association, label) { - return association.apply(err, record); - }); - } - return (_ref5 = associations.getByType('hasMany')) != null ? _ref5.forEach(function(association, label) { - return association.apply(err, record); - }) : void 0; - }); - } - record = _this.constructor._mapIdentity(record); - _this.get('lifecycle').startTransition(endState); - } else { - if (err instanceof Batman.ErrorsSet) { - _this.get('lifecycle').failedValidation(); - } else { - _this.get('lifecycle').error(); - } - } - return typeof callback === "function" ? callback(err, record || _this, env) : void 0; - }); - } else { - return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't save while in state " + (_this.get('lifecycle.state')))) : void 0; - } - }); - }; - - Model.prototype.destroy = function(options, callback) { - var _ref1, - _this = this; - if (!callback) { - _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; - } - if (this.get('lifecycle').destroy()) { - return this._doStorageOperation('destroy', { - data: options - }, function(err, record, env) { - if (!err) { - _this.constructor.get('loaded').remove(_this); - _this.get('lifecycle').destroyed(); - } else { - _this.get('lifecycle').error(); - } - return typeof callback === "function" ? callback(err, record, env) : void 0; - }); - } else { - return typeof callback === "function" ? callback(new Batman.StateMachine.InvalidTransitionError("Can't destroy while in state " + (this.get('lifecycle.state')))) : void 0; - } - }; - - Model.prototype.validate = function(callback) { - var args, count, errors, finishedValidation, key, validator, validators, _j, _k, _len1, _len2, _ref1; - errors = this.get('errors'); - errors.clear(); - validators = this._batman.get('validators') || []; - if (!validators || validators.length === 0) { - if (typeof callback === "function") { - callback(void 0, errors); - } - return true; - } - count = validators.reduce((function(acc, validator) { - return acc + validator.keys.length; - }), 0); - finishedValidation = function() { - if (--count === 0) { - return typeof callback === "function" ? callback(void 0, errors) : void 0; - } - }; - for (_j = 0, _len1 = validators.length; _j < _len1; _j++) { - validator = validators[_j]; - _ref1 = validator.keys; - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - key = _ref1[_k]; - args = [errors, this, key, finishedValidation]; - try { - if (validator.validator) { - validator.validator.validateEach.apply(validator.validator, args); - } else { - validator.callback.apply(validator, args); - } - } catch (e) { - if (typeof callback === "function") { - callback(e, errors); - } - } - } - } - }; - - Model.prototype.associationProxy = function(association) { - var proxies, _base, _name; - Batman.initializeObject(this); - proxies = (_base = this._batman).associationProxies || (_base.associationProxies = {}); - proxies[_name = association.label] || (proxies[_name] = new association.proxyClass(association, this)); - return proxies[association.label]; - }; - - Model.prototype._willSet = function(key) { - if (this._pauseDirtyTracking) { - return true; - } - if (this.get('lifecycle').startTransition('set')) { - if (!this.get('_dirtiedKeys').has(key)) { - this.set("dirtyKeys." + key, this.get(key)); - this.get('_dirtiedKeys').add(key); - } - return true; - } else { - return false; - } - }; - - Model.prototype._doStorageOperation = function(operation, options, callback) { - var adapter, - _this = this; - Batman.developer.assert(this.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); - adapter = this._batman.get('storage'); - return adapter.perform(operation, this, options, function() { - return callback.apply(null, arguments); - }); - }; - - Model.prototype._withoutDirtyTracking = function(block) { - var result; - this._pauseDirtyTracking = true; - result = block.call(this); - this._pauseDirtyTracking = false; - return result; - }; - - _ref1 = ['load', 'save', 'validate', 'destroy']; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - functionName = _ref1[_j]; - Model.prototype[functionName] = Batman.Property.wrapTrackingPrevention(Model.prototype[functionName]); - } - - return Model; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - var k, _fn, _i, _len, _ref, - _this = this; - - _ref = Batman.AssociationCurator.availableAssociations; - _fn = function(k) { - return Batman.Model[k] = function(label, scope) { - var collection, _base; - Batman.initializeObject(this); - collection = (_base = this._batman).associations || (_base.associations = new Batman.AssociationCurator(this)); - return collection.add(new Batman["" + (Batman.helpers.capitalize(k)) + "Association"](this, label, scope)); - }; - }; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - _fn(k); - } - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ParamsReplacer = (function(_super) { - - __extends(ParamsReplacer, _super); - - function ParamsReplacer(navigator, params) { - this.navigator = navigator; - this.params = params; - } - - ParamsReplacer.prototype.redirect = function() { - return this.navigator.replace(this.toObject()); - }; - - ParamsReplacer.prototype.replace = function(params) { - this.params.replace(params); - return this.redirect(); - }; - - ParamsReplacer.prototype.update = function(params) { - this.params.update(params); - return this.redirect(); - }; - - ParamsReplacer.prototype.clear = function() { - this.params.clear(); - return this.redirect(); - }; - - ParamsReplacer.prototype.toObject = function() { - return this.params.toObject(); - }; - - ParamsReplacer.accessor({ - get: function(k) { - return this.params.get(k); - }, - set: function(k, v) { - var oldValue, result; - oldValue = this.params.get(k); - result = this.params.set(k, v); - if (oldValue !== v) { - this.redirect(); - } - return result; - }, - unset: function(k) { - var hadKey, result; - hadKey = this.params.hasKey(k); - result = this.params.unset(k); - if (hadKey) { - this.redirect(); - } - return result; - } - }); - - return ParamsReplacer; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ParamsPusher = (function(_super) { - - __extends(ParamsPusher, _super); - - function ParamsPusher() { - return ParamsPusher.__super__.constructor.apply(this, arguments); - } - - ParamsPusher.prototype.redirect = function() { - return this.navigator.push(this.toObject()); - }; - - return ParamsPusher; - - })(Batman.ParamsReplacer); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.NamedRouteQuery = (function(_super) { - - __extends(NamedRouteQuery, _super); - - NamedRouteQuery.prototype.isNamedRouteQuery = true; - - function NamedRouteQuery(routeMap, args) { - var key; - if (args == null) { - args = []; - } - NamedRouteQuery.__super__.constructor.call(this, { - routeMap: routeMap, - args: args - }); - for (key in this.get('routeMap').childrenByName) { - this[key] = this._queryAccess.bind(this, key); - } - } - - NamedRouteQuery.accessor('route', function() { - var collectionRoute, memberRoute, route, _i, _len, _ref, _ref1; - _ref = this.get('routeMap'), memberRoute = _ref.memberRoute, collectionRoute = _ref.collectionRoute; - _ref1 = [memberRoute, collectionRoute]; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - route = _ref1[_i]; - if (route != null) { - if (route.namedArguments.length === this.get('args').length) { - return route; - } - } - } - return collectionRoute || memberRoute; - }); - - NamedRouteQuery.accessor('path', function() { - return this.path(); - }); - - NamedRouteQuery.accessor('routeMap', 'args', 'cardinality', 'hashValue', Batman.Property.defaultAccessor); - - NamedRouteQuery.accessor({ - get: function(key) { - if (key == null) { - return; - } - if (typeof key === 'string') { - return this.nextQueryForName(key); - } else { - return this.nextQueryWithArgument(key); - } - }, - cache: false - }); - - NamedRouteQuery.accessor('withHash', function() { - var _this = this; - return new Batman.Accessible(function(hashValue) { - return _this.withHash(hashValue); - }); - }); - - NamedRouteQuery.prototype.withHash = function(hashValue) { - var clone; - clone = this.clone(); - clone.set('hashValue', hashValue); - return clone; - }; - - NamedRouteQuery.prototype.nextQueryForName = function(key) { - var map; - if (map = this.get('routeMap').childrenByName[key]) { - return new Batman.NamedRouteQuery(map, this.args); - } else { - return Batman.developer.error("Couldn't find a route for the name " + key + "!"); - } - }; - - NamedRouteQuery.prototype.nextQueryWithArgument = function(arg) { - var args; - args = this.args.slice(0); - args.push(arg); - return this.clone(args); - }; - - NamedRouteQuery.prototype.path = function() { - var argumentName, argumentValue, index, namedArguments, params, _i, _len; - params = {}; - namedArguments = this.get('route.namedArguments'); - for (index = _i = 0, _len = namedArguments.length; _i < _len; index = ++_i) { - argumentName = namedArguments[index]; - if ((argumentValue = this.get('args')[index]) != null) { - params[argumentName] = this._toParam(argumentValue); - } - } - if (this.get('hashValue') != null) { - params['#'] = this.get('hashValue'); - } - return this.get('route').pathFromParams(params); - }; - - NamedRouteQuery.prototype.toString = function() { - return this.path(); - }; - - NamedRouteQuery.prototype.clone = function(args) { - if (args == null) { - args = this.args; - } - return new Batman.NamedRouteQuery(this.routeMap, args); - }; - - NamedRouteQuery.prototype._toParam = function(arg) { - if (arg instanceof Batman.AssociationProxy) { - arg = arg.get('target'); - } - if ((arg != null ? arg.toParam : void 0) != null) { - return arg.toParam(); - } else { - return arg; - } - }; - - NamedRouteQuery.prototype._queryAccess = function(key, arg) { - var query; - query = this.nextQueryForName(key); - if (arg != null) { - query = query.nextQueryWithArgument(arg); - } - return query; - }; - - return NamedRouteQuery; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Dispatcher = (function(_super) { - var ControllerDirectory; - - __extends(Dispatcher, _super); - - Dispatcher.canInferRoute = function(argument) { - return argument instanceof Batman.Model || argument instanceof Batman.AssociationProxy || argument.prototype instanceof Batman.Model; - }; - - Dispatcher.paramsFromArgument = function(argument) { - var resourceNameFromModel; - resourceNameFromModel = function(model) { - return Batman.helpers.camelize(Batman.helpers.pluralize(model.get('resourceName')), true); - }; - if (!this.canInferRoute(argument)) { - return argument; - } - if (argument instanceof Batman.Model || argument instanceof Batman.AssociationProxy) { - if (argument.isProxy) { - argument = argument.get('target'); - } - if (argument != null) { - return { - controller: resourceNameFromModel(argument.constructor), - action: 'show', - id: argument.get('id') - }; - } else { - return {}; - } - } else if (argument.prototype instanceof Batman.Model) { - return { - controller: resourceNameFromModel(argument), - action: 'index' - }; - } else { - return argument; - } - }; - - ControllerDirectory = (function(_super1) { - - __extends(ControllerDirectory, _super1); - - function ControllerDirectory() { - return ControllerDirectory.__super__.constructor.apply(this, arguments); - } - - ControllerDirectory.accessor('__app', Batman.Property.defaultAccessor); - - ControllerDirectory.accessor(function(key) { - return this.get("__app." + (Batman.helpers.capitalize(key)) + "Controller.sharedController"); - }); - - return ControllerDirectory; - - })(Batman.Object); - - Dispatcher.accessor('controllers', function() { - return new ControllerDirectory({ - __app: this.get('app') - }); - }); - - function Dispatcher(app, routeMap) { - Dispatcher.__super__.constructor.call(this, { - app: app, - routeMap: routeMap - }); - } - - Dispatcher.prototype.routeForParams = function(params) { - params = this.constructor.paramsFromArgument(params); - return this.get('routeMap').routeForParams(params); - }; - - Dispatcher.prototype.pathFromParams = function(params) { - var _ref; - if (typeof params === 'string') { - return params; - } - params = this.constructor.paramsFromArgument(params); - return (_ref = this.routeForParams(params)) != null ? _ref.pathFromParams(params) : void 0; - }; - - Dispatcher.prototype.dispatch = function(params) { - var inferredParams, path, route, _ref; - inferredParams = this.constructor.paramsFromArgument(params); - route = this.routeForParams(inferredParams); - if (route) { - _ref = route.pathAndParamsFromArgument(inferredParams), path = _ref[0], params = _ref[1]; - this.set('app.currentRoute', route); - this.set('app.currentURL', path); - this.get('app.currentParams').replace(params || {}); - route.dispatch(params); - } else { - if (Batman.typeOf(params) === 'Object' && !this.constructor.canInferRoute(params)) { - return this.get('app.currentParams').replace(params); - } else { - this.get('app.currentParams').clear(); - } - if (params !== '/404') { - return Batman.redirect('/404'); - } - } - return path; - }; - - return Dispatcher; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Route = (function(_super) { - - __extends(Route, _super); - - Route.regexps = { - namedParam: /:([\w\d]+)/g, - splatParam: /\*([\w\d]+)/g, - queryParam: '(?:\\?.+)?', - namedOrSplat: /[:|\*]([\w\d]+)/g, - namePrefix: '[:|\*]', - escapeRegExp: /[-[\]{}+?.,\\^$|#\s]/g, - openOptParam: /\(/g, - closeOptParam: /\)/g - }; - - Route.prototype.optionKeys = ['member', 'collection']; - - Route.prototype.testKeys = ['controller', 'action']; - - Route.prototype.isRoute = true; - - function Route(templatePath, baseParams) { - var k, matches, namedArguments, pattern, properties, regexp, regexps, _i, _len, _ref; - regexps = this.constructor.regexps; - if (templatePath.indexOf('/') !== 0) { - templatePath = "/" + templatePath; - } - pattern = templatePath.replace(regexps.escapeRegExp, '\\$&'); - regexp = RegExp("^" + (pattern.replace(regexps.openOptParam, '(?:').replace(regexps.closeOptParam, ')?').replace(regexps.namedParam, '([^\/]+)').replace(regexps.splatParam, '(.*?)')) + regexps.queryParam + "$"); - namedArguments = ((function() { - var _results; - _results = []; - while (matches = regexps.namedOrSplat.exec(pattern)) { - _results.push(matches[1]); - } - return _results; - })()); - properties = { - templatePath: templatePath, - pattern: pattern, - regexp: regexp, - namedArguments: namedArguments, - baseParams: baseParams - }; - _ref = this.optionKeys; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - properties[k] = baseParams[k]; - delete baseParams[k]; - } - Route.__super__.constructor.call(this, properties); - } - - Route.prototype.paramsFromPath = function(pathAndQuery) { - var index, match, matches, name, namedArguments, params, uri, _i, _len; - uri = new Batman.URI(pathAndQuery); - namedArguments = this.get('namedArguments'); - params = Batman.extend({ - path: uri.path - }, this.get('baseParams')); - matches = this.get('regexp').exec(uri.path).slice(1); - for (index = _i = 0, _len = matches.length; _i < _len; index = ++_i) { - match = matches[index]; - name = namedArguments[index]; - params[name] = match; - } - return Batman.extend(params, uri.queryParams); - }; - - Route.prototype.pathFromParams = function(argumentParams) { - var hash, key, name, newPath, params, path, query, regexp, regexps, _i, _j, _len, _len1, _ref, _ref1; - params = Batman.extend({}, argumentParams); - path = this.get('templatePath'); - regexps = this.constructor.regexps; - _ref = this.get('namedArguments'); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - name = _ref[_i]; - regexp = RegExp("" + regexps.namePrefix + name); - newPath = path.replace(regexp, (params[name] != null ? params[name] : '')); - if (newPath !== path) { - delete params[name]; - path = newPath; - } - } - path = path.replace(regexps.openOptParam, '').replace(regexps.closeOptParam, '').replace(/([^\/])\/+$/, '$1'); - _ref1 = this.testKeys; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - key = _ref1[_j]; - delete params[key]; - } - if (params['#']) { - hash = params['#']; - delete params['#']; - } - query = Batman.URI.queryFromParams(params); - if (query) { - path += "?" + query; - } - if (hash) { - path += "#" + hash; - } - return path; - }; - - Route.prototype.test = function(pathOrParams) { - var key, path, value, _i, _len, _ref; - if (typeof pathOrParams === 'string') { - path = pathOrParams; - } else if (pathOrParams.path != null) { - path = pathOrParams.path; - } else { - path = this.pathFromParams(pathOrParams); - _ref = this.testKeys; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - key = _ref[_i]; - if ((value = this.get(key)) != null) { - if (pathOrParams[key] !== value) { - return false; - } - } - } - } - return this.get('regexp').test(path); - }; - - Route.prototype.pathAndParamsFromArgument = function(pathOrParams) { - var params, path; - if (typeof pathOrParams === 'string') { - params = this.paramsFromPath(pathOrParams); - path = pathOrParams; - } else { - params = pathOrParams; - path = this.pathFromParams(pathOrParams); - } - return [path, params]; - }; - - Route.prototype.dispatch = function(params) { - if (!this.test(params)) { - return false; - } - return this.get('callback')(params); - }; - - Route.prototype.callback = function() { - throw new Batman.DevelopmentError("Override callback in a Route subclass"); - }; - - return Route; - - })(Batman.Object); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ControllerActionRoute = (function(_super) { - - __extends(ControllerActionRoute, _super); - - ControllerActionRoute.prototype.optionKeys = ['member', 'collection', 'app', 'controller', 'action']; - - function ControllerActionRoute(templatePath, options) { - this.callback = __bind(this.callback, this); - - var action, controller, _ref; - if (options.signature) { - _ref = options.signature.split('#'), controller = _ref[0], action = _ref[1]; - action || (action = 'index'); - options.controller = controller; - options.action = action; - delete options.signature; - } - ControllerActionRoute.__super__.constructor.call(this, templatePath, options); - } - - ControllerActionRoute.prototype.callback = function(params) { - var controller; - controller = this.get("app.dispatcher.controllers." + (this.get('controller'))); - return controller.dispatch(this.get('action'), params); - }; - - return ControllerActionRoute; - - })(Batman.Route); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.CallbackActionRoute = (function(_super) { - - __extends(CallbackActionRoute, _super); - - function CallbackActionRoute() { - return CallbackActionRoute.__super__.constructor.apply(this, arguments); - } - - CallbackActionRoute.prototype.optionKeys = ['member', 'collection', 'callback', 'app']; - - CallbackActionRoute.prototype.controller = false; - - CallbackActionRoute.prototype.action = false; - - return CallbackActionRoute; - - })(Batman.Route); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.Hash = (function(_super) { - var k, _fn, _i, _j, _len, _len1, _ref, _ref1, - _this = this; - - __extends(Hash, _super); - - Hash.Metadata = (function(_super1) { - - __extends(Metadata, _super1); - - Batman.extend(Metadata.prototype, Batman.Enumerable); - - function Metadata(hash) { - this.hash = hash; - } - - Metadata.accessor('length', function() { - this.hash.registerAsMutableSource(); - return this.hash.length; - }); - - Metadata.accessor('isEmpty', 'keys', 'toArray', function(key) { - this.hash.registerAsMutableSource(); - return this.hash[key](); - }); - - Metadata.prototype.forEach = function() { - var _ref; - return (_ref = this.hash).forEach.apply(_ref, arguments); - }; - - return Metadata; - - })(Batman.Object); - - function Hash() { - this.meta = new this.constructor.Metadata(this); - Batman.SimpleHash.apply(this, arguments); - Hash.__super__.constructor.apply(this, arguments); - } - - Batman.extend(Hash.prototype, Batman.Enumerable); - - Hash.prototype.propertyClass = Batman.Property; - - Hash.defaultAccessor = { - get: Batman.SimpleHash.prototype.get, - set: Hash.mutation(function(key, value) { - var result; - result = Batman.SimpleHash.prototype.set.call(this, key, value); - this.fire('itemsWereAdded', key); - return result; - }), - unset: Hash.mutation(function(key) { - var result; - result = Batman.SimpleHash.prototype.unset.call(this, key); - if (result != null) { - this.fire('itemsWereRemoved', key); - } - return result; - }), - cache: false - }; - - Hash.accessor(Hash.defaultAccessor); - - Hash.prototype._preventMutationEvents = function(block) { - this.prevent('change'); - this.prevent('itemsWereAdded'); - this.prevent('itemsWereRemoved'); - try { - return block.call(this); - } finally { - this.allow('change'); - this.allow('itemsWereAdded'); - this.allow('itemsWereRemoved'); - } - }; - - Hash.prototype.clear = Hash.mutation(function() { - var keys, result; - keys = this.keys(); - this._preventMutationEvents(function() { - var _this = this; - return this.forEach(function(k) { - return _this.unset(k); - }); - }); - result = Batman.SimpleHash.prototype.clear.call(this); - this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(keys))); - return result; - }); - - Hash.prototype.update = Hash.mutation(function(object) { - var addedKeys; - addedKeys = []; - this._preventMutationEvents(function() { - var _this = this; - return Batman.forEach(object, function(k, v) { - if (!_this.hasKey(k)) { - addedKeys.push(k); - } - return _this.set(k, v); - }); - }); - if (addedKeys.length > 0) { - return this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedKeys))); - } - }); - - Hash.prototype.replace = Hash.mutation(function(object) { - var addedKeys, removedKeys; - addedKeys = []; - removedKeys = []; - this._preventMutationEvents(function() { - var _this = this; - this.forEach(function(k, _) { - if (!Batman.objectHasKey(object, k)) { - _this.unset(k); - return removedKeys.push(k); - } - }); - return Batman.forEach(object, function(k, v) { - if (!_this.hasKey(k)) { - addedKeys.push(k); - } - return _this.set(k, v); - }); - }); - if (addedKeys.length > 0) { - this.fire.apply(this, ['itemsWereAdded'].concat(__slice.call(addedKeys))); - } - if (removedKeys.length > 0) { - return this.fire.apply(this, ['itemsWereRemoved'].concat(__slice.call(removedKeys))); - } - }); - - _ref = ['equality', 'hashKeyFor', 'objectKey', 'prefixedKey', 'unprefixedKey']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - Hash.prototype[k] = Batman.SimpleHash.prototype[k]; - } - - _ref1 = ['hasKey', 'forEach', 'isEmpty', 'keys', 'toArray', 'merge', 'toJSON', 'toObject']; - _fn = function(k) { - return Hash.prototype[k] = function() { - this.registerAsMutableSource(); - return Batman.SimpleHash.prototype[k].apply(this, arguments); - }; - }; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - k = _ref1[_j]; - _fn(k); - } - - return Hash; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.RenderCache = (function(_super) { - - __extends(RenderCache, _super); - - RenderCache.prototype.maximumLength = 4; - - function RenderCache() { - RenderCache.__super__.constructor.apply(this, arguments); - this.keyQueue = []; - } - - RenderCache.prototype.viewForOptions = function(options) { - var _this = this; - if (options.cache === false || options.viewClass.prototype.cache === false) { - return this._newViewFromOptions(options); - } - return this.getOrSet(options, function() { - return _this._newViewFromOptions(Batman.extend({}, options)); - }); - }; - - RenderCache.prototype._newViewFromOptions = function(options) { - return new options.viewClass(options); - }; - - RenderCache.wrapAccessor(function(core) { - return { - cache: false, - get: function(key) { - var result; - result = core.get.call(this, key); - if (result) { - this._addOrBubbleKey(key); - } - return result; - }, - set: function(key, value) { - var result; - result = core.set.apply(this, arguments); - result.set('cached', true); - this._addOrBubbleKey(key); - this._evictExpiredKeys(); - return result; - }, - unset: function(key) { - var result; - result = core.unset.apply(this, arguments); - result.set('cached', false); - this._removeKeyFromQueue(key); - return result; - } - }; - }); - - RenderCache.prototype.equality = function(incomingOptions, storageOptions) { - var key; - if (Object.keys(incomingOptions).length !== Object.keys(storageOptions).length) { - return false; - } - for (key in incomingOptions) { - if (!(key === 'view')) { - if (incomingOptions[key] !== storageOptions[key]) { - return false; - } - } - } - return true; - }; - - RenderCache.prototype.reset = function() { - var key, _i, _len, _ref, _results; - _ref = this.keyQueue.slice(0); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - key = _ref[_i]; - _results.push(this.unset(key)); - } - return _results; - }; - - RenderCache.prototype._addOrBubbleKey = function(key) { - this._removeKeyFromQueue(key); - return this.keyQueue.unshift(key); - }; - - RenderCache.prototype._removeKeyFromQueue = function(key) { - var index, queuedKey, _i, _len, _ref; - _ref = this.keyQueue; - for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) { - queuedKey = _ref[index]; - if (this.equality(queuedKey, key)) { - this.keyQueue.splice(index, 1); - break; - } - } - return key; - }; - - RenderCache.prototype._evictExpiredKeys = function() { - var currentKeys, i, key, _i, _ref, _ref1; - if (this.length > this.maximumLength) { - currentKeys = this.keyQueue.slice(0); - for (i = _i = _ref = this.maximumLength, _ref1 = currentKeys.length; _ref <= _ref1 ? _i < _ref1 : _i > _ref1; i = _ref <= _ref1 ? ++_i : --_i) { - key = currentKeys[i]; - if (!this.get(key).isInDOM()) { - this.unset(key); - } - } - } - }; - - return RenderCache; - - })(Batman.Hash); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; - - Batman.Controller = (function(_super) { - var _optionsFromFilterArguments; - - __extends(Controller, _super); - - Controller.singleton('sharedController'); - - Controller.wrapAccessor('routingKey', function(core) { - return { - get: function() { - if (this.routingKey != null) { - return this.routingKey; - } else { - if (Batman.config.minificationErrors) { - Batman.developer.error("Please define `routingKey` on the prototype of " + (Batman.functionName(this.constructor)) + " in order for your controller to be minification safe."); - } - return Batman.functionName(this.constructor).replace(/Controller$/, ''); - } - } - }; - }); - - Controller.accessor('_renderContext', function() { - return Batman.RenderContext.root().descend(this); - }); - - _optionsFromFilterArguments = function(options, nameOrFunction) { - if (!nameOrFunction) { - nameOrFunction = options; - options = {}; - } else { - if (typeof options === 'string') { - options = { - only: [options] - }; - } else { - if (options.only && Batman.typeOf(options.only) !== 'Array') { - options.only = [options.only]; - } - if (options.except && Batman.typeOf(options.except) !== 'Array') { - options.except = [options.except]; - } - } - } - options.block = nameOrFunction; - return options; - }; - - Controller.beforeFilter = function() { - var filters, options, _base; - Batman.initializeObject(this); - options = _optionsFromFilterArguments.apply(null, arguments); - filters = (_base = this._batman).beforeFilters || (_base.beforeFilters = new Batman.SimpleHash); - return filters.set(options.block, options); - }; - - Controller.afterFilter = function() { - var filters, options, _base; - Batman.initializeObject(this); - options = _optionsFromFilterArguments.apply(null, arguments); - filters = (_base = this._batman).afterFilters || (_base.afterFilters = new Batman.SimpleHash); - return filters.set(options.block, options); - }; - - Controller.afterFilter(function(params) { - if (this.autoScrollToHash && (params['#'] != null)) { - return this.scrollToHash(params['#']); - } - }); - - function Controller() { - this.redirect = __bind(this.redirect, this); - Controller.__super__.constructor.apply(this, arguments); - this._resetActionFrames(); - } - - Controller.prototype.renderCache = new Batman.RenderCache; - - Controller.prototype.defaultRenderYield = 'main'; - - Controller.prototype.autoScrollToHash = true; - - Controller.prototype.dispatch = function(action, params) { - var redirectTo; - if (params == null) { - params = {}; - } - params.controller || (params.controller = this.get('routingKey')); - params.action || (params.action = action); - params.target || (params.target = this); - this._resetActionFrames(); - this.set('action', action); - this.set('params', params); - Batman.DOM.Yield.cycleAll(); - this.executeAction(action, params); - Batman.DOM.Yield.clearAllStale(); - redirectTo = this._afterFilterRedirect; - delete this._afterFilterRedirect; - if (redirectTo) { - return Batman.redirect(redirectTo); - } - }; - - Controller.prototype.executeAction = function(action, params) { - var frame, oldRedirect, parentFrame, result, _ref, _ref1, - _this = this; - if (params == null) { - params = this.get('params'); - } - Batman.developer.assert(this[action], "Error! Controller action " + (this.get('routingKey')) + "." + action + " couldn't be found!"); - parentFrame = this._actionFrames[this._actionFrames.length - 1]; - frame = new Batman.ControllerActionFrame({ - parentFrame: parentFrame, - action: action - }, function() { - var _ref; - _this._runFilters(action, params, 'afterFilters'); - _this._resetActionFrames(); - return (_ref = Batman.navigator) != null ? _ref.redirect = oldRedirect : void 0; - }); - this._actionFrames.push(frame); - frame.startOperation({ - internal: true - }); - oldRedirect = (_ref = Batman.navigator) != null ? _ref.redirect : void 0; - if ((_ref1 = Batman.navigator) != null) { - _ref1.redirect = this.redirect; - } - this._runFilters(action, params, 'beforeFilters'); - result = this[action](params); - if (!frame.operationOccurred) { - this.render(); - } - frame.finishOperation(); - return result; - }; - - Controller.prototype.redirect = function(url) { - var frame; - frame = this._actionFrames[this._actionFrames.length - 1]; - if (frame) { - if (frame.operationOccurred) { - Batman.developer.warn("Warning! Trying to redirect but an action has already been taken during " + (this.get('routingKey')) + "." + (frame.action || this.get('action'))); - } - frame.startAndFinishOperation(); - if (this._afterFilterRedirect != null) { - return Batman.developer.warn("Warning! Multiple actions trying to redirect!"); - } else { - return this._afterFilterRedirect = url; - } - } else { - if (Batman.typeOf(url) === 'Object') { - if (!url.controller) { - url.controller = this; - } - } - return Batman.redirect(url); - } - }; - - Controller.prototype.render = function(options) { - var action, frame, view, _ref, _ref1, - _this = this; - if (options == null) { - options = {}; - } - if (frame = (_ref = this._actionFrames) != null ? _ref[this._actionFrames.length - 1] : void 0) { - frame.startOperation(); - } - if (options === false) { - frame.finishOperation(); - return; - } - action = (frame != null ? frame.action : void 0) || this.get('action'); - if (options) { - options.into || (options.into = this.defaultRenderYield); - } - if (!options.view) { - options.viewClass || (options.viewClass = this._viewClassForAction(action)); - options.context || (options.context = this.get('_renderContext')); - options.source || (options.source = Batman.helpers.underscore(this.get('routingKey') + '/' + action)); - view = this.renderCache.viewForOptions(options); - } else { - view = options.view; - options.view = null; - } - if (view) { - if ((_ref1 = Batman.currentApp) != null) { - _ref1.prevent('ready'); - } - view.on('ready', function() { - var _ref2; - Batman.DOM.Yield.withName(options.into).replace(view.get('node')); - if ((_ref2 = Batman.currentApp) != null) { - _ref2.allowAndFire('ready'); - } - return frame != null ? frame.finishOperation() : void 0; - }); - } - return view; - }; - - Controller.prototype.scrollToHash = function(hash) { - if (hash == null) { - hash = this.get('params')['#']; - } - return Batman.DOM.scrollIntoView(hash); - }; - - Controller.prototype._resetActionFrames = function() { - return this._actionFrames = []; - }; - - Controller.prototype._viewClassForAction = function(action) { - var classPrefix, _ref; - classPrefix = this.get('routingKey').replace('/', '_'); - return ((_ref = Batman.currentApp) != null ? _ref[Batman.helpers.camelize("" + classPrefix + "_" + action + "_view")] : void 0) || Batman.View; - }; - - Controller.prototype._runFilters = function(action, params, filters) { - var _ref, - _this = this; - if (filters = (_ref = this.constructor._batman) != null ? _ref.get(filters) : void 0) { - return filters.forEach(function(_, options) { - var block; - if (options.only && __indexOf.call(options.only, action) < 0) { - return; - } - if (options.except && __indexOf.call(options.except, action) >= 0) { - return; - } - block = options.block; - if (typeof block === 'function') { - return block.call(_this, params); - } else { - return typeof _this[block] === "function" ? _this[block](params) : void 0; - } - }); - } - }; - - return Controller; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Set = (function(_super) { - var k, _fn, _i, _j, _len, _len1, _ref, _ref1, - _this = this; - - __extends(Set, _super); - - function Set() { - Batman.SimpleSet.apply(this, arguments); - } - - Batman.extend(Set.prototype, Batman.Enumerable); - - Set._applySetAccessors = function(klass) { - var accessor, accessors, key, _results; - accessors = { - first: function() { - return this.toArray()[0]; - }, - last: function() { - return this.toArray()[this.length - 1]; - }, - isEmpty: function() { - return this.isEmpty(); - }, - toArray: function() { - return this.toArray(); - }, - length: function() { - this.registerAsMutableSource(); - return this.length; - }, - indexedBy: function() { - var _this = this; - return new Batman.TerminalAccessible(function(key) { - return _this.indexedBy(key); - }); - }, - indexedByUnique: function() { - var _this = this; - return new Batman.TerminalAccessible(function(key) { - return _this.indexedByUnique(key); - }); - }, - sortedBy: function() { - var _this = this; - return new Batman.TerminalAccessible(function(key) { - return _this.sortedBy(key); - }); - }, - sortedByDescending: function() { - var _this = this; - return new Batman.TerminalAccessible(function(key) { - return _this.sortedBy(key, 'desc'); - }); - } - }; - _results = []; - for (key in accessors) { - accessor = accessors[key]; - _results.push(klass.accessor(key, accessor)); - } - return _results; - }; - - Set._applySetAccessors(Set); - - _ref = ['add', 'remove', 'clear', 'replace', 'indexedBy', 'indexedByUnique', 'sortedBy', 'equality', '_indexOfItem']; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - Set.prototype[k] = Batman.SimpleSet.prototype[k]; - } - - _ref1 = ['find', 'merge', 'forEach', 'toArray', 'isEmpty', 'has']; - _fn = function(k) { - return Set.prototype[k] = function() { - this.registerAsMutableSource(); - return Batman.SimpleSet.prototype[k].apply(this, arguments); - }; - }; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - k = _ref1[_j]; - _fn(k); - } - - Set.prototype.toJSON = Set.prototype.toArray; - - return Set; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ErrorsSet = (function(_super) { - - __extends(ErrorsSet, _super); - - function ErrorsSet() { - return ErrorsSet.__super__.constructor.apply(this, arguments); - } - - ErrorsSet.accessor(function(key) { - return this.indexedBy('attribute').get(key); - }); - - ErrorsSet.prototype.add = function(key, error) { - return ErrorsSet.__super__.add.call(this, new Batman.ValidationError(key, error)); - }; - - return ErrorsSet; - - })(Batman.Set); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.SetProxy = (function(_super) { - var k, _fn, _i, _len, _ref, - _this = this; - - __extends(SetProxy, _super); - - function SetProxy(base) { - var _this = this; - this.base = base; - SetProxy.__super__.constructor.call(this); - this.length = this.base.length; - this.base.on('itemsWereAdded', function() { - var items; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - _this.set('length', _this.base.length); - return _this.fire.apply(_this, ['itemsWereAdded'].concat(__slice.call(items))); - }); - this.base.on('itemsWereRemoved', function() { - var items; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - _this.set('length', _this.base.length); - return _this.fire.apply(_this, ['itemsWereRemoved'].concat(__slice.call(items))); - }); - } - - Batman.extend(SetProxy.prototype, Batman.Enumerable); - - SetProxy.prototype.filter = function(f) { - var r; - r = new Batman.Set(); - return this.reduce((function(r, e) { - if (f(e)) { - r.add(e); - } - return r; - }), r); - }; - - SetProxy.prototype.replace = function() { - var length, result; - length = this.property('length'); - length.isolate(); - result = this.base.replace.apply(this, arguments); - length.expose(); - return result; - }; - - _ref = ['add', 'remove', 'find', 'clear', 'has', 'merge', 'toArray', 'isEmpty', 'indexedBy', 'indexedByUnique', 'sortedBy']; - _fn = function(k) { - return SetProxy.prototype[k] = function() { - var _ref1; - return (_ref1 = this.base)[k].apply(_ref1, arguments); - }; - }; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - _fn(k); - } - - Batman.Set._applySetAccessors(SetProxy); - - SetProxy.accessor('length', { - get: function() { - this.registerAsMutableSource(); - return this.length; - }, - set: function(_, v) { - return this.length = v; - } - }); - - return SetProxy; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.BinarySetOperation = (function(_super) { - - __extends(BinarySetOperation, _super); - - function BinarySetOperation(left, right) { - this.left = left; - this.right = right; - this._setup = __bind(this._setup, this); - - BinarySetOperation.__super__.constructor.call(this); - this._setup(this.left, this.right); - this._setup(this.right, this.left); - } - - BinarySetOperation.prototype._setup = function(set, opposite) { - var _this = this; - set.on('itemsWereAdded', function() { - var items; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return _this._itemsWereAddedToSource.apply(_this, [set, opposite].concat(__slice.call(items))); - }); - set.on('itemsWereRemoved', function() { - var items; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return _this._itemsWereRemovedFromSource.apply(_this, [set, opposite].concat(__slice.call(items))); - }); - return this._itemsWereAddedToSource.apply(this, [set, opposite].concat(__slice.call(set.toArray()))); - }; - - BinarySetOperation.prototype.merge = function() { - var merged, others, set, _i, _len; - others = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - merged = new Batman.Set; - others.unshift(this); - for (_i = 0, _len = others.length; _i < _len; _i++) { - set = others[_i]; - set.forEach(function(v) { - return merged.add(v); - }); - } - return merged; - }; - - BinarySetOperation.prototype.filter = Batman.SetProxy.prototype.filter; - - return BinarySetOperation; - - })(Batman.Set); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.SetUnion = (function(_super) { - - __extends(SetUnion, _super); - - function SetUnion() { - return SetUnion.__super__.constructor.apply(this, arguments); - } - - SetUnion.prototype._itemsWereAddedToSource = function() { - var items, opposite, source; - source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - return this.add.apply(this, items); - }; - - SetUnion.prototype._itemsWereRemovedFromSource = function() { - var item, items, itemsToRemove, opposite, source; - source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - itemsToRemove = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (!opposite.has(item)) { - _results.push(item); - } - } - return _results; - })(); - return this.remove.apply(this, itemsToRemove); - }; - - return SetUnion; - - })(Batman.BinarySetOperation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.SetIntersection = (function(_super) { - - __extends(SetIntersection, _super); - - function SetIntersection() { - return SetIntersection.__super__.constructor.apply(this, arguments); - } - - SetIntersection.prototype._itemsWereAddedToSource = function() { - var item, items, itemsToAdd, opposite, source; - source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - itemsToAdd = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (opposite.has(item)) { - _results.push(item); - } - } - return _results; - })(); - return this.add.apply(this, itemsToAdd); - }; - - SetIntersection.prototype._itemsWereRemovedFromSource = function() { - var items, opposite, source; - source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - return this.remove.apply(this, items); - }; - - return SetIntersection; - - })(Batman.BinarySetOperation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.SetComplement = (function(_super) { - - __extends(SetComplement, _super); - - function SetComplement() { - return SetComplement.__super__.constructor.apply(this, arguments); - } - - SetComplement.prototype._itemsWereAddedToSource = function() { - var item, items, itemsToAdd, itemsToRemove, opposite, source; - source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - if (source === this.left) { - itemsToAdd = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (!opposite.has(item)) { - _results.push(item); - } - } - return _results; - })(); - return this.add.apply(this, itemsToAdd); - } else { - itemsToRemove = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (opposite.has(item)) { - _results.push(item); - } - } - return _results; - })(); - return this.remove.apply(this, itemsToRemove); - } - }; - - SetComplement.prototype._itemsWereRemovedFromSource = function() { - var item, items, itemsToAdd, opposite, source; - source = arguments[0], opposite = arguments[1], items = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - if (source === this.left) { - return this.remove.apply(this, items); - } else { - itemsToAdd = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (opposite.has(item)) { - _results.push(item); - } - } - return _results; - })(); - return this.add.apply(this, itemsToAdd); - } - }; - - SetComplement.prototype._addComplement = function(items, opposite) { - var item; - return this.add.apply(this, (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if (opposite.has(item)) { - _results.push(item); - } - } - return _results; - })()); - }; - - return SetComplement; - - })(Batman.BinarySetOperation); - -}).call(this); - -(function() { - - Batman.mixins = new Batman.Object; - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Accessible = (function(_super) { - - __extends(Accessible, _super); - - function Accessible() { - this.accessor.apply(this, arguments); - } - - return Accessible; - - })(Batman.Object); - - Batman.TerminalAccessible = (function(_super) { - - __extends(TerminalAccessible, _super); - - function TerminalAccessible() { - return TerminalAccessible.__super__.constructor.apply(this, arguments); - } - - TerminalAccessible.prototype.propertyClass = Batman.Property; - - return TerminalAccessible; - - })(Batman.Accessible); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.SetObserver = (function(_super) { - - __extends(SetObserver, _super); - - function SetObserver(base) { - var _this = this; - this.base = base; - this._itemObservers = new Batman.SimpleHash; - this._setObservers = new Batman.SimpleHash; - this._setObservers.set("itemsWereAdded", function() { - return _this.fire.apply(_this, ['itemsWereAdded'].concat(__slice.call(arguments))); - }); - this._setObservers.set("itemsWereRemoved", function() { - return _this.fire.apply(_this, ['itemsWereRemoved'].concat(__slice.call(arguments))); - }); - this.on('itemsWereAdded', this.startObservingItems.bind(this)); - this.on('itemsWereRemoved', this.stopObservingItems.bind(this)); - } - - SetObserver.prototype.observedItemKeys = []; - - SetObserver.prototype.observerForItemAndKey = function(item, key) {}; - - SetObserver.prototype._getOrSetObserverForItemAndKey = function(item, key) { - var _this = this; - return this._itemObservers.getOrSet(item, function() { - var observersByKey; - observersByKey = new Batman.SimpleHash; - return observersByKey.getOrSet(key, function() { - return _this.observerForItemAndKey(item, key); - }); - }); - }; - - SetObserver.prototype.startObserving = function() { - this._manageItemObservers("observe"); - return this._manageSetObservers("addHandler"); - }; - - SetObserver.prototype.stopObserving = function() { - this._manageItemObservers("forget"); - return this._manageSetObservers("removeHandler"); - }; - - SetObserver.prototype.startObservingItems = function() { - var item, items, _i, _len, _results; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - _results.push(this._manageObserversForItem(item, "observe")); - } - return _results; - }; - - SetObserver.prototype.stopObservingItems = function() { - var item, items, _i, _len, _results; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - _results.push(this._manageObserversForItem(item, "forget")); - } - return _results; - }; - - SetObserver.prototype._manageObserversForItem = function(item, method) { - var key, _i, _len, _ref; - if (!item.isObservable) { - return; - } - _ref = this.observedItemKeys; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - key = _ref[_i]; - item[method](key, this._getOrSetObserverForItemAndKey(item, key)); - } - if (method === "forget") { - return this._itemObservers.unset(item); - } - }; - - SetObserver.prototype._manageItemObservers = function(method) { - var _this = this; - return this.base.forEach(function(item) { - return _this._manageObserversForItem(item, method); - }); - }; - - SetObserver.prototype._manageSetObservers = function(method) { - var _this = this; - if (!this.base.isObservable) { - return; - } - return this._setObservers.forEach(function(key, observer) { - return _this.base.event(key)[method](observer); - }); - }; - - return SetObserver; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.SetSort = (function(_super) { - - __extends(SetSort, _super); - - function SetSort(base, key, order) { - var boundReIndex; - this.key = key; - if (order == null) { - order = "asc"; - } - SetSort.__super__.constructor.call(this, base); - this.descending = order.toLowerCase() === "desc"; - if (this.base.isObservable) { - this._setObserver = new Batman.SetObserver(this.base); - this._setObserver.observedItemKeys = [this.key]; - boundReIndex = this._reIndex.bind(this); - this._setObserver.observerForItemAndKey = function() { - return boundReIndex; - }; - this._setObserver.on('itemsWereAdded', boundReIndex); - this._setObserver.on('itemsWereRemoved', boundReIndex); - this.startObserving(); - } - this._reIndex(); - } - - SetSort.prototype.startObserving = function() { - var _ref; - return (_ref = this._setObserver) != null ? _ref.startObserving() : void 0; - }; - - SetSort.prototype.stopObserving = function() { - var _ref; - return (_ref = this._setObserver) != null ? _ref.stopObserving() : void 0; - }; - - SetSort.prototype.toArray = function() { - return this.get('_storage'); - }; - - SetSort.prototype.forEach = function(iterator, ctx) { - var e, i, _i, _len, _ref, _results; - _ref = this.get('_storage'); - _results = []; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - e = _ref[i]; - _results.push(iterator.call(ctx, e, i, this)); - } - return _results; - }; - - SetSort.prototype.compare = function(a, b) { - if (a === b) { - return 0; - } - if (a === void 0) { - return 1; - } - if (b === void 0) { - return -1; - } - if (a === null) { - return 1; - } - if (b === null) { - return -1; - } - if (a === false) { - return 1; - } - if (b === false) { - return -1; - } - if (a === true) { - return 1; - } - if (b === true) { - return -1; - } - if (a !== a) { - if (b !== b) { - return 0; - } else { - return 1; - } - } - if (b !== b) { - return -1; - } - if (a > b) { - return 1; - } - if (a < b) { - return -1; - } - return 0; - }; - - SetSort.prototype._reIndex = function() { - var newOrder, _ref, - _this = this; - newOrder = this.base.toArray().sort(function(a, b) { - var multiple, valueA, valueB; - valueA = Batman.get(a, _this.key); - if (typeof valueA === 'function') { - valueA = valueA.call(a); - } - if (valueA != null) { - valueA = valueA.valueOf(); - } - valueB = Batman.get(b, _this.key); - if (typeof valueB === 'function') { - valueB = valueB.call(b); - } - if (valueB != null) { - valueB = valueB.valueOf(); - } - multiple = _this.descending ? -1 : 1; - return _this.compare.call(_this, valueA, valueB) * multiple; - }); - if ((_ref = this._setObserver) != null) { - _ref.startObservingItems.apply(_ref, newOrder); - } - return this.set('_storage', newOrder); - }; - - return SetSort; - - })(Batman.SetProxy); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.AssociationSet = (function(_super) { - - __extends(AssociationSet, _super); - - function AssociationSet(foreignKeyValue, association) { - var base; - this.foreignKeyValue = foreignKeyValue; - this.association = association; - base = new Batman.Set; - AssociationSet.__super__.constructor.call(this, base, '_batmanID'); - } - - AssociationSet.prototype.loaded = false; - - AssociationSet.prototype.load = function(callback) { - var _this = this; - if (this.foreignKeyValue == null) { - return callback(void 0, this); - } - return this.association.getRelatedModel().load(this._getLoadOptions(), function(err, records) { - if (!err) { - _this.markAsLoaded(); - } - return callback(err, _this); - }); - }; - - AssociationSet.prototype._getLoadOptions = function() { - var loadOptions; - loadOptions = {}; - loadOptions[this.association.foreignKey] = this.foreignKeyValue; - return loadOptions; - }; - - AssociationSet.accessor('loaded', Batman.Property.defaultAccessor); - - AssociationSet.prototype.markAsLoaded = function() { - this.set('loaded', true); - return this.fire('loaded'); - }; - - return AssociationSet; - - })(Batman.SetSort); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PolymorphicAssociationSet = (function(_super) { - - __extends(PolymorphicAssociationSet, _super); - - function PolymorphicAssociationSet(foreignKeyValue, foreignTypeKeyValue, association) { - this.foreignKeyValue = foreignKeyValue; - this.foreignTypeKeyValue = foreignTypeKeyValue; - this.association = association; - PolymorphicAssociationSet.__super__.constructor.call(this, this.foreignKeyValue, this.association); - } - - PolymorphicAssociationSet.prototype._getLoadOptions = function() { - var loadOptions; - loadOptions = {}; - loadOptions[this.association.foreignKey] = this.foreignKeyValue; - loadOptions[this.association.foreignTypeKey] = this.foreignTypeKeyValue; - return loadOptions; - }; - - return PolymorphicAssociationSet; - - })(Batman.AssociationSet); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.SetIndex = (function(_super) { - - __extends(SetIndex, _super); - - SetIndex.accessor('toArray', function() { - return this.toArray(); - }); - - Batman.extend(SetIndex.prototype, Batman.Enumerable); - - SetIndex.prototype.propertyClass = Batman.Property; - - function SetIndex(base, key) { - var _this = this; - this.base = base; - this.key = key; - SetIndex.__super__.constructor.call(this); - this._storage = new Batman.Hash; - if (this.base.isEventEmitter) { - this._setObserver = new Batman.SetObserver(this.base); - this._setObserver.observedItemKeys = [this.key]; - this._setObserver.observerForItemAndKey = this.observerForItemAndKey.bind(this); - this._setObserver.on('itemsWereAdded', function() { - var item, items, _i, _len, _results; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - _results.push(_this._addItem(item)); - } - return _results; - }); - this._setObserver.on('itemsWereRemoved', function() { - var item, items, _i, _len, _results; - items = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - _results.push(_this._removeItem(item)); - } - return _results; - }); - } - this.base.forEach(this._addItem.bind(this)); - this.startObserving(); - } - - SetIndex.accessor(function(key) { - return this._resultSetForKey(key); - }); - - SetIndex.prototype.startObserving = function() { - var _ref; - return (_ref = this._setObserver) != null ? _ref.startObserving() : void 0; - }; - - SetIndex.prototype.stopObserving = function() { - var _ref; - return (_ref = this._setObserver) != null ? _ref.stopObserving() : void 0; - }; - - SetIndex.prototype.observerForItemAndKey = function(item, key) { - var _this = this; - return function(newValue, oldValue) { - _this._removeItemFromKey(item, oldValue); - return _this._addItemToKey(item, newValue); - }; - }; - - SetIndex.prototype.forEach = function(iterator, ctx) { - var _this = this; - return this._storage.forEach(function(key, set) { - if (set.get('length') > 0) { - return iterator.call(ctx, key, set, _this); - } - }); - }; - - SetIndex.prototype.toArray = function() { - var results; - results = []; - this._storage.forEach(function(key, set) { - if (set.get('length') > 0) { - return results.push(key); - } - }); - return results; - }; - - SetIndex.prototype._addItem = function(item) { - return this._addItemToKey(item, this._keyForItem(item)); - }; - - SetIndex.prototype._addItemToKey = function(item, key) { - return this._resultSetForKey(key).add(item); - }; - - SetIndex.prototype._removeItem = function(item) { - return this._removeItemFromKey(item, this._keyForItem(item)); - }; - - SetIndex.prototype._removeItemFromKey = function(item, key) { - return this._resultSetForKey(key).remove(item); - }; - - SetIndex.prototype._resultSetForKey = function(key) { - return this._storage.getOrSet(key, function() { - return new Batman.Set; - }); - }; - - SetIndex.prototype._keyForItem = function(item) { - return Batman.Keypath.forBaseAndKey(item, this.key).getValue(); - }; - - return SetIndex; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PolymorphicAssociationSetIndex = (function(_super) { - - __extends(PolymorphicAssociationSetIndex, _super); - - function PolymorphicAssociationSetIndex(association, type, key) { - this.association = association; - this.type = type; - PolymorphicAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); - } - - PolymorphicAssociationSetIndex.prototype._resultSetForKey = function(key) { - var _this = this; - return this._storage.getOrSet(key, function() { - return new _this.association.proxyClass(key, _this.type, _this.association); - }); - }; - - return PolymorphicAssociationSetIndex; - - })(Batman.SetIndex); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.AssociationSetIndex = (function(_super) { - - __extends(AssociationSetIndex, _super); - - function AssociationSetIndex(association, key) { - this.association = association; - AssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); - } - - AssociationSetIndex.prototype._resultSetForKey = function(key) { - var _this = this; - return this._storage.getOrSet(key, function() { - return new _this.association.proxyClass(key, _this.association); - }); - }; - - AssociationSetIndex.prototype._setResultSet = function(key, set) { - return this._storage.set(key, set); - }; - - return AssociationSetIndex; - - })(Batman.SetIndex); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.UniqueSetIndex = (function(_super) { - - __extends(UniqueSetIndex, _super); - - function UniqueSetIndex() { - this._uniqueIndex = new Batman.Hash; - UniqueSetIndex.__super__.constructor.apply(this, arguments); - } - - UniqueSetIndex.accessor(function(key) { - return this._uniqueIndex.get(key); - }); - - UniqueSetIndex.prototype._addItemToKey = function(item, key) { - this._resultSetForKey(key).add(item); - if (!this._uniqueIndex.hasKey(key)) { - return this._uniqueIndex.set(key, item); - } - }; - - UniqueSetIndex.prototype._removeItemFromKey = function(item, key) { - var resultSet; - resultSet = this._resultSetForKey(key); - UniqueSetIndex.__super__._removeItemFromKey.apply(this, arguments); - if (resultSet.isEmpty()) { - return this._uniqueIndex.unset(key); - } else { - return this._uniqueIndex.set(key, resultSet.toArray()[0]); - } - }; - - return UniqueSetIndex; - - })(Batman.SetIndex); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.UniqueAssociationSetIndex = (function(_super) { - - __extends(UniqueAssociationSetIndex, _super); - - function UniqueAssociationSetIndex(association, key) { - this.association = association; - UniqueAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); - } - - return UniqueAssociationSetIndex; - - })(Batman.UniqueSetIndex); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PolymorphicUniqueAssociationSetIndex = (function(_super) { - - __extends(PolymorphicUniqueAssociationSetIndex, _super); - - function PolymorphicUniqueAssociationSetIndex(association, type, key) { - this.association = association; - this.type = type; - PolymorphicUniqueAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); - } - - return PolymorphicUniqueAssociationSetIndex; - - })(Batman.UniqueSetIndex); - -}).call(this); - -(function() { - - Batman.URI = (function() { - /* - # URI parsing - */ - - var attributes, childKeyMatchers, decodeQueryComponent, encodeComponent, encodeQueryComponent, keyVal, nameParser, normalizeParams, plus, queryFromParams, r20, strictParser; - - strictParser = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/; - - attributes = ["source", "protocol", "authority", "userInfo", "user", "password", "hostname", "port", "relative", "path", "directory", "file", "query", "hash"]; - - function URI(str) { - var i, matches; - matches = strictParser.exec(str); - i = 14; - while (i--) { - this[attributes[i]] = matches[i] || ''; - } - this.queryParams = this.constructor.paramsFromQuery(this.query); - delete this.authority; - delete this.userInfo; - delete this.relative; - delete this.directory; - delete this.file; - delete this.query; - } - - URI.prototype.queryString = function() { - return this.constructor.queryFromParams(this.queryParams); - }; - - URI.prototype.toString = function() { - return [this.protocol ? "" + this.protocol + ":" : void 0, this.authority() ? "//" : void 0, this.authority(), this.relative()].join(""); - }; - - URI.prototype.userInfo = function() { - return [this.user, this.password ? ":" + this.password : void 0].join(""); - }; - - URI.prototype.authority = function() { - return [this.userInfo(), this.user || this.password ? "@" : void 0, this.hostname, this.port ? ":" + this.port : void 0].join(""); - }; - - URI.prototype.relative = function() { - var query; - query = this.queryString(); - return [this.path, query ? "?" + query : void 0, this.hash ? "#" + this.hash : void 0].join(""); - }; - - URI.prototype.directory = function() { - var splitPath; - splitPath = this.path.split('/'); - if (splitPath.length > 1) { - return splitPath.slice(0, splitPath.length - 1).join('/') + "/"; - } else { - return ""; - } - }; - - URI.prototype.file = function() { - var splitPath; - splitPath = this.path.split("/"); - return splitPath[splitPath.length - 1]; - }; - - /* - # query parsing - */ - - - URI.paramsFromQuery = function(query) { - var matches, params, segment, _i, _len, _ref; - params = {}; - _ref = query.split('&'); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - segment = _ref[_i]; - if (matches = segment.match(keyVal)) { - normalizeParams(params, decodeQueryComponent(matches[1]), decodeQueryComponent(matches[2])); - } else { - normalizeParams(params, decodeQueryComponent(segment), null); - } - } - return params; - }; - - URI.decodeQueryComponent = decodeQueryComponent = function(str) { - return decodeURIComponent(str.replace(plus, '%20')); - }; - - nameParser = /^[\[\]]*([^\[\]]+)\]*(.*)/; - - childKeyMatchers = [/^\[\]\[([^\[\]]+)\]$/, /^\[\](.+)$/]; - - plus = /\+/g; - - r20 = /%20/g; - - keyVal = /^([^=]*)=(.*)/; - - normalizeParams = function(params, name, v) { - var after, childKey, k, last, matches, _ref, _ref1, _ref2; - if (matches = name.match(nameParser)) { - k = matches[1]; - after = matches[2]; - } else { - return; - } - if (after === '') { - params[k] = v; - } else if (after === '[]') { - if ((_ref = params[k]) == null) { - params[k] = []; - } - if (Batman.typeOf(params[k]) !== 'Array') { - throw new Error("expected Array (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); - } - params[k].push(v); - } else if (matches = after.match(childKeyMatchers[0]) || after.match(childKeyMatchers[1])) { - childKey = matches[1]; - if ((_ref1 = params[k]) == null) { - params[k] = []; - } - if (Batman.typeOf(params[k]) !== 'Array') { - throw new Error("expected Array (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); - } - last = params[k][params[k].length - 1]; - if (Batman.typeOf(last) === 'Object' && !(childKey in last)) { - normalizeParams(last, childKey, v); - } else { - params[k].push(normalizeParams({}, childKey, v)); - } - } else { - if ((_ref2 = params[k]) == null) { - params[k] = {}; - } - if (Batman.typeOf(params[k]) !== 'Object') { - throw new Error("expected Object (got " + (Batman.typeOf(params[k])) + ") for param \"" + k + "\""); - } - params[k] = normalizeParams(params[k], after, v); - } - return params; - }; - - /* - # query building - */ - - - URI.queryFromParams = queryFromParams = function(value, prefix) { - var arrayResults, k, v, valueType; - if (value == null) { - return prefix; - } - valueType = Batman.typeOf(value); - if (!((prefix != null) || valueType === 'Object')) { - throw new Error("value must be an Object"); - } - switch (valueType) { - case 'Array': - return ((function() { - var _i, _len; - arrayResults = []; - if (value.length === 0) { - arrayResults.push(queryFromParams(null, "" + prefix + "[]")); - } else { - for (_i = 0, _len = value.length; _i < _len; _i++) { - v = value[_i]; - arrayResults.push(queryFromParams(v, "" + prefix + "[]")); - } - } - return arrayResults; - })()).join("&"); - case 'Object': - return ((function() { - var _results; - _results = []; - for (k in value) { - v = value[k]; - _results.push(queryFromParams(v, prefix ? "" + prefix + "[" + (encodeQueryComponent(k)) + "]" : encodeQueryComponent(k))); - } - return _results; - })()).join("&"); - default: - if (prefix != null) { - return "" + prefix + "=" + (encodeQueryComponent(value)); - } else { - return encodeQueryComponent(value); - } - } - }; - - URI.encodeComponent = encodeComponent = function(str) { - if (str != null) { - return encodeURIComponent(str); - } else { - return ''; - } - }; - - URI.encodeQueryComponent = encodeQueryComponent = function(str) { - return encodeComponent(str).replace(r20, '+'); - }; - - return URI; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.Request = (function(_super) { - var dataHasFileUploads; - - __extends(Request, _super); - - Request.objectToFormData = function(data) { - var formData, key, pairForList, val, _i, _len, _ref, _ref1; - pairForList = function(key, object, first) { - var k, list, v; - if (first == null) { - first = false; - } - return list = (function() { - switch (Batman.typeOf(object)) { - case 'Object': - list = (function() { - var _results; - _results = []; - for (k in object) { - v = object[k]; - _results.push(pairForList((first ? k : "" + key + "[" + k + "]"), v)); - } - return _results; - })(); - return list.reduce(function(acc, list) { - return acc.concat(list); - }, []); - case 'Array': - return object.reduce(function(acc, element) { - return acc.concat(pairForList("" + key + "[]", element)); - }, []); - default: - return [[key, object != null ? object : ""]]; - } - })(); - }; - formData = new Batman.container.FormData(); - _ref = pairForList("", data, true); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - _ref1 = _ref[_i], key = _ref1[0], val = _ref1[1]; - formData.append(key, val); - } - return formData; - }; - - Request.dataHasFileUploads = dataHasFileUploads = function(data) { - var k, type, v, _i, _len; - if ((typeof File !== "undefined" && File !== null) && data instanceof File) { - return true; - } - type = Batman.typeOf(data); - switch (type) { - case 'Object': - for (k in data) { - v = data[k]; - if (dataHasFileUploads(v)) { - return true; - } - } - break; - case 'Array': - for (_i = 0, _len = data.length; _i < _len; _i++) { - v = data[_i]; - if (dataHasFileUploads(v)) { - return true; - } - } - } - return false; - }; - - Request.wrapAccessor('method', function(core) { - return { - set: function(k, val) { - return core.set.call(this, k, val != null ? typeof val.toUpperCase === "function" ? val.toUpperCase() : void 0 : void 0); - } - }; - }); - - Request.prototype.method = 'GET'; - - Request.prototype.hasFileUploads = function() { - return dataHasFileUploads(this.data); - }; - - Request.prototype.contentType = 'application/x-www-form-urlencoded'; - - Request.prototype.autosend = true; - - function Request(options) { - var handler, handlers, k, _ref; - handlers = {}; - for (k in options) { - handler = options[k]; - if (!(k === 'success' || k === 'error' || k === 'loading' || k === 'loaded')) { - continue; - } - handlers[k] = handler; - delete options[k]; - } - Request.__super__.constructor.call(this, options); - for (k in handlers) { - handler = handlers[k]; - this.on(k, handler); - } - if (((_ref = this.get('url')) != null ? _ref.length : void 0) > 0) { - if (this.autosend) { - this.send(); - } - } else { - this.observe('url', function(url) { - if (url != null) { - return this.send(); - } - }); - } - } - - Request.prototype.send = function() { - return Batman.developer.error("Please source a dependency file for a request implementation"); - }; - - return Request; - - })(Batman.Object); - -}).call(this); - -(function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __slice = [].slice; - - Batman.Navigator = (function() { - - Navigator.defaultClass = function() { - if (Batman.config.usePushState && Batman.PushStateNavigator.isSupported()) { - return Batman.PushStateNavigator; - } else { - return Batman.HashbangNavigator; - } - }; - - Navigator.forApp = function(app) { - return new (this.defaultClass())(app); - }; - - function Navigator(app) { - this.app = app; - this.handleCurrentLocation = __bind(this.handleCurrentLocation, this); - - } - - Navigator.prototype.start = function() { - var _this = this; - if (typeof window === 'undefined') { - return; - } - if (this.started) { - return; - } - this.started = true; - this.startWatching(); - Batman.currentApp.prevent('ready'); - return Batman.setImmediate(function() { - if (_this.started && Batman.currentApp) { - _this.handleCurrentLocation(); - return Batman.currentApp.allowAndFire('ready'); - } - }); - }; - - Navigator.prototype.stop = function() { - this.stopWatching(); - return this.started = false; - }; - - Navigator.prototype.handleLocation = function(location) { - var path; - path = this.pathFromLocation(location); - if (path === this.cachedPath) { - return; - } - return this.dispatch(path); - }; - - Navigator.prototype.handleCurrentLocation = function() { - return this.handleLocation(window.location); - }; - - Navigator.prototype.dispatch = function(params) { - return this.cachedPath = this.app.get('dispatcher').dispatch(params); - }; - - Navigator.prototype.push = function(params) { - var path; - path = this.dispatch(params); - this.pushState(null, '', path); - return path; - }; - - Navigator.prototype.replace = function(params) { - var path; - path = this.dispatch(params); - this.replaceState(null, '', path); - return path; - }; - - Navigator.prototype.redirect = Navigator.prototype.push; - - Navigator.prototype.normalizePath = function() { - var i, seg, segments; - segments = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - segments = (function() { - var _i, _len, _results; - _results = []; - for (i = _i = 0, _len = segments.length; _i < _len; i = ++_i) { - seg = segments[i]; - _results.push(("" + seg).replace(/^(?!\/)/, '/').replace(/\/+$/, '')); - } - return _results; - })(); - return segments.join('') || '/'; - }; - - Navigator.normalizePath = Navigator.prototype.normalizePath; - - return Navigator; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PushStateNavigator = (function(_super) { - - __extends(PushStateNavigator, _super); - - function PushStateNavigator() { - return PushStateNavigator.__super__.constructor.apply(this, arguments); - } - - PushStateNavigator.isSupported = function() { - var _ref; - return (typeof window !== "undefined" && window !== null ? (_ref = window.history) != null ? _ref.pushState : void 0 : void 0) != null; - }; - - PushStateNavigator.prototype.startWatching = function() { - return Batman.addEventListener(window, 'popstate', this.handleCurrentLocation); - }; - - PushStateNavigator.prototype.stopWatching = function() { - return Batman.removeEventListener(window, 'popstate', this.handleCurrentLocation); - }; - - PushStateNavigator.prototype.pushState = function(stateObject, title, path) { - return window.history.pushState(stateObject, title, this.linkTo(path)); - }; - - PushStateNavigator.prototype.replaceState = function(stateObject, title, path) { - return window.history.replaceState(stateObject, title, this.linkTo(path)); - }; - - PushStateNavigator.prototype.linkTo = function(url) { - return this.normalizePath(Batman.config.pathPrefix, url); - }; - - PushStateNavigator.prototype.pathFromLocation = function(location) { - var fullPath, prefixPattern; - fullPath = "" + (location.pathname || '') + (location.search || ''); - prefixPattern = new RegExp("^" + (this.normalizePath(Batman.config.pathPrefix))); - return this.normalizePath(fullPath.replace(prefixPattern, '')); - }; - - PushStateNavigator.prototype.handleLocation = function(location) { - var hashbangPath, path; - path = this.pathFromLocation(location); - if (path === '/' && (hashbangPath = Batman.HashbangNavigator.prototype.pathFromLocation(location)) !== '/') { - return this.replace(hashbangPath); - } else { - return PushStateNavigator.__super__.handleLocation.apply(this, arguments); - } - }; - - return PushStateNavigator; - - })(Batman.Navigator); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.HashbangNavigator = (function(_super) { - - __extends(HashbangNavigator, _super); - - function HashbangNavigator() { - return HashbangNavigator.__super__.constructor.apply(this, arguments); - } - - HashbangNavigator.prototype.HASH_PREFIX = '#!'; - - if ((typeof window !== "undefined" && window !== null) && 'onhashchange' in window) { - HashbangNavigator.prototype.startWatching = function() { - return Batman.addEventListener(window, 'hashchange', this.handleCurrentLocation); - }; - HashbangNavigator.prototype.stopWatching = function() { - return Batman.removeEventListener(window, 'hashchange', this.handleCurrentLocation); - }; - } else { - HashbangNavigator.prototype.startWatching = function() { - return this.interval = setInterval(this.handleCurrentLocation, 100); - }; - HashbangNavigator.prototype.stopWatching = function() { - return this.interval = clearInterval(this.interval); - }; - } - - HashbangNavigator.prototype.pushState = function(stateObject, title, path) { - return window.location.hash = this.linkTo(path); - }; - - HashbangNavigator.prototype.replaceState = function(stateObject, title, path) { - var loc; - loc = window.location; - return loc.replace("" + loc.pathname + loc.search + (this.linkTo(path))); - }; - - HashbangNavigator.prototype.linkTo = function(url) { - return this.HASH_PREFIX + url; - }; - - HashbangNavigator.prototype.pathFromLocation = function(location) { - var hash; - hash = location.hash; - if ((hash != null ? hash.substr(0, 2) : void 0) === this.HASH_PREFIX) { - return this.normalizePath(hash.substr(2)); - } else { - return '/'; - } - }; - - HashbangNavigator.prototype.handleLocation = function(location) { - var realPath; - if (!Batman.config.usePushState) { - return HashbangNavigator.__super__.handleLocation.apply(this, arguments); - } - realPath = Batman.PushStateNavigator.prototype.pathFromLocation(location); - if (realPath === '/') { - return HashbangNavigator.__super__.handleLocation.apply(this, arguments); - } else { - return location.replace(this.normalizePath("" + Batman.config.pathPrefix + (this.linkTo(realPath)))); - } - }; - - return HashbangNavigator; - - })(Batman.Navigator); - -}).call(this); - -(function() { - - Batman.RouteMap = (function() { - - RouteMap.prototype.memberRoute = null; - - RouteMap.prototype.collectionRoute = null; - - function RouteMap() { - this.childrenByOrder = []; - this.childrenByName = {}; - } - - RouteMap.prototype.routeForParams = function(params) { - var route, _i, _len, _ref; - _ref = this.childrenByOrder; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - route = _ref[_i]; - if (route.test(params)) { - return route; - } - } - return void 0; - }; - - RouteMap.prototype.addRoute = function(name, route) { - var base, names, - _this = this; - this.childrenByOrder.push(route); - if (name.length > 0 && (names = name.split('.')).length > 0) { - base = names.shift(); - if (!this.childrenByName[base]) { - this.childrenByName[base] = new Batman.RouteMap; - } - this.childrenByName[base].addRoute(names.join('.'), route); - } else { - if (route.get('member')) { - Batman.developer["do"](function() { - if (_this.memberRoute) { - return Batman.developer.error("Member route with name " + name + " already exists!"); - } - }); - this.memberRoute = route; - } else { - Batman.developer["do"](function() { - if (_this.collectionRoute) { - return Batman.developer.error("Collection route with name " + name + " already exists!"); - } - }); - this.collectionRoute = route; - } - } - return true; - }; - - return RouteMap; - - })(); - -}).call(this); - -(function() { - var __slice = [].slice; - - Batman.RouteMapBuilder = (function() { - - RouteMapBuilder.BUILDER_FUNCTIONS = ['resources', 'member', 'collection', 'route', 'root']; - - RouteMapBuilder.ROUTES = { - index: { - cardinality: 'collection', - path: function(resource) { - return resource; - }, - name: function(resource) { - return resource; - } - }, - "new": { - cardinality: 'collection', - path: function(resource) { - return "" + resource + "/new"; - }, - name: function(resource) { - return "" + resource + ".new"; - } - }, - show: { - cardinality: 'member', - path: function(resource) { - return "" + resource + "/:id"; - }, - name: function(resource) { - return resource; - } - }, - edit: { - cardinality: 'member', - path: function(resource) { - return "" + resource + "/:id/edit"; - }, - name: function(resource) { - return "" + resource + ".edit"; - } - }, - collection: { - cardinality: 'collection', - path: function(resource, name) { - return "" + resource + "/" + name; - }, - name: function(resource, name) { - return "" + resource + "." + name; - } - }, - member: { - cardinality: 'member', - path: function(resource, name) { - return "" + resource + "/:id/" + name; - }, - name: function(resource, name) { - return "" + resource + "." + name; - } - } - }; - - function RouteMapBuilder(app, routeMap, parent, baseOptions) { - this.app = app; - this.routeMap = routeMap; - this.parent = parent; - this.baseOptions = baseOptions != null ? baseOptions : {}; - if (this.parent) { - this.rootPath = this.parent._nestingPath(); - this.rootName = this.parent._nestingName(); - } else { - this.rootPath = ''; - this.rootName = ''; - } - } - - RouteMapBuilder.prototype.resources = function() { - var action, actions, arg, args, as, callback, childBuilder, controller, included, k, options, path, resourceName, resourceNames, resourceRoot, routeOptions, routeTemplate, v, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - resourceNames = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = args.length; _i < _len; _i++) { - arg = args[_i]; - if (typeof arg === 'string') { - _results.push(arg); - } - } - return _results; - })(); - if (typeof args[args.length - 1] === 'function') { - callback = args.pop(); - } - if (typeof args[args.length - 1] === 'object') { - options = args.pop(); - } else { - options = {}; - } - actions = { - index: true, - "new": true, - show: true, - edit: true - }; - if (options.except) { - _ref = options.except; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - actions[k] = false; - } - delete options.except; - } else if (options.only) { - for (k in actions) { - v = actions[k]; - actions[k] = false; - } - _ref1 = options.only; - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - k = _ref1[_j]; - actions[k] = true; - } - delete options.only; - } - for (_k = 0, _len2 = resourceNames.length; _k < _len2; _k++) { - resourceName = resourceNames[_k]; - resourceRoot = Batman.helpers.pluralize(resourceName); - controller = Batman.helpers.camelize(resourceRoot, true); - childBuilder = this._childBuilder({ - controller: controller - }); - if (callback != null) { - callback.call(childBuilder); - } - for (action in actions) { - included = actions[action]; - if (!(included)) { - continue; - } - routeTemplate = this.constructor.ROUTES[action]; - as = routeTemplate.name(resourceRoot); - path = routeTemplate.path(resourceRoot); - routeOptions = Batman.extend({ - controller: controller, - action: action, - path: path, - as: as - }, options); - childBuilder[routeTemplate.cardinality](action, routeOptions); - } - } - return true; - }; - - RouteMapBuilder.prototype.member = function() { - return this._addRoutesWithCardinality.apply(this, ['member'].concat(__slice.call(arguments))); - }; - - RouteMapBuilder.prototype.collection = function() { - return this._addRoutesWithCardinality.apply(this, ['collection'].concat(__slice.call(arguments))); - }; - - RouteMapBuilder.prototype.root = function(signature, options) { - return this.route('/', signature, options); - }; - - RouteMapBuilder.prototype.route = function(path, signature, options, callback) { - if (!callback) { - if (typeof options === 'function') { - callback = options; - options = void 0; - } else if (typeof signature === 'function') { - callback = signature; - signature = void 0; - } - } - if (!options) { - if (typeof signature === 'string') { - options = { - signature: signature - }; - } else { - options = signature; - } - options || (options = {}); - } else { - if (signature) { - options.signature = signature; - } - } - if (callback) { - options.callback = callback; - } - options.as || (options.as = this._nameFromPath(path)); - options.path = path; - return this._addRoute(options); - }; - - RouteMapBuilder.prototype._addRoutesWithCardinality = function() { - var cardinality, name, names, options, resourceRoot, routeOptions, routeTemplate, _i, _j, _len; - cardinality = arguments[0], names = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), options = arguments[_i++]; - if (typeof options === 'string') { - names.push(options); - options = {}; - } - options = Batman.extend({}, this.baseOptions, options); - options[cardinality] = true; - routeTemplate = this.constructor.ROUTES[cardinality]; - resourceRoot = options.controller; - for (_j = 0, _len = names.length; _j < _len; _j++) { - name = names[_j]; - routeOptions = Batman.extend({ - action: name - }, options); - if (routeOptions.path == null) { - routeOptions.path = routeTemplate.path(resourceRoot, name); - } - if (routeOptions.as == null) { - routeOptions.as = routeTemplate.name(resourceRoot, name); - } - this._addRoute(routeOptions); - } - return true; - }; - - RouteMapBuilder.prototype._addRoute = function(options) { - var klass, name, path, route; - if (options == null) { - options = {}; - } - path = this.rootPath + options.path; - name = this.rootName + Batman.helpers.camelize(options.as, true); - delete options.as; - delete options.path; - klass = options.callback ? Batman.CallbackActionRoute : Batman.ControllerActionRoute; - options.app = this.app; - route = new klass(path, options); - return this.routeMap.addRoute(name, route); - }; - - RouteMapBuilder.prototype._nameFromPath = function(path) { - path = path.replace(Batman.Route.regexps.namedOrSplat, '').replace(/\/+/g, '.').replace(/(^\.)|(\.$)/g, ''); - return path; - }; - - RouteMapBuilder.prototype._nestingPath = function() { - var nestingParam, nestingSegment; - if (!this.parent) { - return ""; - } else { - nestingParam = ":" + Batman.helpers.singularize(this.baseOptions.controller) + "Id"; - nestingSegment = Batman.helpers.underscore(this.baseOptions.controller); - return "" + (this.parent._nestingPath()) + "/" + nestingSegment + "/" + nestingParam + "/"; - } - }; - - RouteMapBuilder.prototype._nestingName = function() { - if (!this.parent) { - return ""; - } else { - return this.baseOptions.controller + "."; - } - }; - - RouteMapBuilder.prototype._childBuilder = function(baseOptions) { - if (baseOptions == null) { - baseOptions = {}; - } - return new Batman.RouteMapBuilder(this.app, this.routeMap, this, baseOptions); - }; - - return RouteMapBuilder; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.App = (function(_super) { - var name, _fn, _i, _len, _ref, - _this = this; - - __extends(App, _super); - - function App() { - return App.__super__.constructor.apply(this, arguments); - } - - App.classAccessor('currentParams', { - get: function() { - return new Batman.Hash; - }, - 'final': true - }); - - App.classAccessor('paramsManager', { - get: function() { - var nav, params; - if (!(nav = this.get('navigator'))) { - return; - } - params = this.get('currentParams'); - return params.replacer = new Batman.ParamsReplacer(nav, params); - }, - 'final': true - }); - - App.classAccessor('paramsPusher', { - get: function() { - var nav, params; - if (!(nav = this.get('navigator'))) { - return; - } - params = this.get('currentParams'); - return params.pusher = new Batman.ParamsPusher(nav, params); - }, - 'final': true - }); - - App.classAccessor('routes', function() { - return new Batman.NamedRouteQuery(this.get('routeMap')); - }); - - App.classAccessor('routeMap', function() { - return new Batman.RouteMap; - }); - - App.classAccessor('routeMapBuilder', function() { - return new Batman.RouteMapBuilder(this, this.get('routeMap')); - }); - - App.classAccessor('dispatcher', function() { - return new Batman.Dispatcher(this, this.get('routeMap')); - }); - - App.classAccessor('controllers', function() { - return this.get('dispatcher.controllers'); - }); - - App.classAccessor('_renderContext', function() { - return Batman.RenderContext.base.descend(this); - }); - - App.requirePath = ''; - - Batman.developer["do"](function() { - App.require = function() { - var base, name, names, path, _i, _len, - _this = this; - path = arguments[0], names = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - base = this.requirePath + path; - for (_i = 0, _len = names.length; _i < _len; _i++) { - name = names[_i]; - this.prevent('run'); - path = base + '/' + name + '.coffee'; - new Batman.Request({ - url: path, - type: 'html', - success: function(response) { - CoffeeScript["eval"](response); - _this.allow('run'); - if (!_this.isPrevented('run')) { - _this.fire('loaded'); - } - if (_this.wantsToRun) { - return _this.run(); - } - } - }); - } - return this; - }; - App.controller = function() { - var names; - names = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - names = names.map(function(n) { - return n + '_controller'; - }); - return this.require.apply(this, ['controllers'].concat(__slice.call(names))); - }; - App.model = function() { - return this.require.apply(this, ['models'].concat(__slice.call(arguments))); - }; - return App.view = function() { - return this.require.apply(this, ['views'].concat(__slice.call(arguments))); - }; - }); - - App.layout = void 0; - - _ref = Batman.RouteMapBuilder.BUILDER_FUNCTIONS; - _fn = function(name) { - return App[name] = function() { - var _ref1; - return (_ref1 = this.get('routeMapBuilder'))[name].apply(_ref1, arguments); - }; - }; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - name = _ref[_i]; - _fn(name); - } - - App.event('ready').oneShot = true; - - App.event('run').oneShot = true; - - App.run = function() { - var layout, layoutClass, - _this = this; - if (Batman.currentApp) { - if (Batman.currentApp === this) { - return; - } - Batman.currentApp.stop(); - } - if (this.hasRun) { - return false; - } - if (this.isPrevented('run')) { - this.wantsToRun = true; - return false; - } else { - delete this.wantsToRun; - } - Batman.currentApp = this; - Batman.App.set('current', this); - if (this.get('dispatcher') == null) { - this.set('dispatcher', new Batman.Dispatcher(this, this.get('routeMap'))); - this.set('controllers', this.get('dispatcher.controllers')); - } - if (this.get('navigator') == null) { - this.set('navigator', Batman.Navigator.forApp(this)); - this.on('run', function() { - Batman.navigator = _this.get('navigator'); - if (Object.keys(_this.get('dispatcher').routeMap).length > 0) { - return Batman.navigator.start(); - } - }); - } - this.observe('layout', function(layout) { - return layout != null ? layout.on('ready', function() { - return _this.fire('ready'); - }) : void 0; - }); - layout = this.get('layout'); - if (layout) { - if (typeof layout === 'string') { - layoutClass = this[Batman.helpers.camelize(layout) + 'View']; - } - } else { - if (layout !== null) { - layoutClass = Batman.View; - } - } - if (layoutClass) { - layout = this.set('layout', new layoutClass({ - context: this, - node: document - })); - } - this.hasRun = true; - this.fire('run'); - return this; - }; - - App.event('ready').oneShot = true; - - App.event('stop').oneShot = true; - - App.stop = function() { - var _ref1; - if ((_ref1 = this.navigator) != null) { - _ref1.stop(); - } - Batman.navigator = null; - this.hasRun = false; - this.fire('stop'); - return this; - }; - - return App; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - - Batman.Association = (function() { - - Association.prototype.associationType = ''; - - Association.prototype.isPolymorphic = false; - - Association.prototype.defaultOptions = { - saveInline: true, - autoload: true, - nestUrl: false - }; - - function Association(model, label, options) { - var defaultOptions, encoder, getAccessor, self; - this.model = model; - this.label = label; - if (options == null) { - options = {}; - } - defaultOptions = { - namespace: Batman.currentApp, - name: Batman.helpers.camelize(Batman.helpers.singularize(this.label)) - }; - this.options = Batman.extend(defaultOptions, this.defaultOptions, options); - if (this.options.nestUrl) { - if (!(this.model.urlNestsUnder != null)) { - developer.error("You must persist the the model " + this.model.constructor.name + " to use the url helpers on an association"); - } - this.model.urlNestsUnder(Batman.helpers.underscore(this.getRelatedModel().get('resourceName'))); - } - if (this.options.extend != null) { - Batman.extend(this, this.options.extend); - } - encoder = { - encode: this.options.saveInline ? this.encoder() : false, - decode: this.decoder() - }; - this.model.encode(this.label, encoder); - self = this; - getAccessor = function() { - return self.getAccessor.call(this, self, this.model, this.label); - }; - this.model.accessor(this.label, { - get: getAccessor, - set: model.defaultAccessor.set, - unset: model.defaultAccessor.unset - }); - } - - Association.prototype.getRelatedModel = function() { - var className, relatedModel, scope; - scope = this.options.namespace || Batman.currentApp; - className = this.options.name; - relatedModel = scope != null ? scope[className] : void 0; - Batman.developer["do"](function() { - if ((Batman.currentApp != null) && !relatedModel) { - return Batman.developer.warn("Related model " + className + " hasn't loaded yet."); - } - }); - return relatedModel; - }; - - Association.prototype.getFromAttributes = function(record) { - return record.get("attributes." + this.label); - }; - - Association.prototype.setIntoAttributes = function(record, value) { - return record.get('attributes').set(this.label, value); - }; - - Association.prototype.inverse = function() { - var inverse, relatedAssocs, - _this = this; - if (relatedAssocs = this.getRelatedModel()._batman.get('associations')) { - if (this.options.inverseOf) { - return relatedAssocs.getByLabel(this.options.inverseOf); - } - inverse = null; - relatedAssocs.forEach(function(label, assoc) { - if (assoc.getRelatedModel() === _this.model) { - return inverse = assoc; - } - }); - return inverse; - } - }; - - Association.prototype.reset = function() { - delete this.index; - return true; - }; - - return Association; - - })(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PluralAssociation = (function(_super) { - - __extends(PluralAssociation, _super); - - function PluralAssociation() { - return PluralAssociation.__super__.constructor.apply(this, arguments); - } - - PluralAssociation.prototype.proxyClass = Batman.AssociationSet; - - PluralAssociation.prototype.isSingular = false; - - PluralAssociation.prototype.setForRecord = Batman.Property.wrapTrackingPrevention(function(record) { - var id; - if (id = record.get(this.primaryKey)) { - return this.setIndex().get(id); - } else { - return new this.proxyClass(void 0, this); - } - }); - - PluralAssociation.prototype.getAccessor = function(self, model, label) { - var relatedRecords, setInAttributes, - _this = this; - if (!self.getRelatedModel()) { - return; - } - if (setInAttributes = self.getFromAttributes(this)) { - return setInAttributes; - } else { - relatedRecords = self.setForRecord(this); - self.setIntoAttributes(this, relatedRecords); - Batman.Property.withoutTracking(function() { - if (self.options.autoload && !_this.isNew() && !relatedRecords.loaded) { - return relatedRecords.load(function(error, records) { - if (error) { - throw error; - } - }); - } - }); - return relatedRecords; - } - }; - - PluralAssociation.prototype.setIndex = function() { - this.index || (this.index = new Batman.AssociationSetIndex(this, this[this.indexRelatedModelOn])); - return this.index; - }; - - return PluralAssociation; - - })(Batman.Association); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.HasManyAssociation = (function(_super) { - - __extends(HasManyAssociation, _super); - - HasManyAssociation.prototype.associationType = 'hasMany'; - - HasManyAssociation.prototype.indexRelatedModelOn = 'foreignKey'; - - function HasManyAssociation(model, label, options) { - if (options != null ? options.as : void 0) { - return (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.PolymorphicHasManyAssociation, arguments, function(){}); - } - HasManyAssociation.__super__.constructor.apply(this, arguments); - this.primaryKey = this.options.primaryKey || "id"; - this.foreignKey = this.options.foreignKey || ("" + (Batman.helpers.underscore(model.get('resourceName'))) + "_id"); - } - - HasManyAssociation.prototype.apply = function(baseSaveError, base) { - var relations, set, - _this = this; - if (!baseSaveError) { - if (relations = this.getFromAttributes(base)) { - relations.forEach(function(model) { - return model.set(_this.foreignKey, base.get(_this.primaryKey)); - }); - } - base.set(this.label, set = this.setForRecord(base)); - if (base.lifecycle.get('state') === 'creating') { - return set.markAsLoaded(); - } - } - }; - - HasManyAssociation.prototype.encoder = function() { - var association; - association = this; - return function(relationSet, _, __, record) { - var jsonArray; - if (relationSet != null) { - jsonArray = []; - relationSet.forEach(function(relation) { - var relationJSON; - relationJSON = relation.toJSON(); - if (!association.inverse() || association.inverse().options.encodeForeignKey) { - relationJSON[association.foreignKey] = record.get(association.primaryKey); - } - return jsonArray.push(relationJSON); - }); - } - return jsonArray; - }; - }; - - HasManyAssociation.prototype.decoder = function() { - var association; - association = this; - return function(data, key, _, __, parentRecord) { - var existingRecord, existingRelations, jsonObject, newRelations, record, relatedModel, savedRecord, _i, _len; - if (relatedModel = association.getRelatedModel()) { - existingRelations = association.getFromAttributes(parentRecord) || association.setForRecord(parentRecord); - newRelations = existingRelations.filter(function(relation) { - return relation.isNew(); - }).toArray(); - for (_i = 0, _len = data.length; _i < _len; _i++) { - jsonObject = data[_i]; - record = new relatedModel(); - record._withoutDirtyTracking(function() { - return this.fromJSON(jsonObject); - }); - existingRecord = relatedModel.get('loaded').indexedByUnique('id').get(record.get('id')); - if (existingRecord != null) { - existingRecord._withoutDirtyTracking(function() { - return this.fromJSON(jsonObject); - }); - record = existingRecord; - } else { - if (newRelations.length > 0) { - savedRecord = newRelations.shift(); - savedRecord._withoutDirtyTracking(function() { - return this.fromJSON(jsonObject); - }); - record = savedRecord; - } - } - record = relatedModel._mapIdentity(record); - existingRelations.add(record); - if (association.options.inverseOf) { - record.set(association.options.inverseOf, parentRecord); - } - } - existingRelations.markAsLoaded(); - } else { - Batman.developer.error("Can't decode model " + association.options.name + " because it hasn't been loaded yet!"); - } - return existingRelations; - }; - }; - - return HasManyAssociation; - - })(Batman.PluralAssociation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PolymorphicHasManyAssociation = (function(_super) { - - __extends(PolymorphicHasManyAssociation, _super); - - PolymorphicHasManyAssociation.prototype.proxyClass = Batman.PolymorphicAssociationSet; - - PolymorphicHasManyAssociation.prototype.isPolymorphic = true; - - function PolymorphicHasManyAssociation(model, label, options) { - options.inverseOf = this.foreignLabel = options.as; - delete options.as; - options.foreignKey || (options.foreignKey = "" + this.foreignLabel + "_id"); - PolymorphicHasManyAssociation.__super__.constructor.call(this, model, label, options); - this.foreignTypeKey = options.foreignTypeKey || ("" + this.foreignLabel + "_type"); - this.model.encode(this.foreignTypeKey); - } - - PolymorphicHasManyAssociation.prototype.apply = function(baseSaveError, base) { - var relations, - _this = this; - if (!baseSaveError) { - if (relations = this.getFromAttributes(base)) { - PolymorphicHasManyAssociation.__super__.apply.apply(this, arguments); - relations.forEach(function(model) { - return model.set(_this.foreignTypeKey, _this.modelType()); - }); - } - } - return true; - }; - - PolymorphicHasManyAssociation.prototype.getRelatedModelForType = function() { - return this.getRelatedModel(); - }; - - PolymorphicHasManyAssociation.prototype.modelType = function() { - return this.model.get('resourceName'); - }; - - PolymorphicHasManyAssociation.prototype.setIndex = function() { - if (!this.typeIndex) { - this.typeIndex = new Batman.PolymorphicAssociationSetIndex(this, this.modelType(), this[this.indexRelatedModelOn]); - } - return this.typeIndex; - }; - - PolymorphicHasManyAssociation.prototype.encoder = function() { - var association; - association = this; - return function(relationSet, _, __, record) { - var jsonArray; - if (relationSet != null) { - jsonArray = []; - relationSet.forEach(function(relation) { - var relationJSON; - relationJSON = relation.toJSON(); - relationJSON[association.foreignKey] = record.get(association.primaryKey); - relationJSON[association.foreignTypeKey] = association.modelType(); - return jsonArray.push(relationJSON); - }); - } - return jsonArray; - }; - }; - - return PolymorphicHasManyAssociation; - - })(Batman.HasManyAssociation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.SingularAssociation = (function(_super) { - - __extends(SingularAssociation, _super); - - function SingularAssociation() { - return SingularAssociation.__super__.constructor.apply(this, arguments); - } - - SingularAssociation.prototype.isSingular = true; - - SingularAssociation.prototype.getAccessor = function(self, model, label) { - var proxy, recordInAttributes; - if (recordInAttributes = self.getFromAttributes(this)) { - return recordInAttributes; - } - if (self.getRelatedModel()) { - proxy = this.associationProxy(self); - Batman.Property.withoutTracking(function() { - if (!proxy.get('loaded') && self.options.autoload) { - return proxy.load(); - } - }); - return proxy; - } - }; - - SingularAssociation.prototype.setIndex = function() { - this.index || (this.index = new Batman.UniqueAssociationSetIndex(this, this[this.indexRelatedModelOn])); - return this.index; - }; - - return SingularAssociation; - - })(Batman.Association); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.HasOneAssociation = (function(_super) { - - __extends(HasOneAssociation, _super); - - HasOneAssociation.prototype.associationType = 'hasOne'; - - HasOneAssociation.prototype.proxyClass = Batman.HasOneProxy; - - HasOneAssociation.prototype.indexRelatedModelOn = 'foreignKey'; - - function HasOneAssociation() { - HasOneAssociation.__super__.constructor.apply(this, arguments); - this.primaryKey = this.options.primaryKey || "id"; - this.foreignKey = this.options.foreignKey || ("" + (Batman.helpers.underscore(this.model.get('resourceName'))) + "_id"); - } - - HasOneAssociation.prototype.apply = function(baseSaveError, base) { - var relation; - if (relation = this.getFromAttributes(base)) { - return relation.set(this.foreignKey, base.get(this.primaryKey)); - } - }; - - HasOneAssociation.prototype.encoder = function() { - var association; - association = this; - return function(val, key, object, record) { - var json; - if (!association.options.saveInline) { - return; - } - if (json = val.toJSON()) { - json[association.foreignKey] = record.get(association.primaryKey); - } - return json; - }; - }; - - HasOneAssociation.prototype.decoder = function() { - var association; - association = this; - return function(data, _, __, ___, parentRecord) { - var record, relatedModel; - relatedModel = association.getRelatedModel(); - record = new relatedModel(); - record._withoutDirtyTracking(function() { - return this.fromJSON(data); - }); - if (association.options.inverseOf) { - record.set(association.options.inverseOf, parentRecord); - } - record = relatedModel._mapIdentity(record); - return record; - }; - }; - - return HasOneAssociation; - - })(Batman.SingularAssociation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.BelongsToAssociation = (function(_super) { - - __extends(BelongsToAssociation, _super); - - BelongsToAssociation.prototype.associationType = 'belongsTo'; - - BelongsToAssociation.prototype.proxyClass = Batman.BelongsToProxy; - - BelongsToAssociation.prototype.indexRelatedModelOn = 'primaryKey'; - - BelongsToAssociation.prototype.defaultOptions = { - saveInline: false, - autoload: true, - encodeForeignKey: true - }; - - function BelongsToAssociation(model, label, options) { - if (options != null ? options.polymorphic : void 0) { - delete options.polymorphic; - return (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.PolymorphicBelongsToAssociation, arguments, function(){}); - } - BelongsToAssociation.__super__.constructor.apply(this, arguments); - this.foreignKey = this.options.foreignKey || ("" + this.label + "_id"); - this.primaryKey = this.options.primaryKey || "id"; - if (this.options.encodeForeignKey) { - this.model.encode(this.foreignKey); - } - } - - BelongsToAssociation.prototype.encoder = function() { - return function(val) { - return val.toJSON(); - }; - }; - - BelongsToAssociation.prototype.decoder = function() { - var association; - association = this; - return function(data, _, __, ___, childRecord) { - var inverse, record, relatedModel; - relatedModel = association.getRelatedModel(); - record = new relatedModel(); - record._withoutDirtyTracking(function() { - return this.fromJSON(data); - }); - record = relatedModel._mapIdentity(record); - if (association.options.inverseOf) { - if (inverse = association.inverse()) { - if (inverse instanceof Batman.HasManyAssociation) { - childRecord.set(association.foreignKey, record.get(association.primaryKey)); - } else { - record.set(inverse.label, childRecord); - } - } - } - childRecord.set(association.label, record); - return record; - }; - }; - - BelongsToAssociation.prototype.apply = function(base) { - var foreignValue, model; - if (model = base.get(this.label)) { - foreignValue = model.get(this.primaryKey); - if (foreignValue !== void 0) { - return base.set(this.foreignKey, foreignValue); - } - } - }; - - return BelongsToAssociation; - - })(Batman.SingularAssociation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PolymorphicBelongsToAssociation = (function(_super) { - - __extends(PolymorphicBelongsToAssociation, _super); - - PolymorphicBelongsToAssociation.prototype.isPolymorphic = true; - - PolymorphicBelongsToAssociation.prototype.proxyClass = Batman.PolymorphicBelongsToProxy; - - PolymorphicBelongsToAssociation.prototype.defaultOptions = Batman.mixin({}, Batman.BelongsToAssociation.prototype.defaultOptions, { - encodeForeignTypeKey: true - }); - - function PolymorphicBelongsToAssociation() { - PolymorphicBelongsToAssociation.__super__.constructor.apply(this, arguments); - this.foreignTypeKey = this.options.foreignTypeKey || ("" + this.label + "_type"); - if (this.options.encodeForeignTypeKey) { - this.model.encode(this.foreignTypeKey); - } - this.typeIndicies = {}; - } - - PolymorphicBelongsToAssociation.prototype.getRelatedModel = false; - - PolymorphicBelongsToAssociation.prototype.setIndex = false; - - PolymorphicBelongsToAssociation.prototype.inverse = false; - - PolymorphicBelongsToAssociation.prototype.apply = function(base) { - var foreignTypeValue, instanceOrProxy, model; - PolymorphicBelongsToAssociation.__super__.apply.apply(this, arguments); - if (instanceOrProxy = base.get(this.label)) { - if (instanceOrProxy instanceof Batman.AssociationProxy) { - model = instanceOrProxy.association.model; - } else { - model = instanceOrProxy.constructor; - } - foreignTypeValue = model.get('resourceName'); - return base.set(this.foreignTypeKey, foreignTypeValue); - } - }; - - PolymorphicBelongsToAssociation.prototype.getAccessor = function(self, model, label) { - var proxy, recordInAttributes; - if (recordInAttributes = self.getFromAttributes(this)) { - return recordInAttributes; - } - if (self.getRelatedModelForType(this.get(self.foreignTypeKey))) { - proxy = this.associationProxy(self); - Batman.Property.withoutTracking(function() { - if (!proxy.get('loaded') && self.options.autoload) { - return proxy.load(); - } - }); - return proxy; - } - }; - - PolymorphicBelongsToAssociation.prototype.url = function(recordOptions) { - var ending, helper, id, inverse, root, type, _ref, _ref1; - type = (_ref = recordOptions.data) != null ? _ref[this.foreignTypeKey] : void 0; - if (type && (inverse = this.inverseForType(type))) { - root = Batman.helpers.pluralize(type).toLowerCase(); - id = (_ref1 = recordOptions.data) != null ? _ref1[this.foreignKey] : void 0; - helper = inverse.isSingular ? "singularize" : "pluralize"; - ending = Batman.helpers[helper](inverse.label); - return "/" + root + "/" + id + "/" + ending; - } - }; - - PolymorphicBelongsToAssociation.prototype.getRelatedModelForType = function(type) { - var relatedModel, scope; - scope = this.options.namespace || Batman.currentApp; - if (type) { - relatedModel = scope != null ? scope[type] : void 0; - relatedModel || (relatedModel = scope != null ? scope[Batman.helpers.camelize(type)] : void 0); - } - Batman.developer["do"](function() { - if ((Batman.currentApp != null) && !relatedModel) { - return Batman.developer.warn("Related model " + type + " for polymorphic association not found."); - } - }); - return relatedModel; - }; - - PolymorphicBelongsToAssociation.prototype.setIndexForType = function(type) { - var _base; - (_base = this.typeIndicies)[type] || (_base[type] = new Batman.PolymorphicUniqueAssociationSetIndex(this, type, this.primaryKey)); - return this.typeIndicies[type]; - }; - - PolymorphicBelongsToAssociation.prototype.inverseForType = function(type) { - var inverse, relatedAssocs, _ref, - _this = this; - if (relatedAssocs = (_ref = this.getRelatedModelForType(type)) != null ? _ref._batman.get('associations') : void 0) { - if (this.options.inverseOf) { - return relatedAssocs.getByLabel(this.options.inverseOf); - } - inverse = null; - relatedAssocs.forEach(function(label, assoc) { - if (assoc.getRelatedModel() === _this.model) { - return inverse = assoc; - } - }); - return inverse; - } - }; - - PolymorphicBelongsToAssociation.prototype.decoder = function() { - var association; - association = this; - return function(data, key, response, ___, childRecord) { - var foreignTypeValue, inverse, record, relatedModel; - foreignTypeValue = response[association.foreignTypeKey] || childRecord.get(association.foreignTypeKey); - relatedModel = association.getRelatedModelForType(foreignTypeValue); - record = new relatedModel(); - record._withoutDirtyTracking(function() { - return this.fromJSON(data); - }); - record = relatedModel._mapIdentity(record); - if (association.options.inverseOf) { - if (inverse = association.inverseForType(foreignTypeValue)) { - if (inverse instanceof Batman.PolymorphicHasManyAssociation) { - childRecord.set(association.foreignKey, record.get(association.primaryKey)); - childRecord.set(association.foreignTypeKey, foreignTypeValue); - } else { - record.set(inverse.label, childRecord); - } - } - } - childRecord.set(association.label, record); - return record; - }; - }; - - return PolymorphicBelongsToAssociation; - - })(Batman.BelongsToAssociation); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.Validator = (function(_super) { - - __extends(Validator, _super); - - function Validator() { - var mixins, options; - options = arguments[0], mixins = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - this.options = options; - Validator.__super__.constructor.apply(this, mixins); - } - - Validator.prototype.validate = function(record) { - return Batman.developer.error("You must override validate in Batman.Validator subclasses."); - }; - - Validator.prototype.format = function(key, messageKey, interpolations) { - return Batman.t("errors.messages." + messageKey, interpolations); - }; - - Validator.options = function() { - var options; - options = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - Batman.initializeObject(this); - if (this._batman.options) { - return this._batman.options.concat(options); - } else { - return this._batman.options = options; - } - }; - - Validator.matches = function(options) { - var key, results, shouldReturn, value, _ref, _ref1; - results = {}; - shouldReturn = false; - for (key in options) { - value = options[key]; - if (~((_ref = this._batman) != null ? (_ref1 = _ref.options) != null ? _ref1.indexOf(key) : void 0 : void 0)) { - results[key] = value; - shouldReturn = true; - } - } - if (shouldReturn) { - return results; - } - }; - - return Validator; - - })(Batman.Object); - -}).call(this); - -(function() { - - Batman.Validators = []; - - Batman.extend(Batman.translate.messages, { - errors: { - format: "%{attribute} %{message}", - messages: { - too_short: "must be at least %{count} characters", - too_long: "must be less than %{count} characters", - wrong_length: "must be %{count} characters", - blank: "can't be blank", - not_numeric: "must be a number", - not_matching: "is not valid" - } - } - }); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.RegExpValidator = (function(_super) { - - __extends(RegExpValidator, _super); - - RegExpValidator.options('regexp', 'pattern'); - - function RegExpValidator(options) { - var _ref; - this.regexp = (_ref = options.regexp) != null ? _ref : options.pattern; - RegExpValidator.__super__.constructor.apply(this, arguments); - } - - RegExpValidator.prototype.validateEach = function(errors, record, key, callback) { - var value; - value = record.get(key); - if ((value != null) && value !== '') { - if (!this.regexp.test(value)) { - errors.add(key, this.format(key, 'not_matching')); - } - } - return callback(); - }; - - return RegExpValidator; - - })(Batman.Validator); - - Batman.Validators.push(Batman.RegExpValidator); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.PresenceValidator = (function(_super) { - - __extends(PresenceValidator, _super); - - function PresenceValidator() { - return PresenceValidator.__super__.constructor.apply(this, arguments); - } - - PresenceValidator.options('presence'); - - PresenceValidator.prototype.validateEach = function(errors, record, key, callback) { - var value; - value = record.get(key); - if (this.options.presence && (!(value != null) || value === '')) { - errors.add(key, this.format(key, 'blank')); - } - return callback(); - }; - - return PresenceValidator; - - })(Batman.Validator); - - Batman.Validators.push(Batman.PresenceValidator); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.NumericValidator = (function(_super) { - - __extends(NumericValidator, _super); - - function NumericValidator() { - return NumericValidator.__super__.constructor.apply(this, arguments); - } - - NumericValidator.options('numeric'); - - NumericValidator.prototype.validateEach = function(errors, record, key, callback) { - var value; - value = record.get(key); - if (this.options.numeric && isNaN(parseFloat(value))) { - errors.add(key, this.format(key, 'not_numeric')); - } - return callback(); - }; - - return NumericValidator; - - })(Batman.Validator); - - Batman.Validators.push(Batman.NumericValidator); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.LengthValidator = (function(_super) { - - __extends(LengthValidator, _super); - - LengthValidator.options('minLength', 'maxLength', 'length', 'lengthWithin', 'lengthIn'); - - function LengthValidator(options) { - var range; - if (range = options.lengthIn || options.lengthWithin) { - options.minLength = range[0]; - options.maxLength = range[1] || -1; - delete options.lengthWithin; - delete options.lengthIn; - } - LengthValidator.__super__.constructor.apply(this, arguments); - } - - LengthValidator.prototype.validateEach = function(errors, record, key, callback) { - var options, value, _ref; - options = this.options; - value = (_ref = record.get(key)) != null ? _ref : []; - if (options.minLength && value.length < options.minLength) { - errors.add(key, this.format(key, 'too_short', { - count: options.minLength - })); - } - if (options.maxLength && value.length > options.maxLength) { - errors.add(key, this.format(key, 'too_long', { - count: options.maxLength - })); - } - if (options.length && value.length !== options.length) { - errors.add(key, this.format(key, 'wrong_length', { - count: options.length - })); - } - return callback(); - }; - - return LengthValidator; - - })(Batman.Validator); - - Batman.Validators.push(Batman.LengthValidator); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ControllerActionFrame = (function(_super) { - - __extends(ControllerActionFrame, _super); - - ControllerActionFrame.prototype.operationOccurred = false; - - ControllerActionFrame.prototype.remainingOperations = 0; - - ControllerActionFrame.prototype.event('complete').oneShot = true; - - function ControllerActionFrame(options, onComplete) { - ControllerActionFrame.__super__.constructor.call(this, options); - this.on('complete', onComplete); - } - - ControllerActionFrame.prototype.startOperation = function(options) { - if (options == null) { - options = {}; - } - if (!options.internal) { - this.operationOccurred = true; - } - this._changeOperationsCounter(1); - return true; - }; - - ControllerActionFrame.prototype.finishOperation = function() { - this._changeOperationsCounter(-1); - return true; - }; - - ControllerActionFrame.prototype.startAndFinishOperation = function(options) { - this.startOperation(options); - this.finishOperation(options); - return true; - }; - - ControllerActionFrame.prototype._changeOperationsCounter = function(delta) { - var _ref; - this.remainingOperations += delta; - if (this.remainingOperations === 0) { - this.fire('complete'); - } - if ((_ref = this.parentFrame) != null) { - _ref._changeOperationsCounter(delta); - } - }; - - return ControllerActionFrame; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.InsertionBinding = (function(_super) { - - __extends(InsertionBinding, _super); - - InsertionBinding.prototype.isTwoWay = false; - - InsertionBinding.prototype.bindImmediately = false; - - function InsertionBinding(node, className, key, context, parentRenderer, invert) { - var result, - _this = this; - this.invert = invert != null ? invert : false; - this.placeholderNode = document.createComment("detached node " + (this.get('_batmanID'))); - result = InsertionBinding.__super__.constructor.apply(this, arguments); - Batman.DOM.onParseExit(this.node, function() { - _this.bind(); - if (_this.placeholderNode != null) { - return Batman.DOM.trackBinding(_this, _this.placeholderNode); - } - }); - result; - - } - - InsertionBinding.prototype.dataChange = function(value) { - var parentNode; - parentNode = this.placeholderNode.parentNode || this.node.parentNode; - if (!!value === !this.invert) { - if (!(this.node.parentNode != null)) { - Batman.DOM.insertBefore(parentNode, this.node, this.placeholderNode); - return parentNode.removeChild(this.placeholderNode); - } - } else { - parentNode.insertBefore(this.placeholderNode, this.node); - return Batman.DOM.removeNode(this.node); - } - }; - - InsertionBinding.prototype.die = function() { - if (this.dead) { - return; - } - InsertionBinding.__super__.die.apply(this, arguments); - if (!!this.get('filteredValue') === !this.invert) { - return Batman.DOM.destroyNode(this.placeholderNode); - } else { - return Batman.DOM.destroyNode(this.node); - } - }; - - return InsertionBinding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var isEmptyDataObject; - - isEmptyDataObject = function(obj) { - var name; - for (name in obj) { - return false; - } - return true; - }; - - Batman.extend(Batman, { - cache: {}, - uuid: 0, - expando: "batman" + Math.random().toString().replace(/\D/g, ''), - canDeleteExpando: (function() { - var div; - try { - div = document.createElement('div'); - return delete div.test; - } catch (e) { - return Batman.canDeleteExpando = false; - } - })(), - noData: { - "embed": true, - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - hasData: function(elem) { - elem = (elem.nodeType ? Batman.cache[elem[Batman.expando]] : elem[Batman.expando]); - return !!elem && !isEmptyDataObject(elem); - }, - data: function(elem, name, data, pvt) { - var cache, getByName, id, internalKey, ret, thisCache; - if (!Batman.acceptData(elem)) { - return; - } - internalKey = Batman.expando; - getByName = typeof name === "string"; - cache = Batman.cache; - id = elem[Batman.expando]; - if ((!id || (pvt && id && (cache[id] && !cache[id][internalKey]))) && getByName && data === void 0) { - return; - } - if (!id) { - if (elem.nodeType !== 3) { - elem[Batman.expando] = id = ++Batman.uuid; - } else { - id = Batman.expando; - } - } - if (!cache[id]) { - cache[id] = {}; - } - if (typeof name === "object" || typeof name === "function") { - if (pvt) { - cache[id][internalKey] = Batman.extend(cache[id][internalKey], name); - } else { - cache[id] = Batman.extend(cache[id], name); - } - } - thisCache = cache[id]; - if (pvt) { - thisCache[internalKey] || (thisCache[internalKey] = {}); - thisCache = thisCache[internalKey]; - } - if (data !== void 0) { - thisCache[name] = data; - } - if (getByName) { - ret = thisCache[name]; - } else { - ret = thisCache; - } - return ret; - }, - removeData: function(elem, name, pvt) { - var cache, id, internalCache, internalKey, isNode, thisCache; - if (!Batman.acceptData(elem)) { - return; - } - internalKey = Batman.expando; - isNode = elem.nodeType; - cache = Batman.cache; - id = elem[Batman.expando]; - if (!cache[id]) { - return; - } - if (name) { - thisCache = pvt ? cache[id][internalKey] : cache[id]; - if (thisCache) { - delete thisCache[name]; - if (!isEmptyDataObject(thisCache)) { - return; - } - } - } - if (pvt) { - delete cache[id][internalKey]; - if (!isEmptyDataObject(cache[id])) { - return; - } - } - internalCache = cache[id][internalKey]; - if (Batman.canDeleteExpando || !cache.setInterval) { - delete cache[id]; - } else { - cache[id] = null; - } - if (internalCache) { - cache[id] = {}; - return cache[id][internalKey] = internalCache; - } else { - if (Batman.canDeleteExpando) { - return delete elem[Batman.expando]; - } else if (elem.removeAttribute) { - return elem.removeAttribute(Batman.expando); - } else { - return elem[Batman.expando] = null; - } - } - }, - _data: function(elem, name, data) { - return Batman.data(elem, name, data, true); - }, - acceptData: function(elem) { - var match; - if (elem.nodeName) { - match = Batman.noData[elem.nodeName.toLowerCase()]; - if (match) { - return !(match === true || elem.getAttribute("classid") !== match); - } - } - return true; - } - }); - -}).call(this); - -(function() { - var buntUndefined, defaultAndOr, - __slice = [].slice; - - buntUndefined = function(f) { - return function(value) { - if (typeof value === 'undefined') { - return void 0; - } else { - return f.apply(this, arguments); - } - }; - }; - - defaultAndOr = function(lhs, rhs) { - return lhs || rhs; - }; - - Batman.Filters = { - raw: buntUndefined(function(value, binding) { - binding.escapeValue = false; - return value; - }), - get: buntUndefined(function(value, key) { - if (value.get != null) { - return value.get(key); - } else { - return value[key]; - } - }), - equals: buntUndefined(function(lhs, rhs, binding) { - return lhs === rhs; - }), - and: function(lhs, rhs) { - return lhs && rhs; - }, - or: function(lhs, rhs, binding) { - return lhs || rhs; - }, - not: function(value, binding) { - return !!!value; - }, - matches: buntUndefined(function(value, searchFor) { - return value.indexOf(searchFor) !== -1; - }), - truncate: buntUndefined(function(value, length, end, binding) { - if (end == null) { - end = "..."; - } - if (!binding) { - binding = end; - end = "..."; - } - if (value.length > length) { - value = value.substr(0, length - end.length) + end; - } - return value; - }), - "default": function(value, defaultValue, binding) { - if ((value != null) && value !== '') { - return value; - } else { - return defaultValue; - } - }, - prepend: function(value, string, binding) { - return string + value; - }, - append: function(value, string, binding) { - return value + string; - }, - replace: buntUndefined(function(value, searchFor, replaceWith, flags, binding) { - if (!binding) { - binding = flags; - flags = void 0; - } - if (flags === void 0) { - return value.replace(searchFor, replaceWith); - } else { - return value.replace(searchFor, replaceWith, flags); - } - }), - downcase: buntUndefined(function(value) { - return value.toLowerCase(); - }), - upcase: buntUndefined(function(value) { - return value.toUpperCase(); - }), - pluralize: buntUndefined(function(string, count, includeCount, binding) { - if (!binding) { - binding = includeCount; - includeCount = true; - if (!binding) { - binding = count; - count = void 0; - } - } - if (count) { - return Batman.helpers.pluralize(count, string, void 0, includeCount); - } else { - return Batman.helpers.pluralize(string); - } - }), - humanize: buntUndefined(function(string, binding) { - return Batman.helpers.humanize(string); - }), - join: buntUndefined(function(value, withWhat, binding) { - if (withWhat == null) { - withWhat = ''; - } - if (!binding) { - binding = withWhat; - withWhat = ''; - } - return value.join(withWhat); - }), - sort: buntUndefined(function(value) { - return value.sort(); - }), - map: buntUndefined(function(value, key) { - return value.map(function(x) { - return Batman.get(x, key); - }); - }), - has: function(set, item) { - if (set == null) { - return false; - } - return Batman.contains(set, item); - }, - first: buntUndefined(function(value) { - return value[0]; - }), - meta: buntUndefined(function(value, keypath) { - Batman.developer.assert(value.meta, "Error, value doesn't have a meta to filter on!"); - return value.meta.get(keypath); - }), - interpolate: function(string, interpolationKeypaths, binding) { - var k, v, values; - if (!binding) { - binding = interpolationKeypaths; - interpolationKeypaths = void 0; - } - if (!string) { - return; - } - values = {}; - for (k in interpolationKeypaths) { - v = interpolationKeypaths[k]; - values[k] = this.get(v); - if (!(values[k] != null)) { - Batman.developer.warn("Warning! Undefined interpolation key " + k + " for interpolation", string); - values[k] = ''; - } - } - return Batman.helpers.interpolate(string, values); - }, - withArguments: function() { - var binding, block, curryArgs, _i; - block = arguments[0], curryArgs = 3 <= arguments.length ? __slice.call(arguments, 1, _i = arguments.length - 1) : (_i = 1, []), binding = arguments[_i++]; - if (!block) { - return; - } - return function() { - var regularArgs; - regularArgs = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - return block.call.apply(block, [this].concat(__slice.call(curryArgs), __slice.call(regularArgs))); - }; - }, - routeToAction: buntUndefined(function(model, action) { - var params; - params = Batman.Dispatcher.paramsFromArgument(model); - params.action = action; - return params; - }), - escape: buntUndefined(Batman.escapeHTML) - }; - - (function() { - var k, _i, _len, _ref, _results; - _ref = ['capitalize', 'singularize', 'underscore', 'camelize']; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - k = _ref[_i]; - _results.push(Batman.Filters[k] = buntUndefined(Batman.helpers[k])); - } - return _results; - })(); - - Batman.developer.addFilters(); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.RenderContext = (function() { - var ContextProxy; - - RenderContext.deProxy = function(object) { - if ((object != null) && object.isContextProxy) { - return object.get('proxiedObject'); - } else { - return object; - } - }; - - RenderContext.root = function() { - var root; - if (Batman.currentApp != null) { - root = Batman.currentApp.get('_renderContext'); - } - return root != null ? root : root = this.base; - }; - - RenderContext.prototype.windowWrapper = { - window: Batman.container - }; - - function RenderContext(object, parent) { - this.object = object; - this.parent = parent; - } - - RenderContext.prototype.findKey = function(key) { - var base, currentNode, val; - base = key.split('.')[0].split('|')[0].trim(); - currentNode = this; - while (currentNode) { - val = Batman.get(currentNode.object, base); - if (typeof val !== 'undefined') { - val = Batman.get(currentNode.object, key); - return [val, currentNode.object].map(this.constructor.deProxy); - } - currentNode = currentNode.parent; - } - return [Batman.get(this.windowWrapper, key), this.windowWrapper]; - }; - - RenderContext.prototype.get = function(key) { - return this.findKey(key)[0]; - }; - - RenderContext.prototype.contextForKey = function(key) { - return this.findKey(key)[1]; - }; - - RenderContext.prototype.descend = function(object, scopedKey) { - var oldObject; - if (scopedKey) { - oldObject = object; - object = new Batman.Object(); - object[scopedKey] = oldObject; - } - return new this.constructor(object, this); - }; - - RenderContext.prototype.descendWithKey = function(key, scopedKey) { - var proxy; - proxy = new ContextProxy(this, key); - return this.descend(proxy, scopedKey); - }; - - RenderContext.prototype.chain = function() { - var parent, x; - x = []; - parent = this; - while (parent) { - x.push(parent.object); - parent = parent.parent; - } - return x; - }; - - RenderContext.ContextProxy = ContextProxy = (function(_super) { - - __extends(ContextProxy, _super); - - ContextProxy.prototype.isContextProxy = true; - - ContextProxy.accessor('proxiedObject', function() { - return this.binding.get('filteredValue'); - }); - - ContextProxy.accessor({ - get: function(key) { - return this.get("proxiedObject." + key); - }, - set: function(key, value) { - return this.set("proxiedObject." + key, value); - }, - unset: function(key) { - return this.unset("proxiedObject." + key); - } - }); - - function ContextProxy(renderContext, keyPath, localKey) { - this.renderContext = renderContext; - this.keyPath = keyPath; - this.localKey = localKey; - this.binding = new Batman.DOM.AbstractBinding(void 0, this.keyPath, this.renderContext); - } - - return ContextProxy; - - })(Batman.Object); - - return RenderContext; - - }).call(this); - - Batman.RenderContext.base = new Batman.RenderContext(Batman.RenderContext.prototype.windowWrapper); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.ViewStore = (function(_super) { - - __extends(ViewStore, _super); - - ViewStore.prefix = 'views'; - - ViewStore.fetchFromRemote = true; - - function ViewStore() { - ViewStore.__super__.constructor.apply(this, arguments); - this._viewContents = {}; - this._requestedPaths = new Batman.SimpleSet; - } - - ViewStore.prototype.propertyClass = Batman.Property; - - ViewStore.prototype.fetchView = function(path) { - var _this = this; - return new Batman.Request({ - url: Batman.Navigator.normalizePath(this.constructor.prefix, "" + path + ".html"), - type: 'html', - success: function(response) { - return _this.set(path, response); - }, - error: function(response) { - throw new Error("Could not load view from " + path); - } - }); - }; - - ViewStore.accessor({ - 'final': true, - get: function(path) { - var contents; - if (path[0] !== '/') { - return this.get("/" + path); - } - if (this._viewContents[path]) { - return this._viewContents[path]; - } - if (this._requestedPaths.has(path)) { - return; - } - if (contents = this._sourceFromDOM(path)) { - return contents; - } - if (this.constructor.fetchFromRemote) { - this.fetchView(path); - } else { - throw new Error("Couldn't find view source for \'" + path + "\'!"); - } - }, - set: function(path, content) { - if (path[0] !== '/') { - return this.set("/" + path, content); - } - this._requestedPaths.add(path); - return this._viewContents[path] = content; - } - }); - - ViewStore.prototype.prefetch = function(path) { - this.get(path); - return true; - }; - - ViewStore.prototype._sourceFromDOM = function(path) { - var node, relativePath; - relativePath = path.slice(1); - if (node = Batman.DOM.querySelector(document, "[data-defineview*='" + relativePath + "']")) { - Batman.setImmediate(function() { - var _ref; - return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; - }); - return Batman.DOM.defineView(path, node); - } - }; - - return ViewStore; - - })(Batman.Object); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.View = (function(_super) { - - __extends(View, _super); - - View.YieldStorage = (function(_super1) { - - __extends(YieldStorage, _super1); - - function YieldStorage() { - return YieldStorage.__super__.constructor.apply(this, arguments); - } - - YieldStorage.wrapAccessor(function(core) { - return { - get: function(key) { - var val; - val = core.get.call(this, key); - if (!(val != null)) { - val = this.set(key, []); - } - return val; - } - }; - }); - - return YieldStorage; - - })(Batman.Hash); - - View.store = new Batman.ViewStore(); - - View.option = function() { - var keys, - _this = this; - keys = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - keys.forEach(function(key) { - return _this.accessor(_this.prototype._argumentBindingKey(key), function(bindingKey) { - var context, keyPath, node, _ref; - if (!((node = this.get('node')) && (context = this.get('context')))) { - return; - } - keyPath = node.getAttribute(("data-view-" + key).toLowerCase()); - if (keyPath == null) { - return; - } - if ((_ref = this[bindingKey]) != null) { - _ref.die(); - } - return this[bindingKey] = new Batman.DOM.ViewArgumentBinding(node, keyPath, context); - }); - }); - return this.accessor.apply(this, __slice.call(keys).concat([function(key) { - var _ref; - return (_ref = this.get(this._argumentBindingKey(key))) != null ? _ref.get('filteredValue') : void 0; - }])); - }; - - View.prototype.isView = true; - - View.prototype.cache = true; - - View.prototype._rendered = false; - - View.prototype.node = null; - - View.prototype.event('ready').oneShot = true; - - View.accessor('html', { - get: function() { - var source; - if (this.html && this.html.length > 0) { - return this.html; - } - if (!(source = this.get('source'))) { - return; - } - source = Batman.Navigator.normalizePath(source); - return this.html = this.constructor.store.get(source); - }, - set: function(_, html) { - return this.html = html; - } - }); - - View.accessor('node', { - get: function() { - var html; - if (this.node == null) { - html = this.get('html'); - if (!(html && html.length > 0)) { - return; - } - this.node = document.createElement('div'); - this._setNodeOwner(this.node); - Batman.setInnerHTML(this.node, html); - } - return this.node; - }, - set: function(_, node) { - var updateHTML, - _this = this; - this.node = node; - this._setNodeOwner(node); - updateHTML = function(html) { - if (html != null) { - Batman.setInnerHTML(_this.node, html); - return _this.forget('html', updateHTML); - } - }; - this.observeAndFire('html', updateHTML); - return node; - } - }); - - View.accessor('yields', function() { - return new this.constructor.YieldStorage; - }); - - View.accessor('fetched?', function() { - return this.get('source') != null; - }); - - View.accessor('readyToRender', function() { - var _ref; - return this.get('node') && (this.get('fetched?') ? ((_ref = this.get('html')) != null ? _ref.length : void 0) > 0 : true); - }); - - function View(options) { - var context, - _this = this; - if (options == null) { - options = {}; - } - context = options.context; - if (context) { - if (!(context instanceof Batman.RenderContext)) { - context = Batman.RenderContext.root().descend(context); - } - } else { - context = Batman.RenderContext.root(); - } - options.context = context.descend(this); - View.__super__.constructor.call(this, options); - Batman.Property.withoutTracking(function() { - return _this.observeAndFire('readyToRender', function(ready) { - if (ready) { - return _this.render(); - } - }); - }); - } - - View.prototype.render = function() { - var node, - _this = this; - if (this._rendered) { - return; - } - this._rendered = true; - this._renderer = new Batman.Renderer(node = this.get('node'), this.get('context'), this); - return this._renderer.on('rendered', function() { - return _this.fire('ready', node); - }); - }; - - View.prototype.isInDOM = function() { - var node; - if ((node = this.get('node'))) { - return (node.parentNode != null) || this.get('yields').some(function(name, nodes) { - var _i, _len; - for (_i = 0, _len = nodes.length; _i < _len; _i++) { - node = nodes[_i].node; - if (node.parentNode != null) { - return true; - } - } - return false; - }); - } else { - return false; - } - }; - - View.prototype.applyYields = function() { - return this.get('yields').forEach(function(name, nodes) { - var action, node, yieldObject, _i, _len, _ref, _results; - yieldObject = Batman.DOM.Yield.withName(name); - _results = []; - for (_i = 0, _len = nodes.length; _i < _len; _i++) { - _ref = nodes[_i], node = _ref.node, action = _ref.action; - _results.push(yieldObject[action](node)); - } - return _results; - }); - }; - - View.prototype.retractYields = function() { - return this.get('yields').forEach(function(name, nodes) { - var node, _i, _len, _ref, _results; - _results = []; - for (_i = 0, _len = nodes.length; _i < _len; _i++) { - node = nodes[_i].node; - _results.push((_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0); - } - return _results; - }); - }; - - View.prototype.pushYieldAction = function(key, action, node) { - this._setNodeYielder(node); - return this.get("yields").get(key).push({ - node: node, - action: action - }); - }; - - View.prototype._argumentBindingKey = function(key) { - return "_" + key + "ArgumentBinding"; - }; - - View.prototype._setNodeOwner = function(node) { - return Batman._data(node, 'view', this); - }; - - View.prototype._setNodeYielder = function(node) { - return Batman._data(node, 'yielder', this); - }; - - View.prototype.on('ready', function() { - return typeof this.ready === "function" ? this.ready.apply(this, arguments) : void 0; - }); - - View.prototype.on('appear', function() { - return typeof this.viewDidAppear === "function" ? this.viewDidAppear.apply(this, arguments) : void 0; - }); - - View.prototype.on('disappear', function() { - return typeof this.viewDidDisappear === "function" ? this.viewDidDisappear.apply(this, arguments) : void 0; - }); - - View.prototype.on('beforeAppear', function() { - return typeof this.viewWillAppear === "function" ? this.viewWillAppear.apply(this, arguments) : void 0; - }); - - View.prototype.on('beforeDisappear', function() { - return typeof this.viewWillDisappear === "function" ? this.viewWillDisappear.apply(this, arguments) : void 0; - }); - - return View; - - }).call(this, Batman.Object); - -}).call(this); - -(function() { - var Yield, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - - Batman.DOM.Yield = Yield = (function(_super) { - - __extends(Yield, _super); - - Yield.yields = {}; - - Yield.queued = function(fn) { - return function() { - var args, handler, - _this = this; - args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; - if (this.containerNode != null) { - return fn.apply(this, args); - } else { - return handler = this.observe('containerNode', function() { - var result; - result = fn.apply(_this, args); - _this.forget('containerNode', handler); - return result; - }); - } - }; - }; - - Yield.reset = function() { - return this.yields = {}; - }; - - Yield.withName = function(name) { - var _base; - (_base = this.yields)[name] || (_base[name] = new this({ - name: name - })); - return this.yields[name]; - }; - - Yield.forEach = function(f) { - var name, yieldObject, _ref; - _ref = this.yields; - for (name in _ref) { - yieldObject = _ref[name]; - f(yieldObject); - } - }; - - Yield.clearAll = function() { - return this.forEach(function(yieldObject) { - return yieldObject.clear(); - }); - }; - - Yield.cycleAll = function() { - return this.forEach(function(yieldObject) { - return yieldObject.cycle(); - }); - }; - - Yield.clearAllStale = function() { - return this.forEach(function(yieldObject) { - return yieldObject.clearStale(); - }); - }; - - function Yield() { - this.cycle(); - } - - Yield.prototype.cycle = function() { - return this.currentVersionNodes = []; - }; - - Yield.prototype.clear = Yield.queued(function() { - var child, _i, _len, _ref, _results; - this.cycle(); - _ref = (function() { - var _j, _len, _ref, _results1; - _ref = this.containerNode.childNodes; - _results1 = []; - for (_j = 0, _len = _ref.length; _j < _len; _j++) { - child = _ref[_j]; - _results1.push(child); - } - return _results1; - }).call(this); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - _results.push(Batman.removeOrDestroyNode(child)); - } - return _results; - }); - - Yield.prototype.clearStale = Yield.queued(function() { - var child, _i, _len, _ref, _results; - _ref = (function() { - var _j, _len, _ref, _results1; - _ref = this.containerNode.childNodes; - _results1 = []; - for (_j = 0, _len = _ref.length; _j < _len; _j++) { - child = _ref[_j]; - _results1.push(child); - } - return _results1; - }).call(this); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - if (!~this.currentVersionNodes.indexOf(child)) { - _results.push(Batman.removeOrDestroyNode(child)); - } - } - return _results; - }); - - Yield.prototype.append = Yield.queued(function(node) { - this.currentVersionNodes.push(node); - return Batman.appendChild(this.containerNode, node, true); - }); - - Yield.prototype.replace = Yield.queued(function(node) { - this.clear(); - return this.append(node); - }); - - return Yield; - - })(Batman.Object); - -}).call(this); - -(function() { - - - -}).call(this); \ No newline at end of file diff --git a/vendor/javascripts/es5-shim.js b/vendor/javascripts/es5-shim.js deleted file mode 100644 index ce79780..0000000 --- a/vendor/javascripts/es5-shim.js +++ /dev/null @@ -1,1021 +0,0 @@ -// vim: ts=4 sts=4 sw=4 expandtab -// -- kriskowal Kris Kowal Copyright (C) 2009-2011 MIT License -// -- tlrobinson Tom Robinson Copyright (C) 2009-2010 MIT License (Narwhal Project) -// -- dantman Daniel Friesen Copyright (C) 2010 XXX TODO License or CLA -// -- fschaefer Florian Schäfer Copyright (C) 2010 MIT License -// -- Gozala Irakli Gozalishvili Copyright (C) 2010 MIT License -// -- kitcambridge Kit Cambridge Copyright (C) 2011 MIT License -// -- kossnocorp Sasha Koss XXX TODO License or CLA -// -- bryanforbes Bryan Forbes XXX TODO License or CLA -// -- killdream Quildreen Motta Copyright (C) 2011 MIT Licence -// -- michaelficarra Michael Ficarra Copyright (C) 2011 3-clause BSD License -// -- sharkbrainguy Gerard Paapu Copyright (C) 2011 MIT License -// -- bbqsrc Brendan Molloy XXX TODO License or CLA -// -- iwyg XXX TODO License or CLA -// -- DomenicDenicola Domenic Denicola XXX TODO License or CLA -// -- xavierm02 Montillet Xavier XXX TODO License or CLA -// -- Raynos Raynos XXX TODO License or CLA -// -- samsonjs Sami Samhuri XXX TODO License or CLA -// -- rwldrn Rick Waldron Copyright (C) 2011 MIT License -// -- lexer Alexey Zakharov XXX TODO License or CLA - -/*! - Copyright (c) 2009, 280 North Inc. http://280north.com/ - MIT License. http://github.com/280north/narwhal/blob/master/README.md -*/ - -// Module systems magic dance -(function (definition) { - // RequireJS - if (typeof define == "function") { - define(definition); - // CommonJS and + + +<% content_for(:title) { "1080p dashboard" } %> + +
    +
      +
    • +
      + +
    • + +
    • +
      +
    • + +
    • +
      +
    • + +
    • +
      +
    • + +
    • +
      +
    • + +
    • +
      +
    • + +
    • +
      + +
    • + +
    • +
      +
    • + +
    • +
      + +
    • + +
    +
    Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://localhost:3000/widgets/welcome
    +
    \ No newline at end of file diff --git a/templates/project/jobs/buzzwords.rb b/templates/project/jobs/buzzwords.rb index 109dc60..2668d5a 100644 --- a/templates/project/jobs/buzzwords.rb +++ b/templates/project/jobs/buzzwords.rb @@ -3,7 +3,7 @@ buzzword_counts = Hash.new({ value: 0 }) SCHEDULER.every '2s' do random_buzzword = buzzwords.sample - buzzword_counts[random_buzzword] = { label: random_buzzword, value: buzzword_counts[random_buzzword][:value] + 1 } + buzzword_counts[random_buzzword] = { label: random_buzzword, value: (buzzword_counts[random_buzzword][:value] + 1) % 30 } send_event('buzzwords', { items: buzzword_counts.values }) end \ No newline at end of file diff --git a/templates/project/jobs/convergence.rb b/templates/project/jobs/convergence.rb index f66b6a5..1da2a5b 100644 --- a/templates/project/jobs/convergence.rb +++ b/templates/project/jobs/convergence.rb @@ -1,3 +1,4 @@ +# Populate the graph with some random points points = [] (1..10).each do |i| points << { x: i, y: rand(50) } diff --git a/templates/project/jobs/sample.rb b/templates/project/jobs/sample.rb index 2314dc2..1fe008d 100644 --- a/templates/project/jobs/sample.rb +++ b/templates/project/jobs/sample.rb @@ -1,9 +1,13 @@ current_valuation = 0 +current_karma = 0 SCHEDULER.every '2s' do last_valuation = current_valuation + last_karma = current_karma current_valuation = rand(100) + current_karma = rand(200000) send_event('valuation', { current: current_valuation, last: last_valuation }) + send_event('karma', { current: current_karma, last: last_karma }) send_event('synergy', { value: rand(100) }) end \ No newline at end of file diff --git a/templates/project/jobs/twitter.rb b/templates/project/jobs/twitter.rb new file mode 100644 index 0000000..9359a89 --- /dev/null +++ b/templates/project/jobs/twitter.rb @@ -0,0 +1,17 @@ +require 'net/http' +require 'json' + +search_term = URI::encode('#todayilearned') + +SCHEDULER.every '10m', :first_in => 0 do |job| + http = Net::HTTP.new('search.twitter.com') + response = http.request(Net::HTTP::Get.new("/search.json?q=#{search_term}")) + tweets = JSON.parse(response.body)["results"] + if tweets + tweets.map! do |tweet| + { name: tweet['from_user'], body: tweet['text'], avatar: tweet['profile_image_url_https'] } + end + + send_event('twitter_mentions', comments: tweets) + end +end \ No newline at end of file diff --git a/templates/project/public/.empty_directory b/templates/project/public/.empty_directory deleted file mode 100644 index 3da7f49..0000000 --- a/templates/project/public/.empty_directory +++ /dev/null @@ -1 +0,0 @@ -.empty_directory \ No newline at end of file diff --git a/templates/project/widgets/clock/clock.coffee b/templates/project/widgets/clock/clock.coffee new file mode 100644 index 0000000..cd6b116 --- /dev/null +++ b/templates/project/widgets/clock/clock.coffee @@ -0,0 +1,18 @@ +class Dashing.Clock extends Dashing.Widget + + ready: -> + setInterval(@startTime, 500) + + startTime: => + today = new Date() + + h = today.getHours() + m = today.getMinutes() + s = today.getSeconds() + m = @formatTime(m) + s = @formatTime(s) + @set('time', h + ":" + m + ":" + s) + @set('date', today.toDateString()) + + formatTime: (i) -> + if i < 10 then "0" + i else i \ No newline at end of file diff --git a/templates/project/widgets/clock/clock.html b/templates/project/widgets/clock/clock.html new file mode 100644 index 0000000..06759d4 --- /dev/null +++ b/templates/project/widgets/clock/clock.html @@ -0,0 +1,2 @@ +

    +

    \ No newline at end of file diff --git a/templates/project/widgets/clock/clock.scss b/templates/project/widgets/clock/clock.scss new file mode 100644 index 0000000..831ea94 --- /dev/null +++ b/templates/project/widgets/clock/clock.scss @@ -0,0 +1,13 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$background-color: #dc5945; + +// ---------------------------------------------------------------------------- +// Widget-clock styles +// ---------------------------------------------------------------------------- +.widget-clock { + + background-color: $background-color; + +} \ No newline at end of file diff --git a/templates/project/widgets/comments/comments.coffee b/templates/project/widgets/comments/comments.coffee new file mode 100644 index 0000000..1e81b56 --- /dev/null +++ b/templates/project/widgets/comments/comments.coffee @@ -0,0 +1,24 @@ +class Dashing.Comments extends Dashing.Widget + + @accessor 'quote', -> + "“#{@get('current_comment')?.body}”" + + ready: -> + @currentIndex = 0 + @commentElem = $(@node).find('.comment-container') + @nextComment() + @startCarousel() + + onData: (data) -> + @currentIndex = 0 + + startCarousel: -> + setInterval(@nextComment, 8000) + + nextComment: => + comments = @get('comments') + if comments + @commentElem.fadeOut => + @currentIndex = (@currentIndex + 1) % comments.length + @set 'current_comment', comments[@currentIndex] + @commentElem.fadeIn() \ No newline at end of file diff --git a/templates/project/widgets/comments/comments.html b/templates/project/widgets/comments/comments.html new file mode 100644 index 0000000..844800f --- /dev/null +++ b/templates/project/widgets/comments/comments.html @@ -0,0 +1,7 @@ +

    +
    +

    +

    +
    + +

    \ No newline at end of file diff --git a/templates/project/widgets/comments/comments.scss b/templates/project/widgets/comments/comments.scss new file mode 100644 index 0000000..40e2a6b --- /dev/null +++ b/templates/project/widgets/comments/comments.scss @@ -0,0 +1,33 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$background-color: #eb9c3c; + +$title-color: rgba(255, 255, 255, 0.7); +$moreinfo-color: rgba(255, 255, 255, 0.7); + +// ---------------------------------------------------------------------------- +// Widget-comment styles +// ---------------------------------------------------------------------------- +.widget-comments { + + background-color: $background-color; + + .title { + color: $title-color; + margin-bottom: 15px; + } + + .name { + padding-left: 5px; + } + + .comment-container { + display: none; + } + + .more-info { + color: $moreinfo-color; + } + +} \ No newline at end of file diff --git a/templates/project/widgets/graph/graph.coffee b/templates/project/widgets/graph/graph.coffee index 8b56a87..9b2eeec 100644 --- a/templates/project/widgets/graph/graph.coffee +++ b/templates/project/widgets/graph/graph.coffee @@ -1,22 +1,32 @@ class Dashing.Graph extends Dashing.Widget @accessor 'current', -> + return @get('displayedValue') if @get('displayedValue') points = @get('points') if points points[points.length - 1].y ready: -> + container = $(@node).parent() + # Gross hacks. Let's fix this. + width = (Dashing.widget_base_dimensions[0] * container.data("sizex")) + Dashing.widget_margins[0] * 2 * (container.data("sizex") - 1) + height = (Dashing.widget_base_dimensions[1] * container.data("sizey")) @graph = new Rickshaw.Graph( element: @node - width: $(@node).parent().width() + width: width + height: height series: [ { color: "#fff", - data: [{ x: 0, y: 0}] + data: [{x:0, y:0}] } ] ) + + @graph.series[0].data = @get('points') if @get('points') + x_axis = new Rickshaw.Graph.Axis.Time(graph: @graph) + y_axis = new Rickshaw.Graph.Axis.Y(graph: @graph, tickFormat: Rickshaw.Fixtures.Number.formatKMBT) @graph.render() onData: (data) -> diff --git a/templates/project/widgets/graph/graph.html b/templates/project/widgets/graph/graph.html index 8680efb..d1794db 100644 --- a/templates/project/widgets/graph/graph.html +++ b/templates/project/widgets/graph/graph.html @@ -1,5 +1,5 @@

    -

    +

    -

    \ No newline at end of file +

    \ No newline at end of file diff --git a/templates/project/widgets/graph/graph.scss b/templates/project/widgets/graph/graph.scss index f2a1e21..71cd4d4 100644 --- a/templates/project/widgets/graph/graph.scss +++ b/templates/project/widgets/graph/graph.scss @@ -1,13 +1,12 @@ // ---------------------------------------------------------------------------- // Sass declarations // ---------------------------------------------------------------------------- -$background-color: #2e864f; -$value-color: #fff; +$background-color: #dc5945; -$title-color: lighten($background-color, 75%); -$moreinfo-color: lighten($background-color, 45%); +$title-color: rgba(255, 255, 255, 0.7); +$moreinfo-color: rgba(255, 255, 255, 0.3); +$tick-color: rgba(0, 0, 0, 0.4); -$graph_color: lighten($background-color, 75%); // ---------------------------------------------------------------------------- // Widget-graph styles @@ -17,14 +16,13 @@ $graph_color: lighten($background-color, 75%); background-color: $background-color; position: relative; + svg { - color: $graph_color; + position: absolute; opacity: 0.4; fill-opacity: 0.4; - position: absolute; - bottom: 0; - left: 0; - right: 0; + left: 0px; + top: 0px; } .title, .value { @@ -36,7 +34,7 @@ $graph_color: lighten($background-color, 75%); color: $title-color; } - .text-moreinfo { + .more-info { color: $moreinfo-color; font-weight: 600; font-size: 20px; @@ -46,6 +44,22 @@ $graph_color: lighten($background-color, 75%); .x_tick { position: absolute; bottom: 0; + .title { + font-size: 20px; + color: $tick-color; + opacity: 0.5; + padding-bottom: 3px; + } + } + + .y_ticks { + font-size: 20px; + fill: $tick-color; + fill-opacity: 1; + } + + .domain { + display: none; } } \ No newline at end of file diff --git a/templates/project/widgets/iframe/iframe.coffee b/templates/project/widgets/iframe/iframe.coffee new file mode 100644 index 0000000..4d4ca9a --- /dev/null +++ b/templates/project/widgets/iframe/iframe.coffee @@ -0,0 +1,9 @@ +class Dashing.Iframe extends Dashing.Widget + + ready: -> + # This is fired when the widget is done being rendered + + onData: (data) -> + # Handle incoming data + # You can access the html node of this widget with `@node` + # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. \ No newline at end of file diff --git a/templates/project/widgets/iframe/iframe.html b/templates/project/widgets/iframe/iframe.html new file mode 100644 index 0000000..bfccba4 --- /dev/null +++ b/templates/project/widgets/iframe/iframe.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/project/widgets/iframe/iframe.scss b/templates/project/widgets/iframe/iframe.scss new file mode 100644 index 0000000..7c757bf --- /dev/null +++ b/templates/project/widgets/iframe/iframe.scss @@ -0,0 +1,8 @@ +.widget-iframe { + padding: 3px 0px 0px 0px !important; + + iframe { + width: 100%; + height: 100%; + } +} \ No newline at end of file diff --git a/templates/project/widgets/image/image.coffee b/templates/project/widgets/image/image.coffee new file mode 100644 index 0000000..418e385 --- /dev/null +++ b/templates/project/widgets/image/image.coffee @@ -0,0 +1,9 @@ +class Dashing.Image extends Dashing.Widget + + ready: -> + # This is fired when the widget is done being rendered + + onData: (data) -> + # Handle incoming data + # You can access the html node of this widget with `@node` + # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. \ No newline at end of file diff --git a/templates/project/widgets/image/image.html b/templates/project/widgets/image/image.html new file mode 100644 index 0000000..cf2b228 --- /dev/null +++ b/templates/project/widgets/image/image.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/templates/project/widgets/image/image.scss b/templates/project/widgets/image/image.scss new file mode 100644 index 0000000..10ca81d --- /dev/null +++ b/templates/project/widgets/image/image.scss @@ -0,0 +1,13 @@ +// ---------------------------------------------------------------------------- +// Sass declarations +// ---------------------------------------------------------------------------- +$background-color: #4b4b4b; + +// ---------------------------------------------------------------------------- +// Widget-image styles +// ---------------------------------------------------------------------------- +.widget-image { + + background-color: $background-color; + +} \ No newline at end of file diff --git a/templates/project/widgets/list/list.coffee b/templates/project/widgets/list/list.coffee index 3ca892b..3cbf7a1 100644 --- a/templates/project/widgets/list/list.coffee +++ b/templates/project/widgets/list/list.coffee @@ -1,13 +1,6 @@ class Dashing.List extends Dashing.Widget - @accessor 'current', Dashing.AnimatedValue - - @accessor 'arrow', -> - if @get('last') - if parseInt(@get('current')) > parseInt(@get('last')) then 'arrow-up' else 'arrow-down' - ready: -> - Batman.setImmediate => - if @get('unordered') - $(@node).find('ol').remove() - else - $(@node).find('ul').remove() \ No newline at end of file + if @get('unordered') + $(@node).find('ol').remove() + else + $(@node).find('ul').remove() \ No newline at end of file diff --git a/templates/project/widgets/list/list.html b/templates/project/widgets/list/list.html index cc90d42..86752bf 100644 --- a/templates/project/widgets/list/list.html +++ b/templates/project/widgets/list/list.html @@ -12,4 +12,7 @@
  • -
\ No newline at end of file + + +

+

\ No newline at end of file diff --git a/templates/project/widgets/list/list.scss b/templates/project/widgets/list/list.scss index 098200d..90b6c84 100644 --- a/templates/project/widgets/list/list.scss +++ b/templates/project/widgets/list/list.scss @@ -1,12 +1,12 @@ // ---------------------------------------------------------------------------- // Sass declarations // ---------------------------------------------------------------------------- - $background-color: #12b0c5; $value-color: #fff; -$title-color: lighten($background-color, 45%); -$label-color: lighten($background-color, 45%); +$title-color: rgba(255, 255, 255, 0.7); +$label-color: rgba(255, 255, 255, 0.7); +$moreinfo-color: rgba(255, 255, 255, 0.7); // ---------------------------------------------------------------------------- // Widget-list styles @@ -49,4 +49,12 @@ $label-color: lighten($background-color, 45%); color: $value-color; } + .updated-at { + color: rgba(0, 0, 0, 0.3); + } + + .more-info { + color: $moreinfo-color; + } + } \ No newline at end of file diff --git a/templates/project/widgets/meter/meter.html b/templates/project/widgets/meter/meter.html index 6051d2f..7d51b15 100644 --- a/templates/project/widgets/meter/meter.html +++ b/templates/project/widgets/meter/meter.html @@ -2,4 +2,6 @@ -

\ No newline at end of file +

+ +

\ No newline at end of file diff --git a/templates/project/widgets/meter/meter.scss b/templates/project/widgets/meter/meter.scss index dec0cc6..98cf638 100644 --- a/templates/project/widgets/meter/meter.scss +++ b/templates/project/widgets/meter/meter.scss @@ -1,15 +1,12 @@ // ---------------------------------------------------------------------------- // Sass declarations // ---------------------------------------------------------------------------- - $background-color: #9c4274; -$value-color: #fff; -$title-color: lighten($background-color, 75%); -$moreinfo-color: lighten($background-color, 45%); +$title-color: rgba(255, 255, 255, 0.7); +$moreinfo-color: rgba(255, 255, 255, 0.3); -$meter-background: darken($background-color, 10%); -$meter-foreground: lighten($background-color, 75%); +$meter-background: darken($background-color, 15%); // ---------------------------------------------------------------------------- // Widget-meter styles @@ -20,18 +17,19 @@ $meter-foreground: lighten($background-color, 75%); input.meter { background-color: $meter-background; - color: $meter-foreground; + color: #fff; } .title { color: $title-color; } - .text-moreinfo { + .more-info { color: $moreinfo-color; - font-weight: 600; - font-size: 20px; - margin-top: 0; + } + + .updated-at { + color: rgba(0, 0, 0, 0.3); } } \ No newline at end of file diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee index 78e7523..46cd6c2 100644 --- a/templates/project/widgets/number/number.coffee +++ b/templates/project/widgets/number/number.coffee @@ -8,17 +8,13 @@ class Dashing.Number extends Dashing.Widget if last != 0 diff = Math.abs(Math.round((current - last) / last * 100)) "#{diff}%" + else + "" @accessor 'arrow', -> if @get('last') if parseInt(@get('current')) > parseInt(@get('last')) then 'icon-arrow-up' else 'icon-arrow-down' - @accessor 'statusStyle', -> - "status-#{@get('status')}" - - @accessor 'needsAttention', -> - @get('status') == 'warning' || @get('status') == 'danger' - onData: (data) -> if data.status $(@get('node')).addClass("status-#{data.status}") \ No newline at end of file diff --git a/templates/project/widgets/number/number.html b/templates/project/widgets/number/number.html index 6e9a03e..d7eeab9 100644 --- a/templates/project/widgets/number/number.html +++ b/templates/project/widgets/number/number.html @@ -1,9 +1,11 @@ -

+

-

+

- 50% +

-

2012-07-26 10:59AM

\ No newline at end of file +

+ +

diff --git a/templates/project/widgets/number/number.scss b/templates/project/widgets/number/number.scss index d134561..608624b 100644 --- a/templates/project/widgets/number/number.scss +++ b/templates/project/widgets/number/number.scss @@ -1,11 +1,11 @@ // ---------------------------------------------------------------------------- // Sass declarations // ---------------------------------------------------------------------------- -$background-color: #00b1a4; +$background-color: #47bbb3; $value-color: #fff; -$title-color: lighten($background-color, 75%); -$moreinfo-color: lighten($background-color, 45%); +$title-color: rgba(255, 255, 255, 0.7);; +$moreinfo-color: rgba(255, 255, 255, 0.7);; // ---------------------------------------------------------------------------- // Widget-number styles @@ -23,13 +23,17 @@ $moreinfo-color: lighten($background-color, 45%); } .change-rate { - font-weight: 300; + font-weight: 500; font-size: 30px; color: $value-color; } - .text-moreinfo { + .more-info { color: $moreinfo-color; } + + .updated-at { + color: rgba(0, 0, 0, 0.3); + } } \ No newline at end of file diff --git a/templates/project/widgets/text/text.html b/templates/project/widgets/text/text.html index 02bd0f7..45322ca 100644 --- a/templates/project/widgets/text/text.html +++ b/templates/project/widgets/text/text.html @@ -1,5 +1,7 @@

-

+

-

2012-07-26 10:59AM

\ No newline at end of file +

+ +

\ No newline at end of file diff --git a/templates/project/widgets/text/text.scss b/templates/project/widgets/text/text.scss index 4293602..4e6c6e3 100644 --- a/templates/project/widgets/text/text.scss +++ b/templates/project/widgets/text/text.scss @@ -1,11 +1,10 @@ // ---------------------------------------------------------------------------- // Sass declarations // ---------------------------------------------------------------------------- -$background-color: #ec663c;; -$value-color: #fff; +$background-color: #ec663c; -$title-color: lighten($background-color, 40%); -$moreinfo-color: lighten($background-color, 30%); +$title-color: rgba(255, 255, 255, 0.7); +$moreinfo-color: rgba(255, 255, 255, 0.7); // ---------------------------------------------------------------------------- // Widget-text styles @@ -18,8 +17,16 @@ $moreinfo-color: lighten($background-color, 30%); color: $title-color; } - .text-moreinfo { + .more-info { color: $moreinfo-color; } + + .updated-at { + color: rgba(255, 255, 255, 0.7); + } + + &.large h3 { + font-size: 65px; + } } \ No newline at end of file -- cgit v1.2.3 From 76cf77a89a17dd12299a6f4b63c967163ceae39a Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Tue, 30 Oct 2012 11:45:12 -0400 Subject: Make the default port 3030 --- bin/dashing | 5 +++-- templates/project/dashboards/sample.erb | 2 +- templates/project/dashboards/sampletv.erb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/dashing b/bin/dashing index e363ee2..fb1332f 100755 --- a/bin/dashing +++ b/bin/dashing @@ -14,7 +14,7 @@ def send_event(id, data) req = Net::HTTP::Post.new("/widgets/#{id}") req["content-type"] = "application/json" req.body = JSON.unparse(data.merge(:auth_token => Dashing::CLI.auth_token)) - res = Net::HTTP.new('localhost', 3000).start { |http| http.request(req) } + res = Net::HTTP.new('localhost', 3030).start { |http| http.request(req) } puts "Data Sent to #{id}: #{data}" end @@ -61,8 +61,9 @@ module Dashing desc "start", "Starts the server in style!" method_option :job_path, :desc => "Specify the directory where jobs are stored" def start(*args) + port_option = args.include?('-p')? '' : ' -p 3030' args = args.join(" ") - command = "bundle exec thin -R config.ru start #{args}" + command = "bundle exec thin -R config.ru start #{port_option} #{args}" command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] system(command) end diff --git a/templates/project/dashboards/sample.erb b/templates/project/dashboards/sample.erb index ab5cb00..7435b56 100644 --- a/templates/project/dashboards/sample.erb +++ b/templates/project/dashboards/sample.erb @@ -21,5 +21,5 @@
-
Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://localhost:3000/widgets/welcome
+
Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://<%=request.host%>:<%=request.port%>/widgets/welcome
\ No newline at end of file diff --git a/templates/project/dashboards/sampletv.erb b/templates/project/dashboards/sampletv.erb index b52eed7..7ac9112 100644 --- a/templates/project/dashboards/sampletv.erb +++ b/templates/project/dashboards/sampletv.erb @@ -52,5 +52,5 @@ $(function() { -
Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://localhost:3000/widgets/welcome
+
Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://<%=request.host%>:<%=request.port%>/widgets/welcome
\ No newline at end of file -- cgit v1.2.3 From d87442ef06436dfef4c1cdb685c4d6bc9366e272 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Tue, 30 Oct 2012 11:45:20 -0400 Subject: Release 1.0! --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 610de20..d920137 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -1,13 +1,13 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '0.1.3' + s.version = '1.0' s.date = '2012-10-30' s.executables << 'dashing' s.summary = "The exceptionally handsome dashboard framework." s.description = "This framework lets you build & easily layout dashboards with your own custom widgets. Use it to make a status boards for your ops team, or use it to track signups, conversion rates, or whatever else metrics you'd like to see in one spot. Included with the framework are ready-made widgets for you to use or customize. All of this code was extracted out of a project at Shopify that displays dashboards on TVs around the office." - s.authors = ["Daniel Beauchamp"] + s.author = "Daniel Beauchamp" s.email = 'daniel.beauchamp@shopify.com' s.files = ["lib/Dashing.rb"] s.homepage = 'http://shopify.github.com/dashing' -- cgit v1.2.3 From 77d859b096362a71306125d590156921e4f0a10d Mon Sep 17 00:00:00 2001 From: Ryan Seys Date: Tue, 30 Oct 2012 18:59:58 -0400 Subject: Save layout only suggested when layout changes. Closes #3 --- templates/project/assets/javascripts/application.coffee | 1 + .../project/assets/javascripts/dashing.gridster.coffee | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/templates/project/assets/javascripts/application.coffee b/templates/project/assets/javascripts/application.coffee index be030e1..a1cbf3f 100644 --- a/templates/project/assets/javascripts/application.coffee +++ b/templates/project/assets/javascripts/application.coffee @@ -22,3 +22,4 @@ Dashing.on 'ready', -> avoid_overlapped_widgets: !Dashing.customGridsterLayout draggable: stop: Dashing.showGridsterInstructions + start: -> Dashing.currentWidgetPositions = Dashing.getWidgetPositions() diff --git a/templates/project/assets/javascripts/dashing.gridster.coffee b/templates/project/assets/javascripts/dashing.gridster.coffee index 0f6f9a1..e25c561 100644 --- a/templates/project/assets/javascripts/dashing.gridster.coffee +++ b/templates/project/assets/javascripts/dashing.gridster.coffee @@ -13,20 +13,25 @@ Dashing.gridsterLayout = (positions) -> $(widget).attr('data-row', positions[index].row) $(widget).attr('data-col', positions[index].col) +Dashing.getWidgetPositions = -> + $(".gridster ul:first").gridster().data('gridster').serialize() + Dashing.showGridsterInstructions = -> - data = $(".gridster ul:first").gridster().data('gridster').serialize() + newWidgetPositions = Dashing.getWidgetPositions() + + unless JSON.stringify(newWidgetPositions) == JSON.stringify(Dashing.currentWidgetPositions) + Dashing.currentWidgetPositions = newWidgetPositions $('#save-gridster').slideDown() $('#gridster-code').text(" ") - $ -> $('#save-gridster').leanModal() $('#save-gridster').click -> - $('#save-gridster').slideUp() \ No newline at end of file + $('#save-gridster').slideUp() -- cgit v1.2.3 From 837cf50007ef8cbd7ec017d4e8cb67adc5725568 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 14 Nov 2012 12:18:25 -0500 Subject: Set explicit delay for AnimatedNumber filter. Firefox doesn't run SetInterval unless there is a delay specified. Closes #6 --- javascripts/dashing.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index d6d7e22..6662725 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -70,7 +70,7 @@ Dashing.AnimatedValue = num = parseFloat(num) up = to > num num_interval = Math.abs(num - to) / 90 - @[timer] = + @[timer] = setInterval => num = if up then Math.ceil(num+num_interval) else Math.floor(num-num_interval) if (up && num > to) || (!up && num < to) @@ -80,7 +80,8 @@ Dashing.AnimatedValue = delete @[timer] @[k] = num @set k, to - @[k] = num + , 10 + @[k] = num Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} -- cgit v1.2.3 From 694f8d98ad751be221cc3156356b9e452638ce5f Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 28 Nov 2012 12:51:56 -0500 Subject: Specify uf8 encoding in the gemspec. --- dashing.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dashing.gemspec b/dashing.gemspec index d920137..478e895 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -1,3 +1,5 @@ +# -*- encoding: utf-8 -*- + Gem::Specification.new do |s| s.name = 'dashing' s.version = '1.0' -- cgit v1.2.3 From c39be899b629378c0a4e1dd4beab528ebcbffa6e Mon Sep 17 00:00:00 2001 From: Scott Gerring Date: Sat, 3 Nov 2012 13:18:40 +0800 Subject: Display 'last updated' using user's locale. Closes #10 --- javascripts/dashing.coffee | 6 ++++-- lib/dashing.rb | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index 6662725..faf21a0 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -44,8 +44,10 @@ class Dashing.Widget extends Batman.View @accessor 'updatedAtMessage', -> if updatedAt = @get('updatedAt') - timestamp = updatedAt.toString().match(/\d*:\d*/)[0] - "Last updated at #{timestamp}" + timestamp = new Date(updatedAt * 1000) + hours = timestamp.getHours() + minutes = ("0" + timestamp.getMinutes()).slice(-2) + "Last updated at #{hours}:#{minutes}" @::on 'ready', -> Dashing.Widget.fire 'ready' diff --git a/lib/dashing.rb b/lib/dashing.rb index 7d066cc..37dc54d 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -81,7 +81,7 @@ end def send_event(id, body) body["id"] = id - body["updatedAt"] = Time.now + body["updatedAt"] = Time.now.to_i event = format_event(body.to_json) settings.history[id] = event settings.connections.each { |out| out << event } -- cgit v1.2.3 From 5934a2729d93d24e67016dc4dd101c689378ae33 Mon Sep 17 00:00:00 2001 From: Ayrton De Craene Date: Fri, 16 Nov 2012 11:18:06 +0100 Subject: Removes whitespace :scissors: --- templates/project/widgets/clock/clock.scss | 6 +++--- templates/project/widgets/comments/comments.coffee | 2 +- templates/project/widgets/comments/comments.html | 4 ++-- templates/project/widgets/comments/comments.scss | 10 +++++----- templates/project/widgets/graph/graph.html | 2 +- templates/project/widgets/graph/graph.scss | 8 ++++---- templates/project/widgets/iframe/iframe.coffee | 2 +- templates/project/widgets/iframe/iframe.html | 2 +- templates/project/widgets/iframe/iframe.scss | 4 ++-- templates/project/widgets/image/image.coffee | 2 +- templates/project/widgets/image/image.html | 2 +- templates/project/widgets/image/image.scss | 4 ++-- templates/project/widgets/list/list.coffee | 2 +- templates/project/widgets/list/list.html | 2 +- templates/project/widgets/list/list.scss | 8 ++++---- templates/project/widgets/meter/meter.coffee | 2 +- templates/project/widgets/meter/meter.html | 2 +- templates/project/widgets/meter/meter.scss | 12 ++++++------ templates/project/widgets/number/number.coffee | 2 +- templates/project/widgets/number/number.html | 2 +- templates/project/widgets/number/number.scss | 10 +++++----- templates/project/widgets/text/text.coffee | 2 +- templates/project/widgets/text/text.html | 2 +- templates/project/widgets/text/text.scss | 10 +++++----- 24 files changed, 52 insertions(+), 52 deletions(-) diff --git a/templates/project/widgets/clock/clock.scss b/templates/project/widgets/clock/clock.scss index 831ea94..19e91bf 100644 --- a/templates/project/widgets/clock/clock.scss +++ b/templates/project/widgets/clock/clock.scss @@ -6,8 +6,8 @@ $background-color: #dc5945; // ---------------------------------------------------------------------------- // Widget-clock styles // ---------------------------------------------------------------------------- -.widget-clock { +.widget-clock { background-color: $background-color; - -} \ No newline at end of file + +} diff --git a/templates/project/widgets/comments/comments.coffee b/templates/project/widgets/comments/comments.coffee index 1e81b56..ff659ec 100644 --- a/templates/project/widgets/comments/comments.coffee +++ b/templates/project/widgets/comments/comments.coffee @@ -21,4 +21,4 @@ class Dashing.Comments extends Dashing.Widget @commentElem.fadeOut => @currentIndex = (@currentIndex + 1) % comments.length @set 'current_comment', comments[@currentIndex] - @commentElem.fadeIn() \ No newline at end of file + @commentElem.fadeIn() diff --git a/templates/project/widgets/comments/comments.html b/templates/project/widgets/comments/comments.html index 844800f..898d2f6 100644 --- a/templates/project/widgets/comments/comments.html +++ b/templates/project/widgets/comments/comments.html @@ -1,7 +1,7 @@

-

+

-

\ No newline at end of file +

diff --git a/templates/project/widgets/comments/comments.scss b/templates/project/widgets/comments/comments.scss index 40e2a6b..2ace30e 100644 --- a/templates/project/widgets/comments/comments.scss +++ b/templates/project/widgets/comments/comments.scss @@ -9,11 +9,11 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); // ---------------------------------------------------------------------------- // Widget-comment styles // ---------------------------------------------------------------------------- -.widget-comments { +.widget-comments { background-color: $background-color; - - .title { + + .title { color: $title-color; margin-bottom: 15px; } @@ -29,5 +29,5 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); .more-info { color: $moreinfo-color; } - -} \ No newline at end of file + +} diff --git a/templates/project/widgets/graph/graph.html b/templates/project/widgets/graph/graph.html index d1794db..456dd0f 100644 --- a/templates/project/widgets/graph/graph.html +++ b/templates/project/widgets/graph/graph.html @@ -2,4 +2,4 @@

-

\ No newline at end of file +

diff --git a/templates/project/widgets/graph/graph.scss b/templates/project/widgets/graph/graph.scss index 71cd4d4..1000b6f 100644 --- a/templates/project/widgets/graph/graph.scss +++ b/templates/project/widgets/graph/graph.scss @@ -11,7 +11,7 @@ $tick-color: rgba(0, 0, 0, 0.4); // ---------------------------------------------------------------------------- // Widget-graph styles // ---------------------------------------------------------------------------- -.widget-graph { +.widget-graph { background-color: $background-color; position: relative; @@ -30,7 +30,7 @@ $tick-color: rgba(0, 0, 0, 0.4); z-index: 99; } - .title { + .title { color: $title-color; } @@ -51,7 +51,7 @@ $tick-color: rgba(0, 0, 0, 0.4); padding-bottom: 3px; } } - + .y_ticks { font-size: 20px; fill: $tick-color; @@ -62,4 +62,4 @@ $tick-color: rgba(0, 0, 0, 0.4); display: none; } -} \ No newline at end of file +} diff --git a/templates/project/widgets/iframe/iframe.coffee b/templates/project/widgets/iframe/iframe.coffee index 4d4ca9a..e3ee947 100644 --- a/templates/project/widgets/iframe/iframe.coffee +++ b/templates/project/widgets/iframe/iframe.coffee @@ -6,4 +6,4 @@ class Dashing.Iframe extends Dashing.Widget onData: (data) -> # Handle incoming data # You can access the html node of this widget with `@node` - # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. \ No newline at end of file + # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. diff --git a/templates/project/widgets/iframe/iframe.html b/templates/project/widgets/iframe/iframe.html index bfccba4..385f6da 100644 --- a/templates/project/widgets/iframe/iframe.html +++ b/templates/project/widgets/iframe/iframe.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/templates/project/widgets/iframe/iframe.scss b/templates/project/widgets/iframe/iframe.scss index 7c757bf..6827a1b 100644 --- a/templates/project/widgets/iframe/iframe.scss +++ b/templates/project/widgets/iframe/iframe.scss @@ -1,8 +1,8 @@ -.widget-iframe { +.widget-iframe { padding: 3px 0px 0px 0px !important; iframe { width: 100%; height: 100%; } -} \ No newline at end of file +} diff --git a/templates/project/widgets/image/image.coffee b/templates/project/widgets/image/image.coffee index 418e385..c3892c0 100644 --- a/templates/project/widgets/image/image.coffee +++ b/templates/project/widgets/image/image.coffee @@ -6,4 +6,4 @@ class Dashing.Image extends Dashing.Widget onData: (data) -> # Handle incoming data # You can access the html node of this widget with `@node` - # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. \ No newline at end of file + # Example: $(@node).fadeOut().fadeIn() will make the node flash each time data comes in. diff --git a/templates/project/widgets/image/image.html b/templates/project/widgets/image/image.html index cf2b228..41a88eb 100644 --- a/templates/project/widgets/image/image.html +++ b/templates/project/widgets/image/image.html @@ -1 +1 @@ - \ No newline at end of file + diff --git a/templates/project/widgets/image/image.scss b/templates/project/widgets/image/image.scss index 10ca81d..0b1a316 100644 --- a/templates/project/widgets/image/image.scss +++ b/templates/project/widgets/image/image.scss @@ -6,8 +6,8 @@ $background-color: #4b4b4b; // ---------------------------------------------------------------------------- // Widget-image styles // ---------------------------------------------------------------------------- -.widget-image { +.widget-image { background-color: $background-color; -} \ No newline at end of file +} diff --git a/templates/project/widgets/list/list.coffee b/templates/project/widgets/list/list.coffee index 3cbf7a1..0028073 100644 --- a/templates/project/widgets/list/list.coffee +++ b/templates/project/widgets/list/list.coffee @@ -3,4 +3,4 @@ class Dashing.List extends Dashing.Widget if @get('unordered') $(@node).find('ol').remove() else - $(@node).find('ul').remove() \ No newline at end of file + $(@node).find('ul').remove() diff --git a/templates/project/widgets/list/list.html b/templates/project/widgets/list/list.html index 86752bf..07e0471 100644 --- a/templates/project/widgets/list/list.html +++ b/templates/project/widgets/list/list.html @@ -15,4 +15,4 @@

-

\ No newline at end of file +

diff --git a/templates/project/widgets/list/list.scss b/templates/project/widgets/list/list.scss index 90b6c84..bce7010 100644 --- a/templates/project/widgets/list/list.scss +++ b/templates/project/widgets/list/list.scss @@ -11,12 +11,12 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); // ---------------------------------------------------------------------------- // Widget-list styles // ---------------------------------------------------------------------------- -.widget-list { +.widget-list { background-color: $background-color; vertical-align: top; - .title { + .title { color: $title-color; } @@ -39,7 +39,7 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); } .label { - color: $label-color; + color: $label-color; } .value { @@ -57,4 +57,4 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); color: $moreinfo-color; } -} \ No newline at end of file +} diff --git a/templates/project/widgets/meter/meter.coffee b/templates/project/widgets/meter/meter.coffee index 0e0a8ad..b823ec7 100644 --- a/templates/project/widgets/meter/meter.coffee +++ b/templates/project/widgets/meter/meter.coffee @@ -11,4 +11,4 @@ class Dashing.Meter extends Dashing.Widget meter = $(@node).find(".meter") meter.attr("data-bgcolor", meter.css("background-color")) meter.attr("data-fgcolor", meter.css("color")) - meter.knob() \ No newline at end of file + meter.knob() diff --git a/templates/project/widgets/meter/meter.html b/templates/project/widgets/meter/meter.html index 7d51b15..16f1f06 100644 --- a/templates/project/widgets/meter/meter.html +++ b/templates/project/widgets/meter/meter.html @@ -4,4 +4,4 @@

-

\ No newline at end of file +

diff --git a/templates/project/widgets/meter/meter.scss b/templates/project/widgets/meter/meter.scss index 98cf638..da9ff0b 100644 --- a/templates/project/widgets/meter/meter.scss +++ b/templates/project/widgets/meter/meter.scss @@ -11,16 +11,16 @@ $meter-background: darken($background-color, 15%); // ---------------------------------------------------------------------------- // Widget-meter styles // ---------------------------------------------------------------------------- -.widget-meter { +.widget-meter { background-color: $background-color; - - input.meter { + + input.meter { background-color: $meter-background; color: #fff; } - .title { + .title { color: $title-color; } @@ -31,5 +31,5 @@ $meter-background: darken($background-color, 15%); .updated-at { color: rgba(0, 0, 0, 0.3); } - -} \ No newline at end of file + +} diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee index 46cd6c2..c288dd7 100644 --- a/templates/project/widgets/number/number.coffee +++ b/templates/project/widgets/number/number.coffee @@ -17,4 +17,4 @@ class Dashing.Number extends Dashing.Widget onData: (data) -> if data.status - $(@get('node')).addClass("status-#{data.status}") \ No newline at end of file + $(@get('node')).addClass("status-#{data.status}") diff --git a/templates/project/widgets/number/number.html b/templates/project/widgets/number/number.html index d7eeab9..45e601b 100644 --- a/templates/project/widgets/number/number.html +++ b/templates/project/widgets/number/number.html @@ -2,7 +2,7 @@

-

+

diff --git a/templates/project/widgets/number/number.scss b/templates/project/widgets/number/number.scss index 608624b..292f8cc 100644 --- a/templates/project/widgets/number/number.scss +++ b/templates/project/widgets/number/number.scss @@ -10,11 +10,11 @@ $moreinfo-color: rgba(255, 255, 255, 0.7);; // ---------------------------------------------------------------------------- // Widget-number styles // ---------------------------------------------------------------------------- -.widget-number { +.widget-number { background-color: $background-color; - - .title { + + .title { color: $title-color; } @@ -35,5 +35,5 @@ $moreinfo-color: rgba(255, 255, 255, 0.7);; .updated-at { color: rgba(0, 0, 0, 0.3); } - -} \ No newline at end of file + +} diff --git a/templates/project/widgets/text/text.coffee b/templates/project/widgets/text/text.coffee index 05974b8..1741d8b 100644 --- a/templates/project/widgets/text/text.coffee +++ b/templates/project/widgets/text/text.coffee @@ -1 +1 @@ -class Dashing.Text extends Dashing.Widget \ No newline at end of file +class Dashing.Text extends Dashing.Widget diff --git a/templates/project/widgets/text/text.html b/templates/project/widgets/text/text.html index 45322ca..7aeb66d 100644 --- a/templates/project/widgets/text/text.html +++ b/templates/project/widgets/text/text.html @@ -4,4 +4,4 @@

-

\ No newline at end of file +

diff --git a/templates/project/widgets/text/text.scss b/templates/project/widgets/text/text.scss index 4e6c6e3..45d790e 100644 --- a/templates/project/widgets/text/text.scss +++ b/templates/project/widgets/text/text.scss @@ -9,11 +9,11 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); // ---------------------------------------------------------------------------- // Widget-text styles // ---------------------------------------------------------------------------- -.widget-text { +.widget-text { background-color: $background-color; - - .title { + + .title { color: $title-color; } @@ -24,9 +24,9 @@ $moreinfo-color: rgba(255, 255, 255, 0.7); .updated-at { color: rgba(255, 255, 255, 0.7); } - + &.large h3 { font-size: 65px; } -} \ No newline at end of file +} -- cgit v1.2.3 From 58e971454d5c84dc7c0a1656c9dce3ec00bc75a0 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 5 Dec 2012 23:50:20 -0500 Subject: Update readme to include a description --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cdcc722..bbd047d 100644 --- a/README.md +++ b/README.md @@ -1 +1,8 @@ -Check out the [Homepage](http://shopify.github.com/dashing) \ No newline at end of file +# [Dashing](http://shopify.github.com/dashing) + +Dashing is a Sinatra based framework that lets you build beautiful dashboards. It looks especially great on TVs. + +[Check out the homepage](http://shopify.github.com/dashing). + +# License +Distributed under the MIT license -- cgit v1.2.3 From b32636b45b376ddf4da23f10bd9c8b5025f39864 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 5 Dec 2012 23:53:16 -0500 Subject: Added link to MIT license in readme. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbd047d..9e0efef 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,4 @@ Dashing is a Sinatra based framework that lets you build beautiful dashboards. I [Check out the homepage](http://shopify.github.com/dashing). # License -Distributed under the MIT license +Distributed under the [MIT license](https://github.com/Shopify/dashing/blob/master/MIT-LICENSE) -- cgit v1.2.3 From baccda3dfc9d16493becea6261eb65459d860e68 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Wed, 12 Dec 2012 10:04:26 -0500 Subject: Correctly removes old status classes on the number widget when updating the status --- templates/project/widgets/number/number.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee index c288dd7..3ada5a6 100644 --- a/templates/project/widgets/number/number.coffee +++ b/templates/project/widgets/number/number.coffee @@ -17,4 +17,4 @@ class Dashing.Number extends Dashing.Widget onData: (data) -> if data.status - $(@get('node')).addClass("status-#{data.status}") + $(@get('node')).removeClass("status-danger status-warning").addClass("status-#{data.status}") -- cgit v1.2.3 From efc78f648a76ccc9421e3fc0a16e9f6c6448b346 Mon Sep 17 00:00:00 2001 From: Tim Santeford Date: Thu, 6 Dec 2012 01:10:48 -0800 Subject: Prevents duplicate widget event notifications --- javascripts/dashing.coffee | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index faf21a0..ebf5c0a 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -100,12 +100,13 @@ source.addEventListener 'error', (e)-> source.addEventListener 'message', (e) => data = JSON.parse(e.data) - if Dashing.debugMode - console.log("Received data for #{data.id}", data) - lastEvents[data.id] = data - if widgets[data.id]?.length > 0 - for widget in widgets[data.id] - widget.receiveData(data) + if lastEvents[data.id]?.updatedAt != data.updatedAt + if Dashing.debugMode + console.log("Received data for #{data.id}", data) + lastEvents[data.id] = data + if widgets[data.id]?.length > 0 + for widget in widgets[data.id] + widget.receiveData(data) $(document).ready -> -- cgit v1.2.3 From 27338212e6347bebed1cbf08963a9af110368b76 Mon Sep 17 00:00:00 2001 From: Kevin Thompson Date: Sun, 16 Dec 2012 23:47:00 -0800 Subject: Establish test suite. --- Rakefile | 10 ++++++++++ test/cli_test.rb | 20 ++++++++++++++++++++ test/test_helper.rb | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 Rakefile create mode 100644 test/cli_test.rb create mode 100644 test/test_helper.rb diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..765e5bd --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require 'rubygems' +require 'rake' + +require 'rake/testtask' +Rake::TestTask.new(:test) do |test| + test.libs << 'lib' << 'test' + test.pattern = 'test/**/*_test.rb' +end + +task :default => [:test] \ No newline at end of file diff --git a/test/cli_test.rb b/test/cli_test.rb new file mode 100644 index 0000000..4dc1eb3 --- /dev/null +++ b/test/cli_test.rb @@ -0,0 +1,20 @@ +require 'test_helper' +silent{ load 'bin/dashing' } + +module Thor::Actions + def source_paths + [File.join(File.expand_path(File.dirname(__FILE__)), '../templates')] + end +end + +class CliTest < Dashing::Test + + def test_project_directory_created + temp do |dir| + cli = Dashing::CLI.new + silent{ cli.new 'Dashboard' } + assert Dir.exist?(File.join(dir,'dashboard')), 'Dashing directory was not created.' + end + end + +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..d2337c5 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,34 @@ +require 'rack/test' +require 'stringio' +require 'test/unit' +require 'tmpdir' + +ENV['RACK_ENV'] = 'test' +WORKING_DIRECTORY = Dir.pwd.freeze +ARGV.clear + +def silent + _stdout = $stdout + $stdout = mock = StringIO.new + begin + yield + ensure + $stdout = _stdout + end +end + +def temp + path = File.expand_path "#{Dir.tmpdir}/#{Time.now.to_i}#{rand(1000)}/" + FileUtils.mkdir_p path + Dir.chdir path + yield path +ensure + Dir.chdir WORKING_DIRECTORY + FileUtils.rm_rf(path) if File.exists?(path) +end + +module Dashing + class Test < Test::Unit::TestCase + include Rack::Test::Methods + end +end \ No newline at end of file -- cgit v1.2.3 From 264ce7e1b3ccdb5a900842c66831bd999b03090d Mon Sep 17 00:00:00 2001 From: David Underwood Date: Sat, 29 Dec 2012 20:06:17 +0000 Subject: Makes the status class removal more flexible as suggested by @crcastle --- templates/project/widgets/number/number.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee index 3ada5a6..645ee7f 100644 --- a/templates/project/widgets/number/number.coffee +++ b/templates/project/widgets/number/number.coffee @@ -17,4 +17,8 @@ class Dashing.Number extends Dashing.Widget onData: (data) -> if data.status - $(@get('node')).removeClass("status-danger status-warning").addClass("status-#{data.status}") + # clear existing "status-*" classes + $(@get('node')).attr 'class', (i,c) -> + c.replace /\bstatus-\S+/g, '' + # add new class + $(@get('node')).addClass "status-#{data.status}" -- cgit v1.2.3 From cdc1a5fcf994bee8d05bc48b2959b475448bfa12 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Thu, 10 Jan 2013 23:50:15 -0500 Subject: Update to 1.0.2. Specify dependency on rack <= 1.4.2 until Sinatra supports 1.4.2+ --- dashing.gemspec | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 478e895..0199fda 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0' - s.date = '2012-10-30' + s.version = '1.0.2' + s.date = '2013-01-10' s.executables << 'dashing' @@ -24,5 +24,6 @@ Gem::Specification.new do |s| s.add_dependency('rufus-scheduler') s.add_dependency('thor') s.add_dependency('sprockets') + s.add_dependency('rack', ['>= 1.3.6', '< 1.4.2']) # Use this temporarily until sinatra supports Rack 1.4.2+ end \ No newline at end of file -- cgit v1.2.3 From 17ef11ebf1ba22c63cfee4b668f314d69d9bd684 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Thu, 24 Jan 2013 17:14:26 -0500 Subject: Allow overriding the 'updatedAt' field. This is useful if you want to show the freshness of the data instead of when the job was last run. --- lib/dashing.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 37dc54d..04e4cee 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -80,8 +80,8 @@ def production? end def send_event(id, body) - body["id"] = id - body["updatedAt"] = Time.now.to_i + body[:id] = id + body[:updatedAt] ||= Time.now.to_i event = format_event(body.to_json) settings.history[id] = event settings.connections.each { |out| out << event } -- cgit v1.2.3 From 7a064c4193a2590527b1848adc56fc9d340c7851 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Fri, 8 Feb 2013 12:33:59 -0500 Subject: No longer clamp rack version to 1.4.2. People should update to 1.5.2+ --- dashing.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 0199fda..dc5aca9 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0.2' - s.date = '2013-01-10' + s.version = '1.0.3' + s.date = '2013-02-07' s.executables << 'dashing' @@ -24,6 +24,6 @@ Gem::Specification.new do |s| s.add_dependency('rufus-scheduler') s.add_dependency('thor') s.add_dependency('sprockets') - s.add_dependency('rack', ['>= 1.3.6', '< 1.4.2']) # Use this temporarily until sinatra supports Rack 1.4.2+ + s.add_dependency('rack') end \ No newline at end of file -- cgit v1.2.3 From 6dcda5d7cd26514cac1b18438af7913105e68f00 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 13 Feb 2013 21:32:34 -0500 Subject: Added the public directory for serving static assets. This allows for stuff like favicons and custom 404/500 pages. --- lib/dashing.rb | 10 +++++++++- templates/project/assets/images/favicon.ico | Bin 5430 -> 0 bytes templates/project/public/404.html | 26 ++++++++++++++++++++++++++ templates/project/public/favicon.ico | Bin 0 -> 5430 bytes 4 files changed, 35 insertions(+), 1 deletion(-) delete mode 100644 templates/project/assets/images/favicon.ico create mode 100644 templates/project/public/404.html create mode 100644 templates/project/public/favicon.ico diff --git a/lib/dashing.rb b/lib/dashing.rb index 04e4cee..bae4c29 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -49,7 +49,11 @@ end get '/:dashboard' do protected! - erb params[:dashboard].to_sym + if File.exist? File.join(settings.views, "#{params[:dashboard]}.erb") + erb params[:dashboard].to_sym + else + halt 404 + end end get '/views/:widget?.html' do @@ -71,6 +75,10 @@ post '/widgets/:id' do end end +not_found do + send_file File.join(settings.public_folder, '404.html') +end + def development? ENV['RACK_ENV'] == 'development' end diff --git a/templates/project/assets/images/favicon.ico b/templates/project/assets/images/favicon.ico deleted file mode 100644 index 29a408f..0000000 Binary files a/templates/project/assets/images/favicon.ico and /dev/null differ diff --git a/templates/project/public/404.html b/templates/project/public/404.html new file mode 100644 index 0000000..1a8f334 --- /dev/null +++ b/templates/project/public/404.html @@ -0,0 +1,26 @@ + + + + This Dashboard doesn't exist. + + + + + +
+

Drats! That Dashboard doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+ + \ No newline at end of file diff --git a/templates/project/public/favicon.ico b/templates/project/public/favicon.ico new file mode 100644 index 0000000..29a408f Binary files /dev/null and b/templates/project/public/favicon.ico differ -- cgit v1.2.3 From 27f124a0b7af7035798053945560f0fa44956962 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 13 Feb 2013 23:31:29 -0500 Subject: Bump to version 1.0.4 --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index dc5aca9..915819a 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0.3' - s.date = '2013-02-07' + s.version = '1.0.4' + s.date = '2013-02-13' s.executables << 'dashing' -- cgit v1.2.3 From 4e19979f72ce5ccf11a0aae4bc74275191eb9b83 Mon Sep 17 00:00:00 2001 From: John Tajima Date: Tue, 12 Mar 2013 18:03:18 +0000 Subject: update to latest batman --- javascripts/batman.jquery.js | 6 +- javascripts/batman.js | 3331 +++++++++++++++++++++++++++++------------- 2 files changed, 2326 insertions(+), 1011 deletions(-) diff --git a/javascripts/batman.jquery.js b/javascripts/batman.jquery.js index 0716b0e..30843e8 100644 --- a/javascripts/batman.jquery.js +++ b/javascripts/batman.jquery.js @@ -49,6 +49,9 @@ Batman.DOM.willInsertNode(child); jQuery(parent).append(child); return Batman.DOM.didInsertNode(child); + }, + innerText: function(node) { + return jQuery(node).text(); } }); @@ -66,8 +69,7 @@ }; Batman.Request.prototype._prepareOptions = function(data) { - var options, _ref, - _this = this; + var options, _ref, _this = this; options = { url: this.get('url'), type: this.get('method'), diff --git a/javascripts/batman.js b/javascripts/batman.js index c4e5f34..2619c94 100644 --- a/javascripts/batman.js +++ b/javascripts/batman.js @@ -1,18 +1,19 @@ (function() { - var Batman, - __slice = [].slice; + var Batman, __slice = [].slice; Batman = function() { var mixins; mixins = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return (function(func, args, ctor) { ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; + var child = new ctor, + result = func.apply(child, args), + t = typeof result; return t == "object" || t == "function" ? result || child : child; - })(Batman.Object, mixins, function(){}); + })(Batman.Object, mixins, function() {}); }; - Batman.version = '0.13.0'; + Batman.version = '0.14.1'; Batman.config = { pathPrefix: '/', @@ -49,10 +50,129 @@ }).call(this); (function() { - var _implementImmediates, _objectToString, - __slice = [].slice, + var _Batman; + + Batman._Batman = _Batman = (function() { + + function _Batman(object) { + this.object = object; + } + + _Batman.prototype.check = function(object) { + if (object !== this.object) { + object._batman = new Batman._Batman(object); + return false; + } + return true; + }; + + _Batman.prototype.get = function(key) { + var reduction, results; + results = this.getAll(key); + switch (results.length) { + case 0: + return void 0; + case 1: + return results[0]; + default: + reduction = results[0].concat != null ? + function(a, b) { + return a.concat(b); + } : results[0].merge != null ? + function(a, b) { + return a.merge(b); + } : results.every(function(x) { + return typeof x === 'object'; + }) ? (results.unshift({}), function(a, b) { + return Batman.extend(a, b); + }) : void 0; + if (reduction) { + return results.reduceRight(reduction); + } else { + return results; + } + } + }; + + _Batman.prototype.getFirst = function(key) { + var results; + results = this.getAll(key); + return results[0]; + }; + + _Batman.prototype.getAll = function(keyOrGetter) { + var getter, results, val; + if (typeof keyOrGetter === 'function') { + getter = keyOrGetter; + } else { + getter = function(ancestor) { + var _ref; + return (_ref = ancestor._batman) != null ? _ref[keyOrGetter] : void 0; + }; + } + results = this.ancestors(getter); + if (val = getter(this.object)) { + results.unshift(val); + } + return results; + }; + + _Batman.prototype.ancestors = function(getter) { + var ancestor, results, val, _i, _len, _ref; + this._allAncestors || (this._allAncestors = this.allAncestors()); + if (getter) { + results = []; + _ref = this._allAncestors; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + ancestor = _ref[_i]; + val = getter(ancestor); + if (val != null) { + results.push(val); + } + } + return results; + } else { + return this._allAncestors; + } + }; + + _Batman.prototype.allAncestors = function() { + var isClass, parent, proto, results, _ref, _ref1; + results = []; + isClass = !! this.object.prototype; + parent = isClass ? (_ref = this.object.__super__) != null ? _ref.constructor : void 0 : (proto = Object.getPrototypeOf(this.object)) === this.object ? this.object.constructor.__super__ : proto; + if (parent != null) { + if ((_ref1 = parent._batman) != null) { + _ref1.check(parent); + } + results.push(parent); + if (parent._batman != null) { + results = results.concat(parent._batman.allAncestors()); + } + } + return results; + }; + + _Batman.prototype.set = function(key, value) { + return this[key] = value; + }; + + return _Batman; + + })(); + +}).call(this); + +(function() { + var chr, _encodedChars, _encodedCharsPattern, _entityMap, _implementImmediates, _objectToString, _unsafeChars, _unsafeCharsPattern, __slice = [].slice, __hasProp = {}.hasOwnProperty, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + __indexOf = [].indexOf || + function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; Batman.typeOf = function(object) { if (typeof object === 'undefined') { @@ -147,8 +267,6 @@ return false; }; - Batman.setImmediate = Batman.clearImmediate = null; - _implementImmediates = function(container) { var canUsePostMessage, count, functions, getHandle, handler, prefix, tasks; canUsePostMessage = function() { @@ -170,12 +288,9 @@ getHandle = function() { return "go" + (++count); }; - if (container.setImmediate) { + if (container.setImmediate && container.clearImmediate) { Batman.setImmediate = container.setImmediate; - Batman.clearImmediate = container.clearImmediate; - } else if (container.msSetImmediate) { - Batman.setImmediate = msSetImmediate; - Batman.clearImmediate = msClearImmediate; + return Batman.clearImmediate = container.clearImmediate; } else if (canUsePostMessage()) { prefix = 'com.batman.'; functions = new Batman.SimpleHash; @@ -185,7 +300,7 @@ return; } handle = e.data.substring(prefix.length); - return typeof (_base = tasks.unset(handle)) === "function" ? _base() : void 0; + return typeof(_base = tasks.unset(handle)) === "function" ? _base() : void 0; }; if (container.addEventListener) { container.addEventListener('message', handler, false); @@ -198,7 +313,7 @@ container.postMessage(prefix + handle, "*"); return handle; }; - Batman.clearImmediate = function(handle) { + return Batman.clearImmediate = function(handle) { return tasks.unset(handle); }; } else if (typeof document !== 'undefined' && __indexOf.call(document.createElement("script"), "onreadystatechange") >= 0) { @@ -208,7 +323,7 @@ script = document.createElement("script"); script.onreadystatechange = function() { var _base; - if (typeof (_base = tasks.get(handle)) === "function") { + if (typeof(_base = tasks.get(handle)) === "function") { _base(); } script.onreadystatechange = null; @@ -218,7 +333,7 @@ document.documentElement.appendChild(script); return handle; }; - Batman.clearImmediate = function(handle) { + return Batman.clearImmediate = function(handle) { return tasks.unset(handle); }; } else if (typeof process !== "undefined" && process !== null ? process.nextTick : void 0) { @@ -235,19 +350,17 @@ }); return handle; }; - Batman.clearImmediate = function(handle) { + return Batman.clearImmediate = function(handle) { return delete functions[handle]; }; } else { Batman.setImmediate = function(f) { return setTimeout(f, 0); }; - Batman.clearImmediate = function(handle) { + return Batman.clearImmediate = function(handle) { return clearTimeout(handle); }; } - Batman.setImmediate = Batman.setImmediate; - return Batman.clearImmediate = Batman.clearImmediate; }; Batman.setImmediate = function() { @@ -323,22 +436,47 @@ return base; }; + _entityMap = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" + }; + + _unsafeChars = []; + + _encodedChars = []; + + for (chr in _entityMap) { + _unsafeChars.push(chr); + _encodedChars.push(_entityMap[chr]); + } + + _unsafeCharsPattern = new RegExp("[" + (_unsafeChars.join('')) + "]", "g"); + + _encodedCharsPattern = new RegExp("(" + (_encodedChars.join('|')) + ")", "g"); + Batman.escapeHTML = (function() { - var replacements; - replacements = { - "&": "&", - "<": "<", - ">": ">", - "\"": """, - "'": "'" - }; return function(s) { - return ("" + s).replace(/[&<>'"]/g, function(c) { - return replacements[c]; + return ("" + s).replace(_unsafeCharsPattern, function(c) { + return _entityMap[c]; }); }; })(); + Batman.unescapeHTML = (function() { + return function(s) { + var node; + if (s == null) { + return; + } + node = Batman._unescapeHTMLNode || (Batman._unescapeHTMLNode = document.createElement('DIV')); + node.innerHTML = s; + return Batman.DOM.innerText(node); + }; + })(); + Batman.translate = function(x, values) { if (values == null) { values = {}; @@ -369,7 +507,13 @@ (function() { var __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + __indexOf = [].indexOf || + function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; Batman.Inflector = (function() { @@ -419,14 +563,14 @@ return number + "th"; } else { switch (absNumber % 10) { - case 1: - return number + "st"; - case 2: - return number + "nd"; - case 3: - return number + "rd"; - default: - return number + "th"; + case 1: + return number + "st"; + case 2: + return number + "nd"; + case 3: + return number + "rd"; + default: + return number + "th"; } } }; @@ -780,6 +924,9 @@ return value; } }); + }, + deprecated: function(deprecatedName, upgradeString) { + return Batman.developer.warn("" + deprecatedName + " has been deprecated.", upgradeString || ''); } }; @@ -789,107 +936,6 @@ }).call(this); -(function() { - var _Batman; - - Batman._Batman = _Batman = (function() { - - function _Batman(object) { - this.object = object; - } - - _Batman.prototype.check = function(object) { - if (object !== this.object) { - object._batman = new Batman._Batman(object); - return false; - } - return true; - }; - - _Batman.prototype.get = function(key) { - var reduction, results; - results = this.getAll(key); - switch (results.length) { - case 0: - return void 0; - case 1: - return results[0]; - default: - reduction = results[0].concat != null ? function(a, b) { - return a.concat(b); - } : results[0].merge != null ? function(a, b) { - return a.merge(b); - } : results.every(function(x) { - return typeof x === 'object'; - }) ? (results.unshift({}), function(a, b) { - return Batman.extend(a, b); - }) : void 0; - if (reduction) { - return results.reduceRight(reduction); - } else { - return results; - } - } - }; - - _Batman.prototype.getFirst = function(key) { - var results; - results = this.getAll(key); - return results[0]; - }; - - _Batman.prototype.getAll = function(keyOrGetter) { - var getter, results, val; - if (typeof keyOrGetter === 'function') { - getter = keyOrGetter; - } else { - getter = function(ancestor) { - var _ref; - return (_ref = ancestor._batman) != null ? _ref[keyOrGetter] : void 0; - }; - } - results = this.ancestors(getter); - if (val = getter(this.object)) { - results.unshift(val); - } - return results; - }; - - _Batman.prototype.ancestors = function(getter) { - var isClass, parent, proto, results, val, _ref, _ref1; - if (getter == null) { - getter = function(x) { - return x; - }; - } - results = []; - isClass = !!this.object.prototype; - parent = isClass ? (_ref = this.object.__super__) != null ? _ref.constructor : void 0 : (proto = Object.getPrototypeOf(this.object)) === this.object ? this.object.constructor.__super__ : proto; - if (parent != null) { - if ((_ref1 = parent._batman) != null) { - _ref1.check(parent); - } - val = getter(parent); - if (val != null) { - results.push(val); - } - if (parent._batman != null) { - results = results.concat(parent._batman.ancestors(getter)); - } - } - return results; - }; - - _Batman.prototype.set = function(key, value) { - return this[key] = value; - }; - - return _Batman; - - })(); - -}).call(this); - (function() { Batman.Event = (function() { @@ -905,7 +951,6 @@ function Event(base, key) { this.base = base; this.key = key; - this.handlers = []; this._preventCount = 0; } @@ -924,6 +969,7 @@ }; Event.prototype.addHandler = function(handler) { + this.handlers || (this.handlers = []); if (this.handlers.indexOf(handler) === -1) { this.handlers.push(handler); } @@ -935,29 +981,35 @@ Event.prototype.removeHandler = function(handler) { var index; - if ((index = this.handlers.indexOf(handler)) !== -1) { + if (this.handlers && (index = this.handlers.indexOf(handler)) !== -1) { this.handlers.splice(index, 1); } return this; }; Event.prototype.eachHandler = function(iterator) { - var key, _ref, _ref1; - this.handlers.slice().forEach(iterator); - if ((_ref = this.base) != null ? _ref.isEventEmitter : void 0) { + var ancestor, key, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _results; + if ((_ref = this.handlers) != null) { + _ref.slice().forEach(iterator); + } + if ((_ref1 = this.base) != null ? _ref1.isEventEmitter : void 0) { key = this.key; - return (_ref1 = this.base._batman) != null ? _ref1.ancestors(function(ancestor) { - var handlers, _ref2, _ref3; - if (ancestor.isEventEmitter && ((_ref2 = ancestor._batman) != null ? (_ref3 = _ref2.events) != null ? _ref3.hasOwnProperty(key) : void 0 : void 0)) { - handlers = ancestor.event(key).handlers; - return handlers.slice().forEach(iterator); + _ref3 = (_ref2 = this.base._batman) != null ? _ref2.ancestors() : void 0; + _results = []; + for (_i = 0, _len = _ref3.length; _i < _len; _i++) { + ancestor = _ref3[_i]; + if (ancestor.isEventEmitter && ((_ref4 = ancestor._batman) != null ? (_ref5 = _ref4.events) != null ? _ref5.hasOwnProperty(key) : void 0 : void 0)) { + _results.push((_ref6 = ancestor.event(key, false)) != null ? (_ref7 = _ref6.handlers) != null ? _ref7.slice().forEach(iterator) : void 0 : void 0); + } else { + _results.push(void 0); } - }) : void 0; + } + return _results; } }; Event.prototype.clearHandlers = function() { - return this.handlers = []; + return this.handlers = void 0; }; Event.prototype.handlerContext = function() { @@ -991,15 +1043,16 @@ }; Event.prototype.fire = function() { - var args, context; + return this.fireWithContext(this.handlerContext(), arguments); + }; + + Event.prototype.fireWithContext = function(context, args) { if (this.isPrevented() || this._oneShotFired) { return false; } - context = this.handlerContext(); - args = arguments; if (this.oneShot) { this._oneShotFired = true; - this._oneShotArgs = arguments; + this._oneShotArgs = args; } return this.eachHandler(function(handler) { return handler.apply(context, args); @@ -1007,8 +1060,12 @@ }; Event.prototype.allowAndFire = function() { + return this.allowAndFireWithContext(this.handlerContext, arguments); + }; + + Event.prototype.allowAndFireWithContext = function(context, args) { this.allow(); - return this.fire.apply(this, arguments); + return this.fireWithContext(context, args); }; return Event; @@ -1019,7 +1076,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PropertyEvent = (function(_super) { @@ -1052,21 +1120,32 @@ var _ref, _ref1; return (_ref = this._batman) != null ? typeof _ref.get === "function" ? (_ref1 = _ref.get('events')) != null ? _ref1.hasOwnProperty(key) : void 0 : void 0 : void 0; }, - event: function(key) { - var eventClass, events, existingEvent, newEvent, _base; + event: function(key, createEvent) { + var ancestor, eventClass, events, existingEvent, newEvent, _base, _i, _len, _ref, _ref1, _ref2, _ref3; + if (createEvent == null) { + createEvent = true; + } Batman.initializeObject(this); eventClass = this.eventClass || Batman.Event; - events = (_base = this._batman).events || (_base.events = {}); - if (events.hasOwnProperty(key)) { - return existingEvent = events[key]; + if ((_ref = this._batman.events) != null ? _ref.hasOwnProperty(key) : void 0) { + return existingEvent = this._batman.events[key]; } else { - this._batman.ancestors(function(ancestor) { - var _ref, _ref1; - return existingEvent || (existingEvent = (_ref = ancestor._batman) != null ? (_ref1 = _ref.events) != null ? _ref1[key] : void 0 : void 0); - }); - newEvent = events[key] = new eventClass(this, key); - newEvent.oneShot = existingEvent != null ? existingEvent.oneShot : void 0; - return newEvent; + _ref1 = this._batman.ancestors(); + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + ancestor = _ref1[_i]; + existingEvent = (_ref2 = ancestor._batman) != null ? (_ref3 = _ref2.events) != null ? _ref3[key] : void 0 : void 0; + if (existingEvent) { + break; + } + } + if (createEvent || (existingEvent != null ? existingEvent.oneShot : void 0)) { + events = (_base = this._batman).events || (_base.events = {}); + newEvent = events[key] = new eventClass(this, key); + newEvent.oneShot = existingEvent != null ? existingEvent.oneShot : void 0; + return newEvent; + } else { + return existingEvent; + } } }, on: function() { @@ -1093,9 +1172,11 @@ }, mutation: function(wrappedFunction) { return function() { - var result; + var result, _ref; result = wrappedFunction.apply(this, arguments); - this.event('change').fire(this, this); + if ((_ref = this.event('change', false)) != null) { + _ref.fire(this, this); + } return result; }; }, @@ -1108,17 +1189,18 @@ return this; }, isPrevented: function(key) { - return this.event(key).isPrevented(); + var _ref; + return (_ref = this.event(key, false)) != null ? _ref.isPrevented() : void 0; }, fire: function() { var args, key, _ref; key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - return (_ref = this.event(key)).fire.apply(_ref, args); + return (_ref = this.event(key, false)) != null ? _ref.fireWithContext(this, args) : void 0; }, allowAndFire: function() { var args, key, _ref; key = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - return (_ref = this.event(key)).allowAndFire.apply(_ref, args); + return (_ref = this.event(key, false)) != null ? _ref.allowAndFireWithContext(this, args) : void 0; } }; @@ -1130,109 +1212,117 @@ Batman.Enumerable = { isEnumerable: true, map: function(f, ctx) { - var r; + var result; if (ctx == null) { ctx = Batman.container; } - r = []; + result = []; this.forEach(function() { - return r.push(f.apply(ctx, arguments)); + return result.push(f.apply(ctx, arguments)); }); - return r; + return result; }, mapToProperty: function(key) { - var r; - r = []; + var result; + result = []; this.forEach(function(item) { - return r.push(item.get(key)); + return result.push(item.get(key)); }); - return r; + return result; }, every: function(f, ctx) { - var r; + var result; if (ctx == null) { ctx = Batman.container; } - r = true; + result = true; this.forEach(function() { - return r = r && f.apply(ctx, arguments); + return result = result && f.apply(ctx, arguments); }); - return r; + return result; }, some: function(f, ctx) { - var r; + var result; if (ctx == null) { ctx = Batman.container; } - r = false; + result = false; this.forEach(function() { - return r = r || f.apply(ctx, arguments); + return result = result || f.apply(ctx, arguments); }); - return r; + return result; }, - reduce: function(f, r) { - var count, self; + reduce: function(f, accumulator) { + var count, initialValuePassed, self; count = 0; self = this; + if (accumulator != null) { + initialValuePassed = true; + } else { + initialValuePassed = false; + } this.forEach(function() { - if (r != null) { - return r = f.apply(null, [r].concat(__slice.call(arguments), [count], [self])); - } else { - return r = arguments[0]; + if (!initialValuePassed) { + accumulator = arguments[0]; + initialValuePassed = true; + return; } + return accumulator = f.apply(null, [accumulator].concat(__slice.call(arguments), [count], [self])); }); - return r; + return accumulator; }, filter: function(f) { - var r, wrap; - r = new this.constructor; - if (r.add) { - wrap = function(r, e) { - if (f(e)) { - r.add(e); + var result, wrap; + result = new this.constructor; + if (result.add) { + wrap = function(result, element) { + if (f(element)) { + result.add(element); } - return r; + return result; }; - } else if (r.set) { - wrap = function(r, k, v) { - if (f(k, v)) { - r.set(k, v); + } else if (result.set) { + wrap = function(result, key, value) { + if (f(key, value)) { + result.set(key, value); } - return r; + return result; }; } else { - if (!r.push) { - r = []; + if (!result.push) { + result = []; } - wrap = function(r, e) { - if (f(e)) { - r.push(e); + wrap = function(result, element) { + if (f(element)) { + result.push(element); } - return r; + return result; }; } - return this.reduce(wrap, r); + return this.reduce(wrap, result); }, - inGroupsOf: function(n) { - var current, i, r; - r = []; + inGroupsOf: function(groupSize) { + var current, i, result; + result = []; current = false; i = 0; - this.forEach(function(x) { - if (i++ % n === 0) { + this.forEach(function(element) { + if (i++ % groupSize === 0) { current = []; - r.push(current); + result.push(current); } - return current.push(x); + return current.push(element); }); - return r; + return result; } }; }).call(this); (function() { - var __slice = [].slice; + var _objectToString, __slice = [].slice; + + _objectToString = Object.prototype.toString; Batman.SimpleHash = (function() { @@ -1246,8 +1336,6 @@ Batman.extend(SimpleHash.prototype, Batman.Enumerable); - SimpleHash.prototype.propertyClass = Batman.Property; - SimpleHash.prototype.hasKey = function(key) { var pair, pairs, _i, _len; if (this.objectKey(key)) { @@ -1361,7 +1449,17 @@ }; SimpleHash.prototype.hashKeyFor = function(obj) { - return (obj != null ? typeof obj.hashKey === "function" ? obj.hashKey() : void 0 : void 0) || obj; + var hashKey, typeString; + if (hashKey = obj != null ? typeof obj.hashKey === "function" ? obj.hashKey() : void 0 : void 0) { + return hashKey; + } else { + typeString = _objectToString.call(obj); + if (typeString === "[object Array]") { + return typeString; + } else { + return obj; + } + } }; SimpleHash.prototype.equality = function(lhs, rhs) { @@ -1486,7 +1584,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.AssociationCurator = (function(_super) { @@ -1559,10 +1668,22 @@ Batman.SimpleSet = (function() { function SimpleSet() { + var item, itemsToAdd; this._storage = []; this.length = 0; - if (arguments.length > 0) { - this.add.apply(this, arguments); + itemsToAdd = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = arguments.length; _i < _len; _i++) { + item = arguments[_i]; + if (item != null) { + _results.push(item); + } + } + return _results; + }).apply(this, arguments); + if (itemsToAdd.length > 0) { + this.add.apply(this, itemsToAdd); } } @@ -1598,7 +1719,7 @@ removedItems = []; for (_i = 0, _len = items.length; _i < _len; _i++) { item = items[_i]; - if (!(~(index = this._indexOfItem(item)))) { + if (!(~ (index = this._indexOfItem(item)))) { continue; } this._storage.splice(index, 1); @@ -1624,11 +1745,14 @@ }; SimpleSet.prototype.forEach = function(iterator, ctx) { - var container; - container = this; - return this._storage.slice().forEach(function(key) { - return iterator.call(ctx, key, null, container); - }); + var key, _i, _len, _ref, _results; + _ref = this._storage; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push(iterator.call(ctx, key, null, this)); + } + return _results; }; SimpleSet.prototype.isEmpty = function() { @@ -1721,18 +1845,19 @@ }).call(this); (function() { - var __slice = [].slice; + var SOURCE_TRACKER_STACK, SOURCE_TRACKER_STACK_VALID, __slice = [].slice; + + SOURCE_TRACKER_STACK = []; + + SOURCE_TRACKER_STACK_VALID = true; Batman.Property = (function() { Batman.mixin(Property.prototype, Batman.EventEmitter); - Property._sourceTrackerStack = []; + Property._sourceTrackerStack = SOURCE_TRACKER_STACK; - Property.sourceTracker = function() { - var stack; - return (stack = this._sourceTrackerStack)[stack.length - 1]; - }; + Property._sourceTrackerStackValid = SOURCE_TRACKER_STACK_VALID; Property.defaultAccessor = { get: function(key) { @@ -1756,15 +1881,18 @@ }; Property.accessorForBaseAndKey = function(base, key) { - var accessor, _bm, _ref, - _this = this; + var accessor, ancestor, _bm, _i, _len, _ref, _ref1, _ref2, _ref3; if ((_bm = base._batman) != null) { accessor = (_ref = _bm.keyAccessors) != null ? _ref.get(key) : void 0; if (!accessor) { - _bm.ancestors(function(ancestor) { - var _ref1, _ref2; - return accessor || (accessor = (_ref1 = ancestor._batman) != null ? (_ref2 = _ref1.keyAccessors) != null ? _ref2.get(key) : void 0 : void 0); - }); + _ref1 = _bm.ancestors(); + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + ancestor = _ref1[_i]; + accessor = (_ref2 = ancestor._batman) != null ? (_ref3 = _ref2.keyAccessors) != null ? _ref3.get(key) : void 0 : void 0; + if (accessor) { + break; + } + } } } return accessor || this.defaultAccessorForBase(base); @@ -1794,23 +1922,46 @@ }; Property.registerSource = function(obj) { - var _ref; + var set; if (!obj.isEventEmitter) { return; } - return (_ref = this.sourceTracker()) != null ? _ref.add(obj) : void 0; + if (SOURCE_TRACKER_STACK_VALID) { + set = SOURCE_TRACKER_STACK[SOURCE_TRACKER_STACK.length - 1]; + } else { + set = []; + SOURCE_TRACKER_STACK.push(set); + SOURCE_TRACKER_STACK_VALID = true; + } + if (set != null) { + set.push(obj); + } + return void 0; }; Property.pushSourceTracker = function() { - return Batman.Property._sourceTrackerStack.push(new Batman.SimpleSet); + if (SOURCE_TRACKER_STACK_VALID) { + return SOURCE_TRACKER_STACK_VALID = false; + } else { + return SOURCE_TRACKER_STACK.push([]); + } }; - Property.pushDummySourceTracker = function() { - return Batman.Property._sourceTrackerStack.push(null); + Property.popSourceTracker = function() { + if (SOURCE_TRACKER_STACK_VALID) { + return SOURCE_TRACKER_STACK.pop(); + } else { + SOURCE_TRACKER_STACK_VALID = true; + return void 0; + } }; - Property.popSourceTracker = function() { - return Batman.Property._sourceTrackerStack.pop(); + Property.pushDummySourceTracker = function() { + if (!SOURCE_TRACKER_STACK_VALID) { + SOURCE_TRACKER_STACK.push([]); + SOURCE_TRACKER_STACK_VALID = true; + } + return SOURCE_TRACKER_STACK.push(null); }; function Property(base, key) { @@ -1837,11 +1988,7 @@ }; Property.prototype.hashKey = function() { - var key; - this.hashKey = function() { - return key; - }; - return key = ""; + return this._hashKey || (this._hashKey = ""); }; Property.prototype.event = function(key) { @@ -1853,36 +2000,49 @@ }; Property.prototype.changeEvent = function() { - var event; - event = this.event('change'); - this.changeEvent = function() { - return event; - }; - return event; + return this._changeEvent || (this._changeEvent = this.event('change')); }; Property.prototype.accessor = function() { - var accessor; - accessor = this.constructor.accessorForBaseAndKey(this.base, this.key); - this.accessor = function() { - return accessor; - }; - return accessor; + return this._accessor || (this._accessor = this.constructor.accessorForBaseAndKey(this.base, this.key)); }; Property.prototype.eachObserver = function(iterator) { - var key; + var ancestor, handlers, key, object, property, _i, _j, _len, _len1, _ref, _ref1, _ref2, _results; key = this.key; - this.changeEvent().handlers.slice().forEach(iterator); + handlers = (_ref = this.changeEvent().handlers) != null ? _ref.slice() : void 0; + if (handlers) { + for (_i = 0, _len = handlers.length; _i < _len; _i++) { + object = handlers[_i]; + iterator(object); + } + } if (this.base.isObservable) { - return this.base._batman.ancestors(function(ancestor) { - var handlers, property; + _ref1 = this.base._batman.ancestors(); + _results = []; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + ancestor = _ref1[_j]; if (ancestor.isObservable && ancestor.hasProperty(key)) { property = ancestor.property(key); - handlers = property.changeEvent().handlers; - return handlers.slice().forEach(iterator); + handlers = (_ref2 = property.changeEvent().handlers) != null ? _ref2.slice() : void 0; + if (handlers) { + _results.push((function() { + var _k, _len2, _results1; + _results1 = []; + for (_k = 0, _len2 = handlers.length; _k < _len2; _k++) { + object = handlers[_k]; + _results1.push(iterator(object)); + } + return _results1; + })()); + } else { + _results.push(void 0); + } + } else { + _results.push(void 0); } - }); + } + return _results; } }; @@ -1900,25 +2060,28 @@ }; Property.prototype.updateSourcesFromTracker = function() { - var handler, newSources; + var handler, newSources, source, _i, _j, _len, _len1, _ref, _ref1, _results; newSources = this.constructor.popSourceTracker(); handler = this.sourceChangeHandler(); - this._eachSourceChangeEvent(function(e) { - return e.removeHandler(handler); - }); + if (this.sources) { + _ref = this.sources; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + source = _ref[_i]; + if (source != null) { + source.event('change').removeHandler(handler); + } + } + } this.sources = newSources; - return this._eachSourceChangeEvent(function(e) { - return e.addHandler(handler); - }); - }; - - Property.prototype._eachSourceChangeEvent = function(iterator) { - if (this.sources == null) { - return; + if (this.sources) { + _ref1 = this.sources; + _results = []; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + source = _ref1[_j]; + _results.push(source != null ? source.event('change').addHandler(handler) : void 0); + } + return _results; } - return this.sources.forEach(function(source) { - return iterator(source.event('change')); - }); }; Property.prototype.getValue = function() { @@ -1970,16 +2133,12 @@ }; Property.prototype.sourceChangeHandler = function() { - var handler, - _this = this; - handler = this._handleSourceChange.bind(this); + var _this = this; + this._sourceChangeHandler || (this._sourceChangeHandler = this._handleSourceChange.bind(this)); Batman.developer["do"](function() { - return handler.property = _this; + return _this._sourceChangeHandler.property = _this; }); - this.sourceChangeHandler = function() { - return handler; - }; - return handler; + return this._sourceChangeHandler; }; Property.prototype._handleSourceChange = function() { @@ -2069,11 +2228,15 @@ }; Property.prototype._removeHandlers = function() { - var handler; + var handler, source, _i, _len, _ref; handler = this.sourceChangeHandler(); - this._eachSourceChangeEvent(function(e) { - return e.removeHandler(handler); - }); + if (this.sources) { + _ref = this.sources; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + source = _ref[_i]; + source.event('change').removeHandler(handler); + } + } delete this.sources; return this.changeEvent().clearHandlers(); }; @@ -2136,7 +2299,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Keypath = (function(_super) { @@ -2379,25 +2553,25 @@ } isSetting = arguments.length > 1; switch (node.nodeName.toUpperCase()) { - case 'INPUT': - case 'TEXTAREA': - if (isSetting) { - return node.value = value; - } else { - return node.value; - } - break; - case 'SELECT': - if (isSetting) { - return node.value = value; - } - break; - default: - if (isSetting) { - return Batman.DOM.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value); - } else { - return node.innerHTML; - } + case 'INPUT': + case 'TEXTAREA': + if (isSetting) { + return node.value = value; + } else { + return node.value; + } + break; + case 'SELECT': + if (isSetting) { + return node.value = value; + } + break; + default: + if (isSetting) { + return Batman.DOM.setInnerHTML(node, escapeValue ? Batman.escapeHTML(value) : value); + } else { + return node.innerHTML; + } } }, nodeIsEditable: function(node) { @@ -2435,7 +2609,7 @@ return node.detachEvent('on' + eventName, callback); } }, - hasAddEventListener: !!(typeof window !== "undefined" && window !== null ? window.addEventListener : void 0), + hasAddEventListener: !! (typeof window !== "undefined" && window !== null ? window.addEventListener : void 0), preventDefault: function(e) { if (typeof e.preventDefault === "function") { return e.preventDefault(); @@ -2536,16 +2710,7 @@ var bindings, child, eventListeners, eventName, listeners, view, _i, _len, _ref; view = Batman._data(node, 'view'); if (view) { - view.fire('destroy', node); - view.get('yields').forEach(function(name, actions) { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = actions.length; _i < _len; _i++) { - node = actions[_i].node; - _results.push(Batman.DOM.didDestroyNode(node)); - } - return _results; - }); + view.die(); } if (bindings = Batman._data(node, 'bindings')) { bindings.forEach(function(binding) { @@ -2578,121 +2743,126 @@ }).call(this); (function() { - var __slice = [].slice; + + Batman.DOM.ReaderBindingDefinition = (function() { + + function ReaderBindingDefinition(node, keyPath, context, renderer) { + this.node = node; + this.keyPath = keyPath; + this.context = context; + this.renderer = renderer; + } + + return ReaderBindingDefinition; + + })(); + + Batman.BindingDefinitionOnlyObserve = { + Data: 'data', + Node: 'node', + All: 'all', + None: 'none' + }; Batman.DOM.readers = { - target: function(node, key, context, renderer) { - Batman.DOM.readers.bind(node, key, context, renderer, 'nodeChange'); - return true; + target: function(definition) { + definition.onlyObserve = Batman.BindingDefinitionOnlyObserve.Node; + return Batman.DOM.readers.bind(definition); }, - source: function(node, key, context, renderer) { - Batman.DOM.readers.bind(node, key, context, renderer, 'dataChange'); - return true; + source: function(definition) { + definition.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + return Batman.DOM.readers.bind(definition); }, - bind: function(node, key, context, renderer, only) { - var bindingClass; - bindingClass = false; + bind: function(definition) { + var bindingClass, node; + node = definition.node; switch (node.nodeName.toLowerCase()) { - case 'input': - switch (node.getAttribute('type')) { - case 'checkbox': - Batman.DOM.attrReaders.bind(node, 'checked', key, context, renderer, only); - return true; - case 'radio': - bindingClass = Batman.DOM.RadioBinding; - break; - case 'file': - bindingClass = Batman.DOM.FileBinding; - } + case 'input': + switch (node.getAttribute('type')) { + case 'checkbox': + definition.attr = 'checked'; + Batman.DOM.attrReaders.bind(definition); + return true; + case 'radio': + bindingClass = Batman.DOM.RadioBinding; break; - case 'select': - bindingClass = Batman.DOM.SelectBinding; + case 'file': + bindingClass = Batman.DOM.FileBinding; + } + break; + case 'select': + bindingClass = Batman.DOM.SelectBinding; } - bindingClass || (bindingClass = Batman.DOM.Binding); - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(bindingClass, arguments, function(){}); - return true; + bindingClass || (bindingClass = Batman.DOM.ValueBinding); + return new bindingClass(definition); }, - context: function(node, key, context, renderer) { - return context.descendWithKey(key); + context: function(definition) { + return definition.context.descendWithDefinition(definition); }, - mixin: function(node, key, context, renderer) { - new Batman.DOM.MixinBinding(node, key, context.descend(Batman.mixins), renderer); - return true; + mixin: function(definition) { + definition.context = definition.context.descend(Batman.mixins); + return new Batman.DOM.MixinBinding(definition); }, - showif: function(node, key, context, parentRenderer, invert) { - new Batman.DOM.ShowHideBinding(node, key, context, parentRenderer, false, invert); - return true; + showif: function(definition) { + return new Batman.DOM.ShowHideBinding(definition); }, - hideif: function() { - var _ref; - return (_ref = Batman.DOM.readers).showif.apply(_ref, __slice.call(arguments).concat([true])); + hideif: function(definition) { + definition.invert = true; + return new Batman.DOM.ShowHideBinding(definition); }, - insertif: function(node, key, context, parentRenderer, invert) { - new Batman.DOM.InsertionBinding(node, key, context, parentRenderer, false, invert); - return true; + insertif: function(definition) { + return new Batman.DOM.InsertionBinding(definition); }, - removeif: function() { - var _ref; - return (_ref = Batman.DOM.readers).insertif.apply(_ref, __slice.call(arguments).concat([true])); + removeif: function(definition) { + definition.invert = true; + return new Batman.DOM.InsertionBinding(definition); }, - route: function() { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.RouteBinding, arguments, function(){}); - return true; + route: function(definition) { + return new Batman.DOM.RouteBinding(definition); }, - view: function() { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.ViewBinding, arguments, function(){}); - return false; + view: function(definition) { + return new Batman.DOM.ViewBinding(definition); }, - partial: function(node, path, context, renderer) { - Batman.DOM.partial(node, path, context, renderer); - return true; + partial: function(definition) { + return Batman.DOM.partial(definition.node, definition.keyPath, definition.context, definition.renderer); }, - defineview: function(node, name, context, renderer) { + defineview: function(definition) { + var node; + node = definition.node; Batman.DOM.onParseExit(node, function() { var _ref; return (_ref = node.parentNode) != null ? _ref.removeChild(node) : void 0; }); - Batman.DOM.defineView(name, node); - return false; + Batman.DOM.defineView(definition.keyPath, node); + return { + skipChildren: true + }; }, - renderif: function(node, key, context, renderer) { - new Batman.DOM.DeferredRenderingBinding(node, key, context, renderer); - return false; + renderif: function(definition) { + return new Batman.DOM.DeferredRenderingBinding(definition); }, - "yield": function(node, key) { - Batman.DOM.onParseExit(node, function() { - return Batman.DOM.Yield.withName(key).set('containerNode', node); + "yield": function(definition) { + var keyPath, node; + node = definition.node, keyPath = definition.keyPath; + return Batman.DOM.onParseExit(node, function() { + return Batman.DOM.Yield.withName(keyPath).set('containerNode', node); }); - return true; }, - contentfor: function(node, key, context, renderer, action) { - if (action == null) { - action = 'append'; - } - Batman.DOM.onParseExit(node, function() { + contentfor: function(definition) { + var keyPath, node, renderer, swapMethod, value; + node = definition.node, value = definition.value, swapMethod = definition.swapMethod, renderer = definition.renderer, keyPath = definition.keyPath; + swapMethod || (swapMethod = 'append'); + return Batman.DOM.onParseExit(node, function() { var _ref; if ((_ref = node.parentNode) != null) { _ref.removeChild(node); } - return renderer.view.pushYieldAction(key, action, node); + return renderer.view.pushYieldAction(keyPath, swapMethod, node); }); - return true; }, - replace: function(node, key, context, renderer) { - Batman.DOM.readers.contentfor(node, key, context, renderer, 'replace'); - return true; + replace: function(definition) { + definition.swapMethod = 'replace'; + return Batman.DOM.readers.contentfor(definition); } }; @@ -2700,7 +2870,13 @@ (function() { var __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + __indexOf = [].indexOf || + function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; Batman.DOM.events = { click: function(node, callback, context, eventName) { @@ -2710,7 +2886,7 @@ Batman.DOM.addEventListener(node, eventName, function() { var args, event; event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - if (event.metaKey || event.ctrlKey) { + if (event.metaKey || event.ctrlKey || event.button === 1) { return; } Batman.DOM.preventDefault(event); @@ -2732,24 +2908,24 @@ eventNames = (function() { var _ref; switch (node.nodeName.toUpperCase()) { - case 'TEXTAREA': + case 'TEXTAREA': + return ['input', 'keyup', 'change']; + case 'INPUT': + if (_ref = node.type.toLowerCase(), __indexOf.call(Batman.DOM.textInputTypes, _ref) >= 0) { + oldCallback = callback; + callback = function(node, event) { + if (event.type === 'keyup' && Batman.DOM.events.isEnter(event)) { + return; + } + return oldCallback(node, event); + }; return ['input', 'keyup', 'change']; - case 'INPUT': - if (_ref = node.type.toLowerCase(), __indexOf.call(Batman.DOM.textInputTypes, _ref) >= 0) { - oldCallback = callback; - callback = function(node, event) { - if (event.type === 'keyup' && Batman.DOM.events.isEnter(event)) { - return; - } - return oldCallback.apply(null, arguments); - }; - return ['input', 'keyup', 'change']; - } else { - return ['input', 'change']; - } - break; - default: - return ['change']; + } else { + return ['input', 'change']; + } + break; + default: + return ['change']; } })(); _results = []; @@ -2820,6 +2996,20 @@ (function() { + Batman.DOM.AttrReaderBindingDefinition = (function() { + + function AttrReaderBindingDefinition(node, attr, keyPath, context, renderer) { + this.node = node; + this.attr = attr; + this.keyPath = keyPath; + this.context = context; + this.renderer = renderer; + } + + return AttrReaderBindingDefinition; + + })(); + Batman.DOM.attrReaders = { _parseAttribute: function(value) { if (value === 'false') { @@ -2830,80 +3020,72 @@ } return value; }, - source: function(node, attr, key, context, renderer) { - return Batman.DOM.attrReaders.bind(node, attr, key, context, renderer, 'dataChange'); + source: function(definition) { + definition.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + return Batman.DOM.attrReaders.bind(definition); }, - bind: function(node, attr, key, context, renderer, only) { + bind: function(definition) { var bindingClass; bindingClass = (function() { - switch (attr) { - case 'checked': - case 'disabled': - case 'selected': - return Batman.DOM.CheckedBinding; - case 'value': - case 'href': - case 'src': - case 'size': - return Batman.DOM.NodeAttributeBinding; - case 'class': - return Batman.DOM.ClassBinding; - case 'style': - return Batman.DOM.StyleBinding; - default: - return Batman.DOM.AttributeBinding; + switch (definition.attr) { + case 'checked': + case 'disabled': + case 'selected': + return Batman.DOM.CheckedBinding; + case 'value': + case 'href': + case 'src': + case 'size': + return Batman.DOM.NodeAttributeBinding; + case 'class': + return Batman.DOM.ClassBinding; + case 'style': + return Batman.DOM.StyleBinding; + default: + return Batman.DOM.AttributeBinding; } })(); - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(bindingClass, arguments, function(){}); - return true; + return new bindingClass(definition); }, - context: function(node, contextName, key, context) { - return context.descendWithKey(key, contextName); + context: function(definition) { + return definition.context.descendWithDefinition(definition); }, - event: function(node, eventName, key, context) { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.EventBinding, arguments, function(){}); - return true; + event: function(definition) { + return new Batman.DOM.EventBinding(definition); }, - addclass: function(node, className, key, context, parentRenderer, invert) { - new Batman.DOM.AddClassBinding(node, className, key, context, parentRenderer, false, invert); - return true; + addclass: function(definition) { + return new Batman.DOM.AddClassBinding(definition); }, - removeclass: function(node, className, key, context, parentRenderer) { - return Batman.DOM.attrReaders.addclass(node, className, key, context, parentRenderer, true); + removeclass: function(definition) { + definition.invert = true; + return new Batman.DOM.AddClassBinding(definition); }, - foreach: function(node, iteratorName, key, context, parentRenderer) { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.IteratorBinding, arguments, function(){}); - return false; + foreach: function(definition) { + return new Batman.DOM.IteratorBinding(definition); }, - formfor: function(node, localName, key, context) { - (function(func, args, ctor) { - ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; - return t == "object" || t == "function" ? result || child : child; - })(Batman.DOM.FormBinding, arguments, function(){}); - return context.descendWithKey(key, localName); + formfor: function(definition) { + new Batman.DOM.FormBinding(definition); + return definition.context.descendWithDefinition(definition); } }; }).call(this); (function() { - var BatmanObject, ObjectFunctions, getAccessorObject, promiseWrapper, wrapSingleAccessor, - __slice = [].slice, + var BatmanObject, ObjectFunctions, getAccessorObject, promiseWrapper, wrapSingleAccessor, __slice = [].slice, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; getAccessorObject = function(base, accessor) { var deprecated, _i, _len, _ref; @@ -2929,8 +3111,7 @@ return function(defaultAccessor) { return { get: function(key) { - var asyncDeliver, existingValue, newValue, _base, _base1, _ref, _ref1, - _this = this; + var asyncDeliver, existingValue, newValue, _base, _base1, _ref, _ref1, _this = this; if ((existingValue = defaultAccessor.get.apply(this, arguments)) != null) { return existingValue; } @@ -3110,14 +3291,11 @@ }; BatmanObject.prototype.hashKey = function() { - var key; + var _base; if (typeof this.isEqual === 'function') { return; } - this.hashKey = function() { - return key; - }; - return key = ""; + return (_base = this._batman).hashKey || (_base.hashKey = ""); }; BatmanObject.prototype.toJSON = function() { @@ -3142,9 +3320,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Renderer = (function(_super) { var bindingRegexp, bindingSortOrder, bindingSortPositions, k, name, pos, _i, _j, _len, _len1, _ref; @@ -3233,8 +3426,7 @@ }; Renderer.prototype.parseNode = function(node) { - var argument, attribute, bindings, keypath, names, nextNode, oldContext, result, skipChildren, _base, _base1, _k, _l, _len2, _len3, _ref1, _ref2, _ref3, _ref4, - _this = this; + var attr, attribute, binding, bindingDefinition, bindings, names, nextNode, oldContext, reader, skipChildren, value, _k, _l, _len2, _len3, _ref1, _ref2, _ref3, _ref4, _this = this; if (this.deferEvery && (new Date - this.startTime) > this.deferEvery) { this.resumeNode = node; this.timeout = Batman.setImmediate(this.resume); @@ -3253,17 +3445,17 @@ } _ref3 = bindings.sort(this._sortBindings); for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { - _ref4 = _ref3[_l], name = _ref4[0], argument = _ref4[1], keypath = _ref4[2]; - result = argument ? typeof (_base = Batman.DOM.attrReaders)[name] === "function" ? _base[name](node, argument, keypath, this.context, this) : void 0 : typeof (_base1 = Batman.DOM.readers)[name] === "function" ? _base1[name](node, keypath, this.context, this) : void 0; - if (result === false) { - skipChildren = true; - break; - } else if (result instanceof Batman.RenderContext) { + _ref4 = _ref3[_l], name = _ref4[0], attr = _ref4[1], value = _ref4[2]; + binding = attr ? (reader = Batman.DOM.attrReaders[name]) ? (bindingDefinition = new Batman.DOM.AttrReaderBindingDefinition(node, attr, value, this.context, this), reader(bindingDefinition)) : void 0 : (reader = Batman.DOM.readers[name]) ? (bindingDefinition = new Batman.DOM.ReaderBindingDefinition(node, value, this.context, this), reader(bindingDefinition)) : void 0; + if (binding instanceof Batman.RenderContext) { oldContext = this.context; - this.context = result; + this.context = binding; Batman.DOM.onParseExit(node, function() { return _this.context = oldContext; }); + } else if (binding != null ? binding.skipChildren : void 0) { + skipChildren = true; + break; } } } @@ -3320,16 +3512,31 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.AbstractBinding = (function(_super) { - var get_dot_rx, get_rx, keypath_rx; + var get_dot_rx, get_rx, keypath_rx, onlyAll, onlyData, onlyNode; __extends(AbstractBinding, _super); - keypath_rx = /(^|,)\s*(?:(true|false)|("[^"]*")|(\{[^\}]*\})|([a-zA-Z][\w\-\.]*[\?\!]?))\s*(?=$|,)/g; + keypath_rx = /(^|,)\s*(?:(true|false)|("[^"]*")|(\{[^\}]*\})|(([0-9]+[a-zA-Z\_]|[a-zA-Z])[\w\-\.]*[\?\!]?))\s*(?=$|,)/g; get_dot_rx = /(?:\]\.)(.+?)(?=[\[\.]|\s*\||$)/; @@ -3397,6 +3604,12 @@ return this.renderContext.contextForKey(this.key); }); + onlyAll = Batman.BindingDefinitionOnlyObserve.All; + + onlyData = Batman.BindingDefinitionOnlyObserve.Data; + + onlyNode = Batman.BindingDefinitionOnlyObserve.Node; + AbstractBinding.prototype.bindImmediately = true; AbstractBinding.prototype.shouldSet = true; @@ -3405,17 +3618,22 @@ AbstractBinding.prototype.escapeValue = true; - function AbstractBinding(node, keyPath, renderContext, renderer, only) { - this.node = node; - this.keyPath = keyPath; - this.renderContext = renderContext; - this.renderer = renderer; - this.only = only != null ? only : false; - this._fireDataChange = __bind(this._fireDataChange, this); + AbstractBinding.prototype.onlyObserve = onlyAll; - this._fireNodeChange = __bind(this._fireNodeChange, this); + AbstractBinding.prototype.skipParseFilter = false; - this.parseFilter(); + function AbstractBinding(definition) { + this._fireDataChange = __bind(this._fireDataChange, this); + this.node = definition.node, this.keyPath = definition.keyPath, this.renderContext = definition.context, this.renderer = definition.renderer; + if (definition.onlyObserve) { + this.onlyObserve = definition.onlyObserve; + } + if (definition.skipParseFilter != null) { + this.skipParseFilter = definition.skipParseFilter; + } + if (!this.skipParseFilter) { + this.parseFilter(); + } if (this.bindImmediately) { this.bind(); } @@ -3427,16 +3645,16 @@ AbstractBinding.prototype.bind = function() { var _ref, _ref1; - if ((this.node != null) && ((_ref = this.only) === false || _ref === 'nodeChange') && Batman.DOM.nodeIsEditable(this.node)) { - Batman.DOM.events.change(this.node, this._fireNodeChange); - if (this.only === 'nodeChange') { + if (this.node && ((_ref = this.onlyObserve) === onlyAll || _ref === onlyNode) && Batman.DOM.nodeIsEditable(this.node)) { + Batman.DOM.events.change(this.node, this._fireNodeChange.bind(this)); + if (this.onlyObserve === onlyNode) { this._fireNodeChange(); } } - if ((_ref1 = this.only) === false || _ref1 === 'dataChange') { + if ((_ref1 = this.onlyObserve) === onlyAll || _ref1 === onlyData) { this.observeAndFire('filteredValue', this._fireDataChange); } - if (this.node != null) { + if (this.node) { return Batman.DOM.trackBinding(this, this.node); } }; @@ -3470,6 +3688,10 @@ }); } this.fire('die'); + this.node = null; + this.keyPath = null; + this.renderContext = null; + this.renderer = null; this.dead = true; return true; }; @@ -3536,12 +3758,27 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.ViewBinding = (function(_super) { __extends(ViewBinding, _super); + ViewBinding.prototype.skipChildren = true; + + ViewBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + function ViewBinding() { ViewBinding.__super__.constructor.apply(this, arguments); this.renderer.prevent('rendered'); @@ -3549,7 +3786,7 @@ } ViewBinding.prototype.dataChange = function(viewClassOrInstance) { - var _this = this; + var _ref, _this = this; if (viewClassOrInstance == null) { return; } @@ -3567,7 +3804,15 @@ this.view.on('ready', function() { return _this.renderer.allowAndFire('rendered'); }); - return this.die(); + this.forget(); + return (_ref = this._batman.properties) != null ? _ref.forEach(function(key, property) { + return property.die(); + }) : void 0; + }; + + ViewBinding.prototype.die = function() { + this.view = null; + return ViewBinding.__super__.die.apply(this, arguments); }; return ViewBinding; @@ -3578,7 +3823,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.ViewArgumentBinding = (function(_super) { @@ -3588,6 +3844,8 @@ return ViewArgumentBinding.__super__.constructor.apply(this, arguments); } + ViewArgumentBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.None; + return ViewArgumentBinding; })(Batman.DOM.AbstractBinding); @@ -3596,27 +3854,81 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; + + Batman.DOM.ValueBinding = (function(_super) { + + __extends(ValueBinding, _super); + + function ValueBinding(definition) { + var _ref; + this.isInputBinding = (_ref = definition.node.nodeName.toLowerCase()) === 'input' || _ref === 'textarea'; + ValueBinding.__super__.constructor.apply(this, arguments); + } + + ValueBinding.prototype.nodeChange = function(node, context) { + if (this.isTwoWay()) { + return this.set('filteredValue', this.node.value); + } + }; + + ValueBinding.prototype.dataChange = function(value, node) { + return Batman.DOM.valueForNode(this.node, value, this.escapeValue); + }; + + return ValueBinding; + + })(Batman.DOM.AbstractBinding); + +}).call(this); + +(function() { + var __hasProp = {}.hasOwnProperty, + __extends = 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; + }; Batman.DOM.ShowHideBinding = (function(_super) { __extends(ShowHideBinding, _super); - function ShowHideBinding(node, className, key, context, parentRenderer, invert) { + ShowHideBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + + function ShowHideBinding(definition) { var display; - this.invert = invert != null ? invert : false; - display = node.style.display; + display = definition.node.style.display; if (!display || display === 'none') { display = ''; } this.originalDisplay = display; + this.invert = definition.invert; ShowHideBinding.__super__.constructor.apply(this, arguments); } ShowHideBinding.prototype.dataChange = function(value) { var hide, view, _ref; view = Batman._data(this.node, 'view'); - if (!!value === !this.invert) { + if ( !! value === !this.invert) { if (view != null) { view.fire('beforeAppear', this.node); } @@ -3629,7 +3941,7 @@ if (view != null) { view.fire('beforeDisappear', this.node); } - if (typeof (hide = Batman.data(this.node, 'hide')) === 'function') { + if (typeof(hide = Batman.data(this.node, 'hide')) === 'function') { hide.call(this.node); } else { Batman.DOM.setStyleProperty(this.node, 'display', 'none', 'important'); @@ -3645,9 +3957,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.SelectBinding = (function(_super) { @@ -3670,8 +3997,7 @@ } SelectBinding.prototype.childBindingAdded = function(binding) { - var dataChangeHandler, - _this = this; + var dataChangeHandler, _this = this; if (binding instanceof Batman.DOM.CheckedBinding) { binding.on('dataChange', dataChangeHandler = function() { return _this.nodeChange(); @@ -3699,8 +4025,7 @@ SelectBinding.prototype.lastKeyContext = null; SelectBinding.prototype.dataChange = function(newValue) { - var child, matches, valueToChild, _i, _len, _name, _ref, - _this = this; + var child, matches, valueToChild, _i, _len, _name, _ref, _this = this; this.lastKeyContext || (this.lastKeyContext = this.get('keyContext')); if (this.lastKeyContext !== this.get('keyContext')) { this.canSetImplicitly = true; @@ -3777,7 +4102,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.RouteBinding = (function(_super) { @@ -3787,7 +4123,9 @@ return RouteBinding.__super__.constructor.apply(this, arguments); } - RouteBinding.prototype.onATag = false; + RouteBinding.prototype.onAnchorTag = false; + + RouteBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; RouteBinding.accessor('dispatcher', function() { return this.renderContext.get('dispatcher') || Batman.App.get('current.dispatcher'); @@ -3796,7 +4134,7 @@ RouteBinding.prototype.bind = function() { var _this = this; if (this.node.nodeName.toUpperCase() === 'A') { - this.onATag = true; + this.onAnchorTag = true; } RouteBinding.__super__.bind.apply(this, arguments); return Batman.DOM.events.click(this.node, function(node, event) { @@ -3814,11 +4152,11 @@ RouteBinding.prototype.dataChange = function(value) { var path; - if (value != null) { + if (value) { path = this.pathFromValue(value); } - if (this.onATag) { - if ((path != null) && (Batman.navigator != null)) { + if (this.onAnchorTag) { + if (path && Batman.navigator) { path = Batman.navigator.linkTo(path); } else { path = "#"; @@ -3829,7 +4167,7 @@ RouteBinding.prototype.pathFromValue = function(value) { var _ref; - if (value != null) { + if (value) { if (value.isNamedRouteQuery) { return value.get('path'); } else { @@ -3846,7 +4184,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.RadioBinding = (function(_super) { @@ -3889,7 +4238,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.MixinBinding = (function(_super) { @@ -3899,6 +4259,8 @@ return MixinBinding.__super__.constructor.apply(this, arguments); } + MixinBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + MixinBinding.prototype.dataChange = function(value) { if (value != null) { return Batman.mixin(this.node, value); @@ -3913,7 +4275,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.FileBinding = (function(_super) { @@ -3944,7 +4317,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.DeferredRenderingBinding = (function(_super) { @@ -3952,6 +4336,8 @@ DeferredRenderingBinding.prototype.rendered = false; + DeferredRenderingBinding.prototype.skipChildren = true; + function DeferredRenderingBinding() { DeferredRenderingBinding.__super__.constructor.apply(this, arguments); this.node.removeAttribute("data-renderif"); @@ -3978,48 +4364,26 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; - - Batman.DOM.Binding = (function(_super) { - - __extends(Binding, _super); - - function Binding(node) { - var _ref; - this.isInputBinding = (_ref = node.nodeName.toLowerCase()) === 'input' || _ref === 'textarea'; - Binding.__super__.constructor.apply(this, arguments); - } - - Binding.prototype.nodeChange = function(node, context) { - if (this.isTwoWay()) { - return this.set('filteredValue', this.node.value); + __extends = 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; }; - Binding.prototype.dataChange = function(value, node) { - return Batman.DOM.valueForNode(this.node, value, this.escapeValue); - }; - - return Binding; - - })(Batman.DOM.AbstractBinding); - -}).call(this); - -(function() { - var __hasProp = {}.hasOwnProperty, - __extends = 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; }, - __slice = [].slice; - Batman.DOM.AbstractAttributeBinding = (function(_super) { __extends(AbstractAttributeBinding, _super); - function AbstractAttributeBinding() { - var args, attributeName, node; - node = arguments[0], attributeName = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; - this.attributeName = attributeName; - AbstractAttributeBinding.__super__.constructor.apply(this, [node].concat(__slice.call(args))); + function AbstractAttributeBinding(definition) { + this.attributeName = definition.attr; + AbstractAttributeBinding.__super__.constructor.apply(this, arguments); } return AbstractAttributeBinding; @@ -4029,9 +4393,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.FormBinding = (function(_super) { @@ -4043,14 +4422,16 @@ FormBinding.prototype.defaultErrorsListSelector = 'div.errors'; + FormBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.None; + FormBinding.accessor('errorsListSelector', function() { return this.get('node').getAttribute('data-errors-list') || this.defaultErrorsListSelector; }); - function FormBinding(node, contextName, keyPath, renderContext, renderer, only) { + function FormBinding() { this.childBindingAdded = __bind(this.childBindingAdded, this); FormBinding.__super__.constructor.apply(this, arguments); - this.contextName = contextName; + this.contextName = this.attributeName; delete this.attributeName; Batman.DOM.events.submit(this.get('node'), function(node, e) { return Batman.DOM.preventDefault(e); @@ -4059,12 +4440,13 @@ } FormBinding.prototype.childBindingAdded = function(binding) { - var field, index, node; + var definition, field, index, node; if (binding.isInputBinding && Batman.isChildOf(this.get('node'), binding.get('node'))) { - if (~(index = binding.get('key').indexOf(this.contextName))) { + if (~ (index = binding.get('key').indexOf(this.contextName))) { node = binding.get('node'); field = binding.get('key').slice(index + this.contextName.length + 1); - return new Batman.DOM.AddClassBinding(node, this.errorClass, this.get('keyPath') + (" | get 'errors." + field + ".length'"), this.renderContext, this.renderer); + definition = new Batman.DOM.AttrReaderBindingDefinition(node, this.errorClass, this.get('keyPath') + (" | get 'errors." + field + ".length'"), this.renderContext, this.renderer); + return new Batman.DOM.AddClassBinding(definition); } } }; @@ -4090,28 +4472,43 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.EventBinding = (function(_super) { __extends(EventBinding, _super); - EventBinding.prototype.bindImmediately = false; + EventBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.None; - function EventBinding(node, eventName, key, context) { - var attacher, callback, - _this = this; + function EventBinding() { + var attacher, callback, confirmText, _this = this; EventBinding.__super__.constructor.apply(this, arguments); + if (confirmText = this.node.getAttribute('data-confirm')) { + Batman.developer.deprecated("data-confirm"); + } callback = function() { var _ref; + if (confirmText && !confirm(confirmText)) { + return; + } return (_ref = _this.get('filteredValue')) != null ? _ref.apply(_this.get('callbackContext'), arguments) : void 0; }; if (attacher = Batman.DOM.events[this.attributeName]) { - attacher(this.node, callback, context); + attacher(this.node, callback, this.renderContext); } else { - Batman.DOM.events.other(this.node, this.attributeName, callback, context); + Batman.DOM.events.other(this.node, this.attributeName, callback, this.renderContext); } - this.bind(); } EventBinding.accessor('callbackContext', function() { @@ -4153,7 +4550,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.NodeAttributeBinding = (function(_super) { @@ -4184,7 +4592,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.CheckedBinding = (function(_super) { @@ -4197,7 +4616,7 @@ CheckedBinding.prototype.isInputBinding = true; CheckedBinding.prototype.dataChange = function(value) { - return this.node[this.attributeName] = !!value; + return this.node[this.attributeName] = !! value; }; return CheckedBinding; @@ -4208,7 +4627,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.AttributeBinding = (function(_super) { @@ -4218,6 +4648,8 @@ return AttributeBinding.__super__.constructor.apply(this, arguments); } + AttributeBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + AttributeBinding.prototype.dataChange = function(value) { return this.node.setAttribute(this.attributeName, value); }; @@ -4236,21 +4668,34 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.AddClassBinding = (function(_super) { __extends(AddClassBinding, _super); - function AddClassBinding(node, className, keyPath, renderContext, renderer, only, invert) { - var name, names; - this.invert = invert != null ? invert : false; - names = className.split('|'); + AddClassBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + + function AddClassBinding(definition) { + var name; + this.invert = definition.invert; this.classes = (function() { - var _i, _len, _results; + var _i, _len, _ref, _results; + _ref = definition.attr.split('|'); _results = []; - for (_i = 0, _len = names.length; _i < _len; _i++) { - name = names[_i]; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + name = _ref[_i]; _results.push({ name: name, pattern: new RegExp("(?:^|\\s)" + name + "(?:$|\\s)", 'i') @@ -4259,7 +4704,6 @@ return _results; })(); AddClassBinding.__super__.constructor.apply(this, arguments); - delete this.attributeName; } AddClassBinding.prototype.dataChange = function(value) { @@ -4269,7 +4713,7 @@ for (_i = 0, _len = _ref.length; _i < _len; _i++) { _ref1 = _ref[_i], name = _ref1.name, pattern = _ref1.pattern; includesClassName = pattern.test(currentName); - if (!!value === !this.invert) { + if ( !! value === !this.invert) { if (!includesClassName) { this.node.className = "" + currentName + " " + name; } @@ -4290,7 +4734,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.AbstractCollectionBinding = (function(_super) { @@ -4339,37 +4794,31 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.DOM.StyleBinding = (function(_super) { __extends(StyleBinding, _super); - StyleBinding.SingleStyleBinding = (function(_super1) { - - __extends(SingleStyleBinding, _super1); - - SingleStyleBinding.prototype.isTwoWay = function() { - return false; - }; - - function SingleStyleBinding() { - var args, parent, _i; - args = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), parent = arguments[_i++]; - this.parent = parent; - SingleStyleBinding.__super__.constructor.apply(this, args); - } - - SingleStyleBinding.prototype.dataChange = function(value) { - return this.parent.setStyle(this.attributeName, value); - }; - - return SingleStyleBinding; - - })(Batman.DOM.AbstractAttributeBinding); + StyleBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; function StyleBinding() { this.setStyle = __bind(this.setStyle, this); @@ -4421,7 +4870,9 @@ }; StyleBinding.prototype.bindSingleAttribute = function(attr, keyPath) { - return this.styleBindings[attr] = new this.constructor.SingleStyleBinding(this.node, attr, keyPath, this.renderContext, this.renderer, this.only, this); + var definition; + definition = new Batman.DOM.AttrReaderBindingDefinition(this.node, attr, keyPath, this.renderContext, this.renderer); + return this.styleBindings[attr] = new Batman.DOM.StyleBinding.SingleStyleBinding(definition, this); }; StyleBinding.prototype.setStyle = function(key, value) { @@ -4466,6 +4917,29 @@ return StyleBinding.__super__.unbindCollection.apply(this, arguments); }; + StyleBinding.SingleStyleBinding = (function(_super1) { + + __extends(SingleStyleBinding, _super1); + + SingleStyleBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + + SingleStyleBinding.prototype.isTwoWay = function() { + return false; + }; + + function SingleStyleBinding(definition, parent) { + this.parent = parent; + SingleStyleBinding.__super__.constructor.call(this, definition); + } + + SingleStyleBinding.prototype.dataChange = function(value) { + return this.parent.setStyle(this.attributeName, value); + }; + + return SingleStyleBinding; + + })(Batman.DOM.AbstractAttributeBinding); + return StyleBinding; })(Batman.DOM.AbstractCollectionBinding); @@ -4473,9 +4947,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.IteratorBinding = (function(_super) { @@ -4487,18 +4976,17 @@ IteratorBinding.prototype.bindImmediately = false; - function IteratorBinding(sourceNode, iteratorName, key, context, parentRenderer) { - var previousSiblingNode, - _this = this; - this.iteratorName = iteratorName; - this.key = key; - this.context = context; - this.parentRenderer = parentRenderer; + IteratorBinding.prototype.skipChildren = true; + + IteratorBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + + function IteratorBinding(definition) { this.handleArrayChanged = __bind(this.handleArrayChanged, this); + var previousSiblingNode, sourceNode, _this = this; + sourceNode = definition.node, this.iteratorName = definition.attr, this.key = definition.keyPath, this.parentRenderer = definition.renderer; this.nodeMap = new Batman.SimpleHash; this.rendererMap = new Batman.SimpleHash; - this.fragment = document.createDocumentFragment(); this.prototypeNode = sourceNode.cloneNode(true); this.prototypeNode.removeAttribute("data-foreach-" + this.iteratorName); previousSiblingNode = sourceNode.nextSibling; @@ -4516,18 +5004,14 @@ _this.bind(); return _this.parentRenderer.allowAndFire('rendered'); }); - IteratorBinding.__super__.constructor.call(this, this.endNode, this.iteratorName, this.key, this.context, this.parentRenderer); + definition.node = this.endNode; + IteratorBinding.__super__.constructor.apply(this, arguments); } IteratorBinding.prototype.parentNode = function() { return this.endNode.parentNode; }; - IteratorBinding.prototype.die = function() { - this.dead = true; - return IteratorBinding.__super__.die.apply(this, arguments); - }; - IteratorBinding.prototype.dataChange = function(collection) { var items, _items; if (collection != null) { @@ -4543,12 +5027,11 @@ }; IteratorBinding.prototype.handleArrayChanged = function(newItems) { - var existingNode, index, newItem, node, nodeAtIndex, parentNode, startIndex, unseenNodeMap, _i, _len, - _this = this; + var existingNode, index, newItem, node, nodeAtIndex, parentNode, startIndex, unseenNodeMap, _i, _len, _this = this; parentNode = this.parentNode(); startIndex = this._getStartNodeIndex() + 1; unseenNodeMap = this.nodeMap.merge(); - if (newItems != null) { + if (newItems) { for (index = _i = 0, _len = newItems.length; _i < _len; index = ++_i) { newItem = newItems[index]; nodeAtIndex = parentNode.childNodes[startIndex + index]; @@ -4562,7 +5045,12 @@ } } unseenNodeMap.forEach(function(item, node) { - return _this._removeItem(item); + if (_this._nodesToBeRendered.has(node)) { + _this._nodesToBeRemoved || (_this._nodesToBeRemoved = new Batman.SimpleSet); + return _this._nodesToBeRemoved.add(node); + } else { + return _this._removeItem(item); + } }); }; @@ -4571,16 +5059,24 @@ }; IteratorBinding.prototype._newNodeForItem = function(newItem) { - var newNode, renderer, - _this = this; + var newNode, renderer, _this = this; newNode = this.prototypeNode.cloneNode(true); + this._nodesToBeRendered || (this._nodesToBeRendered = new Batman.SimpleSet); + this._nodesToBeRendered.add(newNode); Batman._data(newNode, "" + this.iteratorName + "Item", newItem); this.nodeMap.set(newItem, newNode); this.parentRenderer.prevent('rendered'); renderer = new Batman.Renderer(newNode, this.renderContext.descend(newItem, this.iteratorName), this.parentRenderer.view); - renderer.on('rendered', function() { - Batman.DOM.propagateBindingEvents(newNode); - _this.fire('nodeAdded', newNode, newItem); + renderer.once('rendered', function() { + var _ref; + _this._nodesToBeRendered.remove(newNode); + if ((_ref = _this._nodesToBeRemoved) != null ? _ref.has(newNode) : void 0) { + _this._nodesToBeRemoved.remove(newNode); + _this._removeItem(newItem); + } else { + Batman.DOM.propagateBindingEvents(newNode); + _this.fire('nodeAdded', newNode, newItem); + } return _this.parentRenderer.allowAndFire('rendered'); }); return newNode; @@ -4605,6 +5101,15 @@ return this.fire('nodeRemoved', node, item); }; + IteratorBinding.prototype.die = function() { + var _ref; + if (this._nodesToBeRendered && !this._nodesToBeRendered.isEmpty()) { + this._nodesToBeRemoved || (this._nodesToBeRemoved = new Batman.SimpleSet); + (_ref = this._nodesToBeRemoved).add.apply(_ref, this._nodesToBeRendered.toArray()); + } + return IteratorBinding.__super__.die.apply(this, arguments); + }; + return IteratorBinding; })(Batman.DOM.AbstractCollectionBinding); @@ -4612,9 +5117,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.ClassBinding = (function(_super) { @@ -4625,6 +5145,8 @@ return ClassBinding.__super__.constructor.apply(this, arguments); } + ClassBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + ClassBinding.prototype.dataChange = function(value) { if (value != null) { this.unbindCollection(); @@ -4672,7 +5194,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ValidationError = (function(_super) { @@ -4700,7 +5233,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.StorageAdapter = (function(_super) { @@ -4912,8 +5456,7 @@ }; StorageAdapter.prototype.runFilter = function(position, action, env, callback) { - var actionFilters, allFilters, filters, next, - _this = this; + var actionFilters, allFilters, filters, next, _this = this; this._inheritFilters(); allFilters = this._batman.filters[position].all || []; actionFilters = this._batman.filters[position][action] || []; @@ -4952,8 +5495,7 @@ }; StorageAdapter.prototype.perform = function(key, subject, options, callback) { - var env, next, - _this = this; + var env, next, _this = this; options || (options = {}); env = { options: options, @@ -4979,13 +5521,29 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + __indexOf = [].indexOf || + function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; Batman.RestStorage = (function(_super) { - var key, _fn, _i, _len, _ref, - _this = this; + var key, _fn, _i, _len, _ref, _this = this; __extends(RestStorage, _super); @@ -5329,6 +5887,7 @@ '403': RestStorage.NotAllowedError, '404': RestStorage.NotFoundError, '406': RestStorage.NotAcceptableError, + '409': RestStorage.RecordExistsError, '422': RestStorage.UnprocessableRecordError, '500': RestStorage.InternalStorageError, '501': RestStorage.NotImplementedError @@ -5356,7 +5915,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.LocalStorage = (function(_super) { @@ -5533,7 +6103,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.SessionStorage = (function(_super) { @@ -5561,7 +6142,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ParamsReplacer = (function(_super) { @@ -5627,7 +6219,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ParamsPusher = (function(_super) { @@ -5649,7 +6252,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.NamedRouteQuery = (function(_super) { @@ -5791,7 +6405,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Dispatcher = (function(_super) { var ControllerDirectory; @@ -5922,7 +6547,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Route = (function(_super) { @@ -6080,9 +6716,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ControllerActionRoute = (function(_super) { @@ -6118,7 +6769,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.CallbackActionRoute = (function(_super) { @@ -6142,12 +6804,22 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.Hash = (function(_super) { - var k, _fn, _i, _j, _len, _len1, _ref, _ref1, - _this = this; + var k, _fn, _i, _j, _len, _len1, _ref, _ref1, _this = this; __extends(Hash, _super); @@ -6308,7 +6980,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.RenderCache = (function(_super) { @@ -6428,11 +7111,32 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + __indexOf = [].indexOf || + function(item) { + for (var i = 0, l = this.length; i < l; i++) { + if (i in this && this[i] === item) return i; + } + return -1; + }; Batman.Controller = (function(_super) { var _optionsFromFilterArguments; @@ -6520,8 +7224,7 @@ }; Controller.prototype.errorHandler = function(callback) { - var errorFrame, _ref, - _this = this; + var errorFrame, _ref, _this = this; errorFrame = (_ref = this._actionFrames) != null ? _ref[this._actionFrames.length - 1] : void 0; return function(err, result, env) { if (err) { @@ -6541,8 +7244,7 @@ }; Controller.prototype.handleError = function(error) { - var handled, _ref, - _this = this; + var handled, _ref, _this = this; handled = false; if ((_ref = this.constructor._batman.getAll('errorHandlers')) != null) { _ref.forEach(function(hash) { @@ -6601,8 +7303,7 @@ }; Controller.prototype.executeAction = function(action, params) { - var frame, oldRedirect, parentFrame, result, _ref, _ref1, - _this = this; + var frame, oldRedirect, parentFrame, result, _ref, _ref1, _this = this; if (params == null) { params = this.get('params'); } @@ -6662,8 +7363,7 @@ }; Controller.prototype.render = function(options) { - var action, frame, view, _ref, _ref1, - _this = this; + var action, frame, view, _ref, _ref1, _this = this; if (options == null) { options = {}; } @@ -6691,7 +7391,7 @@ if ((_ref1 = Batman.currentApp) != null) { _ref1.prevent('ready'); } - view.on('ready', function() { + view.once('ready', function() { var _ref2; Batman.DOM.Yield.withName(options.into).replace(view.get('node')); if ((_ref2 = Batman.currentApp) != null) { @@ -6754,11 +7454,21 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Set = (function(_super) { - var k, _fn, _i, _j, _len, _len1, _ref, _ref1, - _this = this; + var k, _fn, _i, _j, _len, _len1, _ref, _ref1, _this = this; __extends(Set, _super); @@ -6850,7 +7560,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ErrorsSet = (function(_super) { @@ -6876,12 +7597,22 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.SetProxy = (function(_super) { - var k, _fn, _i, _len, _ref, - _this = this; + var k, _fn, _i, _len, _ref, _this = this; __extends(SetProxy, _super); @@ -6907,14 +7638,12 @@ Batman.extend(SetProxy.prototype, Batman.Enumerable); SetProxy.prototype.filter = function(f) { - var r; - r = new Batman.Set(); - return this.reduce((function(r, e) { - if (f(e)) { - r.add(e); + return this.reduce(function(accumulator, element) { + if (f(element)) { + accumulator.add(element); } - return r; - }), r); + return accumulator; + }, new Batman.Set()); }; SetProxy.prototype.replace = function() { @@ -6957,9 +7686,24 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.BinarySetOperation = (function(_super) { @@ -7015,7 +7759,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.SetUnion = (function(_super) { @@ -7057,7 +7812,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.SetIntersection = (function(_super) { @@ -7082,7 +7848,9 @@ } return _results; })(); - return this.add.apply(this, itemsToAdd); + if (itemsToAdd.length > 0) { + return this.add.apply(this, itemsToAdd); + } }; SetIntersection.prototype._itemsWereRemovedFromSource = function() { @@ -7099,7 +7867,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.SetComplement = (function(_super) { @@ -7125,7 +7904,9 @@ } return _results; })(); - return this.add.apply(this, itemsToAdd); + if (itemsToAdd.length > 0) { + return this.add.apply(this, itemsToAdd); + } } else { itemsToRemove = (function() { var _i, _len, _results; @@ -7138,7 +7919,9 @@ } return _results; })(); - return this.remove.apply(this, itemsToRemove); + if (itemsToRemove.length > 0) { + return this.remove.apply(this, itemsToRemove); + } } }; @@ -7159,13 +7942,15 @@ } return _results; })(); - return this.add.apply(this, itemsToAdd); + if (itemsToAdd.length > 0) { + return this.add.apply(this, itemsToAdd); + } } }; SetComplement.prototype._addComplement = function(items, opposite) { - var item; - return this.add.apply(this, (function() { + var item, itemsToAdd; + itemsToAdd = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = items.length; _i < _len; _i++) { @@ -7175,7 +7960,10 @@ } } return _results; - })()); + })(); + if (itemsToAdd.length > 0) { + return this.add.apply(this, itemsToAdd); + } }; return SetComplement; @@ -7186,7 +7974,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.StateMachine = (function(_super) { @@ -7200,8 +7999,7 @@ StateMachine.InvalidTransitionError.prototype = new Error; StateMachine.transitions = function(table) { - var definePredicate, fromState, k, object, predicateKeys, toState, transitions, v, _fn, _ref, - _this = this; + var definePredicate, fromState, k, object, predicateKeys, toState, transitions, v, _fn, _ref, _this = this; for (k in table) { v = table[k]; if (!(v.from && v.to)) { @@ -7347,9 +8145,19 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, + var __hasProp = {}.hasOwnProperty, + __extends = 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; + }, __slice = [].slice; Batman.Model = (function(_super) { @@ -7384,15 +8192,15 @@ Batman.initializeObject(this.prototype); (_base = this.prototype._batman).encoders || (_base.encoders = new Batman.SimpleHash); encoder = {}; - switch (Batman.typeOf(encoderOrLastKey)) { - case 'String': - keys.push(encoderOrLastKey); - break; - case 'Function': - encoder.encode = encoderOrLastKey; - break; - default: - encoder = encoderOrLastKey; + switch (Batman.typeOf(encoderOrLastKey)) { + case 'String': + keys.push(encoderOrLastKey); + break; + case 'Function': + encoder.encode = encoderOrLastKey; + break; + default: + encoder = encoderOrLastKey; } for (_j = 0, _len = keys.length; _j < _len; _j++) { key = keys[_j]; @@ -7543,20 +8351,12 @@ var _this = this; this.fire('loading', options); return this._doStorageOperation('readAll', options, function(err, records, env) { - var mappedRecords, record; + var mappedRecords; if (err != null) { _this.fire('error', err); return typeof callback === "function" ? callback(err, []) : void 0; } else { - mappedRecords = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = records.length; _i < _len; _i++) { - record = records[_i]; - _results.push(this._mapIdentity(record)); - } - return _results; - }).call(_this); + mappedRecords = _this._mapIdentities(records); _this.fire('loaded', mappedRecords, env); return typeof callback === "function" ? callback(err, mappedRecords, env) : void 0; } @@ -7566,7 +8366,8 @@ Model.create = function(attrs, callback) { var obj, _ref; if (!callback) { - _ref = [{}, attrs], attrs = _ref[0], callback = _ref[1]; + _ref = [{}, + attrs], attrs = _ref[0], callback = _ref[1]; } obj = new this(attrs); obj.save(callback); @@ -7595,22 +8396,30 @@ }; Model._mapIdentity = function(record) { - var existing, id, _ref; - if (typeof (id = record.get('id')) === 'undefined' || id === '') { - return record; - } else { - existing = (_ref = this.get("loaded.indexedBy.id").get(id)) != null ? _ref.toArray()[0] : void 0; - if (existing) { + return this._mapIdentities([record])[0]; + }; + + Model._mapIdentities = function(records) { + var existing, id, index, newRecords, record, _i, _len, _ref, _ref1; + newRecords = []; + for (index = _i = 0, _len = records.length; _i < _len; index = ++_i) { + record = records[index]; + if (!((id = record.get('id')) != null)) { + continue; + } else if (existing = (_ref = this.get('loaded.indexedBy.id').get(id)) != null ? _ref.toArray()[0] : void 0) { existing._withoutDirtyTracking(function() { var _ref1; return this.updateAttributes(((_ref1 = record.get('attributes')) != null ? _ref1.toObject() : void 0) || {}); }); - return existing; + records[index] = existing; } else { - this.get('loaded').add(record); - return record; + newRecords.push(record); } } + if (newRecords.length) { + (_ref1 = this.get('loaded')).add.apply(_ref1, newRecords); + } + return records; }; Model._doStorageOperation = function(operation, options, callback) { @@ -7685,14 +8494,6 @@ if (idOrAttributes == null) { idOrAttributes = {}; } - this.destroy = __bind(this.destroy, this); - - this.save = __bind(this.save, this); - - this.loadWithOptions = __bind(this.loadWithOptions, this); - - this.load = __bind(this.load, this); - Batman.developer.assert(this instanceof Batman.Object, "constructors must be called with new"); if (Batman.typeOf(idOrAttributes) === 'Object') { Model.__super__.constructor.call(this, idOrAttributes); @@ -7795,8 +8596,7 @@ }; Model.prototype.toJSON = function() { - var encoders, obj, - _this = this; + var encoders, obj, _this = this; obj = {}; encoders = this._batman.get('encoders'); if (!(!encoders || encoders.isEmpty())) { @@ -7817,8 +8617,7 @@ }; Model.prototype.fromJSON = function(data) { - var encoders, key, obj, value, - _this = this; + var encoders, key, obj, value, _this = this; obj = {}; encoders = this._batman.get('encoders'); if (!encoders || encoders.isEmpty() || !encoders.some(function(key, encoder) { @@ -7853,7 +8652,8 @@ Model.prototype.load = function(options, callback) { var _ref1; if (!callback) { - _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + _ref1 = [{}, + options], options = _ref1[0], callback = _ref1[1]; } else { options = { data: options @@ -7863,8 +8663,7 @@ }; Model.prototype.loadWithOptions = function(options, callback) { - var callbackQueue, hasOptions, _ref1, - _this = this; + var callbackQueue, hasOptions, _ref1, _this = this; hasOptions = Object.keys(options).length !== 0; if ((_ref1 = this.get('lifecycle.state')) === 'destroying' || _ref1 === 'destroyed') { if (typeof callback === "function") { @@ -7908,10 +8707,10 @@ }; Model.prototype.save = function(options, callback) { - var endState, isNew, startState, storageOperation, _ref1, _ref2, - _this = this; + var endState, isNew, startState, storageOperation, _ref1, _ref2, _this = this; if (!callback) { - _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + _ref1 = [{}, + options], options = _ref1[0], callback = _ref1[1]; } isNew = this.isNew(); _ref2 = isNew ? ['create', 'create', 'created'] : ['save', 'update', 'saved'], startState = _ref2[0], storageOperation = _ref2[1], endState = _ref2[2]; @@ -7924,8 +8723,7 @@ } associations = _this.constructor._batman.get('associations'); _this._withoutDirtyTracking(function() { - var _ref3, - _this = this; + var _ref3, _this = this; return associations != null ? (_ref3 = associations.getByType('belongsTo')) != null ? _ref3.forEach(function(association, label) { return association.apply(_this); }) : void 0 : void 0; @@ -7967,10 +8765,10 @@ }; Model.prototype.destroy = function(options, callback) { - var _ref1, - _this = this; + var _ref1, _this = this; if (!callback) { - _ref1 = [{}, options], options = _ref1[0], callback = _ref1[1]; + _ref1 = [{}, + options], options = _ref1[0], callback = _ref1[1]; } if (this.get('lifecycle').destroy()) { return this._doStorageOperation('destroy', { @@ -8053,8 +8851,7 @@ }; Model.prototype._doStorageOperation = function(operation, options, callback) { - var adapter, - _this = this; + var adapter, _this = this; Batman.developer.assert(this.hasStorage(), "Can't " + operation + " model " + (Batman.functionName(this.constructor)) + " without any storage adapters!"); adapter = this._batman.get('storage'); return adapter.perform(operation, this, options, function() { @@ -8083,8 +8880,7 @@ }).call(this); (function() { - var k, _fn, _i, _len, _ref, - _this = this; + var k, _fn, _i, _len, _ref, _this = this; _ref = Batman.AssociationCurator.availableAssociations; _fn = function(k) { @@ -8104,7 +8900,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Proxy = (function(_super) { @@ -8144,7 +8951,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.AssociationProxy = (function(_super) { @@ -8230,7 +9048,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.HasOneProxy = (function(_super) { @@ -8249,8 +9078,7 @@ }; HasOneProxy.prototype.fetchFromRemote = function(callback) { - var loadOptions, - _this = this; + var loadOptions, _this = this; loadOptions = { data: {} }; @@ -8279,7 +9107,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.BelongsToProxy = (function(_super) { @@ -8298,8 +9137,7 @@ }; BelongsToProxy.prototype.fetchFromRemote = function(callback) { - var loadOptions, - _this = this; + var loadOptions, _this = this; loadOptions = {}; if (this.association.options.url) { loadOptions.recordUrl = this.association.options.url; @@ -8320,7 +9158,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PolymorphicBelongsToProxy = (function(_super) { @@ -8339,8 +9188,7 @@ }; PolymorphicBelongsToProxy.prototype.fetchFromRemote = function(callback) { - var loadOptions, - _this = this; + var loadOptions, _this = this; loadOptions = {}; if (this.association.options.url) { loadOptions.recordUrl = this.association.options.url; @@ -8361,7 +9209,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Accessible = (function(_super) { @@ -8557,36 +9416,36 @@ throw new Error("value must be an Object"); } switch (valueType) { - case 'Array': - return ((function() { - var _i, _len; - arrayResults = []; - if (value.length === 0) { - arrayResults.push(queryFromParams(null, "" + prefix + "[]")); - } else { - for (_i = 0, _len = value.length; _i < _len; _i++) { - v = value[_i]; - arrayResults.push(queryFromParams(v, "" + prefix + "[]")); - } - } - return arrayResults; - })()).join("&"); - case 'Object': - return ((function() { - var _results; - _results = []; - for (k in value) { - v = value[k]; - _results.push(queryFromParams(v, prefix ? "" + prefix + "[" + (encodeQueryComponent(k)) + "]" : encodeQueryComponent(k))); - } - return _results; - })()).join("&"); - default: - if (prefix != null) { - return "" + prefix + "=" + (encodeQueryComponent(value)); + case 'Array': + return ((function() { + var _i, _len; + arrayResults = []; + if (value.length === 0) { + arrayResults.push(queryFromParams(null, "" + prefix + "[]")); } else { - return encodeQueryComponent(value); + for (_i = 0, _len = value.length; _i < _len; _i++) { + v = value[_i]; + arrayResults.push(queryFromParams(v, "" + prefix + "[]")); + } + } + return arrayResults; + })()).join("&"); + case 'Object': + return ((function() { + var _results; + _results = []; + for (k in value) { + v = value[k]; + _results.push(queryFromParams(v, prefix ? "" + prefix + "[" + (encodeQueryComponent(k)) + "]" : encodeQueryComponent(k))); } + return _results; + })()).join("&"); + default: + if (prefix != null) { + return "" + prefix + "=" + (encodeQueryComponent(value)); + } else { + return encodeQueryComponent(value); + } } }; @@ -8610,7 +9469,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.Request = (function(_super) { var dataHasFileUploads; @@ -8629,25 +9499,25 @@ } return list = (function() { switch (Batman.typeOf(object)) { - case 'Object': - list = (function() { - var _results; - _results = []; - for (k in object) { - v = object[k]; - _results.push(pairForList((first ? k : "" + key + "[" + k + "]"), v)); - } - return _results; - })(); - return list.reduce(function(acc, list) { - return acc.concat(list); - }, []); - case 'Array': - return object.reduce(function(acc, element) { - return acc.concat(pairForList("" + key + "[]", element)); - }, []); - default: - return [[key, object != null ? object : ""]]; + case 'Object': + list = (function() { + var _results; + _results = []; + for (k in object) { + v = object[k]; + _results.push(pairForList((first ? k : "" + key + "[" + k + "]"), v)); + } + return _results; + })(); + return list.reduce(function(acc, list) { + return acc.concat(list); + }, []); + case 'Array': + return object.reduce(function(acc, element) { + return acc.concat(pairForList("" + key + "[]", element)); + }, []); + default: + return [[key, object != null ? object : ""]]; } })(); }; @@ -8667,21 +9537,21 @@ } type = Batman.typeOf(data); switch (type) { - case 'Object': - for (k in data) { - v = data[k]; - if (dataHasFileUploads(v)) { - return true; - } + case 'Object': + for (k in data) { + v = data[k]; + if (dataHasFileUploads(v)) { + return true; } - break; - case 'Array': - for (_i = 0, _len = data.length; _i < _len; _i++) { - v = data[_i]; - if (dataHasFileUploads(v)) { - return true; - } + } + break; + case 'Array': + for (_i = 0, _len = data.length; _i < _len; _i++) { + v = data[_i]; + if (dataHasFileUploads(v)) { + return true; } + } } return false; }; @@ -8745,7 +9615,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.SetObserver = (function(_super) { @@ -8854,14 +9735,25 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.SetSort = (function(_super) { __extends(SetSort, _super); function SetSort(base, key, order) { - var boundReIndex; + var boundReIndex, _this = this; this.key = key; if (order == null) { order = "asc"; @@ -8871,7 +9763,9 @@ if (this.base.isObservable) { this._setObserver = new Batman.SetObserver(this.base); this._setObserver.observedItemKeys = [this.key]; - boundReIndex = this._reIndex.bind(this); + boundReIndex = function() { + return _this._reIndex(); + }; this._setObserver.observerForItemAndKey = function() { return boundReIndex; }; @@ -8923,9 +9817,11 @@ this.base.registerAsMutableSource(); return (function(func, args, ctor) { ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; + var child = new ctor, + result = func.apply(child, args), + t = typeof result; return t == "object" || t == "function" ? result || child : child; - })(Batman.Set, this._storage, function(){}).merge(other).sortedBy(this.key, this.order); + })(Batman.Set, this._storage, function() {}).merge(other).sortedBy(this.key, this.order); }; SetSort.prototype.compare = function(a, b) { @@ -8976,8 +9872,7 @@ }; SetSort.prototype._reIndex = function() { - var newOrder, _ref, - _this = this; + var newOrder, _ref, _this = this; newOrder = this.base.toArray().sort(function(a, b) { var multiple, valueA, valueB; valueA = Batman.get(a, _this.key); @@ -9011,7 +9906,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.AssociationSet = (function(_super) { @@ -9068,7 +9974,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PolymorphicAssociationSet = (function(_super) { @@ -9103,7 +10020,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.SetIndex = (function(_super) { @@ -9229,7 +10157,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PolymorphicAssociationSetIndex = (function(_super) { @@ -9238,14 +10177,25 @@ function PolymorphicAssociationSetIndex(association, type, key) { this.association = association; this.type = type; - PolymorphicAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModelForType(type).get('loaded'), key); + PolymorphicAssociationSetIndex.__super__.constructor.call(this, this.association.getRelatedModel().get('loaded'), key); } PolymorphicAssociationSetIndex.prototype._resultSetForKey = function(key) { - var _this = this; - return this._storage.getOrSet(key, function() { - return new _this.association.proxyClass(key, _this.type, _this.association); - }); + return this.association.setForKey(key); + }; + + PolymorphicAssociationSetIndex.prototype._addItem = function(item) { + if (this.association.modelType() !== item.get(this.association.foreignTypeKey)) { + return; + } + return PolymorphicAssociationSetIndex.__super__._addItem.apply(this, arguments); + }; + + PolymorphicAssociationSetIndex.prototype._removeItem = function(item) { + if (this.association.modelType() !== item.get(this.association.foreignTypeKey)) { + return; + } + return PolymorphicAssociationSetIndex.__super__._removeItem.apply(this, arguments); }; return PolymorphicAssociationSetIndex; @@ -9256,7 +10206,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.AssociationSetIndex = (function(_super) { @@ -9299,7 +10260,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.UniqueSetIndex = (function(_super) { @@ -9340,7 +10312,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.UniqueAssociationSetIndex = (function(_super) { @@ -9359,7 +10342,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PolymorphicUniqueAssociationSetIndex = (function(_super) { @@ -9378,7 +10372,11 @@ }).call(this); (function() { - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + var __bind = function(fn, me) { + return function() { + return fn.apply(me, arguments); + }; + }, __slice = [].slice; Batman.Navigator = (function() { @@ -9392,7 +10390,7 @@ }; Navigator.forApp = function(app) { - return new (this.defaultClass())(app); + return new(this.defaultClass())(app); }; function Navigator(app) { @@ -9448,7 +10446,7 @@ Navigator.prototype.push = function(params) { var path, pathFromParams, _base; - pathFromParams = typeof (_base = this.app.get('dispatcher')).pathFromParams === "function" ? _base.pathFromParams(params) : void 0; + pathFromParams = typeof(_base = this.app.get('dispatcher')).pathFromParams === "function" ? _base.pathFromParams(params) : void 0; if (pathFromParams) { this._lastRedirect = pathFromParams; } @@ -9461,7 +10459,7 @@ Navigator.prototype.replace = function(params) { var path, pathFromParams, _base; - pathFromParams = typeof (_base = this.app.get('dispatcher')).pathFromParams === "function" ? _base.pathFromParams(params) : void 0; + pathFromParams = typeof(_base = this.app.get('dispatcher')).pathFromParams === "function" ? _base.pathFromParams(params) : void 0; if (pathFromParams) { this._lastRedirect = pathFromParams; } @@ -9499,7 +10497,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PushStateNavigator = (function(_super) { @@ -9563,7 +10572,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.HashbangNavigator = (function(_super) { @@ -9660,8 +10680,7 @@ }; RouteMap.prototype.addRoute = function(name, route) { - var base, names, - _this = this; + var base, names, _this = this; this.childrenByOrder.push(route); if (name.length > 0 && (names = name.split('.')).length > 0) { base = names.shift(); @@ -9948,7 +10967,7 @@ } else { nestingParam = ":" + Batman.helpers.singularize(this.baseOptions.controller) + "Id"; nestingSegment = Batman.helpers.underscore(this.baseOptions.controller); - return "" + (this.parent._nestingPath()) + "/" + nestingSegment + "/" + nestingParam + "/"; + return "" + (this.parent._nestingPath()) + nestingSegment + "/" + nestingParam + "/"; } }; @@ -9956,7 +10975,7 @@ if (!this.parent) { return ""; } else { - return this.baseOptions.controller + "."; + return this.parent._nestingName() + this.baseOptions.controller + "."; } }; @@ -9975,12 +10994,22 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.App = (function(_super) { - var name, _fn, _i, _len, _ref, - _this = this; + var name, _fn, _i, _len, _ref, _this = this; __extends(App, _super); @@ -10046,10 +11075,12 @@ App.requirePath = ''; Batman.developer["do"](function() { + var requireDeprecated; + requireDeprecated = "Please use whatever means you'd like to load your code before calling App.run."; App.require = function() { - var base, name, names, path, _i, _len, - _this = this; + var base, name, names, path, _i, _len, _this = this; path = arguments[0], names = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + Batman.developer.deprecated("App.require", requireDeprecated); base = this.requirePath + path; for (_i = 0, _len = names.length; _i < _len; _i++) { name = names[_i]; @@ -10075,15 +11106,18 @@ App.controller = function() { var names; names = 1 <= arguments.length ? __slice.call(arguments, 0) : []; + Batman.developer.deprecated("App.controller", requireDeprecated); names = names.map(function(n) { return n + '_controller'; }); return this.require.apply(this, ['controllers'].concat(__slice.call(names))); }; App.model = function() { + Batman.developer.deprecated("App.model", requireDeprecated); return this.require.apply(this, ['models'].concat(__slice.call(arguments))); }; return App.view = function() { + Batman.developer.deprecated("App.view", requireDeprecated); return this.require.apply(this, ['views'].concat(__slice.call(arguments))); }; }); @@ -10109,8 +11143,7 @@ App.event('run').oneShot = true; App.run = function() { - var layout, layoutClass, - _this = this; + var layout, layoutClass, _this = this; if (Batman.currentApp) { if (Batman.currentApp === this) { return; @@ -10216,7 +11249,7 @@ this.options = Batman.extend(defaultOptions, this.defaultOptions, options); if (this.options.nestUrl) { if (!(this.model.urlNestsUnder != null)) { - developer.error("You must persist the the model " + this.model.constructor.name + " to use the url helpers on an association"); + Batman.developer.error("You must persist the the model " + this.model.constructor.name + " to use the url helpers on an association"); } this.model.urlNestsUnder(Batman.helpers.underscore(this.getRelatedModel().get('resourceName'))); } @@ -10261,8 +11294,7 @@ }; Association.prototype.inverse = function() { - var inverse, relatedAssocs, - _this = this; + var inverse, relatedAssocs, _this = this; if (relatedAssocs = this.getRelatedModel()._batman.get('associations')) { if (this.options.inverseOf) { return relatedAssocs.getByLabel(this.options.inverseOf); @@ -10290,7 +11322,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PluralAssociation = (function(_super) { @@ -10306,8 +11349,7 @@ } PluralAssociation.prototype.setForRecord = function(record) { - var childModelSetIndex, indexValue, - _this = this; + var childModelSetIndex, indexValue, _this = this; indexValue = this.indexValueForRecord(record); childModelSetIndex = this.setIndex(); Batman.Property.withoutTracking(function() { @@ -10319,7 +11361,7 @@ return existingValueSet; } } - newSet = new _this.proxyClass(indexValue, _this); + newSet = _this.proxyClassInstanceForKey(indexValue); if (indexValue != null) { _this._setsByValue.set(indexValue, newSet); } @@ -10334,8 +11376,7 @@ }; PluralAssociation.prototype.setForKey = Batman.Property.wrapTrackingPrevention(function(indexValue) { - var foundSet, - _this = this; + var foundSet, _this = this; foundSet = void 0; this._setsByRecord.forEach(function(record, set) { if (foundSet != null) { @@ -10350,13 +11391,16 @@ return foundSet; } return this._setsByValue.getOrSet(indexValue, function() { - return new _this.proxyClass(indexValue, _this); + return _this.proxyClassInstanceForKey(indexValue); }); }); + PluralAssociation.prototype.proxyClassInstanceForKey = function(indexValue) { + return new this.proxyClass(indexValue, this); + }; + PluralAssociation.prototype.getAccessor = function(self, model, label) { - var relatedRecords, setInAttributes, - _this = this; + var relatedRecords, setInAttributes, _this = this; if (!self.getRelatedModel()) { return; } @@ -10410,7 +11454,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.HasManyAssociation = (function(_super) { @@ -10424,9 +11479,11 @@ if (options != null ? options.as : void 0) { return (function(func, args, ctor) { ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; + var child = new ctor, + result = func.apply(child, args), + t = typeof result; return t == "object" || t == "function" ? result || child : child; - })(Batman.PolymorphicHasManyAssociation, arguments, function(){}); + })(Batman.PolymorphicHasManyAssociation, arguments, function() {}); } HasManyAssociation.__super__.constructor.apply(this, arguments); this.primaryKey = this.options.primaryKey || "id"; @@ -10434,8 +11491,7 @@ } HasManyAssociation.prototype.apply = function(baseSaveError, base) { - var relations, set, - _this = this; + var relations, set, _this = this; if (!baseSaveError) { if (relations = this.getFromAttributes(base)) { relations.forEach(function(model) { @@ -10522,7 +11578,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PolymorphicHasManyAssociation = (function(_super) { @@ -10542,8 +11609,7 @@ } PolymorphicHasManyAssociation.prototype.apply = function(baseSaveError, base) { - var relations, - _this = this; + var relations, _this = this; if (!baseSaveError) { if (relations = this.getFromAttributes(base)) { PolymorphicHasManyAssociation.__super__.apply.apply(this, arguments); @@ -10555,8 +11621,25 @@ return true; }; - PolymorphicHasManyAssociation.prototype.getRelatedModelForType = function() { - return this.getRelatedModel(); + PolymorphicHasManyAssociation.prototype.proxyClassInstanceForKey = function(indexValue) { + return new this.proxyClass(indexValue, this.modelType(), this); + }; + + PolymorphicHasManyAssociation.prototype.getRelatedModelForType = function(type) { + var relatedModel, scope; + scope = this.options.namespace || Batman.currentApp; + if (type) { + relatedModel = scope != null ? scope[type] : void 0; + relatedModel || (relatedModel = scope != null ? scope[Batman.helpers.camelize(type)] : void 0); + } else { + relatedModel = this.getRelatedModel(); + } + Batman.developer["do"](function() { + if ((Batman.currentApp != null) && !relatedModel) { + return Batman.developer.warn("Related model " + type + " for polymorphic association not found."); + } + }); + return relatedModel; }; PolymorphicHasManyAssociation.prototype.modelType = function() { @@ -10564,9 +11647,7 @@ }; PolymorphicHasManyAssociation.prototype.setIndex = function() { - if (!this.typeIndex) { - this.typeIndex = new Batman.PolymorphicAssociationSetIndex(this, this.modelType(), this[this.indexRelatedModelOn]); - } + this.typeIndex || (this.typeIndex = new Batman.PolymorphicAssociationSetIndex(this, this.modelType(), this[this.indexRelatedModelOn])); return this.typeIndex; }; @@ -10589,6 +11670,53 @@ }; }; + PolymorphicHasManyAssociation.prototype.decoder = function() { + var association; + association = this; + return function(data, key, _, __, parentRecord) { + var existingRecord, existingRelations, jsonObject, newRelations, record, relatedModel, savedRecord, subType, type, _i, _len; + if (relatedModel = association.getRelatedModel()) { + existingRelations = association.getFromAttributes(parentRecord) || association.setForRecord(parentRecord); + newRelations = existingRelations.filter(function(relation) { + return relation.isNew(); + }).toArray(); + for (_i = 0, _len = data.length; _i < _len; _i++) { + jsonObject = data[_i]; + type = jsonObject[association.options.foreignTypeKey]; + subType = association.getRelatedModelForType(type); + record = new subType(); + record._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + existingRecord = relatedModel.get('loaded').indexedByUnique('id').get(record.get('id')); + if (existingRecord != null) { + existingRecord._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + record = existingRecord; + } else { + if (newRelations.length > 0) { + savedRecord = newRelations.shift(); + savedRecord._withoutDirtyTracking(function() { + return this.fromJSON(jsonObject); + }); + record = savedRecord; + } + } + record = relatedModel._mapIdentity(record); + existingRelations.add(record); + if (association.options.inverseOf) { + record.set(association.options.inverseOf, parentRecord); + } + } + existingRelations.markAsLoaded(); + } else { + Batman.developer.error("Can't decode model " + association.options.name + " because it hasn't been loaded yet!"); + } + return existingRelations; + }; + }; + return PolymorphicHasManyAssociation; })(Batman.HasManyAssociation); @@ -10597,7 +11725,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.SingularAssociation = (function(_super) { @@ -10653,7 +11792,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.HasOneAssociation = (function(_super) { @@ -10718,7 +11868,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.BelongsToAssociation = (function(_super) { @@ -10741,9 +11902,11 @@ delete options.polymorphic; return (function(func, args, ctor) { ctor.prototype = func.prototype; - var child = new ctor, result = func.apply(child, args), t = typeof result; + var child = new ctor, + result = func.apply(child, args), + t = typeof result; return t == "object" || t == "function" ? result || child : child; - })(Batman.PolymorphicBelongsToAssociation, arguments, function(){}); + })(Batman.PolymorphicBelongsToAssociation, arguments, function() {}); } BelongsToAssociation.__super__.constructor.apply(this, arguments); this.foreignKey = this.options.foreignKey || ("" + this.label + "_id"); @@ -10798,7 +11961,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PolymorphicBelongsToAssociation = (function(_super) { @@ -10828,15 +12002,10 @@ PolymorphicBelongsToAssociation.prototype.inverse = false; PolymorphicBelongsToAssociation.prototype.apply = function(base) { - var foreignTypeValue, instanceOrProxy, model; + var foreignTypeValue, instanceOrProxy; PolymorphicBelongsToAssociation.__super__.apply.apply(this, arguments); if (instanceOrProxy = base.get(this.label)) { - if (instanceOrProxy instanceof Batman.AssociationProxy) { - model = instanceOrProxy.association.model; - } else { - model = instanceOrProxy.constructor; - } - foreignTypeValue = model.get('resourceName'); + foreignTypeValue = instanceOrProxy instanceof Batman.PolymorphicBelongsToProxy ? instanceOrProxy.get('foreignTypeValue') : instanceOrProxy.constructor.get('resourceName'); return base.set(this.foreignTypeKey, foreignTypeValue); } }; @@ -10891,8 +12060,7 @@ }; PolymorphicBelongsToAssociation.prototype.inverseForType = function(type) { - var inverse, relatedAssocs, _ref, - _this = this; + var inverse, relatedAssocs, _ref, _this = this; if (relatedAssocs = (_ref = this.getRelatedModelForType(type)) != null ? _ref._batman.get('associations') : void 0) { if (this.options.inverseOf) { return relatedAssocs.getByLabel(this.options.inverseOf); @@ -10938,7 +12106,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.Validator = (function(_super) { @@ -10971,10 +12150,10 @@ shouldReturn = false; for (key in options) { value = options[key]; - if (~((_ref = this._options) != null ? _ref.indexOf(key) : void 0)) { + if (~ ((_ref = this._options) != null ? _ref.indexOf(key) : void 0)) { results[key] = value; } - if (~((_ref1 = this._triggers) != null ? _ref1.indexOf(key) : void 0)) { + if (~ ((_ref1 = this._triggers) != null ? _ref1.indexOf(key) : void 0)) { results[key] = value; shouldReturn = true; } @@ -11039,7 +12218,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.RegExpValidator = (function(_super) { @@ -11077,7 +12267,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.PresenceValidator = (function(_super) { @@ -11112,7 +12313,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.NumericValidator = (function(_super) { @@ -11183,7 +12395,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.LengthValidator = (function(_super) { @@ -11242,7 +12465,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.AssociatedValidator = (function(_super) { @@ -11255,8 +12489,7 @@ AssociatedValidator.triggers('associated'); AssociatedValidator.prototype.validateEach = function(errors, record, key, callback) { - var childFinished, count, value, - _this = this; + var childFinished, count, value, _this = this; value = record.get(key); if (value != null) { if (value instanceof Batman.AssociationProxy) { @@ -11296,7 +12529,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ControllerActionFrame = (function(_super) { @@ -11310,7 +12554,7 @@ function ControllerActionFrame(options, onComplete) { ControllerActionFrame.__super__.constructor.call(this, options); - this.on('complete', onComplete); + this.once('complete', onComplete); } ControllerActionFrame.prototype.startOperation = function(options) { @@ -11354,7 +12598,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.DOM.InsertionBinding = (function(_super) { @@ -11364,26 +12619,25 @@ InsertionBinding.prototype.bindImmediately = false; - function InsertionBinding(node, className, key, context, parentRenderer, invert) { - var result, - _this = this; - this.invert = invert != null ? invert : false; + InsertionBinding.prototype.onlyObserve = Batman.BindingDefinitionOnlyObserve.Data; + + function InsertionBinding(definition) { + var _this = this; + this.invert = definition.invert; this.placeholderNode = document.createComment("detached node " + (this.get('_batmanID'))); - result = InsertionBinding.__super__.constructor.apply(this, arguments); + InsertionBinding.__super__.constructor.apply(this, arguments); Batman.DOM.onParseExit(this.node, function() { _this.bind(); if (_this.placeholderNode != null) { return Batman.DOM.trackBinding(_this, _this.placeholderNode); } }); - result; - } InsertionBinding.prototype.dataChange = function(value) { var parentNode; parentNode = this.placeholderNode.parentNode || this.node.parentNode; - if (!!value === !this.invert) { + if ( !! value === !this.invert) { if (!(this.node.parentNode != null)) { Batman.DOM.insertBefore(parentNode, this.node, this.placeholderNode); return parentNode.removeChild(this.placeholderNode); @@ -11397,14 +12651,17 @@ }; InsertionBinding.prototype.die = function() { + var filteredValue, node, placeholderNode; if (this.dead) { return; } + node = this.node, placeholderNode = this.placeholderNode; + filteredValue = this.get('filteredValue'); InsertionBinding.__super__.die.apply(this, arguments); - if (!!this.get('filteredValue') === !this.invert) { - return Batman.DOM.destroyNode(this.placeholderNode); + if ( !! filteredValue === !this.invert) { + return Batman.DOM.destroyNode(placeholderNode); } else { - return Batman.DOM.destroyNode(this.node); + return Batman.DOM.destroyNode(node); } }; @@ -11555,8 +12812,7 @@ }).call(this); (function() { - var buntUndefined, defaultAndOr, - __slice = [].slice; + var buntUndefined, defaultAndOr, __slice = [].slice; buntUndefined = function(f) { return function(value) { @@ -11752,7 +13008,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.RenderContext = (function() { var ContextProxy; @@ -11815,10 +13082,10 @@ return new this.constructor(object, this); }; - RenderContext.prototype.descendWithKey = function(key, scopedKey) { + RenderContext.prototype.descendWithDefinition = function(definition) { var proxy; - proxy = new ContextProxy(this, key); - return this.descend(proxy, scopedKey); + proxy = new ContextProxy(definition); + return this.descend(proxy, definition.attr); }; RenderContext.prototype.chain = function() { @@ -11854,11 +13121,8 @@ } }); - function ContextProxy(renderContext, keyPath, localKey) { - this.renderContext = renderContext; - this.keyPath = keyPath; - this.localKey = localKey; - this.binding = new Batman.DOM.AbstractBinding(void 0, this.keyPath, this.renderContext); + function ContextProxy(definition) { + this.binding = new Batman.DOM.AbstractBinding(definition); } return ContextProxy; @@ -11875,7 +13139,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }; + __extends = 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; + }; Batman.ViewStore = (function(_super) { @@ -11907,7 +13182,7 @@ 'final': true, get: function(path) { var contents; - if (path[0] !== '/') { + if (path.charAt(0) !== '/') { return this.get("/" + path); } if (this._viewContents[path]) { @@ -11926,7 +13201,7 @@ } }, set: function(path, content) { - if (path[0] !== '/') { + if (path.charAt(0) !== '/') { return this.set("/" + path, content); } this._requestedPaths.add(path); @@ -11959,7 +13234,18 @@ (function() { var __hasProp = {}.hasOwnProperty, - __extends = 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; }, + __extends = 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; + }, __slice = [].slice; Batman.View = (function(_super) { @@ -12025,7 +13311,7 @@ View.accessor('argumentBindings', function() { var _this = this; return new Batman.TerminalAccessible(function(key) { - var bindingKey, context, keyPath, node, _ref; + var bindingKey, context, definition, keyPath, node, _ref; if (!((node = _this.get('node')) && (context = _this.get('context')))) { return; } @@ -12037,7 +13323,8 @@ if ((_ref = _this[bindingKey]) != null) { _ref.die(); } - return _this[bindingKey] = new Batman.DOM.ViewArgumentBinding(node, keyPath, context); + definition = new Batman.DOM.ReaderBindingDefinition(node, keyPath, context); + return _this[bindingKey] = new Batman.DOM.ViewArgumentBinding(definition); }); }); @@ -12073,8 +13360,7 @@ return this.node; }, set: function(_, node) { - var updateHTML, - _this = this; + var updateHTML, _this = this; this.node = node; this._setNodeOwner(node); updateHTML = function(html) { @@ -12102,8 +13388,7 @@ }); function View(options) { - var context, - _this = this; + var context, _this = this; if (options == null) { options = {}; } @@ -12127,14 +13412,13 @@ } View.prototype.render = function() { - var node, - _this = this; + var node, _this = this; if (this._rendered) { return; } this._rendered = true; this._renderer = new Batman.Renderer(node = this.get('node'), this.get('context'), this); - return this._renderer.on('rendered', function() { + return this._renderer.once('rendered', function() { return _this.fire('ready', node); }); }; @@ -12157,6 +13441,26 @@ } }; + View.prototype.die = function() { + var _ref; + this.fire('destroy', this.node); + this.forget(); + if ((_ref = this._batman.properties) != null) { + _ref.forEach(function(key, property) { + return property.die(); + }); + } + return this.get('yields').forEach(function(name, actions) { + var node, _i, _len, _results; + _results = []; + for (_i = 0, _len = actions.length; _i < _len; _i++) { + node = actions[_i].node; + _results.push(Batman.DOM.didDestroyNode(node)); + } + return _results; + }); + }; + View.prototype.applyYields = function() { return this.get('yields').forEach(function(name, nodes) { var action, node, yieldObject, _i, _len, _ref, _results; @@ -12225,9 +13529,19 @@ }).call(this); (function() { - var Yield, - __hasProp = {}.hasOwnProperty, - __extends = 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; }, + var Yield, __hasProp = {}.hasOwnProperty, + __extends = 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; + }, __slice = [].slice; Batman.DOM.Yield = Yield = (function(_super) { @@ -12238,8 +13552,7 @@ Yield.queued = function(fn) { return function() { - var args, handler, - _this = this; + var args, handler, _this = this; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (this.containerNode != null) { return fn.apply(this, args); -- cgit v1.2.3 From 339f2e24ffeae847684a643d95eee4b923d27452 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Tue, 12 Mar 2013 19:44:20 +0100 Subject: Use https ruby gems in the gemfile --- templates/project/Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/project/Gemfile b/templates/project/Gemfile index 75cc574..8f1b17a 100644 --- a/templates/project/Gemfile +++ b/templates/project/Gemfile @@ -1,3 +1,3 @@ -source :rubygems +source 'https://rubygems.org' gem 'dashing' \ No newline at end of file -- cgit v1.2.3 From 4247f127bd88cd5d09f3778e07daf2a5d9c5de88 Mon Sep 17 00:00:00 2001 From: Emmanuel Hadoux Date: Wed, 20 Mar 2013 14:43:09 +0100 Subject: Add a Thor command to install a widget by its Gist Id. --- bin/dashing | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/bin/dashing b/bin/dashing index fb1332f..4fb4b50 100755 --- a/bin/dashing +++ b/bin/dashing @@ -3,6 +3,7 @@ require 'thor' require 'net/http' require 'json' +require 'open-uri' class MockScheduler def method_missing(*args) @@ -55,9 +56,34 @@ module Dashing send("generate_#{type}".to_sym, name) rescue NoMethodError => e puts "Invalid generator. Either use widget, dashboard, or job" - end + end map "g" => :generate + desc "install GIST_ID", "Installs a new widget from a gist." + def install(gist_id) + public_url = "https://gist.github.com/#{gist_id}" + gist = JSON.parse(open("https://api.github.com/gists/#{gist_id}").read) + + gist['files'].each do |filename, contents| + if filename.end_with?(".rb") + create_file File.join(Dir.pwd, 'jobs', filename), contents['content'] + elsif filename.end_with?(".coffee", ".html", ".scss") + widget_name = File.basename(filename, '.*') + create_file File.join(Dir.pwd, 'widgets', widget_name, filename), contents['content'] + end + end + + print set_color("Don't forget to edit the ", :yellow) + print set_color("Gemfile ", :yellow, :bold) + print set_color("and run ", :yellow) + print set_color("bundle install ", :yellow, :bold) + say set_color("if needed. More information for this widget can be found at #{public_url}", :yellow) + + rescue OpenURI::HTTPError => e + say set_color("Could not find gist at #{public_url}"), :red + end + map "i" => :install + desc "start", "Starts the server in style!" method_option :job_path, :desc => "Specify the directory where jobs are stored" def start(*args) @@ -76,7 +102,7 @@ module Dashing f = File.join(Dir.pwd, "jobs", "#{name}.rb") require f end - + end end -- cgit v1.2.3 From d59a2cc3fec5527844b81e9443445000f25d33d6 Mon Sep 17 00:00:00 2001 From: Steve Faulkner Date: Wed, 27 Mar 2013 14:48:44 -0500 Subject: Create .gitignore --- templates/project/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 templates/project/.gitignore diff --git a/templates/project/.gitignore b/templates/project/.gitignore new file mode 100644 index 0000000..ba646ec --- /dev/null +++ b/templates/project/.gitignore @@ -0,0 +1 @@ +*DS_STORE -- cgit v1.2.3 From 4937c2a2ea6768d6b1df80288c0963a3c1bb66b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20Sandstr=C3=B6m?= Date: Thu, 28 Mar 2013 16:44:56 +0100 Subject: Remove unnecessary semicolons --- templates/project/widgets/number/number.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/project/widgets/number/number.scss b/templates/project/widgets/number/number.scss index 292f8cc..8875794 100644 --- a/templates/project/widgets/number/number.scss +++ b/templates/project/widgets/number/number.scss @@ -4,8 +4,8 @@ $background-color: #47bbb3; $value-color: #fff; -$title-color: rgba(255, 255, 255, 0.7);; -$moreinfo-color: rgba(255, 255, 255, 0.7);; +$title-color: rgba(255, 255, 255, 0.7); +$moreinfo-color: rgba(255, 255, 255, 0.7); // ---------------------------------------------------------------------------- // Widget-number styles -- cgit v1.2.3 From 98f326eab33ee741c2d95c1861fc5c9233f0b47d Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 26 Mar 2013 13:27:58 -0400 Subject: Send an X-Accel-Redirect in /events to disable nginx buffering. --- lib/dashing.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index bae4c29..949cfee 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -32,6 +32,7 @@ end get '/events', provides: 'text/event-stream' do protected! + response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx stream :keep_open do |out| settings.connections << out out << latest_events @@ -116,4 +117,4 @@ Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } job_path = ENV["JOB_PATH"] || 'jobs' files = Dir[File.join(settings.root, job_path, '/*.rb')] -files.each { |job| require(job) } +files.each { |job| require(job) } -- cgit v1.2.3 From caaf6a8bd78cb980f282e88452b6901de3a99b2f Mon Sep 17 00:00:00 2001 From: Peter Suschlik Date: Thu, 18 Apr 2013 14:04:18 +0200 Subject: Use protocol agnostic google font url. HTTPS users are happy now :) --- templates/project/dashboards/layout.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/project/dashboards/layout.erb b/templates/project/dashboards/layout.erb index 23d3c9a..eae9785 100644 --- a/templates/project/dashboards/layout.erb +++ b/templates/project/dashboards/layout.erb @@ -12,7 +12,7 @@ - + -- cgit v1.2.3 From a1b14ec184f48285d5fa2bef4d2bb426b2bd2c58 Mon Sep 17 00:00:00 2001 From: Joel Friedlaender Date: Mon, 29 Apr 2013 15:24:42 +1000 Subject: Added suffix option for number widget Added an option to append a suffix to the number in the number widget. Done in the same was as prepend. Useful for things like percentage (eg. 10%). --- templates/project/widgets/number/number.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/project/widgets/number/number.html b/templates/project/widgets/number/number.html index 45e601b..795a469 100644 --- a/templates/project/widgets/number/number.html +++ b/templates/project/widgets/number/number.html @@ -1,6 +1,6 @@

-

+

-- cgit v1.2.3 From 31bdc6da2706eec95c54ca46cb8e544661296bf6 Mon Sep 17 00:00:00 2001 From: Federico Bana Date: Mon, 25 Mar 2013 16:58:19 -0300 Subject: Properly hyphenate css class names for widgets. --- bin/dashing | 7 ++++++- templates/widget/%name%/%name%.scss.tt | 2 +- test/cli_test.rb | 8 ++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/bin/dashing b/bin/dashing index 4fb4b50..8c7e348 100755 --- a/bin/dashing +++ b/bin/dashing @@ -28,6 +28,11 @@ module Dashing class << self attr_accessor :auth_token + + def hyphenate(str) + return str.downcase if str =~ /^[A-Z-]+$/ + str.gsub('_', '-').gsub(/\B[A-Z]/, '-\&').squeeze('-').downcase + end end attr_accessor :name @@ -106,4 +111,4 @@ module Dashing end end -Dashing::CLI.start \ No newline at end of file +Dashing::CLI.start diff --git a/templates/widget/%name%/%name%.scss.tt b/templates/widget/%name%/%name%.scss.tt index 0da5c49..660a554 100644 --- a/templates/widget/%name%/%name%.scss.tt +++ b/templates/widget/%name%/%name%.scss.tt @@ -1,3 +1,3 @@ -.widget-<%= name %> { +.widget-<%= Dashing::CLI.hyphenate(name) %> { } \ No newline at end of file diff --git a/test/cli_test.rb b/test/cli_test.rb index 4dc1eb3..6c43e2c 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -17,4 +17,12 @@ class CliTest < Dashing::Test end end + def test_hyphenate + assert_equal 'power', Dashing::CLI.hyphenate('Power') + assert_equal 'power', Dashing::CLI.hyphenate('POWER') + assert_equal 'power-rangers', Dashing::CLI.hyphenate('PowerRangers') + assert_equal 'power-ranger', Dashing::CLI.hyphenate('Power_ranger') + assert_equal 'super-power-rangers', Dashing::CLI.hyphenate('SuperPowerRangers') + end + end \ No newline at end of file -- cgit v1.2.3 From 1a974c754789b0b675d39442cead91213f706851 Mon Sep 17 00:00:00 2001 From: Aaron Peckham Date: Tue, 7 May 2013 15:09:54 -0700 Subject: Test that the Sinatra app redirects to the default dashboard; saves data posted to /widgets/X, and requires auth; returns data on /events; returns the sample dashboards; and returns sample widgets. --- bin/dashing | 8 ------ test/app_test.rb | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 8 deletions(-) create mode 100644 test/app_test.rb diff --git a/bin/dashing b/bin/dashing index 8c7e348..30824ce 100755 --- a/bin/dashing +++ b/bin/dashing @@ -11,14 +11,6 @@ class MockScheduler end end -def send_event(id, data) - req = Net::HTTP::Post.new("/widgets/#{id}") - req["content-type"] = "application/json" - req.body = JSON.unparse(data.merge(:auth_token => Dashing::CLI.auth_token)) - res = Net::HTTP.new('localhost', 3030).start { |http| http.request(req) } - puts "Data Sent to #{id}: #{data}" -end - SCHEDULER = MockScheduler.new module Dashing diff --git a/test/app_test.rb b/test/app_test.rb new file mode 100644 index 0000000..445c538 --- /dev/null +++ b/test/app_test.rb @@ -0,0 +1,84 @@ +require 'test_helper' +require File.expand_path('../../lib/dashing', __FILE__) + +class AppTest < Dashing::Test + def setup + @connection = [] + Sinatra::Application.settings.connections = [@connection] + Sinatra::Application.settings.auth_token = nil + end + + def test_redirect_to_default_dashboard + Sinatra::Application.settings.default_dashboard = 'test1' + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/test1', last_response.location + end + + def test_post_widgets_without_auth_token + post '/widgets/some_widget', JSON.generate({value: 6}) + assert_equal 204, last_response.status + + assert_equal 1, @connection.length + data = parse_data @connection[0] + assert_equal 6, data['value'] + assert_equal 'some_widget', data['id'] + assert data['updatedAt'] + end + + def test_post_widgets_with_invalid_auth_token + Sinatra::Application.settings.auth_token = 'sekrit' + post '/widgets/some_widget', JSON.generate({value: 9}) + assert_equal 401, last_response.status + end + + def test_post_widgets_with_valid_auth_token + Sinatra::Application.settings.auth_token = 'sekrit' + post '/widgets/some_widget', JSON.generate({value: 9, auth_token: 'sekrit'}) + assert_equal 204, last_response.status + end + + def test_get_events + post '/widgets/some_widget', JSON.generate({value: 8}) + assert_equal 204, last_response.status + + get '/events' + assert_equal 200, last_response.status + assert_equal 8, parse_data(@connection[0])['value'] + end + + def test_get_dashboard + with_generated_project do + get '/sampletv' + assert_equal 200, last_response.status + assert_include last_response.body, 'class="gridster"' + end + end + + def test_get_widget + with_generated_project do + get '/views/meter.html' + assert_equal 200, last_response.status + assert_include last_response.body, 'class="meter"' + end + end + + def with_generated_project + temp do |dir| + cli = Dashing::CLI.new + silent { cli.new 'new_project' } + + Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') + Sinatra::Application.settings.root = File.join(dir, 'new_project') + yield + end + end + + def app + Sinatra::Application + end + + def parse_data(string) + JSON.parse string[/data: (.+)/, 1] + end +end \ No newline at end of file -- cgit v1.2.3 From 50c8638f95584dbd863de6da042755ea400ee40b Mon Sep 17 00:00:00 2001 From: Aaron Peckham Date: Tue, 7 May 2013 21:27:46 -0700 Subject: add test for redirecting to first dashboard, and returning a 404 if dashboard doesn't exist --- test/app_test.rb | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/test/app_test.rb b/test/app_test.rb index 445c538..f6fa537 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -6,13 +6,7 @@ class AppTest < Dashing::Test @connection = [] Sinatra::Application.settings.connections = [@connection] Sinatra::Application.settings.auth_token = nil - end - - def test_redirect_to_default_dashboard - Sinatra::Application.settings.default_dashboard = 'test1' - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/test1', last_response.location + Sinatra::Application.settings.default_dashboard = nil end def test_post_widgets_without_auth_token @@ -46,6 +40,23 @@ class AppTest < Dashing::Test assert_equal 200, last_response.status assert_equal 8, parse_data(@connection[0])['value'] end + + def test_redirect_to_default_dashboard + with_generated_project do + Sinatra::Application.settings.default_dashboard = 'test1' + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/test1', last_response.location + end + end + + def test_redirect_to_first_dashboard + with_generated_project do + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/sample', last_response.location + end + end def test_get_dashboard with_generated_project do @@ -54,6 +65,13 @@ class AppTest < Dashing::Test assert_include last_response.body, 'class="gridster"' end end + + def test_get_nonexistent_dashboard + with_generated_project do + get '/nodashboard' + assert_equal 404, last_response.status + end + end def test_get_widget with_generated_project do -- cgit v1.2.3 From 8ad8097ed22cb557a2b5d946d11158575e82cb94 Mon Sep 17 00:00:00 2001 From: Zachary Salzbank Date: Mon, 29 Apr 2013 20:49:02 -0300 Subject: allow send_event to be called from within modules resolves the error: undefined local variable or method `settings' when send_event is called from in a module --- lib/dashing.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 949cfee..952b614 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -92,8 +92,8 @@ def send_event(id, body) body[:id] = id body[:updatedAt] ||= Time.now.to_i event = format_event(body.to_json) - settings.history[id] = event - settings.connections.each { |out| out << event } + Sinatra::Application.settings.history[id] = event + Sinatra::Application.settings.connections.each { |out| out << event } end def format_event(body) -- cgit v1.2.3 From 627504c696541432ba6f53b54754f6c8a547d611 Mon Sep 17 00:00:00 2001 From: Ben Thomas Date: Sun, 14 Apr 2013 13:22:06 -0600 Subject: updated version of gridster --- .../assets/javascripts/gridster/jquery.gridster.js | 687 ++++++++++++++++----- 1 file changed, 530 insertions(+), 157 deletions(-) diff --git a/templates/project/assets/javascripts/gridster/jquery.gridster.js b/templates/project/assets/javascripts/gridster/jquery.gridster.js index 9099177..9451c9a 100644 --- a/templates/project/assets/javascripts/gridster/jquery.gridster.js +++ b/templates/project/assets/javascripts/gridster/jquery.gridster.js @@ -1,6 +1,6 @@ -/*! gridster.js - v0.1.0 - 2012-08-14 +/*! gridster.js - v0.1.0 - 2013-02-15 * http://gridster.net/ -* Copyright (c) 2012 ducksboard; Licensed MIT */ +* Copyright (c) 2013 ducksboard; Licensed MIT */ ;(function($, window, document, undefined){ /** @@ -285,12 +285,8 @@ fn.get_closest_colliders = function(player_data_coords){ var colliders = this.find_collisions(player_data_coords); - var min_area = 100; - colliders.sort(function(a, b){ - if (a.area <= min_area) { - return 1; - } + colliders.sort(function(a, b) { /* if colliders are being overlapped by the "C" (center) region, * we have to set a lower index in the array to which they are placed * above in the grid. */ @@ -302,7 +298,7 @@ } } - if (a.area < b.area){ + if (a.area < b.area) { return 1; } @@ -369,8 +365,10 @@ distance: 1, limit: true, offset_left: 0, - autoscroll: true - // ,drag: function(e){}, + autoscroll: true, + ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], + handle: null + // drag: function(e){}, // start : function(e, ui){}, // stop : function(e){} }; @@ -424,12 +422,30 @@ fn.init = function() { this.calculate_positions(); this.$container.css('position', 'relative'); - this.enable(); + this.disabled = false; + this.events(); - $(window).bind('resize', - throttle($.proxy(this.calculate_positions, this), 200)); + this.on_window_resize = throttle($.proxy(this.calculate_positions, this), 200); + $(window).bind('resize', this.on_window_resize); }; + fn.events = function() { + this.proxied_on_select_start = $.proxy(this.on_select_start, this); + this.$container.on('selectstart', this.proxied_on_select_start); + + this.proxied_drag_handler = $.proxy(this.drag_handler, this); + this.$container.on(pointer_events.start, this.options.items, this.proxied_drag_handler); + + this.proxied_pointer_events_end = $.proxy(function(e) { + this.is_dragging = false; + if (this.disabled) { return; } + this.$body.off(pointer_events.move); + if (this.drag_start) { + this.on_dragstop(e); + } + }, this); + this.$body.on(pointer_events.end, this.proxied_pointer_events_end); + }; fn.get_actual_pos = function($el) { var pos = $el.position(); @@ -441,7 +457,7 @@ if (isTouch) { var oe = e.originalEvent; e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; - }; + } return { left: e.clientX, @@ -500,7 +516,7 @@ $window.scrollTop(nextScrollTop); this.scrollOffset = this.scrollOffset + 30; } - }; + } if (abs_mouse_top <= mouse_up_zone) { nextScrollTop = scrollTop - 30; @@ -508,26 +524,24 @@ $window.scrollTop(nextScrollTop); this.scrollOffset = this.scrollOffset - 30; } - }; - } + } + }; fn.calculate_positions = function(e) { this.window_height = $window.height(); - } + }; fn.drag_handler = function(e) { var node = e.target.nodeName; - - if (e.which !== 1 && !isTouch) { + if (this.disabled || e.which !== 1 && !isTouch) { return; } - if (node === 'INPUT' || node === 'TEXTAREA' || node === 'SELECT' || - node === 'BUTTON') { + if (this.ignore_drag(e)) { return; - }; + } var self = this; var first = true; @@ -537,7 +551,7 @@ this.mouse_init_pos = this.get_mouse_pos(e); this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; - this.$body.on(pointer_events.move, function(mme){ + this.on_pointer_events_move = function(mme){ var mouse_actual_pos = self.get_mouse_pos(mme); var diff_x = Math.abs( mouse_actual_pos.left - self.mouse_init_pos.left); @@ -545,7 +559,7 @@ mouse_actual_pos.top - self.mouse_init_pos.top); if (!(diff_x > self.options.distance || diff_y > self.options.distance) - ) { + ) { return false; } @@ -555,12 +569,14 @@ return false; } - if (self.is_dragging == true) { + if (self.is_dragging === true) { self.on_dragmove.call(self, mme); } return false; - }); + }; + + this.$body.on(pointer_events.move, this.on_pointer_events_move); return false; }; @@ -646,38 +662,43 @@ }; fn.on_select_start = function(e) { - return false; - } + if (this.disabled) { return; } + if (this.ignore_drag(e)) { + return; + } - fn.enable = function(){ - this.$container.on('selectstart', this.on_select_start); - - this.$container.on(pointer_events.start, this.options.items, $.proxy( - this.drag_handler, this)); - - this.$body.on(pointer_events.end, $.proxy(function(e) { - this.is_dragging = false; - this.$body.off(pointer_events.move); - if (this.drag_start) { - this.on_dragstop(e); - } - }, this)); + return false; }; + fn.enable = function() { + this.disabled = false; + }; - fn.disable = function(){ - this.$container.off(pointer_events.start); - this.$body.off(pointer_events.end); - this.$container.off('selectstart', this.on_select_start); + fn.disable = function() { + this.disabled = true; }; fn.destroy = function(){ this.disable(); + + this.$container.off('selectstart', this.proxied_on_select_start); + this.$container.off(pointer_events.start, this.proxied_drag_handler); + this.$body.off(pointer_events.end, this.proxied_pointer_events_end); + this.$body.off(pointer_events.move, this.on_pointer_events_move); + $(window).unbind('resize', this.on_window_resize); + $.removeData(this.$container, 'drag'); }; + fn.ignore_drag = function(event) { + if (this.options.handle) { + return !$(event.target).is(this.options.handle); + } + + return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0; + }; //jQuery adapter $.fn.drag = function ( options ) { @@ -694,7 +715,8 @@ ;(function($, window, document, undefined) { var defaults = { - widget_selector: '> li', + namespace: '', + widget_selector: 'li', widget_margins: [10, 10], widget_base_dimensions: [400, 225], extra_rows: 0, @@ -702,13 +724,14 @@ min_cols: 1, min_rows: 15, max_size_x: 6, - max_size_y: 6, autogenerate_stylesheet: true, avoid_overlapped_widgets: true, serialize_params: function($w, wgd) { return { col: wgd.col, - row: wgd.row + row: wgd.row, + size_x: wgd.size_x, + size_y: wgd.size_y }; }, collision: {}, @@ -742,8 +765,6 @@ * @param {Number} [options.min_rows] The minimum required rows. * @param {Number} [options.max_size_x] The maximum number of columns * that a widget can span. - * @param {Number} [options.max_size_y] The maximum number of rows - * that a widget can span. * @param {Boolean} [options.autogenerate_stylesheet] If true, all the * CSS required to position all widgets in their respective columns * and rows will be generated automatically and injected to the @@ -770,7 +791,7 @@ this.options = $.extend(true, defaults, options); this.$el = $(el); this.$wrapper = this.$el.parent(); - this.$widgets = $(this.options.widget_selector, this.$el).addClass('gs_w'); + this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w'); this.widgets = []; this.$changed = $([]); this.wrapper_width = this.$wrapper.width(); @@ -786,14 +807,15 @@ var fn = Gridster.prototype; fn.init = function() { - this.generate_grid_and_stylesheet(); - this.get_widgets_from_DOM(); - this.set_dom_grid_height(); - this.$wrapper.addClass('ready'); - this.draggable(); + this.generate_grid_and_stylesheet(); + this.get_widgets_from_DOM(); + this.set_dom_grid_height(); + this.$wrapper.addClass('ready'); + this.draggable(); + + this.on_window_resize = throttle($.proxy(this.recalculate_faux_grid, this), 200); - $(window).bind( - 'resize', throttle($.proxy(this.recalculate_faux_grid, this), 200)); + $(window).bind('resize', this.on_window_resize); }; @@ -826,32 +848,251 @@ * Add a new widget to the grid. * * @method add_widget - * @param {String} html The string representing the HTML of the widget. - * @param {Number} size_x The nº of rows the widget occupies horizontally. - * @param {Number} size_y The nº of columns the widget occupies vertically. + * @param {String|HTMLElement} html The string representing the HTML of the widget + * or the HTMLElement. + * @param {Number} [size_x] The nº of rows the widget occupies horizontally. + * @param {Number} [size_y] The nº of columns the widget occupies vertically. + * @param {Number} [col] The column the widget should start in. + * @param {Number} [row] The row the widget should start in. * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. * the widget that was just created. */ - fn.add_widget = function(html, size_x, size_y) { - var next_pos = this.next_position(size_x, size_y); + fn.add_widget = function(html, size_x, size_y, col, row) { + var pos; + size_x || (size_x = 1); + size_y || (size_y = 1); + + if (!col & !row) { + pos = this.next_position(size_x, size_y); + }else{ + pos = { + col: col, + row: row + }; + + this.empty_cells(col, row, size_x, size_y); + } var $w = $(html).attr({ - 'data-col': next_pos.col, - 'data-row': next_pos.row, - 'data-sizex' : next_pos.size_x, - 'data-sizey' : next_pos.size_y + 'data-col': pos.col, + 'data-row': pos.row, + 'data-sizex' : size_x, + 'data-sizey' : size_y }).addClass('gs_w').appendTo(this.$el).hide(); this.$widgets = this.$widgets.add($w); this.register_widget($w); + this.add_faux_rows(pos.size_y); + //this.add_faux_cols(pos.size_x); + this.set_dom_grid_height(); return $w.fadeIn(); }; + + /** + * Change the size of a widget. + * + * @method resize_widget + * @param {HTMLElement} $widget The jQuery wrapped HTMLElement + * representing the widget. + * @param {Number} size_x The number of columns that will occupy the widget. + * @param {Number} size_y The number of rows that will occupy the widget. + * @return {HTMLElement} Returns $widget. + */ + fn.resize_widget = function($widget, size_x, size_y) { + var wgd = $widget.coords().grid; + size_x || (size_x = wgd.size_x); + size_y || (size_y = wgd.size_y); + + if (size_x > this.cols) { + size_x = this.cols; + } + + var old_cells_occupied = this.get_cells_occupied(wgd); + var old_size_x = wgd.size_x; + var old_size_y = wgd.size_y; + var old_col = wgd.col; + var new_col = old_col; + var wider = size_x > old_size_x; + var taller = size_y > old_size_y; + + if (old_col + size_x - 1 > this.cols) { + var diff = old_col + (size_x - 1) - this.cols; + var c = old_col - diff; + new_col = Math.max(1, c); + } + + var new_grid_data = { + col: new_col, + row: wgd.row, + size_x: size_x, + size_y: size_y + }; + + var new_cells_occupied = this.get_cells_occupied(new_grid_data); + + var empty_cols = []; + $.each(old_cells_occupied.cols, function(i, col) { + if ($.inArray(col, new_cells_occupied.cols) === -1) { + empty_cols.push(col); + } + }); + + var occupied_cols = []; + $.each(new_cells_occupied.cols, function(i, col) { + if ($.inArray(col, old_cells_occupied.cols) === -1) { + occupied_cols.push(col); + } + }); + + var empty_rows = []; + $.each(old_cells_occupied.rows, function(i, row) { + if ($.inArray(row, new_cells_occupied.rows) === -1) { + empty_rows.push(row); + } + }); + + var occupied_rows = []; + $.each(new_cells_occupied.rows, function(i, row) { + if ($.inArray(row, old_cells_occupied.rows) === -1) { + occupied_rows.push(row); + } + }); + + this.remove_from_gridmap(wgd); + + if (occupied_cols.length) { + var cols_to_empty = [ + new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget + ]; + this.empty_cells.apply(this, cols_to_empty); + } + + if (occupied_rows.length) { + var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget]; + this.empty_cells.apply(this, rows_to_empty); + } + + wgd.col = new_col; + wgd.size_x = size_x; + wgd.size_y = size_y; + this.add_to_gridmap(new_grid_data, $widget); + + //update coords instance attributes + $widget.data('coords').update({ + width: (size_x * this.options.widget_base_dimensions[0] + + ((size_x - 1) * this.options.widget_margins[0]) * 2), + height: (size_y * this.options.widget_base_dimensions[1] + + ((size_y - 1) * this.options.widget_margins[1]) * 2) + }); + + if (size_y > old_size_y) { + this.add_faux_rows(size_y - old_size_y); + } + + if (size_x > old_size_x) { + this.add_faux_cols(size_x - old_size_x); + } + + $widget.attr({ + 'data-col': new_col, + 'data-sizex': size_x, + 'data-sizey': size_y + }); + + if (empty_cols.length) { + var cols_to_remove_holes = [ + empty_cols[0], wgd.row, + empty_cols.length, + Math.min(old_size_y, size_y), + $widget + ]; + + this.remove_empty_cells.apply(this, cols_to_remove_holes); + } + + if (empty_rows.length) { + var rows_to_remove_holes = [ + new_col, wgd.row, size_x, size_y, $widget + ]; + this.remove_empty_cells.apply(this, rows_to_remove_holes); + } + + return $widget; + }; + + /** + * Move down widgets in cells represented by the arguments col, row, size_x, + * size_y + * + * @method empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} $exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.empty_cells = function(col, row, size_x, size_y, $exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row - size_y, + size_x: size_x, + size_y: size_y + }); + + $nexts.not($exclude).each($.proxy(function(i, w) { + var wgd = $(w).coords().grid; + if (!(wgd.row <= (row + size_y - 1))) { return; } + var diff = (row + size_y) - wgd.row; + this.move_widget_down($(w), diff); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + + /** + * Move up widgets below cells represented by the arguments col, row, size_x, + * size_y. + * + * @method remove_empty_cells + * @param {Number} col The column where the group of cells begin. + * @param {Number} row The row where the group of cells begin. + * @param {Number} size_x The number of columns that the group of cells + * occupy. + * @param {Number} size_y The number of rows that the group of cells + * occupy. + * @param {HTMLElement} exclude Exclude widgets from being moved. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { + var $nexts = this.widgets_below({ + col: col, + row: row, + size_x: size_x, + size_y: size_y + }); + + $nexts.not(exclude).each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), size_y ); + }, this)); + + this.set_dom_grid_height(); + + return this; + }; + + /** * Get the most left column below to add a new widget. * @@ -867,9 +1108,10 @@ var ga = this.gridmap; var cols_l = ga.length; var valid_pos = []; + var rows_l; for (var c = 1; c < cols_l; c++) { - var rows_l = ga[c].length; + rows_l = ga[c].length; for (var r = 1; r <= rows_l; r++) { var can_move_to = this.can_move_to({ size_x: size_x, @@ -899,12 +1141,21 @@ * * @method remove_widget * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. + * @param {Boolean|Function} silent If true, widgets below the removed one + * will not move up. If a Function is passed it will be used as callback. + * @param {Function} callback Function executed when the widget is removed. * @return {Class} Returns the instance of the Gridster Class. */ - fn.remove_widget = function(el, callback) { + fn.remove_widget = function(el, silent, callback) { var $el = el instanceof jQuery ? el : $(el); var wgd = $el.coords().grid; + // if silent is a function assume it's a callback + if ($.isFunction(silent)) { + callback = silent; + silent = false; + } + this.cells_occupied_by_placeholder = {}; this.$widgets = this.$widgets.not($el); @@ -915,9 +1166,11 @@ $el.fadeOut($.proxy(function() { $el.remove(); - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), wgd.size_y ); - }, this)); + if (!silent) { + $nexts.each($.proxy(function(i, widget) { + this.move_widget_up( $(widget), wgd.size_y ); + }, this)); + } this.set_dom_grid_height(); @@ -928,6 +1181,22 @@ }; + /** + * Remove all widgets from the grid. + * + * @method remove_all_widgets + * @param {Function} callback Function executed for each widget removed. + * @return {Class} Returns the instance of the Gridster Class. + */ + fn.remove_all_widgets = function(callback) { + this.$widgets.each($.proxy(function(i, el){ + this.remove_widget(el, true, callback); + }, this)); + + return this; + }; + + /** * Returns a serialized array of the widgets in the grid. * @@ -1001,7 +1270,7 @@ $el.data('coords').grid = wgd; this.add_to_gridmap(wgd, $el); - this.widgets.push($el); + return this; }; @@ -1073,7 +1342,6 @@ var self = this; var draggable_options = $.extend(true, {}, this.options.draggable, { offset_left: this.options.widget_margins[0], - items: '.gs_w', start: function(event, ui) { self.$widgets.filter('.player-revert') .removeClass('player-revert'); @@ -1105,8 +1373,8 @@ * This function is executed when the player begins to be dragged. * * @method on_start_drag - * @param {Event} The original browser event - * @param {Object} A prepared ui object. + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object. */ fn.on_start_drag = function(event, ui) { @@ -1156,14 +1424,14 @@ * This function is executed when the player is being dragged. * * @method on_drag - * @param {Event} The original browser event - * @param {Object} A prepared ui object. + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object. */ fn.on_drag = function(event, ui) { //break if dragstop has been fired if (this.$player === null) { return false; - }; + } var abs_offset = { left: ui.position.left + this.baseX, @@ -1199,8 +1467,8 @@ * This function is executed when the player stops being dragged. * * @method on_stop_drag - * @param {Event} The original browser event - * @param {Object} A prepared ui object. + * @param {Event} event The original browser event + * @param {Object} ui A prepared ui object. */ fn.on_stop_drag = function(event, ui) { this.$helper.add(this.$player).add(this.$wrapper) @@ -1244,7 +1512,13 @@ } this.$preview_holder.remove(); + this.$player = null; + this.$helper = null; + this.placeholder_grid_data = {}; + this.player_grid_data = {}; + this.cells_occupied_by_placeholder = {}; + this.cells_occupied_by_player = {}; this.set_dom_grid_height(); }; @@ -1263,7 +1537,7 @@ */ fn.on_overlapped_column_change = function(start_callback, stop_callback) { if (!this.colliders_data.length) { - return; + return this; } var cols = this.get_targeted_columns( this.colliders_data[0].el.data.col); @@ -1296,14 +1570,14 @@ * * @param {Function} start_callback Function executed when a new row begins * to be overlapped. The row is passed as first argument. - * @param {Function} stop_callback Function executed when a row stops being + * @param {Function} end_callback Function executed when a row stops being * overlapped. The row is passed as first argument. * @method on_overlapped_row_change * @return {Class} Returns the instance of the Gridster Class. */ fn.on_overlapped_row_change = function(start_callback, end_callback) { if (!this.colliders_data.length) { - return; + return this; } var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); var last_n_rows = this.last_rows.length; @@ -1329,18 +1603,18 @@ /** * Sets the current position of the player * - * @param {Function} start_callback Function executed when a new row begins - * to be overlapped. The row is passed as first argument. - * @param {Function} stop_callback Function executed when a row stops being - * overlapped. The row is passed as first argument. + * @param {Number} col + * @param {Number} row + * @param {Boolean} no_player * @method set_player - * @return {Class} Returns the instance of the Gridster Class. + * @return {object} */ - fn.set_player = function(col, row) { - this.empty_cells_player_occupies(); - + fn.set_player = function(col, row, no_player) { var self = this; - var cell = self.colliders_data[0].el.data; + if (!no_player) { + this.empty_cells_player_occupies(); + } + var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; var to_col = cell.col; var to_row = row || cell.row; @@ -1384,9 +1658,9 @@ * a upper row and which not. * * @method widgets_contraints - * @param {HTMLElements} $widgets A jQuery wrapped collection of + * @param {jQuery} $widgets A jQuery wrapped collection of * HTMLElements. - * @return {Array} Returns a literal Object with two keys: `can_go_up` & + * @return {object} Returns a literal Object with two keys: `can_go_up` & * `can_not_go_up`. Each contains a set of HTMLElements. */ fn.widgets_constraints = function($widgets) { @@ -1425,6 +1699,11 @@ */ fn.sort_by_row_asc = function(widgets) { widgets = widgets.sort(function(a, b) { + if (!a.row) { + a = $(a).coords().grid; + b = $(b).coords().grid; + } + if (a.row > b.row) { return 1; } @@ -1445,7 +1724,7 @@ */ fn.sort_by_row_and_col_asc = function(widgets) { widgets = widgets.sort(function(a, b) { - if (a.row > b.row || a.row == b.row && a.col > b.col) { + if (a.row > b.row || a.row === b.row && a.col > b.col) { return 1; } return -1; @@ -1499,7 +1778,7 @@ * each widget) in descending way. * * @method manage_movements - * @param {HTMLElements} $widgets A jQuery collection of HTMLElements + * @param {jQuery} $widgets A jQuery collection of HTMLElements * representing the widgets you want to move. * @param {Number} to_col The column to which we want to move the widgets. * @param {Number} to_row The row to which we want to move the widgets. @@ -1680,13 +1959,14 @@ /** - * Get widgets overlapping with the player. + * Get widgets overlapping with the player or with the object passed + * representing the grid cells. * * @method get_widgets_under_player * @return {HTMLElement} Returns a jQuery collection of HTMLElements */ - fn.get_widgets_under_player = function() { - var cells = this.cells_occupied_by_player; + fn.get_widgets_under_player = function(cells) { + cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); var $widgets = $([]); $.each(cells.cols, $.proxy(function(i, col) { @@ -1720,7 +2000,7 @@ size_x: phgd.size_x }); - //Prevents widgets go out of the grid + // Prevents widgets go out of the grid var right_col = (col + phgd.size_x - 1); if (right_col > this.cols) { col = col - (right_col - col); @@ -1747,6 +2027,16 @@ }, this)); } + + var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder); + if ($widgets_under_ph.length) { + $widgets_under_ph.each($.proxy(function(i, widget) { + var $w = $(widget); + this.move_widget_down( + $w, row + phgd.size_y - $w.data('coords').grid.row); + }, this)); + } + }; @@ -1814,33 +2104,26 @@ var upper_rows = []; var min_row = 10000; - if (widget_grid_data.col < this.player_grid_data.col && - (widget_grid_data.col + widget_grid_data.size_y - 1) > - (this.player_grid_data.col + this.player_grid_data.size_y - 1) - ) { - return false; - }; - - /* generate an array with columns as index and array with upper rows + /* generate an array with columns as index and array with topmost rows * empty as value */ this.for_each_column_occupied(widget_grid_data, function(tcol) { var grid_col = this.gridmap[tcol]; upper_rows[tcol] = []; var r = p_bottom_row + 1; - + // iterate over each row while (--r > 0) { if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { if (!grid_col[r].is(widget_grid_data.el)) { break; - }; + } } if (!this.is_player(tcol, r) && !this.is_placeholder_in(tcol, r) && !this.is_player_in(tcol, r)) { upper_rows[tcol].push(r); - }; + } if (r < min_row) { min_row = r; @@ -1942,7 +2225,7 @@ * Get widgets overlapping with the player. * * @method get_widgets_overlapped - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + * @return {jQuery} Returns a jQuery collection of HTMLElements. */ fn.get_widgets_overlapped = function() { var $w; @@ -1956,7 +2239,6 @@ // if there is a widget in the player position if (!this.gridmap[col]) { return true; } //next iteration var $w = this.gridmap[col][row]; - if (this.is_occupied(col, row) && !this.is_player($w) && $.inArray($w, used) === -1 ) { @@ -1976,7 +2258,7 @@ * * @method on_start_overlapping_column * @param {Number} col The collided column. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + * @return {jQuery} Returns a jQuery collection of HTMLElements. */ fn.on_start_overlapping_column = function(col) { this.set_player(col, false); @@ -1987,8 +2269,8 @@ * A callback executed when the player begins to collide with a row. * * @method on_start_overlapping_row - * @param {Number} col The collided row. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + * @param {Number} row The collided row. + * @return {jQuery} Returns a jQuery collection of HTMLElements. */ fn.on_start_overlapping_row = function(row) { this.set_player(false, row); @@ -2000,7 +2282,7 @@ * * @method on_stop_overlapping_column * @param {Number} col The collided row. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + * @return {jQuery} Returns a jQuery collection of HTMLElements. */ fn.on_stop_overlapping_column = function(col) { this.set_player(col, false); @@ -2018,7 +2300,7 @@ * * @method on_stop_overlapping_row * @param {Number} row The collided row. - * @return {HTMLElements} Returns a jQuery collection of HTMLElements. + * @return {jQuery} Returns a jQuery collection of HTMLElements. */ fn.on_stop_overlapping_row = function(row) { this.set_player(false, row); @@ -2128,9 +2410,9 @@ * Move down the specified widget and all below it. * * @method move_widget_down - * @param {HTMLElement} $widget The jQuery object representing the widget + * @param {jQuery} $widget The jQuery object representing the widget * you want to move. - * @param {Number} The number of cells that the widget has to move. + * @param {Number} y_units The number of cells that the widget has to move. * @return {Class} Returns the instance of the Gridster Class. */ fn.move_widget_down = function($widget, y_units) { @@ -2266,7 +2548,7 @@ * * @method widgets_below * @param {HTMLElement} $el The jQuery wrapped HTMLElement. - * @return {HTMLElements} A jQuery collection of HTMLElements. + * @return {jQuery} A jQuery collection of HTMLElements. */ fn.widgets_below = function($el) { var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; @@ -2276,14 +2558,12 @@ var $nexts = $([]); this.for_each_column_occupied(el_grid_data, function(col) { - self.for_each_widget_below(col, next_row, - function(tcol, trow) { - if (!self.is_player(this) && - $.inArray(this, $nexts) === -1) { - $nexts = $nexts.add(this); - return true; // break - } - }); + self.for_each_widget_below(col, next_row, function(tcol, trow) { + if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { + $nexts = $nexts.add(this); + return true; // break + } + }); }); return this.sort_by_row_asc($nexts); @@ -2331,6 +2611,7 @@ this.for_each_column_occupied(el_grid_data, function(col) { var $w = this.is_widget(col, prev_row); + if (this.is_occupied(col, prev_row) || this.is_player(col, prev_row) || this.is_placeholder_in(col, prev_row) || @@ -2356,9 +2637,10 @@ * the widget. * @param {Object} col The col to check. * @param {Object} row The row to check. + * @param {Number} [max_row] The max row allowed. * @return {Boolean} Returns true if all cells are empty, else return false. */ - fn.can_move_to = function(widget_grid_data, col, row) { + fn.can_move_to = function(widget_grid_data, col, row, max_row) { var ga = this.gridmap; var $w = widget_grid_data.el; var future_wd = { @@ -2373,7 +2655,11 @@ var right_col = col + widget_grid_data.size_x - 1; if (right_col > this.cols) { return false; - }; + } + + if (max_row && max_row < row + widget_grid_data.size_y - 1) { + return false; + } this.for_each_cell_occupied(future_wd, function(tcol, trow) { var $tw = this.is_widget(tcol, trow); @@ -2646,7 +2932,7 @@ } return $widgets; - } + }; /** @@ -2672,16 +2958,16 @@ */ fn.generate_stylesheet = function(opts) { var styles = ''; - var extra_cells = 10; - var max_size_y = this.options.max_size_y; var max_size_x = this.options.max_size_x; + var max_rows = 0; + var max_cols = 0; var i; var rules; opts || (opts = {}); opts.cols || (opts.cols = this.cols); opts.rows || (opts.rows = this.rows); - opts.namespace || (opts.namespace = ''); + opts.namespace || (opts.namespace = this.options.namespace); opts.widget_base_dimensions || (opts.widget_base_dimensions = this.options.widget_base_dimensions); opts.widget_margins || @@ -2691,8 +2977,8 @@ opts.min_widget_height = (opts.widget_margins[1] * 2) + opts.widget_base_dimensions[1]; - var serialized_opts = $.param(opts); // don't duplicate stylesheets for the same configuration + var serialized_opts = $.param(opts); if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { return false; } @@ -2700,7 +2986,7 @@ Gridster.generated_stylesheets.push(serialized_opts); /* generate CSS styles for cols */ - for (i = opts.cols + extra_cells; i >= 0; i--) { + for (i = opts.cols; i >= 0; i--) { styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + ((i * opts.widget_base_dimensions[0]) + (i * opts.widget_margins[0]) + @@ -2708,14 +2994,14 @@ } /* generate CSS styles for rows */ - for (i = opts.rows + extra_cells; i >= 0; i--) { + for (i = opts.rows; i >= 0; i--) { styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + ((i * opts.widget_base_dimensions[1]) + (i * opts.widget_margins[1]) + ((i + 1) * opts.widget_margins[1]) ) + 'px;} '); } - for (var y = 1; y <= max_size_y; y++) { + for (var y = 1; y <= opts.rows; y++) { styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + (y * opts.widget_base_dimensions[1] + (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}'); @@ -2771,7 +3057,23 @@ for (col = cols; col > 0; col--) { this.gridmap[col] = []; for (row = rows; row > 0; row--) { - var coords = $({ + this.add_faux_cell(row, col); + } + } + return this; + }; + + + /** + * Add cell to the faux grid. + * + * @method add_faux_cell + * @param {Number} row The row for the new faux cell. + * @param {Number} col The col for the new faux cell. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cell = function(row, col) { + var coords = $({ left: this.baseX + ((col - 1) * this.min_widget_width), top: this.baseY + (row -1) * this.min_widget_height, width: this.min_widget_width, @@ -2782,10 +3084,66 @@ original_row: row }).coords(); - this.gridmap[col][row] = false; - this.faux_grid.push(coords); + if (!$.isArray(this.gridmap[col])) { + this.gridmap[col] = []; + } + + this.gridmap[col][row] = false; + this.faux_grid.push(coords); + + return this; + }; + + + /** + * Add rows to the faux grid. + * + * @method add_faux_rows + * @param {Number} rows The number of rows you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_rows = function(rows) { + var actual_rows = this.rows; + var max_rows = actual_rows + (rows || 1); + + for (var r = max_rows; r > actual_rows; r--) { + for (var c = this.cols; c >= 1; c--) { + this.add_faux_cell(r, c); } } + + this.rows = max_rows; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + + return this; + }; + + /** + * Add cols to the faux grid. + * + * @method add_faux_cols + * @param {Number} cols The number of cols you want to add to the faux grid. + * @return {Object} Returns the instance of the Gridster class. + */ + fn.add_faux_cols = function(cols) { + var actual_cols = this.cols; + var max_cols = actual_cols + (cols || 1); + + for (var c = actual_cols; c < max_cols; c++) { + for (var r = this.rows; r >= 1; r--) { + this.add_faux_cell(r, c); + } + } + + this.cols = max_cols; + + if (this.options.autogenerate_stylesheet) { + this.generate_stylesheet(); + } + return this; }; @@ -2841,8 +3199,6 @@ var cols = Math.floor(aw / this.min_widget_width) + this.options.extra_cols; - var rows = Math.floor(ah / this.min_widget_height) + - this.options.extra_rows; var actual_cols = this.$widgets.map(function() { return $(this).attr('data-col'); @@ -2851,18 +3207,16 @@ //needed to pass tests with phantomjs actual_cols.length || (actual_cols = [0]); - var actual_rows = this.$widgets.map(function() { - return $(this).attr('data-row'); - }); - actual_rows = Array.prototype.slice.call(actual_rows, 0); - //needed to pass tests with phantomjs - actual_rows.length || (actual_rows = [0]); - var min_cols = Math.max.apply(Math, actual_cols); - var min_rows = Math.max.apply(Math, actual_rows); + + // get all rows that could be occupied by the current widgets + var max_rows = this.options.extra_rows; + this.$widgets.each(function(i, w) { + max_rows += (+$(w).attr('data-sizey')); + }); this.cols = Math.max(min_cols, cols, this.options.min_cols); - this.rows = Math.max(min_rows, rows, this.options.min_rows); + this.rows = Math.max(max_rows, this.options.min_rows); this.baseX = ($(window).width() - aw) / 2; this.baseY = this.$wrapper.offset().top; @@ -2871,11 +3225,29 @@ this.generate_stylesheet(); } - /* more faux rows that needed are created so that there are cells - * where drag beyond the limits */ return this.generate_faux_grid(this.rows, this.cols); }; + /** + * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks + * + * @method destroy + * @return {undefined} + */ + fn.destroy = function(){ + // remove bound callback on window resize + $(window).unbind('resize', this.on_window_resize); + + if(this.drag_api){ + this.drag_api.destroy(); + } + + // lastly, remove gridster element + // this will additionally cause any data associated to this element to be removed, including this + // very gridster instance + this.$el.remove(); + }; + //jQuery adapter $.fn.gridster = function(options) { @@ -2886,5 +3258,6 @@ }); }; + $.Gridster = fn; }(jQuery, window, document)); \ No newline at end of file -- cgit v1.2.3 From 56b3ac96521c2630fde811b0f5fdf045a4ab7ff3 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Thu, 9 May 2013 23:03:18 +0200 Subject: Bump coffee script version. --- dashing.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 915819a..49d89da 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0.4' - s.date = '2013-02-13' + s.version = '1.0.5' + s.date = '2013-05-09' s.executables << 'dashing' @@ -17,7 +17,7 @@ Gem::Specification.new do |s| s.files = Dir['README.md', 'javascripts/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] s.add_dependency('sass') - s.add_dependency('coffee-script') + s.add_dependency('coffee-script', '>=1.6.2') s.add_dependency('sinatra') s.add_dependency('sinatra-contrib') s.add_dependency('thin') -- cgit v1.2.3 From 8795505a06fe58dfb5f414078587349b7771af62 Mon Sep 17 00:00:00 2001 From: Aaron Peckham Date: Thu, 9 May 2013 23:27:44 -0700 Subject: use any Tilt-supported view engine for dashboards, including Haml --- lib/dashing.rb | 10 +++++++--- test/app_test.rb | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 952b614..391095d 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -50,8 +50,12 @@ end get '/:dashboard' do protected! - if File.exist? File.join(settings.views, "#{params[:dashboard]}.erb") - erb params[:dashboard].to_sym + view_engine = Tilt.mappings.keys.find do |ext| + File.exist? File.join(settings.views, "#{params[:dashboard]}.#{ext}") + end + + if view_engine + render view_engine.to_sym, params[:dashboard].to_sym else halt 404 end @@ -107,7 +111,7 @@ def latest_events end def first_dashboard - files = Dir[File.join(settings.views, '*.erb')].collect { |f| f.match(/(\w*).erb/)[1] } + files = Dir[File.join(settings.views, '*')].collect { |f| File.basename(f, '.*') } files -= ['layout'] files.first end diff --git a/test/app_test.rb b/test/app_test.rb index f6fa537..83bdb74 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -58,6 +58,15 @@ class AppTest < Dashing::Test end end + def test_redirect_to_first_dashboard_without_erb + with_generated_project do |dir| + FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/htmltest', last_response.location + end + end + def test_get_dashboard with_generated_project do get '/sampletv' @@ -65,7 +74,26 @@ class AppTest < Dashing::Test assert_include last_response.body, 'class="gridster"' end end - + + begin + require 'haml' + def test_get_haml + with_generated_project do |dir| + File.write(File.join(dir, "dashboards/hamltest.haml"), <<-HAML) +.gridster + %ul + %li{data: {col: 1, row: 1, sizex: 1, sizey: 1}} + %div{data: {view: "Clock"}} + %i.icon-time.icon-background +HAML + get '/hamltest' + assert_equal 200, last_response.status + assert_include last_response.body, "class='gridster'" + end + end + rescue LoadError + end + def test_get_nonexistent_dashboard with_generated_project do get '/nodashboard' @@ -88,7 +116,7 @@ class AppTest < Dashing::Test Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') Sinatra::Application.settings.root = File.join(dir, 'new_project') - yield + yield Sinatra::Application.settings.root end end -- cgit v1.2.3 From b1b0b3c18d6ee05e42a043dde8d48058841df35c Mon Sep 17 00:00:00 2001 From: Nathan Broadbent Date: Sat, 18 May 2013 11:48:22 +1200 Subject: Persist history at exit and load on start, so that server restarts don't lose all pushed events --- lib/dashing.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 952b614..63fdc37 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -5,6 +5,7 @@ require 'rufus/scheduler' require 'coffee-script' require 'sass' require 'json' +require 'yaml' SCHEDULER = Rufus::Scheduler.start_new @@ -17,7 +18,21 @@ set :digest_assets, false settings.sprockets.append_path path end -set server: 'thin', connections: [], history: {} +set server: 'thin', connections: [], history_file: 'tmp/history.yml' + +# Persist history in tmp file at exit +at_exit do + File.open(settings.history_file, 'w') do |f| + f.puts settings.history.to_yaml + end +end + +if File.exists?(settings.history_file) + set history: YAML.load_file(settings.history_file) +else + set history: {} +end + set :public_folder, File.join(settings.root, 'public') set :views, File.join(settings.root, 'dashboards') set :default_dashboard, nil -- cgit v1.2.3 From a6eea61f2a7cfbf67175583dd7dcb49a4c09da75 Mon Sep 17 00:00:00 2001 From: Aaron Peckham Date: Mon, 20 May 2013 12:19:35 -0700 Subject: allow widget views to be written in any Tilt-supported template language --- lib/dashing.rb | 24 +++++++++++++++--------- test/app_test.rb | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 391095d..04921fe 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -50,21 +50,20 @@ end get '/:dashboard' do protected! - view_engine = Tilt.mappings.keys.find do |ext| - File.exist? File.join(settings.views, "#{params[:dashboard]}.#{ext}") + tilt_html_engines.each do |suffix, _| + file = File.join(settings.views, "#{params[:dashboard]}.#{suffix}") + return render(suffix.to_sym, params[:dashboard].to_sym) if File.exist? file end - if view_engine - render view_engine.to_sym, params[:dashboard].to_sym - else - halt 404 - end + halt 404 end get '/views/:widget?.html' do protected! - widget = params[:widget] - send_file File.join(settings.root, 'widgets', widget, "#{widget}.html") + tilt_html_engines.each do |suffix, engines| + file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{suffix}") + return engines.first.new(file).render if File.exist? file + end end post '/widgets/:id' do @@ -116,6 +115,13 @@ def first_dashboard files.first end +def tilt_html_engines + Tilt.mappings.select do |_, engines| + default_mime_type = engines.first.default_mime_type + default_mime_type.nil? || default_mime_type == 'text/html' + end +end + Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } {}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. diff --git a/test/app_test.rb b/test/app_test.rb index 83bdb74..97aad3a 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -72,26 +72,33 @@ class AppTest < Dashing::Test get '/sampletv' assert_equal 200, last_response.status assert_include last_response.body, 'class="gridster"' + assert_include last_response.body, "DOCTYPE" end end begin require 'haml' - def test_get_haml + + def test_get_haml_dashboard with_generated_project do |dir| - File.write(File.join(dir, "dashboards/hamltest.haml"), <<-HAML) -.gridster - %ul - %li{data: {col: 1, row: 1, sizex: 1, sizey: 1}} - %div{data: {view: "Clock"}} - %i.icon-time.icon-background -HAML + File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') get '/hamltest' assert_equal 200, last_response.status assert_include last_response.body, "class='gridster'" end end + + def test_get_haml_widget + with_generated_project do |dir| + File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') + File.unlink(File.join(dir, 'widgets/clock/clock.html')) + get '/views/clock.html' + assert_equal 200, last_response.status + assert_include last_response.body, '

haml

' + end + end rescue LoadError + puts "[skipping haml tests because haml isn't installed]" end def test_get_nonexistent_dashboard -- cgit v1.2.3 From f91c1b8962860eaeaa428d3ea75ebf61ced9ec6a Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 14 Jun 2013 18:14:02 +0200 Subject: Added dependency to the twitter gem so that the twitter widget can work with the 1.1 API. --- templates/project/Gemfile | 5 ++++- templates/project/jobs/twitter.rb | 31 +++++++++++++++++++++---------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/templates/project/Gemfile b/templates/project/Gemfile index 8f1b17a..e6ccd84 100644 --- a/templates/project/Gemfile +++ b/templates/project/Gemfile @@ -1,3 +1,6 @@ source 'https://rubygems.org' -gem 'dashing' \ No newline at end of file +gem 'dashing' + +## Remove this if you don't need a twitter widget. +gem 'twitter' \ No newline at end of file diff --git a/templates/project/jobs/twitter.rb b/templates/project/jobs/twitter.rb index 9359a89..5e70f30 100644 --- a/templates/project/jobs/twitter.rb +++ b/templates/project/jobs/twitter.rb @@ -1,17 +1,28 @@ -require 'net/http' -require 'json' +require 'twitter' + + +#### Get your twitter keys & secrets: +#### https://dev.twitter.com/docs/auth/tokens-devtwittercom +Twitter.configure do |config| + config.consumer_key = 'YOUR_CONSUMER_KEY' + config.consumer_secret = 'YOUR_CONSUMER_SECRET' + config.oauth_token = 'YOUR_OAUTH_TOKEN' + config.oauth_token_secret = 'YOUR_OAUTH_SECRET' +end search_term = URI::encode('#todayilearned') SCHEDULER.every '10m', :first_in => 0 do |job| - http = Net::HTTP.new('search.twitter.com') - response = http.request(Net::HTTP::Get.new("/search.json?q=#{search_term}")) - tweets = JSON.parse(response.body)["results"] - if tweets - tweets.map! do |tweet| - { name: tweet['from_user'], body: tweet['text'], avatar: tweet['profile_image_url_https'] } + begin + tweets = Twitter.search("#{search_term}").results + + if tweets + tweets.map! do |tweet| + { name: tweet.user.name, body: tweet.text, avatar: tweet.user.profile_image_url_https } + end + send_event('twitter_mentions', comments: tweets) end - - send_event('twitter_mentions', comments: tweets) + rescue Twitter::Error + puts "\e[33mFor the twitter widget to work, you need to put in your twitter API keys in the jobs/twitter.rb file.\e[0m" end end \ No newline at end of file -- cgit v1.2.3 From 2e1c714cc6cb957bbd23b248dd0945ce21757f4f Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 14 Jun 2013 18:32:38 +0200 Subject: Version 1.0.6. --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 49d89da..95c6608 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0.5' - s.date = '2013-05-09' + s.version = '1.0.6' + s.date = '2013-06-14' s.executables << 'dashing' -- cgit v1.2.3 From 6f2b57596819f6ecf9f61f161db8d8a7620a5ea8 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Fri, 21 Jun 2013 11:18:24 -0400 Subject: Version 1.0.7 --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 95c6608..56de14f 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0.6' - s.date = '2013-06-14' + s.version = '1.0.7' + s.date = '2013-06-21' s.executables << 'dashing' -- cgit v1.2.3 From f609a409637d9586814d5f37e9a060e89eab8382 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Fri, 21 Jun 2013 11:42:17 -0400 Subject: Changes history file location to avoid failing tests --- lib/dashing.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 24b191c..34e2cb5 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -18,7 +18,7 @@ set :digest_assets, false settings.sprockets.append_path path end -set server: 'thin', connections: [], history_file: 'tmp/history.yml' +set server: 'thin', connections: [], history_file: 'history.yml' # Persist history in tmp file at exit at_exit do -- cgit v1.2.3 From 062a84ca3921464e0ca4a65b4d914a4d40513858 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 24 Jun 2013 16:52:59 +0200 Subject: Update License --- MIT-LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MIT-LICENSE b/MIT-LICENSE index ade2039..d2bf435 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012 AUTHOR_NAME +Copyright (c) 2013 Shopify Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -17,4 +17,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -- cgit v1.2.3 From 32edb874f2fa2aefe363ec9d92d5f529cec489d8 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Tue, 25 Jun 2013 11:40:35 -0400 Subject: render titles correctly --- templates/project/dashboards/sample.erb | 2 +- templates/project/dashboards/sampletv.erb | 2 +- test/app_test.rb | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/templates/project/dashboards/sample.erb b/templates/project/dashboards/sample.erb index 7435b56..d41d538 100644 --- a/templates/project/dashboards/sample.erb +++ b/templates/project/dashboards/sample.erb @@ -1,4 +1,4 @@ -<% content_for(:title) { "My super sweet dashboard" } %> +<% content_for :title do %>My super sweet dashboard<% end %>
  • diff --git a/templates/project/dashboards/sampletv.erb b/templates/project/dashboards/sampletv.erb index 7ac9112..b88e636 100644 --- a/templates/project/dashboards/sampletv.erb +++ b/templates/project/dashboards/sampletv.erb @@ -8,7 +8,7 @@ $(function() { -<% content_for(:title) { "1080p dashboard" } %> +<% content_for :title do %>1080p dashboard<% end %>
      diff --git a/test/app_test.rb b/test/app_test.rb index 97aad3a..8b1be19 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -40,7 +40,7 @@ class AppTest < Dashing::Test assert_equal 200, last_response.status assert_equal 8, parse_data(@connection[0])['value'] end - + def test_redirect_to_default_dashboard with_generated_project do Sinatra::Application.settings.default_dashboard = 'test1' @@ -76,6 +76,13 @@ class AppTest < Dashing::Test end end + def test_page_title_set_correctly + with_generated_project do + get '/sampletv' + assert_include last_response.body, '1080p dashboard' + end + end + begin require 'haml' -- cgit v1.2.3 From 86d8c29db3087ce53f8c198cea6036c025d83855 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Thu, 27 Jun 2013 08:32:45 -0400 Subject: Updates gitignore to exclude compiled gem --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4ef0a06..2cc7498 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *DS_STORE -/Gemfile.lock \ No newline at end of file +/Gemfile.lock +*.gem \ No newline at end of file -- cgit v1.2.3 From 7b2a1e7cbd4bfc7cb256b4d374906ab90ad4360c Mon Sep 17 00:00:00 2001 From: David Underwood Date: Thu, 27 Jun 2013 08:37:12 -0400 Subject: bump minor gem version for release of history file --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 56de14f..0e3e46f 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.0.7' + s.version = '1.1.0' s.date = '2013-06-21' s.executables << 'dashing' -- cgit v1.2.3 From 86aac07d890c6ec87d9486e9580ecc87bc5dab26 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Fri, 28 Jun 2013 12:37:52 -0400 Subject: Yo dawg, I heard you liked jobs so we added recursive loading to your job loader so you can have job subfolders in the job folder that contain jobs --- lib/dashing.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index 34e2cb5..dc62395 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -141,5 +141,5 @@ Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } {}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. job_path = ENV["JOB_PATH"] || 'jobs' -files = Dir[File.join(settings.root, job_path, '/*.rb')] +files = Dir[File.join(settings.root, job_path, '**', '/*.rb')] files.each { |job| require(job) } -- cgit v1.2.3 From 3f58bbd626cd84d1cb24375b4d8fe6df75ce85ba Mon Sep 17 00:00:00 2001 From: Pieter van de Bruggen Date: Sun, 4 Nov 2012 17:10:36 -0800 Subject: Adding application messaging. While widgets are the most common target for events, there is good reason to sometimes target the application as a whole. This patch adds support for such events using the /-prefixed notation. (This convention is safe for use since it represents an extremely uncommon widget ID, and one which data could not be POSTed to.) Such events are NOT subject to replay, and are handled on the client-side by firing corresponding events on the Dashing application class. As a proof of concept (and to fufill a feature request), this patch also introduces a POST /reload endpoint, which when provided with a valid authkey (and optionally a dashboard name) fires the appropriate 'reload' event on all of the loaded dashboards. The 'reload' event handler then reloads the dashboard, unless a different dashboard was specified. --- javascripts/dashing.coffee | 13 +++++++++++-- lib/dashing.rb | 17 +++++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index ebf5c0a..f90c14b 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -25,6 +25,12 @@ Batman.Filters.shortenedNumber = (num) -> num class window.Dashing extends Batman.App + @on 'reload', (data) -> + if data.dashboard? + location.reload() if window.location.pathname is "/#{data.dashboard}" + else + location.reload() + @root -> Dashing.params = Batman.URI.paramsFromQuery(window.location.search.slice(1)); @@ -83,7 +89,6 @@ Dashing.AnimatedValue = @[k] = num @set k, to , 10 - @[k] = num Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} @@ -98,9 +103,13 @@ source.addEventListener 'error', (e)-> if (e.readyState == EventSource.CLOSED) console.log("Connection closed") -source.addEventListener 'message', (e) => +source.addEventListener 'message', (e) -> data = JSON.parse(e.data) if lastEvents[data.id]?.updatedAt != data.updatedAt + # /messages are internal messages, and cannot correspond to widgets. + # We will handle them as events on the Dashing application. + return Dashing.fire(data.id.slice(1), data) if data.id[0] is '/' + if Dashing.debugMode console.log("Received data for #{data.id}", data) lastEvents[data.id] = data diff --git a/lib/dashing.rb b/lib/dashing.rb index dc62395..4c1b44b 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -81,9 +81,22 @@ get '/views/:widget?.html' do end end +post '/reload' do + request.body.rewind + body = JSON.parse(request.body.read) + auth_token = body.delete("auth_token") + if !settings.auth_token || settings.auth_token == auth_token + send_event('/reload', body) + 204 # response without entity body + else + status 401 + "Invalid API key\n" + end +end + post '/widgets/:id' do request.body.rewind - body = JSON.parse(request.body.read) + body = JSON.parse(request.body.read) auth_token = body.delete("auth_token") if !settings.auth_token || settings.auth_token == auth_token send_event(params['id'], body) @@ -110,7 +123,7 @@ def send_event(id, body) body[:id] = id body[:updatedAt] ||= Time.now.to_i event = format_event(body.to_json) - Sinatra::Application.settings.history[id] = event + Sinatra::Application.settings.history[id] = event unless id =~ /^\// Sinatra::Application.settings.connections.each { |out| out << event } end -- cgit v1.2.3 From 5f8cbcb7debde027e79d87733b84cb852aa47dad Mon Sep 17 00:00:00 2001 From: Chad Jolly Date: Sun, 14 Jul 2013 18:36:19 -0600 Subject: dashboard events - use SSE event names --- javascripts/dashing.coffee | 9 +++++---- lib/dashing.rb | 17 ++++++++++------- test/app_test.rb | 16 +++++++++++++++- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index f90c14b..c4178f3 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -106,10 +106,6 @@ source.addEventListener 'error', (e)-> source.addEventListener 'message', (e) -> data = JSON.parse(e.data) if lastEvents[data.id]?.updatedAt != data.updatedAt - # /messages are internal messages, and cannot correspond to widgets. - # We will handle them as events on the Dashing application. - return Dashing.fire(data.id.slice(1), data) if data.id[0] is '/' - if Dashing.debugMode console.log("Received data for #{data.id}", data) lastEvents[data.id] = data @@ -117,6 +113,11 @@ source.addEventListener 'message', (e) -> for widget in widgets[data.id] widget.receiveData(data) +source.addEventListener 'dashboards', (e) -> + data = JSON.parse(e.data) + if Dashing.debugMode + console.log("Received data for dashboards", data) + Dashing.fire data.event, data $(document).ready -> Dashing.run() diff --git a/lib/dashing.rb b/lib/dashing.rb index 4c1b44b..935a031 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -81,12 +81,13 @@ get '/views/:widget?.html' do end end -post '/reload' do +post '/dashboards/:id' do request.body.rewind body = JSON.parse(request.body.read) + body['dashboard'] ||= params['id'] auth_token = body.delete("auth_token") if !settings.auth_token || settings.auth_token == auth_token - send_event('/reload', body) + send_event(params['id'], body, 'dashboards') 204 # response without entity body else status 401 @@ -119,16 +120,18 @@ def production? ENV['RACK_ENV'] == 'production' end -def send_event(id, body) +def send_event(id, body, target=nil) body[:id] = id body[:updatedAt] ||= Time.now.to_i - event = format_event(body.to_json) - Sinatra::Application.settings.history[id] = event unless id =~ /^\// + event = format_event(body.to_json, target) + Sinatra::Application.settings.history[id] = event unless target == 'dashboards' Sinatra::Application.settings.connections.each { |out| out << event } end -def format_event(body) - "data: #{body}\n\n" +def format_event(body, name=nil) + str = "" + str << "event: #{name}\n" if name + str << "data: #{body}\n\n" end def latest_events diff --git a/test/app_test.rb b/test/app_test.rb index 8b1be19..69e57c9 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -41,6 +41,16 @@ class AppTest < Dashing::Test assert_equal 8, parse_data(@connection[0])['value'] end + def test_dashboard_events + post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) + assert_equal 204, last_response.status + + get '/events' + assert_equal 200, last_response.status + assert_equal 'dashboards', parse_event(@connection[0]) + assert_equal 'reload', parse_data(@connection[0])['event'] + end + def test_redirect_to_default_dashboard with_generated_project do Sinatra::Application.settings.default_dashboard = 'test1' @@ -141,4 +151,8 @@ class AppTest < Dashing::Test def parse_data(string) JSON.parse string[/data: (.+)/, 1] end -end \ No newline at end of file + + def parse_event(string) + string[/event: (.+)/, 1] + end +end -- cgit v1.2.3 From 630269f1e695987002317c34cb4d6c703d5c1c40 Mon Sep 17 00:00:00 2001 From: Chad Jolly Date: Sun, 14 Jul 2013 22:03:11 -0600 Subject: use tmp dir for history file when running tests --- test/app_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/app_test.rb b/test/app_test.rb index 8b1be19..0546814 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -1,5 +1,6 @@ require 'test_helper' require File.expand_path('../../lib/dashing', __FILE__) +Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') class AppTest < Dashing::Test def setup @@ -141,4 +142,4 @@ class AppTest < Dashing::Test def parse_data(string) JSON.parse string[/data: (.+)/, 1] end -end \ No newline at end of file +end -- cgit v1.2.3 From 04f967847774d65dffaf0d6d6a8c29211b4fa7ea Mon Sep 17 00:00:00 2001 From: Matt Critchlow Date: Tue, 23 Jul 2013 17:54:19 -0700 Subject: add stop command to dashing fix dashing stop text description remove local comment from stop method --- bin/dashing | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/dashing b/bin/dashing index 30824ce..9d97700 100755 --- a/bin/dashing +++ b/bin/dashing @@ -92,6 +92,12 @@ module Dashing end map "s" => :start + desc "stop", "Stops the thin server" + def stop + command = "bundle exec thin stop" + system(command) + end + desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job. Make sure to supply your auth token if you have one set." def job(name, auth_token = "") Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } -- cgit v1.2.3 From 60dcd73bac913afe0a49b6c6c07b709aa288fd7d Mon Sep 17 00:00:00 2001 From: Chad Jolly Date: Sat, 20 Jul 2013 14:09:51 -0600 Subject: only fire dashboard events when target is current dashboard * send event to all dashboards by including {"dashboard": "*"} in payload * reload event forces reload from server, no caching --- javascripts/dashing.coffee | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index c4178f3..5712e98 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -26,10 +26,7 @@ Batman.Filters.shortenedNumber = (num) -> class window.Dashing extends Batman.App @on 'reload', (data) -> - if data.dashboard? - location.reload() if window.location.pathname is "/#{data.dashboard}" - else - location.reload() + window.location.reload(true) @root -> Dashing.params = Batman.URI.paramsFromQuery(window.location.search.slice(1)); @@ -89,6 +86,7 @@ Dashing.AnimatedValue = @[k] = num @set k, to , 10 + @[k] = num Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} @@ -117,7 +115,8 @@ source.addEventListener 'dashboards', (e) -> data = JSON.parse(e.data) if Dashing.debugMode console.log("Received data for dashboards", data) - Dashing.fire data.event, data + if data.dashboard is '*' or window.location.pathname is "/#{data.dashboard}" + Dashing.fire data.event, data $(document).ready -> Dashing.run() -- cgit v1.2.3 From bf0315fde57d27602a90ee6f2ecc92b2b73d42f5 Mon Sep 17 00:00:00 2001 From: Matt Critchlow Date: Tue, 23 Jul 2013 17:54:19 -0700 Subject: add stop command to dashing fix dashing stop text description remove local comment from stop method --- bin/dashing | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/dashing b/bin/dashing index 30824ce..9d97700 100755 --- a/bin/dashing +++ b/bin/dashing @@ -92,6 +92,12 @@ module Dashing end map "s" => :start + desc "stop", "Stops the thin server" + def stop + command = "bundle exec thin stop" + system(command) + end + desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job. Make sure to supply your auth token if you have one set." def job(name, auth_token = "") Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } -- cgit v1.2.3 From 60a3ddff2333a8fd518cbd190d5de254e6471cf6 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Mon, 29 Jul 2013 12:06:01 -0400 Subject: update gemspec to 1.2.0 --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 0e3e46f..050266b 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.1.0' - s.date = '2013-06-21' + s.version = '1.2.0' + s.date = '2013-07-29' s.executables << 'dashing' -- cgit v1.2.3 From 06ba2ea902bfd73a9c9437e7f44063b21611edb7 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Wed, 31 Jul 2013 10:49:00 +0200 Subject: Authenticate / route as to not leak private dashboard url --- lib/dashing.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dashing.rb b/lib/dashing.rb index 935a031..f5b60ca 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -56,6 +56,7 @@ get '/events', provides: 'text/event-stream' do end get '/' do + protected! begin redirect "/" + (settings.default_dashboard || first_dashboard).to_s rescue NoMethodError => e -- cgit v1.2.3 From 8e14229951405d18d1e206c2dabaeeb7644a42e0 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Thu, 8 Aug 2013 11:25:07 +0200 Subject: Handle widgets with multiple capital letters This change allows widgets to have names like AwesomeWidgetYes and it will be given awesome-widget-yes instead of awesome-widget_yes --- javascripts/dashing.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index 5712e98..d24bf54 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -11,7 +11,7 @@ Batman.Filters.dashize = (str) -> dashes_rx1 = /([A-Z]+)([A-Z][a-z])/g; dashes_rx2 = /([a-z\d])([A-Z])/g; - return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace('_', '-').toLowerCase() + return str.replace(dashes_rx1, '$1_$2').replace(dashes_rx2, '$1_$2').replace(/_/g, '-').toLowerCase() Batman.Filters.shortenedNumber = (num) -> return num if isNaN(num) -- cgit v1.2.3 From 7f2031512e5003d0d20d07bcebf248f76cfcd0a8 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 9 Aug 2013 18:23:00 +0200 Subject: The default dashboard is picked simply as the first one alphabetically across all OSes. Closes #97 --- lib/dashing.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index f5b60ca..2c3a810 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -144,7 +144,7 @@ end def first_dashboard files = Dir[File.join(settings.views, '*')].collect { |f| File.basename(f, '.*') } files -= ['layout'] - files.first + files.sort.first end def tilt_html_engines -- cgit v1.2.3 From 2b715ac63dd2de5c718142822663dbded44bbecd Mon Sep 17 00:00:00 2001 From: David Underwood Date: Fri, 16 Aug 2013 20:35:32 -0400 Subject: Allow the graph type to be specified when using the graph widget --- templates/project/widgets/graph/graph.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/project/widgets/graph/graph.coffee b/templates/project/widgets/graph/graph.coffee index 9b2eeec..28ce88e 100644 --- a/templates/project/widgets/graph/graph.coffee +++ b/templates/project/widgets/graph/graph.coffee @@ -15,6 +15,7 @@ class Dashing.Graph extends Dashing.Widget element: @node width: width height: height + renderer: @get("graphtype") series: [ { color: "#fff", -- cgit v1.2.3 From 9f93895bd40aad02e88f7ed7bfd954c930aa27db Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Tue, 20 Aug 2013 15:35:10 +0200 Subject: Strip html by default in widgets. Users can disable this with the 'raw' filter. Closes #176 --- templates/project/widgets/comments/comments.html | 2 +- templates/project/widgets/number/number.html | 2 +- templates/project/widgets/text/text.html | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/project/widgets/comments/comments.html b/templates/project/widgets/comments/comments.html index 898d2f6..7c580be 100644 --- a/templates/project/widgets/comments/comments.html +++ b/templates/project/widgets/comments/comments.html @@ -4,4 +4,4 @@

    -

    +

    diff --git a/templates/project/widgets/number/number.html b/templates/project/widgets/number/number.html index 795a469..c82e5f4 100644 --- a/templates/project/widgets/number/number.html +++ b/templates/project/widgets/number/number.html @@ -6,6 +6,6 @@

    -

    +

    diff --git a/templates/project/widgets/text/text.html b/templates/project/widgets/text/text.html index 7aeb66d..decd109 100644 --- a/templates/project/widgets/text/text.html +++ b/templates/project/widgets/text/text.html @@ -1,7 +1,7 @@

    -

    +

    -

    +

    -- cgit v1.2.3 From 9496b31d7787182b561bd99f8674901bd7667976 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Tue, 20 Aug 2013 09:54:21 -0400 Subject: Updates rickshaw and d3, and puts version numbers in the filenames --- templates/project/assets/javascripts/d3-3.2.8.js | 5 +++++ templates/project/assets/javascripts/d3.v2.min.js | 4 ---- templates/project/assets/javascripts/rickshaw-1.4.3.min.js | 2 ++ templates/project/assets/javascripts/rickshaw.min.js | 2 -- 4 files changed, 7 insertions(+), 6 deletions(-) create mode 100755 templates/project/assets/javascripts/d3-3.2.8.js delete mode 100644 templates/project/assets/javascripts/d3.v2.min.js create mode 100644 templates/project/assets/javascripts/rickshaw-1.4.3.min.js delete mode 100644 templates/project/assets/javascripts/rickshaw.min.js diff --git a/templates/project/assets/javascripts/d3-3.2.8.js b/templates/project/assets/javascripts/d3-3.2.8.js new file mode 100755 index 0000000..91fa2eb --- /dev/null +++ b/templates/project/assets/javascripts/d3-3.2.8.js @@ -0,0 +1,5 @@ +d3=function(){function n(n){return null!=n&&!isNaN(n)}function t(n){return n.length}function e(n){for(var t=1;n*t%1;)t*=10;return t}function r(n,t){try{for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}catch(r){n.prototype=t}}function i(){}function u(){}function a(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function o(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.substring(1);for(var e=0,r=Ca.length;r>e;++e){var i=Ca[e]+t;if(i in n)return i}}function c(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}function l(n){return Array.prototype.slice.call(n)}function s(){}function f(){}function h(n){function t(){for(var t,r=e,i=-1,u=r.length;++ie;e++)for(var i,u=n[e],a=0,o=u.length;o>a;a++)(i=u[a])&&t(i,a,e);return n}function C(n){return La(n,Ua),n}function z(n){var t,e;return function(r,i,u){var a,o=n[u].update,c=o.length;for(u!=e&&(e=u,t=0),i>=t&&(t=i+1);!(a=o[t])&&++t0&&(n=n.substring(0,o));var l=Va.get(n);return l&&(n=l,c=L),o?t?i:r:t?s:u}function j(n,t){return function(e){var r=ya.event;ya.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{ya.event=r}}}function L(n,t){var e=j(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function H(){var n=".dragsuppress-"+ ++Za,t="touchmove"+n,e="selectstart"+n,r="dragstart"+n,i="click"+n,u=ya.select(ba).on(t,g).on(e,g).on(r,g),a=xa.style,o=a[Xa];return a[Xa]="none",function(t){function e(){u.on(i,null)}u.on(n,null),a[Xa]=o,t&&(u.on(i,function(){g(),e()},!0),setTimeout(e,0))}}function F(n,t){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>Ba&&(ba.scrollX||ba.scrollY)){e=ya.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var i=e[0][0].getScreenCTM();Ba=!(i.f||i.e),e.remove()}return Ba?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var u=n.getBoundingClientRect();return[t.clientX-u.left-n.clientLeft,t.clientY-u.top-n.clientTop]}function P(){}function O(n,t,e){return new Y(n,t,e)}function Y(n,t,e){this.h=n,this.s=t,this.l=e}function R(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?u+(a-u)*n/60:180>n?a:240>n?u+(a-u)*(240-n)/60:u}function i(n){return Math.round(255*r(n))}var u,a;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,a=.5>=e?e*(1+t):e+t-e*t,u=2*e-a,at(i(n+120),i(n),i(n-120))}function U(n){return n>0?1:0>n?-1:0}function I(n){return n>1?0:-1>n?Ka:Math.acos(n)}function V(n){return n>1?Ka/2:-1>n?-Ka/2:Math.asin(n)}function X(n){return(Math.exp(n)-Math.exp(-n))/2}function Z(n){return(Math.exp(n)+Math.exp(-n))/2}function B(n){return(n=Math.sin(n/2))*n}function $(n,t,e){return new W(n,t,e)}function W(n,t,e){this.h=n,this.c=t,this.l=e}function J(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),G(e,Math.cos(n*=to)*t,Math.sin(n)*t)}function G(n,t,e){return new K(n,t,e)}function K(n,t,e){this.l=n,this.a=t,this.b=e}function Q(n,t,e){var r=(n+16)/116,i=r+t/500,u=r-e/200;return i=tt(i)*uo,r=tt(r)*ao,u=tt(u)*oo,at(rt(3.2404542*i-1.5371385*r-.4985314*u),rt(-.969266*i+1.8760108*r+.041556*u),rt(.0556434*i-.2040259*r+1.0572252*u))}function nt(n,t,e){return n>0?$(Math.atan2(e,t)*eo,Math.sqrt(t*t+e*e),n):$(0/0,0/0,n)}function tt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function et(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function rt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function it(n){return at(n>>16,255&n>>8,255&n)}function ut(n){return it(n)+""}function at(n,t,e){return new ot(n,t,e)}function ot(n,t,e){this.r=n,this.g=t,this.b=e}function ct(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function lt(n,t,e){var r,i,u,a=0,o=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(i=r[2].split(","),r[1]){case"hsl":return e(parseFloat(i[0]),parseFloat(i[1])/100,parseFloat(i[2])/100);case"rgb":return t(gt(i[0]),gt(i[1]),gt(i[2]))}return(u=so.get(n))?t(u.r,u.g,u.b):(null!=n&&"#"===n.charAt(0)&&(4===n.length?(a=n.charAt(1),a+=a,o=n.charAt(2),o+=o,c=n.charAt(3),c+=c):7===n.length&&(a=n.substring(1,3),o=n.substring(3,5),c=n.substring(5,7)),a=parseInt(a,16),o=parseInt(o,16),c=parseInt(c,16)),t(a,o,c))}function st(n,t,e){var r,i,u=Math.min(n/=255,t/=255,e/=255),a=Math.max(n,t,e),o=a-u,c=(a+u)/2;return o?(i=.5>c?o/(a+u):o/(2-a-u),r=n==a?(t-e)/o+(e>t?6:0):t==a?(e-n)/o+2:(n-t)/o+4,r*=60):(r=0/0,i=c>0&&1>c?0:r),O(r,i,c)}function ft(n,t,e){n=ht(n),t=ht(t),e=ht(e);var r=et((.4124564*n+.3575761*t+.1804375*e)/uo),i=et((.2126729*n+.7151522*t+.072175*e)/ao),u=et((.0193339*n+.119192*t+.9503041*e)/oo);return G(116*i-16,500*(r-i),200*(i-u))}function ht(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function gt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function pt(n){return"function"==typeof n?n:function(){return n}}function mt(n){return n}function dt(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),vt(t,e,n,r)}}function vt(n,t,e,r){function i(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(u,c)}catch(r){return a.error.call(u,r),void 0}a.load.call(u,n)}else a.error.call(u,c)}var u={},a=ya.dispatch("progress","load","error"),o={},c=new XMLHttpRequest,l=null;return!ba.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=i:c.onreadystatechange=function(){c.readyState>3&&i()},c.onprogress=function(n){var t=ya.event;ya.event=n;try{a.progress.call(u,c)}finally{ya.event=t}},u.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?o[n]:(null==t?delete o[n]:o[n]=t+"",u)},u.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",u):t},u.responseType=function(n){return arguments.length?(l=n,u):l},u.response=function(n){return e=n,u},["get","post"].forEach(function(n){u[n]=function(){return u.send.apply(u,[n].concat(za(arguments)))}}),u.send=function(e,r,i){if(2===arguments.length&&"function"==typeof r&&(i=r,r=null),c.open(e,n,!0),null==t||"accept"in o||(o.accept=t+",*/*"),c.setRequestHeader)for(var a in o)c.setRequestHeader(a,o[a]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=i&&u.on("error",i).on("load",function(n){i(null,n)}),c.send(null==r?null:r),u},u.abort=function(){return c.abort(),u},ya.rebind(u,a,"on"),null==r?u:u.get(yt(r))}function yt(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Mt(){var n=bt(),t=_t()-n;t>24?(isFinite(t)&&(clearTimeout(po),po=setTimeout(Mt,t)),go=0):(go=1,vo(Mt))}function xt(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now()),mo.callback=n,mo.time=e+t}function bt(){var n=Date.now();for(mo=fo;mo;)n>=mo.time&&(mo.flush=mo.callback(n-mo.time)),mo=mo.next;return n}function _t(){for(var n,t=fo,e=1/0;t;)t.flush?t=n?n.next=t.next:fo=t.next:(t.time8?function(n){return n/e}:function(n){return n*e},symbol:n}}function St(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Et(n){return n+""}function kt(){}function At(n,t,e){var r=e.s=n+t,i=r-n,u=r-i;e.t=n-u+(t-i)}function Nt(n,t){n&&qo.hasOwnProperty(n.type)&&qo[n.type](n,t)}function qt(n,t,e){var r,i=-1,u=n.length-e;for(t.lineStart();++io;++o)i.point((e=n[o])[0],e[1]);return i.lineEnd(),void 0}var c={point:e,points:n,other:null,visited:!1,entry:!0,subject:!0},l={point:e,points:[e],other:c,visited:!1,entry:!1,subject:!1};c.other=l,u.push(c),a.push(l),c={point:r,points:[r],other:null,visited:!1,entry:!1,subject:!0},l={point:r,points:[r],other:c,visited:!1,entry:!0,subject:!1},c.other=l,u.push(c),a.push(l)}}),a.sort(t),Bt(u),Bt(a),u.length){if(e)for(var o=1,c=!e(a[0].point),l=a.length;l>o;++o)a[o].entry=c=!c;for(var s,f,h,g=u[0];;){for(s=g;s.visited;)if((s=s.next)===g)return;f=s.points,i.lineStart();do{if(s.visited=s.other.visited=!0,s.entry){if(s.subject)for(var o=0;o=0;)i.point((h=f[o])[0],h[1])}else r(s.point,s.prev.point,-1,i);s=s.prev}s=s.other,f=s.points}while(!s.visited);i.lineEnd()}}}function Bt(n){if(t=n.length){for(var t,e,r=0,i=n[0];++r1&&2&t&&e.push(e.pop().concat(e.shift())),h.push(e.filter(Wt))}}var h,g,p,m=t(i),d={point:u,lineStart:o,lineEnd:c,polygonStart:function(){d.point=l,d.lineStart=s,d.lineEnd=f,h=[],g=[],i.polygonStart()},polygonEnd:function(){d.point=u,d.lineStart=o,d.lineEnd=c,h=ya.merge(h),h.length?Zt(h,Gt,null,e,i):r(g)&&(i.lineStart(),e(null,null,1,i),i.lineEnd()),i.polygonEnd(),h=g=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},v=Jt(),y=t(v);return d}}function Wt(n){return n.length>1}function Jt(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:s,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Gt(n,t){return((n=n.point)[0]<0?n[1]-Ka/2-Qa:Ka/2-n[1])-((t=t.point)[0]<0?t[1]-Ka/2-Qa:Ka/2-t[1])}function Kt(n,t){var e=n[0],r=n[1],i=[Math.sin(e),-Math.cos(e),0],u=0,a=!1,o=!1,c=0;Co.reset();for(var l=0,s=t.length;s>l;++l){var f=t[l],h=f.length;if(h){for(var g=f[0],p=g[0],m=g[1]/2+Ka/4,d=Math.sin(m),v=Math.cos(m),y=1;;){y===h&&(y=0),n=f[y];var M=n[0],x=n[1]/2+Ka/4,b=Math.sin(x),_=Math.cos(x),w=M-p,S=Math.abs(w)>Ka,E=d*b;if(Co.add(Math.atan2(E*Math.sin(w),v*_+E*Math.cos(w))),Math.abs(x)=0?2:-2)*Ka:w,S^p>=e^M>=e){var k=jt(zt(g),zt(n));Ft(k);var A=jt(i,k);Ft(A);var N=(S^w>=0?-1:1)*V(A[2]);r>N&&(c+=S^w>=0?1:-1)}if(!y++)break;p=M,d=b,v=_,g=n}Math.abs(u)>Qa&&(a=!0)}}return(!o&&!a&&0>Co||-Qa>u)^1&c}function Qt(n){var t,e=0/0,r=0/0,i=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(u,a){var o=u>0?Ka:-Ka,c=Math.abs(u-e);Math.abs(c-Ka)0?Ka/2:-Ka/2),n.point(i,r),n.lineEnd(),n.lineStart(),n.point(o,r),n.point(u,r),t=0):i!==o&&c>=Ka&&(Math.abs(e-i)Qa?Math.atan((Math.sin(t)*(u=Math.cos(r))*Math.sin(e)-Math.sin(r)*(i=Math.cos(t))*Math.sin(n))/(i*u*a)):(t+r)/2}function te(n,t,e,r){var i;if(null==n)i=e*Ka/2,r.point(-Ka,i),r.point(0,i),r.point(Ka,i),r.point(Ka,0),r.point(Ka,-i),r.point(0,-i),r.point(-Ka,-i),r.point(-Ka,0),r.point(-Ka,i);else if(Math.abs(n[0]-t[0])>Qa){var u=(n[0]a}function e(n){var e,u,a,c,s;return{lineStart:function(){c=a=!1,s=1},point:function(f,h){var g,p=[f,h],m=t(f,h),d=o?m?0:i(f,h):m?i(f+(0>f?Ka:-Ka),h):0;if(!e&&(c=a=m)&&n.lineStart(),m!==a&&(g=r(e,p),(Ot(e,g)||Ot(p,g))&&(p[0]+=Qa,p[1]+=Qa,m=t(p[0],p[1]))),m!==a)s=0,m?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(l&&e&&o^m){var v;d&u||!(v=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(v[0][0],v[0][1]),n.point(v[1][0],v[1][1]),n.lineEnd()):(n.point(v[1][0],v[1][1]),n.lineEnd(),n.lineStart(),n.point(v[0][0],v[0][1])))}!m||e&&Ot(e,p)||n.point(p[0],p[1]),e=p,a=m,u=d},lineEnd:function(){a&&n.lineEnd(),e=null},clean:function(){return s|(c&&a)<<1}}}function r(n,t,e){var r=zt(n),i=zt(t),u=[1,0,0],o=jt(r,i),c=Dt(o,o),l=o[0],s=c-l*l;if(!s)return!e&&n;var f=a*c/s,h=-a*l/s,g=jt(u,o),p=Ht(u,f),m=Ht(o,h);Lt(p,m);var d=g,v=Dt(p,d),y=Dt(d,d),M=v*v-y*(Dt(p,p)-1);if(!(0>M)){var x=Math.sqrt(M),b=Ht(d,(-v-x)/y);if(Lt(b,p),b=Pt(b),!e)return b;var _,w=n[0],S=t[0],E=n[1],k=t[1];w>S&&(_=w,w=S,S=_);var A=S-w,N=Math.abs(A-Ka)A;if(!N&&E>k&&(_=E,E=k,k=_),q?N?E+k>0^b[1]<(Math.abs(b[0]-w)Ka^(w<=b[0]&&b[0]<=S)){var T=Ht(d,(-v+x)/y);return Lt(T,p),[b,Pt(T)]}}}function i(t,e){var r=o?n:Ka-n,i=0;return-r>t?i|=1:t>r&&(i|=2),-r>e?i|=4:e>r&&(i|=8),i}function u(n){return Kt(c,n)}var a=Math.cos(n),o=a>0,c=[n,0],l=Math.abs(a)>Qa,s=Ne(n,6*to);return $t(t,e,s,u)}function ie(n,t,e,r){function i(r,i){return Math.abs(r[0]-n)0?0:3:Math.abs(r[0]-e)0?2:1:Math.abs(r[1]-t)0?1:0:i>0?3:2}function u(n,t){return a(n.point,t.point)}function a(n,t){var e=i(n,1),r=i(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}function o(i,u){var a=u[0]-i[0],o=u[1]-i[1],c=[0,1];return Math.abs(a)0&&(i[0]+=c[0]*a,i[1]+=c[0]*o),!0):!1}return function(c){function l(u){var a=i(u,-1),o=s([0===a||3===a?n:e,a>1?r:t]);return o}function s(n){for(var t=0,e=M.length,r=n[1],i=0;e>i;++i)for(var u,a=1,o=M[i],c=o.length,l=o[0];c>a;++a)u=o[a],l[1]<=r?u[1]>r&&f(l,u,n)>0&&++t:u[1]<=r&&f(l,u,n)<0&&--t,l=u;return 0!==t}function f(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(e[0]-n[0])*(t[1]-n[1])}function h(u,o,c,l){var s=0,f=0;if(null==u||(s=i(u,c))!==(f=i(o,c))||a(u,o)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(o[0],o[1])}function g(i,u){return i>=n&&e>=i&&u>=t&&r>=u}function p(n,t){g(n,t)&&c.point(n,t)}function m(){T.point=v,M&&M.push(x=[]),A=!0,k=!1,S=E=0/0}function d(){y&&(v(b,_),w&&k&&q.rejoin(),y.push(q.buffer())),T.point=p,k&&c.lineEnd()}function v(n,t){n=Math.max(-Bo,Math.min(Bo,n)),t=Math.max(-Bo,Math.min(Bo,t));var e=g(n,t);if(M&&x.push([n,t]),A)b=n,_=t,w=e,A=!1,e&&(c.lineStart(),c.point(n,t));else if(e&&k)c.point(n,t);else{var r=[S,E],i=[n,t];o(r,i)?(k||(c.lineStart(),c.point(r[0],r[1])),c.point(i[0],i[1]),e||c.lineEnd()):e&&(c.lineStart(),c.point(n,t))}S=n,E=t,k=e}var y,M,x,b,_,w,S,E,k,A,N=c,q=Jt(),T={point:p,lineStart:m,lineEnd:d,polygonStart:function(){c=q,y=[],M=[]},polygonEnd:function(){c=N,(y=ya.merge(y)).length?(c.polygonStart(),Zt(y,u,l,h,c),c.polygonEnd()):s([n,t])&&(c.polygonStart(),c.lineStart(),h(null,null,1,c),c.lineEnd(),c.polygonEnd()),y=M=x=null}};return T}}function ue(n,t,e){if(Math.abs(t)=n;var r=n/t;if(t>0){if(r>e[1])return!1;r>e[0]&&(e[0]=r)}else{if(rn&&(Jo=n),n>Ko&&(Ko=n),Go>t&&(Go=t),t>Qo&&(Qo=t)}function fe(){function n(n,t){a.push("M",n,",",t,u)}function t(n,t){a.push("M",n,",",t),o.point=e}function e(n,t){a.push("L",n,",",t)}function r(){o.point=n}function i(){a.push("Z")}var u=he(4.5),a=[],o={point:n,lineStart:function(){o.point=t},lineEnd:r,polygonStart:function(){o.lineEnd=i},polygonEnd:function(){o.lineEnd=r,o.point=n},pointRadius:function(n){return u=he(n),o},result:function(){if(a.length){var n=a.join("");return a=[],n}}};return o}function he(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function ge(n,t){Lo+=n,Ho+=t,++Fo}function pe(){function n(n,r){var i=n-t,u=r-e,a=Math.sqrt(i*i+u*u);Po+=a*(t+n)/2,Oo+=a*(e+r)/2,Yo+=a,ge(t=n,e=r)}var t,e;ec.point=function(r,i){ec.point=n,ge(t=r,e=i)}}function me(){ec.point=ge}function de(){function n(n,t){var e=n-r,u=t-i,a=Math.sqrt(e*e+u*u);Po+=a*(r+n)/2,Oo+=a*(i+t)/2,Yo+=a,a=i*n-r*t,Ro+=a*(r+n),Uo+=a*(i+t),Io+=3*a,ge(r=n,i=t)}var t,e,r,i;ec.point=function(u,a){ec.point=n,ge(t=r=u,e=i=a)},ec.lineEnd=function(){n(t,e)}}function ve(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,a,0,2*Ka)}function e(t,e){n.moveTo(t,e),o.point=r}function r(t,e){n.lineTo(t,e)}function i(){o.point=t}function u(){n.closePath()}var a=4.5,o={point:t,lineStart:function(){o.point=e},lineEnd:i,polygonStart:function(){o.lineEnd=u},polygonEnd:function(){o.lineEnd=i,o.point=t},pointRadius:function(n){return a=n,o},result:s};return o}function ye(n){function t(t){function r(e,r){e=n(e,r),t.point(e[0],e[1])}function i(){M=0/0,S.point=a,t.lineStart()}function a(r,i){var a=zt([r,i]),o=n(r,i);e(M,x,y,b,_,w,M=o[0],x=o[1],y=r,b=a[0],_=a[1],w=a[2],u,t),t.point(M,x)}function o(){S.point=r,t.lineEnd()}function c(){i(),S.point=l,S.lineEnd=s}function l(n,t){a(f=n,h=t),g=M,p=x,m=b,d=_,v=w,S.point=a}function s(){e(M,x,y,b,_,w,g,p,f,m,d,v,u,t),S.lineEnd=o,o()}var f,h,g,p,m,d,v,y,M,x,b,_,w,S={point:r,lineStart:i,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=i}};return S}function e(t,u,a,o,c,l,s,f,h,g,p,m,d,v){var y=s-t,M=f-u,x=y*y+M*M;if(x>4*r&&d--){var b=o+g,_=c+p,w=l+m,S=Math.sqrt(b*b+_*_+w*w),E=Math.asin(w/=S),k=Math.abs(Math.abs(w)-1)r||Math.abs((y*T+M*C)/x-.5)>.3||i>o*g+c*p+l*m)&&(e(t,u,a,o,c,l,N,q,k,b/=S,_/=S,w,d,v),v.point(N,q),e(N,q,k,b,_,w,s,f,h,g,p,m,d,v))}}var r=.5,i=Math.cos(30*to),u=16;return t.precision=function(n){return arguments.length?(u=(r=n*n)>0&&16,t):Math.sqrt(r)},t}function Me(n){var t=ye(function(t,e){return n([t*eo,e*eo])});return function(n){return n=t(n),{point:function(t,e){n.point(t*to,e*to)},sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}}function xe(n){return be(function(){return n})()}function be(n){function t(n){return n=o(n[0]*to,n[1]*to),[n[0]*h+c,l-n[1]*h]}function e(n){return n=o.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*eo,n[1]*eo]}function r(){o=ae(a=Se(v,y,M),u);var n=u(m,d);return c=g-n[0]*h,l=p+n[1]*h,i()}function i(){return s&&(s.valid=!1,s=null),t}var u,a,o,c,l,s,f=ye(function(n,t){return n=u(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,m=0,d=0,v=0,y=0,M=0,x=Xo,b=mt,_=null,w=null;return t.stream=function(n){return s&&(s.valid=!1),s=_e(a,x(f(b(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(x=null==n?(_=n,Xo):re((_=+n)*to),i()):_},t.clipExtent=function(n){return arguments.length?(w=n,b=null==n?mt:ie(n[0][0],n[0][1],n[1][0],n[1][1]),i()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(m=n[0]%360*to,d=n[1]%360*to,r()):[m*eo,d*eo]},t.rotate=function(n){return arguments.length?(v=n[0]%360*to,y=n[1]%360*to,M=n.length>2?n[2]%360*to:0,r()):[v*eo,y*eo,M*eo]},ya.rebind(t,f,"precision"),function(){return u=n.apply(this,arguments),t.invert=u.invert&&e,r()}}function _e(n,t){return{point:function(e,r){r=n(e*to,r*to),e=r[0],t.point(e>Ka?e-2*Ka:-Ka>e?e+2*Ka:e,r[1])},sphere:function(){t.sphere()},lineStart:function(){t.lineStart()},lineEnd:function(){t.lineEnd()},polygonStart:function(){t.polygonStart()},polygonEnd:function(){t.polygonEnd()}}}function we(n,t){return[n,t]}function Se(n,t,e){return n?t||e?ae(ke(n),Ae(t,e)):ke(n):t||e?Ae(t,e):we}function Ee(n){return function(t,e){return t+=n,[t>Ka?t-2*Ka:-Ka>t?t+2*Ka:t,e]}}function ke(n){var t=Ee(n);return t.invert=Ee(-n),t}function Ae(n,t){function e(n,t){var e=Math.cos(t),o=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+o*i;return[Math.atan2(c*u-s*a,o*r-l*i),V(s*u+c*a)]}var r=Math.cos(n),i=Math.sin(n),u=Math.cos(t),a=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),o=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*u-c*a;return[Math.atan2(c*u+l*a,o*r+s*i),V(s*r-o*i)]},e}function Ne(n,t){var e=Math.cos(n),r=Math.sin(n);return function(i,u,a,o){null!=i?(i=qe(e,i),u=qe(e,u),(a>0?u>i:i>u)&&(i+=2*a*Ka)):(i=n+2*a*Ka,u=n);for(var c,l=a*t,s=i;a>0?s>u:u>s;s-=l)o.point((c=Pt([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],c[1])}}function qe(n,t){var e=zt(t);e[0]-=n,Ft(e);var r=I(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Qa)%(2*Math.PI)}function Te(n,t,e){var r=ya.range(n,t-Qa,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function Ce(n,t,e){var r=ya.range(n,t-Qa,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function ze(n){return n.source}function De(n){return n.target}function je(n,t,e,r){var i=Math.cos(t),u=Math.sin(t),a=Math.cos(r),o=Math.sin(r),c=i*Math.cos(n),l=i*Math.sin(n),s=a*Math.cos(e),f=a*Math.sin(e),h=2*Math.asin(Math.sqrt(B(r-t)+i*a*B(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,i=e*l+t*f,a=e*u+t*o;return[Math.atan2(i,r)*eo,Math.atan2(a,Math.sqrt(r*r+i*i))*eo]}:function(){return[n*eo,t*eo]};return p.distance=h,p}function Le(){function n(n,i){var u=Math.sin(i*=to),a=Math.cos(i),o=Math.abs((n*=to)-t),c=Math.cos(o);rc+=Math.atan2(Math.sqrt((o=a*Math.sin(o))*o+(o=r*u-e*a*c)*o),e*u+r*a*c),t=n,e=u,r=a}var t,e,r;ic.point=function(i,u){t=i*to,e=Math.sin(u*=to),r=Math.cos(u),ic.point=n},ic.lineEnd=function(){ic.point=ic.lineEnd=s}}function He(n,t){function e(t,e){var r=Math.cos(t),i=Math.cos(e),u=n(r*i);return[u*i*Math.sin(t),u*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),i=t(r),u=Math.sin(i),a=Math.cos(i);return[Math.atan2(n*u,r*a),Math.asin(r&&e*u/r)]},e}function Fe(n,t){function e(n,t){var e=Math.abs(Math.abs(t)-Ka/2)1&&i.push("H",r[0]),i.join("")}function $e(n){for(var t=0,e=n.length,r=n[0],i=[r[0],",",r[1]];++t1){o=t[1],u=n[c],c++,r+="C"+(i[0]+a[0])+","+(i[1]+a[1])+","+(u[0]-o[0])+","+(u[1]-o[1])+","+u[0]+","+u[1];for(var l=2;l9&&(i=3*t/Math.sqrt(i),a[o]=i*e,a[o+1]=i*r));for(o=-1;++o<=c;)i=(n[Math.min(c,o+1)][0]-n[Math.max(0,o-1)][0])/(6*(1+a[o]*a[o])),u.push([i||0,a[o]*i||0]);return u}function sr(n){return n.length<3?Xe(n):n[0]+Qe(n,lr(n))}function fr(n,t,e,r){var i,u,a,o,c,l,s;return i=r[n],u=i[0],a=i[1],i=r[t],o=i[0],c=i[1],i=r[e],l=i[0],s=i[1],(s-a)*(o-u)-(c-a)*(l-u)>0}function hr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function gr(n,t,e,r){var i=n[0],u=e[0],a=t[0]-i,o=r[0]-u,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(o*(c-l)-f*(i-u))/(f*a-o*s);return[i+h*a,c+h*s]}function pr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function mr(n,t){var e={list:n.map(function(n,t){return{index:t,x:n[0],y:n[1]}}).sort(function(n,t){return n.yt.y?1:n.xt.x?1:0}),bottomSite:null},r={list:[],leftEnd:null,rightEnd:null,init:function(){r.leftEnd=r.createHalfEdge(null,"l"),r.rightEnd=r.createHalfEdge(null,"l"),r.leftEnd.r=r.rightEnd,r.rightEnd.l=r.leftEnd,r.list.unshift(r.leftEnd,r.rightEnd)},createHalfEdge:function(n,t){return{edge:n,side:t,vertex:null,l:null,r:null}},insert:function(n,t){t.l=n,t.r=n.r,n.r.l=t,n.r=t},leftBound:function(n){var t=r.leftEnd;do t=t.r;while(t!=r.rightEnd&&i.rightOf(t,n));return t=t.l},del:function(n){n.l.r=n.r,n.r.l=n.l,n.edge=null},right:function(n){return n.r},left:function(n){return n.l},leftRegion:function(n){return null==n.edge?e.bottomSite:n.edge.region[n.side]},rightRegion:function(n){return null==n.edge?e.bottomSite:n.edge.region[mc[n.side]]}},i={bisect:function(n,t){var e={region:{l:n,r:t},ep:{l:null,r:null}},r=t.x-n.x,i=t.y-n.y,u=r>0?r:-r,a=i>0?i:-i;return e.c=n.x*r+n.y*i+.5*(r*r+i*i),u>a?(e.a=1,e.b=i/r,e.c/=r):(e.b=1,e.a=r/i,e.c/=i),e},intersect:function(n,t){var e=n.edge,r=t.edge;if(!e||!r||e.region.r==r.region.r)return null;var i=e.a*r.b-e.b*r.a;if(Math.abs(i)<1e-10)return null;var u,a,o=(e.c*r.b-r.c*e.b)/i,c=(r.c*e.a-e.c*r.a)/i,l=e.region.r,s=r.region.r;l.y=a.region.r.x;return f&&"l"===u.side||!f&&"r"===u.side?null:{x:o,y:c}},rightOf:function(n,t){var e=n.edge,r=e.region.r,i=t.x>r.x;if(i&&"l"===n.side)return 1;if(!i&&"r"===n.side)return 0;if(1===e.a){var u=t.y-r.y,a=t.x-r.x,o=0,c=0;if(!i&&e.b<0||i&&e.b>=0?c=o=u>=e.b*a:(c=t.x+t.y*e.b>e.c,e.b<0&&(c=!c),c||(o=1)),!o){var l=r.x-e.region.l.x;c=e.b*(a*a-u*u)h*h+g*g}return"l"===n.side?c:!c},endPoint:function(n,e,r){n.ep[e]=r,n.ep[mc[e]]&&t(n)},distance:function(n,t){var e=n.x-t.x,r=n.y-t.y;return Math.sqrt(e*e+r*r)}},u={list:[],insert:function(n,t,e){n.vertex=t,n.ystar=t.y+e;for(var r=0,i=u.list,a=i.length;a>r;r++){var o=i[r];if(!(n.ystar>o.ystar||n.ystar==o.ystar&&t.x>o.vertex.x))break}i.splice(r,0,n)},del:function(n){for(var t=0,e=u.list,r=e.length;r>t&&e[t]!=n;++t);e.splice(t,1)},empty:function(){return 0===u.list.length},nextEvent:function(n){for(var t=0,e=u.list,r=e.length;r>t;++t)if(e[t]==n)return e[t+1];return null},min:function(){var n=u.list[0];return{x:n.vertex.x,y:n.ystar}},extractMin:function(){return u.list.shift()}};r.init(),e.bottomSite=e.list.shift();for(var a,o,c,l,s,f,h,g,p,m,d,v,y,M=e.list.shift();;)if(u.empty()||(a=u.min()),M&&(u.empty()||M.yg.y&&(p=h,h=g,g=p,y="r"),v=i.bisect(h,g),f=r.createHalfEdge(v,y),r.insert(l,f),i.endPoint(v,mc[y],d),m=i.intersect(l,f),m&&(u.del(l),u.insert(l,m,i.distance(m,h))),m=i.intersect(f,s),m&&u.insert(f,m,i.distance(m,h))}for(o=r.right(r.leftEnd);o!=r.rightEnd;o=r.right(o))t(o.edge)}function dr(n){return n.x}function vr(n){return n.y}function yr(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function Mr(n,t,e,r,i,u){if(!n(t,e,r,i,u)){var a=.5*(e+i),o=.5*(r+u),c=t.nodes;c[0]&&Mr(n,c[0],e,r,a,o),c[1]&&Mr(n,c[1],a,r,i,o),c[2]&&Mr(n,c[2],e,o,a,u),c[3]&&Mr(n,c[3],a,o,i,u)}}function xr(n,t){n=ya.rgb(n),t=ya.rgb(t);var e=n.r,r=n.g,i=n.b,u=t.r-e,a=t.g-r,o=t.b-i;return function(n){return"#"+ct(Math.round(e+u*n))+ct(Math.round(r+a*n))+ct(Math.round(i+o*n))}}function br(n,t){var e,r={},i={};for(e in n)e in t?r[e]=Sr(n[e],t[e]):i[e]=n[e];for(e in t)e in n||(i[e]=t[e]);return function(n){for(e in r)i[e]=r[e](n);return i}}function _r(n,t){return t-=n=+n,function(e){return n+t*e}}function wr(n,t){var e,r,i,u,a,o=0,c=0,l=[],s=[];for(n+="",t+="",dc.lastIndex=0,r=0;e=dc.exec(t);++r)e.index&&l.push(t.substring(o,c=e.index)),s.push({i:l.length,x:e[0]}),l.push(null),o=dc.lastIndex;for(or;++r)if(a=s[r],a.x==e[0]){if(a.i)if(null==l[a.i+1])for(l[a.i-1]+=a.x,l.splice(a.i,1),i=r+1;u>i;++i)s[i].i--;else for(l[a.i-1]+=a.x+l[a.i+1],l.splice(a.i,2),i=r+1;u>i;++i)s[i].i-=2;else if(null==l[a.i+1])l[a.i]=a.x;else for(l[a.i]=a.x+l[a.i+1],l.splice(a.i+1,1),i=r+1;u>i;++i)s[i].i--;s.splice(r,1),u--,r--}else a.x=_r(parseFloat(e[0]),parseFloat(a.x));for(;u>r;)a=s.pop(),null==l[a.i+1]?l[a.i]=a.x:(l[a.i]=a.x+l[a.i+1],l.splice(a.i+1,1)),u--;return 1===l.length?null==l[0]?(a=s[0].x,function(n){return a(n)+""}):function(){return t}:function(n){for(r=0;u>r;++r)l[(a=s[r]).i]=a.x(n);return l.join("")}}function Sr(n,t){for(var e,r=ya.interpolators.length;--r>=0&&!(e=ya.interpolators[r](n,t)););return e}function Er(n,t){var e,r=[],i=[],u=n.length,a=t.length,o=Math.min(n.length,t.length);for(e=0;o>e;++e)r.push(Sr(n[e],t[e]));for(;u>e;++e)i[e]=n[e];for(;a>e;++e)i[e]=t[e];return function(n){for(e=0;o>e;++e)i[e]=r[e](n);return i}}function kr(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function Ar(n){return function(t){return 1-n(1-t)}}function Nr(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function qr(n){return n*n}function Tr(n){return n*n*n}function Cr(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function zr(n){return function(t){return Math.pow(t,n)}}function Dr(n){return 1-Math.cos(n*Ka/2)}function jr(n){return Math.pow(2,10*(n-1))}function Lr(n){return 1-Math.sqrt(1-n*n)}function Hr(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/(2*Ka)*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,10*-r)*Math.sin(2*(r-e)*Ka/t)}}function Fr(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function Pr(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Or(n,t){n=ya.hcl(n),t=ya.hcl(t);var e=n.h,r=n.c,i=n.l,u=t.h-e,a=t.c-r,o=t.l-i;return isNaN(a)&&(a=0,r=isNaN(r)?t.c:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return J(e+u*n,r+a*n,i+o*n)+""}}function Yr(n,t){n=ya.hsl(n),t=ya.hsl(t);var e=n.h,r=n.s,i=n.l,u=t.h-e,a=t.s-r,o=t.l-i;return isNaN(a)&&(a=0,r=isNaN(r)?t.s:r),isNaN(u)?(u=0,e=isNaN(e)?t.h:e):u>180?u-=360:-180>u&&(u+=360),function(n){return R(e+u*n,r+a*n,i+o*n)+""}}function Rr(n,t){n=ya.lab(n),t=ya.lab(t);var e=n.l,r=n.a,i=n.b,u=t.l-e,a=t.a-r,o=t.b-i;return function(n){return Q(e+u*n,r+a*n,i+o*n)+""}}function Ur(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Ir(n){var t=[n.a,n.b],e=[n.c,n.d],r=Xr(t),i=Vr(t,e),u=Xr(Zr(e,t,-i))||0;t[0]*e[1]180?s+=360:s-l>180&&(l+=360),i.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:_r(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?i.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:_r(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),i.push({i:e-4,x:_r(g[0],p[0])},{i:e-2,x:_r(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=i.length,function(n){for(var t,u=-1;++ue;++e)(t=n[e][1])>i&&(r=e,i=t);return r}function mi(n){return n.reduce(di,0)}function di(n,t){return n+t[1]}function vi(n,t){return yi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function yi(n,t){for(var e=-1,r=+n[0],i=(n[1]-r)/t,u=[];++e<=t;)u[e]=i*e+r;return u}function Mi(n){return[ya.min(n),ya.max(n)]}function xi(n,t){return n.parent==t.parent?1:2}function bi(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}function _i(n){var t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree.thread}function wi(n,t){var e=n.children;if(e&&(i=e.length))for(var r,i,u=-1;++u0&&(n=r);return n}function Si(n,t){return n.x-t.x}function Ei(n,t){return t.x-n.x}function ki(n,t){return n.depth-t.depth}function Ai(n,t){function e(n,r){var i=n.children;if(i&&(a=i.length))for(var u,a,o=null,c=-1;++c=0;)t=i[u]._tree,t.prelim+=e,t.mod+=e,e+=t.shift+(r+=t.change)}function qi(n,t,e){n=n._tree,t=t._tree;var r=e/(t.number-n.number);n.change+=r,t.change-=r,t.shift+=e,t.prelim+=e,t.mod+=e}function Ti(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ancestor:e}function Ci(n,t){return n.value-t.value}function zi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Di(n,t){n._pack_next=t,t._pack_prev=n}function ji(n,t){var e=t.x-n.x,r=t.y-n.y,i=n.r+t.r;return.999*i*i>e*e+r*r}function Li(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,i,u,a,o,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(Hi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(i=e[1],i.x=i.r,i.y=0,t(i),l>2))for(u=e[2],Oi(r,i,u),t(u),zi(r,u),r._pack_prev=u,zi(u,i),i=r._pack_next,a=3;l>a;a++){Oi(r,i,u=e[a]);var p=0,m=1,d=1;for(o=i._pack_next;o!==i;o=o._pack_next,m++)if(ji(o,u)){p=1;break}if(1==p)for(c=r._pack_prev;c!==o._pack_prev&&!ji(c,u);c=c._pack_prev,d++);p?(d>m||m==d&&i.ra;a++)u=e[a],u.x-=v,u.y-=y,M=Math.max(M,u.r+Math.sqrt(u.x*u.x+u.y*u.y));n.r=M,e.forEach(Fi)}}function Hi(n){n._pack_next=n._pack_prev=n}function Fi(n){delete n._pack_next,delete n._pack_prev}function Pi(n,t,e,r){var i=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,i)for(var u=-1,a=i.length;++ui&&(e+=i/2,i=0),0>u&&(r+=u/2,u=0),{x:e,y:r,dx:i,dy:u}}function Zi(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Bi(n){return n.rangeExtent?n.rangeExtent():Zi(n.range())}function $i(n,t,e,r){var i=e(n[0],n[1]),u=r(t[0],t[1]);return function(n){return u(i(n))}}function Wi(n,t){var e,r=0,i=n.length-1,u=n[r],a=n[i];return u>a&&(e=r,r=i,i=e,e=u,u=a,a=e),n[r]=t.floor(u),n[i]=t.ceil(a),n}function Ji(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:kc}function Gi(n,t,e,r){var i=[],u=[],a=0,o=Math.min(n.length,t.length)-1;for(n[o]2?Gi:$i,c=r?Wr:$r;return a=i(n,t,c,e),o=i(t,n,c,Sr),u}function u(n){return a(n)}var a,o;return u.invert=function(n){return o(n)},u.domain=function(t){return arguments.length?(n=t.map(Number),i()):n},u.range=function(n){return arguments.length?(t=n,i()):t},u.rangeRound=function(n){return u.range(n).interpolate(Ur)},u.clamp=function(n){return arguments.length?(r=n,i()):r},u.interpolate=function(n){return arguments.length?(e=n,i()):e},u.ticks=function(t){return ru(n,t)},u.tickFormat=function(t,e){return iu(n,t,e)},u.nice=function(t){return nu(n,t),i()},u.copy=function(){return Ki(n,t,e,r)},i()}function Qi(n,t){return ya.rebind(n,t,"range","rangeRound","interpolate","clamp")}function nu(n,t){return Wi(n,Ji(t?eu(n,t)[2]:tu(n)))}function tu(n){var t=Zi(n),e=t[1]-t[0];return Math.pow(10,Math.round(Math.log(e)/Math.LN10)-1)}function eu(n,t){var e=Zi(n),r=e[1]-e[0],i=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),u=t/r*i;return.15>=u?i*=10:.35>=u?i*=5:.75>=u&&(i*=2),e[0]=Math.ceil(e[0]/i)*i,e[1]=Math.floor(e[1]/i)*i+.5*i,e[2]=i,e}function ru(n,t){return ya.range.apply(ya,eu(n,t))}function iu(n,t,e){var r=-Math.floor(Math.log(eu(n,t)[2])/Math.LN10+.01);return ya.format(e?e.replace(wo,function(n,t,e,i,u,a,o,c,l,s){return[t,e,i,u,a,o,c,l||"."+(r-2*("%"===s)),s].join("")}):",."+r+"f")}function uu(n,t,e,r){function i(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function u(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function a(t){return n(i(t))}return a.invert=function(t){return u(n.invert(t))},a.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(i)),a):r},a.base=function(e){return arguments.length?(t=+e,n.domain(r.map(i)),a):t},a.nice=function(){var t=Wi(r.map(i),e?Math:Nc);return n.domain(t),r=t.map(u),a},a.ticks=function(){var n=Zi(r),a=[],o=n[0],c=n[1],l=Math.floor(i(o)),s=Math.ceil(i(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)a.push(u(l)*h);a.push(u(l))}else for(a.push(u(l));l++0;h--)a.push(u(l)*h);for(l=0;a[l]c;s--);a=a.slice(l,s)}return a},a.tickFormat=function(n,t){if(!arguments.length)return Ac;arguments.length<2?t=Ac:"function"!=typeof t&&(t=ya.format(t));var r,o=Math.max(.1,n/a.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/u(c(i(n)+r))<=o?t(n):""}},a.copy=function(){return uu(n.copy(),t,e,r)},Qi(a,n)}function au(n,t,e){function r(t){return n(i(t))}var i=ou(t),u=ou(1/t);return r.invert=function(t){return u(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(i)),r):e},r.ticks=function(n){return ru(e,n)},r.tickFormat=function(n,t){return iu(e,n,t)},r.nice=function(n){return r.domain(nu(e,n))},r.exponent=function(a){return arguments.length?(i=ou(t=a),u=ou(1/t),n.domain(e.map(i)),r):t},r.copy=function(){return au(n.copy(),t,e)},Qi(r,n)}function ou(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function cu(n,t){function e(t){return a[((u.get(t)||u.set(t,n.push(t)))-1)%a.length]}function r(t,e){return ya.range(n.length).map(function(n){return t+e*n})}var u,a,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new i;for(var a,o=-1,c=r.length;++oe?[0/0,0/0]:[e>0?i[e-1]:n[0],et?0/0:t/u+n,[t,t+1/u]},r.copy=function(){return su(n,t,e)},i()}function fu(n,t){function e(e){return e>=e?t[ya.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return fu(n,t)},e}function hu(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return ru(n,t)},t.tickFormat=function(t,e){return iu(n,t,e)},t.copy=function(){return hu(n)},t}function gu(n){return n.innerRadius}function pu(n){return n.outerRadius}function mu(n){return n.startAngle}function du(n){return n.endAngle}function vu(n){for(var t,e,r,i=-1,u=n.length;++ie?l():(u.active=e,a.event&&a.event.start.call(n,s,t),a.tween.forEach(function(e,r){(r=r.call(n,s,t))&&p.push(r)}),c(r)?1:(xt(c,0,o),void 0))}function c(r){if(u.active!==e)return l();for(var i=(r-h)/g,o=f(i),c=p.length;c>0;)p[--c].call(n,o);return i>=1?(l(),a.event&&a.event.end.call(n,s,t),1):void 0}function l(){return--u.count?delete u[e]:delete n.__transition__,1}var s=n.__data__,f=a.ease,h=a.delay,g=a.duration,p=[];return r>=h?i(r):(xt(i,h,o),void 0)},0,o)}}function qu(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function Tu(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function Cu(n,t,e){if(r=[],e&&t.length>1){for(var r,i,u,a=Zi(n.domain()),o=-1,c=t.length,l=(t[1]-t[0])/++e;++o0;)(u=+t[o]-i*l)>=a[0]&&r.push(u);for(--o,i=0;++i1?Date.UTC.apply(this,arguments):arguments[0])}function Du(n,t,e){function r(t){var e=n(t),r=u(e,1);return r-t>t-e?e:r}function i(e){return t(e=n(new Zc(e-1)),1),e}function u(n,e){return t(n=new Zc(+n),e),n}function a(n,r,u){var a=i(n),o=[];if(u>1)for(;r>a;)e(a)%u||o.push(new Date(+a)),t(a,1);else for(;r>a;)o.push(new Date(+a)),t(a,1);return o}function o(n,t,e){try{Zc=zu;var r=new zu;return r._=n,a(r,t,e)}finally{Zc=Date}}n.floor=n,n.round=r,n.ceil=i,n.offset=u,n.range=a;var c=n.utc=ju(n);return c.floor=c,c.round=ju(r),c.ceil=ju(i),c.offset=ju(u),c.range=o,n}function ju(n){return function(t,e){try{Zc=zu;var r=new zu;return r._=t,n(r,e)._}finally{Zc=Date}}}function Lu(n,t,e,r){for(var i,u,a=0,o=t.length,c=e.length;o>a;){if(r>=c)return-1;if(i=t.charCodeAt(a++),37===i){if(u=gl[t.charAt(a++)],!u||(r=u(n,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}function Hu(n){return new RegExp("^(?:"+n.map(ya.requote).join("|")+")","i")}function Fu(n){for(var t=new i,e=-1,r=n.length;++en?"-":"",i=(r?-n:n)+"",u=i.length;return r+(e>u?new Array(e-u+1).join(t)+i:i)}function Ou(n,t,e){il.lastIndex=0;var r=il.exec(t.substring(e));return r?(n.w=ul.get(r[0].toLowerCase()),e+r[0].length):-1}function Yu(n,t,e){el.lastIndex=0;var r=el.exec(t.substring(e));return r?(n.w=rl.get(r[0].toLowerCase()),e+r[0].length):-1}function Ru(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Uu(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e));return r?(n.U=+r[0],e+r[0].length):-1}function Iu(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e));return r?(n.W=+r[0],e+r[0].length):-1}function Vu(n,t,e){cl.lastIndex=0;var r=cl.exec(t.substring(e));return r?(n.m=ll.get(r[0].toLowerCase()),e+r[0].length):-1}function Xu(n,t,e){al.lastIndex=0;var r=al.exec(t.substring(e));return r?(n.m=ol.get(r[0].toLowerCase()),e+r[0].length):-1}function Zu(n,t,e){return Lu(n,hl.c.toString(),t,e)}function Bu(n,t,e){return Lu(n,hl.x.toString(),t,e)}function $u(n,t,e){return Lu(n,hl.X.toString(),t,e)}function Wu(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Ju(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+2));return r?(n.y=Gu(+r[0]),e+r[0].length):-1}function Gu(n){return n+(n>68?1900:2e3)}function Ku(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qu(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function na(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function ta(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ea(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function ra(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ia(n,t,e){pl.lastIndex=0;var r=pl.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ua(n,t,e){var r=ml.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}function aa(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(Math.abs(t)/60),i=Math.abs(t)%60;return e+Pu(r,"0",2)+Pu(i,"0",2)}function oa(n,t,e){sl.lastIndex=0;var r=sl.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function ca(n){return n.toISOString()}function la(n,t,e){function r(t){return n(t)}return r.invert=function(t){return sa(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(sa)},r.nice=function(n){return r.domain(Wi(r.domain(),n))},r.ticks=function(e,i){var u=Zi(r.domain());if("function"!=typeof e){var a=u[1]-u[0],o=a/e,c=ya.bisect(vl,o);if(c==vl.length)return t.year(u,e);if(!c)return n.ticks(e).map(sa);o/vl[c-1]n?-1:n>t?1:n>=t?0:0/0},ya.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},ya.min=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i=e);)e=void 0;for(;++ir&&(e=r)}else{for(;++i=e);)e=void 0;for(;++ir&&(e=r)}return e},ya.max=function(n,t){var e,r,i=-1,u=n.length;if(1===arguments.length){for(;++i=e);)e=void 0;for(;++ie&&(e=r)}else{for(;++i=e);)e=void 0;for(;++ie&&(e=r)}return e},ya.extent=function(n,t){var e,r,i,u=-1,a=n.length;if(1===arguments.length){for(;++u=e);)e=i=void 0;for(;++ur&&(e=r),r>i&&(i=r))}else{for(;++u=e);)e=void 0;for(;++ur&&(e=r),r>i&&(i=r))}return[e,i]},ya.sum=function(n,t){var e,r=0,i=n.length,u=-1;if(1===arguments.length)for(;++u1&&(t=t.map(e)),t=t.filter(n),t.length?ya.quantile(t.sort(ya.ascending),.5):void 0},ya.bisector=function(n){return{left:function(t,e,r,i){for(arguments.length<3&&(r=0),arguments.length<4&&(i=t.length);i>r;){var u=r+i>>>1;n.call(t,t[u],u)r;){var u=r+i>>>1;er)for(;(i=n+r*++o)>t;)u.push(i/a);else for(;(i=n+r*++o)=a.length)return r?r.call(u,o):e?o.sort(e):o;for(var l,s,f,h,g=-1,p=o.length,m=a[c++],d=new i;++g=a.length)return n;var r=[],i=o[e++];return n.forEach(function(n,i){r.push({key:n,values:t(i,e)})}),i?r.sort(function(n,t){return i(n.key,t.key)}):r}var e,r,u={},a=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(ya.map,e,0),0)},u.key=function(n){return a.push(n),u},u.sortKeys=function(n){return o[a.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},ya.set=function(n){var t=new u;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},r(u,{has:function(n){return qa+n in this},add:function(n){return this[qa+n]=!0,n},remove:function(n){return n=qa+n,n in this&&delete this[n]},values:function(){var n=[];return this.forEach(function(t){n.push(t)}),n},forEach:function(n){for(var t in this)t.charCodeAt(0)===Ta&&n.call(this,t.substring(1))}}),ya.behavior={},ya.rebind=function(n,t){for(var e,r=1,i=arguments.length;++r=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},ya.event=null,ya.requote=function(n){return n.replace(ja,"\\$&")};var ja=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,La={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},Ha=function(n,t){return t.querySelector(n)},Fa=function(n,t){return t.querySelectorAll(n)},Pa=xa[o(xa,"matchesSelector")],Oa=function(n,t){return Pa.call(n,t)};"function"==typeof Sizzle&&(Ha=function(n,t){return Sizzle(n,t)[0]||null},Fa=function(n,t){return Sizzle.uniqueSort(Sizzle(n,t))},Oa=Sizzle.matchesSelector),ya.selection=function(){return Ia};var Ya=ya.selection.prototype=[];Ya.select=function(n){var t,e,r,i,u=[];n=v(n);for(var a=-1,o=this.length;++a=0&&(e=n.substring(0,t),n=n.substring(t+1)),Ra.hasOwnProperty(e)?{space:Ra[e],local:n}:n}},Ya.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=ya.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(M(t,n[t]));return this}return this.each(M(n,t))},Ya.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=n.trim().split(/^|\s+/g)).length,i=-1;if(t=e.classList){for(;++ir){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(S(e,n[e],t));return this}if(2>r)return ba.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(S(n,t,e))},Ya.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(E(t,n[t]));return this}return this.each(E(n,t))},Ya.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},Ya.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},Ya.append=function(n){return n=k(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},Ya.insert=function(n,t){return n=k(n),t=v(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments))})},Ya.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},Ya.data=function(n,t){function e(n,e){var r,u,a,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),m=new Array(o);if(t){var d,v=new i,y=new i,M=[];for(r=-1;++rr;++r)p[r]=A(e[r]);for(;o>r;++r)m[r]=n[r]}p.update=g,p.parentNode=g.parentNode=m.parentNode=n.parentNode,c.push(p),l.push(g),s.push(m)}var r,u,a=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++au;u++){i.push(t=[]),t.parentNode=(e=this[u]).parentNode;for(var o=0,c=e.length;c>o;o++)(r=e[o])&&n.call(r,r.__data__,o)&&t.push(r)}return d(i)},Ya.order=function(){for(var n=-1,t=this.length;++n=0;)(e=r[i])&&(u&&u!==e.nextSibling&&u.parentNode.insertBefore(e,u),u=e);return this},Ya.sort=function(n){n=q.apply(this,arguments);for(var t=-1,e=this.length;++tn;n++)for(var e=this[n],r=0,i=e.length;i>r;r++){var u=e[r];if(u)return u}return null},Ya.size=function(){var n=0;return this.each(function(){++n}),n};var Ua=[];ya.selection.enter=C,ya.selection.enter.prototype=Ua,Ua.append=Ya.append,Ua.empty=Ya.empty,Ua.node=Ya.node,Ua.call=Ya.call,Ua.size=Ya.size,Ua.select=function(n){for(var t,e,r,i,u,a=[],o=-1,c=this.length;++or){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(D(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(D(n,t,e))};var Va=ya.map({mouseenter:"mouseover",mouseleave:"mouseout"});Va.forEach(function(n){"on"+n in Ma&&Va.remove(n)});var Xa=o(xa.style,"userSelect"),Za=0;ya.mouse=function(n){return F(n,p())};var Ba=/WebKit/.test(ba.navigator.userAgent)?-1:0;ya.touches=function(n,t){return arguments.length<2&&(t=p().touches),t?za(t).map(function(t){var e=F(n,t);return e.identifier=t.identifier,e}):[]},ya.behavior.drag=function(){function n(){this.on("mousedown.drag",a).on("touchstart.drag",o)}function t(){return ya.event.changedTouches[0].identifier}function e(n,t){return ya.touches(n).filter(function(n){return n.identifier===t})[0]}function r(n,t,e,r){return function(){function a(){if(!s)return o();var n=t(s,g),e=n[0]-m[0],r=n[1]-m[1];d|=e|r,m=n,f({type:"drag",x:n[0]+c[0],y:n[1]+c[1],dx:e,dy:r})}function o(){v.on(e+"."+p,null).on(r+"."+p,null),y(d&&ya.event.target===h),f({type:"dragend"})}var c,l=this,s=l.parentNode,f=i.of(l,arguments),h=ya.event.target,g=n(),p=null==g?"drag":"drag-"+g,m=t(s,g),d=0,v=ya.select(ba).on(e+"."+p,a).on(r+"."+p,o),y=H();u?(c=u.apply(l,arguments),c=[c.x-m[0],c.y-m[1]]):c=[0,0],f({type:"dragstart"})}}var i=m(n,"drag","dragstart","dragend"),u=null,a=r(s,ya.mouse,"mousemove","mouseup"),o=r(t,e,"touchmove","touchend");return n.origin=function(t){return arguments.length?(u=t,n):u},ya.rebind(n,i,"on")},ya.behavior.zoom=function(){function n(){this.on(w,o).on(Ja+".zoom",l).on(S,s).on("dblclick.zoom",f).on(k,c)}function t(n){return[(n[0]-x[0])/b,(n[1]-x[1])/b]}function e(n){return[n[0]*b+x[0],n[1]*b+x[1]]}function r(n){b=Math.max(_[0],Math.min(_[1],n))}function i(n,t){t=e(t),x[0]+=n[0]-t[0],x[1]+=n[1]-t[1]}function u(){v&&v.domain(d.range().map(function(n){return(n-x[0])/b}).map(d.invert)),M&&M.domain(y.range().map(function(n){return(n-x[1])/b}).map(y.invert))}function a(n){u(),n({type:"zoom",scale:b,translate:x})}function o(){function n(){c=1,i(ya.mouse(r),f),a(u)}function e(){l.on(S,ba===r?s:null).on(E,null),h(c&&ya.event.target===o)}var r=this,u=q.of(r,arguments),o=ya.event.target,c=0,l=ya.select(ba).on(S,n).on(E,e),f=t(ya.mouse(r)),h=H()}function c(){function n(){var n=ya.touches(h);return f=b,s={},n.forEach(function(n){s[n.identifier]=t(n)}),n}function e(){var t=Date.now(),e=n();if(1===e.length){if(500>t-p){var u=e[0],o=s[u.identifier];r(2*b),i(u,o),g(),a(m)}p=t}else if(e.length>1){var u=e[0],c=e[1],l=u[0]-c[0],f=u[1]-c[1];d=l*l+f*f}}function u(){var n=ya.touches(h),t=n[0],e=s[t.identifier];if(u=n[1]){var u,o=s[u.identifier],c=ya.event.scale;if(null==c){var l=(l=u[0]-t[0])*l+(l=u[1]-t[1])*l;c=d&&Math.sqrt(l/d)}t=[(t[0]+u[0])/2,(t[1]+u[1])/2],e=[(e[0]+o[0])/2,(e[1]+o[1])/2],r(c*f)}p=null,i(t,e),a(m)}function l(){ya.event.touches.length?n():(v.on(A,null).on(N,null),y.on(w,o).on(k,c),M())}var s,f,h=this,m=q.of(h,arguments),d=0,v=ya.select(ba).on(A,u).on(N,l),y=ya.select(h).on(w,null).on(k,e),M=H();e()}function l(){g(),h||(h=t(ya.mouse(this))),r(Math.pow(2,.002*$a())*b),i(ya.mouse(this),h),a(q.of(this,arguments))}function s(){h=null}function f(){var n=ya.mouse(this),e=t(n),u=Math.log(b)/Math.LN2;r(Math.pow(2,ya.event.shiftKey?Math.ceil(u)-1:Math.floor(u)+1)),i(n,e),a(q.of(this,arguments))}var h,p,d,v,y,M,x=[0,0],b=1,_=Wa,w="mousedown.zoom",S="mousemove.zoom",E="mouseup.zoom",k="touchstart.zoom",A="touchmove.zoom",N="touchend.zoom",q=m(n,"zoom");return n.translate=function(t){return arguments.length?(x=t.map(Number),u(),n):x},n.scale=function(t){return arguments.length?(b=+t,u(),n):b},n.scaleExtent=function(t){return arguments.length?(_=null==t?Wa:t.map(Number),n):_},n.x=function(t){return arguments.length?(v=t,d=t.copy(),x=[0,0],b=1,n):v},n.y=function(t){return arguments.length?(M=t,y=t.copy(),x=[0,0],b=1,n):M},ya.rebind(n,q,"on")};var $a,Wa=[0,1/0],Ja="onwheel"in Ma?($a=function(){return-ya.event.deltaY*(ya.event.deltaMode?120:1)},"wheel"):"onmousewheel"in Ma?($a=function(){return ya.event.wheelDelta},"mousewheel"):($a=function(){return-ya.event.detail},"MozMousePixelScroll");P.prototype.toString=function(){return this.rgb()+""},ya.hsl=function(n,t,e){return 1===arguments.length?n instanceof Y?O(n.h,n.s,n.l):lt(""+n,st,O):O(+n,+t,+e)};var Ga=Y.prototype=new P;Ga.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),O(this.h,this.s,this.l/n)},Ga.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),O(this.h,this.s,n*this.l)},Ga.rgb=function(){return R(this.h,this.s,this.l)};var Ka=Math.PI,Qa=1e-6,no=Qa*Qa,to=Ka/180,eo=180/Ka;ya.hcl=function(n,t,e){return 1===arguments.length?n instanceof W?$(n.h,n.c,n.l):n instanceof K?nt(n.l,n.a,n.b):nt((n=ft((n=ya.rgb(n)).r,n.g,n.b)).l,n.a,n.b):$(+n,+t,+e)};var ro=W.prototype=new P;ro.brighter=function(n){return $(this.h,this.c,Math.min(100,this.l+io*(arguments.length?n:1)))},ro.darker=function(n){return $(this.h,this.c,Math.max(0,this.l-io*(arguments.length?n:1)))},ro.rgb=function(){return J(this.h,this.c,this.l).rgb()},ya.lab=function(n,t,e){return 1===arguments.length?n instanceof K?G(n.l,n.a,n.b):n instanceof W?J(n.l,n.c,n.h):ft((n=ya.rgb(n)).r,n.g,n.b):G(+n,+t,+e)};var io=18,uo=.95047,ao=1,oo=1.08883,co=K.prototype=new P;co.brighter=function(n){return G(Math.min(100,this.l+io*(arguments.length?n:1)),this.a,this.b)},co.darker=function(n){return G(Math.max(0,this.l-io*(arguments.length?n:1)),this.a,this.b)},co.rgb=function(){return Q(this.l,this.a,this.b)},ya.rgb=function(n,t,e){return 1===arguments.length?n instanceof ot?at(n.r,n.g,n.b):lt(""+n,at,R):at(~~n,~~t,~~e)};var lo=ot.prototype=new P;lo.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,i=30;return t||e||r?(t&&i>t&&(t=i),e&&i>e&&(e=i),r&&i>r&&(r=i),at(Math.min(255,~~(t/n)),Math.min(255,~~(e/n)),Math.min(255,~~(r/n)))):at(i,i,i)},lo.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),at(~~(n*this.r),~~(n*this.g),~~(n*this.b))},lo.hsl=function(){return st(this.r,this.g,this.b)},lo.toString=function(){return"#"+ct(this.r)+ct(this.g)+ct(this.b)};var so=ya.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});so.forEach(function(n,t){so.set(n,it(t))}),ya.functor=pt,ya.xhr=dt(mt),ya.dsv=function(n,t){function e(n,e,u){arguments.length<3&&(u=e,e=null);var a=ya.xhr(n,t,u);return a.row=function(n){return arguments.length?a.response(null==(e=n)?r:i(n)):e},a.row(e)}function r(n){return e.parse(n.responseText)}function i(n){return function(t){return e.parse(t.responseText,n)}}function a(t){return t.map(o).join(n)}function o(n){return c.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var c=new RegExp('["'+n+"\n]"),l=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var i=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(i(n),e)}:i})},e.parseRows=function(n,t){function e(){if(s>=c)return a;if(i)return i=!1,u;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++s;){var r=n.charCodeAt(s++),o=1;if(10===r)i=!0;else if(13===r)i=!0,10===n.charCodeAt(s)&&(++s,++o);else if(r!==l)continue;return n.substring(t,s-o)}return n.substring(t)}for(var r,i,u={},a={},o=[],c=n.length,s=0,f=0;(r=e())!==a;){for(var h=[];r!==u&&r!==a;)h.push(r),r=e();(!t||(h=t(h,f++)))&&o.push(h)}return o},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new u,i=[];return t.forEach(function(n){for(var t in n)r.has(t)||i.push(r.add(t))}),[i.map(o).join(n)].concat(t.map(function(t){return i.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(a).join("\n")},e},ya.csv=ya.dsv(",","text/csv"),ya.tsv=ya.dsv(" ","text/tab-separated-values");var fo,ho,go,po,mo,vo=ba[o(ba,"requestAnimationFrame")]||function(n){setTimeout(n,17)};ya.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var i=e+t,u={callback:n,time:i,next:null};ho?ho.next=u:fo=u,ho=u,go||(po=clearTimeout(po),go=1,vo(Mt))},ya.timer.flush=function(){bt(),_t()};var yo=".",Mo=",",xo=[3,3],bo="$",_o=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"].map(wt);ya.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=ya.round(n,St(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),_o[8+e/3]},ya.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)},ya.format=function(n){var t=wo.exec(n),e=t[1]||" ",r=t[2]||">",i=t[3]||"",u=t[4]||"",a=t[5],o=+t[6],c=t[7],l=t[8],s=t[9],f=1,h="",g=!1;switch(l&&(l=+l.substring(1)),(a||"0"===e&&"="===r)&&(a=e="0",r="=",c&&(o-=Math.floor((o-1)/4))),s){case"n":c=!0,s="g";break;case"%":f=100,h="%",s="f";break;case"p":f=100,h="%",s="r";break;case"b":case"o":case"x":case"X":"#"===u&&(u="0"+s.toLowerCase());case"c":case"d":g=!0,l=0;break;case"s":f=-1,s="r"}"#"===u?u="":"$"===u&&(u=bo),"r"!=s||l||(s="g"),null!=l&&("g"==s?l=Math.max(1,Math.min(21,l)):("e"==s||"f"==s)&&(l=Math.max(0,Math.min(20,l)))),s=So.get(s)||Et;var p=a&&c;return function(n){if(g&&n%1)return"";var t=0>n||0===n&&0>1/n?(n=-n,"-"):i;if(0>f){var m=ya.formatPrefix(n,l);n=m.scale(n),h=m.symbol}else n*=f;n=s(n,l);var d=n.lastIndexOf("."),v=0>d?n:n.substring(0,d),y=0>d?"":yo+n.substring(d+1);!a&&c&&(v=Eo(v));var M=u.length+v.length+y.length+(p?0:t.length),x=o>M?new Array(M=o-M+1).join(e):"";return p&&(v=Eo(x+v)),t+=u,n=v+y,("<"===r?t+n+x:">"===r?x+t+n:"^"===r?x.substring(0,M>>=1)+t+n+x.substring(M):t+(p?n:x+n))+h}};var wo=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,So=ya.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=ya.round(n,St(n,t))).toFixed(Math.max(0,Math.min(20,St(n*(1+1e-15),t))))}}),Eo=mt;if(xo){var ko=xo.length;Eo=function(n){for(var t=n.length,e=[],r=0,i=xo[0];t>0&&i>0;)e.push(n.substring(t-=i,t+i)),i=xo[r=(r+1)%ko];return e.reverse().join(Mo)}}ya.geo={},kt.prototype={s:0,t:0,add:function(n){At(n,this.t,Ao),At(Ao.s,this.s,this),this.s?this.t+=Ao.t:this.s=Ao.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var Ao=new kt;ya.geo.stream=function(n,t){n&&No.hasOwnProperty(n.type)?No[n.type](n,t):Nt(n,t)};var No={Feature:function(n,t){Nt(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,i=e.length;++rn?4*Ka+n:n,zo.lineStart=zo.lineEnd=zo.point=s}};ya.geo.bounds=function(){function n(n,t){M.push(x=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=zt([t*to,e*to]);if(v){var i=jt(v,r),u=[i[1],-i[0],0],a=jt(u,i);Ft(a),a=Pt(a);var c=t-p,l=c>0?1:-1,m=a[0]*eo*l,d=Math.abs(c)>180;if(d^(m>l*p&&l*t>m)){var y=a[1]*eo;y>g&&(g=y)}else if(m=(m+360)%360-180,d^(m>l*p&&l*t>m)){var y=-a[1]*eo;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?o(s,t)>o(s,h)&&(h=t):o(t,h)>o(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?o(s,t)>o(s,h)&&(h=t):o(t,h)>o(s,h)&&(s=t)}else n(t,e);v=r,p=t}function e(){b.point=t}function r(){x[0]=s,x[1]=h,b.point=n,v=null}function i(n,e){if(v){var r=n-p;y+=Math.abs(r)>180?r+(r>0?360:-360):r}else m=n,d=e;zo.point(n,e),t(n,e)}function u(){zo.lineStart()}function a(){i(m,d),zo.lineEnd(),Math.abs(y)>Qa&&(s=-(h=180)),x[0]=s,x[1]=h,v=null}function o(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nCo?(s=-(h=180),f=-(g=90)):y>Qa?g=90:-Qa>y&&(f=-90),x[0]=s,x[1]=h}};return function(n){g=h=-(s=f=1/0),M=[],ya.geo.stream(n,b);var t=M.length;if(t){M.sort(c);for(var e,r=1,i=M[0],u=[i];t>r;++r)e=M[r],l(e[0],i)||l(e[1],i)?(o(i[0],e[1])>o(i[0],i[1])&&(i[1]=e[1]),o(e[0],i[1])>o(i[0],i[1])&&(i[0]=e[0])):u.push(i=e);for(var a,e,p=-1/0,t=u.length-1,r=0,i=u[t];t>=r;i=e,++r)e=u[r],(a=o(i[1],e[0]))>p&&(p=a,s=e[0],h=i[1])}return M=x=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),ya.geo.centroid=function(n){Do=jo=Lo=Ho=Fo=Po=Oo=Yo=Ro=Uo=Io=0,ya.geo.stream(n,Vo);var t=Ro,e=Uo,r=Io,i=t*t+e*e+r*r;return no>i&&(t=Po,e=Oo,r=Yo,Qa>jo&&(t=Lo,e=Ho,r=Fo),i=t*t+e*e+r*r,no>i)?[0/0,0/0]:[Math.atan2(e,t)*eo,V(r/Math.sqrt(i))*eo]};var Do,jo,Lo,Ho,Fo,Po,Oo,Yo,Ro,Uo,Io,Vo={sphere:s,point:Yt,lineStart:Ut,lineEnd:It,polygonStart:function(){Vo.lineStart=Vt},polygonEnd:function(){Vo.lineStart=Ut}},Xo=$t(Xt,Qt,te,ee),Zo=[-Ka,0],Bo=1e9;(ya.geo.conicEqualArea=function(){return oe(ce)}).raw=ce,ya.geo.albers=function(){return ya.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},ya.geo.albersUsa=function(){function n(n){var u=n[0],a=n[1];return t=null,e(u,a),t||(r(u,a),t)||i(u,a),t}var t,e,r,i,u=ya.geo.albers(),a=ya.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),o=ya.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=u.scale(),e=u.translate(),r=(n[0]-e[0])/t,i=(n[1]-e[1])/t;return(i>=.12&&.234>i&&r>=-.425&&-.214>r?a:i>=.166&&.234>i&&r>=-.214&&-.115>r?o:u).invert(n)},n.stream=function(n){var t=u.stream(n),e=a.stream(n),r=o.stream(n);return{point:function(n,i){t.point(n,i),e.point(n,i),r.point(n,i)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(u.precision(t),a.precision(t),o.precision(t),n):u.precision()},n.scale=function(t){return arguments.length?(u.scale(t),a.scale(.35*t),o.scale(t),n.translate(u.translate())):u.scale()},n.translate=function(t){if(!arguments.length)return u.translate();var l=u.scale(),s=+t[0],f=+t[1];return e=u.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=a.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Qa,f+.12*l+Qa],[s-.214*l-Qa,f+.234*l-Qa]]).stream(c).point,i=o.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Qa,f+.166*l+Qa],[s-.115*l-Qa,f+.234*l-Qa]]).stream(c).point,n},n.scale(1070)};var $o,Wo,Jo,Go,Ko,Qo,nc={point:s,lineStart:s,lineEnd:s,polygonStart:function(){Wo=0,nc.lineStart=le},polygonEnd:function(){nc.lineStart=nc.lineEnd=nc.point=s,$o+=Math.abs(Wo/2)}},tc={point:se,lineStart:s,lineEnd:s,polygonStart:s,polygonEnd:s},ec={point:ge,lineStart:pe,lineEnd:me,polygonStart:function(){ec.lineStart=de},polygonEnd:function(){ec.point=ge,ec.lineStart=pe,ec.lineEnd=me}};ya.geo.path=function(){function n(n){return n&&("function"==typeof o&&u.pointRadius(+o.apply(this,arguments)),a&&a.valid||(a=i(u)),ya.geo.stream(n,a)),u.result()}function t(){return a=null,n}var e,r,i,u,a,o=4.5;return n.area=function(n){return $o=0,ya.geo.stream(n,i(nc)),$o},n.centroid=function(n){return Lo=Ho=Fo=Po=Oo=Yo=Ro=Uo=Io=0,ya.geo.stream(n,i(ec)),Io?[Ro/Io,Uo/Io]:Yo?[Po/Yo,Oo/Yo]:Fo?[Lo/Fo,Ho/Fo]:[0/0,0/0]},n.bounds=function(n){return Ko=Qo=-(Jo=Go=1/0),ya.geo.stream(n,i(tc)),[[Jo,Go],[Ko,Qo]]},n.projection=function(n){return arguments.length?(i=(e=n)?n.stream||Me(n):mt,t()):e},n.context=function(n){return arguments.length?(u=null==(r=n)?new fe:new ve(n),"function"!=typeof o&&u.pointRadius(o),t()):r},n.pointRadius=function(t){return arguments.length?(o="function"==typeof t?t:(u.pointRadius(+t),+t),n):o},n.projection(ya.geo.albersUsa()).context(null)},ya.geo.projection=xe,ya.geo.projectionMutator=be,(ya.geo.equirectangular=function(){return xe(we)}).raw=we.invert=we,ya.geo.rotation=function(n){function t(t){return t=n(t[0]*to,t[1]*to),t[0]*=eo,t[1]*=eo,t}return n=Se(n[0]%360*to,n[1]*to,n.length>2?n[2]*to:0),t.invert=function(t){return t=n.invert(t[0]*to,t[1]*to),t[0]*=eo,t[1]*=eo,t},t},ya.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=Se(-n[0]*to,-n[1]*to,0).invert,i=[];return e(null,null,1,{point:function(n,e){i.push(n=t(n,e)),n[0]*=eo,n[1]*=eo}}),{type:"Polygon",coordinates:[i]}}var t,e,r=[0,0],i=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=Ne((t=+r)*to,i*to),n):t},n.precision=function(r){return arguments.length?(e=Ne(t*to,(i=+r)*to),n):i},n.angle(90)},ya.geo.distance=function(n,t){var e,r=(t[0]-n[0])*to,i=n[1]*to,u=t[1]*to,a=Math.sin(r),o=Math.cos(r),c=Math.sin(i),l=Math.cos(i),s=Math.sin(u),f=Math.cos(u);return Math.atan2(Math.sqrt((e=f*a)*e+(e=l*s-c*f*o)*e),c*s+l*f*o)},ya.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return ya.range(Math.ceil(u/d)*d,i,d).map(h).concat(ya.range(Math.ceil(l/v)*v,c,v).map(g)).concat(ya.range(Math.ceil(r/p)*p,e,p).filter(function(n){return Math.abs(n%d)>Qa}).map(s)).concat(ya.range(Math.ceil(o/m)*m,a,m).filter(function(n){return Math.abs(n%v)>Qa}).map(f))}var e,r,i,u,a,o,c,l,s,f,h,g,p=10,m=p,d=90,v=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(u).concat(g(c).slice(1),h(i).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(u=+t[0][0],i=+t[1][0],l=+t[0][1],c=+t[1][1],u>i&&(t=u,u=i,i=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[u,l],[i,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],o=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),o>a&&(t=o,o=a,a=t),n.precision(y)):[[r,o],[e,a]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],v=+t[1],n):[d,v]},n.minorStep=function(t){return arguments.length?(p=+t[0],m=+t[1],n):[p,m]},n.precision=function(t){return arguments.length?(y=+t,s=Te(o,a,90),f=Ce(r,e,y),h=Te(l,c,90),g=Ce(u,i,y),n):y},n.majorExtent([[-180,-90+Qa],[180,90-Qa]]).minorExtent([[-180,-80-Qa],[180,80+Qa]])},ya.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||i.apply(this,arguments)]}}var t,e,r=ze,i=De;return n.distance=function(){return ya.geo.distance(t||r.apply(this,arguments),e||i.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(i=t,e="function"==typeof t?null:t,n):i},n.precision=function(){return arguments.length?n:0},n},ya.geo.interpolate=function(n,t){return je(n[0]*to,n[1]*to,t[0]*to,t[1]*to)},ya.geo.length=function(n){return rc=0,ya.geo.stream(n,ic),rc};var rc,ic={sphere:s,point:s,lineStart:Le,lineEnd:s,polygonStart:s,polygonEnd:s},uc=He(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(ya.geo.azimuthalEqualArea=function(){return xe(uc)}).raw=uc;var ac=He(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},mt);(ya.geo.azimuthalEquidistant=function(){return xe(ac)}).raw=ac,(ya.geo.conicConformal=function(){return oe(Fe)}).raw=Fe,(ya.geo.conicEquidistant=function(){return oe(Pe)}).raw=Pe;var oc=He(function(n){return 1/n},Math.atan);(ya.geo.gnomonic=function(){return xe(oc)}).raw=oc,Oe.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ka/2]},(ya.geo.mercator=function(){return Ye(Oe)}).raw=Oe;var cc=He(function(){return 1},Math.asin);(ya.geo.orthographic=function(){return xe(cc)}).raw=cc;var lc=He(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(ya.geo.stereographic=function(){return xe(lc)}).raw=lc,Re.invert=function(n,t){return[Math.atan2(X(n),Math.cos(t)),V(Math.sin(t)/Z(n))]},(ya.geo.transverseMercator=function(){return Ye(Re)}).raw=Re,ya.geom={},ya.svg={},ya.svg.line=function(){return Ue(mt)};var sc=ya.map({linear:Xe,"linear-closed":Ze,step:Be,"step-before":$e,"step-after":We,basis:tr,"basis-open":er,"basis-closed":rr,bundle:ir,cardinal:Ke,"cardinal-open":Je,"cardinal-closed":Ge,monotone:sr}); +sc.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var fc=[0,2/3,1/3,0],hc=[0,1/3,2/3,0],gc=[0,1/6,2/3,1/6];ya.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,i,u,a,o,c,l,s,f,h,g,p,m=pt(e),d=pt(r),v=n.length,y=v-1,M=[],x=[],b=0;if(m===Ie&&r===Ve)t=n;else for(u=0,t=[];v>u;++u)t.push([+m.call(this,i=n[u],u),+d.call(this,i,u)]);for(u=1;v>u;++u)(t[u][1]u;++u)u!==b&&(c=t[u][1]-t[b][1],o=t[u][0]-t[b][0],M.push({angle:Math.atan2(c,o),index:u}));for(M.sort(function(n,t){return n.angle-t.angle}),g=M[0].angle,h=M[0].index,f=0,u=1;y>u;++u){if(a=M[u].index,g==M[u].angle){if(o=t[h][0]-t[b][0],c=t[h][1]-t[b][1],l=t[a][0]-t[b][0],s=t[a][1]-t[b][1],o*o+c*c>=l*l+s*s){M[u].index=-1;continue}M[f].index=-1}g=M[u].angle,f=u,h=a}for(x.push(b),u=0,a=0;2>u;++a)M[a].index>-1&&(x.push(M[a].index),u++);for(p=x.length;y>a;++a)if(!(M[a].index<0)){for(;!fr(x[p-2],x[p-1],M[a].index,t);)--p;x[p++]=M[a].index}var _=[];for(u=p-1;u>=0;--u)_.push(n[x[u]]);return _}var e=Ie,r=Ve;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},ya.geom.polygon=function(n){return La(n,pc),n};var pc=ya.geom.polygon.prototype=[];pc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],i=0;++to;o++)e.push([i,t[o],t[o+1]])}),e},ya.geom.voronoi=function(n){function t(n){var t,u,a,o=n.map(function(){return[]}),c=pt(e),l=pt(r),s=n.length,f=1e6;if(c===Ie&&l===Ve)t=n;else for(t=new Array(s),a=0;s>a;++a)t[a]=[+c.call(this,u=n[a],a),+l.call(this,u,a)];if(mr(t,function(n){var t,e,r,i,u,a;1===n.a&&n.b>=0?(t=n.ep.r,e=n.ep.l):(t=n.ep.l,e=n.ep.r),1===n.a?(u=t?t.y:-f,r=n.c-n.b*u,a=e?e.y:f,i=n.c-n.b*a):(r=t?t.x:-f,u=n.c-n.a*r,i=e?e.x:f,a=n.c-n.a*i);var c=[r,u],l=[i,a];o[n.region.l.index].push(c,l),o[n.region.r.index].push(c,l)}),o=o.map(function(n,e){var r=t[e][0],i=t[e][1],u=n.map(function(n){return Math.atan2(n[0]-r,n[1]-i)}),a=ya.range(n.length).sort(function(n,t){return u[n]-u[t]});return a.filter(function(n,t){return!t||u[n]-u[a[t-1]]>Qa}).map(function(t){return n[t]})}),o.forEach(function(n,e){var r=n.length;if(!r)return n.push([-f,-f],[-f,f],[f,f],[f,-f]);if(!(r>2)){var i=t[e],u=n[0],a=n[1],o=i[0],c=i[1],l=u[0],s=u[1],h=a[0],g=a[1],p=Math.abs(h-l),m=g-s;if(Math.abs(m)c?-f:f;n.push([-f,d],[f,d])}else if(Qa>p){var v=l>o?-f:f;n.push([v,-f],[v,f])}else{var d=(l-o)*(g-s)>(h-l)*(s-c)?f:-f,y=Math.abs(m)-p;Math.abs(y)m?d:-d,d]):(y>0&&(d*=-1),n.push([-f,d],[f,d]))}}}),i)for(a=0;s>a;++a)i.clip(o[a]);for(a=0;s>a;++a)o[a].point=n[a];return o}var e=Ie,r=Ve,i=null;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.clipExtent=function(n){if(!arguments.length)return i&&[i[0],i[2]];if(null==n)i=null;else{var e=+n[0][0],r=+n[0][1],u=+n[1][0],a=+n[1][1];i=ya.geom.polygon([[e,r],[e,a],[u,a],[u,r]])}return t},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):i&&i[2]},t.links=function(n){var t,i,u,a=n.map(function(){return[]}),o=[],c=pt(e),l=pt(r),s=n.length;if(c===Ie&&l===Ve)t=n;else for(t=new Array(s),u=0;s>u;++u)t[u]=[+c.call(this,i=n[u],u),+l.call(this,i,u)];return mr(t,function(t){var e=t.region.l.index,r=t.region.r.index;a[e][r]||(a[e][r]=a[r][e]=!0,o.push({source:n[e],target:n[r]}))}),o},t.triangles=function(n){if(e===Ie&&r===Ve)return ya.geom.delaunay(n);for(var t,i=new Array(c),u=pt(e),a=pt(r),o=-1,c=n.length;++o=l,h=r>=s,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=yr()),f?i=l:o=l,h?a=s:c=s,u(n,t,e,r,i,a,o,c)}var s,f,h,g,p,m,d,v,y,M=pt(o),x=pt(c);if(null!=t)m=t,d=e,v=r,y=i;else if(v=y=-(m=d=1/0),f=[],h=[],p=n.length,a)for(g=0;p>g;++g)s=n[g],s.xv&&(v=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var b=+M(s=n[g],g),_=+x(s,g);m>b&&(m=b),d>_&&(d=_),b>v&&(v=b),_>y&&(y=_),f.push(b),h.push(_)}var w=v-m,S=y-d;w>S?y=d+w:v=m+S;var E=yr();if(E.add=function(n){u(E,n,+M(n,++g),+x(n,g),m,d,v,y)},E.visit=function(n){Mr(n,E,m,d,v,y)},g=-1,null==t){for(;++g=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=yc.get(e)||vc,r=Mc.get(r)||mt,kr(r(e.apply(null,Array.prototype.slice.call(arguments,1))))},ya.interpolateHcl=Or,ya.interpolateHsl=Yr,ya.interpolateLab=Rr,ya.interpolateRound=Ur,ya.transform=function(n){var t=Ma.createElementNS(ya.ns.prefix.svg,"g");return(ya.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Ir(e?e.matrix:xc)})(n)},Ir.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var xc={a:1,b:0,c:0,d:1,e:0,f:0};ya.interpolateTransform=Br,ya.layout={},ya.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e(i-e)*o){var c=t.charge*o*o;return n.px-=u*c,n.py-=a*c,!0}if(t.point&&isFinite(o)){var c=t.pointCharge*o*o;n.px-=u*c,n.py-=a*c}}return!t.charge}}function t(n){n.px=ya.event.x,n.py=ya.event.y,o.resume()}var e,r,i,u,a,o={},c=ya.dispatch("start","tick","end"),l=[1,1],s=.9,f=bc,h=_c,g=-30,p=.1,m=.8,d=[],v=[];return o.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,o,f,h,m,y,M,x,b=d.length,_=v.length;for(e=0;_>e;++e)o=v[e],f=o.source,h=o.target,M=h.x-f.x,x=h.y-f.y,(m=M*M+x*x)&&(m=r*u[e]*((m=Math.sqrt(m))-i[e])/m,M*=m,x*=m,h.x-=M*(y=f.weight/(h.weight+f.weight)),h.y-=x*y,f.x+=M*(y=1-y),f.y+=x*y);if((y=r*p)&&(M=l[0]/2,x=l[1]/2,e=-1,y))for(;++e0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),ya.timer(o.tick)),o):r},o.start=function(){function n(n,r){for(var i,u=t(e),a=-1,o=u.length;++ar;++r)c[r]=[];for(r=0;m>r;++r){var n=v[r];c[n.source.index].push(n.target),c[n.target.index].push(n.source)}}return c[e]}var e,r,c,s,p=d.length,m=v.length,y=l[0],M=l[1];for(e=0;p>e;++e)(s=d[e]).index=e,s.weight=0;for(e=0;m>e;++e)s=v[e],"number"==typeof s.source&&(s.source=d[s.source]),"number"==typeof s.target&&(s.target=d[s.target]),++s.source.weight,++s.target.weight;for(e=0;p>e;++e)s=d[e],isNaN(s.x)&&(s.x=n("x",y)),isNaN(s.y)&&(s.y=n("y",M)),isNaN(s.px)&&(s.px=s.x),isNaN(s.py)&&(s.py=s.y);if(i=[],"function"==typeof f)for(e=0;m>e;++e)i[e]=+f.call(this,v[e],e);else for(e=0;m>e;++e)i[e]=f;if(u=[],"function"==typeof h)for(e=0;m>e;++e)u[e]=+h.call(this,v[e],e);else for(e=0;m>e;++e)u[e]=h;if(a=[],"function"==typeof g)for(e=0;p>e;++e)a[e]=+g.call(this,d[e],e);else for(e=0;p>e;++e)a[e]=g;return o.resume()},o.resume=function(){return o.alpha(.1)},o.stop=function(){return o.alpha(0)},o.drag=function(){return e||(e=ya.behavior.drag().origin(mt).on("dragstart.force",Qr).on("drag.force",t).on("dragend.force",ni)),arguments.length?(this.on("mouseover.force",ti).on("mouseout.force",ei).call(e),void 0):e},ya.rebind(o,c,"on")};var bc=20,_c=1;ya.layout.hierarchy=function(){function n(t,a,o){var c=i.call(e,t,a);if(t.depth=a,o.push(t),c&&(l=c.length)){for(var l,s,f=-1,h=t.children=[],g=0,p=a+1;++fg;++g)for(i.call(n,l[0][g],p=m[g],s[0][g][1]),h=1;d>h;++h)i.call(n,l[h][g],p+=s[h-1][g][1],s[h][g][1]);return o}var t=mt,e=hi,r=gi,i=fi,u=li,a=si;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:Sc.get(t)||hi,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:Ec.get(t)||gi,n):r},n.x=function(t){return arguments.length?(u=t,n):u},n.y=function(t){return arguments.length?(a=t,n):a},n.out=function(t){return arguments.length?(i=t,n):i},n};var Sc=ya.map({"inside-out":function(n){var t,e,r=n.length,i=n.map(pi),u=n.map(mi),a=ya.range(r).sort(function(n,t){return i[n]-i[t]}),o=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=a[t],c>o?(o+=u[e],l.push(e)):(c+=u[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return ya.range(n.length).reverse()},"default":hi}),Ec=ya.map({silhouette:function(n){var t,e,r,i=n.length,u=n[0].length,a=[],o=0,c=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];r>o&&(o=r),a.push(r)}for(e=0;u>e;++e)c[e]=(o-a[e])/2;return c},wiggle:function(n){var t,e,r,i,u,a,o,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,i=0;s>t;++t)i+=n[t][e][1];for(t=0,u=0,o=f[e][0]-f[e-1][0];s>t;++t){for(r=0,a=(n[t][e][1]-n[t][e-1][1])/(2*o);t>r;++r)a+=(n[r][e][1]-n[r][e-1][1])/o;u+=a*n[t][e][1]}g[e]=c-=i?u/i*o:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,i=n.length,u=n[0].length,a=1/i,o=[];for(e=0;u>e;++e){for(t=0,r=0;i>t;t++)r+=n[t][e][1];if(r)for(t=0;i>t;t++)n[t][e][1]/=r;else for(t=0;i>t;t++)n[t][e][1]=a}for(e=0;u>e;++e)o[e]=0;return o},zero:gi});ya.layout.histogram=function(){function n(n,u){for(var a,o,c=[],l=n.map(e,this),s=r.call(this,l,u),f=i.call(this,s,l,u),u=-1,h=l.length,g=f.length-1,p=t?1:1/h;++u0)for(u=-1;++u=s[0]&&o<=s[1]&&(a=c[ya.bisect(f,o,1,g)-1],a.y+=p,a.push(n[u]));return c}var t=!0,e=Number,r=Mi,i=vi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=pt(t),n):r},n.bins=function(t){return arguments.length?(i="number"==typeof t?function(n){return yi(n,t)}:pt(t),n):i},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},ya.layout.tree=function(){function n(n,u){function a(n,t){var r=n.children,i=n._tree;if(r&&(u=r.length)){for(var u,o,l,s=r[0],f=s,h=-1;++h0&&(qi(Ti(o,n,r),n,i),l+=i,s+=i),f+=o._tree.mod,l+=u._tree.mod,h+=c._tree.mod,s+=a._tree.mod;o&&!_i(a)&&(a._tree.thread=o,a._tree.mod+=f-s),u&&!bi(c)&&(c._tree.thread=u,c._tree.mod+=l-h,r=n)}return r}var l=t.call(this,n,u),s=l[0];Ai(s,function(n,t){n._tree={ancestor:n,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),a(s),o(s,-s._tree.prelim);var f=wi(s,Ei),h=wi(s,Si),g=wi(s,ki),p=f.x-e(f,h)/2,m=h.x+e(h,f)/2,d=g.depth||1;return Ai(s,i?function(n){n.x*=r[0],n.y=n.depth*r[1],delete n._tree}:function(n){n.x=(n.x-p)/(m-p)*r[0],n.y=n.depth/d*r[1],delete n._tree}),l}var t=ya.layout.hierarchy().sort(null).value(null),e=xi,r=[1,1],i=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return arguments.length?(i=null!=(r=t),n):i?r:null},ii(n,t)},ya.layout.pack=function(){function n(n,u){var a=e.call(this,n,u),o=a[0],c=i[0],l=i[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(o.x=o.y=0,Ai(o,function(n){n.r=+s(n.value)}),Ai(o,Li),r){var f=r*(t?1:Math.max(2*o.r/c,2*o.r/l))/2;Ai(o,function(n){n.r+=f}),Ai(o,Li),Ai(o,function(n){n.r-=f})}return Pi(o,c/2,l/2,t?1:1/Math.max(2*o.r/c,2*o.r/l)),a}var t,e=ya.layout.hierarchy().sort(Ci),r=0,i=[1,1];return n.size=function(t){return arguments.length?(i=t,n):i},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},ii(n,e)},ya.layout.cluster=function(){function n(n,u){var a,o=t.call(this,n,u),c=o[0],l=0;Ai(c,function(n){var t=n.children;t&&t.length?(n.x=Ri(t),n.y=Yi(t)):(n.x=a?l+=e(n,a):0,n.y=0,a=n)});var s=Ui(c),f=Ii(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Ai(c,i?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),o}var t=ya.layout.hierarchy().sort(null).value(null),e=xi,r=[1,1],i=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(i=null==(r=t),n):i?null:r},n.nodeSize=function(t){return arguments.length?(i=null!=(r=t),n):i?r:null},ii(n,t)},ya.layout.treemap=function(){function n(n,t){for(var e,r,i=-1,u=n.length;++it?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var u=e.children;if(u&&u.length){var a,o,c,l=f(e),s=[],h=u.slice(),p=1/0,m="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(a=h[c-1]),s.area+=a.area,"squarify"!==g||(o=r(s,m))<=p?(h.pop(),p=o):(s.area-=s.pop().area,i(s,m,l,!1),m=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(i(s,m,l,!0),s.length=s.area=0),u.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var u,a=f(t),o=r.slice(),c=[];for(n(o,a.dx*a.dy/t.value),c.area=0;u=o.pop();)c.push(u),c.area+=u.area,null!=u.z&&(i(c,u.z?a.dx:a.dy,a,!o.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,i=0,u=1/0,a=-1,o=n.length;++ae&&(u=e),e>i&&(i=e));return r*=r,t*=t,r?Math.max(t*i*p/r,r/(t*u*p)):1/0}function i(n,t,e,r){var i,u=-1,a=n.length,o=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++ue.dx)&&(s=e.dx);++ue&&(t=1),1>e&&(n=0),function(){var e,r,i;do e=2*Math.random()-1,r=2*Math.random()-1,i=e*e+r*r;while(!i||i>1);return n+t*e*Math.sqrt(-2*Math.log(i)/i)}},logNormal:function(){var n=ya.random.normal.apply(ya,arguments);return function(){return Math.exp(n())}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t/n}}},ya.scale={};var kc={floor:mt,ceil:mt};ya.scale.linear=function(){return Ki([0,1],[0,1],Sr,!1)},ya.scale.log=function(){return uu(ya.scale.linear().domain([0,1]),10,!0,[1,10])};var Ac=ya.format(".0e"),Nc={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};ya.scale.pow=function(){return au(ya.scale.linear(),1,[0,1])},ya.scale.sqrt=function(){return ya.scale.pow().exponent(.5)},ya.scale.ordinal=function(){return cu([],{t:"range",a:[[]]})},ya.scale.category10=function(){return ya.scale.ordinal().range(qc)},ya.scale.category20=function(){return ya.scale.ordinal().range(Tc)},ya.scale.category20b=function(){return ya.scale.ordinal().range(Cc)},ya.scale.category20c=function(){return ya.scale.ordinal().range(zc)};var qc=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(ut),Tc=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(ut),Cc=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(ut),zc=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(ut);ya.scale.quantile=function(){return lu([],[])},ya.scale.quantize=function(){return su(0,1,[0,1])},ya.scale.threshold=function(){return fu([.5],[0,1])},ya.scale.identity=function(){return hu([0,1])},ya.svg.arc=function(){function n(){var n=t.apply(this,arguments),u=e.apply(this,arguments),a=r.apply(this,arguments)+Dc,o=i.apply(this,arguments)+Dc,c=(a>o&&(c=a,a=o,o=c),o-a),l=Ka>c?"0":"1",s=Math.cos(a),f=Math.sin(a),h=Math.cos(o),g=Math.sin(o);return c>=jc?n?"M0,"+u+"A"+u+","+u+" 0 1,1 0,"+-u+"A"+u+","+u+" 0 1,1 0,"+u+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+u+"A"+u+","+u+" 0 1,1 0,"+-u+"A"+u+","+u+" 0 1,1 0,"+u+"Z":n?"M"+u*s+","+u*f+"A"+u+","+u+" 0 "+l+",1 "+u*h+","+u*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+l+",0 "+n*s+","+n*f+"Z":"M"+u*s+","+u*f+"A"+u+","+u+" 0 "+l+",1 "+u*h+","+u*g+"L0,0"+"Z"}var t=gu,e=pu,r=mu,i=du;return n.innerRadius=function(e){return arguments.length?(t=pt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=pt(t),n):e},n.startAngle=function(t){return arguments.length?(r=pt(t),n):r},n.endAngle=function(t){return arguments.length?(i=pt(t),n):i},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,u=(r.apply(this,arguments)+i.apply(this,arguments))/2+Dc;return[Math.cos(u)*n,Math.sin(u)*n]},n};var Dc=-Ka/2,jc=2*Ka-1e-6;ya.svg.line.radial=function(){var n=Ue(vu);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},$e.reverse=We,We.reverse=$e,ya.svg.area=function(){return yu(mt)},ya.svg.area.radial=function(){var n=yu(vu);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},ya.svg.chord=function(){function n(n,o){var c=t(this,u,n,o),l=t(this,a,n,o);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?i(c.r,c.p1,c.r,c.p0):i(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+i(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var i=t.call(n,e,r),u=o.call(n,i,r),a=c.call(n,i,r)+Dc,s=l.call(n,i,r)+Dc;return{r:u,a0:a,a1:s,p0:[u*Math.cos(a),u*Math.sin(a)],p1:[u*Math.cos(s),u*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Ka)+",1 "+t}function i(n,t,e,r){return"Q 0,0 "+r}var u=ze,a=De,o=Mu,c=mu,l=du;return n.radius=function(t){return arguments.length?(o=pt(t),n):o},n.source=function(t){return arguments.length?(u=pt(t),n):u},n.target=function(t){return arguments.length?(a=pt(t),n):a},n.startAngle=function(t){return arguments.length?(c=pt(t),n):c},n.endAngle=function(t){return arguments.length?(l=pt(t),n):l},n},ya.svg.diagonal=function(){function n(n,i){var u=t.call(this,n,i),a=e.call(this,n,i),o=(u.y+a.y)/2,c=[u,{x:u.x,y:o},{x:a.x,y:o},a];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=ze,e=De,r=xu;return n.source=function(e){return arguments.length?(t=pt(e),n):t},n.target=function(t){return arguments.length?(e=pt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},ya.svg.diagonal.radial=function(){var n=ya.svg.diagonal(),t=xu,e=n.projection;return n.projection=function(n){return arguments.length?e(bu(t=n)):t},n},ya.svg.symbol=function(){function n(n,r){return(Lc.get(t.call(this,n,r))||Su)(e.call(this,n,r))}var t=wu,e=_u;return n.type=function(e){return arguments.length?(t=pt(e),n):t},n.size=function(t){return arguments.length?(e=pt(t),n):e},n};var Lc=ya.map({circle:Su,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Oc)),e=t*Oc;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/Pc),e=t*Pc/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/Pc),e=t*Pc/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});ya.svg.symbolTypes=Lc.keys();var Hc,Fc,Pc=Math.sqrt(3),Oc=Math.tan(30*to),Yc=[],Rc=0;Yc.call=Ya.call,Yc.empty=Ya.empty,Yc.node=Ya.node,Yc.size=Ya.size,ya.transition=function(n){return arguments.length?Hc?n.transition():n:Ia.transition()},ya.transition.prototype=Yc,Yc.select=function(n){var t,e,r,i=this.id,u=[];n=v(n);for(var a=-1,o=this.length;++au;u++){i.push(t=[]);for(var e=this[u],o=0,c=e.length;c>o;o++)(r=e[o])&&n.call(r,r.__data__,o)&&t.push(r)}return Eu(i,this.id)},Yc.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):T(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Yc.attr=function(n,t){function e(){this.removeAttribute(o)}function r(){this.removeAttributeNS(o.space,o.local)}function i(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(o);return e!==n&&(t=a(e,n),function(n){this.setAttribute(o,t(n))})})}function u(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(o.space,o.local);return e!==n&&(t=a(e,n),function(n){this.setAttributeNS(o.space,o.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var a="transform"==n?Br:Sr,o=ya.ns.qualify(n);return ku(this,"attr."+n,t,o.local?u:i)},Yc.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(i));return r&&function(n){this.setAttribute(i,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(i.space,i.local));return r&&function(n){this.setAttributeNS(i.space,i.local,r(n))}}var i=ya.ns.qualify(n);return this.tween("attr."+n,i.local?r:e)},Yc.style=function(n,t,e){function r(){this.style.removeProperty(n)}function i(t){return null==t?r:(t+="",function(){var r,i=ba.getComputedStyle(this,null).getPropertyValue(n);return i!==t&&(r=Sr(i,t),function(t){this.style.setProperty(n,r(t),e)})})}var u=arguments.length;if(3>u){if("string"!=typeof n){2>u&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return ku(this,"style."+n,t,i)},Yc.styleTween=function(n,t,e){function r(r,i){var u=t.call(this,r,i,ba.getComputedStyle(this,null).getPropertyValue(n));return u&&function(t){this.style.setProperty(n,u(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Yc.text=function(n){return ku(this,"text",n,Au)},Yc.remove=function(){return this.each("end.transition",function(){var n;!this.__transition__&&(n=this.parentNode)&&n.removeChild(this)})},Yc.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=ya.ease.apply(ya,arguments)),T(this,function(e){e.__transition__[t].ease=n}))},Yc.delay=function(n){var t=this.id;return T(this,"function"==typeof n?function(e,r,i){e.__transition__[t].delay=0|n.call(e,e.__data__,r,i)}:(n|=0,function(e){e.__transition__[t].delay=n}))},Yc.duration=function(n){var t=this.id;return T(this,"function"==typeof n?function(e,r,i){e.__transition__[t].duration=Math.max(1,0|n.call(e,e.__data__,r,i))}:(n=Math.max(1,0|n),function(e){e.__transition__[t].duration=n}))},Yc.each=function(n,t){var e=this.id;if(arguments.length<2){var r=Fc,i=Hc;Hc=e,T(this,function(t,r,i){Fc=t.__transition__[e],n.call(t,t.__data__,r,i)}),Fc=r,Hc=i}else T(this,function(r){var i=r.__transition__[e];(i.event||(i.event=ya.dispatch("start","end"))).on(n,t)});return this},Yc.transition=function(){for(var n,t,e,r,i=this.id,u=++Rc,a=[],o=0,c=this.length;c>o;o++){a.push(n=[]);for(var t=this[o],l=0,s=t.length;s>l;l++)(e=t[l])&&(r=Object.create(e.__transition__[i]),r.delay+=r.duration,Nu(e,l,u,r)),n.push(e)}return Eu(a,u)},ya.svg.axis=function(){function n(n){n.each(function(){var n,f=ya.select(this),h=null==l?e.ticks?e.ticks.apply(e,c):e.domain():l,g=null==t?e.tickFormat?e.tickFormat.apply(e,c):String:t,p=Cu(e,h,s),m=f.selectAll(".tick.minor").data(p,String),d=m.enter().insert("line",".tick").attr("class","tick minor").style("opacity",1e-6),v=ya.transition(m.exit()).style("opacity",1e-6).remove(),y=ya.transition(m).style("opacity",1),M=f.selectAll(".tick.major").data(h,String),x=M.enter().insert("g",".domain").attr("class","tick major").style("opacity",1e-6),b=ya.transition(M.exit()).style("opacity",1e-6).remove(),_=ya.transition(M).style("opacity",1),w=Bi(e),S=f.selectAll(".domain").data([0]),E=(S.enter().append("path").attr("class","domain"),ya.transition(S)),k=e.copy(),A=this.__chart__||k; +this.__chart__=k,x.append("line"),x.append("text");var N=x.select("line"),q=_.select("line"),T=M.select("text").text(g),C=x.select("text"),z=_.select("text");switch(r){case"bottom":n=qu,d.attr("y2",u),y.attr("x2",0).attr("y2",u),N.attr("y2",i),C.attr("y",Math.max(i,0)+o),q.attr("x2",0).attr("y2",i),z.attr("x",0).attr("y",Math.max(i,0)+o),T.attr("dy",".71em").style("text-anchor","middle"),E.attr("d","M"+w[0]+","+a+"V0H"+w[1]+"V"+a);break;case"top":n=qu,d.attr("y2",-u),y.attr("x2",0).attr("y2",-u),N.attr("y2",-i),C.attr("y",-(Math.max(i,0)+o)),q.attr("x2",0).attr("y2",-i),z.attr("x",0).attr("y",-(Math.max(i,0)+o)),T.attr("dy","0em").style("text-anchor","middle"),E.attr("d","M"+w[0]+","+-a+"V0H"+w[1]+"V"+-a);break;case"left":n=Tu,d.attr("x2",-u),y.attr("x2",-u).attr("y2",0),N.attr("x2",-i),C.attr("x",-(Math.max(i,0)+o)),q.attr("x2",-i).attr("y2",0),z.attr("x",-(Math.max(i,0)+o)).attr("y",0),T.attr("dy",".32em").style("text-anchor","end"),E.attr("d","M"+-a+","+w[0]+"H0V"+w[1]+"H"+-a);break;case"right":n=Tu,d.attr("x2",u),y.attr("x2",u).attr("y2",0),N.attr("x2",i),C.attr("x",Math.max(i,0)+o),q.attr("x2",i).attr("y2",0),z.attr("x",Math.max(i,0)+o).attr("y",0),T.attr("dy",".32em").style("text-anchor","start"),E.attr("d","M"+a+","+w[0]+"H0V"+w[1]+"H"+a)}if(e.rangeBand){var D=k.rangeBand()/2,j=function(n){return k(n)+D};x.call(n,j),_.call(n,j)}else x.call(n,A),_.call(n,k),b.call(n,k),d.call(n,A),y.call(n,k),v.call(n,k)})}var t,e=ya.scale.linear(),r=Uc,i=6,u=6,a=6,o=3,c=[10],l=null,s=0;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Ic?t+"":Uc,n):r},n.ticks=function(){return arguments.length?(c=arguments,n):c},n.tickValues=function(t){return arguments.length?(l=t,n):l},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t,e){if(!arguments.length)return i;var r=arguments.length-1;return i=+t,u=r>1?+e:i,a=r>0?+arguments[r]:i,n},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(t){return arguments.length?(s=+t,n):s},n};var Uc="bottom",Ic={top:1,right:1,bottom:1,left:1};ya.svg.brush=function(){function n(u){u.each(function(){var u,a=ya.select(this),s=a.selectAll(".background").data([0]),f=a.selectAll(".extent").data([0]),h=a.selectAll(".resize").data(l,String);a.style("pointer-events","all").on("mousedown.brush",i).on("touchstart.brush",i),s.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),f.enter().append("rect").attr("class","extent").style("cursor","move"),h.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Vc[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),h.style("display",n.empty()?"none":null),h.exit().remove(),o&&(u=Bi(o),s.attr("x",u[0]).attr("width",u[1]-u[0]),e(a)),c&&(u=Bi(c),s.attr("y",u[0]).attr("height",u[1]-u[0]),r(a)),t(a)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)][0]+","+s[+/^s/.test(n)][1]+")"})}function e(n){n.select(".extent").attr("x",s[0][0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1][0]-s[0][0])}function r(n){n.select(".extent").attr("y",s[0][1]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",s[1][1]-s[0][1])}function i(){function i(){var n=ya.event.changedTouches;return n?ya.touches(M,n)[0]:ya.mouse(M)}function l(){32==ya.event.keyCode&&(k||(v=null,N[0]-=s[1][0],N[1]-=s[1][1],k=2),g())}function h(){32==ya.event.keyCode&&2==k&&(N[0]+=s[1][0],N[1]+=s[1][1],k=0,g())}function p(){var n=i(),u=!1;y&&(n[0]+=y[0],n[1]+=y[1]),k||(ya.event.altKey?(v||(v=[(s[0][0]+s[1][0])/2,(s[0][1]+s[1][1])/2]),N[0]=s[+(n[0]l?(i=r,r=l):i=l),s[0][e]!==r||s[1][e]!==i?(u=null,s[0][e]=r,s[1][e]=i,!0):void 0}function d(){p(),_.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),ya.select("body").style("cursor",null),q.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),A(),b({type:"brushend"})}var v,y,M=this,x=ya.select(ya.event.target),b=a.of(M,arguments),_=ya.select(M),w=x.datum(),S=!/^(n|s)$/.test(w)&&o,E=!/^(e|w)$/.test(w)&&c,k=x.classed("extent"),A=H(),N=i(),q=ya.select(ba).on("keydown.brush",l).on("keyup.brush",h);if(ya.event.changedTouches?q.on("touchmove.brush",p).on("touchend.brush",d):q.on("mousemove.brush",p).on("mouseup.brush",d),k)N[0]=s[0][0]-N[0],N[1]=s[0][1]-N[1];else if(w){var T=+/w$/.test(w),C=+/^n/.test(w);y=[s[1-T][0]-N[0],s[1-C][1]-N[1]],N[0]=s[T][0],N[1]=s[C][1]}else ya.event.altKey&&(v=N.slice());_.style("pointer-events","none").selectAll(".resize").style("display",null),ya.select("body").style("cursor",x.style("cursor")),b({type:"brushstart"}),p()}var u,a=m(n,"brushstart","brush","brushend"),o=null,c=null,l=Xc[0],s=[[0,0],[0,0]],f=[!0,!0];return n.x=function(t){return arguments.length?(o=t,l=Xc[!o<<1|!c],n):o},n.y=function(t){return arguments.length?(c=t,l=Xc[!o<<1|!c],n):c},n.clamp=function(t){return arguments.length?(o&&c?f=[!!t[0],!!t[1]]:(o||c)&&(f[+!o]=!!t),n):o&&c?f:o||c?f[+!o]:null},n.extent=function(t){var e,r,i,a,l;return arguments.length?(u=[[0,0],[0,0]],o&&(e=t[0],r=t[1],c&&(e=e[0],r=r[0]),u[0][0]=e,u[1][0]=r,o.invert&&(e=o(e),r=o(r)),e>r&&(l=e,e=r,r=l),s[0][0]=0|e,s[1][0]=0|r),c&&(i=t[0],a=t[1],o&&(i=i[1],a=a[1]),u[0][1]=i,u[1][1]=a,c.invert&&(i=c(i),a=c(a)),i>a&&(l=i,i=a,a=l),s[0][1]=0|i,s[1][1]=0|a),n):(t=u||s,o&&(e=t[0][0],r=t[1][0],u||(e=s[0][0],r=s[1][0],o.invert&&(e=o.invert(e),r=o.invert(r)),e>r&&(l=e,e=r,r=l))),c&&(i=t[0][1],a=t[1][1],u||(i=s[0][1],a=s[1][1],c.invert&&(i=c.invert(i),a=c.invert(a)),i>a&&(l=i,i=a,a=l))),o&&c?[[e,i],[r,a]]:o?[e,r]:c&&[i,a])},n.clear=function(){return u=null,s[0][0]=s[0][1]=s[1][0]=s[1][1]=0,n},n.empty=function(){return o&&s[0][0]===s[1][0]||c&&s[0][1]===s[1][1]},ya.rebind(n,a,"on")};var Vc={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Xc=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]];ya.time={};var Zc=Date,Bc=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];zu.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){$c.setUTCDate.apply(this._,arguments)},setDay:function(){$c.setUTCDay.apply(this._,arguments)},setFullYear:function(){$c.setUTCFullYear.apply(this._,arguments)},setHours:function(){$c.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){$c.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){$c.setUTCMinutes.apply(this._,arguments)},setMonth:function(){$c.setUTCMonth.apply(this._,arguments)},setSeconds:function(){$c.setUTCSeconds.apply(this._,arguments)},setTime:function(){$c.setTime.apply(this._,arguments)}};var $c=Date.prototype,Wc="%a %b %e %X %Y",Jc="%m/%d/%Y",Gc="%H:%M:%S",Kc=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],Qc=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],nl=["January","February","March","April","May","June","July","August","September","October","November","December"],tl=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];ya.time.year=Du(function(n){return n=ya.time.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),ya.time.years=ya.time.year.range,ya.time.years.utc=ya.time.year.utc.range,ya.time.day=Du(function(n){var t=new Zc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),ya.time.days=ya.time.day.range,ya.time.days.utc=ya.time.day.utc.range,ya.time.dayOfYear=function(n){var t=ya.time.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},Bc.forEach(function(n,t){n=n.toLowerCase(),t=7-t;var e=ya.time[n]=Du(function(n){return(n=ya.time.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=ya.time.year(n).getDay();return Math.floor((ya.time.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});ya.time[n+"s"]=e.range,ya.time[n+"s"].utc=e.utc.range,ya.time[n+"OfYear"]=function(n){var e=ya.time.year(n).getDay();return Math.floor((ya.time.dayOfYear(n)+(e+t)%7)/7)}}),ya.time.week=ya.time.sunday,ya.time.weeks=ya.time.sunday.range,ya.time.weeks.utc=ya.time.sunday.utc.range,ya.time.weekOfYear=ya.time.sundayOfYear,ya.time.format=function(n){function t(t){for(var r,i,u,a=[],o=-1,c=0;++o=12?"PM":"AM"},S:function(n,t){return Pu(n.getSeconds(),t,2)},U:function(n,t){return Pu(ya.time.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Pu(ya.time.mondayOfYear(n),t,2)},x:ya.time.format(Jc),X:ya.time.format(Gc),y:function(n,t){return Pu(n.getFullYear()%100,t,2)},Y:function(n,t){return Pu(n.getFullYear()%1e4,t,4)},Z:aa,"%":function(){return"%"}},gl={a:Ou,A:Yu,b:Vu,B:Xu,c:Zu,d:Qu,e:Qu,H:ta,I:ta,j:na,L:ia,m:Ku,M:ea,p:ua,S:ra,U:Uu,w:Ru,W:Iu,x:Bu,X:$u,y:Ju,Y:Wu,"%":oa},pl=/^\s*\d+/,ml=ya.map({am:0,pm:1});ya.time.format.utc=function(n){function t(n){try{Zc=zu;var t=new Zc;return t._=n,e(t)}finally{Zc=Date}}var e=ya.time.format(n);return t.parse=function(n){try{Zc=zu;var t=e.parse(n);return t&&t._}finally{Zc=Date}},t.toString=e.toString,t};var dl=ya.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");ya.time.format.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?ca:dl,ca.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},ca.toString=dl.toString,ya.time.second=Du(function(n){return new Zc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),ya.time.seconds=ya.time.second.range,ya.time.seconds.utc=ya.time.second.utc.range,ya.time.minute=Du(function(n){return new Zc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),ya.time.minutes=ya.time.minute.range,ya.time.minutes.utc=ya.time.minute.utc.range,ya.time.hour=Du(function(n){var t=n.getTimezoneOffset()/60;return new Zc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),ya.time.hours=ya.time.hour.range,ya.time.hours.utc=ya.time.hour.utc.range,ya.time.month=Du(function(n){return n=ya.time.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),ya.time.months=ya.time.month.range,ya.time.months.utc=ya.time.month.utc.range;var vl=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],yl=[[ya.time.second,1],[ya.time.second,5],[ya.time.second,15],[ya.time.second,30],[ya.time.minute,1],[ya.time.minute,5],[ya.time.minute,15],[ya.time.minute,30],[ya.time.hour,1],[ya.time.hour,3],[ya.time.hour,6],[ya.time.hour,12],[ya.time.day,1],[ya.time.day,2],[ya.time.week,1],[ya.time.month,1],[ya.time.month,3],[ya.time.year,1]],Ml=[[ya.time.format("%Y"),Xt],[ya.time.format("%B"),function(n){return n.getMonth()}],[ya.time.format("%b %d"),function(n){return 1!=n.getDate()}],[ya.time.format("%a %d"),function(n){return n.getDay()&&1!=n.getDate()}],[ya.time.format("%I %p"),function(n){return n.getHours()}],[ya.time.format("%I:%M"),function(n){return n.getMinutes()}],[ya.time.format(":%S"),function(n){return n.getSeconds()}],[ya.time.format(".%L"),function(n){return n.getMilliseconds()}]],xl=ya.scale.linear(),bl=fa(Ml);yl.year=function(n,t){return xl.domain(n.map(ga)).ticks(t).map(ha)},ya.time.scale=function(){return la(ya.scale.linear(),yl,bl)};var _l=yl.map(function(n){return[n[0].utc,n[1]]}),wl=[[ya.time.format.utc("%Y"),Xt],[ya.time.format.utc("%B"),function(n){return n.getUTCMonth()}],[ya.time.format.utc("%b %d"),function(n){return 1!=n.getUTCDate()}],[ya.time.format.utc("%a %d"),function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],[ya.time.format.utc("%I %p"),function(n){return n.getUTCHours()}],[ya.time.format.utc("%I:%M"),function(n){return n.getUTCMinutes()}],[ya.time.format.utc(":%S"),function(n){return n.getUTCSeconds()}],[ya.time.format.utc(".%L"),function(n){return n.getUTCMilliseconds()}]],Sl=fa(wl);return _l.year=function(n,t){return xl.domain(n.map(ma)).ticks(t).map(pa)},ya.time.scale.utc=function(){return la(ya.scale.linear(),_l,Sl)},ya.text=dt(function(n){return n.responseText}),ya.json=function(n,t){return vt(n,"application/json",da,t)},ya.html=function(n,t){return vt(n,"text/html",va,t)},ya.xml=dt(function(n){return n.responseXML}),ya}(); \ No newline at end of file diff --git a/templates/project/assets/javascripts/d3.v2.min.js b/templates/project/assets/javascripts/d3.v2.min.js deleted file mode 100644 index ecd5ff0..0000000 --- a/templates/project/assets/javascripts/d3.v2.min.js +++ /dev/null @@ -1,4 +0,0 @@ -(function(){function d(a,b){try{for(var c in b)Object.defineProperty(a.prototype,c,{value:b[c],enumerable:!1})}catch(d){a.prototype=b}}function f(a){var b=-1,c=a.length,d=[];while(++b=0?a.substring(b):(b=a.length,""),d=[];while(b>0)d.push(a.substring(b-=3,b+3));return d.reverse().join(",")+c}function H(a,b){var c=Math.pow(10,Math.abs(8-b)*3);return{scale:b>8?function(a){return a/c}:function(a){return a*c},symbol:a}}function N(a){return function(b){return b<=0?0:b>=1?1:a(b)}}function O(a){return function(b){return 1-a(1-b)}}function P(a){return function(b){return.5*(b<.5?a(2*b):2-a(2-2*b))}}function Q(a){return a}function R(a){return function(b){return Math.pow(b,a)}}function S(a){return 1-Math.cos(a*Math.PI/2)}function T(a){return Math.pow(2,10*(a-1))}function U(a){return 1-Math.sqrt(1-a*a)}function V(a,b){var c;return arguments.length<2&&(b=.45),arguments.length<1?(a=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/a),function(d){return 1+a*Math.pow(2,10*-d)*Math.sin((d-c)*2*Math.PI/b)}}function W(a){return a||(a=1.70158),function(b){return b*b*((a+1)*b-a)}}function X(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375}function Y(){d3.event.stopPropagation(),d3.event.preventDefault()}function Z(){var a=d3.event,b;while(b=a.sourceEvent)a=b;return a}function $(a){var b=new z,c=0,d=arguments.length;while(++c360?a-=360:a<0&&(a+=360),a<60?d+(e-d)*a/60:a<180?e:a<240?d+(e-d)*(240-a)/60:d}function g(a){return Math.round(f(a)*255)}var d,e;return a%=360,a<0&&(a+=360),b=b<0?0:b>1?1:b,c=c<0?0:c>1?1:c,e=c<=.5?c*(1+b):c+b-c*b,d=2*c-e,bj(g(a+120),g(a),g(a-120))}function bv(a,b,c){return new bw(a,b,c)}function bw(a,b,c){this.h=a,this.c=b,this.l=c}function bx(a,b,c){return by(c,Math.cos(a*=Math.PI/180)*b,Math.sin(a)*b)}function by(a,b,c){return new bz(a,b,c)}function bz(a,b,c){this.l=a,this.a=b,this.b=c}function bE(a,b,c){var d=(a+16)/116,e=d+b/500,f=d-c/200;return e=bG(e)*bB,d=bG(d)*bC,f=bG(f)*bD,bj(bI(3.2404542*e-1.5371385*d-.4985314*f),bI(-0.969266*e+1.8760108*d+.041556*f),bI(.0556434*e-.2040259*d+1.0572252*f))}function bF(a,b,c){return bv(Math.atan2(c,b)/Math.PI*180,Math.sqrt(b*b+c*c),a)}function bG(a){return a>.206893034?a*a*a:(a-4/29)/7.787037}function bH(a){return a>.008856?Math.pow(a,1/3):7.787037*a+4/29}function bI(a){return Math.round(255*(a<=.00304?12.92*a:1.055*Math.pow(a,1/2.4)-.055))}function bJ(a){return i(a,bP),a}function bQ(a){return function(){return bK(a,this)}}function bR(a){return function(){return bL(a,this)}}function bS(a,b){function c(){this.removeAttribute(a)}function d(){this.removeAttributeNS(a.space,a.local)}function e(){this.setAttribute(a,b)}function f(){this.setAttributeNS(a.space,a.local,b)}function g(){var c=b.apply(this,arguments);c==null?this.removeAttribute(a):this.setAttribute(a,c)}function h(){var c=b.apply(this,arguments);c==null?this.removeAttributeNS(a.space,a.local):this.setAttributeNS(a.space,a.local,c)}return a=d3.ns.qualify(a),b==null?a.local?d:c:typeof b=="function"?a.local?h:g:a.local?f:e}function bT(a){return new RegExp("(?:^|\\s+)"+d3.requote(a)+"(?:\\s+|$)","g")}function bU(a,b){function d(){var d=-1;while(++d0&&(a=a.substring(0,e)),b?g:f}function ca(a,b){for(var c=0,d=a.length;cb?q():(m.active=b,d.forEach(function(b,c){(c=c.call(a,n,h))&&j.push(c)}),e.start.call(a,n,h),p(f)||d3.timer(p,0,c),1)}function p(c){if(m.active!==b)return q();var d=(c-k)/l,g=f(d),i=j.length;while(i>0)j[--i].call(a,g);if(d>=1)return q(),ch=b,e.end.call(a,n,h),ch=0,1}function q(){return--m.count||delete a.__transition__,1}var j=[],k=a.delay,l=a.duration,m=(a=a.node).__transition__||(a.__transition__={active:0,count:0}),n=a.__data__;++m.count,k<=g?o(g):d3.timer(o,k,c)})},0,c),a}function co(a){var b=ch,c=cn,d=cl,e=cm;return ch=this.id,cn=this.ease(),ca(this,function(b,c,d){cl=b.delay,cm=b.duration,a.call(b=b.node,b.__data__,c,d)}),ch=b,cn=c,cl=d,cm=e,this}function cq(a,b,c){return c!=""&&cp}function cr(a,b){return d3.tween(a,bg(b))}function cv(){var a,b=Date.now(),c=cs;while(c)a=b-c.then,a>=c.delay&&(c.flush=c.callback(a)),c=c.next;var d=cw()-b;d>24?(isFinite(d)&&(clearTimeout(cu),cu=setTimeout(cv,d)),ct=0):(ct=1,cx(cv))}function cw(){var a=null,b=cs,c=Infinity;while(b)b.flush?b=a?a.next=b.next:cs=b.next:(c=Math.min(c,b.then+b.delay),b=(a=b).next);return c}function cz(a,b){var c=a.ownerSVGElement||a;if(c.createSVGPoint){var d=c.createSVGPoint();if(cy<0&&(window.scrollX||window.scrollY)){c=d3.select(document.body).append("svg").style("position","absolute").style("top",0).style("left",0);var e=c[0][0].getScreenCTM();cy=!e.f&&!e.e,c.remove()}return cy?(d.x=b.pageX,d.y=b.pageY):(d.x=b.clientX,d.y=b.clientY),d=d.matrixTransform(a.getScreenCTM().inverse()),[d.x,d.y]}var f=a.getBoundingClientRect();return[b.clientX-f.left-a.clientLeft,b.clientY-f.top-a.clientTop]}function cA(){}function cB(a){var b=a[0],c=a[a.length-1];return b2?cM:cL,i=d?bi:bh;return e=g(a,b,i,c),f=g(b,a,i,d3.interpolate),h}function h(a){return e(a)}var e,f;return h.invert=function(a){return f(a)},h.domain=function(b){return arguments.length?(a=b.map(Number),g()):a},h.range=function(a){return arguments.length?(b=a,g()):b},h.rangeRound=function(a){return h.range(a).interpolate(d3.interpolateRound)},h.clamp=function(a){return arguments.length?(d=a,g()):d},h.interpolate=function(a){return arguments.length?(c=a,g()):c},h.ticks=function(b){return cJ(a,b)},h.tickFormat=function(b){return cK(a,b)},h.nice=function(){return cD(a,cH),g()},h.copy=function(){return cF(a,b,c,d)},g()}function cG(a,b){return d3.rebind(a,b,"range","rangeRound","interpolate","clamp")}function cH(a){return a=Math.pow(10,Math.round(Math.log(a)/Math.LN10)-1),a&&{floor:function(b){return Math.floor(b/a)*a},ceil:function(b){return Math.ceil(b/a)*a}}}function cI(a,b){var c=cB(a),d=c[1]-c[0],e=Math.pow(10,Math.floor(Math.log(d/b)/Math.LN10)),f=b/d*e;return f<=.15?e*=10:f<=.35?e*=5:f<=.75&&(e*=2),c[0]=Math.ceil(c[0]/e)*e,c[1]=Math.floor(c[1]/e)*e+e*.5,c[2]=e,c}function cJ(a,b){return d3.range.apply(d3,cI(a,b))}function cK(a,b){return d3.format(",."+Math.max(0,-Math.floor(Math.log(cI(a,b)[2])/Math.LN10+.01))+"f")}function cL(a,b,c,d){var e=c(a[0],a[1]),f=d(b[0],b[1]);return function(a){return f(e(a))}}function cM(a,b,c,d){var e=[],f=[],g=0,h=Math.min(a.length,b.length)-1;a[h]0;j--)e.push(c(f)*j)}else{for(;fi;g--);e=e.slice(f,g)}return e},d.tickFormat=function(a,e){arguments.length<2&&(e=cO);if(arguments.length<1)return e;var f=Math.max(.1,a/d.ticks().length),g=b===cQ?(h=-1e-12,Math.floor):(h=1e-12,Math.ceil),h;return function(a){return a/c(g(b(a)+h))<=f?e(a):""}},d.copy=function(){return cN(a.copy(),b)},cG(d,a)}function cP(a){return Math.log(a<0?0:a)/Math.LN10}function cQ(a){return-Math.log(a>0?0:-a)/Math.LN10}function cR(a,b){function e(b){return a(c(b))}var c=cS(b),d=cS(1/b);return e.invert=function(b){return d(a.invert(b))},e.domain=function(b){return arguments.length?(a.domain(b.map(c)),e):a.domain().map(d)},e.ticks=function(a){return cJ(e.domain(),a)},e.tickFormat=function(a){return cK(e.domain(),a)},e.nice=function(){return e.domain(cD(e.domain(),cH))},e.exponent=function(a){if(!arguments.length)return b;var f=e.domain();return c=cS(b=a),d=cS(1/b),e.domain(f)},e.copy=function(){return cR(a.copy(),b)},cG(e,a)}function cS(a){return function(b){return b<0?-Math.pow(-b,a):Math.pow(b,a)}}function cT(a,b){function f(b){return d[((c.get(b)||c.set(b,a.push(b)))-1)%d.length]}function g(b,c){return d3.range(a.length).map(function(a){return b+c*a})}var c,d,e;return f.domain=function(d){if(!arguments.length)return a;a=[],c=new j;var e=-1,g=d.length,h;while(++e1){h=b[1],f=a[i],i++,d+="C"+(e[0]+g[0])+","+(e[1]+g[1])+","+(f[0]-h[0])+","+(f[1]-h[1])+","+f[0]+","+f[1];for(var j=2;j9&&(f=c*3/Math.sqrt(f),g[h]=f*d,g[h+1]=f*e));h=-1;while(++h<=i)f=(a[Math.min(i,h+1)][0]-a[Math.max(0,h-1)][0])/(6*(1+g[h]*g[h])),b.push([f||0,g[h]*f||0]);return b}function dG(a){return a.length<3?dk(a):a[0]+ds(a,dF(a))}function dH(a){var b,c=-1,d=a.length,e,f;while(++c1){var d=cB(a.domain()),e,f=-1,g=b.length,h=(b[1]-b[0])/++c,i,j;while(++f0;)(j=+b[f]-i*h)>=d[0]&&e.push(j);for(--f,i=0;++id&&(c=b,d=e);return c}function ex(a){return a.reduce(ey,0)}function ey(a,b){return a+b[1]}function ez(a,b){return eA(a,Math.ceil(Math.log(b.length)/Math.LN2+1))}function eA(a,b){var c=-1,d=+a[0],e=(a[1]-d)/b,f=[];while(++c<=b)f[c]=e*c+d;return f}function eB(a){return[d3.min(a),d3.max(a)]}function eC(a,b){return d3.rebind(a,b,"sort","children","value"),a.links=eG,a.nodes=function(b){return eH=!0,(a.nodes=a)(b)},a}function eD(a){return a.children}function eE(a){return a.value}function eF(a,b){return b.value-a.value}function eG(a){return d3.merge(a.map(function(a){return(a.children||[]).map(function(b){return{source:a,target:b}})}))}function eI(a,b){return a.value-b.value}function eJ(a,b){var c=a._pack_next;a._pack_next=b,b._pack_prev=a,b._pack_next=c,c._pack_prev=b}function eK(a,b){a._pack_next=b,b._pack_prev=a}function eL(a,b){var c=b.x-a.x,d=b.y-a.y,e=a.r+b.r;return e*e-c*c-d*d>.001}function eM(a){function n(a){c=Math.min(a.x-a.r,c),d=Math.max(a.x+a.r,d),e=Math.min(a.y-a.r,e),f=Math.max(a.y+a.r,f)}if(!(b=a.children)||!(m=b.length))return;var b,c=Infinity,d=-Infinity,e=Infinity,f=-Infinity,g,h,i,j,k,l,m;b.forEach(eN),g=b[0],g.x=-g.r,g.y=0,n(g);if(m>1){h=b[1],h.x=h.r,h.y=0,n(h);if(m>2){i=b[2],eQ(g,h,i),n(i),eJ(g,i),g._pack_prev=i,eJ(i,h),h=g._pack_next;for(j=3;j0&&(a=d)}return a}function eZ(a,b){return a.x-b.x}function e$(a,b){return b.x-a.x}function e_(a,b){return a.depth-b.depth}function fa(a,b){function c(a,d){var e=a.children;if(e&&(i=e.length)){var f,g=null,h=-1,i;while(++h=0)f=d[e]._tree,f.prelim+=b,f.mod+=b,b+=f.shift+(c+=f.change)}function fc(a,b,c){a=a._tree,b=b._tree;var d=c/(b.number-a.number);a.change+=d,b.change-=d,b.shift+=c,b.prelim+=c,b.mod+=c}function fd(a,b,c){return a._tree.ancestor.parent==b.parent?a._tree.ancestor:c}function fe(a){return{x:a.x,y:a.y,dx:a.dx,dy:a.dy}}function ff(a,b){var c=a.x+b[3],d=a.y+b[0],e=a.dx-b[1]-b[3],f=a.dy-b[0]-b[2];return e<0&&(c+=e/2,e=0),f<0&&(d+=f/2,f=0),{x:c,y:d,dx:e,dy:f}}function fg(a,b){function f(a,c){d3.text(a,b,function(a){c(a&&f.parse(a))})}function g(b){return b.map(h).join(a)}function h(a){return d.test(a)?'"'+a.replace(/\"/g,'""')+'"':a}var c=new RegExp("\r\n|["+a+"\r\n]","g"),d=new RegExp('["'+a+"\n]"),e=a.charCodeAt(0);return f.parse=function(a){var b;return f.parseRows(a,function(a,c){if(c){var d={},e=-1,f=b.length;while(++e=a.length)return f;if(j)return j=!1,d;var b=c.lastIndex;if(a.charCodeAt(b)===34){var g=b;while(g++0}function fC(a,b,c){return(c[0]-b[0])*(a[1]-b[1])<(c[1]-b[1])*(a[0]-b[0])}function fD(a,b,c,d){var e=a[0],f=b[0],g=c[0],h=d[0],i=a[1],j=b[1],k=c[1],l=d[1],m=e-g,n=f-e,o=h-g,p=i-k,q=j-i,r=l-k,s=(o*p-r*m)/(r*n-o*q);return[e+s*n,i+s*q]}function fF(a,b){var c={list:a.map(function(a,b){return{index:b,x:a[0],y:a[1]}}).sort(function(a,b){return a.yb.y?1:a.xb.x?1:0}),bottomSite:null},d={list:[],leftEnd:null,rightEnd:null,init:function(){d.leftEnd=d.createHalfEdge(null,"l"),d.rightEnd=d.createHalfEdge(null,"l"),d.leftEnd.r=d.rightEnd,d.rightEnd.l=d.leftEnd,d.list.unshift(d.leftEnd,d.rightEnd)},createHalfEdge:function(a,b){return{edge:a,side:b,vertex:null,l:null,r:null}},insert:function(a,b){b.l=a,b.r=a.r,a.r.l=b,a.r=b},leftBound:function(a){var b=d.leftEnd;do b=b.r;while(b!=d.rightEnd&&e.rightOf(b,a));return b=b.l,b},del:function(a){a.l.r=a.r,a.r.l=a.l,a.edge=null},right:function(a){return a.r},left:function(a){return a.l},leftRegion:function(a){return a.edge==null?c.bottomSite:a.edge.region[a.side]},rightRegion:function(a){return a.edge==null?c.bottomSite:a.edge.region[fE[a.side]]}},e={bisect:function(a,b){var c={region:{l:a,r:b},ep:{l:null,r:null}},d=b.x-a.x,e=b.y-a.y,f=d>0?d:-d,g=e>0?e:-e;return c.c=a.x*d+a.y*e+(d*d+e*e)*.5,f>g?(c.a=1,c.b=e/d,c.c/=d):(c.b=1,c.a=d/e,c.c/=e),c},intersect:function(a,b){var c=a.edge,d=b.edge;if(!c||!d||c.region.r==d.region.r)return null;var e=c.a*d.b-c.b*d.a;if(Math.abs(e)<1e-10)return null;var f=(c.c*d.b-d.c*c.b)/e,g=(d.c*c.a-c.c*d.a)/e,h=c.region.r,i=d.region.r,j,k;h.y=k.region.r.x;return l&&j.side==="l"||!l&&j.side==="r"?null:{x:f,y:g}},rightOf:function(a,b){var c=a.edge,d=c.region.r,e=b.x>d.x;if(e&&a.side==="l")return 1;if(!e&&a.side==="r")return 0;if(c.a===1){var f=b.y-d.y,g=b.x-d.x,h=0,i=0;!e&&c.b<0||e&&c.b>=0?i=h=f>=c.b*g:(i=b.x+b.y*c.b>c.c,c.b<0&&(i=!i),i||(h=1));if(!h){var j=d.x-c.region.l.x;i=c.b*(g*g-f*f)m*m+n*n}return a.side==="l"?i:!i},endPoint:function(a,c,d){a.ep[c]=d;if(!a.ep[fE[c]])return;b(a)},distance:function(a,b){var c=a.x-b.x,d=a.y-b.y;return Math.sqrt(c*c+d*d)}},f={list:[],insert:function(a,b,c){a.vertex=b,a.ystar=b.y+c;for(var d=0,e=f.list,g=e.length;dh.ystar||a.ystar==h.ystar&&b.x>h.vertex.x)continue;break}e.splice(d,0,a)},del:function(a){for(var b=0,c=f.list,d=c.length;bo.y&&(p=n,n=o,o=p,t="r"),s=e.bisect(n,o),m=d.createHalfEdge(s,t),d.insert(k,m),e.endPoint(s,fE[t],r),q=e.intersect(k,m),q&&(f.del(k),f.insert(k,q,e.distance(q,n))),q=e.intersect(m,l),q&&f.insert(m,q,e.distance(q,n));else break}for(i=d.right(d.leftEnd);i!=d.rightEnd;i=d.right(i))b(i.edge)}function fG(){return{leaf:!0,nodes:[],point:null}}function fH(a,b,c,d,e,f){if(!a(b,c,d,e,f)){var g=(c+e)*.5,h=(d+f)*.5,i=b.nodes;i[0]&&fH(a,i[0],c,d,g,h),i[1]&&fH(a,i[1],g,d,e,h),i[2]&&fH(a,i[2],c,h,g,f),i[3]&&fH(a,i[3],g,h,e,f)}}function fI(a){return{x:a[0],y:a[1]}}function fL(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function fU(a){return a.substring(0,3)}function fV(a,b,c,d){var e,f,g=0,h=b.length,i=c.length;while(g=i)return-1;e=b.charCodeAt(g++);if(e==37){f=gh[b.charAt(g++)];if(!f||(d=f(a,c,d))<0)return-1}else if(e!=c.charCodeAt(d++))return-1}return d}function fW(a){return new RegExp("^(?:"+a.map(d3.requote).join("|")+")","i")}function fX(a){var b=new j,c=-1,d=a.length;while(++c68?1900:2e3)}function gs(a,b,c){gy.lastIndex=0;var d=gy.exec(b.substring(c,c+2));return d?(a.m=d[0]-1,c+=d[0].length):-1}function gt(a,b,c){gy.lastIndex=0;var d=gy.exec(b.substring(c,c+2));return d?(a.d=+d[0],c+=d[0].length):-1}function gu(a,b,c){gy.lastIndex=0;var d=gy.exec(b.substring(c,c+2));return d?(a.H=+d[0],c+=d[0].length):-1}function gv(a,b,c){gy.lastIndex=0;var d=gy.exec(b.substring(c,c+2));return d?(a.M=+d[0],c+=d[0].length):-1}function gw(a,b,c){gy.lastIndex=0;var d=gy.exec(b.substring(c,c+2));return d?(a.S=+d[0],c+=d[0].length):-1}function gx(a,b,c){gy.lastIndex=0;var d=gy.exec(b.substring(c,c+3));return d?(a.L=+d[0],c+=d[0].length):-1}function gz(a,b,c){var d=gA.get(b.substring(c,c+=2).toLowerCase());return d==null?-1:(a.p=d,c)}function gB(a){var b=a.getTimezoneOffset(),c=b>0?"-":"+",d=~~(Math.abs(b)/60),e=Math.abs(b)%60;return c+fY(d)+fY(e)}function gD(a){return a.toISOString()}function gE(a,b,c){function d(b){var c=a(b),d=f(c,1);return b-c1)while(gb?1:a>=b?0:NaN},d3.descending=function(a,b){return ba?1:b>=a?0:NaN},d3.mean=function(a,b){var c=a.length,d,e=0,f=-1,g=0;if(arguments.length===1)while(++f1&&(a=a.map(b)),a=a.filter(r),a.length?d3.quantile(a.sort(d3.ascending),.5):undefined},d3.min=function(a,b){var c=-1,d=a.length,e,f;if(arguments.length===1){while(++cf&&(e=f)}else{while(++cf&&(e=f)}return e},d3.max=function(a,b){var c=-1,d=a.length,e,f;if(arguments.length===1){while(++ce&&(e=f)}else{while(++ce&&(e=f)}return e},d3.extent=function(a,b){var c=-1,d=a.length,e,f,g;if(arguments.length===1){while(++cf&&(e=f),gf&&(e=f),g1);return a+b*c*Math.sqrt(-2*Math.log(e)/e)}},logNormal:function(a,b){var c=arguments.length;c<2&&(b=1),c<1&&(a=0);var d=d3.random.normal();return function(){return Math.exp(a+b*d())}},irwinHall:function(a){return function(){for(var b=0,c=0;c>>1;a.call(b,b[f],f)>>1;c0&&(e=f);return e},d3.last=function(a,b){var c=0,d=a.length,e=a[0],f;arguments.length===1&&(b=d3.ascending);while(++c=b.length)return e?e.call(a,c):d?c.sort(d):c;var h=-1,i=c.length,k=b[g++],l,m,n=new j,o,p={};while(++h=b.length)return a;var e=[],f=c[d++],h;for(h in a)e.push({key:h,values:g(a[h],d)});return f&&e.sort(function(a,b){return f(a.key,b.key)}),e}var a={},b=[],c=[],d,e;return a.map=function(a){return f(a,0)},a.entries=function(a){return g(f(a,0),0)},a.key=function(c){return b.push(c),a},a.sortKeys=function(d){return c[b.length-1]=d,a},a.sortValues=function(b){return d=b,a},a.rollup=function(b){return e=b,a},a},d3.keys=function(a){var b=[];for(var c in a)b.push(c);return b},d3.values=function(a){var b=[];for(var c in a)b.push(a[c]);return b},d3.entries=function(a){var b=[];for(var c in a)b.push({key:c,value:a[c]});return b},d3.permute=function(a,b){var c=[],d=-1,e=b.length;while(++db)d.push(g/e);else while((g=a+c*++f)=200&&a<300||a===304?d:null)}},d.send(null)},d3.text=function(a,b,c){function d(a){c(a&&a.responseText)}arguments.length<3&&(c=b,b=null),d3.xhr(a,b,d)},d3.json=function(a,b){d3.text(a,"application/json",function(a){b(a?JSON.parse(a):null)})},d3.html=function(a,b){d3.text(a,"text/html",function(a){if(a!=null){var c=document.createRange();c.selectNode(document.body),a=c.createContextualFragment(a)}b(a)})},d3.xml=function(a,b,c){function d(a){c(a&&a.responseXML)}arguments.length<3&&(c=b,b=null),d3.xhr(a,b,d)};var y={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};d3.ns={prefix:y,qualify:function(a){var b=a.indexOf(":"),c=a;return b>=0&&(c=a.substring(0,b),a=a.substring(b+1)),y.hasOwnProperty(c)?{space:y[c],local:a}:a}},d3.dispatch=function(){var a=new z,b=-1,c=arguments.length;while(++b0&&(d=a.substring(c+1),a=a.substring(0,c)),arguments.length<2?this[a].on(d):this[a].on(d,b)},d3.format=function(a){var b=B.exec(a),c=b[1]||" ",d=b[3]||"",e=b[5],f=+b[6],g=b[7],h=b[8],i=b[9],j=1,k="",l=!1;h&&(h=+h.substring(1)),e&&(c="0",g&&(f-=Math.floor((f-1)/4)));switch(i){case"n":g=!0,i="g";break;case"%":j=100,k="%",i="f";break;case"p":j=100,k="%",i="r";break;case"d":l=!0,h=0;break;case"s":j=-1,i="r"}return i=="r"&&!h&&(i="g"),i=C.get(i)||E,function(a){if(l&&a%1)return"";var b=a<0&&(a=-a)?"-":d;if(j<0){var m=d3.formatPrefix(a,h);a=m.scale(a),k=m.symbol}else a*=j;a=i(a,h);if(e){var n=a.length+b.length;n=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/,C=d3.map({g:function(a,b){return a.toPrecision(b)},e:function(a,b){return a.toExponential(b)},f:function(a,b){return a.toFixed(b)},r:function(a,b){return d3.round(a,b=D(a,b)).toFixed(Math.max(0,Math.min(20,b)))}}),G=["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(H);d3.formatPrefix=function(a,b){var c=0;return a&&(a<0&&(a*=-1),b&&(a=d3.round(a,D(a,b))),c=1+Math.floor(1e-12+Math.log(a)/Math.LN10),c=Math.max(-24,Math.min(24,Math.floor((c<=0?c+1:c-1)/3)*3))),G[8+c/3]};var I=R(2),J=R(3),K=function(){return Q},L=d3.map({linear:K,poly:R,quad:function(){return I},cubic:function(){return J},sin:function(){return S},exp:function(){return T},circle:function(){return U},elastic:V,back:W,bounce:function(){return X}}),M=d3.map({"in":Q,out:O,"in-out":P,"out-in":function(a){return P(O(a))}});d3.ease=function(a){var b=a.indexOf("-"),c=b>=0?a.substring(0,b):a,d=b>=0?a.substring(b+1):"in";return c=L.get(c)||K,d=M.get(d)||Q,N(d(c.apply(null,Array.prototype.slice.call(arguments,1))))},d3.event=null,d3.transform=function(a){var b=document.createElementNS(d3.ns.prefix.svg,"g");return(d3.transform=function(a){b.setAttribute("transform",a);var c=b.transform.baseVal.consolidate();return new _(c?c.matrix:be)})(a)},_.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var bd=180/Math.PI,be={a:1,b:0,c:0,d:1,e:0,f:0};d3.interpolate=function(a,b){var c=d3.interpolators.length,d;while(--c>=0&&!(d=d3.interpolators[c](a,b)));return d},d3.interpolateNumber=function(a,b){return b-=a,function(c){return a+b*c}},d3.interpolateRound=function(a,b){return b-=a,function(c){return Math.round(a+b*c)}},d3.interpolateString=function(a,b){var c,d,e,f=0,g=0,h=[],i=[],j,k;bf.lastIndex=0;for(d=0;c=bf.exec(b);++d)c.index&&h.push(b.substring(f,g=c.index)),i.push({i:h.length,x:c[0]}),h.push(null),f=bf.lastIndex;f180?k+=360:k-j>180&&(j+=360),d.push({i:c.push(c.pop()+"rotate(",null,")")-2,x:d3.interpolateNumber(j,k)})):k&&c.push(c.pop()+"rotate("+k+")"),l!=m?d.push({i:c.push(c.pop()+"skewX(",null,")")-2,x:d3.interpolateNumber(l,m)}):m&&c.push(c.pop()+"skewX("+m+")"),n[0]!=o[0]||n[1]!=o[1]?(e=c.push(c.pop()+"scale(",null,",",null,")"),d.push({i:e-4,x:d3.interpolateNumber(n[0],o[0])},{i:e-2,x:d3.interpolateNumber(n[1],o[1])})):(o[0]!=1||o[1]!=1)&&c.push(c.pop()+"scale("+o+")"),e=d.length,function(a){var b=-1,f;while(++b180?f-=360:f<-180&&(f+=360),function(a){return bu(c+f*a,d+g*a,e+h*a)+""}},d3.interpolateLab=function(a,b){a=d3.lab(a),b=d3.lab(b);var c=a.l,d=a.a,e=a.b,f=b.l-c,g=b.a-d,h=b.b-e;return function(a){return bE(c+f*a,d+g*a,e+h*a)+""}},d3.interpolateHcl=function(a,b){a=d3.hcl(a),b=d3.hcl(b);var c=a.h,d=a.c,e=a.l,f=b.h-c,g=b.c-d,h=b.l-e;return f>180?f-=360:f<-180&&(f+=360),function(a){return bx(c+f*a,d+g*a,e+h*a)+""}},d3.interpolateArray=function(a,b){var c=[],d=[],e=a.length,f=b.length,g=Math.min(a.length,b.length),h;for(h=0;h=0;)if(f=c[d])e&&e!==f.nextSibling&&e.parentNode.insertBefore(f,e),e=f;return this},bP.sort=function(a){a=b$.apply(this,arguments);for(var b=-1,c=this.length;++b=db?e?"M0,"+f+"A"+f+","+f+" 0 1,1 0,"+ -f+"A"+f+","+f+" 0 1,1 0,"+f+"M0,"+e+"A"+e+","+e+" 0 1,0 0,"+ -e+"A"+e+","+e+" 0 1,0 0,"+e+"Z":"M0,"+f+"A"+f+","+f+" 0 1,1 0,"+ -f+"A"+f+","+f+" 0 1,1 0,"+f+"Z":e?"M"+f*k+","+f*l+"A"+f+","+f+" 0 "+j+",1 "+f*m+","+f*n+"L"+e*m+","+e*n+"A"+e+","+e+" 0 "+j+",0 "+e*k+","+e*l+"Z":"M"+f*k+","+f*l+"A"+f+","+f+" 0 "+j+",1 "+f*m+","+f*n+"L0,0"+"Z"}var a=dc,b=dd,c=de,d=df;return e.innerRadius=function(b){return arguments.length?(a=p(b),e):a},e.outerRadius=function(a){return arguments.length?(b=p(a),e):b},e.startAngle=function(a){return arguments.length?(c=p(a),e):c},e.endAngle=function(a){return arguments.length?(d=p(a),e):d},e.centroid=function(){var e=(a.apply(this,arguments)+b.apply(this,arguments))/2,f=(c.apply(this,arguments)+d.apply(this,arguments))/2+da;return[Math.cos(f)*e,Math.sin(f)*e]},e};var da=-Math.PI/2,db=2*Math.PI-1e-6;d3.svg.line=function(){return dg(m)};var dj=d3.map({linear:dk,"linear-closed":dl,"step-before":dm,"step-after":dn,basis:du,"basis-open":dv,"basis-closed":dw,bundle:dx,cardinal:dr,"cardinal-open":dp,"cardinal-closed":dq,monotone:dG});dj.forEach(function(a,b){b.key=a,b.closed=/-closed$/.test(a)});var dz=[0,2/3,1/3,0],dA=[0,1/3,2/3,0],dB=[0,1/6,2/3,1/6];d3.svg.line.radial=function(){var a=dg(dH);return a.radius=a.x,delete a.x,a.angle=a.y,delete a.y,a},dm.reverse=dn,dn.reverse=dm,d3.svg.area=function(){return dI(m)},d3.svg.area.radial=function(){var a=dI(dH);return a.radius=a.x,delete a.x,a.innerRadius=a.x0,delete a.x0,a.outerRadius=a.x1,delete a.x1,a.angle=a.y,delete a.y,a.startAngle=a.y0,delete a.y0,a.endAngle=a.y1,delete a.y1,a},d3.svg.chord=function(){function f(c,d){var e=g(this,a,c,d),f=g(this,b,c,d);return"M"+e.p0+i(e.r,e.p1,e.a1-e.a0)+(h(e,f)?j(e.r,e.p1,e.r,e.p0):j(e.r,e.p1,f.r,f.p0)+i(f.r,f.p1,f.a1-f.a0)+j(f.r,f.p1,e.r,e.p0))+"Z"}function g(a,b,f,g){var h=b.call(a,f,g),i=c.call(a,h,g),j=d.call(a,h,g)+da,k=e.call(a,h,g)+da;return{r:i,a0:j,a1:k,p0:[i*Math.cos(j),i*Math.sin(j)],p1:[i*Math.cos(k),i*Math.sin(k)]}}function h(a,b){return a.a0==b.a0&&a.a1==b.a1}function i(a,b,c){return"A"+a+","+a+" 0 "+ +(c>Math.PI)+",1 "+b}function j(a,b,c,d){return"Q 0,0 "+d}var a=dJ,b=dK,c=dL,d=de,e=df;return f.radius=function(a){return arguments.length?(c=p(a),f):c},f.source=function(b){return arguments.length?(a=p(b),f):a},f.target=function(a){return arguments.length?(b=p(a),f):b},f.startAngle=function(a){return arguments.length?(d=p(a),f):d},f.endAngle=function(a){return arguments.length?(e=p(a),f):e},f},d3.svg.diagonal=function(){function d(d,e){var f=a.call(this,d,e),g=b.call(this,d,e),h=(f.y+g.y)/2,i=[f,{x:f.x,y:h},{x:g.x,y:h},g];return i=i.map(c),"M"+i[0]+"C"+i[1]+" "+i[2]+" "+i[3]}var a=dJ,b=dK,c=dO;return d.source=function(b){return arguments.length?(a=p(b),d):a},d.target=function(a){return arguments.length?(b=p(a),d):b},d.projection=function(a){return arguments.length?(c=a,d):c},d},d3.svg.diagonal.radial=function(){var a=d3.svg.diagonal(),b=dO,c=a.projection;return a.projection=function(a){return arguments.length?c(dP(b=a)):b},a},d3.svg.mouse=d3.mouse,d3.svg.touches=d3.touches,d3.svg.symbol=function(){function c(c,d){return(dT.get(a.call(this,c,d))||dS)(b.call(this,c,d))}var a=dR,b=dQ;return c.type=function(b){return arguments.length?(a=p(b),c):a},c.size=function(a){return arguments.length?(b=p(a),c):b},c};var dT=d3.map({circle:dS,cross:function(a){var b=Math.sqrt(a/5)/2;return"M"+ -3*b+","+ -b+"H"+ -b+"V"+ -3*b+"H"+b+"V"+ -b+"H"+3*b+"V"+b+"H"+b+"V"+3*b+"H"+ -b+"V"+b+"H"+ -3*b+"Z"},diamond:function(a){var b=Math.sqrt(a/(2*dV)),c=b*dV;return"M0,"+ -b+"L"+c+",0"+" 0,"+b+" "+ -c+",0"+"Z"},square:function(a){var b=Math.sqrt(a)/2;return"M"+ -b+","+ -b+"L"+b+","+ -b+" "+b+","+b+" "+ -b+","+b+"Z"},"triangle-down":function(a){var b=Math.sqrt(a/dU),c=b*dU/2;return"M0,"+c+"L"+b+","+ -c+" "+ -b+","+ -c+"Z"},"triangle-up":function(a){var b=Math.sqrt(a/dU),c=b*dU/2;return"M0,"+ -c+"L"+b+","+c+" "+ -b+","+c+"Z"}});d3.svg.symbolTypes=dT.keys();var dU=Math.sqrt(3),dV=Math.tan(30*Math.PI/180);d3.svg.axis=function(){function k(k){k.each(function(){var k=d3.select(this),l=h==null?a.ticks?a.ticks.apply(a,g):a.domain():h,m=i==null?a.tickFormat?a.tickFormat.apply(a,g):String:i,n=dY(a,l,j),o=k.selectAll(".minor").data(n,String),p=o.enter().insert("line","g").attr("class","tick minor").style("opacity",1e-6),q=d3.transition(o.exit()).style("opacity",1e-6).remove(),r=d3.transition(o).style("opacity",1),s=k.selectAll("g").data(l,String),t=s.enter().insert("g","path").style("opacity",1e-6),u=d3.transition(s.exit()).style("opacity",1e-6).remove(),v=d3.transition(s).style("opacity",1),w,x=cC(a),y=k.selectAll(".domain").data([0]),z=y.enter().append("path").attr("class","domain"),A=d3.transition(y),B=a.copy(),C=this.__chart__||B;this.__chart__=B,t.append("line").attr("class","tick"),t.append("text");var D=t.select("line"),E=v.select("line"),F=s.select("text").text(m),G=t.select("text"),H=v.select("text");switch(b){case"bottom":w=dW,p.attr("y2",d),r.attr("x2",0).attr("y2",d),D.attr("y2",c),G.attr("y",Math.max(c,0)+f),E.attr("x2",0).attr("y2",c),H.attr("x",0).attr("y",Math.max(c,0)+f),F.attr("dy",".71em").attr("text-anchor","middle"),A.attr("d","M"+x[0]+","+e+"V0H"+x[1]+"V"+e);break;case"top":w=dW,p.attr("y2",-d),r.attr("x2",0).attr("y2",-d),D.attr("y2",-c),G.attr("y",-(Math.max(c,0)+f)),E.attr("x2",0).attr("y2",-c),H.attr("x",0).attr("y",-(Math.max(c,0)+f)),F.attr("dy","0em").attr("text-anchor","middle"),A.attr("d","M"+x[0]+","+ -e+"V0H"+x[1]+"V"+ -e);break;case"left":w=dX,p.attr("x2",-d),r.attr("x2",-d).attr("y2",0),D.attr("x2",-c),G.attr("x",-(Math.max(c,0)+f)),E.attr("x2",-c).attr("y2",0),H.attr("x",-(Math.max(c,0)+f)).attr("y",0),F.attr("dy",".32em").attr("text-anchor","end"),A.attr("d","M"+ -e+","+x[0]+"H0V"+x[1]+"H"+ -e);break;case"right":w=dX,p.attr("x2",d),r.attr("x2",d).attr("y2",0),D.attr("x2",c),G.attr("x",Math.max(c,0)+f),E.attr("x2",c).attr("y2",0),H.attr("x",Math.max(c,0)+f).attr("y",0),F.attr("dy",".32em").attr("text-anchor","start"),A.attr("d","M"+e+","+x[0]+"H0V"+x[1]+"H"+e)}if(a.ticks)t.call(w,C),v.call(w,B),u.call(w,B),p.call(w,C),r.call(w,B),q.call(w,B);else{var I=B.rangeBand()/2,J=function(a){return B(a)+I};t.call(w,J),v.call(w,J)}})}var a=d3.scale.linear(),b="bottom",c=6,d=6,e=6,f=3,g=[10],h=null,i,j=0;return k.scale=function(b){return arguments.length?(a=b,k):a},k.orient=function(a){return arguments.length?(b=a,k):b},k.ticks=function(){return arguments.length?(g=arguments,k):g},k.tickValues=function(a){return arguments.length?(h=a,k):h},k.tickFormat=function(a){return arguments.length?(i=a,k):i},k.tickSize=function(a,b,f){if(!arguments.length)return c;var g=arguments.length-1;return c=+a,d=g>1?+b:c,e=g>0?+arguments[g]:c,k},k.tickPadding=function(a){return arguments.length?(f=+a,k):f},k.tickSubdivide=function(a){return arguments.length?(j=+a,k):j},k},d3.svg.brush=function(){function g(a){a.each(function(){var a=d3.select(this),e=a.selectAll(".background").data([0]),f=a.selectAll(".extent").data([0]),l=a.selectAll(".resize").data(d,String),m;a.style("pointer-events","all").on("mousedown.brush",k).on("touchstart.brush",k),e.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),f.enter().append("rect").attr("class","extent").style("cursor","move"),l.enter().append("g").attr("class",function(a){return"resize "+a}).style("cursor",function(a){return dZ[a]}).append("rect").attr("x",function(a){return/[ew]$/.test(a)?-3:null}).attr("y",function(a){return/^[ns]/.test(a)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),l.style("display",g.empty()?"none":null),l.exit().remove(),b&&(m=cC(b),e.attr("x",m[0]).attr("width",m[1]-m[0]),i(a)),c&&(m=cC(c),e.attr("y",m[0]).attr("height",m[1]-m[0]),j(a)),h(a)})}function h(a){a.selectAll(".resize").attr("transform",function(a){return"translate("+e[+/e$/.test(a)][0]+","+e[+/^s/.test(a)][1]+")"})}function i(a){a.select(".extent").attr("x",e[0][0]),a.selectAll(".extent,.n>rect,.s>rect").attr("width",e[1][0]-e[0][0])}function j(a){a.select(".extent").attr("y",e[0][1]),a.selectAll(".extent,.e>rect,.w>rect").attr("height",e[1][1]-e[0][1])}function k(){function x(){var a=d3.event.changedTouches;return a?d3.touches(d,a)[0]:d3.mouse(d)}function y(){d3.event.keyCode==32&&(q||(r=null,s[0]-=e[1][0],s[1]-=e[1][1],q=2),Y())}function z(){d3.event.keyCode==32&&q==2&&(s[0]+=e[1][0],s[1]+=e[1][1],q=0,Y())}function A(){var a=x(),d=!1;t&&(a[0]+=t[0],a[1]+=t[1]),q||(d3.event.altKey?(r||(r=[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]),s[0]=e[+(a[0]0?e=c:e=0:c>0&&(b.start({type:"start",alpha:e=c}),d3.timer(a.tick)),a):e},a.start=function(){function p(a,c){var d=t(b),e=-1,f=d.length,g;while(++ee&&(e=h),d.push(h)}for(g=0;g0){f=-1;while(++f=i[0]&&o<=i[1]&&(k=g[d3.bisect(j,o,1,m)-1],k.y+=n,k.push(e[f]))}return g}var a=!0,b=Number,c=eB,d=ez;return e.value=function(a){return arguments.length?(b=a,e):b},e.range=function(a){return arguments.length?(c=p(a),e):c},e.bins=function(a){return arguments.length?(d=typeof a=="number"?function(b){return eA(b,a)}:p(a),e):d},e.frequency=function(b){return arguments.length?(a=!!b,e):a},e},d3.layout.hierarchy=function(){function d(e,g,h){var i=b.call(f,e,g),j=eH?e:{data:e};j.depth=g,h.push(j);if(i&&(l=i.length)){var k=-1,l,m=j.children=[],n=0,o=g+1,p;while(++k0){var k=b*j/2;fa(g,function(a){a.r+=k}),fa(g,eM),fa(g,function(a){a.r-=k}),j=Math.max(2*g.r/h,2*g.r/i)}return eP(g,h/2,i/2,1/j),f}var a=d3.layout.hierarchy().sort(eI),b=0,c=[1,1];return d.size=function(a){return arguments.length?(c=a,d):c},d.padding=function(a){return arguments.length?(b=+a,d):b},eC(d,a)},d3.layout.cluster=function(){function d(d,e){var f=a.call(this,d,e),g=f[0],h,i=0,j,k;fa(g,function(a){var c=a.children;c&&c.length?(a.x=eS(c),a.y=eR(c)):(a.x=h?i+=b(a,h):0,a.y=0,h=a)});var l=eT(g),m=eU(g),n=l.x-b(l,m)/2,o=m.x+b(m,l)/2;return fa(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=(1-(g.y?a.y/g.y:1))*c[1]}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=eV,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},eC(d,a)},d3.layout.tree=function(){function d(d,e){function h(a,c){var d=a.children,e=a._tree;if(d&&(f=d.length)){var f,g=d[0],i,k=g,l,m=-1;while(++m0&&(fc(fd(g,a,d),a,m),i+=m,j+=m),k+=g._tree.mod,i+=e._tree.mod,l+=h._tree.mod,j+=f._tree.mod;g&&!eX(f)&&(f._tree.thread=g,f._tree.mod+=k-j),e&&!eW(h)&&(h._tree.thread=e,h._tree.mod+=i-l,d=a)}return d}var f=a.call(this,d,e),g=f[0];fa(g,function(a,b){a._tree={ancestor:a,prelim:0,mod:0,change:0,shift:0,number:b?b._tree.number+1:0}}),h(g),i(g,-g._tree.prelim);var k=eY(g,e$),l=eY(g,eZ),m=eY(g,e_),n=k.x-b(k,l)/2,o=l.x+b(l,k)/2,p=m.depth||1;return fa(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=a.depth/p*c[1],delete a._tree}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=eV,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},eC(d,a)},d3.layout.treemap=function(){function i(a,b){var c=-1,d=a.length,e,f;while(++c0)d.push(g=f[o-1]),d.area+=g.area,(k=l(d,n))<=h?(f.pop(),h=k):(d.area-=d.pop().area,m(d,n,c,!1),n=Math.min(c.dx,c.dy),d.length=d.area=0,h=Infinity);d.length&&(m(d,n,c,!0),d.length=d.area=0),b.forEach(j)}}function k(a){var b=a.children;if(b&&b.length){var c=e(a),d=b.slice(),f,g=[];i(d,c.dx*c.dy/a.value),g.area=0;while(f=d.pop())g.push(f),g.area+=f.area,f.z!=null&&(m(g,f.z?c.dx:c.dy,c,!d.length),g.length=g.area=0);b.forEach(k)}}function l(a,b){var c=a.area,d,e=0,f=Infinity,g=-1,i=a.length;while(++ge&&(e=d)}return c*=c,b*=b,c?Math.max(b*e*h/c,c/(b*f*h)):Infinity}function m(a,c,d,e){var f=-1,g=a.length,h=d.x,i=d.y,j=c?b(a.area/c):0,k;if(c==d.dx){if(e||j>d.dy)j=d.dy;while(++fd.dx)j=d.dx;while(++f50?b:f<-140?c:g<21?d:a)(e)}var a=d3.geo.albers(),b=d3.geo.albers().origin([-160,60]).parallels([55,65]),c=d3.geo.albers().origin([-160,20]).parallels([8,18]),d=d3.geo.albers().origin([-60,10]).parallels([8,18]);return e.scale=function(f){return arguments.length?(a.scale(f),b.scale(f*.6),c.scale(f),d.scale(f*1.5),e.translate(a.translate())):a.scale()},e.translate=function(f){if(!arguments.length)return a.translate();var g=a.scale()/1e3,h=f[0],i=f[1];return a.translate(f),b.translate([h-400*g,i+170*g]),c.translate([h-190*g,i+200*g]),d.translate([h+580*g,i+430*g]),e},e.scale(a.scale())},d3.geo.bonne=function(){function g(g){var h=g[0]*fh-c,i=g[1]*fh-d;if(e){var j=f+e-i,k=h*Math.cos(i)/j;h=j*Math.sin(k),i=j*Math.cos(k)-f}else h*=Math.cos(i),i*=-1;return[a*h+b[0],a*i+b[1]]}var a=200,b=[480,250],c,d,e,f;return g.invert=function(d){var g=(d[0]-b[0])/a,h=(d[1]-b[1])/a;if(e){var i=f+h,j=Math.sqrt(g*g+i*i);h=f+e-j,g=c+j*Math.atan2(g,i)/Math.cos(h)}else h*=-1,g/=Math.cos(h);return[g/fh,h/fh]},g.parallel=function(a){return arguments.length?(f=1/ -Math.tan(e=a*fh),g):e/fh},g.origin=function(a){return arguments.length?(c=a[0]*fh,d=a[1]*fh,g):[c/fh,d/fh]},g.scale=function(b){return arguments.length?(a=+b,g):a},g.translate=function(a){return arguments.length?(b=[+a[0],+a[1]],g):b},g.origin([0,0]).parallel(45)},d3.geo.equirectangular=function(){function c(c){var d=c[0]/360,e=-c[1]/360;return[a*d+b[0],a*e+b[1]]}var a=500,b=[480,250];return c.invert=function(c){var d=(c[0]-b[0])/a,e=(c[1]-b[1])/a;return[360*d,-360*e]},c.scale=function(b){return arguments.length?(a=+b,c):a},c.translate=function(a){return arguments.length?(b=[+a[0],+a[1]],c):b},c},d3.geo.mercator=function(){function c(c){var d=c[0]/360,e=-(Math.log(Math.tan(Math.PI/4+c[1]*fh/2))/fh)/360;return[a*d+b[0],a*Math.max(-0.5,Math.min(.5,e))+b[1]]}var a=500,b=[480,250];return c.invert=function(c){var d=(c[0]-b[0])/a,e=(c[1]-b[1])/a;return[360*d,2*Math.atan(Math.exp(-360*e*fh))/fh-90]},c.scale=function(b){return arguments.length?(a=+b,c):a},c.translate=function(a){return arguments.length?(b=[+a[0],+a[1]],c):b},c},d3.geo.path=function(){function e(c,e){typeof a=="function"&&(b=fj(a.apply(this,arguments))),g(c);var f=d.length?d.join(""):null;return d=[],f}function f(a){return c(a).join(",")}function i(a){var b=l(a[0]),c=0,d=a.length;while(++c0){d.push("M");while(++h0){d.push("M");while(++kd&&(d=a),fe&&(e=f)}),[[b,c],[d,e]]};var fl={Feature:fm,FeatureCollection:fn,GeometryCollection:fo,LineString:fp,MultiLineString:fq,MultiPoint:fp,MultiPolygon:fr,Point:fs,Polygon:ft};d3.geo.circle=function(){function e(){}function f(a){return d.distance(a)=k*k+l*l?d[f].index=-1:(d[m].index=-1,o=d[f].angle,m=f,n=g)):(o=d[f].angle,m=f,n=g);e.push(h);for(f=0,g=0;f<2;++g)d[g].index!==-1&&(e.push(d[g].index),f++);p=e.length;for(;g=0?(c=a.ep.r,d=a.ep.l):(c=a.ep.l,d=a.ep.r),a.a===1?(g=c?c.y:-1e6,e=a.c-a.b*g,h=d?d.y:1e6,f=a.c-a.b*h):(e=c?c.x:-1e6,g=a.c-a.a*e,f=d?d.x:1e6,h=a.c-a.a*f);var i=[e,g],j=[f,h];b[a.region.l.index].push(i,j),b[a.region.r.index].push(i,j)}),b.map(function(b,c){var d=a[c][0],e=a[c][1];return b.forEach(function(a){a.angle=Math.atan2(a[0]-d,a[1]-e)}),b.sort(function(a,b){return a.angle-b.angle}).filter(function(a,c){return!c||a.angle-b[c-1].angle>1e-10})})};var fE={l:"r",r:"l"};d3.geom.delaunay=function(a){var b=a.map(function(){return[]}),c=[];return fF(a,function(c){b[c.region.l.index].push(a[c.region.r.index])}),b.forEach(function(b,d){var e=a[d],f=e[0],g=e[1];b.forEach(function(a){a.angle=Math.atan2(a[0]-f,a[1]-g)}),b.sort(function(a,b){return a.angle-b.angle});for(var h=0,i=b.length-1;h=g,j=b.y>=h,l=(j<<1)+i;a.leaf=!1,a=a.nodes[l]||(a.nodes[l]=fG()),i?c=g:e=g,j?d=h:f=h,k(a,b,c,d,e,f)}var f,g=-1,h=a.length;h&&isNaN(a[0].x)&&(a=a.map(fI));if(arguments.length<5)if(arguments.length===3)e=d=c,c=b;else{b=c=Infinity,d=e=-Infinity;while(++gd&&(d=f.x),f.y>e&&(e=f.y);var i=d-b,j=e-c;i>j?e=c+i:d=b+j}var m=fG();return m.add=function(a){k(m,a,b,c,d,e)},m.visit=function(a){fH(a,m,b,c,d,e)},a.forEach(m.add),m},d3.time={};var fJ=Date,fK=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];fL.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){fM.setUTCDate.apply(this._,arguments)},setDay:function(){fM.setUTCDay.apply(this._,arguments)},setFullYear:function(){fM.setUTCFullYear.apply(this._,arguments)},setHours:function(){fM.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){fM.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){fM.setUTCMinutes.apply(this._,arguments)},setMonth:function(){fM.setUTCMonth.apply(this._,arguments)},setSeconds:function(){fM.setUTCSeconds.apply(this._,arguments)},setTime:function(){fM.setTime.apply(this._,arguments)}};var fM=Date.prototype,fN="%a %b %e %H:%M:%S %Y",fO="%m/%d/%y",fP="%H:%M:%S",fQ=fK,fR=fQ.map(fU),fS=["January","February","March","April","May","June","July","August","September","October","November","December"],fT=fS.map(fU);d3.time.format=function(a){function c(c){var d=[],e=-1,f=0,g,h;while(++e=12?"PM":"AM"},S:function(a){return fY(a.getSeconds())},U:function(a){return fY(d3.time.sundayOfYear(a))},w:function(a){return a.getDay()},W:function(a){return fY(d3.time.mondayOfYear(a))},x:d3.time.format(fO),X:d3.time.format(fP),y:function(a){return fY(a.getFullYear()%100)},Y:function(a){return f$(a.getFullYear()%1e4)},Z:gB,"%":function(a){return"%"}},gh={a:gi,A:gj,b:gk,B:gl,c:gm,d:gt,e:gt,H:gu,I:gu,L:gx,m:gs,M:gv,p:gz,S:gw,x:gn,X:go,y:gq,Y:gp},gy=/^\s*\d+/,gA=d3.map({am:0,pm:1});d3.time.format.utc=function(a){function c(a){try{fJ=fL;var c=new fJ;return c._=a,b(c)}finally{fJ=Date}}var b=d3.time.format(a);return c.parse=function(a){try{fJ=fL;var c=b.parse(a);return c&&c._}finally{fJ=Date}},c.toString=b.toString,c};var gC=d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");d3.time.format.iso=Date.prototype.toISOString?gD:gC,gD.parse=function(a){var b=new Date(a);return isNaN(b)?null:b},gD.toString=gC.toString,d3.time.second=gE(function(a){return new fJ(Math.floor(a/1e3)*1e3)},function(a,b){a.setTime(a.getTime()+Math.floor(b)*1e3)},function(a){return a.getSeconds()}),d3.time.seconds=d3.time.second.range,d3.time.seconds.utc=d3.time.second.utc.range,d3.time.minute=gE(function(a){return new fJ(Math.floor(a/6e4)*6e4)},function(a,b){a.setTime(a.getTime()+Math.floor(b)*6e4)},function(a){return a.getMinutes()}),d3.time.minutes=d3.time.minute.range,d3.time.minutes.utc=d3.time.minute.utc.range,d3.time.hour=gE(function(a){var b=a.getTimezoneOffset()/60;return new fJ((Math.floor(a/36e5-b)+b)*36e5)},function(a,b){a.setTime(a.getTime()+Math.floor(b)*36e5)},function(a){return a.getHours()}),d3.time.hours=d3.time.hour.range,d3.time.hours.utc=d3.time.hour.utc.range,d3.time.day=gE(function(a){var b=new fJ(0,a.getMonth(),a.getDate());return b.setFullYear(a.getFullYear()),b},function(a,b){a.setDate(a.getDate()+b)},function(a){return a.getDate()-1}),d3.time.days=d3.time.day.range,d3.time.days.utc=d3.time.day.utc.range,d3.time.dayOfYear=function(a){var b=d3.time.year(a);return Math.floor((a-b-(a.getTimezoneOffset()-b.getTimezoneOffset())*6e4)/864e5)},fK.forEach(function(a,b){a=a.toLowerCase(),b=7-b;var c=d3.time[a]=gE(function(a){return(a=d3.time.day(a)).setDate(a.getDate()-(a.getDay()+b)%7),a},function(a,b){a.setDate(a.getDate()+Math.floor(b)*7)},function(a){var c=d3.time.year(a).getDay();return Math.floor((d3.time.dayOfYear(a)+(c+b)%7)/7)-(c!==b)});d3.time[a+"s"]=c.range,d3.time[a+"s"].utc=c.utc.range,d3.time[a+"OfYear"]=function(a){var c=d3.time.year(a).getDay();return Math.floor((d3.time.dayOfYear(a)+(c+b)%7)/7)}}),d3.time.week=d3.time.sunday,d3.time.weeks=d3.time.sunday.range,d3.time.weeks.utc=d3.time.sunday.utc.range,d3.time.weekOfYear=d3.time.sundayOfYear,d3.time.month=gE(function(a){return a=d3.time.day(a),a.setDate(1),a},function(a,b){a.setMonth(a.getMonth()+b)},function(a){return a.getMonth()}),d3.time.months=d3.time.month.range,d3.time.months.utc=d3.time.month.utc.range,d3.time.year=gE(function(a){return a=d3.time.day(a),a.setMonth(0,1),a},function(a,b){a.setFullYear(a.getFullYear()+b)},function(a){return a.getFullYear()}),d3.time.years=d3.time.year.range,d3.time.years.utc=d3.time.year.utc.range;var gM=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],gN=[[d3.time.second,1],[d3.time.second,5],[d3.time.second,15],[d3.time.second,30],[d3.time.minute,1],[d3.time.minute,5],[d3.time.minute,15],[d3.time.minute,30],[d3.time.hour,1],[d3.time.hour,3],[d3.time.hour,6],[d3.time.hour,12],[d3.time.day,1],[d3.time.day,2],[d3.time.week,1],[d3.time.month,1],[d3.time.month,3],[d3.time.year,1]],gO=[[d3.time.format("%Y"),function(a){return!0}],[d3.time.format("%B"),function(a){return a.getMonth()}],[d3.time.format("%b %d"),function(a){return a.getDate()!=1}],[d3.time.format("%a %d"),function(a){return a.getDay()&&a.getDate()!=1}],[d3.time.format("%I %p"),function(a){return a.getHours()}],[d3.time.format("%I:%M"),function(a){return a.getMinutes()}],[d3.time.format(":%S"),function(a){return a.getSeconds()}],[d3.time.format(".%L"),function(a){return a.getMilliseconds()}]],gP=d3.scale.linear(),gQ=gJ(gO);gN.year=function(a,b){return gP.domain(a.map(gL)).ticks(b).map(gK)},d3.time.scale=function(){return gG(d3.scale.linear(),gN,gQ)};var gR=gN.map(function(a){return[a[0].utc,a[1]]}),gS=[[d3.time.format.utc("%Y"),function(a){return!0}],[d3.time.format.utc("%B"),function(a){return a.getUTCMonth()}],[d3.time.format.utc("%b %d"),function(a){return a.getUTCDate()!=1}],[d3.time.format.utc("%a %d"),function(a){return a.getUTCDay()&&a.getUTCDate()!=1}],[d3.time.format.utc("%I %p"),function(a){return a.getUTCHours()}],[d3.time.format.utc("%I:%M"),function(a){return a.getUTCMinutes()}],[d3.time.format.utc(":%S"),function(a){return a.getUTCSeconds()}],[d3.time.format.utc(".%L"),function(a){return a.getUTCMilliseconds()}]],gT=gJ(gS);gR.year=function(a,b){return gP.domain(a.map(gV)).ticks(b).map(gU)},d3.time.scale.utc=function(){return gG(d3.scale.linear(),gR,gT)}})(); \ No newline at end of file diff --git a/templates/project/assets/javascripts/rickshaw-1.4.3.min.js b/templates/project/assets/javascripts/rickshaw-1.4.3.min.js new file mode 100644 index 0000000..fac600f --- /dev/null +++ b/templates/project/assets/javascripts/rickshaw-1.4.3.min.js @@ -0,0 +1,2 @@ +var Rickshaw={namespace:function(namespace,obj){var parts=namespace.split(".");var parent=Rickshaw;for(var i=1,length=parts.length;i=3){if(s.data[2].xthis.window.xMax)isInRange=false;return isInRange}return true};this.onUpdate=function(callback){this.updateCallbacks.push(callback)};this.registerRenderer=function(renderer){this._renderers=this._renderers||{};this._renderers[renderer.name]=renderer};this.configure=function(args){if(args.width||args.height){this.setSize(args)}Rickshaw.keys(this.defaults).forEach(function(k){this[k]=k in args?args[k]:k in this?this[k]:this.defaults[k]},this);this.setRenderer(args.renderer||this.renderer.name,args)};this.setRenderer=function(r,args){if(typeof r=="function"){this.renderer=new r({graph:self});this.registerRenderer(this.renderer)}else{if(!this._renderers[r]){throw"couldn't find renderer "+r}this.renderer=this._renderers[r]}if(typeof args=="object"){this.renderer.configure(args)}};this.setSize=function(args){args=args||{};if(typeof window!==undefined){var style=window.getComputedStyle(this.element,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);var elementHeight=parseInt(style.getPropertyValue("height"),10)}this.width=args.width||elementWidth||400;this.height=args.height||elementHeight||250;this.vis&&this.vis.attr("width",this.width).attr("height",this.height)};this.initialize(args)};Rickshaw.namespace("Rickshaw.Fixtures.Color");Rickshaw.Fixtures.Color=function(){this.schemes={};this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse();this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"];this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"];this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse();this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"};this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse();this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"];this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]};Rickshaw.namespace("Rickshaw.Fixtures.RandomData");Rickshaw.Fixtures.RandomData=function(timeInterval){var addData;timeInterval=timeInterval||1;var lastRandomValue=200;var timeBase=Math.floor((new Date).getTime()/1e3);this.addData=function(data){var randomValue=Math.random()*100+15+lastRandomValue;var index=data[0].length;var counter=1;data.forEach(function(series){var randomVariance=Math.random()*20;var v=randomValue/25+counter++ +(Math.cos(index*counter*11/960)+2)*15+(Math.cos(index/7)+2)*7+(Math.cos(index/17)+2)*1;series.push({x:index*timeInterval+timeBase,y:v+randomVariance})});lastRandomValue=randomValue*.85};this.removeData=function(data){data.forEach(function(series){series.shift()});timeBase+=timeInterval}};Rickshaw.namespace("Rickshaw.Fixtures.Time");Rickshaw.Fixtures.Time=function(){var tzOffset=(new Date).getTimezoneOffset()*60;var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getUTCFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getUTCFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getUTCMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getUTCDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getUTCSeconds()+"s"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toUTCString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var nearFuture;var rounded;if(unit.name=="month"){nearFuture=new Date((time+unit.seconds-1)*1e3);rounded=new Date(0);rounded.setUTCFullYear(nearFuture.getUTCFullYear());rounded.setUTCMonth(nearFuture.getUTCMonth());rounded.setUTCDate(1);rounded.setUTCHours(0);rounded.setUTCMinutes(0);rounded.setUTCSeconds(0);rounded.setUTCMilliseconds(0);return rounded.getTime()/1e3}if(unit.name=="year"){nearFuture=new Date((time+unit.seconds-1)*1e3);rounded=new Date(0);rounded.setUTCFullYear(nearFuture.getUTCFullYear());rounded.setUTCMonth(0);rounded.setUTCDate(1);rounded.setUTCHours(0);rounded.setUTCMinutes(0);rounded.setUTCSeconds(0);rounded.setUTCMilliseconds(0);return rounded.getTime()/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Time.Local");Rickshaw.Fixtures.Time.Local=function(){var tzOffset=(new Date).getTimezoneOffset()*60;var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getSeconds()+"s"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var nearFuture;var rounded;if(unit.name=="day"){nearFuture=new Date((time+unit.seconds-1)*1e3);rounded=new Date(0);rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(nearFuture.getDate());rounded.setMonth(nearFuture.getMonth());rounded.setFullYear(nearFuture.getFullYear());return rounded.getTime()/1e3}if(unit.name=="month"){nearFuture=new Date((time+unit.seconds-1)*1e3);rounded=new Date(0);rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(1);rounded.setMonth(nearFuture.getMonth());rounded.setFullYear(nearFuture.getFullYear());return rounded.getTime()/1e3}if(unit.name=="year"){nearFuture=new Date((time+unit.seconds-1)*1e3);rounded=new Date(0);rounded.setFullYear(nearFuture.getFullYear());rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(1);rounded.setMonth(0);return rounded.getTime()/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Number");Rickshaw.Fixtures.Number.formatKMBT=function(y){var abs_y=Math.abs(y);if(abs_y>=1e12){return y/1e12+"T"}else if(abs_y>=1e9){return y/1e9+"B"}else if(abs_y>=1e6){return y/1e6+"M"}else if(abs_y>=1e3){return y/1e3+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(y){var abs_y=Math.abs(y);if(abs_y>=0x4000000000000){return y/0x4000000000000+"P"}else if(abs_y>=1099511627776){return y/1099511627776+"T"}else if(abs_y>=1073741824){return y/1073741824+"G"}else if(abs_y>=1048576){return y/1048576+"M"}else if(abs_y>=1024){return y/1024+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.namespace("Rickshaw.Color.Palette");Rickshaw.Color.Palette=function(args){var color=new Rickshaw.Fixtures.Color;args=args||{};this.schemes={};this.scheme=color.schemes[args.scheme]||args.scheme||color.schemes.colorwheel;this.runningIndex=0;this.generatorIndex=0;if(args.interpolatedStopCount){var schemeCount=this.scheme.length-1;var i,j,scheme=[];for(i=0;iself.graph.x.range()[1]){if(annotation.element){annotation.line.classList.add("offscreen");annotation.element.style.display="none"}annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.add("offscreen")});return}if(!annotation.element){var element=annotation.element=document.createElement("div");element.classList.add("annotation");this.elements.timeline.appendChild(element);element.addEventListener("click",function(e){element.classList.toggle("active");annotation.line.classList.toggle("active");annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.toggle("active")})},false)}annotation.element.style.left=left+"px";annotation.element.style.display="block";annotation.boxes.forEach(function(box){var element=box.element;if(!element){element=box.element=document.createElement("div");element.classList.add("content");element.innerHTML=box.content;annotation.element.appendChild(element);annotation.line=document.createElement("div");annotation.line.classList.add("annotation_line");self.graph.element.appendChild(annotation.line);if(box.end){box.rangeElement=document.createElement("div");box.rangeElement.classList.add("annotation_range");self.graph.element.appendChild(box.rangeElement)}}if(box.end){var annotationRangeStart=left;var annotationRangeEnd=Math.min(self.graph.x(box.end),self.graph.x.range()[1]);if(annotationRangeStart>annotationRangeEnd){annotationRangeEnd=left;annotationRangeStart=Math.max(self.graph.x(box.end),self.graph.x.range()[0])}var annotationRangeWidth=annotationRangeEnd-annotationRangeStart;box.rangeElement.style.left=annotationRangeStart+"px";box.rangeElement.style.width=annotationRangeWidth+"px";box.rangeElement.classList.remove("offscreen")}annotation.line.classList.remove("offscreen");annotation.line.style.left=left+"px"})},this)};this.graph.onUpdate(function(){self.update()})};Rickshaw.namespace("Rickshaw.Graph.Axis.Time");Rickshaw.Graph.Axis.Time=function(args){var self=this;this.graph=args.graph;this.elements=[];this.ticksTreatment=args.ticksTreatment||"plain";this.fixedTimeUnit=args.timeUnit;var time=args.timeFixture||new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var unit;var units=time.units;var domain=this.graph.x.domain();var rangeSeconds=domain[1]-domain[0];units.forEach(function(u){if(Math.floor(rangeSeconds/u.seconds)>=2){unit=unit||u}});return unit||time.units[time.units.length-1]};this.tickOffsets=function(){var domain=this.graph.x.domain();var unit=this.fixedTimeUnit||this.appropriateTimeUnit();var count=Math.ceil((domain[1]-domain[0])/unit.seconds);var runningTick=domain[0];var offsets=[];for(var i=0;iself.graph.x.range()[1])return;var element=document.createElement("div");element.style.left=self.graph.x(o.value)+"px";element.classList.add("x_tick");element.classList.add(self.ticksTreatment);var title=document.createElement("div");title.classList.add("title");title.innerHTML=o.unit.formatter(new Date(o.value*1e3));element.appendChild(title);self.graph.element.appendChild(element);self.elements.push(element)})};this.graph.onUpdate(function(){self.render()})};Rickshaw.namespace("Rickshaw.Graph.Axis.X");Rickshaw.Graph.Axis.X=function(args){var self=this;var berthRate=.1;this.initialize=function(args){this.graph=args.graph;this.orientation=args.orientation||"top";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";if(args.element){this.element=args.element;this._discoverSize(args.element,args);this.vis=d3.select(args.element).append("svg:svg").attr("height",this.height).attr("width",this.width).attr("class","rickshaw_graph x_axis_d3");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}this.graph.onUpdate(function(){self.render()})};this.setSize=function(args){args=args||{};if(!this.element)return;this._discoverSize(this.element.parentNode,args);this.vis.attr("height",this.height).attr("width",this.width*(1+berthRate));var berth=Math.floor(this.width*berthRate/2);this.element.style.left=-1*berth+"px"};this.render=function(){if(this.graph.width!==this._renderWidth)this.setSize({auto:true});var axis=d3.svg.axis().scale(this.graph.x).orient(this.orientation);axis.tickFormat(args.tickFormat||function(x){return x});if(this.tickValues)axis.tickValues(this.tickValues);this.ticks=this.staticTicks||Math.floor(this.graph.width/this.pixelsPerTick);var berth=Math.floor(this.width*berthRate/2)||0;var transform;if(this.orientation=="top"){var yOffset=this.height||this.graph.height;transform="translate("+berth+","+yOffset+")"}else{transform="translate("+berth+", 0)"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["x_ticks_d3",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var gridSize=(this.orientation=="bottom"?1:-1)*this.graph.height;this.graph.vis.append("svg:g").attr("class","x_grid_d3").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));this._renderHeight=this.graph.height};this._discoverSize=function(element,args){if(typeof window!=="undefined"){var style=window.getComputedStyle(element,null);var elementHeight=parseInt(style.getPropertyValue("height"),10);if(!args.auto){var elementWidth=parseInt(style.getPropertyValue("width"),10)}}this.width=(args.width||elementWidth||this.graph.width)*(1+berthRate);this.height=args.height||elementHeight||40};this.initialize(args)};Rickshaw.namespace("Rickshaw.Graph.Axis.Y");Rickshaw.Graph.Axis.Y=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.orientation=args.orientation||"right";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";this.tickFormat=args.tickFormat||function(y){return y};this.berthRate=.1;if(args.element){this.element=args.element;this.vis=d3.select(args.element).append("svg:svg").attr("class","rickshaw_graph y_axis");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}var self=this;this.graph.onUpdate(function(){self.render()})},setSize:function(args){args=args||{};if(!this.element)return;if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element.parentNode,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);if(!args.auto){var elementHeight=parseInt(style.getPropertyValue("height"),10)}}this.width=args.width||elementWidth||this.graph.width*this.berthRate;this.height=args.height||elementHeight||this.graph.height;this.vis.attr("width",this.width).attr("height",this.height*(1+this.berthRate));var berth=this.height*this.berthRate;if(this.orientation=="left"){this.element.style.top=-1*berth+"px"}},render:function(){if(this.graph.height!==this._renderHeight)this.setSize({auto:true});this.ticks=this.staticTicks||Math.floor(this.graph.height/this.pixelsPerTick);var axis=this._drawAxis(this.graph.y);this._drawGrid(axis);this._renderHeight=this.graph.height},_drawAxis:function(scale){var axis=d3.svg.axis().scale(scale).orient(this.orientation);axis.tickFormat(this.tickFormat);if(this.tickValues)axis.tickValues(this.tickValues);if(this.orientation=="left"){var berth=this.height*this.berthRate;var transform="translate("+this.width+", "+berth+")"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));return axis},_drawGrid:function(axis){var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize))}});Rickshaw.namespace("Rickshaw.Graph.Axis.Y.Scaled");Rickshaw.Graph.Axis.Y.Scaled=Rickshaw.Class.create(Rickshaw.Graph.Axis.Y,{initialize:function($super,args){if(typeof args.scale==="undefined"){throw new Error("Scaled requires scale")}this.scale=args.scale;if(typeof args.grid==="undefined"){this.grid=true}else{this.grid=args.grid}$super(args)},_drawAxis:function($super,scale){var adjustedScale=this.scale.copy().range(scale.range());return $super(adjustedScale)},_drawGrid:function($super,axis){if(this.grid){$super(axis)}}});Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight");Rickshaw.Graph.Behavior.Series.Highlight=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;var colorSafe={};var activeLine=null;var disabledColor=args.disabledColor||function(seriesColor){return d3.interpolateRgb(seriesColor,d3.rgb("#d8d8d8"))(.8).toString()};this.addHighlightEvents=function(l){l.element.addEventListener("mouseover",function(e){if(activeLine)return;else activeLine=l;self.legend.lines.forEach(function(line,index){if(l===line){if(index>0&&self.graph.renderer.unstack&&(line.series.renderer?line.series.renderer.unstack:true)){var seriesIndex=self.graph.series.length-index-1; +line.originalIndex=seriesIndex;var series=self.graph.series.splice(seriesIndex,1)[0];self.graph.series.push(series)}return}colorSafe[line.series.name]=colorSafe[line.series.name]||line.series.color;line.series.color=disabledColor(line.series.color)});self.graph.update()},false);l.element.addEventListener("mouseout",function(e){if(!activeLine)return;else activeLine=null;self.legend.lines.forEach(function(line){if(l===line&&line.hasOwnProperty("originalIndex")){var series=self.graph.series.pop();self.graph.series.splice(line.originalIndex,0,series);delete line.originalIndex}if(colorSafe[line.series.name]){line.series.color=colorSafe[line.series.name]}});self.graph.update()},false)};if(this.legend){this.legend.lines.forEach(function(l){self.addHighlightEvents(l)})}};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order");Rickshaw.Graph.Behavior.Series.Order=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;if(typeof window.$=="undefined"){throw"couldn't find jQuery at window.$"}if(typeof window.$.ui=="undefined"){throw"couldn't find jQuery UI at window.$.ui"}$(function(){$(self.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(event,ui){var series=[];$(self.legend.list).find("li").each(function(index,item){if(!item.series)return;series.push(item.series)});for(var i=self.graph.series.length-1;i>=0;i--){self.graph.series[i]=series.shift()}self.graph.update()}});$(self.legend.list).disableSelection()});this.graph.onUpdate(function(){var h=window.getComputedStyle(self.legend.element).height;self.legend.element.style.height=h})};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle");Rickshaw.Graph.Behavior.Series.Toggle=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;this.addAnchor=function(line){var anchor=document.createElement("a");anchor.innerHTML="✔";anchor.classList.add("action");line.element.insertBefore(anchor,line.element.firstChild);anchor.onclick=function(e){if(line.series.disabled){line.series.enable();line.element.classList.remove("disabled")}else{if(this.graph.series.filter(function(s){return!s.disabled}).length<=1)return;line.series.disable();line.element.classList.add("disabled")}}.bind(this);var label=line.element.getElementsByTagName("span")[0];label.onclick=function(e){var disableAllOtherLines=line.series.disabled;if(!disableAllOtherLines){for(var i=0;idomainX){dataIndex=Math.abs(domainX-data[i].x)yMax)yMax=y});if(series[0].xxMax)xMax=series[series.length-1].x});xMin-=(xMax-xMin)*this.padding.left;xMax+=(xMax-xMin)*this.padding.right;yMin=this.graph.min==="auto"?yMin:this.graph.min||0;yMax=this.graph.max===undefined?yMax:this.graph.max;if(this.graph.min==="auto"||yMin<0){yMin-=(yMax-yMin)*this.padding.bottom}if(this.graph.max===undefined){yMax+=(yMax-yMin)*this.padding.top}return{x:[xMin,xMax],y:[yMin,yMax]}},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var nodes=vis.selectAll("path").data(data).enter().append("svg:path").attr("d",this.seriesPathFactory());var i=0;series.forEach(function(series){if(series.disabled)return;series.path=nodes[0][i++];this._styleSeries(series)},this)},_styleSeries:function(series){var fill=this.fill?series.color:"none";var stroke=this.stroke?series.color:"none";series.path.setAttribute("fill",fill);series.path.setAttribute("stroke",stroke);series.path.setAttribute("stroke-width",this.strokeWidth);series.path.setAttribute("class",series.className)},configure:function(args){args=args||{};Rickshaw.keys(this.defaults()).forEach(function(key){if(!args.hasOwnProperty(key)){this[key]=this[key]||this.graph[key]||this.defaults()[key];return}if(typeof this.defaults()[key]=="object"){Rickshaw.keys(this.defaults()[key]).forEach(function(k){this[key][k]=args[key][k]!==undefined?args[key][k]:this[key][k]!==undefined?this[key][k]:this.defaults()[key][k]},this)}else{this[key]=args[key]!==undefined?args[key]:this[key]!==undefined?this[key]:this.graph[key]!==undefined?this.graph[key]:this.defaults()[key]}},this)},setStrokeWidth:function(strokeWidth){if(strokeWidth!==undefined){this.strokeWidth=strokeWidth}},setTension:function(tension){if(tension!==undefined){this.tension=tension}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Line");Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack");Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:true,stroke:false,unstack:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar");Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var defaults=Rickshaw.extend($super(),{gapSize:.05,unstack:false});delete defaults.tension;return defaults},initialize:function($super,args){args=args||{};this.gapSize=args.gapSize||this.gapSize;$super(args)},domain:function($super){var domain=$super();var frequentInterval=this._frequentInterval(this.graph.stackedData.slice(-1).shift());domain.x[1]+=Number(frequentInterval.magnitude);return domain},barWidth:function(series){var frequentInterval=this._frequentInterval(series.stack);var barWidth=this.graph.x(series.stack[0].x+frequentInterval.magnitude*(1-this.gapSize));return barWidth},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var barWidth=this.barWidth(series.active()[0]);var barXOffset=0;var activeSeriesCount=series.filter(function(s){return!s.disabled}).length;var seriesBarWidth=this.unstack?barWidth/activeSeriesCount:barWidth;var transform=function(d){var matrix=[1,0,0,d.y<0?-1:1,0,d.y<0?graph.y.magnitude(Math.abs(d.y))*2:0];return"matrix("+matrix.join(",")+")"};series.forEach(function(series){if(series.disabled)return;var barWidth=this.barWidth(series);var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}}); \ No newline at end of file diff --git a/templates/project/assets/javascripts/rickshaw.min.js b/templates/project/assets/javascripts/rickshaw.min.js deleted file mode 100644 index 33fa34f..0000000 --- a/templates/project/assets/javascripts/rickshaw.min.js +++ /dev/null @@ -1,2 +0,0 @@ -Rickshaw={namespace:function(a,b){var c=a.split("."),d=typeof global!="undefined"?global:window,e=d.Rickshaw;for(var f=1,g=c.length;fthis.window.xMax&&(b=!1),b}return!0},this.onUpdate=function(a){this.updateCallbacks.push(a)},this.registerRenderer=function(a){this._renderers=this._renderers||{},this._renderers[a.name]=a},this.configure=function(a){(a.width||a.height)&&this.setSize(a),Rickshaw.keys(this.defaults).forEach(function(b){this[b]=b in a?a[b]:b in this?this[b]:this.defaults[b]},this),this.setRenderer(a.renderer||this.renderer.name,a)},this.setRenderer=function(a,b){if(!this._renderers[a])throw"couldn't find renderer "+a;this.renderer=this._renderers[a],typeof b=="object"&&this.renderer.configure(b)},this.setSize=function(a){a=a||{};if(typeof window!==undefined)var b=window.getComputedStyle(this.element,null),c=parseInt(b.getPropertyValue("width")),d=parseInt(b.getPropertyValue("height"));this.width=a.width||c||400,this.height=a.height||d||250,this.vis&&this.vis.attr("width",this.width).attr("height",this.height)},this.initialize(a)},Rickshaw.namespace("Rickshaw.Fixtures.Color"),Rickshaw.Fixtures.Color=function(){this.schemes={},this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse(),this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"],this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"],this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse(),this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"},this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse(),this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"],this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]},Rickshaw.namespace("Rickshaw.Fixtures.RandomData"),Rickshaw.Fixtures.RandomData=function(a){var b;a=a||1;var c=200,d=Math.floor((new Date).getTime()/1e3);this.addData=function(b){var e=Math.random()*100+15+c,f=b[0].length,g=1;b.forEach(function(b){var c=Math.random()*20,h=e/25+g++ +(Math.cos(f*g*11/960)+2)*15+(Math.cos(f/7)+2)*7+(Math.cos(f/17)+2)*1;b.push({x:f*a+d,y:h+c})}),c=e*.85}},Rickshaw.namespace("Rickshaw.Fixtures.Time"),Rickshaw.Fixtures.Time=function(){var a=(new Date).getTimezoneOffset()*60,b=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],this.units=[{name:"decade",seconds:315576e3,formatter:function(a){return parseInt(a.getUTCFullYear()/10)*10}},{name:"year",seconds:31557600,formatter:function(a){return a.getUTCFullYear()}},{name:"month",seconds:2635200,formatter:function(a){return b.months[a.getUTCMonth()]}},{name:"week",seconds:604800,formatter:function(a){return b.formatDate(a)}},{name:"day",seconds:86400,formatter:function(a){return a.getUTCDate()}},{name:"6 hour",seconds:21600,formatter:function(a){return b.formatTime(a)}},{name:"hour",seconds:3600,formatter:function(a){return b.formatTime(a)}},{name:"15 minute",seconds:900,formatter:function(a){return b.formatTime(a)}},{name:"minute",seconds:60,formatter:function(a){return a.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(a){return a.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(a){return a.getUTCSeconds()+"s"}}],this.unit=function(a){return this.units.filter(function(b){return a==b.name}).shift()},this.formatDate=function(a){return a.toUTCString().match(/, (\w+ \w+ \w+)/)[1]},this.formatTime=function(a){return a.toUTCString().match(/(\d+:\d+):/)[1]},this.ceil=function(a,b){if(b.name=="month"){var c=new Date((a+b.seconds-1)*1e3),d=new Date(0);return d.setUTCFullYear(c.getUTCFullYear()),d.setUTCMonth(c.getUTCMonth()),d.setUTCDate(1),d.setUTCHours(0),d.setUTCMinutes(0),d.setUTCSeconds(0),d.setUTCMilliseconds(0),d.getTime()/1e3}if(b.name=="year"){var c=new Date((a+b.seconds-1)*1e3),d=new Date(0);return d.setUTCFullYear(c.getUTCFullYear()),d.setUTCMonth(0),d.setUTCDate(1),d.setUTCHours(0),d.setUTCMinutes(0),d.setUTCSeconds(0),d.setUTCMilliseconds(0),d.getTime()/1e3}return Math.ceil(a/b.seconds)*b.seconds}},Rickshaw.namespace("Rickshaw.Fixtures.Number"),Rickshaw.Fixtures.Number.formatKMBT=function(a){return a>=1e12?a/1e12+"T":a>=1e9?a/1e9+"B":a>=1e6?a/1e6+"M":a>=1e3?a/1e3+"K":a<1&&a>0?a.toFixed(2):a==0?"":a},Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(a){return a>=0x4000000000000?a/0x4000000000000+"P":a>=1099511627776?a/1099511627776+"T":a>=1073741824?a/1073741824+"G":a>=1048576?a/1048576+"M":a>=1024?a/1024+"K":a<1&&a>0?a.toFixed(2):a==0?"":a},Rickshaw.namespace("Rickshaw.Color.Palette"),Rickshaw.Color.Palette=function(a){var b=new Rickshaw.Fixtures.Color;a=a||{},this.schemes={},this.scheme=b.schemes[a.scheme]||a.scheme||b.schemes.colorwheel,this.runningIndex=0,this.generatorIndex=0;if(a.interpolatedStopCount){var c=this.scheme.length-1,d,e,f=[];for(d=0;dc.graph.x.range()[1]){b.element&&(b.element.style.display="none");return}if(!b.element){var e=b.element=document.createElement("div");e.classList.add("annotation"),this.elements.timeline.appendChild(e),e.addEventListener("click",function(a){e.classList.toggle("active"),b.line.classList.toggle("active")},!1)}b.element.style.left=d+"px",b.element.style.display="block",b.boxes.forEach(function(a){var e=a.element;e||(e=a.element=document.createElement("div"),e.classList.add("content"),e.innerHTML=a.content,b.element.appendChild(e),b.line=document.createElement("div"),b.line.classList.add("annotation_line"),c.graph.element.appendChild(b.line)),b.line.style.left=d+"px"})},this)},this.graph.onUpdate(function(){c.update()})},Rickshaw.namespace("Rickshaw.Graph.Axis.Time"),Rickshaw.Graph.Axis.Time=function(a){var b=this;this.graph=a.graph,this.elements=[],this.ticksTreatment=a.ticksTreatment||"plain",this.fixedTimeUnit=a.timeUnit;var c=new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var a,b=c.units,d=this.graph.x.domain(),e=d[1]-d[0];return b.forEach(function(b){Math.floor(e/b.seconds)>=2&&(a=a||b)}),a||c.units[c.units.length-1]},this.tickOffsets=function(){var a=this.graph.x.domain(),b=this.fixedTimeUnit||this.appropriateTimeUnit(),d=Math.ceil((a[1]-a[0])/b.seconds),e=a[0],f=[];for(var g=0;gb.graph.x.range()[1])return;var c=document.createElement("div");c.style.left=b.graph.x(a.value)+"px",c.classList.add("x_tick"),c.classList.add(b.ticksTreatment);var d=document.createElement("div");d.classList.add("title"),d.innerHTML=a.unit.formatter(new Date(a.value*1e3)),c.appendChild(d),b.graph.element.appendChild(c),b.elements.push(c)})},this.graph.onUpdate(function(){b.render()})},Rickshaw.namespace("Rickshaw.Graph.Axis.Y"),Rickshaw.Graph.Axis.Y=function(a){var b=this,c=.1;this.initialize=function(a){this.graph=a.graph,this.orientation=a.orientation||"right";var c=a.pixelsPerTick||75;this.ticks=a.ticks||Math.floor(this.graph.height/c),this.tickSize=a.tickSize||4,this.ticksTreatment=a.ticksTreatment||"plain",a.element?(this.element=a.element,this.vis=d3.select(a.element).append("svg:svg").attr("class","rickshaw_graph y_axis"),this.element=this.vis[0][0],this.element.style.position="relative",this.setSize({width:a.width,height:a.height})):this.vis=this.graph.vis,this.graph.onUpdate(function(){b.render()})},this.setSize=function(a){a=a||{};if(!this.element)return;if(typeof window!="undefined"){var b=window.getComputedStyle(this.element.parentNode,null),d=parseInt(b.getPropertyValue("width"));if(!a.auto)var e=parseInt(b.getPropertyValue("height"))}this.width=a.width||d||this.graph.width*c,this.height=a.height||e||this.graph.height,this.vis.attr("width",this.width).attr("height",this.height*(1+c));var f=this.height*c;this.element.style.top=-1*f+"px"},this.render=function(){this.graph.height!==this._renderHeight&&this.setSize({auto:!0});var b=d3.svg.axis().scale(this.graph.y).orient(this.orientation);b.tickFormat(a.tickFormat||function(a){return a});if(this.orientation=="left")var d=this.height*c,e="translate("+this.width+", "+d+")";this.element&&this.vis.selectAll("*").remove(),this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",e).call(b.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var f=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(b.ticks(this.ticks).tickSubdivide(0).tickSize(f)),this._renderHeight=this.graph.height},this.initialize(a)},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight"),Rickshaw.Graph.Behavior.Series.Highlight=function(a){this.graph=a.graph,this.legend=a.legend;var b=this,c={};this.addHighlightEvents=function(a){a.element.addEventListener("mouseover",function(d){b.legend.lines.forEach(function(b){if(a===b)return;c[b.series.name]=c[b.series.name]||b.series.color,b.series.color=d3.interpolateRgb(b.series.color,d3.rgb("#d8d8d8"))(.8).toString()}),b.graph.update()},!1),a.element.addEventListener("mouseout",function(a){b.legend.lines.forEach(function(a){c[a.series.name]&&(a.series.color=c[a.series.name])}),b.graph.update()},!1)},this.legend&&this.legend.lines.forEach(function(a){b.addHighlightEvents(a)})},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order"),Rickshaw.Graph.Behavior.Series.Order=function(a){this.graph=a.graph,this.legend=a.legend;var b=this;$(function(){$(b.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(a,c){var d=[];$(b.legend.list).find("li").each(function(a,b){if(!b.series)return;d.push(b.series)});for(var e=b.graph.series.length-1;e>=0;e--)b.graph.series[e]=d.shift();b.graph.update()}}),$(b.legend.list).disableSelection()}),this.graph.onUpdate(function(){var a=window.getComputedStyle(b.legend.element).height;b.legend.element.style.height=a})},Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle"),Rickshaw.Graph.Behavior.Series.Toggle=function(a){this.graph=a.graph,this.legend=a.legend;var b=this;this.addAnchor=function(a){var c=document.createElement("a");c.innerHTML="✔",c.classList.add("action"),a.element.insertBefore(c,a.element.firstChild),c.onclick=function(b){a.series.disabled?(a.series.enable(),a.element.classList.remove("disabled")):(a.series.disable(),a.element.classList.add("disabled"))};var d=a.element.getElementsByTagName("span")[0];d.onclick=function(c){var d=a.series.disabled;if(!d)for(var e=0;ee){j=k;break}f[0][k+1]<=e?k++:k--}var e=f[0][j].x,l=this.xFormatter(e),m=b.x(e),n=0,o=b.series.active().map(function(a){return{order:n++,series:a,name:a.name,value:a.stack[j]}}),p,q=function(a,b){return a.value.y0+a.value.y-(b.value.y0+b.value.y)},r=b.y.magnitude.invert(b.element.offsetHeight-d);o.sort(q).forEach(function(a){a.formattedYValue=this.yFormatter.constructor==Array?this.yFormatter[o.indexOf(a)](a.value.y):this.yFormatter(a.value.y),a.graphX=m,a.graphY=b.y(a.value.y0+a.value.y),r>a.value.y0&&r0?this[0].data.forEach(function(b){a.data.push({x:b.x,y:0})}):a.data.length==0&&a.data.push({x:this.timeBase-(this.timeInterval||0),y:0}),this.push(a),this.legend&&this.legend.addLine(this.itemByName(a.name))},addData:function(a){var b=this.getIndex();Rickshaw.keys(a).forEach(function(a){this.itemByName(a)||this.addItem({name:a})},this),this.forEach(function(c){c.data.push({x:(b*this.timeInterval||1)+this.timeBase,y:a[c.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(a){for(var b=0;b0;d--)this.currentSize+=1,this.currentIndex+=1,this.forEach(function(a){a.data.unshift({x:((d-1)*this.timeInterval||1)+this.timeBase,y:0,i:d})},this)},addData:function($super,a){$super(a),this.currentSize+=1,this.currentIndex+=1;if(this.maxDataPoints!==undefined)while(this.currentSize>this.maxDataPoints)this.dropData()},dropData:function(){this.forEach(function(a){a.data.splice(0,1)}),this.currentSize-=1},getIndex:function(){return this.currentIndex}}); \ No newline at end of file -- cgit v1.2.3 From 3af326da84251069c4e6f7464d0ae8506b20e98b Mon Sep 17 00:00:00 2001 From: David Underwood Date: Wed, 21 Aug 2013 14:18:10 -0400 Subject: Updates fontawesome to 3.2.1 --- .../project/assets/fonts/fontawesome-webfont.eot | Bin 38708 -> 37405 bytes .../project/assets/fonts/fontawesome-webfont.svg | 640 +++++--- .../project/assets/fonts/fontawesome-webfont.ttf | Bin 68476 -> 79076 bytes .../project/assets/fonts/fontawesome-webfont.woff | Bin 41752 -> 43572 bytes .../project/assets/stylesheets/application.scss | 50 +- .../project/assets/stylesheets/font-awesome.css | 1736 ++++++++++++++++---- 6 files changed, 1874 insertions(+), 552 deletions(-) diff --git a/templates/project/assets/fonts/fontawesome-webfont.eot b/templates/project/assets/fonts/fontawesome-webfont.eot index 89070c1..0662cb9 100644 Binary files a/templates/project/assets/fonts/fontawesome-webfont.eot and b/templates/project/assets/fonts/fontawesome-webfont.eot differ diff --git a/templates/project/assets/fonts/fontawesome-webfont.svg b/templates/project/assets/fonts/fontawesome-webfont.svg index 1245f92..2edb4ec 100644 --- a/templates/project/assets/fonts/fontawesome-webfont.svg +++ b/templates/project/assets/fonts/fontawesome-webfont.svg @@ -3,253 +3,397 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/project/assets/fonts/fontawesome-webfont.ttf b/templates/project/assets/fonts/fontawesome-webfont.ttf index c17e9f8..d365924 100644 Binary files a/templates/project/assets/fonts/fontawesome-webfont.ttf and b/templates/project/assets/fonts/fontawesome-webfont.ttf differ diff --git a/templates/project/assets/fonts/fontawesome-webfont.woff b/templates/project/assets/fonts/fontawesome-webfont.woff index 09f2469..b9bd17e 100644 Binary files a/templates/project/assets/fonts/fontawesome-webfont.woff and b/templates/project/assets/fonts/fontawesome-webfont.woff differ diff --git a/templates/project/assets/stylesheets/application.scss b/templates/project/assets/stylesheets/application.scss index ea2cd86..20e009f 100644 --- a/templates/project/assets/stylesheets/application.scss +++ b/templates/project/assets/stylesheets/application.scss @@ -35,22 +35,22 @@ $text-danger-color: #fff; // ---------------------------------------------------------------------------- // Base styles // ---------------------------------------------------------------------------- -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; } -body { - margin: 0; +body { + margin: 0; background-color: $background-color; font-size: 20px; color: $text-color; font-family: 'Open Sans', "Helvetica Neue", Helvetica, Arial, sans-serif; } -b, strong { - font-weight: bold; +b, strong { + font-weight: bold; } a { @@ -58,18 +58,18 @@ a { color: inherit; } -img { - border: 0; - -ms-interpolation-mode: bicubic; - vertical-align: middle; +img { + border: 0; + -ms-interpolation-mode: bicubic; + vertical-align: middle; } -img, object { - max-width: 100%; +img, object { + max-width: 100%; } -iframe { - max-width: 100%; +iframe { + max-width: 100%; } table { @@ -82,16 +82,16 @@ td { vertical-align: middle; } -ul, ol { - padding: 0; - margin: 0; +ul, ol { + padding: 0; + margin: 0; } -h1, h2, h3, h4, h5, p { +h1, h2, h3, h4, h5, p { padding: 0; - margin: 0; + margin: 0; } -h1 { +h1 { margin-bottom: 12px; text-align: center; font-size: 30px; @@ -124,6 +124,8 @@ h3 { top: 0; opacity: 0.1; font-size: 275px; + text-align: center; + margin-top: 82px; } .list-nostyle { @@ -152,7 +154,7 @@ h3 { background-color: $background-warning-color-1; @include animation(status-warning-background, 2s, ease, infinite); - .icon-warning-sign { + .icon-warning-sign { display: inline-block; } @@ -166,7 +168,7 @@ h3 { background-color: $background-danger-color-1; @include animation(status-danger-background, 2s, ease, infinite); - .icon-warning-sign { + .icon-warning-sign { display: inline-block; } diff --git a/templates/project/assets/stylesheets/font-awesome.css b/templates/project/assets/stylesheets/font-awesome.css index c642925..e6f5216 100644 --- a/templates/project/assets/stylesheets/font-awesome.css +++ b/templates/project/assets/stylesheets/font-awesome.css @@ -1,303 +1,1479 @@ -/* Font Awesome - the iconic font designed for use with Twitter Bootstrap - ------------------------------------------------------- - The full suite of pictographic icons, examples, and documentation - can be found at: http://fortawesome.github.com/Font-Awesome/ - - License - ------------------------------------------------------- - The Font Awesome webfont, CSS, and LESS files are licensed under CC BY 3.0: - http://creativecommons.org/licenses/by/3.0/ A mention of - 'Font Awesome - http://fortawesome.github.com/Font-Awesome' in human-readable - source code is considered acceptable attribution (most common on the web). - If human readable source code is not available to the end user, a mention in - an 'About' or 'Credits' screen is considered acceptable (most common in desktop - or mobile software). - - Contact - ------------------------------------------------------- - Email: dave@davegandy.com - Twitter: http://twitter.com/fortaweso_me - Work: http://lemonwi.se co-founder - - */ +/*! + * Font Awesome 3.2.1 + * the iconic font designed for Bootstrap + * ------------------------------------------------------------------------------ + * The full suite of pictographic icons, examples, and documentation can be + * found at http://fontawesome.io. Stay up to date on Twitter at + * http://twitter.com/fontawesome. + * + * License + * ------------------------------------------------------------------------------ + * - The Font Awesome font is licensed under SIL OFL 1.1 - + * http://scripts.sil.org/OFL + * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License - + * http://opensource.org/licenses/mit-license.html + * - Font Awesome documentation licensed under CC BY 3.0 - + * http://creativecommons.org/licenses/by/3.0/ + * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: + * "Font Awesome by Dave Gandy - http://fontawesome.io" + * + * Author - Dave Gandy + * ------------------------------------------------------------------------------ + * Email: dave@fontawesome.io + * Twitter: http://twitter.com/davegandy + * Work: Lead Product Designer @ Kyruus - http://kyruus.com + */ +/* FONT PATH + * -------------------------- */ @font-face { - font-family: "FontAwesome"; - src: url('/assets/fontawesome-webfont.eot'); - src: url('/assets/fontawesome-webfont.eot?#iefix') format('eot'), url('/assets/fontawesome-webfont.woff') format('woff'), url('/assets/fontawesome-webfont.ttf') format('truetype'), url('/assets/fontawesome-webfont.svg#FontAwesome') format('svg'); + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=3.2.1'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../fonts/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg'); font-weight: normal; font-style: normal; } - -/* Font Awesome styles - ------------------------------------------------------- */ -[class^="icon-"]:before, [class*=" icon-"]:before { +/* FONT AWESOME CORE + * -------------------------- */ +[class^="icon-"], +[class*=" icon-"] { font-family: FontAwesome; font-weight: normal; font-style: normal; - display: inline-block; text-decoration: inherit; + -webkit-font-smoothing: antialiased; + *margin-right: .3em; } -a [class^="icon-"], a [class*=" icon-"] { - display: inline-block; +[class^="icon-"]:before, +[class*=" icon-"]:before { text-decoration: inherit; + display: inline-block; + speak: none; } /* makes the font 33% larger relative to the icon container */ .icon-large:before { - vertical-align: top; + vertical-align: -10%; font-size: 1.3333333333333333em; } -.btn [class^="icon-"], .btn [class*=" icon-"] { - /* keeps button heights with and without icons the same */ - - line-height: .9em; +/* makes sure icons active on rollover in links */ +a [class^="icon-"], +a [class*=" icon-"] { + display: inline; } -li [class^="icon-"], li [class*=" icon-"] { +/* increased font size for icon-large */ +[class^="icon-"].icon-fixed-width, +[class*=" icon-"].icon-fixed-width { display: inline-block; - width: 1.25em; - text-align: center; + width: 1.1428571428571428em; + text-align: right; + padding-right: 0.2857142857142857em; } -li .icon-large[class^="icon-"], li .icon-large[class*=" icon-"] { - /* 1.5 increased font size for icon-large * 1.25 width */ - - width: 1.875em; +[class^="icon-"].icon-fixed-width.icon-large, +[class*=" icon-"].icon-fixed-width.icon-large { + width: 1.4285714285714286em; } -li[class^="icon-"], li[class*=" icon-"] { - margin-left: 0; +.icons-ul { + margin-left: 2.142857142857143em; list-style-type: none; } -li[class^="icon-"]:before, li[class*=" icon-"]:before { - text-indent: -2em; +.icons-ul > li { + position: relative; +} +.icons-ul .icon-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; text-align: center; + line-height: inherit; +} +[class^="icon-"].hide, +[class*=" icon-"].hide { + display: none; +} +.icon-muted { + color: #eeeeee; +} +.icon-light { + color: #ffffff; +} +.icon-dark { + color: #333333; +} +.icon-border { + border: solid 1px #eeeeee; + padding: .2em .25em .15em; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +.icon-2x { + font-size: 2em; +} +.icon-2x.icon-border { + border-width: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.icon-3x { + font-size: 3em; +} +.icon-3x.icon-border { + border-width: 3px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.icon-4x { + font-size: 4em; +} +.icon-4x.icon-border { + border-width: 4px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} +.icon-5x { + font-size: 5em; +} +.icon-5x.icon-border { + border-width: 5px; + -webkit-border-radius: 7px; + -moz-border-radius: 7px; + border-radius: 7px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +[class^="icon-"].pull-left, +[class*=" icon-"].pull-left { + margin-right: .3em; +} +[class^="icon-"].pull-right, +[class*=" icon-"].pull-right { + margin-left: .3em; +} +/* BOOTSTRAP SPECIFIC CLASSES + * -------------------------- */ +/* Bootstrap 2.0 sprites.less reset */ +[class^="icon-"], +[class*=" icon-"] { + display: inline; + width: auto; + height: auto; + line-height: normal; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; + margin-top: 0; +} +/* more sprites.less reset */ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { + background-image: none; +} +/* keeps Bootstrap styles with and without icons the same */ +.btn [class^="icon-"].icon-large, +.nav [class^="icon-"].icon-large, +.btn [class*=" icon-"].icon-large, +.nav [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].icon-spin, +.nav [class^="icon-"].icon-spin, +.btn [class*=" icon-"].icon-spin, +.nav [class*=" icon-"].icon-spin { + display: inline-block; +} +.nav-tabs [class^="icon-"], +.nav-pills [class^="icon-"], +.nav-tabs [class*=" icon-"], +.nav-pills [class*=" icon-"], +.nav-tabs [class^="icon-"].icon-large, +.nav-pills [class^="icon-"].icon-large, +.nav-tabs [class*=" icon-"].icon-large, +.nav-pills [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].pull-left.icon-2x, +.btn [class*=" icon-"].pull-left.icon-2x, +.btn [class^="icon-"].pull-right.icon-2x, +.btn [class*=" icon-"].pull-right.icon-2x { + margin-top: .18em; +} +.btn [class^="icon-"].icon-spin.icon-large, +.btn [class*=" icon-"].icon-spin.icon-large { + line-height: .8em; +} +.btn.btn-small [class^="icon-"].pull-left.icon-2x, +.btn.btn-small [class*=" icon-"].pull-left.icon-2x, +.btn.btn-small [class^="icon-"].pull-right.icon-2x, +.btn.btn-small [class*=" icon-"].pull-right.icon-2x { + margin-top: .25em; +} +.btn.btn-large [class^="icon-"], +.btn.btn-large [class*=" icon-"] { + margin-top: 0; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x, +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-top: .05em; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x { + margin-right: .2em; +} +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-left: .2em; +} +/* Fixes alignment in nav lists */ +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + line-height: inherit; +} +/* EXTRAS + * -------------------------- */ +/* Stacked and layered icon */ +.icon-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: -35%; +} +.icon-stack [class^="icon-"], +.icon-stack [class*=" icon-"] { + display: block; + text-align: center; + position: absolute; + width: 100%; + height: 100%; + font-size: 1em; + line-height: inherit; + *line-height: 2em; +} +.icon-stack .icon-stack-base { + font-size: 2em; + *line-height: 1em; +} +/* Animated rotating icon */ +.icon-spin { + display: inline-block; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +/* Prevent stack and spinners from being taken inline when inside a link */ +a .icon-stack, +a .icon-spin { + display: inline-block; + text-decoration: none; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +/* Icon rotations and mirroring */ +.icon-rotate-90:before { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); +} +.icon-rotate-180:before { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); +} +.icon-rotate-270:before { + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); +} +.icon-flip-horizontal:before { + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.icon-flip-vertical:before { + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +/* ensure rotation occurs inside anchor tags */ +a .icon-rotate-90:before, +a .icon-rotate-180:before, +a .icon-rotate-270:before, +a .icon-flip-horizontal:before, +a .icon-flip-vertical:before { + display: inline-block; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { + content: "\f000"; +} +.icon-music:before { + content: "\f001"; +} +.icon-search:before { + content: "\f002"; +} +.icon-envelope-alt:before { + content: "\f003"; +} +.icon-heart:before { + content: "\f004"; +} +.icon-star:before { + content: "\f005"; +} +.icon-star-empty:before { + content: "\f006"; +} +.icon-user:before { + content: "\f007"; +} +.icon-film:before { + content: "\f008"; +} +.icon-th-large:before { + content: "\f009"; +} +.icon-th:before { + content: "\f00a"; +} +.icon-th-list:before { + content: "\f00b"; +} +.icon-ok:before { + content: "\f00c"; +} +.icon-remove:before { + content: "\f00d"; +} +.icon-zoom-in:before { + content: "\f00e"; +} +.icon-zoom-out:before { + content: "\f010"; +} +.icon-power-off:before, +.icon-off:before { + content: "\f011"; +} +.icon-signal:before { + content: "\f012"; +} +.icon-gear:before, +.icon-cog:before { + content: "\f013"; +} +.icon-trash:before { + content: "\f014"; +} +.icon-home:before { + content: "\f015"; +} +.icon-file-alt:before { + content: "\f016"; +} +.icon-time:before { + content: "\f017"; +} +.icon-road:before { + content: "\f018"; +} +.icon-download-alt:before { + content: "\f019"; +} +.icon-download:before { + content: "\f01a"; +} +.icon-upload:before { + content: "\f01b"; +} +.icon-inbox:before { + content: "\f01c"; +} +.icon-play-circle:before { + content: "\f01d"; +} +.icon-rotate-right:before, +.icon-repeat:before { + content: "\f01e"; +} +.icon-refresh:before { + content: "\f021"; +} +.icon-list-alt:before { + content: "\f022"; +} +.icon-lock:before { + content: "\f023"; +} +.icon-flag:before { + content: "\f024"; +} +.icon-headphones:before { + content: "\f025"; +} +.icon-volume-off:before { + content: "\f026"; +} +.icon-volume-down:before { + content: "\f027"; +} +.icon-volume-up:before { + content: "\f028"; +} +.icon-qrcode:before { + content: "\f029"; +} +.icon-barcode:before { + content: "\f02a"; +} +.icon-tag:before { + content: "\f02b"; +} +.icon-tags:before { + content: "\f02c"; +} +.icon-book:before { + content: "\f02d"; +} +.icon-bookmark:before { + content: "\f02e"; +} +.icon-print:before { + content: "\f02f"; +} +.icon-camera:before { + content: "\f030"; +} +.icon-font:before { + content: "\f031"; +} +.icon-bold:before { + content: "\f032"; +} +.icon-italic:before { + content: "\f033"; +} +.icon-text-height:before { + content: "\f034"; +} +.icon-text-width:before { + content: "\f035"; +} +.icon-align-left:before { + content: "\f036"; +} +.icon-align-center:before { + content: "\f037"; +} +.icon-align-right:before { + content: "\f038"; +} +.icon-align-justify:before { + content: "\f039"; +} +.icon-list:before { + content: "\f03a"; +} +.icon-indent-left:before { + content: "\f03b"; +} +.icon-indent-right:before { + content: "\f03c"; +} +.icon-facetime-video:before { + content: "\f03d"; +} +.icon-picture:before { + content: "\f03e"; +} +.icon-pencil:before { + content: "\f040"; +} +.icon-map-marker:before { + content: "\f041"; +} +.icon-adjust:before { + content: "\f042"; +} +.icon-tint:before { + content: "\f043"; +} +.icon-edit:before { + content: "\f044"; +} +.icon-share:before { + content: "\f045"; +} +.icon-check:before { + content: "\f046"; +} +.icon-move:before { + content: "\f047"; +} +.icon-step-backward:before { + content: "\f048"; +} +.icon-fast-backward:before { + content: "\f049"; +} +.icon-backward:before { + content: "\f04a"; +} +.icon-play:before { + content: "\f04b"; +} +.icon-pause:before { + content: "\f04c"; +} +.icon-stop:before { + content: "\f04d"; +} +.icon-forward:before { + content: "\f04e"; +} +.icon-fast-forward:before { + content: "\f050"; +} +.icon-step-forward:before { + content: "\f051"; +} +.icon-eject:before { + content: "\f052"; +} +.icon-chevron-left:before { + content: "\f053"; +} +.icon-chevron-right:before { + content: "\f054"; +} +.icon-plus-sign:before { + content: "\f055"; +} +.icon-minus-sign:before { + content: "\f056"; +} +.icon-remove-sign:before { + content: "\f057"; +} +.icon-ok-sign:before { + content: "\f058"; +} +.icon-question-sign:before { + content: "\f059"; +} +.icon-info-sign:before { + content: "\f05a"; +} +.icon-screenshot:before { + content: "\f05b"; +} +.icon-remove-circle:before { + content: "\f05c"; +} +.icon-ok-circle:before { + content: "\f05d"; +} +.icon-ban-circle:before { + content: "\f05e"; +} +.icon-arrow-left:before { + content: "\f060"; +} +.icon-arrow-right:before { + content: "\f061"; +} +.icon-arrow-up:before { + content: "\f062"; +} +.icon-arrow-down:before { + content: "\f063"; +} +.icon-mail-forward:before, +.icon-share-alt:before { + content: "\f064"; +} +.icon-resize-full:before { + content: "\f065"; +} +.icon-resize-small:before { + content: "\f066"; +} +.icon-plus:before { + content: "\f067"; +} +.icon-minus:before { + content: "\f068"; +} +.icon-asterisk:before { + content: "\f069"; +} +.icon-exclamation-sign:before { + content: "\f06a"; +} +.icon-gift:before { + content: "\f06b"; +} +.icon-leaf:before { + content: "\f06c"; +} +.icon-fire:before { + content: "\f06d"; +} +.icon-eye-open:before { + content: "\f06e"; +} +.icon-eye-close:before { + content: "\f070"; +} +.icon-warning-sign:before { + content: "\f071"; +} +.icon-plane:before { + content: "\f072"; +} +.icon-calendar:before { + content: "\f073"; +} +.icon-random:before { + content: "\f074"; +} +.icon-comment:before { + content: "\f075"; +} +.icon-magnet:before { + content: "\f076"; +} +.icon-chevron-up:before { + content: "\f077"; +} +.icon-chevron-down:before { + content: "\f078"; +} +.icon-retweet:before { + content: "\f079"; +} +.icon-shopping-cart:before { + content: "\f07a"; +} +.icon-folder-close:before { + content: "\f07b"; +} +.icon-folder-open:before { + content: "\f07c"; +} +.icon-resize-vertical:before { + content: "\f07d"; +} +.icon-resize-horizontal:before { + content: "\f07e"; +} +.icon-bar-chart:before { + content: "\f080"; +} +.icon-twitter-sign:before { + content: "\f081"; +} +.icon-facebook-sign:before { + content: "\f082"; +} +.icon-camera-retro:before { + content: "\f083"; +} +.icon-key:before { + content: "\f084"; +} +.icon-gears:before, +.icon-cogs:before { + content: "\f085"; +} +.icon-comments:before { + content: "\f086"; +} +.icon-thumbs-up-alt:before { + content: "\f087"; +} +.icon-thumbs-down-alt:before { + content: "\f088"; +} +.icon-star-half:before { + content: "\f089"; +} +.icon-heart-empty:before { + content: "\f08a"; +} +.icon-signout:before { + content: "\f08b"; +} +.icon-linkedin-sign:before { + content: "\f08c"; +} +.icon-pushpin:before { + content: "\f08d"; +} +.icon-external-link:before { + content: "\f08e"; +} +.icon-signin:before { + content: "\f090"; +} +.icon-trophy:before { + content: "\f091"; +} +.icon-github-sign:before { + content: "\f092"; +} +.icon-upload-alt:before { + content: "\f093"; +} +.icon-lemon:before { + content: "\f094"; +} +.icon-phone:before { + content: "\f095"; +} +.icon-unchecked:before, +.icon-check-empty:before { + content: "\f096"; +} +.icon-bookmark-empty:before { + content: "\f097"; +} +.icon-phone-sign:before { + content: "\f098"; +} +.icon-twitter:before { + content: "\f099"; +} +.icon-facebook:before { + content: "\f09a"; +} +.icon-github:before { + content: "\f09b"; +} +.icon-unlock:before { + content: "\f09c"; +} +.icon-credit-card:before { + content: "\f09d"; +} +.icon-rss:before { + content: "\f09e"; +} +.icon-hdd:before { + content: "\f0a0"; +} +.icon-bullhorn:before { + content: "\f0a1"; +} +.icon-bell:before { + content: "\f0a2"; +} +.icon-certificate:before { + content: "\f0a3"; +} +.icon-hand-right:before { + content: "\f0a4"; +} +.icon-hand-left:before { + content: "\f0a5"; +} +.icon-hand-up:before { + content: "\f0a6"; +} +.icon-hand-down:before { + content: "\f0a7"; +} +.icon-circle-arrow-left:before { + content: "\f0a8"; +} +.icon-circle-arrow-right:before { + content: "\f0a9"; +} +.icon-circle-arrow-up:before { + content: "\f0aa"; +} +.icon-circle-arrow-down:before { + content: "\f0ab"; +} +.icon-globe:before { + content: "\f0ac"; +} +.icon-wrench:before { + content: "\f0ad"; +} +.icon-tasks:before { + content: "\f0ae"; +} +.icon-filter:before { + content: "\f0b0"; +} +.icon-briefcase:before { + content: "\f0b1"; +} +.icon-fullscreen:before { + content: "\f0b2"; +} +.icon-group:before { + content: "\f0c0"; +} +.icon-link:before { + content: "\f0c1"; +} +.icon-cloud:before { + content: "\f0c2"; +} +.icon-beaker:before { + content: "\f0c3"; +} +.icon-cut:before { + content: "\f0c4"; +} +.icon-copy:before { + content: "\f0c5"; +} +.icon-paperclip:before, +.icon-paper-clip:before { + content: "\f0c6"; +} +.icon-save:before { + content: "\f0c7"; +} +.icon-sign-blank:before { + content: "\f0c8"; +} +.icon-reorder:before { + content: "\f0c9"; +} +.icon-list-ul:before { + content: "\f0ca"; +} +.icon-list-ol:before { + content: "\f0cb"; +} +.icon-strikethrough:before { + content: "\f0cc"; +} +.icon-underline:before { + content: "\f0cd"; +} +.icon-table:before { + content: "\f0ce"; +} +.icon-magic:before { + content: "\f0d0"; +} +.icon-truck:before { + content: "\f0d1"; +} +.icon-pinterest:before { + content: "\f0d2"; +} +.icon-pinterest-sign:before { + content: "\f0d3"; +} +.icon-google-plus-sign:before { + content: "\f0d4"; +} +.icon-google-plus:before { + content: "\f0d5"; +} +.icon-money:before { + content: "\f0d6"; +} +.icon-caret-down:before { + content: "\f0d7"; +} +.icon-caret-up:before { + content: "\f0d8"; +} +.icon-caret-left:before { + content: "\f0d9"; +} +.icon-caret-right:before { + content: "\f0da"; +} +.icon-columns:before { + content: "\f0db"; +} +.icon-sort:before { + content: "\f0dc"; +} +.icon-sort-down:before { + content: "\f0dd"; +} +.icon-sort-up:before { + content: "\f0de"; +} +.icon-envelope:before { + content: "\f0e0"; +} +.icon-linkedin:before { + content: "\f0e1"; +} +.icon-rotate-left:before, +.icon-undo:before { + content: "\f0e2"; +} +.icon-legal:before { + content: "\f0e3"; +} +.icon-dashboard:before { + content: "\f0e4"; +} +.icon-comment-alt:before { + content: "\f0e5"; +} +.icon-comments-alt:before { + content: "\f0e6"; +} +.icon-bolt:before { + content: "\f0e7"; +} +.icon-sitemap:before { + content: "\f0e8"; +} +.icon-umbrella:before { + content: "\f0e9"; +} +.icon-paste:before { + content: "\f0ea"; +} +.icon-lightbulb:before { + content: "\f0eb"; +} +.icon-exchange:before { + content: "\f0ec"; +} +.icon-cloud-download:before { + content: "\f0ed"; +} +.icon-cloud-upload:before { + content: "\f0ee"; +} +.icon-user-md:before { + content: "\f0f0"; +} +.icon-stethoscope:before { + content: "\f0f1"; +} +.icon-suitcase:before { + content: "\f0f2"; +} +.icon-bell-alt:before { + content: "\f0f3"; +} +.icon-coffee:before { + content: "\f0f4"; +} +.icon-food:before { + content: "\f0f5"; +} +.icon-file-text-alt:before { + content: "\f0f6"; +} +.icon-building:before { + content: "\f0f7"; +} +.icon-hospital:before { + content: "\f0f8"; +} +.icon-ambulance:before { + content: "\f0f9"; +} +.icon-medkit:before { + content: "\f0fa"; +} +.icon-fighter-jet:before { + content: "\f0fb"; +} +.icon-beer:before { + content: "\f0fc"; +} +.icon-h-sign:before { + content: "\f0fd"; +} +.icon-plus-sign-alt:before { + content: "\f0fe"; +} +.icon-double-angle-left:before { + content: "\f100"; +} +.icon-double-angle-right:before { + content: "\f101"; +} +.icon-double-angle-up:before { + content: "\f102"; +} +.icon-double-angle-down:before { + content: "\f103"; +} +.icon-angle-left:before { + content: "\f104"; +} +.icon-angle-right:before { + content: "\f105"; +} +.icon-angle-up:before { + content: "\f106"; +} +.icon-angle-down:before { + content: "\f107"; +} +.icon-desktop:before { + content: "\f108"; +} +.icon-laptop:before { + content: "\f109"; +} +.icon-tablet:before { + content: "\f10a"; +} +.icon-mobile-phone:before { + content: "\f10b"; +} +.icon-circle-blank:before { + content: "\f10c"; +} +.icon-quote-left:before { + content: "\f10d"; +} +.icon-quote-right:before { + content: "\f10e"; +} +.icon-spinner:before { + content: "\f110"; +} +.icon-circle:before { + content: "\f111"; +} +.icon-mail-reply:before, +.icon-reply:before { + content: "\f112"; +} +.icon-github-alt:before { + content: "\f113"; +} +.icon-folder-close-alt:before { + content: "\f114"; +} +.icon-folder-open-alt:before { + content: "\f115"; +} +.icon-expand-alt:before { + content: "\f116"; +} +.icon-collapse-alt:before { + content: "\f117"; +} +.icon-smile:before { + content: "\f118"; +} +.icon-frown:before { + content: "\f119"; +} +.icon-meh:before { + content: "\f11a"; +} +.icon-gamepad:before { + content: "\f11b"; +} +.icon-keyboard:before { + content: "\f11c"; +} +.icon-flag-alt:before { + content: "\f11d"; +} +.icon-flag-checkered:before { + content: "\f11e"; +} +.icon-terminal:before { + content: "\f120"; +} +.icon-code:before { + content: "\f121"; +} +.icon-reply-all:before { + content: "\f122"; +} +.icon-mail-reply-all:before { + content: "\f122"; +} +.icon-star-half-full:before, +.icon-star-half-empty:before { + content: "\f123"; +} +.icon-location-arrow:before { + content: "\f124"; +} +.icon-crop:before { + content: "\f125"; +} +.icon-code-fork:before { + content: "\f126"; +} +.icon-unlink:before { + content: "\f127"; +} +.icon-question:before { + content: "\f128"; +} +.icon-info:before { + content: "\f129"; +} +.icon-exclamation:before { + content: "\f12a"; +} +.icon-superscript:before { + content: "\f12b"; +} +.icon-subscript:before { + content: "\f12c"; +} +.icon-eraser:before { + content: "\f12d"; +} +.icon-puzzle-piece:before { + content: "\f12e"; +} +.icon-microphone:before { + content: "\f130"; +} +.icon-microphone-off:before { + content: "\f131"; +} +.icon-shield:before { + content: "\f132"; +} +.icon-calendar-empty:before { + content: "\f133"; +} +.icon-fire-extinguisher:before { + content: "\f134"; +} +.icon-rocket:before { + content: "\f135"; +} +.icon-maxcdn:before { + content: "\f136"; +} +.icon-chevron-sign-left:before { + content: "\f137"; +} +.icon-chevron-sign-right:before { + content: "\f138"; +} +.icon-chevron-sign-up:before { + content: "\f139"; +} +.icon-chevron-sign-down:before { + content: "\f13a"; +} +.icon-html5:before { + content: "\f13b"; +} +.icon-css3:before { + content: "\f13c"; +} +.icon-anchor:before { + content: "\f13d"; +} +.icon-unlock-alt:before { + content: "\f13e"; +} +.icon-bullseye:before { + content: "\f140"; +} +.icon-ellipsis-horizontal:before { + content: "\f141"; +} +.icon-ellipsis-vertical:before { + content: "\f142"; +} +.icon-rss-sign:before { + content: "\f143"; +} +.icon-play-sign:before { + content: "\f144"; +} +.icon-ticket:before { + content: "\f145"; +} +.icon-minus-sign-alt:before { + content: "\f146"; +} +.icon-check-minus:before { + content: "\f147"; +} +.icon-level-up:before { + content: "\f148"; +} +.icon-level-down:before { + content: "\f149"; +} +.icon-check-sign:before { + content: "\f14a"; +} +.icon-edit-sign:before { + content: "\f14b"; +} +.icon-external-link-sign:before { + content: "\f14c"; +} +.icon-share-sign:before { + content: "\f14d"; +} +.icon-compass:before { + content: "\f14e"; +} +.icon-collapse:before { + content: "\f150"; +} +.icon-collapse-top:before { + content: "\f151"; +} +.icon-expand:before { + content: "\f152"; +} +.icon-euro:before, +.icon-eur:before { + content: "\f153"; +} +.icon-gbp:before { + content: "\f154"; +} +.icon-dollar:before, +.icon-usd:before { + content: "\f155"; +} +.icon-rupee:before, +.icon-inr:before { + content: "\f156"; +} +.icon-yen:before, +.icon-jpy:before { + content: "\f157"; +} +.icon-renminbi:before, +.icon-cny:before { + content: "\f158"; +} +.icon-won:before, +.icon-krw:before { + content: "\f159"; +} +.icon-bitcoin:before, +.icon-btc:before { + content: "\f15a"; +} +.icon-file:before { + content: "\f15b"; +} +.icon-file-text:before { + content: "\f15c"; +} +.icon-sort-by-alphabet:before { + content: "\f15d"; +} +.icon-sort-by-alphabet-alt:before { + content: "\f15e"; +} +.icon-sort-by-attributes:before { + content: "\f160"; +} +.icon-sort-by-attributes-alt:before { + content: "\f161"; +} +.icon-sort-by-order:before { + content: "\f162"; +} +.icon-sort-by-order-alt:before { + content: "\f163"; +} +.icon-thumbs-up:before { + content: "\f164"; +} +.icon-thumbs-down:before { + content: "\f165"; +} +.icon-youtube-sign:before { + content: "\f166"; +} +.icon-youtube:before { + content: "\f167"; +} +.icon-xing:before { + content: "\f168"; +} +.icon-xing-sign:before { + content: "\f169"; +} +.icon-youtube-play:before { + content: "\f16a"; +} +.icon-dropbox:before { + content: "\f16b"; +} +.icon-stackexchange:before { + content: "\f16c"; +} +.icon-instagram:before { + content: "\f16d"; +} +.icon-flickr:before { + content: "\f16e"; +} +.icon-adn:before { + content: "\f170"; +} +.icon-bitbucket:before { + content: "\f171"; +} +.icon-bitbucket-sign:before { + content: "\f172"; +} +.icon-tumblr:before { + content: "\f173"; +} +.icon-tumblr-sign:before { + content: "\f174"; +} +.icon-long-arrow-down:before { + content: "\f175"; +} +.icon-long-arrow-up:before { + content: "\f176"; +} +.icon-long-arrow-left:before { + content: "\f177"; +} +.icon-long-arrow-right:before { + content: "\f178"; +} +.icon-apple:before { + content: "\f179"; +} +.icon-windows:before { + content: "\f17a"; +} +.icon-android:before { + content: "\f17b"; +} +.icon-linux:before { + content: "\f17c"; +} +.icon-dribbble:before { + content: "\f17d"; +} +.icon-skype:before { + content: "\f17e"; +} +.icon-foursquare:before { + content: "\f180"; +} +.icon-trello:before { + content: "\f181"; +} +.icon-female:before { + content: "\f182"; +} +.icon-male:before { + content: "\f183"; +} +.icon-gittip:before { + content: "\f184"; +} +.icon-sun:before { + content: "\f185"; +} +.icon-moon:before { + content: "\f186"; +} +.icon-archive:before { + content: "\f187"; +} +.icon-bug:before { + content: "\f188"; +} +.icon-vk:before { + content: "\f189"; +} +.icon-weibo:before { + content: "\f18a"; +} +.icon-renren:before { + content: "\f18b"; } -li[class^="icon-"].icon-large:before, li[class*=" icon-"].icon-large:before { - text-indent: -1.3333333333333333em; -} -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen - readers do not read off random characters that represent icons */ -.icon-glass:before { content: "\f000"; } -.icon-music:before { content: "\f001"; } -.icon-search:before { content: "\f002"; } -.icon-envelope:before { content: "\f003"; } -.icon-heart:before { content: "\f004"; } -.icon-star:before { content: "\f005"; } -.icon-star-empty:before { content: "\f006"; } -.icon-user:before { content: "\f007"; } -.icon-film:before { content: "\f008"; } -.icon-th-large:before { content: "\f009"; } -.icon-th:before { content: "\f00a"; } -.icon-th-list:before { content: "\f00b"; } -.icon-ok:before { content: "\f00c"; } -.icon-remove:before { content: "\f00d"; } -.icon-zoom-in:before { content: "\f00e"; } - -.icon-zoom-out:before { content: "\f010"; } -.icon-off:before { content: "\f011"; } -.icon-signal:before { content: "\f012"; } -.icon-cog:before { content: "\f013"; } -.icon-trash:before { content: "\f014"; } -.icon-home:before { content: "\f015"; } -.icon-file:before { content: "\f016"; } -.icon-time:before { content: "\f017"; } -.icon-road:before { content: "\f018"; } -.icon-download-alt:before { content: "\f019"; } -.icon-download:before { content: "\f01a"; } -.icon-upload:before { content: "\f01b"; } -.icon-inbox:before { content: "\f01c"; } -.icon-play-circle:before { content: "\f01d"; } -.icon-repeat:before { content: "\f01e"; } - -/* \f020 doesn't work in Safari. all shifted one down */ -.icon-refresh:before { content: "\f021"; } -.icon-list-alt:before { content: "\f022"; } -.icon-lock:before { content: "\f023"; } -.icon-flag:before { content: "\f024"; } -.icon-headphones:before { content: "\f025"; } -.icon-volume-off:before { content: "\f026"; } -.icon-volume-down:before { content: "\f027"; } -.icon-volume-up:before { content: "\f028"; } -.icon-qrcode:before { content: "\f029"; } -.icon-barcode:before { content: "\f02a"; } -.icon-tag:before { content: "\f02b"; } -.icon-tags:before { content: "\f02c"; } -.icon-book:before { content: "\f02d"; } -.icon-bookmark:before { content: "\f02e"; } -.icon-print:before { content: "\f02f"; } - -.icon-camera:before { content: "\f030"; } -.icon-font:before { content: "\f031"; } -.icon-bold:before { content: "\f032"; } -.icon-italic:before { content: "\f033"; } -.icon-text-height:before { content: "\f034"; } -.icon-text-width:before { content: "\f035"; } -.icon-align-left:before { content: "\f036"; } -.icon-align-center:before { content: "\f037"; } -.icon-align-right:before { content: "\f038"; } -.icon-align-justify:before { content: "\f039"; } -.icon-list:before { content: "\f03a"; } -.icon-indent-left:before { content: "\f03b"; } -.icon-indent-right:before { content: "\f03c"; } -.icon-facetime-video:before { content: "\f03d"; } -.icon-picture:before { content: "\f03e"; } - -.icon-pencil:before { content: "\f040"; } -.icon-map-marker:before { content: "\f041"; } -.icon-adjust:before { content: "\f042"; } -.icon-tint:before { content: "\f043"; } -.icon-edit:before { content: "\f044"; } -.icon-share:before { content: "\f045"; } -.icon-check:before { content: "\f046"; } -.icon-move:before { content: "\f047"; } -.icon-step-backward:before { content: "\f048"; } -.icon-fast-backward:before { content: "\f049"; } -.icon-backward:before { content: "\f04a"; } -.icon-play:before { content: "\f04b"; } -.icon-pause:before { content: "\f04c"; } -.icon-stop:before { content: "\f04d"; } -.icon-forward:before { content: "\f04e"; } - -.icon-fast-forward:before { content: "\f050"; } -.icon-step-forward:before { content: "\f051"; } -.icon-eject:before { content: "\f052"; } -.icon-chevron-left:before { content: "\f053"; } -.icon-chevron-right:before { content: "\f054"; } -.icon-plus-sign:before { content: "\f055"; } -.icon-minus-sign:before { content: "\f056"; } -.icon-remove-sign:before { content: "\f057"; } -.icon-ok-sign:before { content: "\f058"; } -.icon-question-sign:before { content: "\f059"; } -.icon-info-sign:before { content: "\f05a"; } -.icon-screenshot:before { content: "\f05b"; } -.icon-remove-circle:before { content: "\f05c"; } -.icon-ok-circle:before { content: "\f05d"; } -.icon-ban-circle:before { content: "\f05e"; } - -.icon-arrow-left:before { content: "\f060"; } -.icon-arrow-right:before { content: "\f061"; } -.icon-arrow-up:before { content: "\f062"; } -.icon-arrow-down:before { content: "\f063"; } -.icon-share-alt:before { content: "\f064"; } -.icon-resize-full:before { content: "\f065"; } -.icon-resize-small:before { content: "\f066"; } -.icon-plus:before { content: "\f067"; } -.icon-minus:before { content: "\f068"; } -.icon-asterisk:before { content: "\f069"; } -.icon-exclamation-sign:before { content: "\f06a"; } -.icon-gift:before { content: "\f06b"; } -.icon-leaf:before { content: "\f06c"; } -.icon-fire:before { content: "\f06d"; } -.icon-eye-open:before { content: "\f06e"; } - -.icon-eye-close:before { content: "\f070"; } -.icon-warning-sign:before { content: "\f071"; } -.icon-plane:before { content: "\f072"; } -.icon-calendar:before { content: "\f073"; } -.icon-random:before { content: "\f074"; } -.icon-comment:before { content: "\f075"; } -.icon-magnet:before { content: "\f076"; } -.icon-chevron-up:before { content: "\f077"; } -.icon-chevron-down:before { content: "\f078"; } -.icon-retweet:before { content: "\f079"; } -.icon-shopping-cart:before { content: "\f07a"; } -.icon-folder-close:before { content: "\f07b"; } -.icon-folder-open:before { content: "\f07c"; } -.icon-resize-vertical:before { content: "\f07d"; } -.icon-resize-horizontal:before { content: "\f07e"; } - -.icon-bar-chart:before { content: "\f080"; } -.icon-twitter-sign:before { content: "\f081"; } -.icon-facebook-sign:before { content: "\f082"; } -.icon-camera-retro:before { content: "\f083"; } -.icon-key:before { content: "\f084"; } -.icon-cogs:before { content: "\f085"; } -.icon-comments:before { content: "\f086"; } -.icon-thumbs-up:before { content: "\f087"; } -.icon-thumbs-down:before { content: "\f088"; } -.icon-star-half:before { content: "\f089"; } -.icon-heart-empty:before { content: "\f08a"; } -.icon-signout:before { content: "\f08b"; } -.icon-linkedin-sign:before { content: "\f08c"; } -.icon-pushpin:before { content: "\f08d"; } -.icon-external-link:before { content: "\f08e"; } - -.icon-signin:before { content: "\f090"; } -.icon-trophy:before { content: "\f091"; } -.icon-github-sign:before { content: "\f092"; } -.icon-upload-alt:before { content: "\f093"; } -.icon-lemon:before { content: "\f094"; } -.icon-phone:before { content: "\f095"; } -.icon-check-empty:before { content: "\f096"; } -.icon-bookmark-empty:before { content: "\f097"; } -.icon-phone-sign:before { content: "\f098"; } -.icon-twitter:before { content: "\f099"; } -.icon-facebook:before { content: "\f09a"; } -.icon-github:before { content: "\f09b"; } -.icon-unlock:before { content: "\f09c"; } -.icon-credit-card:before { content: "\f09d"; } -.icon-rss:before { content: "\f09e"; } - -.icon-hdd:before { content: "\f0a0"; } -.icon-bullhorn:before { content: "\f0a1"; } -.icon-bell:before { content: "\f0a2"; } -.icon-certificate:before { content: "\f0a3"; } -.icon-hand-right:before { content: "\f0a4"; } -.icon-hand-left:before { content: "\f0a5"; } -.icon-hand-up:before { content: "\f0a6"; } -.icon-hand-down:before { content: "\f0a7"; } -.icon-circle-arrow-left:before { content: "\f0a8"; } -.icon-circle-arrow-right:before { content: "\f0a9"; } -.icon-circle-arrow-up:before { content: "\f0aa"; } -.icon-circle-arrow-down:before { content: "\f0ab"; } -.icon-globe:before { content: "\f0ac"; } -.icon-wrench:before { content: "\f0ad"; } -.icon-tasks:before { content: "\f0ae"; } - -.icon-filter:before { content: "\f0b0"; } -.icon-briefcase:before { content: "\f0b1"; } -.icon-fullscreen:before { content: "\f0b2"; } - -.icon-group:before { content: "\f0c0"; } -.icon-link:before { content: "\f0c1"; } -.icon-cloud:before { content: "\f0c2"; } -.icon-beaker:before { content: "\f0c3"; } -.icon-cut:before { content: "\f0c4"; } -.icon-copy:before { content: "\f0c5"; } -.icon-paper-clip:before { content: "\f0c6"; } -.icon-save:before { content: "\f0c7"; } -.icon-sign-blank:before { content: "\f0c8"; } -.icon-reorder:before { content: "\f0c9"; } -.icon-list-ul:before { content: "\f0ca"; } -.icon-list-ol:before { content: "\f0cb"; } -.icon-strikethrough:before { content: "\f0cc"; } -.icon-underline:before { content: "\f0cd"; } -.icon-table:before { content: "\f0ce"; } - -.icon-magic:before { content: "\f0d0"; } -.icon-truck:before { content: "\f0d1"; } -.icon-pinterest:before { content: "\f0d2"; } -.icon-pinterest-sign:before { content: "\f0d3"; } -.icon-google-plus-sign:before { content: "\f0d4"; } -.icon-google-plus:before { content: "\f0d5"; } -.icon-money:before { content: "\f0d6"; } -.icon-caret-down:before { content: "\f0d7"; } -.icon-caret-up:before { content: "\f0d8"; } -.icon-caret-left:before { content: "\f0d9"; } -.icon-caret-right:before { content: "\f0da"; } -.icon-columns:before { content: "\f0db"; } -.icon-sort:before { content: "\f0dc"; } -.icon-sort-down:before { content: "\f0dd"; } -.icon-sort-up:before { content: "\f0de"; } - -.icon-envelope-alt:before { content: "\f0e0"; } -.icon-linkedin:before { content: "\f0e1"; } -.icon-undo:before { content: "\f0e2"; } -.icon-legal:before { content: "\f0e3"; } -.icon-dashboard:before { content: "\f0e4"; } -.icon-comment-alt:before { content: "\f0e5"; } -.icon-comments-alt:before { content: "\f0e6"; } -.icon-bolt:before { content: "\f0e7"; } -.icon-sitemap:before { content: "\f0e8"; } -.icon-umbrella:before { content: "\f0e9"; } -.icon-paste:before { content: "\f0ea"; } - -.icon-user-md:before { content: "\f200"; } -- cgit v1.2.3 From 99c64d55067fb301910a6626f3bbd2ce8ab30a6d Mon Sep 17 00:00:00 2001 From: micpango Date: Wed, 28 Aug 2013 15:23:58 +0200 Subject: Make relative to allow running on sub-path --- javascripts/dashing.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index d24bf54..ee4b6d4 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -92,7 +92,7 @@ Dashing.widgets = widgets = {} Dashing.lastEvents = lastEvents = {} Dashing.debugMode = false -source = new EventSource('/events') +source = new EventSource('events') source.addEventListener 'open', (e) -> console.log("Connection opened") -- cgit v1.2.3 From e11d3c270c297ba6de2fbc685c74bd67455c83fb Mon Sep 17 00:00:00 2001 From: John Tajima Date: Fri, 30 Aug 2013 16:53:59 +0000 Subject: Fixes event connection close error never re-establishes connection. Fix EventListener connection close check. console log the event on error and connection. Reload current page on connection close error event. --- javascripts/dashing.coffee | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index ee4b6d4..235a965 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -94,12 +94,15 @@ Dashing.debugMode = false source = new EventSource('events') source.addEventListener 'open', (e) -> - console.log("Connection opened") + console.log("Connection opened", e) source.addEventListener 'error', (e)-> - console.log("Connection error") - if (e.readyState == EventSource.CLOSED) + console.log("Connection error", e) + if (e.currentTarget.readyState == EventSource.CLOSED) console.log("Connection closed") + setTimeout (-> + window.location.reload() + ), 10000 source.addEventListener 'message', (e) -> data = JSON.parse(e.data) -- cgit v1.2.3 From 833d995ececc2b26ae791535774f383a1daa9da8 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Mon, 2 Sep 2013 13:04:25 +0200 Subject: Remove silly label --- templates/project/dashboards/sampletv.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/project/dashboards/sampletv.erb b/templates/project/dashboards/sampletv.erb index b88e636..cf4b39c 100644 --- a/templates/project/dashboards/sampletv.erb +++ b/templates/project/dashboards/sampletv.erb @@ -43,7 +43,7 @@ $(function() {
  • -
    +
  • -- cgit v1.2.3 From 7b4cc3e123eefc82674ff7ea68d127dc5a84779e Mon Sep 17 00:00:00 2001 From: John Tajima Date: Tue, 3 Sep 2013 13:35:31 +0000 Subject: change reload to 5 minutes --- javascripts/dashing.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index 235a965..fa677e8 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -102,7 +102,7 @@ source.addEventListener 'error', (e)-> console.log("Connection closed") setTimeout (-> window.location.reload() - ), 10000 + ), 5*60*1000 source.addEventListener 'message', (e) -> data = JSON.parse(e.data) -- cgit v1.2.3 From eb331a2fab101b93bce0a5b87e06927f324c96b8 Mon Sep 17 00:00:00 2001 From: Jordan Wheeler Date: Mon, 9 Sep 2013 15:34:08 -0400 Subject: add firebase gems --- dashing.gemspec | 1 + lib/dashing.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/dashing.gemspec b/dashing.gemspec index 050266b..3e9fc83 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -25,5 +25,6 @@ Gem::Specification.new do |s| s.add_dependency('thor') s.add_dependency('sprockets') s.add_dependency('rack') + s.add_dependency('firebase') end \ No newline at end of file diff --git a/lib/dashing.rb b/lib/dashing.rb index 2c3a810..d4a8c11 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -6,6 +6,7 @@ require 'coffee-script' require 'sass' require 'json' require 'yaml' +require 'firebase' SCHEDULER = Rufus::Scheduler.start_new -- cgit v1.2.3 From b81273772effd5300bfd970abffedad3d0362dbf Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Mon, 9 Sep 2013 21:38:53 +0200 Subject: Revert "Merge pull request #226 from jordanwheeler/use-firebase" This reverts commit a4cdeb81c2cba2b7028f342d56abac22f101bf78, reversing changes made to 2671d387e3c9b845431d41ab93d51cf2bd7b2cf8. --- dashing.gemspec | 1 - lib/dashing.rb | 1 - 2 files changed, 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 3e9fc83..050266b 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -25,6 +25,5 @@ Gem::Specification.new do |s| s.add_dependency('thor') s.add_dependency('sprockets') s.add_dependency('rack') - s.add_dependency('firebase') end \ No newline at end of file diff --git a/lib/dashing.rb b/lib/dashing.rb index d4a8c11..2c3a810 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -6,7 +6,6 @@ require 'coffee-script' require 'sass' require 'json' require 'yaml' -require 'firebase' SCHEDULER = Rufus::Scheduler.start_new -- cgit v1.2.3 From 68836c6471f00e309cf84d26acdbb9eb23a8c5a0 Mon Sep 17 00:00:00 2001 From: Milen Pavlov Date: Wed, 11 Sep 2013 17:33:18 -0400 Subject: gitignore history.yml --- templates/project/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/project/.gitignore b/templates/project/.gitignore index ba646ec..e1be11e 100644 --- a/templates/project/.gitignore +++ b/templates/project/.gitignore @@ -1 +1,2 @@ *DS_STORE +history.yml -- cgit v1.2.3 From a05fb1b50adbb69d1b60b47de0997734da309341 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Thu, 19 Sep 2013 15:03:52 +0200 Subject: Add Travis CI support. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6553133 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: ruby +rvm: + - 2.0.0 + - 1.9.3 \ No newline at end of file -- cgit v1.2.3 From c973499200337b4a343f5df94776fc7b43ceffec Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Thu, 19 Sep 2013 15:06:57 +0200 Subject: Update Readme to include travis CI build status. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9e0efef..01010e0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # [Dashing](http://shopify.github.com/dashing) +![](https://api.travis-ci.org/Shopify/dashing.png) Dashing is a Sinatra based framework that lets you build beautiful dashboards. It looks especially great on TVs. -- cgit v1.2.3 From 795eb52d4e7f9862016caf1f3b9fc54aba7443f7 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Thu, 19 Sep 2013 15:22:41 +0200 Subject: Fix travisCI config to not use a bundled version of rake. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6553133..cbb92e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: ruby rvm: - 2.0.0 - - 1.9.3 \ No newline at end of file + - 1.9.3 + +script: "rake test" \ No newline at end of file -- cgit v1.2.3 From 2c8193105c1682bb445f8fbc33c95f4cb1ba7372 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Wed, 2 Oct 2013 10:01:02 -0400 Subject: Locks rufus to version 2.x --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 050266b..e02ed24 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency('sinatra') s.add_dependency('sinatra-contrib') s.add_dependency('thin') - s.add_dependency('rufus-scheduler') + s.add_dependency('rufus-scheduler', '~> 2.0') s.add_dependency('thor') s.add_dependency('sprockets') s.add_dependency('rack') -- cgit v1.2.3 From 540aefd832248675d3a96db26d46ee4d7f095ae3 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Wed, 2 Oct 2013 10:04:33 -0400 Subject: bump minor version number for release --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index e02ed24..5e74d5e 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.2.0' + s.version = '1.3.0' s.date = '2013-07-29' s.executables << 'dashing' -- cgit v1.2.3 From a9edc7ebfa22a85e7e98baf42f6662ece6a37fe9 Mon Sep 17 00:00:00 2001 From: Sangman Kim Date: Sat, 5 Oct 2013 23:32:41 -0500 Subject: fix url for fontawesome changed url from ../fonts/ to ../assets/ so that dashing can work with its own url scheme. --- templates/project/assets/stylesheets/font-awesome.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/project/assets/stylesheets/font-awesome.css b/templates/project/assets/stylesheets/font-awesome.css index e6f5216..69ae843 100644 --- a/templates/project/assets/stylesheets/font-awesome.css +++ b/templates/project/assets/stylesheets/font-awesome.css @@ -27,8 +27,8 @@ * -------------------------- */ @font-face { font-family: 'FontAwesome'; - src: url('../fonts/fontawesome-webfont.eot?v=3.2.1'); - src: url('../fonts/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../fonts/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg'); + src: url('../assets/fontawesome-webfont.eot?v=3.2.1'); + src: url('../assets/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../assets/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../assets/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../assets/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg'); font-weight: normal; font-style: normal; } -- cgit v1.2.3 From 40280457824cdeb8611aefb882faaa9e721d36b0 Mon Sep 17 00:00:00 2001 From: David Underwood Date: Sun, 6 Oct 2013 11:40:59 -0400 Subject: bumps patch version --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 5e74d5e..626f434 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.3.0' + s.version = '1.3.1' s.date = '2013-07-29' s.executables << 'dashing' -- cgit v1.2.3 From 7ca9e828423d6e19a9b85fc3dbc8f5d8696e937e Mon Sep 17 00:00:00 2001 From: John Tajima Date: Wed, 30 Oct 2013 19:34:45 -0400 Subject: Define a KEYS constant --- lib/dashing.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/dashing.rb b/lib/dashing.rb index 2c3a810..f1b18fc 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -8,6 +8,7 @@ require 'json' require 'yaml' SCHEDULER = Rufus::Scheduler.start_new +KEYS = {} set :root, Dir.pwd -- cgit v1.2.3 From 4177623a7a5e7967514a0d92095e0dcb32896026 Mon Sep 17 00:00:00 2001 From: John Tajima Date: Wed, 30 Oct 2013 19:57:07 -0400 Subject: require config/settings.rb if exists --- lib/dashing.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/dashing.rb b/lib/dashing.rb index f1b18fc..a8e9f33 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -8,7 +8,6 @@ require 'json' require 'yaml' SCHEDULER = Rufus::Scheduler.start_new -KEYS = {} set :root, Dir.pwd @@ -155,6 +154,11 @@ def tilt_html_engines end end +settings_file = File.join(settings.root, 'config/settings.rb') +if (File.exists?(settings_file)) + require settings_file +end + Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } {}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. -- cgit v1.2.3 From 5b045724acd44e691552c0fb8f86b61aa2e0cd06 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Thu, 21 Nov 2013 17:50:11 +0100 Subject: Update to use the new Twitter 5.0.0 gem. --- dashing.gemspec | 5 +++-- templates/project/Gemfile | 2 +- templates/project/jobs/twitter.rb | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 626f434..61c0b3b 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.3.1' - s.date = '2013-07-29' + s.version = '1.3.2' + s.date = '2013-11-21' s.executables << 'dashing' @@ -18,6 +18,7 @@ Gem::Specification.new do |s| s.add_dependency('sass') s.add_dependency('coffee-script', '>=1.6.2') + s.add_dependency('execjs', '>=2.0.0') s.add_dependency('sinatra') s.add_dependency('sinatra-contrib') s.add_dependency('thin') diff --git a/templates/project/Gemfile b/templates/project/Gemfile index e6ccd84..3c7e7a9 100644 --- a/templates/project/Gemfile +++ b/templates/project/Gemfile @@ -3,4 +3,4 @@ source 'https://rubygems.org' gem 'dashing' ## Remove this if you don't need a twitter widget. -gem 'twitter' \ No newline at end of file +gem 'twitter', '>= 5.0.0' \ No newline at end of file diff --git a/templates/project/jobs/twitter.rb b/templates/project/jobs/twitter.rb index 5e70f30..26228bc 100644 --- a/templates/project/jobs/twitter.rb +++ b/templates/project/jobs/twitter.rb @@ -3,7 +3,7 @@ require 'twitter' #### Get your twitter keys & secrets: #### https://dev.twitter.com/docs/auth/tokens-devtwittercom -Twitter.configure do |config| +twitter = Twitter::REST::Client.new do |config| config.consumer_key = 'YOUR_CONSUMER_KEY' config.consumer_secret = 'YOUR_CONSUMER_SECRET' config.oauth_token = 'YOUR_OAUTH_TOKEN' @@ -14,10 +14,10 @@ search_term = URI::encode('#todayilearned') SCHEDULER.every '10m', :first_in => 0 do |job| begin - tweets = Twitter.search("#{search_term}").results + tweets = twitter.search("#{search_term}") if tweets - tweets.map! do |tweet| + tweets = tweets.map do |tweet| { name: tweet.user.name, body: tweet.text, avatar: tweet.user.profile_image_url_https } end send_event('twitter_mentions', comments: tweets) -- cgit v1.2.3 From 4a042c5cfef6d29d509af12830d11304578fa6aa Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Wed, 18 Dec 2013 15:43:46 -0500 Subject: adding pessimistic versioning for gem dependencies --- .ruby-version | 1 + dashing.gemspec | 23 +++++++++++------------ lib/dashing.rb | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..7fa1d1e --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.0.0-p353 diff --git a/dashing.gemspec b/dashing.gemspec index 61c0b3b..3193bd7 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -11,20 +11,19 @@ Gem::Specification.new do |s| s.description = "This framework lets you build & easily layout dashboards with your own custom widgets. Use it to make a status boards for your ops team, or use it to track signups, conversion rates, or whatever else metrics you'd like to see in one spot. Included with the framework are ready-made widgets for you to use or customize. All of this code was extracted out of a project at Shopify that displays dashboards on TVs around the office." s.author = "Daniel Beauchamp" s.email = 'daniel.beauchamp@shopify.com' - s.files = ["lib/Dashing.rb"] s.homepage = 'http://shopify.github.com/dashing' s.files = Dir['README.md', 'javascripts/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] - s.add_dependency('sass') - s.add_dependency('coffee-script', '>=1.6.2') - s.add_dependency('execjs', '>=2.0.0') - s.add_dependency('sinatra') - s.add_dependency('sinatra-contrib') - s.add_dependency('thin') - s.add_dependency('rufus-scheduler', '~> 2.0') - s.add_dependency('thor') - s.add_dependency('sprockets') - s.add_dependency('rack') + s.add_dependency('sass', '~> 3.2.12') + s.add_dependency('coffee-script', '~> 2.2.0') + s.add_dependency('execjs', '~> 2.0.2') + s.add_dependency('sinatra', '~> 1.4.4') + s.add_dependency('sinatra-contrib', '~> 1.4.2') + s.add_dependency('thin', '~> 1.6.1') + s.add_dependency('rufus-scheduler', '~> 3.0.3') + s.add_dependency('thor', '~> 0.18.1') + s.add_dependency('sprockets', '~> 2.10.1') + s.add_dependency('rack', '~> 1.5.2') -end \ No newline at end of file +end diff --git a/lib/dashing.rb b/lib/dashing.rb index a8e9f33..7c4f25a 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -7,7 +7,7 @@ require 'sass' require 'json' require 'yaml' -SCHEDULER = Rufus::Scheduler.start_new +SCHEDULER = Rufus::Scheduler.new set :root, Dir.pwd -- cgit v1.2.3 From 69ed82efa8319e7fbde9df95a4fad4ee96aa5074 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Wed, 18 Dec 2013 15:49:32 -0500 Subject: adding haml to dev dependencies so all tests run --- dashing.gemspec | 3 +++ test/app_test.rb | 37 ++++++++++++++++--------------------- test/test_helper.rb | 3 ++- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 3193bd7..de4a590 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -26,4 +26,7 @@ Gem::Specification.new do |s| s.add_dependency('sprockets', '~> 2.10.1') s.add_dependency('rack', '~> 1.5.2') + s.add_development_dependency('rake', '~> 10.1.0') + s.add_development_dependency('haml', '~> 4.0.4') + end diff --git a/test/app_test.rb b/test/app_test.rb index 0032165..0547eb8 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -1,5 +1,6 @@ require 'test_helper' -require File.expand_path('../../lib/dashing', __FILE__) +require 'haml' + Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') class AppTest < Dashing::Test @@ -94,29 +95,23 @@ class AppTest < Dashing::Test end end - begin - require 'haml' - - def test_get_haml_dashboard - with_generated_project do |dir| - File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') - get '/hamltest' - assert_equal 200, last_response.status - assert_include last_response.body, "class='gridster'" - end + def test_get_haml_dashboard + with_generated_project do |dir| + File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') + get '/hamltest' + assert_equal 200, last_response.status + assert_include last_response.body, "class='gridster'" end + end - def test_get_haml_widget - with_generated_project do |dir| - File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') - File.unlink(File.join(dir, 'widgets/clock/clock.html')) - get '/views/clock.html' - assert_equal 200, last_response.status - assert_include last_response.body, '

    haml

    ' - end + def test_get_haml_widget + with_generated_project do |dir| + File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') + File.unlink(File.join(dir, 'widgets/clock/clock.html')) + get '/views/clock.html' + assert_equal 200, last_response.status + assert_include last_response.body, '

    haml

    ' end - rescue LoadError - puts "[skipping haml tests because haml isn't installed]" end def test_get_nonexistent_dashboard diff --git a/test/test_helper.rb b/test/test_helper.rb index d2337c5..b4bbd9e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,6 +2,7 @@ require 'rack/test' require 'stringio' require 'test/unit' require 'tmpdir' +require_relative '../lib/dashing' ENV['RACK_ENV'] = 'test' WORKING_DIRECTORY = Dir.pwd.freeze @@ -31,4 +32,4 @@ module Dashing class Test < Test::Unit::TestCase include Rack::Test::Methods end -end \ No newline at end of file +end -- cgit v1.2.3 From c3a72795ecab47f94527e079b60549051843caa4 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Wed, 18 Dec 2013 15:55:46 -0500 Subject: switching from test unit to minitest --- dashing.gemspec | 1 + test/app_test.rb | 15 +++++++-------- test/cli_test.rb | 6 +++--- test/test_helper.rb | 23 ++++++++++++++--------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index de4a590..704d66a 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -28,5 +28,6 @@ Gem::Specification.new do |s| s.add_development_dependency('rake', '~> 10.1.0') s.add_development_dependency('haml', '~> 4.0.4') + s.add_development_dependency('minitest', '~> 5.2.0') end diff --git a/test/app_test.rb b/test/app_test.rb index 0547eb8..a176d2e 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -1,11 +1,10 @@ require 'test_helper' require 'haml' -Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') - class AppTest < Dashing::Test def setup @connection = [] + Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') Sinatra::Application.settings.connections = [@connection] Sinatra::Application.settings.auth_token = nil Sinatra::Application.settings.default_dashboard = nil @@ -83,15 +82,15 @@ class AppTest < Dashing::Test with_generated_project do get '/sampletv' assert_equal 200, last_response.status - assert_include last_response.body, 'class="gridster"' - assert_include last_response.body, "DOCTYPE" + assert_includes last_response.body, 'class="gridster"' + assert_includes last_response.body, "DOCTYPE" end end def test_page_title_set_correctly with_generated_project do get '/sampletv' - assert_include last_response.body, '1080p dashboard' + assert_includes last_response.body, '1080p dashboard' end end @@ -100,7 +99,7 @@ class AppTest < Dashing::Test File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') get '/hamltest' assert_equal 200, last_response.status - assert_include last_response.body, "class='gridster'" + assert_includes last_response.body, "class='gridster'" end end @@ -110,7 +109,7 @@ class AppTest < Dashing::Test File.unlink(File.join(dir, 'widgets/clock/clock.html')) get '/views/clock.html' assert_equal 200, last_response.status - assert_include last_response.body, '

    haml

    ' + assert_includes last_response.body, '

    haml

    ' end end @@ -125,7 +124,7 @@ class AppTest < Dashing::Test with_generated_project do get '/views/meter.html' assert_equal 200, last_response.status - assert_include last_response.body, 'class="meter"' + assert_includes last_response.body, 'class="meter"' end end diff --git a/test/cli_test.rb b/test/cli_test.rb index 6c43e2c..2bf3b65 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -1,5 +1,5 @@ require 'test_helper' -silent{ load 'bin/dashing' } +load_quietly 'bin/dashing' module Thor::Actions def source_paths @@ -12,7 +12,7 @@ class CliTest < Dashing::Test def test_project_directory_created temp do |dir| cli = Dashing::CLI.new - silent{ cli.new 'Dashboard' } + silent { cli.new 'Dashboard' } assert Dir.exist?(File.join(dir,'dashboard')), 'Dashing directory was not created.' end end @@ -25,4 +25,4 @@ class CliTest < Dashing::Test assert_equal 'super-power-rangers', Dashing::CLI.hyphenate('SuperPowerRangers') end -end \ No newline at end of file +end diff --git a/test/test_helper.rb b/test/test_helper.rb index b4bbd9e..9c51b87 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,20 +1,19 @@ require 'rack/test' require 'stringio' -require 'test/unit' require 'tmpdir' + +require 'minitest/autorun' +require 'minitest/pride' + require_relative '../lib/dashing' ENV['RACK_ENV'] = 'test' WORKING_DIRECTORY = Dir.pwd.freeze ARGV.clear -def silent - _stdout = $stdout - $stdout = mock = StringIO.new - begin - yield - ensure - $stdout = _stdout +def load_quietly(file) + Minitest::Test.new(nil).capture_io do + load file end end @@ -29,7 +28,13 @@ ensure end module Dashing - class Test < Test::Unit::TestCase + class Test < Minitest::Test include Rack::Test::Methods + + alias_method :silent, :capture_io + + def teardown + FileUtils.rm_f('history.yml') + end end end -- cgit v1.2.3 From d0eef2dbe9d1178111cd768116a66b32a3a4b2b5 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Wed, 18 Dec 2013 19:12:43 -0500 Subject: moving cli to lib and updating bin file --- bin/dashing | 115 +---------------- dashing.gemspec | 3 +- lib/dashing.rb | 3 + lib/dashing/cli.rb | 105 ++++++++++++++++ lib/dashing/downloader.rb | 18 +++ test/app_test.rb | 306 +++++++++++++++++++++++----------------------- test/cli_test.rb | 174 +++++++++++++++++++++++--- test/downloader_test.rb | 26 ++++ test/test_helper.rb | 5 +- 9 files changed, 473 insertions(+), 282 deletions(-) create mode 100644 lib/dashing/cli.rb create mode 100644 lib/dashing/downloader.rb create mode 100644 test/downloader_test.rb diff --git a/bin/dashing b/bin/dashing index 9d97700..051acba 100755 --- a/bin/dashing +++ b/bin/dashing @@ -1,112 +1,7 @@ #!/usr/bin/env ruby +require "pathname" +bin_file = Pathname.new(__FILE__).realpath +$:.unshift File.expand_path("../../lib", bin_file) -require 'thor' -require 'net/http' -require 'json' -require 'open-uri' - -class MockScheduler - def method_missing(*args) - yield - end -end - -SCHEDULER = MockScheduler.new - -module Dashing - - class CLI < Thor - include Thor::Actions - - class << self - attr_accessor :auth_token - - def hyphenate(str) - return str.downcase if str =~ /^[A-Z-]+$/ - str.gsub('_', '-').gsub(/\B[A-Z]/, '-\&').squeeze('-').downcase - end - end - - attr_accessor :name - - no_tasks do - ['widget', 'dashboard', 'job'].each do |type| - define_method "generate_#{type}" do |name| - @name = Thor::Util.snake_case(name) - directory type.to_sym, File.join("#{type}s") - end - end - end - - def self.source_root - File.expand_path('../../templates', __FILE__) - end - - desc "new PROJECT_NAME", "Sets up ALL THE THINGS needed for your dashboard project." - def new(name) - @name = Thor::Util.snake_case(name) - directory :project, @name - end - - desc "generate (widget/dashboard/job) NAME", "Creates a new widget, dashboard, or job." - def generate(type, name) - send("generate_#{type}".to_sym, name) - rescue NoMethodError => e - puts "Invalid generator. Either use widget, dashboard, or job" - end - map "g" => :generate - - desc "install GIST_ID", "Installs a new widget from a gist." - def install(gist_id) - public_url = "https://gist.github.com/#{gist_id}" - gist = JSON.parse(open("https://api.github.com/gists/#{gist_id}").read) - - gist['files'].each do |filename, contents| - if filename.end_with?(".rb") - create_file File.join(Dir.pwd, 'jobs', filename), contents['content'] - elsif filename.end_with?(".coffee", ".html", ".scss") - widget_name = File.basename(filename, '.*') - create_file File.join(Dir.pwd, 'widgets', widget_name, filename), contents['content'] - end - end - - print set_color("Don't forget to edit the ", :yellow) - print set_color("Gemfile ", :yellow, :bold) - print set_color("and run ", :yellow) - print set_color("bundle install ", :yellow, :bold) - say set_color("if needed. More information for this widget can be found at #{public_url}", :yellow) - - rescue OpenURI::HTTPError => e - say set_color("Could not find gist at #{public_url}"), :red - end - map "i" => :install - - desc "start", "Starts the server in style!" - method_option :job_path, :desc => "Specify the directory where jobs are stored" - def start(*args) - port_option = args.include?('-p')? '' : ' -p 3030' - args = args.join(" ") - command = "bundle exec thin -R config.ru start #{port_option} #{args}" - command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] - system(command) - end - map "s" => :start - - desc "stop", "Stops the thin server" - def stop - command = "bundle exec thin stop" - system(command) - end - - desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job. Make sure to supply your auth token if you have one set." - def job(name, auth_token = "") - Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require file } - self.class.auth_token = auth_token - f = File.join(Dir.pwd, "jobs", "#{name}.rb") - require f - end - - end -end - -Dashing::CLI.start +require 'dashing' +Dashing::CLI.start(ARGV) diff --git a/dashing.gemspec b/dashing.gemspec index 704d66a..540839d 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -29,5 +29,6 @@ Gem::Specification.new do |s| s.add_development_dependency('rake', '~> 10.1.0') s.add_development_dependency('haml', '~> 4.0.4') s.add_development_dependency('minitest', '~> 5.2.0') - + s.add_development_dependency('mocha', '~> 0.14.0') + s.add_development_dependency('fakeweb', '~> 1.3.0') end diff --git a/lib/dashing.rb b/lib/dashing.rb index 7c4f25a..54579dd 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -7,6 +7,9 @@ require 'sass' require 'json' require 'yaml' +require 'dashing/cli' +require 'dashing/downloader' + SCHEDULER = Rufus::Scheduler.new set :root, Dir.pwd diff --git a/lib/dashing/cli.rb b/lib/dashing/cli.rb new file mode 100644 index 0000000..001a92e --- /dev/null +++ b/lib/dashing/cli.rb @@ -0,0 +1,105 @@ +require 'thor' +require 'open-uri' + +module Dashing + class CLI < Thor + include Thor::Actions + + attr_reader :name + + class << self + attr_accessor :auth_token + + def CLI.hyphenate(str) + return str.downcase if str =~ /^[A-Z-]+$/ + str.gsub('_', '-').gsub(/\B[A-Z]/, '-\&').squeeze('-').downcase + end + end + + no_tasks do + %w(widget dashboard job).each do |type| + define_method "generate_#{type}" do |name| + @name = Thor::Util.snake_case(name) + directory(type.to_sym, "#{type}s") + end + end + end + + desc "new PROJECT_NAME", "Sets up ALL THE THINGS needed for your dashboard project." + def new(name) + @name = Thor::Util.snake_case(name) + directory(:project, @name) + end + + desc "generate (widget/dashboard/job) NAME", "Creates a new widget, dashboard, or job." + def generate(type, name) + public_send("generate_#{type}".to_sym, name) + rescue NoMethodError => e + puts "Invalid generator. Either use widget, dashboard, or job" + end + + desc "install GIST_ID", "Installs a new widget from a gist." + def install(gist_id) + gist = Downloader.get_gist(gist_id) + public_url = "https://gist.github.com/#{gist_id}" + + gist['files'].each do |file, details| + if file =~ /\.(html|coffee|scss)\z/ + widget_name = File.basename(file, '.*') + new_path = File.join(Dir.pwd, 'widgets', widget_name, file) + create_file(new_path, details['content']) + elsif file.end_with?('.rb') + new_path = File.join(Dir.pwd, 'jobs', file) + create_file(new_path, details['content']) + end + end + + print set_color("Don't forget to edit the ", :yellow) + print set_color("Gemfile ", :yellow, :bold) + print set_color("and run ", :yellow) + print set_color("bundle install ", :yellow, :bold) + say set_color("if needed. More information for this widget can be found at #{public_url}", :yellow) + rescue OpenURI::HTTPError => http_error + say set_color("Could not find gist at #{public_url}"), :red + end + + desc "start", "Starts the server in style!" + method_option :job_path, :desc => "Specify the directory where jobs are stored" + def start(*args) + port_option = args.include?('-p') ? '' : ' -p 3030' + args = args.join(' ') + command = "bundle exec thin -R config.ru start#{port_option} #{args}" + command.prepend "export JOB_PATH=#{options[:job_path]}; " if options[:job_path] + run_command(command) + end + + desc "stop", "Stops the thin server" + def stop + command = "bundle exec thin stop" + run_command(command) + end + + desc "job JOB_NAME AUTH_TOKEN(optional)", "Runs the specified job. Make sure to supply your auth token if you have one set." + def job(name, auth_token = "") + Dir[File.join(Dir.pwd, 'lib/**/*.rb')].each {|file| require_file(file) } + self.class.auth_token = auth_token + f = File.join(Dir.pwd, "jobs", "#{name}.rb") + require_file(f) + end + + # map some commands + map 'g' => :generate + map 'i' => :install + map 's' => :start + + private + + def run_command(command) + system(command) + end + + def require_file(file) + require file + end + end +end diff --git a/lib/dashing/downloader.rb b/lib/dashing/downloader.rb new file mode 100644 index 0000000..140e862 --- /dev/null +++ b/lib/dashing/downloader.rb @@ -0,0 +1,18 @@ +require 'net/http' +require 'open-uri' +require 'json' + +module Dashing + module Downloader + extend self + + def get_gist(gist_id) + get_json("https://api.github.com/gists/#{gist_id}") + end + + def get_json(url) + response = open(url).read + JSON.parse(response) + end + end +end diff --git a/test/app_test.rb b/test/app_test.rb index a176d2e..bf3bbb1 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -1,153 +1,153 @@ -require 'test_helper' -require 'haml' - -class AppTest < Dashing::Test - def setup - @connection = [] - Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') - Sinatra::Application.settings.connections = [@connection] - Sinatra::Application.settings.auth_token = nil - Sinatra::Application.settings.default_dashboard = nil - end - - def test_post_widgets_without_auth_token - post '/widgets/some_widget', JSON.generate({value: 6}) - assert_equal 204, last_response.status - - assert_equal 1, @connection.length - data = parse_data @connection[0] - assert_equal 6, data['value'] - assert_equal 'some_widget', data['id'] - assert data['updatedAt'] - end - - def test_post_widgets_with_invalid_auth_token - Sinatra::Application.settings.auth_token = 'sekrit' - post '/widgets/some_widget', JSON.generate({value: 9}) - assert_equal 401, last_response.status - end - - def test_post_widgets_with_valid_auth_token - Sinatra::Application.settings.auth_token = 'sekrit' - post '/widgets/some_widget', JSON.generate({value: 9, auth_token: 'sekrit'}) - assert_equal 204, last_response.status - end - - def test_get_events - post '/widgets/some_widget', JSON.generate({value: 8}) - assert_equal 204, last_response.status - - get '/events' - assert_equal 200, last_response.status - assert_equal 8, parse_data(@connection[0])['value'] - end - - def test_dashboard_events - post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) - assert_equal 204, last_response.status - - get '/events' - assert_equal 200, last_response.status - assert_equal 'dashboards', parse_event(@connection[0]) - assert_equal 'reload', parse_data(@connection[0])['event'] - end - - def test_redirect_to_default_dashboard - with_generated_project do - Sinatra::Application.settings.default_dashboard = 'test1' - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/test1', last_response.location - end - end - - def test_redirect_to_first_dashboard - with_generated_project do - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/sample', last_response.location - end - end - - def test_redirect_to_first_dashboard_without_erb - with_generated_project do |dir| - FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/htmltest', last_response.location - end - end - - def test_get_dashboard - with_generated_project do - get '/sampletv' - assert_equal 200, last_response.status - assert_includes last_response.body, 'class="gridster"' - assert_includes last_response.body, "DOCTYPE" - end - end - - def test_page_title_set_correctly - with_generated_project do - get '/sampletv' - assert_includes last_response.body, '1080p dashboard' - end - end - - def test_get_haml_dashboard - with_generated_project do |dir| - File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') - get '/hamltest' - assert_equal 200, last_response.status - assert_includes last_response.body, "class='gridster'" - end - end - - def test_get_haml_widget - with_generated_project do |dir| - File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') - File.unlink(File.join(dir, 'widgets/clock/clock.html')) - get '/views/clock.html' - assert_equal 200, last_response.status - assert_includes last_response.body, '

    haml

    ' - end - end - - def test_get_nonexistent_dashboard - with_generated_project do - get '/nodashboard' - assert_equal 404, last_response.status - end - end - - def test_get_widget - with_generated_project do - get '/views/meter.html' - assert_equal 200, last_response.status - assert_includes last_response.body, 'class="meter"' - end - end - - def with_generated_project - temp do |dir| - cli = Dashing::CLI.new - silent { cli.new 'new_project' } - - Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') - Sinatra::Application.settings.root = File.join(dir, 'new_project') - yield Sinatra::Application.settings.root - end - end - - def app - Sinatra::Application - end - - def parse_data(string) - JSON.parse string[/data: (.+)/, 1] - end - - def parse_event(string) - string[/event: (.+)/, 1] - end -end +# require 'test_helper' +# require 'haml' + +# class AppTest < Dashing::Test +# def setup +# @connection = [] +# Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') +# Sinatra::Application.settings.connections = [@connection] +# Sinatra::Application.settings.auth_token = nil +# Sinatra::Application.settings.default_dashboard = nil +# end + +# def test_post_widgets_without_auth_token +# post '/widgets/some_widget', JSON.generate({value: 6}) +# assert_equal 204, last_response.status + +# assert_equal 1, @connection.length +# data = parse_data @connection[0] +# assert_equal 6, data['value'] +# assert_equal 'some_widget', data['id'] +# assert data['updatedAt'] +# end + +# def test_post_widgets_with_invalid_auth_token +# Sinatra::Application.settings.auth_token = 'sekrit' +# post '/widgets/some_widget', JSON.generate({value: 9}) +# assert_equal 401, last_response.status +# end + +# def test_post_widgets_with_valid_auth_token +# Sinatra::Application.settings.auth_token = 'sekrit' +# post '/widgets/some_widget', JSON.generate({value: 9, auth_token: 'sekrit'}) +# assert_equal 204, last_response.status +# end + +# def test_get_events +# post '/widgets/some_widget', JSON.generate({value: 8}) +# assert_equal 204, last_response.status + +# get '/events' +# assert_equal 200, last_response.status +# assert_equal 8, parse_data(@connection[0])['value'] +# end + +# def test_dashboard_events +# post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) +# assert_equal 204, last_response.status + +# get '/events' +# assert_equal 200, last_response.status +# assert_equal 'dashboards', parse_event(@connection[0]) +# assert_equal 'reload', parse_data(@connection[0])['event'] +# end + +# def test_redirect_to_default_dashboard +# with_generated_project do +# Sinatra::Application.settings.default_dashboard = 'test1' +# get '/' +# assert_equal 302, last_response.status +# assert_equal 'http://example.org/test1', last_response.location +# end +# end + +# def test_redirect_to_first_dashboard +# with_generated_project do +# get '/' +# assert_equal 302, last_response.status +# assert_equal 'http://example.org/sample', last_response.location +# end +# end + +# def test_redirect_to_first_dashboard_without_erb +# with_generated_project do |dir| +# FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) +# get '/' +# assert_equal 302, last_response.status +# assert_equal 'http://example.org/htmltest', last_response.location +# end +# end + +# def test_get_dashboard +# with_generated_project do +# get '/sampletv' +# assert_equal 200, last_response.status +# assert_includes last_response.body, 'class="gridster"' +# assert_includes last_response.body, "DOCTYPE" +# end +# end + +# def test_page_title_set_correctly +# with_generated_project do +# get '/sampletv' +# assert_includes last_response.body, '1080p dashboard' +# end +# end + +# def test_get_haml_dashboard +# with_generated_project do |dir| +# File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') +# get '/hamltest' +# assert_equal 200, last_response.status +# assert_includes last_response.body, "class='gridster'" +# end +# end + +# def test_get_haml_widget +# with_generated_project do |dir| +# File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') +# File.unlink(File.join(dir, 'widgets/clock/clock.html')) +# get '/views/clock.html' +# assert_equal 200, last_response.status +# assert_includes last_response.body, '

    haml

    ' +# end +# end + +# def test_get_nonexistent_dashboard +# with_generated_project do +# get '/nodashboard' +# assert_equal 404, last_response.status +# end +# end + +# def test_get_widget +# with_generated_project do +# get '/views/meter.html' +# assert_equal 200, last_response.status +# assert_includes last_response.body, 'class="meter"' +# end +# end + +# def with_generated_project +# temp do |dir| +# cli = Dashing::CLI.new +# silent { cli.new 'new_project' } + +# Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') +# Sinatra::Application.settings.root = File.join(dir, 'new_project') +# yield Sinatra::Application.settings.root +# end +# end + +# def app +# Sinatra::Application +# end + +# def parse_data(string) +# JSON.parse string[/data: (.+)/, 1] +# end + +# def parse_event(string) +# string[/event: (.+)/, 1] +# end +# end diff --git a/test/cli_test.rb b/test/cli_test.rb index 2bf3b65..567827e 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -1,28 +1,168 @@ require 'test_helper' -load_quietly 'bin/dashing' -module Thor::Actions - def source_paths - [File.join(File.expand_path(File.dirname(__FILE__)), '../templates')] +class CLITest < Dashing::Test + def setup + @cli = Dashing::CLI.new + end + + def test_new_task_creates_project_directory + app_name = 'custom_dashboard' + @cli.stubs(:directory).with(:project, app_name).once + @cli.new(app_name) end -end -class CliTest < Dashing::Test + def test_generate_task_delegates_to_type + types = %w(widget dashboard job) - def test_project_directory_created - temp do |dir| - cli = Dashing::CLI.new - silent { cli.new 'Dashboard' } - assert Dir.exist?(File.join(dir,'dashboard')), 'Dashing directory was not created.' + types.each do |type| + @cli.stubs(:public_send).with("generate_#{type}".to_sym, 'name').once + @cli.generate(type, 'name') end end - def test_hyphenate - assert_equal 'power', Dashing::CLI.hyphenate('Power') - assert_equal 'power', Dashing::CLI.hyphenate('POWER') - assert_equal 'power-rangers', Dashing::CLI.hyphenate('PowerRangers') - assert_equal 'power-ranger', Dashing::CLI.hyphenate('Power_ranger') - assert_equal 'super-power-rangers', Dashing::CLI.hyphenate('SuperPowerRangers') + def test_generate_task_warns_when_generator_is_not_defined + output, _ = capture_io do + @cli.generate('wtf', 'name') + end + + assert_includes output, 'Invalid generator' + end + + def test_generate_widget_creates_a_new_widget + @cli.stubs(:directory).with(:widget, 'widgets').once + @cli.generate_widget('WidgetName') + assert_equal 'widget_name', @cli.name + end + + def test_generate_dashboard_creates_a_new_dashboard + @cli.stubs(:directory).with(:dashboard, 'dashboards').once + @cli.generate_dashboard('DashBoardName') + assert_equal 'dash_board_name', @cli.name + end + + def test_generate_job_creates_a_new_job + @cli.stubs(:directory).with(:job, 'jobs').once + @cli.generate_job('MyCustomJob') + assert_equal 'my_custom_job', @cli.name + end + + def test_install_task_requests_gist_from_downloader + return_value = { 'files' => [] } + Dashing::Downloader.stubs(:get_gist).with(123).returns(return_value).once + + capture_io { @cli.install(123) } + end + + def test_install_task_calls_create_file_for_each_valid_file_in_gist + json_response = <<-JSON + { + "files": { + "ruby_job.rb": { "content": "some job content" }, + "num.html": { "content": "some html content" }, + "num.scss": { "content": "some sass content" }, + "num.coffee": { "content": "some coffee content" } + } + } + JSON + + Dir.stubs(:pwd).returns('') + + Dashing::Downloader.stubs(:get_gist).returns(JSON.parse(json_response)) + @cli.stubs(:create_file).with('/jobs/ruby_job.rb', 'some job content').once + @cli.stubs(:create_file).with('/widgets/num/num.html', 'some html content').once + @cli.stubs(:create_file).with('/widgets/num/num.scss', 'some sass content').once + @cli.stubs(:create_file).with('/widgets/num/num.coffee', 'some coffee content').once + + capture_io { @cli.install(123) } + end + + def test_install_task_ignores_invalid_files + json_response = <<-JSON + { + "files": { + "ruby_job.js": { "content": "some job content" }, + "num.css": { "content": "some sass content" } + } + } + JSON + + Dashing::Downloader.stubs(:get_gist).returns(JSON.parse(json_response)) + @cli.stubs(:create_file).never + + capture_io { @cli.install(123) } + end + + def test_install_task_warns_when_gist_not_found + error = OpenURI::HTTPError.new('error', mock()) + Dashing::Downloader.stubs(:get_gist).raises(error) + + output, _ = capture_io { @cli.install(123) } + + assert_includes output, 'Could not find gist at ' + end + + def test_start_task_starts_thin_with_default_port + command = 'bundle exec thin -R config.ru start -p 3030 ' + @cli.stubs(:run_command).with(command).once + @cli.start + end + + def test_start_task_starts_thin_with_specified_port + command = 'bundle exec thin -R config.ru start -p 2020' + @cli.stubs(:run_command).with(command).once + @cli.start('-p', '2020') + end + + def test_start_task_supports_job_path_option + commands = [ + 'export JOB_PATH=other_spot; ', + 'bundle exec thin -R config.ru start -p 3030 ' + ] + + @cli.stubs(:options).returns(job_path: 'other_spot') + @cli.stubs(:run_command).with(commands.join('')).once + @cli.start + end + + def test_stop_task_stops_thin_server + @cli.stubs(:run_command).with('bundle exec thin stop') + @cli.stop + end + + def test_job_task_requires_job_file + Dir.stubs(:pwd).returns('') + @cli.stubs(:require_file).with('/jobs/special_job.rb').once + + @cli.job('special_job') + end + + def test_job_task_requires_every_ruby_file_in_lib + Dir.stubs(:pwd).returns('') + Dir.stubs(:[]).returns(['lib/dashing/cli.rb', 'lib/dashing.rb']) + @cli.stubs(:require_file).times(3) + + @cli.job('special_job') + end + + def test_job_sets_auth_token + @cli.class.stubs(:auth_token=).with('my_token').once + @cli.stubs(:require_file) + + @cli.job('my_job', 'my_token') + end + + def test_hyphenate_lowers_and_hyphenates_inputs + assertion_map = { + 'Power' => 'power', + 'POWER' => 'power', + 'PowerRangers' => 'power-rangers', + 'Power_ranger' => 'power-ranger', + 'SuperPowerRangers' => 'super-power-rangers' + } + + assertion_map.each do |input, expected| + assert_equal expected, Dashing::CLI.hyphenate(input) + end end end diff --git a/test/downloader_test.rb b/test/downloader_test.rb new file mode 100644 index 0000000..930ad56 --- /dev/null +++ b/test/downloader_test.rb @@ -0,0 +1,26 @@ +require 'test_helper' + +class DownloaderTest < Minitest::Test + + def test_get_json_requests_and_parses_content + endpoint = 'http://somehost.com/file.json' + response = '{ "name": "value" }' + FakeWeb.register_uri(:get, endpoint, body: response) + JSON.stubs(:parse).with(response).once + + Dashing::Downloader.get_json(endpoint) + end + + def test_get_json_raises_on_bad_request + FakeWeb.register_uri(:get, 'http://dead-host.com/', status: '404') + + assert_raises(OpenURI::HTTPError) do + Dashing::Downloader.get_json('http://dead-host.com/') + end + end + + def test_load_gist_attempts_to_get_the_gist + Dashing::Downloader.stubs(:get_json).once + Dashing::Downloader.get_gist(123) + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 9c51b87..2f753f6 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,12 +1,15 @@ require 'rack/test' require 'stringio' require 'tmpdir' - +require 'fakeweb' require 'minitest/autorun' require 'minitest/pride' +require 'mocha/setup' require_relative '../lib/dashing' +FakeWeb.allow_net_connect = false + ENV['RACK_ENV'] = 'test' WORKING_DIRECTORY = Dir.pwd.freeze ARGV.clear -- cgit v1.2.3 From 0c1adbdb9fe428db1f4237e7bf021713b188f8f8 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Wed, 18 Dec 2013 19:16:02 -0500 Subject: adding simplecov for verifying test coverage --- .gitignore | 3 ++- dashing.gemspec | 1 + test/test_helper.rb | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2cc7498..38c2f32 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *DS_STORE /Gemfile.lock -*.gem \ No newline at end of file +*.gem +coverage/ diff --git a/dashing.gemspec b/dashing.gemspec index 540839d..8ef27f8 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -31,4 +31,5 @@ Gem::Specification.new do |s| s.add_development_dependency('minitest', '~> 5.2.0') s.add_development_dependency('mocha', '~> 0.14.0') s.add_development_dependency('fakeweb', '~> 1.3.0') + s.add_development_dependency('simplecov', '~> 0.8.2') end diff --git a/test/test_helper.rb b/test/test_helper.rb index 2f753f6..0b719f5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,9 @@ +require 'simplecov' +SimpleCov.start do + add_filter "/vendor/" + add_filter "/test/" +end + require 'rack/test' require 'stringio' require 'tmpdir' -- cgit v1.2.3 From fbc9497dbb8ece970f21bc67164557bba8db2db7 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Wed, 18 Dec 2013 19:22:09 -0500 Subject: moving app to it's own file under lib/dashing --- lib/dashing.rb | 168 +---------------------------- lib/dashing/app.rb | 167 +++++++++++++++++++++++++++++ test/app_test.rb | 307 +++++++++++++++++++++++++++-------------------------- 3 files changed, 323 insertions(+), 319 deletions(-) create mode 100644 lib/dashing/app.rb diff --git a/lib/dashing.rb b/lib/dashing.rb index 54579dd..855aa36 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -1,170 +1,6 @@ -require 'sinatra' -require 'sprockets' -require 'sinatra/content_for' -require 'rufus/scheduler' -require 'coffee-script' -require 'sass' -require 'json' -require 'yaml' - require 'dashing/cli' require 'dashing/downloader' +require 'dashing/app' -SCHEDULER = Rufus::Scheduler.new - -set :root, Dir.pwd - -set :sprockets, Sprockets::Environment.new(settings.root) -set :assets_prefix, '/assets' -set :digest_assets, false -['assets/javascripts', 'assets/stylesheets', 'assets/fonts', 'assets/images', 'widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path| - settings.sprockets.append_path path -end - -set server: 'thin', connections: [], history_file: 'history.yml' - -# Persist history in tmp file at exit -at_exit do - File.open(settings.history_file, 'w') do |f| - f.puts settings.history.to_yaml - end -end - -if File.exists?(settings.history_file) - set history: YAML.load_file(settings.history_file) -else - set history: {} -end - -set :public_folder, File.join(settings.root, 'public') -set :views, File.join(settings.root, 'dashboards') -set :default_dashboard, nil -set :auth_token, nil - -helpers Sinatra::ContentFor -helpers do - def protected! - # override with auth logic - end -end - -get '/events', provides: 'text/event-stream' do - protected! - response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx - stream :keep_open do |out| - settings.connections << out - out << latest_events - out.callback { settings.connections.delete(out) } - end -end - -get '/' do - protected! - begin - redirect "/" + (settings.default_dashboard || first_dashboard).to_s - rescue NoMethodError => e - raise Exception.new("There are no dashboards in your dashboard directory.") - end -end - -get '/:dashboard' do - protected! - tilt_html_engines.each do |suffix, _| - file = File.join(settings.views, "#{params[:dashboard]}.#{suffix}") - return render(suffix.to_sym, params[:dashboard].to_sym) if File.exist? file - end - - halt 404 -end - -get '/views/:widget?.html' do - protected! - tilt_html_engines.each do |suffix, engines| - file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{suffix}") - return engines.first.new(file).render if File.exist? file - end -end - -post '/dashboards/:id' do - request.body.rewind - body = JSON.parse(request.body.read) - body['dashboard'] ||= params['id'] - auth_token = body.delete("auth_token") - if !settings.auth_token || settings.auth_token == auth_token - send_event(params['id'], body, 'dashboards') - 204 # response without entity body - else - status 401 - "Invalid API key\n" - end +module Dashing end - -post '/widgets/:id' do - request.body.rewind - body = JSON.parse(request.body.read) - auth_token = body.delete("auth_token") - if !settings.auth_token || settings.auth_token == auth_token - send_event(params['id'], body) - 204 # response without entity body - else - status 401 - "Invalid API key\n" - end -end - -not_found do - send_file File.join(settings.public_folder, '404.html') -end - -def development? - ENV['RACK_ENV'] == 'development' -end - -def production? - ENV['RACK_ENV'] == 'production' -end - -def send_event(id, body, target=nil) - body[:id] = id - body[:updatedAt] ||= Time.now.to_i - event = format_event(body.to_json, target) - Sinatra::Application.settings.history[id] = event unless target == 'dashboards' - Sinatra::Application.settings.connections.each { |out| out << event } -end - -def format_event(body, name=nil) - str = "" - str << "event: #{name}\n" if name - str << "data: #{body}\n\n" -end - -def latest_events - settings.history.inject("") do |str, (id, body)| - str << body - end -end - -def first_dashboard - files = Dir[File.join(settings.views, '*')].collect { |f| File.basename(f, '.*') } - files -= ['layout'] - files.sort.first -end - -def tilt_html_engines - Tilt.mappings.select do |_, engines| - default_mime_type = engines.first.default_mime_type - default_mime_type.nil? || default_mime_type == 'text/html' - end -end - -settings_file = File.join(settings.root, 'config/settings.rb') -if (File.exists?(settings_file)) - require settings_file -end - -Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } -{}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. - -job_path = ENV["JOB_PATH"] || 'jobs' -files = Dir[File.join(settings.root, job_path, '**', '/*.rb')] -files.each { |job| require(job) } diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb new file mode 100644 index 0000000..7c4f25a --- /dev/null +++ b/lib/dashing/app.rb @@ -0,0 +1,167 @@ +require 'sinatra' +require 'sprockets' +require 'sinatra/content_for' +require 'rufus/scheduler' +require 'coffee-script' +require 'sass' +require 'json' +require 'yaml' + +SCHEDULER = Rufus::Scheduler.new + +set :root, Dir.pwd + +set :sprockets, Sprockets::Environment.new(settings.root) +set :assets_prefix, '/assets' +set :digest_assets, false +['assets/javascripts', 'assets/stylesheets', 'assets/fonts', 'assets/images', 'widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path| + settings.sprockets.append_path path +end + +set server: 'thin', connections: [], history_file: 'history.yml' + +# Persist history in tmp file at exit +at_exit do + File.open(settings.history_file, 'w') do |f| + f.puts settings.history.to_yaml + end +end + +if File.exists?(settings.history_file) + set history: YAML.load_file(settings.history_file) +else + set history: {} +end + +set :public_folder, File.join(settings.root, 'public') +set :views, File.join(settings.root, 'dashboards') +set :default_dashboard, nil +set :auth_token, nil + +helpers Sinatra::ContentFor +helpers do + def protected! + # override with auth logic + end +end + +get '/events', provides: 'text/event-stream' do + protected! + response.headers['X-Accel-Buffering'] = 'no' # Disable buffering for nginx + stream :keep_open do |out| + settings.connections << out + out << latest_events + out.callback { settings.connections.delete(out) } + end +end + +get '/' do + protected! + begin + redirect "/" + (settings.default_dashboard || first_dashboard).to_s + rescue NoMethodError => e + raise Exception.new("There are no dashboards in your dashboard directory.") + end +end + +get '/:dashboard' do + protected! + tilt_html_engines.each do |suffix, _| + file = File.join(settings.views, "#{params[:dashboard]}.#{suffix}") + return render(suffix.to_sym, params[:dashboard].to_sym) if File.exist? file + end + + halt 404 +end + +get '/views/:widget?.html' do + protected! + tilt_html_engines.each do |suffix, engines| + file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{suffix}") + return engines.first.new(file).render if File.exist? file + end +end + +post '/dashboards/:id' do + request.body.rewind + body = JSON.parse(request.body.read) + body['dashboard'] ||= params['id'] + auth_token = body.delete("auth_token") + if !settings.auth_token || settings.auth_token == auth_token + send_event(params['id'], body, 'dashboards') + 204 # response without entity body + else + status 401 + "Invalid API key\n" + end +end + +post '/widgets/:id' do + request.body.rewind + body = JSON.parse(request.body.read) + auth_token = body.delete("auth_token") + if !settings.auth_token || settings.auth_token == auth_token + send_event(params['id'], body) + 204 # response without entity body + else + status 401 + "Invalid API key\n" + end +end + +not_found do + send_file File.join(settings.public_folder, '404.html') +end + +def development? + ENV['RACK_ENV'] == 'development' +end + +def production? + ENV['RACK_ENV'] == 'production' +end + +def send_event(id, body, target=nil) + body[:id] = id + body[:updatedAt] ||= Time.now.to_i + event = format_event(body.to_json, target) + Sinatra::Application.settings.history[id] = event unless target == 'dashboards' + Sinatra::Application.settings.connections.each { |out| out << event } +end + +def format_event(body, name=nil) + str = "" + str << "event: #{name}\n" if name + str << "data: #{body}\n\n" +end + +def latest_events + settings.history.inject("") do |str, (id, body)| + str << body + end +end + +def first_dashboard + files = Dir[File.join(settings.views, '*')].collect { |f| File.basename(f, '.*') } + files -= ['layout'] + files.sort.first +end + +def tilt_html_engines + Tilt.mappings.select do |_, engines| + default_mime_type = engines.first.default_mime_type + default_mime_type.nil? || default_mime_type == 'text/html' + end +end + +settings_file = File.join(settings.root, 'config/settings.rb') +if (File.exists?(settings_file)) + require settings_file +end + +Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } +{}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. + +job_path = ENV["JOB_PATH"] || 'jobs' +files = Dir[File.join(settings.root, job_path, '**', '/*.rb')] +files.each { |job| require(job) } diff --git a/test/app_test.rb b/test/app_test.rb index bf3bbb1..dbb7cb5 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -1,153 +1,154 @@ -# require 'test_helper' -# require 'haml' - -# class AppTest < Dashing::Test -# def setup -# @connection = [] -# Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') -# Sinatra::Application.settings.connections = [@connection] -# Sinatra::Application.settings.auth_token = nil -# Sinatra::Application.settings.default_dashboard = nil -# end - -# def test_post_widgets_without_auth_token -# post '/widgets/some_widget', JSON.generate({value: 6}) -# assert_equal 204, last_response.status - -# assert_equal 1, @connection.length -# data = parse_data @connection[0] -# assert_equal 6, data['value'] -# assert_equal 'some_widget', data['id'] -# assert data['updatedAt'] -# end - -# def test_post_widgets_with_invalid_auth_token -# Sinatra::Application.settings.auth_token = 'sekrit' -# post '/widgets/some_widget', JSON.generate({value: 9}) -# assert_equal 401, last_response.status -# end - -# def test_post_widgets_with_valid_auth_token -# Sinatra::Application.settings.auth_token = 'sekrit' -# post '/widgets/some_widget', JSON.generate({value: 9, auth_token: 'sekrit'}) -# assert_equal 204, last_response.status -# end - -# def test_get_events -# post '/widgets/some_widget', JSON.generate({value: 8}) -# assert_equal 204, last_response.status - -# get '/events' -# assert_equal 200, last_response.status -# assert_equal 8, parse_data(@connection[0])['value'] -# end - -# def test_dashboard_events -# post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) -# assert_equal 204, last_response.status - -# get '/events' -# assert_equal 200, last_response.status -# assert_equal 'dashboards', parse_event(@connection[0]) -# assert_equal 'reload', parse_data(@connection[0])['event'] -# end - -# def test_redirect_to_default_dashboard -# with_generated_project do -# Sinatra::Application.settings.default_dashboard = 'test1' -# get '/' -# assert_equal 302, last_response.status -# assert_equal 'http://example.org/test1', last_response.location -# end -# end - -# def test_redirect_to_first_dashboard -# with_generated_project do -# get '/' -# assert_equal 302, last_response.status -# assert_equal 'http://example.org/sample', last_response.location -# end -# end - -# def test_redirect_to_first_dashboard_without_erb -# with_generated_project do |dir| -# FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) -# get '/' -# assert_equal 302, last_response.status -# assert_equal 'http://example.org/htmltest', last_response.location -# end -# end - -# def test_get_dashboard -# with_generated_project do -# get '/sampletv' -# assert_equal 200, last_response.status -# assert_includes last_response.body, 'class="gridster"' -# assert_includes last_response.body, "DOCTYPE" -# end -# end - -# def test_page_title_set_correctly -# with_generated_project do -# get '/sampletv' -# assert_includes last_response.body, '1080p dashboard' -# end -# end - -# def test_get_haml_dashboard -# with_generated_project do |dir| -# File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') -# get '/hamltest' -# assert_equal 200, last_response.status -# assert_includes last_response.body, "class='gridster'" -# end -# end - -# def test_get_haml_widget -# with_generated_project do |dir| -# File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') -# File.unlink(File.join(dir, 'widgets/clock/clock.html')) -# get '/views/clock.html' -# assert_equal 200, last_response.status -# assert_includes last_response.body, '

    haml

    ' -# end -# end - -# def test_get_nonexistent_dashboard -# with_generated_project do -# get '/nodashboard' -# assert_equal 404, last_response.status -# end -# end - -# def test_get_widget -# with_generated_project do -# get '/views/meter.html' -# assert_equal 200, last_response.status -# assert_includes last_response.body, 'class="meter"' -# end -# end - -# def with_generated_project -# temp do |dir| -# cli = Dashing::CLI.new -# silent { cli.new 'new_project' } - -# Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') -# Sinatra::Application.settings.root = File.join(dir, 'new_project') -# yield Sinatra::Application.settings.root -# end -# end - -# def app -# Sinatra::Application -# end - -# def parse_data(string) -# JSON.parse string[/data: (.+)/, 1] -# end - -# def parse_event(string) -# string[/event: (.+)/, 1] -# end -# end +require 'test_helper' +require 'haml' + +class AppTest < Dashing::Test + def setup + @connection = [] + Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') + Sinatra::Application.settings.connections = [@connection] + Sinatra::Application.settings.auth_token = nil + Sinatra::Application.settings.default_dashboard = nil + end + + def test_post_widgets_without_auth_token + post '/widgets/some_widget', JSON.generate({value: 6}) + assert_equal 204, last_response.status + + assert_equal 1, @connection.length + data = parse_data @connection[0] + assert_equal 6, data['value'] + assert_equal 'some_widget', data['id'] + assert data['updatedAt'] + end + + def test_post_widgets_with_invalid_auth_token + Sinatra::Application.settings.auth_token = 'sekrit' + post '/widgets/some_widget', JSON.generate({value: 9}) + assert_equal 401, last_response.status + end + + def test_post_widgets_with_valid_auth_token + Sinatra::Application.settings.auth_token = 'sekrit' + post '/widgets/some_widget', JSON.generate({value: 9, auth_token: 'sekrit'}) + assert_equal 204, last_response.status + end + + def test_get_events + post '/widgets/some_widget', JSON.generate({value: 8}) + assert_equal 204, last_response.status + + get '/events' + assert_equal 200, last_response.status + assert_equal 8, parse_data(@connection[0])['value'] + end + + def test_dashboard_events + post '/dashboards/my_super_sweet_dashboard', JSON.generate({event: 'reload'}) + assert_equal 204, last_response.status + + get '/events' + assert_equal 200, last_response.status + assert_equal 'dashboards', parse_event(@connection[0]) + assert_equal 'reload', parse_data(@connection[0])['event'] + end + + def test_redirect_to_default_dashboard + with_generated_project do + Sinatra::Application.settings.default_dashboard = 'test1' + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/test1', last_response.location + end + end + + def test_redirect_to_first_dashboard + with_generated_project do + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/sample', last_response.location + end + end + + def test_redirect_to_first_dashboard_without_erb + with_generated_project do |dir| + FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/htmltest', last_response.location + end + end + + def test_get_dashboard + with_generated_project do + get '/sampletv' + assert_equal 200, last_response.status + assert_includes last_response.body, 'class="gridster"' + assert_includes last_response.body, "DOCTYPE" + end + end + + def test_page_title_set_correctly + with_generated_project do + get '/sampletv' + assert_includes last_response.body, '1080p dashboard' + end + end + + def test_get_haml_dashboard + with_generated_project do |dir| + File.write(File.join(dir, 'dashboards/hamltest.haml'), '.gridster') + get '/hamltest' + assert_equal 200, last_response.status + assert_includes last_response.body, "class='gridster'" + end + end + + def test_get_haml_widget + with_generated_project do |dir| + File.write(File.join(dir, 'widgets/clock/clock.haml'), '%h1 haml') + File.unlink(File.join(dir, 'widgets/clock/clock.html')) + get '/views/clock.html' + assert_equal 200, last_response.status + assert_includes last_response.body, '

    haml

    ' + end + end + + def test_get_nonexistent_dashboard + with_generated_project do + get '/nodashboard' + assert_equal 404, last_response.status + end + end + + def test_get_widget + with_generated_project do + get '/views/meter.html' + assert_equal 200, last_response.status + assert_includes last_response.body, 'class="meter"' + end + end + + def with_generated_project + temp do |dir| + cli = Dashing::CLI.new + cli.stubs(:source_paths).returns([File.expand_path('../../templates', __FILE__)]) + silent { cli.new 'new_project' } + + Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') + Sinatra::Application.settings.root = File.join(dir, 'new_project') + yield Sinatra::Application.settings.root + end + end + + def app + Sinatra::Application + end + + def parse_data(string) + JSON.parse string[/data: (.+)/, 1] + end + + def parse_event(string) + string[/event: (.+)/, 1] + end +end -- cgit v1.2.3 From e975ce77408f5995213cc1b85f61e806152ba3a2 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Thu, 19 Dec 2013 12:08:07 -0500 Subject: light refactoring for better test coverage --- bin/dashing | 1 + lib/dashing/app.rb | 110 ++++++++++++++++++++++++++--------------------------- lib/dashing/cli.rb | 26 +++++++------ test/app_test.rb | 83 ++++++++++++++++++++++------------------ 4 files changed, 118 insertions(+), 102 deletions(-) diff --git a/bin/dashing b/bin/dashing index 051acba..97a7af5 100755 --- a/bin/dashing +++ b/bin/dashing @@ -4,4 +4,5 @@ bin_file = Pathname.new(__FILE__).realpath $:.unshift File.expand_path("../../lib", bin_file) require 'dashing' +Dashing::CLI.source_root(File.expand_path('../../templates', bin_file)) Dashing::CLI.start(ARGV) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 7c4f25a..5780b92 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -9,40 +9,59 @@ require 'yaml' SCHEDULER = Rufus::Scheduler.new -set :root, Dir.pwd - -set :sprockets, Sprockets::Environment.new(settings.root) -set :assets_prefix, '/assets' -set :digest_assets, false -['assets/javascripts', 'assets/stylesheets', 'assets/fonts', 'assets/images', 'widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path| - settings.sprockets.append_path path +def development? + ENV['RACK_ENV'] == 'development' end -set server: 'thin', connections: [], history_file: 'history.yml' +def production? + ENV['RACK_ENV'] == 'production' +end -# Persist history in tmp file at exit -at_exit do - File.open(settings.history_file, 'w') do |f| - f.puts settings.history.to_yaml +helpers Sinatra::ContentFor +helpers do + def protected! + # override with auth logic end end +set :root, Dir.pwd +set :sprockets, Sprockets::Environment.new(settings.root) +set :assets_prefix, '/assets' +set :digest_assets, false +set server: 'thin', connections: [], history_file: 'history.yml' +set :public_folder, File.join(settings.root, 'public') +set :views, File.join(settings.root, 'dashboards') +set :default_dashboard, nil +set :auth_token, nil + if File.exists?(settings.history_file) set history: YAML.load_file(settings.history_file) else set history: {} end -set :public_folder, File.join(settings.root, 'public') -set :views, File.join(settings.root, 'dashboards') -set :default_dashboard, nil -set :auth_token, nil +%w(javascripts stylesheets fonts images).each do |path| + settings.sprockets.append_path("assets/#{path}") +end -helpers Sinatra::ContentFor -helpers do - def protected! - # override with auth logic - end +['widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path| + settings.sprockets.append_path(path) +end + +not_found do + send_file File.join(settings.public_folder, '404.html') +end + +at_exit do + File.write(settings.history_file, settings.history.to_yaml) +end + +get '/' do + protected! + dashboard = settings.default_dashboard || first_dashboard + raise Exception.new('There are no dashboards available') if not dashboard + + redirect "/" + dashboard end get '/events', provides: 'text/event-stream' do @@ -55,15 +74,6 @@ get '/events', provides: 'text/event-stream' do end end -get '/' do - protected! - begin - redirect "/" + (settings.default_dashboard || first_dashboard).to_s - rescue NoMethodError => e - raise Exception.new("There are no dashboards in your dashboard directory.") - end -end - get '/:dashboard' do protected! tilt_html_engines.each do |suffix, _| @@ -74,14 +84,6 @@ get '/:dashboard' do halt 404 end -get '/views/:widget?.html' do - protected! - tilt_html_engines.each do |suffix, engines| - file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{suffix}") - return engines.first.new(file).render if File.exist? file - end -end - post '/dashboards/:id' do request.body.rewind body = JSON.parse(request.body.read) @@ -109,16 +111,12 @@ post '/widgets/:id' do end end -not_found do - send_file File.join(settings.public_folder, '404.html') -end - -def development? - ENV['RACK_ENV'] == 'development' -end - -def production? - ENV['RACK_ENV'] == 'production' +get '/views/:widget?.html' do + protected! + tilt_html_engines.each do |suffix, engines| + file = File.join(settings.root, "widgets", params[:widget], "#{params[:widget]}.#{suffix}") + return engines.first.new(file).render if File.exist? file + end end def send_event(id, body, target=nil) @@ -154,14 +152,16 @@ def tilt_html_engines end end -settings_file = File.join(settings.root, 'config/settings.rb') -if (File.exists?(settings_file)) - require settings_file +def require_glob(relative_glob) + Dir[File.join(settings.root, relative_glob)].each do |file| + require file + end end -Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file } -{}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. +settings_file = File.join(settings.root, 'config/settings.rb') +require settings_file if File.exists?(settings_file) +{}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start. job_path = ENV["JOB_PATH"] || 'jobs' -files = Dir[File.join(settings.root, job_path, '**', '/*.rb')] -files.each { |job| require(job) } +require_glob(File.join('lib', '**', '*.rb')) +require_glob(File.join(job_path, '**', '*.rb')) diff --git a/lib/dashing/cli.rb b/lib/dashing/cli.rb index 001a92e..27d8f6b 100644 --- a/lib/dashing/cli.rb +++ b/lib/dashing/cli.rb @@ -10,7 +10,7 @@ module Dashing class << self attr_accessor :auth_token - def CLI.hyphenate(str) + def hyphenate(str) return str.downcase if str =~ /^[A-Z-]+$/ str.gsub('_', '-').gsub(/\B[A-Z]/, '-\&').squeeze('-').downcase end @@ -43,16 +43,7 @@ module Dashing gist = Downloader.get_gist(gist_id) public_url = "https://gist.github.com/#{gist_id}" - gist['files'].each do |file, details| - if file =~ /\.(html|coffee|scss)\z/ - widget_name = File.basename(file, '.*') - new_path = File.join(Dir.pwd, 'widgets', widget_name, file) - create_file(new_path, details['content']) - elsif file.end_with?('.rb') - new_path = File.join(Dir.pwd, 'jobs', file) - create_file(new_path, details['content']) - end - end + install_widget_from_gist(gist) print set_color("Don't forget to edit the ", :yellow) print set_color("Gemfile ", :yellow, :bold) @@ -98,6 +89,19 @@ module Dashing system(command) end + def install_widget_from_gist(gist) + gist['files'].each do |file, details| + if file =~ /\.(html|coffee|scss)\z/ + widget_name = File.basename(file, '.*') + new_path = File.join(Dir.pwd, 'widgets', widget_name, file) + create_file(new_path, details['content']) + elsif file.end_with?('.rb') + new_path = File.join(Dir.pwd, 'jobs', file) + create_file(new_path, details['content']) + end + end + end + def require_file(file) require file end diff --git a/test/app_test.rb b/test/app_test.rb index dbb7cb5..4101e91 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -4,10 +4,45 @@ require 'haml' class AppTest < Dashing::Test def setup @connection = [] - Sinatra::Application.settings.history_file = File.join(Dir.tmpdir, 'history.yml') - Sinatra::Application.settings.connections = [@connection] - Sinatra::Application.settings.auth_token = nil - Sinatra::Application.settings.default_dashboard = nil + app.settings.connections = [@connection] + app.settings.auth_token = nil + app.settings.default_dashboard = nil + app.settings.history_file = File.join(Dir.tmpdir, 'history.yml') + end + + def test_redirect_to_first_dashboard + with_generated_project do + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/sample', last_response.location + end + end + + def test_redirect_to_first_dashboard_without_erb + with_generated_project do |dir| + FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/htmltest', last_response.location + end + end + + def test_redirect_to_default_dashboard + with_generated_project do + app.settings.default_dashboard = 'test1' + get '/' + assert_equal 302, last_response.status + assert_equal 'http://example.org/test1', last_response.location + end + end + + def test_errors_out_when_no_dashboards_available + with_generated_project do + app.settings.views = File.join(app.settings.root, 'lib') + + get '/' + assert_equal 500, last_response.status + end end def test_post_widgets_without_auth_token @@ -22,13 +57,13 @@ class AppTest < Dashing::Test end def test_post_widgets_with_invalid_auth_token - Sinatra::Application.settings.auth_token = 'sekrit' + app.settings.auth_token = 'sekrit' post '/widgets/some_widget', JSON.generate({value: 9}) assert_equal 401, last_response.status end def test_post_widgets_with_valid_auth_token - Sinatra::Application.settings.auth_token = 'sekrit' + app.settings.auth_token = 'sekrit' post '/widgets/some_widget', JSON.generate({value: 9, auth_token: 'sekrit'}) assert_equal 204, last_response.status end @@ -52,32 +87,6 @@ class AppTest < Dashing::Test assert_equal 'reload', parse_data(@connection[0])['event'] end - def test_redirect_to_default_dashboard - with_generated_project do - Sinatra::Application.settings.default_dashboard = 'test1' - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/test1', last_response.location - end - end - - def test_redirect_to_first_dashboard - with_generated_project do - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/sample', last_response.location - end - end - - def test_redirect_to_first_dashboard_without_erb - with_generated_project do |dir| - FileUtils.touch(File.join(dir, "dashboards/htmltest.html")) - get '/' - assert_equal 302, last_response.status - assert_equal 'http://example.org/htmltest', last_response.location - end - end - def test_get_dashboard with_generated_project do get '/sampletv' @@ -129,14 +138,16 @@ class AppTest < Dashing::Test end def with_generated_project + source_path = File.expand_path('../../templates', __FILE__) + temp do |dir| cli = Dashing::CLI.new - cli.stubs(:source_paths).returns([File.expand_path('../../templates', __FILE__)]) + cli.stubs(:source_paths).returns([source_path]) silent { cli.new 'new_project' } - Sinatra::Application.settings.views = File.join(dir, 'new_project/dashboards') - Sinatra::Application.settings.root = File.join(dir, 'new_project') - yield Sinatra::Application.settings.root + app.settings.views = File.join(dir, 'new_project/dashboards') + app.settings.root = File.join(dir, 'new_project') + yield app.settings.root end end -- cgit v1.2.3 From 333f5b2340add43a097abfb421ccce75f2f85ce5 Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Thu, 19 Dec 2013 13:01:17 -0500 Subject: updating javascripts path --- lib/dashing/app.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 5780b92..033849c 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -44,7 +44,7 @@ end settings.sprockets.append_path("assets/#{path}") end -['widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path| +['widgets', File.expand_path('../../../javascripts', __FILE__)]. each do |path| settings.sprockets.append_path(path) end -- cgit v1.2.3 From c49b9bc5d47fe02d26836dee5034fe28490f0ebd Mon Sep 17 00:00:00 2001 From: pseudomuto Date: Mon, 6 Jan 2014 10:32:30 -0500 Subject: removing and ignoring .ruby-version --- .gitignore | 1 + .ruby-version | 1 - .travis.yml | 3 ++- 3 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 .ruby-version diff --git a/.gitignore b/.gitignore index 38c2f32..2d12c6d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /Gemfile.lock *.gem coverage/ +.ruby-version diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 7fa1d1e..0000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.0.0-p353 diff --git a/.travis.yml b/.travis.yml index cbb92e0..0a28e78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: ruby rvm: + - 2.1.0 - 2.0.0 - 1.9.3 -script: "rake test" \ No newline at end of file +script: "rake test" -- cgit v1.2.3 From 628242b7c8d749d01b40d5d0cc23bb5da5843029 Mon Sep 17 00:00:00 2001 From: BX017301 Date: Thu, 16 Jan 2014 12:21:11 -0600 Subject: Update lastEvents if a widget exists. --- javascripts/dashing.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index fa677e8..e5875d8 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -109,8 +109,8 @@ source.addEventListener 'message', (e) -> if lastEvents[data.id]?.updatedAt != data.updatedAt if Dashing.debugMode console.log("Received data for #{data.id}", data) - lastEvents[data.id] = data if widgets[data.id]?.length > 0 + lastEvents[data.id] = data for widget in widgets[data.id] widget.receiveData(data) -- cgit v1.2.3 From 6f097d8293eb69106c2c35f42ad18b8fdcf95d14 Mon Sep 17 00:00:00 2001 From: mr-deamon Date: Wed, 12 Mar 2014 08:42:05 +0100 Subject: Making meter-widget adjustable --- templates/project/dashboards/sample.erb | 4 ++-- templates/project/widgets/meter/meter.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/project/dashboards/sample.erb b/templates/project/dashboards/sample.erb index d41d538..8269b7e 100644 --- a/templates/project/dashboards/sample.erb +++ b/templates/project/dashboards/sample.erb @@ -6,7 +6,7 @@
  • -
    +
  • @@ -22,4 +22,4 @@
Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://<%=request.host%>:<%=request.port%>/widgets/welcome
-
\ No newline at end of file + diff --git a/templates/project/widgets/meter/meter.html b/templates/project/widgets/meter/meter.html index 16f1f06..d2b8c22 100644 --- a/templates/project/widgets/meter/meter.html +++ b/templates/project/widgets/meter/meter.html @@ -1,6 +1,6 @@

- +

-- cgit v1.2.3 From 76a645b75b0f8173a5e5c7c1e16ea9633ca11e40 Mon Sep 17 00:00:00 2001 From: mr-deamon Date: Wed, 12 Mar 2014 10:13:15 +0100 Subject: Adding Suffix and Prefix to Meter-Widget --- templates/project/dashboards/sample.erb | 2 +- templates/project/widgets/meter/meter.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/project/dashboards/sample.erb b/templates/project/dashboards/sample.erb index 8269b7e..08c3b51 100644 --- a/templates/project/dashboards/sample.erb +++ b/templates/project/dashboards/sample.erb @@ -6,7 +6,7 @@
  • -
    +
  • diff --git a/templates/project/widgets/meter/meter.html b/templates/project/widgets/meter/meter.html index d2b8c22..72592fb 100644 --- a/templates/project/widgets/meter/meter.html +++ b/templates/project/widgets/meter/meter.html @@ -1,6 +1,6 @@

    - +

    -- cgit v1.2.3 From 180006aa2eaf5945722c60105b0e60945e88f42e Mon Sep 17 00:00:00 2001 From: Naman Goel Date: Thu, 13 Mar 2014 18:50:35 -0700 Subject: Update License Date Updated the license year. (updated to 2014). --- MIT-LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIT-LICENSE b/MIT-LICENSE index d2bf435..1cb4835 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013 Shopify +Copyright (c) 2014 Shopify Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the -- cgit v1.2.3 From 6c58c68705c5201873958504a141105b826dae79 Mon Sep 17 00:00:00 2001 From: Lillian Ng Date: Mon, 19 May 2014 12:21:15 -0700 Subject: upgrade gridster.js to v0.5.1 --- .../assets/javascripts/gridster/jquery.gridster.js | 3263 -------------------- .../javascripts/gridster/jquery.gridster.min.js | 2 + .../project/assets/stylesheets/application.scss | 4 +- .../project/assets/stylesheets/jquery.gridster.css | 57 - .../assets/stylesheets/jquery.gridster.min.css | 2 + 5 files changed, 6 insertions(+), 3322 deletions(-) delete mode 100644 templates/project/assets/javascripts/gridster/jquery.gridster.js create mode 100644 templates/project/assets/javascripts/gridster/jquery.gridster.min.js delete mode 100644 templates/project/assets/stylesheets/jquery.gridster.css create mode 100644 templates/project/assets/stylesheets/jquery.gridster.min.css diff --git a/templates/project/assets/javascripts/gridster/jquery.gridster.js b/templates/project/assets/javascripts/gridster/jquery.gridster.js deleted file mode 100644 index 9451c9a..0000000 --- a/templates/project/assets/javascripts/gridster/jquery.gridster.js +++ /dev/null @@ -1,3263 +0,0 @@ -/*! gridster.js - v0.1.0 - 2013-02-15 -* http://gridster.net/ -* Copyright (c) 2013 ducksboard; Licensed MIT */ - -;(function($, window, document, undefined){ - /** - * Creates objects with coordinates (x1, y1, x2, y2, cx, cy, width, height) - * to simulate DOM elements on the screen. - * Coords is used by Gridster to create a faux grid with any DOM element can - * collide. - * - * @class Coords - * @param {HTMLElement|Object} obj The jQuery HTMLElement or a object with: left, - * top, width and height properties. - * @return {Object} Coords instance. - * @constructor - */ - function Coords(obj) { - if (obj[0] && $.isPlainObject(obj[0])) { - this.data = obj[0]; - }else { - this.el = obj; - } - - this.isCoords = true; - this.coords = {}; - this.init(); - return this; - } - - - var fn = Coords.prototype; - - - fn.init = function(){ - this.set(); - this.original_coords = this.get(); - }; - - - fn.set = function(update, not_update_offsets) { - var el = this.el; - - if (el && !update) { - this.data = el.offset(); - this.data.width = el.width(); - this.data.height = el.height(); - } - - if (el && update && !not_update_offsets) { - var offset = el.offset(); - this.data.top = offset.top; - this.data.left = offset.left; - } - - var d = this.data; - - this.coords.x1 = d.left; - this.coords.y1 = d.top; - this.coords.x2 = d.left + d.width; - this.coords.y2 = d.top + d.height; - this.coords.cx = d.left + (d.width / 2); - this.coords.cy = d.top + (d.height / 2); - this.coords.width = d.width; - this.coords.height = d.height; - this.coords.el = el || false ; - - return this; - }; - - - fn.update = function(data){ - if (!data && !this.el) { - return this; - } - - if (data) { - var new_data = $.extend({}, this.data, data); - this.data = new_data; - return this.set(true, true); - } - - this.set(true); - return this; - }; - - - fn.get = function(){ - return this.coords; - }; - - - //jQuery adapter - $.fn.coords = function() { - if (this.data('coords') ) { - return this.data('coords'); - } - - var ins = new Coords(this, arguments[0]); - this.data('coords', ins); - return ins; - }; - -}(jQuery, window, document)); - -;(function($, window, document, undefined){ - - var defaults = { - colliders_context: document.body - // ,on_overlap: function(collider_data){}, - // on_overlap_start : function(collider_data){}, - // on_overlap_stop : function(collider_data){} - }; - - - /** - * Detects collisions between a DOM element against other DOM elements or - * Coords objects. - * - * @class Collision - * @uses Coords - * @param {HTMLElement} el The jQuery wrapped HTMLElement. - * @param {HTMLElement|Array} colliders Can be a jQuery collection - * of HTMLElements or an Array of Coords instances. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {Function} [options.on_overlap_start] Executes a function the first - * time each `collider ` is overlapped. - * @param {Function} [options.on_overlap_stop] Executes a function when a - * `collider` is no longer collided. - * @param {Function} [options.on_overlap] Executes a function when the - * mouse is moved during the collision. - * @return {Object} Collision instance. - * @constructor - */ - function Collision(el, colliders, options) { - this.options = $.extend(defaults, options); - this.$element = el; - this.last_colliders = []; - this.last_colliders_coords = []; - if (typeof colliders === 'string' || colliders instanceof jQuery) { - this.$colliders = $(colliders, - this.options.colliders_context).not(this.$element); - }else{ - this.colliders = $(colliders); - } - - this.init(); - } - - - var fn = Collision.prototype; - - - fn.init = function() { - this.find_collisions(); - }; - - - fn.overlaps = function(a, b) { - var x = false; - var y = false; - - if ((b.x1 >= a.x1 && b.x1 <= a.x2) || - (b.x2 >= a.x1 && b.x2 <= a.x2) || - (a.x1 >= b.x1 && a.x2 <= b.x2) - ) { x = true; } - - if ((b.y1 >= a.y1 && b.y1 <= a.y2) || - (b.y2 >= a.y1 && b.y2 <= a.y2) || - (a.y1 >= b.y1 && a.y2 <= b.y2) - ) { y = true; } - - return (x && y); - }; - - - fn.detect_overlapping_region = function(a, b){ - var regionX = ''; - var regionY = ''; - - if (a.y1 > b.cy && a.y1 < b.y2) { regionX = 'N'; } - if (a.y2 > b.y1 && a.y2 < b.cy) { regionX = 'S'; } - if (a.x1 > b.cx && a.x1 < b.x2) { regionY = 'W'; } - if (a.x2 > b.x1 && a.x2 < b.cx) { regionY = 'E'; } - - return (regionX + regionY) || 'C'; - }; - - - fn.calculate_overlapped_area_coords = function(a, b){ - var x1 = Math.max(a.x1, b.x1); - var y1 = Math.max(a.y1, b.y1); - var x2 = Math.min(a.x2, b.x2); - var y2 = Math.min(a.y2, b.y2); - - return $({ - left: x1, - top: y1, - width : (x2 - x1), - height: (y2 - y1) - }).coords().get(); - }; - - - fn.calculate_overlapped_area = function(coords){ - return (coords.width * coords.height); - }; - - - fn.manage_colliders_start_stop = function(new_colliders_coords, start_callback, stop_callback){ - var last = this.last_colliders_coords; - - for (var i = 0, il = last.length; i < il; i++) { - if ($.inArray(last[i], new_colliders_coords) === -1) { - start_callback.call(this, last[i]); - } - } - - for (var j = 0, jl = new_colliders_coords.length; j < jl; j++) { - if ($.inArray(new_colliders_coords[j], last) === -1) { - stop_callback.call(this, new_colliders_coords[j]); - } - - } - }; - - - fn.find_collisions = function(player_data_coords){ - var self = this; - var colliders_coords = []; - var colliders_data = []; - var $colliders = (this.colliders || this.$colliders); - var count = $colliders.length; - var player_coords = self.$element.coords() - .update(player_data_coords || false).get(); - - while(count--){ - var $collider = self.$colliders ? - $($colliders[count]) : $colliders[count]; - var $collider_coords_ins = ($collider.isCoords) ? - $collider : $collider.coords(); - var collider_coords = $collider_coords_ins.get(); - var overlaps = self.overlaps(player_coords, collider_coords); - - if (!overlaps) { - continue; - } - - var region = self.detect_overlapping_region( - player_coords, collider_coords); - - //todo: make this an option - if (region === 'C'){ - var area_coords = self.calculate_overlapped_area_coords( - player_coords, collider_coords); - var area = self.calculate_overlapped_area(area_coords); - var collider_data = { - area: area, - area_coords : area_coords, - region: region, - coords: collider_coords, - player_coords: player_coords, - el: $collider - }; - - if (self.options.on_overlap) { - self.options.on_overlap.call(this, collider_data); - } - colliders_coords.push($collider_coords_ins); - colliders_data.push(collider_data); - } - } - - if (self.options.on_overlap_stop || self.options.on_overlap_start) { - this.manage_colliders_start_stop(colliders_coords, - self.options.on_overlap_stop, self.options.on_overlap_start); - } - - this.last_colliders_coords = colliders_coords; - - return colliders_data; - }; - - - fn.get_closest_colliders = function(player_data_coords){ - var colliders = this.find_collisions(player_data_coords); - - colliders.sort(function(a, b) { - /* if colliders are being overlapped by the "C" (center) region, - * we have to set a lower index in the array to which they are placed - * above in the grid. */ - if (a.region === 'C' && b.region === 'C') { - if (a.coords.y1 < b.coords.y1 || a.coords.x1 < b.coords.x1) { - return - 1; - }else{ - return 1; - } - } - - if (a.area < b.area) { - return 1; - } - - return 1; - }); - return colliders; - }; - - - //jQuery adapter - $.fn.collision = function(collider, options) { - return new Collision( this, collider, options ); - }; - - -}(jQuery, window, document)); - -;(function(window, undefined) { - /* Debounce and throttle functions taken from underscore.js */ - window.debounce = function(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - if (immediate && !timeout) func.apply(context, args); - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - }; - - - window.throttle = function(func, wait) { - var context, args, timeout, throttling, more, result; - var whenDone = debounce( - function(){ more = throttling = false; }, wait); - return function() { - context = this; args = arguments; - var later = function() { - timeout = null; - if (more) func.apply(context, args); - whenDone(); - }; - if (!timeout) timeout = setTimeout(later, wait); - if (throttling) { - more = true; - } else { - result = func.apply(context, args); - } - whenDone(); - throttling = true; - return result; - }; - }; - -})(window); - -;(function($, window, document, undefined){ - - var defaults = { - items: '.gs_w', - distance: 1, - limit: true, - offset_left: 0, - autoscroll: true, - ignore_dragging: ['INPUT', 'TEXTAREA', 'SELECT', 'BUTTON'], - handle: null - // drag: function(e){}, - // start : function(e, ui){}, - // stop : function(e){} - }; - - var $window = $(window); - var isTouch = !!('ontouchstart' in window); - var pointer_events = { - start: isTouch ? 'touchstart' : 'mousedown.draggable', - move: isTouch ? 'touchmove' : 'mousemove.draggable', - end: isTouch ? 'touchend' : 'mouseup.draggable' - }; - - /** - * Basic drag implementation for DOM elements inside a container. - * Provide start/stop/drag callbacks. - * - * @class Draggable - * @param {HTMLElement} el The HTMLelement that contains all the widgets - * to be dragged. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {HTMLElement|String} [options.items] Define who will - * be the draggable items. Can be a CSS Selector String or a - * collection of HTMLElements. - * @param {Number} [options.distance] Distance in pixels after mousedown - * the mouse must move before dragging should start. - * @param {Boolean} [options.limit] Constrains dragging to the width of - * the container - * @param {offset_left} [options.offset_left] Offset added to the item - * that is being dragged. - * @param {Number} [options.drag] Executes a callback when the mouse is - * moved during the dragging. - * @param {Number} [options.start] Executes a callback when the drag - * starts. - * @param {Number} [options.stop] Executes a callback when the drag stops. - * @return {Object} Returns `el`. - * @constructor - */ - function Draggable(el, options) { - this.options = $.extend({}, defaults, options); - this.$body = $(document.body); - this.$container = $(el); - this.$dragitems = $(this.options.items, this.$container); - this.is_dragging = false; - this.player_min_left = 0 + this.options.offset_left; - this.init(); - } - - var fn = Draggable.prototype; - - fn.init = function() { - this.calculate_positions(); - this.$container.css('position', 'relative'); - this.disabled = false; - this.events(); - - this.on_window_resize = throttle($.proxy(this.calculate_positions, this), 200); - $(window).bind('resize', this.on_window_resize); - }; - - fn.events = function() { - this.proxied_on_select_start = $.proxy(this.on_select_start, this); - this.$container.on('selectstart', this.proxied_on_select_start); - - this.proxied_drag_handler = $.proxy(this.drag_handler, this); - this.$container.on(pointer_events.start, this.options.items, this.proxied_drag_handler); - - this.proxied_pointer_events_end = $.proxy(function(e) { - this.is_dragging = false; - if (this.disabled) { return; } - this.$body.off(pointer_events.move); - if (this.drag_start) { - this.on_dragstop(e); - } - }, this); - this.$body.on(pointer_events.end, this.proxied_pointer_events_end); - }; - - fn.get_actual_pos = function($el) { - var pos = $el.position(); - return pos; - }; - - - fn.get_mouse_pos = function(e) { - if (isTouch) { - var oe = e.originalEvent; - e = oe.touches.length ? oe.touches[0] : oe.changedTouches[0]; - } - - return { - left: e.clientX, - top: e.clientY - }; - }; - - - fn.get_offset = function(e) { - e.preventDefault(); - var mouse_actual_pos = this.get_mouse_pos(e); - var diff_x = Math.round( - mouse_actual_pos.left - this.mouse_init_pos.left); - var diff_y = Math.round(mouse_actual_pos.top - this.mouse_init_pos.top); - - var left = Math.round(this.el_init_offset.left + diff_x - this.baseX); - var top = Math.round( - this.el_init_offset.top + diff_y - this.baseY + this.scrollOffset); - - if (this.options.limit) { - if (left > this.player_max_left) { - left = this.player_max_left; - }else if(left < this.player_min_left) { - left = this.player_min_left; - } - } - - return { - left: left, - top: top, - mouse_left: mouse_actual_pos.left, - mouse_top: mouse_actual_pos.top - }; - }; - - - fn.manage_scroll = function(offset) { - /* scroll document */ - var nextScrollTop; - var scrollTop = $window.scrollTop(); - var min_window_y = scrollTop; - var max_window_y = min_window_y + this.window_height; - - var mouse_down_zone = max_window_y - 50; - var mouse_up_zone = min_window_y + 50; - - var abs_mouse_left = offset.mouse_left; - var abs_mouse_top = min_window_y + offset.mouse_top; - - var max_player_y = (this.doc_height - this.window_height + - this.player_height); - - if (abs_mouse_top >= mouse_down_zone) { - nextScrollTop = scrollTop + 30; - if (nextScrollTop < max_player_y) { - $window.scrollTop(nextScrollTop); - this.scrollOffset = this.scrollOffset + 30; - } - } - - if (abs_mouse_top <= mouse_up_zone) { - nextScrollTop = scrollTop - 30; - if (nextScrollTop > 0) { - $window.scrollTop(nextScrollTop); - this.scrollOffset = this.scrollOffset - 30; - } - } - }; - - - fn.calculate_positions = function(e) { - this.window_height = $window.height(); - }; - - - fn.drag_handler = function(e) { - var node = e.target.nodeName; - if (this.disabled || e.which !== 1 && !isTouch) { - return; - } - - if (this.ignore_drag(e)) { - return; - } - - var self = this; - var first = true; - this.$player = $(e.currentTarget); - - this.el_init_pos = this.get_actual_pos(this.$player); - this.mouse_init_pos = this.get_mouse_pos(e); - this.offsetY = this.mouse_init_pos.top - this.el_init_pos.top; - - this.on_pointer_events_move = function(mme){ - var mouse_actual_pos = self.get_mouse_pos(mme); - var diff_x = Math.abs( - mouse_actual_pos.left - self.mouse_init_pos.left); - var diff_y = Math.abs( - mouse_actual_pos.top - self.mouse_init_pos.top); - if (!(diff_x > self.options.distance || - diff_y > self.options.distance) - ) { - return false; - } - - if (first) { - first = false; - self.on_dragstart.call(self, mme); - return false; - } - - if (self.is_dragging === true) { - self.on_dragmove.call(self, mme); - } - - return false; - }; - - this.$body.on(pointer_events.move, this.on_pointer_events_move); - - return false; - }; - - - fn.on_dragstart = function(e) { - e.preventDefault(); - this.drag_start = true; - this.is_dragging = true; - var offset = this.$container.offset(); - this.baseX = Math.round(offset.left); - this.baseY = Math.round(offset.top); - this.doc_height = $(document).height(); - - if (this.options.helper === 'clone') { - this.$helper = this.$player.clone() - .appendTo(this.$container).addClass('helper'); - this.helper = true; - }else{ - this.helper = false; - } - this.scrollOffset = 0; - this.el_init_offset = this.$player.offset(); - this.player_width = this.$player.width(); - this.player_height = this.$player.height(); - this.player_max_left = (this.$container.width() - this.player_width + - this.options.offset_left); - - if (this.options.start) { - this.options.start.call(this.$player, e, { - helper: this.helper ? this.$helper : this.$player - }); - } - return false; - }; - - - fn.on_dragmove = function(e) { - var offset = this.get_offset(e); - - this.options.autoscroll && this.manage_scroll(offset); - - (this.helper ? this.$helper : this.$player).css({ - 'position': 'absolute', - 'left' : offset.left, - 'top' : offset.top - }); - - var ui = { - 'position': { - 'left': offset.left, - 'top': offset.top - } - }; - - if (this.options.drag) { - this.options.drag.call(this.$player, e, ui); - } - return false; - }; - - - fn.on_dragstop = function(e) { - var offset = this.get_offset(e); - this.drag_start = false; - - var ui = { - 'position': { - 'left': offset.left, - 'top': offset.top - } - }; - - if (this.options.stop) { - this.options.stop.call(this.$player, e, ui); - } - - if (this.helper) { - this.$helper.remove(); - } - - return false; - }; - - fn.on_select_start = function(e) { - if (this.disabled) { return; } - - if (this.ignore_drag(e)) { - return; - } - - return false; - }; - - fn.enable = function() { - this.disabled = false; - }; - - fn.disable = function() { - this.disabled = true; - }; - - - fn.destroy = function(){ - this.disable(); - - this.$container.off('selectstart', this.proxied_on_select_start); - this.$container.off(pointer_events.start, this.proxied_drag_handler); - this.$body.off(pointer_events.end, this.proxied_pointer_events_end); - this.$body.off(pointer_events.move, this.on_pointer_events_move); - $(window).unbind('resize', this.on_window_resize); - - $.removeData(this.$container, 'drag'); - }; - - fn.ignore_drag = function(event) { - if (this.options.handle) { - return !$(event.target).is(this.options.handle); - } - - return $.inArray(event.target.nodeName, this.options.ignore_dragging) >= 0; - }; - - //jQuery adapter - $.fn.drag = function ( options ) { - return this.each(function () { - if (!$.data(this, 'drag')) { - $.data(this, 'drag', new Draggable( this, options )); - } - }); - }; - - -}(jQuery, window, document)); - -;(function($, window, document, undefined) { - - var defaults = { - namespace: '', - widget_selector: 'li', - widget_margins: [10, 10], - widget_base_dimensions: [400, 225], - extra_rows: 0, - extra_cols: 0, - min_cols: 1, - min_rows: 15, - max_size_x: 6, - autogenerate_stylesheet: true, - avoid_overlapped_widgets: true, - serialize_params: function($w, wgd) { - return { - col: wgd.col, - row: wgd.row, - size_x: wgd.size_x, - size_y: wgd.size_y - }; - }, - collision: {}, - draggable: { - distance: 4 - } - }; - - - /** - * @class Gridster - * @uses Draggable - * @uses Collision - * @param {HTMLElement} el The HTMLelement that contains all the widgets. - * @param {Object} [options] An Object with all options you want to - * overwrite: - * @param {HTMLElement|String} [options.widget_selector] Define who will - * be the draggable widgets. Can be a CSS Selector String or a - * collection of HTMLElements - * @param {Array} [options.widget_margins] Margin between widgets. - * The first index for the horizontal margin (left, right) and - * the second for the vertical margin (top, bottom). - * @param {Array} [options.widget_base_dimensions] Base widget dimensions - * in pixels. The first index for the width and the second for the - * height. - * @param {Number} [options.extra_cols] Add more columns in addition to - * those that have been calculated. - * @param {Number} [options.extra_rows] Add more rows in addition to - * those that have been calculated. - * @param {Number} [options.min_cols] The minimum required columns. - * @param {Number} [options.min_rows] The minimum required rows. - * @param {Number} [options.max_size_x] The maximum number of columns - * that a widget can span. - * @param {Boolean} [options.autogenerate_stylesheet] If true, all the - * CSS required to position all widgets in their respective columns - * and rows will be generated automatically and injected to the - * `` of the document. You can set this to false, and write - * your own CSS targeting rows and cols via data-attributes like so: - * `[data-col="1"] { left: 10px; }` - * @param {Boolean} [options.avoid_overlapped_widgets] Avoid that widgets loaded - * from the DOM can be overlapped. It is helpful if the positions were - * bad stored in the database or if there was any conflict. - * @param {Function} [options.serialize_params] Return the data you want - * for each widget in the serialization. Two arguments are passed: - * `$w`: the jQuery wrapped HTMLElement, and `wgd`: the grid - * coords object (`col`, `row`, `size_x`, `size_y`). - * @param {Object} [options.collision] An Object with all options for - * Collision class you want to overwrite. See Collision docs for - * more info. - * @param {Object} [options.draggable] An Object with all options for - * Draggable class you want to overwrite. See Draggable docs for more - * info. - * - * @constructor - */ - function Gridster(el, options) { - this.options = $.extend(true, defaults, options); - this.$el = $(el); - this.$wrapper = this.$el.parent(); - this.$widgets = this.$el.children(this.options.widget_selector).addClass('gs_w'); - this.widgets = []; - this.$changed = $([]); - this.wrapper_width = this.$wrapper.width(); - this.min_widget_width = (this.options.widget_margins[0] * 2) + - this.options.widget_base_dimensions[0]; - this.min_widget_height = (this.options.widget_margins[1] * 2) + - this.options.widget_base_dimensions[1]; - this.init(); - } - - Gridster.generated_stylesheets = []; - - var fn = Gridster.prototype; - - fn.init = function() { - this.generate_grid_and_stylesheet(); - this.get_widgets_from_DOM(); - this.set_dom_grid_height(); - this.$wrapper.addClass('ready'); - this.draggable(); - - this.on_window_resize = throttle($.proxy(this.recalculate_faux_grid, this), 200); - - $(window).bind('resize', this.on_window_resize); - }; - - - /** - * Disables dragging. - * - * @method disable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.disable = function() { - this.$wrapper.find('.player-revert').removeClass('player-revert'); - this.drag_api.disable(); - return this; - }; - - - /** - * Enables dragging. - * - * @method enable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.enable = function() { - this.drag_api.enable(); - return this; - }; - - - /** - * Add a new widget to the grid. - * - * @method add_widget - * @param {String|HTMLElement} html The string representing the HTML of the widget - * or the HTMLElement. - * @param {Number} [size_x] The nº of rows the widget occupies horizontally. - * @param {Number} [size_y] The nº of columns the widget occupies vertically. - * @param {Number} [col] The column the widget should start in. - * @param {Number} [row] The row the widget should start in. - * @return {HTMLElement} Returns the jQuery wrapped HTMLElement representing. - * the widget that was just created. - */ - fn.add_widget = function(html, size_x, size_y, col, row) { - var pos; - size_x || (size_x = 1); - size_y || (size_y = 1); - - if (!col & !row) { - pos = this.next_position(size_x, size_y); - }else{ - pos = { - col: col, - row: row - }; - - this.empty_cells(col, row, size_x, size_y); - } - - var $w = $(html).attr({ - 'data-col': pos.col, - 'data-row': pos.row, - 'data-sizex' : size_x, - 'data-sizey' : size_y - }).addClass('gs_w').appendTo(this.$el).hide(); - - this.$widgets = this.$widgets.add($w); - - this.register_widget($w); - - this.add_faux_rows(pos.size_y); - //this.add_faux_cols(pos.size_x); - - this.set_dom_grid_height(); - - return $w.fadeIn(); - }; - - - - /** - * Change the size of a widget. - * - * @method resize_widget - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement - * representing the widget. - * @param {Number} size_x The number of columns that will occupy the widget. - * @param {Number} size_y The number of rows that will occupy the widget. - * @return {HTMLElement} Returns $widget. - */ - fn.resize_widget = function($widget, size_x, size_y) { - var wgd = $widget.coords().grid; - size_x || (size_x = wgd.size_x); - size_y || (size_y = wgd.size_y); - - if (size_x > this.cols) { - size_x = this.cols; - } - - var old_cells_occupied = this.get_cells_occupied(wgd); - var old_size_x = wgd.size_x; - var old_size_y = wgd.size_y; - var old_col = wgd.col; - var new_col = old_col; - var wider = size_x > old_size_x; - var taller = size_y > old_size_y; - - if (old_col + size_x - 1 > this.cols) { - var diff = old_col + (size_x - 1) - this.cols; - var c = old_col - diff; - new_col = Math.max(1, c); - } - - var new_grid_data = { - col: new_col, - row: wgd.row, - size_x: size_x, - size_y: size_y - }; - - var new_cells_occupied = this.get_cells_occupied(new_grid_data); - - var empty_cols = []; - $.each(old_cells_occupied.cols, function(i, col) { - if ($.inArray(col, new_cells_occupied.cols) === -1) { - empty_cols.push(col); - } - }); - - var occupied_cols = []; - $.each(new_cells_occupied.cols, function(i, col) { - if ($.inArray(col, old_cells_occupied.cols) === -1) { - occupied_cols.push(col); - } - }); - - var empty_rows = []; - $.each(old_cells_occupied.rows, function(i, row) { - if ($.inArray(row, new_cells_occupied.rows) === -1) { - empty_rows.push(row); - } - }); - - var occupied_rows = []; - $.each(new_cells_occupied.rows, function(i, row) { - if ($.inArray(row, old_cells_occupied.rows) === -1) { - occupied_rows.push(row); - } - }); - - this.remove_from_gridmap(wgd); - - if (occupied_cols.length) { - var cols_to_empty = [ - new_col, wgd.row, size_x, Math.min(old_size_y, size_y), $widget - ]; - this.empty_cells.apply(this, cols_to_empty); - } - - if (occupied_rows.length) { - var rows_to_empty = [new_col, wgd.row, size_x, size_y, $widget]; - this.empty_cells.apply(this, rows_to_empty); - } - - wgd.col = new_col; - wgd.size_x = size_x; - wgd.size_y = size_y; - this.add_to_gridmap(new_grid_data, $widget); - - //update coords instance attributes - $widget.data('coords').update({ - width: (size_x * this.options.widget_base_dimensions[0] + - ((size_x - 1) * this.options.widget_margins[0]) * 2), - height: (size_y * this.options.widget_base_dimensions[1] + - ((size_y - 1) * this.options.widget_margins[1]) * 2) - }); - - if (size_y > old_size_y) { - this.add_faux_rows(size_y - old_size_y); - } - - if (size_x > old_size_x) { - this.add_faux_cols(size_x - old_size_x); - } - - $widget.attr({ - 'data-col': new_col, - 'data-sizex': size_x, - 'data-sizey': size_y - }); - - if (empty_cols.length) { - var cols_to_remove_holes = [ - empty_cols[0], wgd.row, - empty_cols.length, - Math.min(old_size_y, size_y), - $widget - ]; - - this.remove_empty_cells.apply(this, cols_to_remove_holes); - } - - if (empty_rows.length) { - var rows_to_remove_holes = [ - new_col, wgd.row, size_x, size_y, $widget - ]; - this.remove_empty_cells.apply(this, rows_to_remove_holes); - } - - return $widget; - }; - - /** - * Move down widgets in cells represented by the arguments col, row, size_x, - * size_y - * - * @method empty_cells - * @param {Number} col The column where the group of cells begin. - * @param {Number} row The row where the group of cells begin. - * @param {Number} size_x The number of columns that the group of cells - * occupy. - * @param {Number} size_y The number of rows that the group of cells - * occupy. - * @param {HTMLElement} $exclude Exclude widgets from being moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.empty_cells = function(col, row, size_x, size_y, $exclude) { - var $nexts = this.widgets_below({ - col: col, - row: row - size_y, - size_x: size_x, - size_y: size_y - }); - - $nexts.not($exclude).each($.proxy(function(i, w) { - var wgd = $(w).coords().grid; - if (!(wgd.row <= (row + size_y - 1))) { return; } - var diff = (row + size_y) - wgd.row; - this.move_widget_down($(w), diff); - }, this)); - - this.set_dom_grid_height(); - - return this; - }; - - - /** - * Move up widgets below cells represented by the arguments col, row, size_x, - * size_y. - * - * @method remove_empty_cells - * @param {Number} col The column where the group of cells begin. - * @param {Number} row The row where the group of cells begin. - * @param {Number} size_x The number of columns that the group of cells - * occupy. - * @param {Number} size_y The number of rows that the group of cells - * occupy. - * @param {HTMLElement} exclude Exclude widgets from being moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_empty_cells = function(col, row, size_x, size_y, exclude) { - var $nexts = this.widgets_below({ - col: col, - row: row, - size_x: size_x, - size_y: size_y - }); - - $nexts.not(exclude).each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), size_y ); - }, this)); - - this.set_dom_grid_height(); - - return this; - }; - - - /** - * Get the most left column below to add a new widget. - * - * @method next_position - * @param {Number} size_x The nº of rows the widget occupies horizontally. - * @param {Number} size_y The nº of columns the widget occupies vertically. - * @return {Object} Returns a grid coords object representing the future - * widget coords. - */ - fn.next_position = function(size_x, size_y) { - size_x || (size_x = 1); - size_y || (size_y = 1); - var ga = this.gridmap; - var cols_l = ga.length; - var valid_pos = []; - var rows_l; - - for (var c = 1; c < cols_l; c++) { - rows_l = ga[c].length; - for (var r = 1; r <= rows_l; r++) { - var can_move_to = this.can_move_to({ - size_x: size_x, - size_y: size_y - }, c, r); - - if (can_move_to) { - valid_pos.push({ - col: c, - row: r, - size_y: size_y, - size_x: size_x - }); - } - } - } - - if (valid_pos.length) { - return this.sort_by_row_and_col_asc(valid_pos)[0]; - } - return false; - }; - - - /** - * Remove a widget from the grid. - * - * @method remove_widget - * @param {HTMLElement} el The jQuery wrapped HTMLElement you want to remove. - * @param {Boolean|Function} silent If true, widgets below the removed one - * will not move up. If a Function is passed it will be used as callback. - * @param {Function} callback Function executed when the widget is removed. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_widget = function(el, silent, callback) { - var $el = el instanceof jQuery ? el : $(el); - var wgd = $el.coords().grid; - - // if silent is a function assume it's a callback - if ($.isFunction(silent)) { - callback = silent; - silent = false; - } - - this.cells_occupied_by_placeholder = {}; - this.$widgets = this.$widgets.not($el); - - var $nexts = this.widgets_below($el); - - this.remove_from_gridmap(wgd); - - $el.fadeOut($.proxy(function() { - $el.remove(); - - if (!silent) { - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget), wgd.size_y ); - }, this)); - } - - this.set_dom_grid_height(); - - if (callback) { - callback.call(this, el); - } - }, this)); - }; - - - /** - * Remove all widgets from the grid. - * - * @method remove_all_widgets - * @param {Function} callback Function executed for each widget removed. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_all_widgets = function(callback) { - this.$widgets.each($.proxy(function(i, el){ - this.remove_widget(el, true, callback); - }, this)); - - return this; - }; - - - /** - * Returns a serialized array of the widgets in the grid. - * - * @method serialize - * @param {HTMLElement} [$widgets] The collection of jQuery wrapped - * HTMLElements you want to serialize. If no argument is passed all widgets - * will be serialized. - * @return {Array} Returns an Array of Objects with the data specified in - * the serialize_params option. - */ - fn.serialize = function($widgets) { - $widgets || ($widgets = this.$widgets); - var result = []; - $widgets.each($.proxy(function(i, widget) { - result.push(this.options.serialize_params( - $(widget), $(widget).coords().grid ) ); - }, this)); - - return result; - }; - - - /** - * Returns a serialized array of the widgets that have changed their - * position. - * - * @method serialize_changed - * @return {Array} Returns an Array of Objects with the data specified in - * the serialize_params option. - */ - fn.serialize_changed = function() { - return this.serialize(this.$changed); - }; - - - /** - * Creates the grid coords object representing the widget a add it to the - * mapped array of positions. - * - * @method register_widget - * @return {Array} Returns the instance of the Gridster class. - */ - fn.register_widget = function($el) { - - var wgd = { - 'col': parseInt($el.attr('data-col'), 10), - 'row': parseInt($el.attr('data-row'), 10), - 'size_x': parseInt($el.attr('data-sizex'), 10), - 'size_y': parseInt($el.attr('data-sizey'), 10), - 'el': $el - }; - - if (this.options.avoid_overlapped_widgets && - !this.can_move_to( - {size_x: wgd.size_x, size_y: wgd.size_y}, wgd.col, wgd.row) - ) { - wgd = this.next_position(wgd.size_x, wgd.size_y); - wgd.el = $el; - $el.attr({ - 'data-col': wgd.col, - 'data-row': wgd.row, - 'data-sizex': wgd.size_x, - 'data-sizey': wgd.size_y - }); - } - - // attach Coord object to player data-coord attribute - $el.data('coords', $el.coords()); - - // Extend Coord object with grid position info - $el.data('coords').grid = wgd; - - this.add_to_gridmap(wgd, $el); - - return this; - }; - - - /** - * Update in the mapped array of positions the value of cells represented by - * the grid coords object passed in the `grid_data` param. - * - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @param {HTMLElement|Boolean} value Pass `false` or the jQuery wrapped - * HTMLElement, depends if you want to delete an existing position or add - * a new one. - * @method update_widget_position - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.update_widget_position = function(grid_data, value) { - this.for_each_cell_occupied(grid_data, function(col, row) { - if (!this.gridmap[col]) { return this; } - this.gridmap[col][row] = value; - }); - return this; - }; - - - /** - * Remove a widget from the mapped array of positions. - * - * @method remove_from_gridmap - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.remove_from_gridmap = function(grid_data) { - return this.update_widget_position(grid_data, false); - }; - - - /** - * Add a widget to the mapped array of positions. - * - * @method add_to_gridmap - * @param {Object} grid_data The grid coords object representing the cells - * to update in the mapped array. - * @param {HTMLElement|Boolean} value The value to set in the specified - * position . - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.add_to_gridmap = function(grid_data, value) { - this.update_widget_position(grid_data, value || grid_data.el); - - if (grid_data.el) { - var $widgets = this.widgets_below(grid_data.el); - $widgets.each($.proxy(function(i, widget) { - this.move_widget_up( $(widget)); - }, this)); - } - }; - - - /** - * Make widgets draggable. - * - * @uses Draggable - * @method draggable - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.draggable = function() { - var self = this; - var draggable_options = $.extend(true, {}, this.options.draggable, { - offset_left: this.options.widget_margins[0], - start: function(event, ui) { - self.$widgets.filter('.player-revert') - .removeClass('player-revert'); - - self.$player = $(this); - self.$helper = self.options.draggable.helper === 'clone' ? - $(ui.helper) : self.$player; - self.helper = !self.$helper.is(self.$player); - - self.on_start_drag.call(self, event, ui); - self.$el.trigger('gridster:dragstart'); - }, - stop: function(event, ui) { - self.on_stop_drag.call(self, event, ui); - self.$el.trigger('gridster:dragstop'); - }, - drag: throttle(function(event, ui) { - self.on_drag.call(self, event, ui); - self.$el.trigger('gridster:drag'); - }, 60) - }); - - this.drag_api = this.$el.drag(draggable_options).data('drag'); - return this; - }; - - - /** - * This function is executed when the player begins to be dragged. - * - * @method on_start_drag - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object. - */ - fn.on_start_drag = function(event, ui) { - - this.$helper.add(this.$player).add(this.$wrapper).addClass('dragging'); - - this.$player.addClass('player'); - this.player_grid_data = this.$player.coords().grid; - this.placeholder_grid_data = $.extend({}, this.player_grid_data); - - //set new grid height along the dragging period - this.$el.css('height', this.$el.height() + - (this.player_grid_data.size_y * this.min_widget_height)); - - var colliders = this.faux_grid; - var coords = this.$player.data('coords').coords; - - this.cells_occupied_by_player = this.get_cells_occupied( - this.player_grid_data); - this.cells_occupied_by_placeholder = this.get_cells_occupied( - this.placeholder_grid_data); - - this.last_cols = []; - this.last_rows = []; - - - // see jquery.collision.js - this.collision_api = this.$helper.collision( - colliders, this.options.collision); - - this.$preview_holder = $('
  • ', { - 'class': 'preview-holder', - 'data-row': this.$player.attr('data-row'), - 'data-col': this.$player.attr('data-col'), - css: { - width: coords.width, - height: coords.height - } - }).appendTo(this.$el); - - if (this.options.draggable.start) { - this.options.draggable.start.call(this, event, ui); - } - }; - - - /** - * This function is executed when the player is being dragged. - * - * @method on_drag - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object. - */ - fn.on_drag = function(event, ui) { - //break if dragstop has been fired - if (this.$player === null) { - return false; - } - - var abs_offset = { - left: ui.position.left + this.baseX, - top: ui.position.top + this.baseY - }; - - this.colliders_data = this.collision_api.get_closest_colliders( - abs_offset); - - this.on_overlapped_column_change( - this.on_start_overlapping_column, - this.on_stop_overlapping_column - ); - - this.on_overlapped_row_change( - this.on_start_overlapping_row, - this.on_stop_overlapping_row - ); - - if (this.helper && this.$player) { - this.$player.css({ - 'left': ui.position.left, - 'top': ui.position.top - }); - } - - if (this.options.draggable.drag) { - this.options.draggable.drag.call(this, event, ui); - } - }; - - /** - * This function is executed when the player stops being dragged. - * - * @method on_stop_drag - * @param {Event} event The original browser event - * @param {Object} ui A prepared ui object. - */ - fn.on_stop_drag = function(event, ui) { - this.$helper.add(this.$player).add(this.$wrapper) - .removeClass('dragging'); - - ui.position.left = ui.position.left + this.baseX; - ui.position.top = ui.position.top + this.baseY; - this.colliders_data = this.collision_api.get_closest_colliders(ui.position); - - this.on_overlapped_column_change( - this.on_start_overlapping_column, - this.on_stop_overlapping_column - ); - - this.on_overlapped_row_change( - this.on_start_overlapping_row, - this.on_stop_overlapping_row - ); - - this.$player.addClass('player-revert').removeClass('player') - .attr({ - 'data-col': this.placeholder_grid_data.col, - 'data-row': this.placeholder_grid_data.row - }).css({ - 'left': '', - 'top': '' - }); - - this.$changed = this.$changed.add(this.$player); - - this.cells_occupied_by_player = this.get_cells_occupied( - this.placeholder_grid_data); - this.set_cells_player_occupies( - this.placeholder_grid_data.col, this.placeholder_grid_data.row); - - this.$player.coords().grid.row = this.placeholder_grid_data.row; - this.$player.coords().grid.col = this.placeholder_grid_data.col; - - if (this.options.draggable.stop) { - this.options.draggable.stop.call(this, event, ui); - } - - this.$preview_holder.remove(); - - this.$player = null; - this.$helper = null; - this.placeholder_grid_data = {}; - this.player_grid_data = {}; - this.cells_occupied_by_placeholder = {}; - this.cells_occupied_by_player = {}; - - this.set_dom_grid_height(); - }; - - - /** - * Executes the callbacks passed as arguments when a column begins to be - * overlapped or stops being overlapped. - * - * @param {Function} start_callback Function executed when a new column - * begins to be overlapped. The column is passed as first argument. - * @param {Function} stop_callback Function executed when a column stops - * being overlapped. The column is passed as first argument. - * @method on_overlapped_column_change - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.on_overlapped_column_change = function(start_callback, stop_callback) { - if (!this.colliders_data.length) { - return this; - } - var cols = this.get_targeted_columns( - this.colliders_data[0].el.data.col); - - var last_n_cols = this.last_cols.length; - var n_cols = cols.length; - var i; - - for (i = 0; i < n_cols; i++) { - if ($.inArray(cols[i], this.last_cols) === -1) { - (start_callback || $.noop).call(this, cols[i]); - } - } - - for (i = 0; i< last_n_cols; i++) { - if ($.inArray(this.last_cols[i], cols) === -1) { - (stop_callback || $.noop).call(this, this.last_cols[i]); - } - } - - this.last_cols = cols; - - return this; - }; - - - /** - * Executes the callbacks passed as arguments when a row starts to be - * overlapped or stops being overlapped. - * - * @param {Function} start_callback Function executed when a new row begins - * to be overlapped. The row is passed as first argument. - * @param {Function} end_callback Function executed when a row stops being - * overlapped. The row is passed as first argument. - * @method on_overlapped_row_change - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.on_overlapped_row_change = function(start_callback, end_callback) { - if (!this.colliders_data.length) { - return this; - } - var rows = this.get_targeted_rows(this.colliders_data[0].el.data.row); - var last_n_rows = this.last_rows.length; - var n_rows = rows.length; - var i; - - for (i = 0; i < n_rows; i++) { - if ($.inArray(rows[i], this.last_rows) === -1) { - (start_callback || $.noop).call(this, rows[i]); - } - } - - for (i = 0; i < last_n_rows; i++) { - if ($.inArray(this.last_rows[i], rows) === -1) { - (end_callback || $.noop).call(this, this.last_rows[i]); - } - } - - this.last_rows = rows; - }; - - - /** - * Sets the current position of the player - * - * @param {Number} col - * @param {Number} row - * @param {Boolean} no_player - * @method set_player - * @return {object} - */ - fn.set_player = function(col, row, no_player) { - var self = this; - if (!no_player) { - this.empty_cells_player_occupies(); - } - var cell = !no_player ? self.colliders_data[0].el.data : {col: col}; - var to_col = cell.col; - var to_row = row || cell.row; - - this.player_grid_data = { - col: to_col, - row: to_row, - size_y : this.player_grid_data.size_y, - size_x : this.player_grid_data.size_x - }; - - this.cells_occupied_by_player = this.get_cells_occupied( - this.player_grid_data); - - var $overlapped_widgets = this.get_widgets_overlapped( - this.player_grid_data); - - var constraints = this.widgets_constraints($overlapped_widgets); - - this.manage_movements(constraints.can_go_up, to_col, to_row); - this.manage_movements(constraints.can_not_go_up, to_col, to_row); - - /* if there is not widgets overlapping in the new player position, - * update the new placeholder position. */ - if (!$overlapped_widgets.length) { - var pp = this.can_go_player_up(this.player_grid_data); - if (pp !== false) { - to_row = pp; - } - this.set_placeholder(to_col, to_row); - } - - return { - col: to_col, - row: to_row - }; - }; - - - /** - * See which of the widgets in the $widgets param collection can go to - * a upper row and which not. - * - * @method widgets_contraints - * @param {jQuery} $widgets A jQuery wrapped collection of - * HTMLElements. - * @return {object} Returns a literal Object with two keys: `can_go_up` & - * `can_not_go_up`. Each contains a set of HTMLElements. - */ - fn.widgets_constraints = function($widgets) { - var $widgets_can_go_up = $([]); - var $widgets_can_not_go_up; - var wgd_can_go_up = []; - var wgd_can_not_go_up = []; - - $widgets.each($.proxy(function(i, w) { - var $w = $(w); - var wgd = $w.coords().grid; - if (this.can_go_widget_up(wgd)) { - $widgets_can_go_up = $widgets_can_go_up.add($w); - wgd_can_go_up.push(wgd); - }else{ - wgd_can_not_go_up.push(wgd); - } - }, this)); - - $widgets_can_not_go_up = $widgets.not($widgets_can_go_up); - - return { - can_go_up: this.sort_by_row_asc(wgd_can_go_up), - can_not_go_up: this.sort_by_row_desc(wgd_can_not_go_up) - }; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in ascending way. - * - * @method sort_by_row_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_row_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (!a.row) { - a = $(a).coords().grid; - b = $(b).coords().grid; - } - - if (a.row > b.row) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) placing first the empty cells upper left. - * - * @method sort_by_row_and_col_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_row_and_col_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.row > b.row || a.row === b.row && a.col > b.col) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects by column (representing the grid - * coords of each widget) in ascending way. - * - * @method sort_by_col_asc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_col_asc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.col > b.col) { - return 1; - } - return -1; - }); - - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in descending way. - * - * @method sort_by_row_desc - * @param {Array} widgets Array of grid coords objects - * @return {Array} Returns the array sorted. - */ - fn.sort_by_row_desc = function(widgets) { - widgets = widgets.sort(function(a, b) { - if (a.row + a.size_y < b.row + b.size_y) { - return 1; - } - return -1; - }); - return widgets; - }; - - - /** - * Sorts an Array of grid coords objects (representing the grid coords of - * each widget) in descending way. - * - * @method manage_movements - * @param {jQuery} $widgets A jQuery collection of HTMLElements - * representing the widgets you want to move. - * @param {Number} to_col The column to which we want to move the widgets. - * @param {Number} to_row The row to which we want to move the widgets. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.manage_movements = function($widgets, to_col, to_row) { - $.each($widgets, $.proxy(function(i, w) { - var wgd = w; - var $w = wgd.el; - - var can_go_widget_up = this.can_go_widget_up(wgd); - - if (can_go_widget_up) { - //target CAN go up - //so move widget up - this.move_widget_to($w, can_go_widget_up); - this.set_placeholder(to_col, can_go_widget_up + wgd.size_y); - - } else { - //target can't go up - var can_go_player_up = this.can_go_player_up( - this.player_grid_data); - - if (!can_go_player_up) { - // target can't go up - // player cant't go up - // so we need to move widget down to a position that dont - // overlaps player - var y = (to_row + this.player_grid_data.size_y) - wgd.row; - - this.move_widget_down($w, y); - this.set_placeholder(to_col, to_row); - } - } - }, this)); - - return this; - }; - - /** - * Determines if there is a widget in the row and col given. Or if the - * HTMLElement passed as first argument is the player. - * - * @method is_player - * @param {Number|HTMLElement} col_or_el A jQuery wrapped collection of - * HTMLElements. - * @param {Number} [row] The column to which we want to move the widgets. - * @return {Boolean} Returns true or false. - */ - fn.is_player = function(col_or_el, row) { - if (row && !this.gridmap[col_or_el]) { return false; } - var $w = row ? this.gridmap[col_or_el][row] : col_or_el; - return $w && ($w.is(this.$player) || $w.is(this.$helper)); - }; - - - /** - * Determines if the widget that is being dragged is currently over the row - * and col given. - * - * @method is_player_in - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_player_in = function(col, row) { - var c = this.cells_occupied_by_player || {}; - return $.inArray(col, c.cols) >= 0 && $.inArray(row, c.rows) >= 0; - }; - - - /** - * Determines if the placeholder is currently over the row and col given. - * - * @method is_placeholder_in - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_placeholder_in = function(col, row) { - var c = this.cells_occupied_by_placeholder || {}; - return this.is_placeholder_in_col(col) && $.inArray(row, c.rows) >= 0; - }; - - - /** - * Determines if the placeholder is currently over the column given. - * - * @method is_placeholder_in_col - * @param {Number} col The column to check. - * @return {Boolean} Returns true or false. - */ - fn.is_placeholder_in_col = function(col) { - var c = this.cells_occupied_by_placeholder || []; - return $.inArray(col, c.cols) >= 0; - }; - - - /** - * Determines if the cell represented by col and row params is empty. - * - * @method is_empty - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_empty = function(col, row) { - if (typeof this.gridmap[col] !== 'undefined' && - typeof this.gridmap[col][row] !== 'undefined' && - this.gridmap[col][row] === false - ) { - return true; - } - return false; - }; - - - /** - * Determines if the cell represented by col and row params is occupied. - * - * @method is_occupied - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_occupied = function(col, row) { - if (!this.gridmap[col]) { - return false; - } - - if (this.gridmap[col][row]) { - return true; - } - return false; - }; - - - /** - * Determines if there is a widget in the cell represented by col/row params. - * - * @method is_widget - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean|HTMLElement} Returns false if there is no widget, - * else returns the jQuery HTMLElement - */ - fn.is_widget = function(col, row) { - var cell = this.gridmap[col]; - if (!cell) { - return false; - } - - cell = cell[row]; - - if (cell) { - return cell; - } - - return false; - }; - - - /** - * Determines if there is a widget in the cell represented by col/row - * params and if this is under the widget that is being dragged. - * - * @method is_widget_under_player - * @param {Number} col The column to check. - * @param {Number} row The row to check. - * @return {Boolean} Returns true or false. - */ - fn.is_widget_under_player = function(col, row) { - if (this.is_widget(col, row)) { - return this.is_player_in(col, row); - } - return false; - }; - - - /** - * Get widgets overlapping with the player or with the object passed - * representing the grid cells. - * - * @method get_widgets_under_player - * @return {HTMLElement} Returns a jQuery collection of HTMLElements - */ - fn.get_widgets_under_player = function(cells) { - cells || (cells = this.cells_occupied_by_player || {cols: [], rows: []}); - var $widgets = $([]); - - $.each(cells.cols, $.proxy(function(i, col) { - $.each(cells.rows, $.proxy(function(i, row) { - if(this.is_widget(col, row)) { - $widgets = $widgets.add(this.gridmap[col][row]); - } - }, this)); - }, this)); - - return $widgets; - }; - - - /** - * Put placeholder at the row and column specified. - * - * @method set_placeholder - * @param {Number} col The column to which we want to move the - * placeholder. - * @param {Number} row The row to which we want to move the - * placeholder. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_placeholder = function(col, row) { - var phgd = $.extend({}, this.placeholder_grid_data); - var $nexts = this.widgets_below({ - col: phgd.col, - row: phgd.row, - size_y: phgd.size_y, - size_x: phgd.size_x - }); - - // Prevents widgets go out of the grid - var right_col = (col + phgd.size_x - 1); - if (right_col > this.cols) { - col = col - (right_col - col); - } - - var moved_down = this.placeholder_grid_data.row < row; - var changed_column = this.placeholder_grid_data.col !== col; - - this.placeholder_grid_data.col = col; - this.placeholder_grid_data.row = row; - - this.cells_occupied_by_placeholder = this.get_cells_occupied( - this.placeholder_grid_data); - - this.$preview_holder.attr({ - 'data-row' : row, - 'data-col' : col - }); - - if (moved_down || changed_column) { - $nexts.each($.proxy(function(i, widget) { - this.move_widget_up( - $(widget), this.placeholder_grid_data.col - col + phgd.size_y); - }, this)); - } - - - var $widgets_under_ph = this.get_widgets_under_player(this.cells_occupied_by_placeholder); - if ($widgets_under_ph.length) { - $widgets_under_ph.each($.proxy(function(i, widget) { - var $w = $(widget); - this.move_widget_down( - $w, row + phgd.size_y - $w.data('coords').grid.row); - }, this)); - } - - }; - - - /** - * Determines whether the player can move to a position above. - * - * @method can_go_player_up - * @param {Object} widget_grid_data The actual grid coords object of the - * player. - * @return {Number|Boolean} If the player can be moved to an upper row - * returns the row number, else returns false. - */ - fn.can_go_player_up = function(widget_grid_data) { - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var result = true; - var upper_rows = []; - var min_row = 10000; - var $widgets_under_player = this.get_widgets_under_player(); - - /* generate an array with columns as index and array with upper rows - * empty as value */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = this.gridmap[tcol]; - var r = p_bottom_row + 1; - upper_rows[tcol] = []; - - while (--r > 0) { - if (this.is_empty(tcol, r) || this.is_player(tcol, r) || - this.is_widget(tcol, r) && - grid_col[r].is($widgets_under_player) - ) { - upper_rows[tcol].push(r); - min_row = r < min_row ? r : min_row; - }else{ - break; - } - } - - if (upper_rows[tcol].length === 0) { - result = false; - return true; //break - } - - upper_rows[tcol].sort(); - }); - - if (!result) { return false; } - - return this.get_valid_rows(widget_grid_data, upper_rows, min_row); - }; - - - /** - * Determines whether a widget can move to a position above. - * - * @method can_go_widget_up - * @param {Object} widget_grid_data The actual grid coords object of the - * widget we want to check. - * @return {Number|Boolean} If the widget can be moved to an upper row - * returns the row number, else returns false. - */ - fn.can_go_widget_up = function(widget_grid_data) { - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var result = true; - var upper_rows = []; - var min_row = 10000; - - /* generate an array with columns as index and array with topmost rows - * empty as value */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = this.gridmap[tcol]; - upper_rows[tcol] = []; - - var r = p_bottom_row + 1; - // iterate over each row - while (--r > 0) { - if (this.is_widget(tcol, r) && !this.is_player_in(tcol, r)) { - if (!grid_col[r].is(widget_grid_data.el)) { - break; - } - } - - if (!this.is_player(tcol, r) && - !this.is_placeholder_in(tcol, r) && - !this.is_player_in(tcol, r)) { - upper_rows[tcol].push(r); - } - - if (r < min_row) { - min_row = r; - } - } - - if (upper_rows[tcol].length === 0) { - result = false; - return true; //break - } - - upper_rows[tcol].sort(); - }); - - if (!result) { return false; } - - return this.get_valid_rows(widget_grid_data, upper_rows, min_row); - }; - - - /** - * Search a valid row for the widget represented by `widget_grid_data' in - * the `upper_rows` array. Iteration starts from row specified in `min_row`. - * - * @method get_valid_rows - * @param {Object} widget_grid_data The actual grid coords object of the - * player. - * @param {Array} upper_rows An array with columns as index and arrays - * of valid rows as values. - * @param {Number} min_row The upper row from which the iteration will start. - * @return {Number|Boolean} Returns the upper row valid from the `upper_rows` - * for the widget in question. - */ - fn.get_valid_rows = function(widget_grid_data, upper_rows, min_row) { - var p_top_row = widget_grid_data.row; - var p_bottom_row = widget_grid_data.row + widget_grid_data.size_y - 1; - var size_y = widget_grid_data.size_y; - var r = min_row - 1; - var valid_rows = []; - - while (++r <= p_bottom_row ) { - var common = true; - $.each(upper_rows, function(col, rows) { - if ($.isArray(rows) && $.inArray(r, rows) === -1) { - common = false; - } - }); - - if (common === true) { - valid_rows.push(r); - if (valid_rows.length === size_y) { - break; - } - } - } - - var new_row = false; - if (size_y === 1) { - if (valid_rows[0] !== p_top_row) { - new_row = valid_rows[0] || false; - } - }else{ - if (valid_rows[0] !== p_top_row) { - new_row = this.get_consecutive_numbers_index( - valid_rows, size_y); - } - } - - return new_row; - }; - - - fn.get_consecutive_numbers_index = function(arr, size_y) { - var max = arr.length; - var result = []; - var first = true; - var prev = -1; // or null? - - for (var i=0; i < max; i++) { - if (first || arr[i] === prev + 1) { - result.push(i); - if (result.length === size_y) { - break; - } - first = false; - }else{ - result = []; - first = true; - } - - prev = arr[i]; - } - - return result.length >= size_y ? arr[result[0]] : false; - }; - - - /** - * Get widgets overlapping with the player. - * - * @method get_widgets_overlapped - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.get_widgets_overlapped = function() { - var $w; - var $widgets = $([]); - var used = []; - var rows_from_bottom = this.cells_occupied_by_player.rows.slice(0); - rows_from_bottom.reverse(); - - $.each(this.cells_occupied_by_player.cols, $.proxy(function(i, col) { - $.each(rows_from_bottom, $.proxy(function(i, row) { - // if there is a widget in the player position - if (!this.gridmap[col]) { return true; } //next iteration - var $w = this.gridmap[col][row]; - if (this.is_occupied(col, row) && !this.is_player($w) && - $.inArray($w, used) === -1 - ) { - $widgets = $widgets.add($w); - used.push($w); - } - - }, this)); - }, this)); - - return $widgets; - }; - - - /** - * This callback is executed when the player begins to collide with a column. - * - * @method on_start_overlapping_column - * @param {Number} col The collided column. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_start_overlapping_column = function(col) { - this.set_player(col, false); - }; - - - /** - * A callback executed when the player begins to collide with a row. - * - * @method on_start_overlapping_row - * @param {Number} row The collided row. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_start_overlapping_row = function(row) { - this.set_player(false, row); - }; - - - /** - * A callback executed when the the player ends to collide with a column. - * - * @method on_stop_overlapping_column - * @param {Number} col The collided row. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_stop_overlapping_column = function(col) { - this.set_player(col, false); - - var self = this; - this.for_each_widget_below(col, this.cells_occupied_by_player.rows[0], - function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); - }; - - - /** - * This callback is executed when the player ends to collide with a row. - * - * @method on_stop_overlapping_row - * @param {Number} row The collided row. - * @return {jQuery} Returns a jQuery collection of HTMLElements. - */ - fn.on_stop_overlapping_row = function(row) { - this.set_player(false, row); - - var self = this; - var cols = this.cells_occupied_by_player.cols; - for (var c = 0, cl = cols.length; c < cl; c++) { - this.for_each_widget_below(cols[c], row, function(tcol, trow) { - self.move_widget_up(this, self.player_grid_data.size_y); - }); - } - }; - - - /** - * Move a widget to a specific row. The cell or cells must be empty. - * If the widget has widgets below, all of these widgets will be moved also - * if they can. - * - * @method move_widget_to - * @param {HTMLElement} $widget The jQuery wrapped HTMLElement of the - * widget is going to be moved. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_to = function($widget, row) { - var self = this; - var widget_grid_data = $widget.coords().grid; - var diff = row - widget_grid_data.row; - var $next_widgets = this.widgets_below($widget); - - var can_move_to_new_cell = this.can_move_to( - widget_grid_data, widget_grid_data.col, row, $widget); - - if (can_move_to_new_cell === false) { - return false; - } - - this.remove_from_gridmap(widget_grid_data); - widget_grid_data.row = row; - this.add_to_gridmap(widget_grid_data); - $widget.attr('data-row', row); - this.$changed = this.$changed.add($widget); - - - $next_widgets.each(function(i, widget) { - var $w = $(widget); - var wgd = $w.coords().grid; - var can_go_up = self.can_go_widget_up(wgd); - if (can_go_up && can_go_up !== wgd.row) { - self.move_widget_to($w, can_go_up); - } - }); - - return this; - }; - - - /** - * Move up the specified widget and all below it. - * - * @method move_widget_up - * @param {HTMLElement} $widget The widget you want to move. - * @param {Number} [y_units] The number of cells that the widget has to move. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_up = function($widget, y_units) { - var el_grid_data = $widget.coords().grid; - var actual_row = el_grid_data.row; - var moved = []; - var can_go_up = true; - y_units || (y_units = 1); - - if (!this.can_go_up($widget)) { return false; } //break; - - this.for_each_column_occupied(el_grid_data, function(col) { - // can_go_up - if ($.inArray($widget, moved) === -1) { - var widget_grid_data = $widget.coords().grid; - var next_row = actual_row - y_units; - next_row = this.can_go_up_to_row( - widget_grid_data, col, next_row); - - if (!next_row) { - return true; - } - - var $next_widgets = this.widgets_below($widget); - - this.remove_from_gridmap(widget_grid_data); - widget_grid_data.row = next_row; - this.add_to_gridmap(widget_grid_data); - $widget.attr('data-row', widget_grid_data.row); - this.$changed = this.$changed.add($widget); - - moved.push($widget); - - $next_widgets.each($.proxy(function(i, widget) { - this.move_widget_up($(widget), y_units); - }, this)); - } - }); - - }; - - - /** - * Move down the specified widget and all below it. - * - * @method move_widget_down - * @param {jQuery} $widget The jQuery object representing the widget - * you want to move. - * @param {Number} y_units The number of cells that the widget has to move. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.move_widget_down = function($widget, y_units) { - var el_grid_data = $widget.coords().grid; - var actual_row = el_grid_data.row; - var moved = []; - var y_diff = y_units; - - if (!$widget) { return false; } - - if ($.inArray($widget, moved) === -1) { - - var widget_grid_data = $widget.coords().grid; - var next_row = actual_row + y_units; - var $next_widgets = this.widgets_below($widget); - - this.remove_from_gridmap(widget_grid_data); - - $next_widgets.each($.proxy(function(i, widget) { - var $w = $(widget); - var wd = $w.coords().grid; - var tmp_y = this.displacement_diff( - wd, widget_grid_data, y_diff); - - if (tmp_y > 0) { - this.move_widget_down($w, tmp_y); - } - }, this)); - - widget_grid_data.row = next_row; - this.update_widget_position(widget_grid_data, $widget); - $widget.attr('data-row', widget_grid_data.row); - this.$changed = this.$changed.add($widget); - - moved.push($widget); - } - }; - - - /** - * Check if the widget can move to the specified row, else returns the - * upper row possible. - * - * @method can_go_up_to_row - * @param {Number} widget_grid_data The current grid coords object of the - * widget. - * @param {Number} col The target column. - * @param {Number} row The target row. - * @return {Boolean|Number} Returns the row number if the widget can move - * to the target position, else returns false. - */ - fn.can_go_up_to_row = function(widget_grid_data, col, row) { - var ga = this.gridmap; - var result = true; - var urc = []; // upper_rows_in_columns - var actual_row = widget_grid_data.row; - var r; - - /* generate an array with columns as index and array with - * upper rows empty in the column */ - this.for_each_column_occupied(widget_grid_data, function(tcol) { - var grid_col = ga[tcol]; - urc[tcol] = []; - - r = actual_row; - while (r--) { - if (this.is_empty(tcol, r) && - !this.is_placeholder_in(tcol, r) - ) { - urc[tcol].push(r); - }else{ - break; - } - } - - if (!urc[tcol].length) { - result = false; - return true; - } - - }); - - if (!result) { return false; } - - /* get common rows starting from upper position in all the columns - * that widget occupies */ - r = row; - for (r = 1; r < actual_row; r++) { - var common = true; - - for (var uc = 0, ucl = urc.length; uc < ucl; uc++) { - if (urc[uc] && $.inArray(r, urc[uc]) === -1) { - common = false; - } - } - - if (common === true) { - result = r; - break; - } - } - - return result; - }; - - - fn.displacement_diff = function(widget_grid_data, parent_bgd, y_units) { - var actual_row = widget_grid_data.row; - var diffs = []; - var parent_max_y = parent_bgd.row + parent_bgd.size_y; - - this.for_each_column_occupied(widget_grid_data, function(col) { - var temp_y_units = 0; - - for (var r = parent_max_y; r < actual_row; r++) { - if (this.is_empty(col, r)) { - temp_y_units = temp_y_units + 1; - } - } - - diffs.push(temp_y_units); - }); - - var max_diff = Math.max.apply(Math, diffs); - y_units = (y_units - max_diff); - - return y_units > 0 ? y_units : 0; - }; - - - /** - * Get widgets below a widget. - * - * @method widgets_below - * @param {HTMLElement} $el The jQuery wrapped HTMLElement. - * @return {jQuery} A jQuery collection of HTMLElements. - */ - fn.widgets_below = function($el) { - var el_grid_data = $.isPlainObject($el) ? $el : $el.coords().grid; - var self = this; - var ga = this.gridmap; - var next_row = el_grid_data.row + el_grid_data.size_y - 1; - var $nexts = $([]); - - this.for_each_column_occupied(el_grid_data, function(col) { - self.for_each_widget_below(col, next_row, function(tcol, trow) { - if (!self.is_player(this) && $.inArray(this, $nexts) === -1) { - $nexts = $nexts.add(this); - return true; // break - } - }); - }); - - return this.sort_by_row_asc($nexts); - }; - - - /** - * Update the array of mapped positions with the new player position. - * - * @method set_cells_player_occupies - * @param {Number} col The new player col. - * @param {Number} col The new player row. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.set_cells_player_occupies = function(col, row) { - this.remove_from_gridmap(this.placeholder_grid_data); - this.placeholder_grid_data.col = col; - this.placeholder_grid_data.row = row; - this.add_to_gridmap(this.placeholder_grid_data, this.$player); - return this; - }; - - - /** - * Remove from the array of mapped positions the reference to the player. - * - * @method empty_cells_player_occupies - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.empty_cells_player_occupies = function() { - this.remove_from_gridmap(this.placeholder_grid_data); - return this; - }; - - - fn.can_go_up = function($el) { - var el_grid_data = $el.coords().grid; - var initial_row = el_grid_data.row; - var prev_row = initial_row - 1; - var ga = this.gridmap; - var upper_rows_by_column = []; - - var result = true; - if (initial_row === 1) { return false; } - - this.for_each_column_occupied(el_grid_data, function(col) { - var $w = this.is_widget(col, prev_row); - - if (this.is_occupied(col, prev_row) || - this.is_player(col, prev_row) || - this.is_placeholder_in(col, prev_row) || - this.is_player_in(col, prev_row) - ) { - result = false; - return true; //break - } - }); - - return result; - }; - - - - /** - * Check if it's possible to move a widget to a specific col/row. It takes - * into account the dimensions (`size_y` and `size_x` attrs. of the grid - * coords object) the widget occupies. - * - * @method can_move_to - * @param {Object} widget_grid_data The grid coords object that represents - * the widget. - * @param {Object} col The col to check. - * @param {Object} row The row to check. - * @param {Number} [max_row] The max row allowed. - * @return {Boolean} Returns true if all cells are empty, else return false. - */ - fn.can_move_to = function(widget_grid_data, col, row, max_row) { - var ga = this.gridmap; - var $w = widget_grid_data.el; - var future_wd = { - size_y: widget_grid_data.size_y, - size_x: widget_grid_data.size_x, - col: col, - row: row - }; - var result = true; - - //Prevents widgets go out of the grid - var right_col = col + widget_grid_data.size_x - 1; - if (right_col > this.cols) { - return false; - } - - if (max_row && max_row < row + widget_grid_data.size_y - 1) { - return false; - } - - this.for_each_cell_occupied(future_wd, function(tcol, trow) { - var $tw = this.is_widget(tcol, trow); - if ($tw && (!widget_grid_data.el || $tw.is($w))) { - result = false; - } - }); - - return result; - }; - - - /** - * Given the leftmost column returns all columns that are overlapping - * with the player. - * - * @method get_targeted_columns - * @param {Number} [from_col] The leftmost column. - * @return {Array} Returns an array with column numbers. - */ - fn.get_targeted_columns = function(from_col) { - var max = (from_col || this.player_grid_data.col) + - (this.player_grid_data.size_x - 1); - var cols = []; - for (var col = from_col; col <= max; col++) { - cols.push(col); - } - return cols; - }; - - - /** - * Given the upper row returns all rows that are overlapping with the player. - * - * @method get_targeted_rows - * @param {Number} [from_row] The upper row. - * @return {Array} Returns an array with row numbers. - */ - fn.get_targeted_rows = function(from_row) { - var max = (from_row || this.player_grid_data.row) + - (this.player_grid_data.size_y - 1); - var rows = []; - for (var row = from_row; row <= max; row++) { - rows.push(row); - } - return rows; - }; - - /** - * Get all columns and rows that a widget occupies. - * - * @method get_cells_occupied - * @param {Object} el_grid_data The grid coords object of the widget. - * @return {Object} Returns an object like `{ cols: [], rows: []}`. - */ - fn.get_cells_occupied = function(el_grid_data) { - var cells = { cols: [], rows: []}; - var i; - if (arguments[1] instanceof jQuery) { - el_grid_data = arguments[1].coords().grid; - } - - for (i = 0; i < el_grid_data.size_x; i++) { - var col = el_grid_data.col + i; - cells.cols.push(col); - } - - for (i = 0; i < el_grid_data.size_y; i++) { - var row = el_grid_data.row + i; - cells.rows.push(row); - } - - return cells; - }; - - - /** - * Iterate over the cells occupied by a widget executing a function for - * each one. - * - * @method for_each_cell_occupied - * @param {Object} el_grid_data The grid coords object that represents the - * widget. - * @param {Function} callback The function to execute on each column - * iteration. Column and row are passed as arguments. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_cell_occupied = function(grid_data, callback) { - this.for_each_column_occupied(grid_data, function(col) { - this.for_each_row_occupied(grid_data, function(row) { - callback.call(this, col, row); - }); - }); - return this; - }; - - - /** - * Iterate over the columns occupied by a widget executing a function for - * each one. - * - * @method for_each_column_occupied - * @param {Object} el_grid_data The grid coords object that represents - * the widget. - * @param {Function} callback The function to execute on each column - * iteration. The column number is passed as first argument. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_column_occupied = function(el_grid_data, callback) { - for (var i = 0; i < el_grid_data.size_x; i++) { - var col = el_grid_data.col + i; - callback.call(this, col, el_grid_data); - } - }; - - - /** - * Iterate over the rows occupied by a widget executing a function for - * each one. - * - * @method for_each_row_occupied - * @param {Object} el_grid_data The grid coords object that represents - * the widget. - * @param {Function} callback The function to execute on each column - * iteration. The row number is passed as first argument. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_row_occupied = function(el_grid_data, callback) { - for (var i = 0; i < el_grid_data.size_y; i++) { - var row = el_grid_data.row + i; - callback.call(this, row, el_grid_data); - } - }; - - - - fn._traversing_widgets = function(type, direction, col, row, callback) { - var ga = this.gridmap; - if (!ga[col]) { return; } - - var cr, max; - var action = type + '/' + direction; - if (arguments[2] instanceof jQuery) { - var el_grid_data = arguments[2].coords().grid; - col = el_grid_data.col; - row = el_grid_data.row; - callback = arguments[3]; - } - var matched = []; - var trow = row; - - - var methods = { - 'for_each/above': function() { - while (trow--) { - if (trow > 0 && this.is_widget(col, trow) && - $.inArray(ga[col][trow], matched) === -1 - ) { - cr = callback.call(ga[col][trow], col, trow); - matched.push(ga[col][trow]); - if (cr) { break; } - } - } - }, - 'for_each/below': function() { - for (trow = row + 1, max = ga[col].length; trow < max; trow++) { - if (this.is_widget(col, trow) && - $.inArray(ga[col][trow], matched) === -1 - ) { - cr = callback.call(ga[col][trow], col, trow); - matched.push(ga[col][trow]); - if (cr) { break; } - } - } - } - }; - - if (methods[action]) { - methods[action].call(this); - } - }; - - - /** - * Iterate over each widget above the column and row specified. - * - * @method for_each_widget_above - * @param {Number} col The column to start iterating. - * @param {Number} row The row to start iterating. - * @param {Function} callback The function to execute on each widget - * iteration. The value of `this` inside the function is the jQuery - * wrapped HTMLElement. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_widget_above = function(col, row, callback) { - this._traversing_widgets('for_each', 'above', col, row, callback); - return this; - }; - - - /** - * Iterate over each widget below the column and row specified. - * - * @method for_each_widget_below - * @param {Number} col The column to start iterating. - * @param {Number} row The row to start iterating. - * @param {Function} callback The function to execute on each widget - * iteration. The value of `this` inside the function is the jQuery wrapped - * HTMLElement. - * @return {Class} Returns the instance of the Gridster Class. - */ - fn.for_each_widget_below = function(col, row, callback) { - this._traversing_widgets('for_each', 'below', col, row, callback); - return this; - }; - - - /** - * Returns the highest occupied cell in the grid. - * - * @method get_highest_occupied_cell - * @return {Object} Returns an object with `col` and `row` numbers. - */ - fn.get_highest_occupied_cell = function() { - var r; - var gm = this.gridmap; - var rows = []; - var row_in_col = []; - for (var c = gm.length - 1; c >= 1; c--) { - for (r = gm[c].length - 1; r >= 1; r--) { - if (this.is_widget(c, r)) { - rows.push(r); - row_in_col[r] = c; - break; - } - } - } - - var highest_row = Math.max.apply(Math, rows); - - this.highest_occupied_cell = { - col: row_in_col[highest_row], - row: highest_row - }; - - return this.highest_occupied_cell; - }; - - - fn.get_widgets_from = function(col, row) { - var ga = this.gridmap; - var $widgets = $(); - - if (col) { - $widgets = $widgets.add( - this.$widgets.filter(function() { - var tcol = $(this).attr('data-col'); - return (tcol === col || tcol > col); - }) - ); - } - - if (row) { - $widgets = $widgets.add( - this.$widgets.filter(function() { - var trow = $(this).attr('data-row'); - return (trow === row || trow > row); - }) - ); - } - - return $widgets; - }; - - - /** - * Set the current height of the parent grid. - * - * @method set_dom_grid_height - * @return {Object} Returns the instance of the Gridster class. - */ - fn.set_dom_grid_height = function() { - var r = this.get_highest_occupied_cell().row; - this.$el.css('height', r * this.min_widget_height); - return this; - }; - - - /** - * It generates the neccessary styles to position the widgets. - * - * @method generate_stylesheet - * @param {Number} rows Number of columns. - * @param {Number} cols Number of rows. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_stylesheet = function(opts) { - var styles = ''; - var max_size_x = this.options.max_size_x; - var max_rows = 0; - var max_cols = 0; - var i; - var rules; - - opts || (opts = {}); - opts.cols || (opts.cols = this.cols); - opts.rows || (opts.rows = this.rows); - opts.namespace || (opts.namespace = this.options.namespace); - opts.widget_base_dimensions || - (opts.widget_base_dimensions = this.options.widget_base_dimensions); - opts.widget_margins || - (opts.widget_margins = this.options.widget_margins); - opts.min_widget_width = (opts.widget_margins[0] * 2) + - opts.widget_base_dimensions[0]; - opts.min_widget_height = (opts.widget_margins[1] * 2) + - opts.widget_base_dimensions[1]; - - // don't duplicate stylesheets for the same configuration - var serialized_opts = $.param(opts); - if ($.inArray(serialized_opts, Gridster.generated_stylesheets) >= 0) { - return false; - } - - Gridster.generated_stylesheets.push(serialized_opts); - - /* generate CSS styles for cols */ - for (i = opts.cols; i >= 0; i--) { - styles += (opts.namespace + ' [data-col="'+ (i + 1) + '"] { left:' + - ((i * opts.widget_base_dimensions[0]) + - (i * opts.widget_margins[0]) + - ((i + 1) * opts.widget_margins[0])) + 'px;} '); - } - - /* generate CSS styles for rows */ - for (i = opts.rows; i >= 0; i--) { - styles += (opts.namespace + ' [data-row="' + (i + 1) + '"] { top:' + - ((i * opts.widget_base_dimensions[1]) + - (i * opts.widget_margins[1]) + - ((i + 1) * opts.widget_margins[1]) ) + 'px;} '); - } - - for (var y = 1; y <= opts.rows; y++) { - styles += (opts.namespace + ' [data-sizey="' + y + '"] { height:' + - (y * opts.widget_base_dimensions[1] + - (y - 1) * (opts.widget_margins[1] * 2)) + 'px;}'); - } - - for (var x = 1; x <= max_size_x; x++) { - styles += (opts.namespace + ' [data-sizex="' + x + '"] { width:' + - (x * opts.widget_base_dimensions[0] + - (x - 1) * (opts.widget_margins[0] * 2)) + 'px;}'); - } - - return this.add_style_tag(styles); - }; - - - /** - * Injects the given CSS as string to the head of the document. - * - * @method add_style_tag - * @param {String} css The styles to apply. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_style_tag = function(css) { - var d = document; - var tag = d.createElement('style'); - - d.getElementsByTagName('head')[0].appendChild(tag); - tag.setAttribute('type', 'text/css'); - - if (tag.styleSheet) { - tag.styleSheet.cssText = css; - }else{ - tag.appendChild(document.createTextNode(css)); - } - return this; - }; - - - /** - * Generates a faux grid to collide with it when a widget is dragged and - * detect row or column that we want to go. - * - * @method generate_faux_grid - * @param {Number} rows Number of columns. - * @param {Number} cols Number of rows. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_faux_grid = function(rows, cols) { - this.faux_grid = []; - this.gridmap = []; - var col; - var row; - for (col = cols; col > 0; col--) { - this.gridmap[col] = []; - for (row = rows; row > 0; row--) { - this.add_faux_cell(row, col); - } - } - return this; - }; - - - /** - * Add cell to the faux grid. - * - * @method add_faux_cell - * @param {Number} row The row for the new faux cell. - * @param {Number} col The col for the new faux cell. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_cell = function(row, col) { - var coords = $({ - left: this.baseX + ((col - 1) * this.min_widget_width), - top: this.baseY + (row -1) * this.min_widget_height, - width: this.min_widget_width, - height: this.min_widget_height, - col: col, - row: row, - original_col: col, - original_row: row - }).coords(); - - if (!$.isArray(this.gridmap[col])) { - this.gridmap[col] = []; - } - - this.gridmap[col][row] = false; - this.faux_grid.push(coords); - - return this; - }; - - - /** - * Add rows to the faux grid. - * - * @method add_faux_rows - * @param {Number} rows The number of rows you want to add to the faux grid. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_rows = function(rows) { - var actual_rows = this.rows; - var max_rows = actual_rows + (rows || 1); - - for (var r = max_rows; r > actual_rows; r--) { - for (var c = this.cols; c >= 1; c--) { - this.add_faux_cell(r, c); - } - } - - this.rows = max_rows; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this; - }; - - /** - * Add cols to the faux grid. - * - * @method add_faux_cols - * @param {Number} cols The number of cols you want to add to the faux grid. - * @return {Object} Returns the instance of the Gridster class. - */ - fn.add_faux_cols = function(cols) { - var actual_cols = this.cols; - var max_cols = actual_cols + (cols || 1); - - for (var c = actual_cols; c < max_cols; c++) { - for (var r = this.rows; r >= 1; r--) { - this.add_faux_cell(r, c); - } - } - - this.cols = max_cols; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this; - }; - - - /** - * Recalculates the offsets for the faux grid. You need to use it when - * the browser is resized. - * - * @method recalculate_faux_grid - * @return {Object} Returns the instance of the Gridster class. - */ - fn.recalculate_faux_grid = function() { - var aw = this.$wrapper.width(); - this.baseX = ($(window).width() - aw) / 2; - this.baseY = this.$wrapper.offset().top; - - $.each(this.faux_grid, $.proxy(function(i, coords) { - this.faux_grid[i] = coords.update({ - left: this.baseX + (coords.data.col -1) * this.min_widget_width, - top: this.baseY + (coords.data.row -1) * this.min_widget_height - }); - - }, this)); - - return this; - }; - - - /** - * Get all widgets in the DOM and register them. - * - * @method get_widgets_from_DOM - * @return {Object} Returns the instance of the Gridster class. - */ - fn.get_widgets_from_DOM = function() { - this.$widgets.each($.proxy(function(i, widget) { - this.register_widget($(widget)); - }, this)); - return this; - }; - - - /** - * Calculate columns and rows to be set based on the configuration - * parameters, grid dimensions, etc ... - * - * @method generate_grid_and_stylesheet - * @return {Object} Returns the instance of the Gridster class. - */ - fn.generate_grid_and_stylesheet = function() { - var aw = this.$wrapper.width(); - var ah = this.$wrapper.height(); - - var cols = Math.floor(aw / this.min_widget_width) + - this.options.extra_cols; - - var actual_cols = this.$widgets.map(function() { - return $(this).attr('data-col'); - }); - actual_cols = Array.prototype.slice.call(actual_cols, 0); - //needed to pass tests with phantomjs - actual_cols.length || (actual_cols = [0]); - - var min_cols = Math.max.apply(Math, actual_cols); - - // get all rows that could be occupied by the current widgets - var max_rows = this.options.extra_rows; - this.$widgets.each(function(i, w) { - max_rows += (+$(w).attr('data-sizey')); - }); - - this.cols = Math.max(min_cols, cols, this.options.min_cols); - this.rows = Math.max(max_rows, this.options.min_rows); - - this.baseX = ($(window).width() - aw) / 2; - this.baseY = this.$wrapper.offset().top; - - if (this.options.autogenerate_stylesheet) { - this.generate_stylesheet(); - } - - return this.generate_faux_grid(this.rows, this.cols); - }; - - /** - * Destroy this gridster by removing any sign of its presence, making it easy to avoid memory leaks - * - * @method destroy - * @return {undefined} - */ - fn.destroy = function(){ - // remove bound callback on window resize - $(window).unbind('resize', this.on_window_resize); - - if(this.drag_api){ - this.drag_api.destroy(); - } - - // lastly, remove gridster element - // this will additionally cause any data associated to this element to be removed, including this - // very gridster instance - this.$el.remove(); - }; - - - //jQuery adapter - $.fn.gridster = function(options) { - return this.each(function() { - if (!$(this).data('gridster')) { - $(this).data('gridster', new Gridster( this, options )); - } - }); - }; - - $.Gridster = fn; - -}(jQuery, window, document)); \ No newline at end of file diff --git a/templates/project/assets/javascripts/gridster/jquery.gridster.min.js b/templates/project/assets/javascripts/gridster/jquery.gridster.min.js new file mode 100644 index 0000000..ac34904 --- /dev/null +++ b/templates/project/assets/javascripts/gridster/jquery.gridster.min.js @@ -0,0 +1,2 @@ +/*! gridster.js - v0.5.1 - 2014-03-26 - * http://gridster.net/ - Copyright (c) 2014 ducksboard; Licensed MIT */ (function(t){function i(i){return i[0]&&t.isPlainObject(i[0])?this.data=i[0]:this.el=i,this.isCoords=!0,this.coords={},this.init(),this}var e=i.prototype;e.init=function(){this.set(),this.original_coords=this.get()},e.set=function(t,i){var e=this.el;if(e&&!t&&(this.data=e.offset(),this.data.width=e.width(),this.data.height=e.height()),e&&t&&!i){var s=e.offset();this.data.top=s.top,this.data.left=s.left}var r=this.data;return r.left===undefined&&(r.left=r.x1),r.top===undefined&&(r.top=r.y1),this.coords.x1=r.left,this.coords.y1=r.top,this.coords.x2=r.left+r.width,this.coords.y2=r.top+r.height,this.coords.cx=r.left+r.width/2,this.coords.cy=r.top+r.height/2,this.coords.width=r.width,this.coords.height=r.height,this.coords.el=e||!1,this},e.update=function(i){if(!i&&!this.el)return this;if(i){var e=t.extend({},this.data,i);return this.data=e,this.set(!0,!0)}return this.set(!0),this},e.get=function(){return this.coords},e.destroy=function(){this.el.removeData("coords"),delete this.el},t.fn.coords=function(){if(this.data("coords"))return this.data("coords");var t=new i(this,arguments[0]);return this.data("coords",t),t}})(jQuery,window,document),function(t,i,e){function s(i,e,s){this.options=t.extend(r,s),this.$element=i,this.last_colliders=[],this.last_colliders_coords=[],this.set_colliders(e),this.init()}var r={colliders_context:e.body,overlapping_region:"C"},o=s.prototype;o.init=function(){this.find_collisions()},o.overlaps=function(t,i){var e=!1,s=!1;return(i.x1>=t.x1&&i.x1<=t.x2||i.x2>=t.x1&&i.x2<=t.x2||t.x1>=i.x1&&t.x2<=i.x2)&&(e=!0),(i.y1>=t.y1&&i.y1<=t.y2||i.y2>=t.y1&&i.y2<=t.y2||t.y1>=i.y1&&t.y2<=i.y2)&&(s=!0),e&&s},o.detect_overlapping_region=function(t,i){var e="",s="";return t.y1>i.cy&&t.y1i.y1&&t.y2i.cx&&t.x1i.x1&&t.x2o;o++)-1===t.inArray(r[o],i)&&e.call(this,r[o]);for(var h=0,n=i.length;n>h;h++)-1===t.inArray(i[h],r)&&s.call(this,i[h])},o.find_collisions=function(i){for(var e=this,s=this.options.overlapping_region,r=[],o=[],a=this.colliders||this.$colliders,h=a.length,n=e.$element.coords().update(i||!1).get();h--;){var _=e.$colliders?t(a[h]):a[h],d=_.isCoords?_:_.coords(),l=d.get(),c=e.overlaps(n,l);if(c){var p=e.detect_overlapping_region(n,l);if(p===s||"all"===s){var g=e.calculate_overlapped_area_coords(n,l),u=e.calculate_overlapped_area(g),f={area:u,area_coords:g,region:p,coords:l,player_coords:n,el:_};e.options.on_overlap&&e.options.on_overlap.call(this,f),r.push(d),o.push(f)}}}return(e.options.on_overlap_stop||e.options.on_overlap_start)&&this.manage_colliders_start_stop(r,e.options.on_overlap_start,e.options.on_overlap_stop),this.last_colliders_coords=r,o},o.get_closest_colliders=function(t){var i=this.find_collisions(t);return i.sort(function(t,i){return"C"===t.region&&"C"===i.region?t.coords.y1this.player_max_left?r=this.player_max_left:this.player_min_left>r&&(r=this.player_min_left)),{position:{left:r,top:o},pointer:{left:i.left,top:i.top,diff_left:e+this.scroll_offset_x,diff_top:s+this.scroll_offset_y}}},d.get_drag_data=function(t){var i=this.get_offset(t);return i.$player=this.$player,i.$helper=this.helper?this.$helper:this.$player,i},d.set_limits=function(t){return t||(t=this.$container.width()),this.player_max_left=t-this.player_width+-this.options.offset_left,this.options.container_width=t,this},d.scroll_in=function(i,s){var r,h=a[i],n=50,d=30,l="x"===i,c=l?this.window_width:this.window_height,p=l?t(e).width():t(e).height(),g=l?this.$player.width():this.$player.height(),u=o["scroll"+_(h)](),f=u,w=f+c,m=w-n,y=f+n,v=f+s.pointer[h],z=p-c+g;return v>=m&&(r=u+d,z>r&&(o["scroll"+_(h)](r),this["scroll_offset_"+i]+=d)),y>=v&&(r=u-d,r>0&&(o["scroll"+_(h)](r),this["scroll_offset_"+i]-=d)),this},d.manage_scroll=function(t){this.scroll_in("x",t),this.scroll_in("y",t)},d.calculate_dimensions=function(){this.window_height=o.height(),this.window_width=o.width()},d.drag_handler=function(i){if(i.target.nodeName,!this.disabled&&(1===i.which||h)&&!this.ignore_drag(i)){var e=this,s=!0;return this.$player=t(i.currentTarget),this.el_init_pos=this.get_actual_pos(this.$player),this.mouse_init_pos=this.get_mouse_pos(i),this.offsetY=this.mouse_init_pos.top-this.el_init_pos.top,this.$body.on(n.move,function(t){var i=e.get_mouse_pos(t),r=Math.abs(i.left-e.mouse_init_pos.left),o=Math.abs(i.top-e.mouse_init_pos.top);return r>e.options.distance||o>e.options.distance?s?(s=!1,e.on_dragstart.call(e,t),!1):(e.is_dragging===!0&&e.on_dragmove.call(e,t),!1):!1}),h?undefined:!1}},d.on_dragstart=function(t){if(t.preventDefault(),this.is_dragging)return this;this.drag_start=this.is_dragging=!0;var i=this.$container.offset();return this.baseX=Math.round(i.left),this.baseY=Math.round(i.top),this.initial_container_width=this.options.container_width||this.$container.width(),"clone"===this.options.helper?(this.$helper=this.$player.clone().appendTo(this.$container).addClass("helper"),this.helper=!0):this.helper=!1,this.scroll_offset_y=0,this.scroll_offset_x=0,this.el_init_offset=this.$player.offset(),this.player_width=this.$player.width(),this.player_height=this.$player.height(),this.set_limits(this.options.container_width),this.options.start&&this.options.start.call(this.$player,t,this.get_drag_data(t)),!1},d.on_dragmove=function(t){var i=this.get_drag_data(t);this.options.autoscroll&&this.manage_scroll(i),this.options.move_element&&(this.helper?this.$helper:this.$player).css({position:"absolute",left:i.position.left,top:i.position.top});var e=this.last_position||i.position;return i.prev_position=e,this.options.drag&&this.options.drag.call(this.$player,t,i),this.last_position=i.position,!1},d.on_dragstop=function(t){var i=this.get_drag_data(t);return this.drag_start=!1,this.options.stop&&this.options.stop.call(this.$player,t,i),this.helper&&this.options.remove_helper&&this.$helper.remove(),!1},d.on_select_start=function(t){return this.disabled||this.ignore_drag(t)?undefined:!1},d.enable=function(){this.disabled=!1},d.disable=function(){this.disabled=!0},d.destroy=function(){this.disable(),this.$container.off(".gridster-draggable"),this.$body.off(".gridster-draggable"),t(i).off(".gridster-draggable"),t.removeData(this.$container,"drag")},d.ignore_drag=function(i){return this.options.handle?!t(i.target).is(this.options.handle):t.isFunction(this.options.ignore_dragging)?this.options.ignore_dragging(i):t(i.target).is(this.options.ignore_dragging.join(", "))},t.fn.drag=function(t){return new s(this,t)}}(jQuery,window,document),function(t,i,e){function s(i,e){this.options=t.extend(!0,{},r,e),this.$el=t(i),this.$wrapper=this.$el.parent(),this.$widgets=this.$el.children(this.options.widget_selector).addClass("gs-w"),this.widgets=[],this.$changed=t([]),this.wrapper_width=this.$wrapper.width(),this.min_widget_width=2*this.options.widget_margins[0]+this.options.widget_base_dimensions[0],this.min_widget_height=2*this.options.widget_margins[1]+this.options.widget_base_dimensions[1],this.generated_stylesheets=[],this.$style_tags=t([]),this.init()}var r={namespace:"",widget_selector:"li",widget_margins:[10,10],widget_base_dimensions:[400,225],extra_rows:0,extra_cols:0,min_cols:1,max_cols:1/0,min_rows:15,max_size_x:!1,autogrow_cols:!1,autogenerate_stylesheet:!0,avoid_overlapped_widgets:!0,serialize_params:function(t,i){return{col:i.col,row:i.row,size_x:i.size_x,size_y:i.size_y}},collision:{},draggable:{items:".gs-w",distance:4},resize:{enabled:!1,axes:["both"],handle_append_to:"",handle_class:"gs-resize-handle",max_size:[1/0,1/0],min_size:[1,1]}};s.generated_stylesheets=[];var o=s.prototype;o.init=function(){this.options.resize.enabled&&this.setup_resize(),this.generate_grid_and_stylesheet(),this.get_widgets_from_DOM(),this.set_dom_grid_height(),this.set_dom_grid_width(),this.$wrapper.addClass("ready"),this.draggable(),this.options.resize.enabled&&this.resizable(),t(i).bind("resize.gridster",throttle(t.proxy(this.recalculate_faux_grid,this),200))},o.disable=function(){return this.$wrapper.find(".player-revert").removeClass("player-revert"),this.drag_api.disable(),this},o.enable=function(){return this.drag_api.enable(),this},o.disable_resize=function(){return this.$el.addClass("gs-resize-disabled"),this.resize_api.disable(),this},o.enable_resize=function(){return this.$el.removeClass("gs-resize-disabled"),this.resize_api.enable(),this},o.add_widget=function(i,e,s,r,o,a,h){var n;e||(e=1),s||(s=1),!r&!o?n=this.next_position(e,s):(n={col:r,row:o},this.empty_cells(r,o,e,s));var _=t(i).attr({"data-col":n.col,"data-row":n.row,"data-sizex":e,"data-sizey":s}).addClass("gs-w").appendTo(this.$el).hide();return this.$widgets=this.$widgets.add(_),this.register_widget(_),this.add_faux_rows(n.size_y),a&&this.set_widget_max_size(_,a),h&&this.set_widget_min_size(_,h),this.set_dom_grid_width(),this.set_dom_grid_height(),this.drag_api.set_limits(this.cols*this.min_widget_width),_.fadeIn()},o.set_widget_min_size=function(t,i){if(t="number"==typeof t?this.$widgets.eq(t):t,!t.length)return this;var e=t.data("coords").grid;return e.min_size_x=i[0],e.min_size_y=i[1],this},o.set_widget_max_size=function(t,i){if(t="number"==typeof t?this.$widgets.eq(t):t,!t.length)return this;var e=t.data("coords").grid;return e.max_size_x=i[0],e.max_size_y=i[1],this},o.add_resize_handle=function(i){var e=this.options.resize.handle_append_to;return t(this.resize_handle_tpl).appendTo(e?t(e,i):i),this},o.resize_widget=function(t,i,e,s){var r=t.coords().grid,o=r.col,a=this.options.max_cols,h=r.size_y,n=r.col,_=n;i||(i=r.size_x),e||(e=r.size_y),1/0!==a&&(i=Math.min(i,a-o+1)),e>h&&this.add_faux_rows(Math.max(e-h,0));var d=o+i-1;d>this.cols&&this.add_faux_cols(d-this.cols);var l={col:_,row:r.row,size_x:i,size_y:e};return this.mutate_widget_in_gridmap(t,r,l),this.set_dom_grid_height(),this.set_dom_grid_width(),s&&s.call(this,l.size_x,l.size_y),t},o.mutate_widget_in_gridmap=function(i,e,s){e.size_x;var r=e.size_y,o=this.get_cells_occupied(e),a=this.get_cells_occupied(s),h=[];t.each(o.cols,function(i,e){-1===t.inArray(e,a.cols)&&h.push(e)});var n=[];t.each(a.cols,function(i,e){-1===t.inArray(e,o.cols)&&n.push(e)});var _=[];t.each(o.rows,function(i,e){-1===t.inArray(e,a.rows)&&_.push(e)});var d=[];if(t.each(a.rows,function(i,e){-1===t.inArray(e,o.rows)&&d.push(e)}),this.remove_from_gridmap(e),n.length){var l=[s.col,s.row,s.size_x,Math.min(r,s.size_y),i];this.empty_cells.apply(this,l)}if(d.length){var c=[s.col,s.row,s.size_x,s.size_y,i];this.empty_cells.apply(this,c)}if(e.col=s.col,e.row=s.row,e.size_x=s.size_x,e.size_y=s.size_y,this.add_to_gridmap(s,i),i.removeClass("player-revert"),i.data("coords").update({width:s.size_x*this.options.widget_base_dimensions[0]+2*(s.size_x-1)*this.options.widget_margins[0],height:s.size_y*this.options.widget_base_dimensions[1]+2*(s.size_y-1)*this.options.widget_margins[1]}),i.attr({"data-col":s.col,"data-row":s.row,"data-sizex":s.size_x,"data-sizey":s.size_y}),h.length){var p=[h[0],s.row,h.length,Math.min(r,s.size_y),i];this.remove_empty_cells.apply(this,p)}if(_.length){var g=[s.col,s.row,s.size_x,s.size_y,i];this.remove_empty_cells.apply(this,g)}return this.move_widget_up(i),this},o.empty_cells=function(i,e,s,r,o){var a=this.widgets_below({col:i,row:e-r,size_x:s,size_y:r});return a.not(o).each(t.proxy(function(i,s){var o=t(s).coords().grid;if(e+r-1>=o.row){var a=e+r-o.row;this.move_widget_down(t(s),a)}},this)),this.set_dom_grid_height(),this},o.remove_empty_cells=function(i,e,s,r,o){var a=this.widgets_below({col:i,row:e,size_x:s,size_y:r});return a.not(o).each(t.proxy(function(i,e){this.move_widget_up(t(e),r)},this)),this.set_dom_grid_height(),this},o.next_position=function(t,i){t||(t=1),i||(i=1);for(var e,s=this.gridmap,r=s.length,o=[],a=1;r>a;a++){e=s[a].length;for(var h=1;e>=h;h++){var n=this.can_move_to({size_x:t,size_y:i},a,h);n&&o.push({col:a,row:h,size_y:i,size_x:t})}}return o.length?this.sort_by_row_and_col_asc(o)[0]:!1},o.remove_widget=function(i,e,s){var r=i instanceof t?i:t(i),o=r.coords().grid;t.isFunction(e)&&(s=e,e=!1),this.cells_occupied_by_placeholder={},this.$widgets=this.$widgets.not(r);var a=this.widgets_below(r);return this.remove_from_gridmap(o),r.fadeOut(t.proxy(function(){r.remove(),e||a.each(t.proxy(function(i,e){this.move_widget_up(t(e),o.size_y)},this)),this.set_dom_grid_height(),s&&s.call(this,i)},this)),this},o.remove_all_widgets=function(i){return this.$widgets.each(t.proxy(function(t,e){this.remove_widget(e,!0,i)},this)),this},o.serialize=function(i){i||(i=this.$widgets);var e=[];return i.each(t.proxy(function(i,s){e.push(this.options.serialize_params(t(s),t(s).coords().grid))},this)),e},o.serialize_changed=function(){return this.serialize(this.$changed)},o.register_widget=function(i){var e={col:parseInt(i.attr("data-col"),10),row:parseInt(i.attr("data-row"),10),size_x:parseInt(i.attr("data-sizex"),10),size_y:parseInt(i.attr("data-sizey"),10),max_size_x:parseInt(i.attr("data-max-sizex"),10)||!1,max_size_y:parseInt(i.attr("data-max-sizey"),10)||!1,min_size_x:parseInt(i.attr("data-min-sizex"),10)||!1,min_size_y:parseInt(i.attr("data-min-sizey"),10)||!1,el:i};return this.options.avoid_overlapped_widgets&&!this.can_move_to({size_x:e.size_x,size_y:e.size_y},e.col,e.row)&&(t.extend(e,this.next_position(e.size_x,e.size_y)),i.attr({"data-col":e.col,"data-row":e.row,"data-sizex":e.size_x,"data-sizey":e.size_y})),i.data("coords",i.coords()),i.data("coords").grid=e,this.add_to_gridmap(e,i),this.options.resize.enabled&&this.add_resize_handle(i),this},o.update_widget_position=function(t,i){return this.for_each_cell_occupied(t,function(t,e){return this.gridmap[t]?(this.gridmap[t][e]=i,undefined):this}),this},o.remove_from_gridmap=function(t){return this.update_widget_position(t,!1)},o.add_to_gridmap=function(i,e){if(this.update_widget_position(i,e||i.el),i.el){var s=this.widgets_below(i.el);s.each(t.proxy(function(i,e){this.move_widget_up(t(e))},this))}},o.draggable=function(){var i=this,e=t.extend(!0,{},this.options.draggable,{offset_left:this.options.widget_margins[0],offset_top:this.options.widget_margins[1],container_width:this.cols*this.min_widget_width,limit:!0,ignore_dragging:["INPUT","TEXTAREA","SELECT","BUTTON","."+this.options.resize.handle_class],start:function(e,s){i.$widgets.filter(".player-revert").removeClass("player-revert"),i.$player=t(this),i.$helper=t(s.$helper),i.helper=!i.$helper.is(i.$player),i.on_start_drag.call(i,e,s),i.$el.trigger("gridster:dragstart")},stop:function(t,e){i.on_stop_drag.call(i,t,e),i.$el.trigger("gridster:dragstop")},drag:throttle(function(t,e){i.on_drag.call(i,t,e),i.$el.trigger("gridster:drag")},60)});return this.drag_api=this.$el.drag(e),this},o.resizable=function(){return this.resize_api=this.$el.drag({items:"."+this.options.resize.handle_class,offset_left:this.options.widget_margins[0],container_width:this.container_width,move_element:!1,resize:!0,limit:this.options.autogrow_cols?!1:!0,start:t.proxy(this.on_start_resize,this),stop:t.proxy(function(i,e){delay(t.proxy(function(){this.on_stop_resize(i,e)},this),120)},this),drag:throttle(t.proxy(this.on_resize,this),60)}),this},o.setup_resize=function(){this.resize_handle_class=this.options.resize.handle_class;var i=this.options.resize.axes,e='';return this.resize_handle_tpl=t.map(i,function(t){return e.replace("{type}",t)}).join(""),this},o.on_start_drag=function(i,e){this.$helper.add(this.$player).add(this.$wrapper).addClass("dragging"),this.highest_col=this.get_highest_occupied_cell().col,this.$player.addClass("player"),this.player_grid_data=this.$player.coords().grid,this.placeholder_grid_data=t.extend({},this.player_grid_data),this.set_dom_grid_height(this.$el.height()+this.player_grid_data.size_y*this.min_widget_height),this.set_dom_grid_width(this.cols);var s=this.player_grid_data.size_x,r=this.cols-this.highest_col;this.options.autogrow_cols&&s>=r&&this.add_faux_cols(Math.min(s-r,1));var o=this.faux_grid,a=this.$player.data("coords").coords;this.cells_occupied_by_player=this.get_cells_occupied(this.player_grid_data),this.cells_occupied_by_placeholder=this.get_cells_occupied(this.placeholder_grid_data),this.last_cols=[],this.last_rows=[],this.collision_api=this.$helper.collision(o,this.options.collision),this.$preview_holder=t("<"+this.$player.get(0).tagName+" />",{"class":"preview-holder","data-row":this.$player.attr("data-row"),"data-col":this.$player.attr("data-col"),css:{width:a.width,height:a.height}}).appendTo(this.$el),this.options.draggable.start&&this.options.draggable.start.call(this,i,e)},o.on_drag=function(t,i){if(null===this.$player)return!1;var e={left:i.position.left+this.baseX,top:i.position.top+this.baseY};if(this.options.autogrow_cols){var s=this.placeholder_grid_data.col+this.placeholder_grid_data.size_x-1;s>=this.cols-1&&this.options.max_cols>=this.cols+1&&(this.add_faux_cols(1),this.set_dom_grid_width(this.cols+1),this.drag_api.set_limits(this.container_width)),this.collision_api.set_colliders(this.faux_grid)}this.colliders_data=this.collision_api.get_closest_colliders(e),this.on_overlapped_column_change(this.on_start_overlapping_column,this.on_stop_overlapping_column),this.on_overlapped_row_change(this.on_start_overlapping_row,this.on_stop_overlapping_row),this.helper&&this.$player&&this.$player.css({left:i.position.left,top:i.position.top}),this.options.draggable.drag&&this.options.draggable.drag.call(this,t,i)},o.on_stop_drag=function(t,i){this.$helper.add(this.$player).add(this.$wrapper).removeClass("dragging"),i.position.left=i.position.left+this.baseX,i.position.top=i.position.top+this.baseY,this.colliders_data=this.collision_api.get_closest_colliders(i.position),this.on_overlapped_column_change(this.on_start_overlapping_column,this.on_stop_overlapping_column),this.on_overlapped_row_change(this.on_start_overlapping_row,this.on_stop_overlapping_row),this.$player.addClass("player-revert").removeClass("player").attr({"data-col":this.placeholder_grid_data.col,"data-row":this.placeholder_grid_data.row}).css({left:"",top:""}),this.$changed=this.$changed.add(this.$player),this.cells_occupied_by_player=this.get_cells_occupied(this.placeholder_grid_data),this.set_cells_player_occupies(this.placeholder_grid_data.col,this.placeholder_grid_data.row),this.$player.coords().grid.row=this.placeholder_grid_data.row,this.$player.coords().grid.col=this.placeholder_grid_data.col,this.options.draggable.stop&&this.options.draggable.stop.call(this,t,i),this.$preview_holder.remove(),this.$player=null,this.$helper=null,this.placeholder_grid_data={},this.player_grid_data={},this.cells_occupied_by_placeholder={},this.cells_occupied_by_player={},this.set_dom_grid_height(),this.set_dom_grid_width(),this.options.autogrow_cols&&this.drag_api.set_limits(this.cols*this.min_widget_width)},o.on_start_resize=function(i,e){this.$resized_widget=e.$player.closest(".gs-w"),this.resize_coords=this.$resized_widget.coords(),this.resize_wgd=this.resize_coords.grid,this.resize_initial_width=this.resize_coords.coords.width,this.resize_initial_height=this.resize_coords.coords.height,this.resize_initial_sizex=this.resize_coords.grid.size_x,this.resize_initial_sizey=this.resize_coords.grid.size_y,this.resize_initial_col=this.resize_coords.grid.col,this.resize_last_sizex=this.resize_initial_sizex,this.resize_last_sizey=this.resize_initial_sizey,this.resize_max_size_x=Math.min(this.resize_wgd.max_size_x||this.options.resize.max_size[0],this.options.max_cols-this.resize_initial_col+1),this.resize_max_size_y=this.resize_wgd.max_size_y||this.options.resize.max_size[1],this.resize_min_size_x=this.resize_wgd.min_size_x||this.options.resize.min_size[0]||1,this.resize_min_size_y=this.resize_wgd.min_size_y||this.options.resize.min_size[1]||1,this.resize_initial_last_col=this.get_highest_occupied_cell().col,this.set_dom_grid_width(this.cols),this.resize_dir={right:e.$player.is("."+this.resize_handle_class+"-x"),bottom:e.$player.is("."+this.resize_handle_class+"-y")},this.$resized_widget.css({"min-width":this.options.widget_base_dimensions[0],"min-height":this.options.widget_base_dimensions[1]});var s=this.$resized_widget.get(0).tagName;this.$resize_preview_holder=t("<"+s+" />",{"class":"preview-holder resize-preview-holder","data-row":this.$resized_widget.attr("data-row"),"data-col":this.$resized_widget.attr("data-col"),css:{width:this.resize_initial_width,height:this.resize_initial_height}}).appendTo(this.$el),this.$resized_widget.addClass("resizing"),this.options.resize.start&&this.options.resize.start.call(this,i,e,this.$resized_widget),this.$el.trigger("gridster:resizestart")},o.on_stop_resize=function(i,e){this.$resized_widget.removeClass("resizing").css({width:"",height:""}),delay(t.proxy(function(){this.$resize_preview_holder.remove().css({"min-width":"","min-height":""}),this.options.resize.stop&&this.options.resize.stop.call(this,i,e,this.$resized_widget),this.$el.trigger("gridster:resizestop")},this),300),this.set_dom_grid_width(),this.options.autogrow_cols&&this.drag_api.set_limits(this.cols*this.min_widget_width)},o.on_resize=function(t,i){var e,s=i.pointer.diff_left,r=i.pointer.diff_top,o=this.options.widget_base_dimensions[0],a=this.options.widget_base_dimensions[1],h=this.options.widget_margins[0],n=this.options.widget_margins[1],_=this.resize_max_size_x,d=this.resize_min_size_x,l=this.resize_max_size_y,c=this.resize_min_size_y,p=this.options.autogrow_cols,g=1/0,u=1/0,f=Math.ceil(s/(o+2*h)-.2),w=Math.ceil(r/(a+2*n)-.2),m=Math.max(1,this.resize_initial_sizex+f),y=Math.max(1,this.resize_initial_sizey+w),v=this.container_width/this.min_widget_width-this.resize_initial_col+1,z=v*this.min_widget_width-2*h;if(m=Math.max(Math.min(m,_),d),m=Math.min(v,m),e=_*o+2*(m-1)*h,g=Math.min(e,z),min_width=d*o+2*(m-1)*h,y=Math.max(Math.min(y,l),c),u=l*a+2*(y-1)*n,min_height=c*a+2*(y-1)*n,this.resize_dir.right?y=this.resize_initial_sizey:this.resize_dir.bottom&&(m=this.resize_initial_sizex),p){var x=this.resize_initial_col+m-1;p&&x>=this.resize_initial_last_col&&(this.set_dom_grid_width(Math.max(x+1,this.cols)),x>this.cols&&this.add_faux_cols(x-this.cols))}var $={};!this.resize_dir.bottom&&($.width=Math.max(Math.min(this.resize_initial_width+s,g),min_width)),!this.resize_dir.right&&($.height=Math.max(Math.min(this.resize_initial_height+r,u),min_height)),this.$resized_widget.css($),(m!==this.resize_last_sizex||y!==this.resize_last_sizey)&&(this.resize_widget(this.$resized_widget,m,y),this.set_dom_grid_width(this.cols),this.$resize_preview_holder.css({width:"",height:""}).attr({"data-row":this.$resized_widget.attr("data-row"),"data-sizex":m,"data-sizey":y})),this.options.resize.resize&&this.options.resize.resize.call(this,t,i,this.$resized_widget),this.$el.trigger("gridster:resize"),this.resize_last_sizex=m,this.resize_last_sizey=y},o.on_overlapped_column_change=function(i,e){if(!this.colliders_data.length)return this;var s,r=this.get_targeted_columns(this.colliders_data[0].el.data.col),o=this.last_cols.length,a=r.length;for(s=0;a>s;s++)-1===t.inArray(r[s],this.last_cols)&&(i||t.noop).call(this,r[s]);for(s=0;o>s;s++)-1===t.inArray(this.last_cols[s],r)&&(e||t.noop).call(this,this.last_cols[s]);return this.last_cols=r,this},o.on_overlapped_row_change=function(i,e){if(!this.colliders_data.length)return this;var s,r=this.get_targeted_rows(this.colliders_data[0].el.data.row),o=this.last_rows.length,a=r.length;for(s=0;a>s;s++)-1===t.inArray(r[s],this.last_rows)&&(i||t.noop).call(this,r[s]);for(s=0;o>s;s++)-1===t.inArray(this.last_rows[s],r)&&(e||t.noop).call(this,this.last_rows[s]);this.last_rows=r},o.set_player=function(t,i,e){var s=this;e||this.empty_cells_player_occupies();var r=e?{col:t}:s.colliders_data[0].el.data,o=r.col,a=i||r.row;this.player_grid_data={col:o,row:a,size_y:this.player_grid_data.size_y,size_x:this.player_grid_data.size_x},this.cells_occupied_by_player=this.get_cells_occupied(this.player_grid_data);var h=this.get_widgets_overlapped(this.player_grid_data),n=this.widgets_constraints(h);if(this.manage_movements(n.can_go_up,o,a),this.manage_movements(n.can_not_go_up,o,a),!h.length){var _=this.can_go_player_up(this.player_grid_data);_!==!1&&(a=_),this.set_placeholder(o,a)}return{col:o,row:a}},o.widgets_constraints=function(i){var e,s=t([]),r=[],o=[];return i.each(t.proxy(function(i,e){var a=t(e),h=a.coords().grid;this.can_go_widget_up(h)?(s=s.add(a),r.push(h)):o.push(h)},this)),e=i.not(s),{can_go_up:this.sort_by_row_asc(r),can_not_go_up:this.sort_by_row_desc(o)}},o.sort_by_row_asc=function(i){return i=i.sort(function(i,e){return i.row||(i=t(i).coords().grid,e=t(e).coords().grid),i.row>e.row?1:-1})},o.sort_by_row_and_col_asc=function(t){return t=t.sort(function(t,i){return t.row>i.row||t.row===i.row&&t.col>i.col?1:-1})},o.sort_by_col_asc=function(t){return t=t.sort(function(t,i){return t.col>i.col?1:-1})},o.sort_by_row_desc=function(t){return t=t.sort(function(t,i){return t.row+t.size_y=0&&t.inArray(e,s.rows)>=0},o.is_placeholder_in=function(i,e){var s=this.cells_occupied_by_placeholder||{};return this.is_placeholder_in_col(i)&&t.inArray(e,s.rows)>=0},o.is_placeholder_in_col=function(i){var e=this.cells_occupied_by_placeholder||[];return t.inArray(i,e.cols)>=0},o.is_empty=function(t,i){return this.gridmap[t]!==undefined?this.gridmap[t][i]!==undefined&&this.gridmap[t][i]===!1?!0:!1:!0},o.is_occupied=function(t,i){return this.gridmap[t]?this.gridmap[t][i]?!0:!1:!1},o.is_widget=function(t,i){var e=this.gridmap[t];return e?(e=e[i],e?e:!1):!1},o.is_widget_under_player=function(t,i){return this.is_widget(t,i)?this.is_player_in(t,i):!1},o.get_widgets_under_player=function(i){i||(i=this.cells_occupied_by_player||{cols:[],rows:[]});var e=t([]);return t.each(i.cols,t.proxy(function(s,r){t.each(i.rows,t.proxy(function(t,i){this.is_widget(r,i)&&(e=e.add(this.gridmap[r][i]))},this))},this)),e},o.set_placeholder=function(i,e){var s=t.extend({},this.placeholder_grid_data),r=this.widgets_below({col:s.col,row:s.row,size_y:s.size_y,size_x:s.size_x}),o=i+s.size_x-1;o>this.cols&&(i-=o-i);var a=e>this.placeholder_grid_data.row,h=this.placeholder_grid_data.col!==i;this.placeholder_grid_data.col=i,this.placeholder_grid_data.row=e,this.cells_occupied_by_placeholder=this.get_cells_occupied(this.placeholder_grid_data),this.$preview_holder.attr({"data-row":e,"data-col":i}),(a||h)&&r.each(t.proxy(function(e,r){this.move_widget_up(t(r),this.placeholder_grid_data.col-i+s.size_y)},this));var n=this.get_widgets_under_player(this.cells_occupied_by_placeholder);n.length&&n.each(t.proxy(function(i,r){var o=t(r);this.move_widget_down(o,e+s.size_y-o.data("coords").grid.row)},this))},o.can_go_player_up=function(t){var i=t.row+t.size_y-1,e=!0,s=[],r=1e4,o=this.get_widgets_under_player();return this.for_each_column_occupied(t,function(t){var a=this.gridmap[t],h=i+1;for(s[t]=[];--h>0&&(this.is_empty(t,h)||this.is_player(t,h)||this.is_widget(t,h)&&a[h].is(o));)s[t].push(h),r=r>h?h:r;return 0===s[t].length?(e=!1,!0):(s[t].sort(function(t,i){return t-i}),undefined)}),e?this.get_valid_rows(t,s,r):!1},o.can_go_widget_up=function(t){var i=t.row+t.size_y-1,e=!0,s=[],r=1e4;return this.for_each_column_occupied(t,function(o){var a=this.gridmap[o];s[o]=[];for(var h=i+1;--h>0&&(!this.is_widget(o,h)||this.is_player_in(o,h)||a[h].is(t.el));)this.is_player(o,h)||this.is_placeholder_in(o,h)||this.is_player_in(o,h)||s[o].push(h),r>h&&(r=h);return 0===s[o].length?(e=!1,!0):(s[o].sort(function(t,i){return t-i}),undefined)}),e?this.get_valid_rows(t,s,r):!1},o.get_valid_rows=function(i,e,s){for(var r=i.row,o=i.row+i.size_y-1,a=i.size_y,h=s-1,n=[];o>=++h;){var _=!0;if(t.each(e,function(i,e){t.isArray(e)&&-1===t.inArray(h,e)&&(_=!1)}),_===!0&&(n.push(h),n.length===a))break}var d=!1;return 1===a?n[0]!==r&&(d=n[0]||!1):n[0]!==r&&(d=this.get_consecutive_numbers_index(n,a)),d},o.get_consecutive_numbers_index=function(t,i){for(var e=t.length,s=[],r=!0,o=-1,a=0;e>a;a++){if(r||t[a]===o+1){if(s.push(a),s.length===i)break;r=!1}else s=[],r=!0;o=t[a]}return s.length>=i?t[s[0]]:!1},o.get_widgets_overlapped=function(){var i=t([]),e=[],s=this.cells_occupied_by_player.rows.slice(0);return s.reverse(),t.each(this.cells_occupied_by_player.cols,t.proxy(function(r,o){t.each(s,t.proxy(function(s,r){if(!this.gridmap[o])return!0;var a=this.gridmap[o][r];this.is_occupied(o,r)&&!this.is_player(a)&&-1===t.inArray(a,e)&&(i=i.add(a),e.push(a)) +},this))},this)),i},o.on_start_overlapping_column=function(t){this.set_player(t,!1)},o.on_start_overlapping_row=function(t){this.set_player(!1,t)},o.on_stop_overlapping_column=function(t){this.set_player(t,!1);var i=this;this.for_each_widget_below(t,this.cells_occupied_by_player.rows[0],function(){i.move_widget_up(this,i.player_grid_data.size_y)})},o.on_stop_overlapping_row=function(t){this.set_player(!1,t);for(var i=this,e=this.cells_occupied_by_player.cols,s=0,r=e.length;r>s;s++)this.for_each_widget_below(e[s],t,function(){i.move_widget_up(this,i.player_grid_data.size_y)})},o.move_widget_to=function(i,e){var s=this,r=i.coords().grid;e-r.row;var o=this.widgets_below(i),a=this.can_move_to(r,r.col,e,i);return a===!1?!1:(this.remove_from_gridmap(r),r.row=e,this.add_to_gridmap(r),i.attr("data-row",e),this.$changed=this.$changed.add(i),o.each(function(i,e){var r=t(e),o=r.coords().grid,a=s.can_go_widget_up(o);a&&a!==o.row&&s.move_widget_to(r,a)}),this)},o.move_widget_up=function(i,e){var s=i.coords().grid,r=s.row,o=[];return e||(e=1),this.can_go_up(i)?(this.for_each_column_occupied(s,function(s){if(-1===t.inArray(i,o)){var a=i.coords().grid,h=r-e;if(h=this.can_go_up_to_row(a,s,h),!h)return!0;var n=this.widgets_below(i);this.remove_from_gridmap(a),a.row=h,this.add_to_gridmap(a),i.attr("data-row",a.row),this.$changed=this.$changed.add(i),o.push(i),n.each(t.proxy(function(i,s){this.move_widget_up(t(s),e)},this))}}),undefined):!1},o.move_widget_down=function(i,e){var s,r,o,a;if(0>=e)return!1;if(s=i.coords().grid,r=s.row,o=[],a=e,!i)return!1;if(-1===t.inArray(i,o)){var h=i.coords().grid,n=r+e,_=this.widgets_below(i);this.remove_from_gridmap(h),_.each(t.proxy(function(i,e){var s=t(e),r=s.coords().grid,o=this.displacement_diff(r,h,a);o>0&&this.move_widget_down(s,o)},this)),h.row=n,this.update_widget_position(h,i),i.attr("data-row",h.row),this.$changed=this.$changed.add(i),o.push(i)}},o.can_go_up_to_row=function(i,e,s){var r,o=this.gridmap,a=!0,h=[],n=i.row;if(this.for_each_column_occupied(i,function(t){for(o[t],h[t]=[],r=n;r--&&this.is_empty(t,r)&&!this.is_placeholder_in(t,r);)h[t].push(r);return h[t].length?undefined:(a=!1,!0)}),!a)return!1;for(r=s,r=1;n>r;r++){for(var _=!0,d=0,l=h.length;l>d;d++)h[d]&&-1===t.inArray(r,h[d])&&(_=!1);if(_===!0){a=r;break}}return a},o.displacement_diff=function(t,i,e){var s=t.row,r=[],o=i.row+i.size_y;this.for_each_column_occupied(t,function(t){for(var i=0,e=o;s>e;e++)this.is_empty(t,e)&&(i+=1);r.push(i)});var a=Math.max.apply(Math,r);return e-=a,e>0?e:0},o.widgets_below=function(i){var e=t.isPlainObject(i)?i:i.coords().grid,s=this;this.gridmap;var r=e.row+e.size_y-1,o=t([]);return this.for_each_column_occupied(e,function(i){s.for_each_widget_below(i,r,function(){return s.is_player(this)||-1!==t.inArray(this,o)?undefined:(o=o.add(this),!0)})}),this.sort_by_row_asc(o)},o.set_cells_player_occupies=function(t,i){return this.remove_from_gridmap(this.placeholder_grid_data),this.placeholder_grid_data.col=t,this.placeholder_grid_data.row=i,this.add_to_gridmap(this.placeholder_grid_data,this.$player),this},o.empty_cells_player_occupies=function(){return this.remove_from_gridmap(this.placeholder_grid_data),this},o.can_go_up=function(t){var i=t.coords().grid,e=i.row,s=e-1;this.gridmap;var r=!0;return 1===e?!1:(this.for_each_column_occupied(i,function(t){return this.is_widget(t,s),this.is_occupied(t,s)||this.is_player(t,s)||this.is_placeholder_in(t,s)||this.is_player_in(t,s)?(r=!1,!0):undefined}),r)},o.can_move_to=function(t,i,e,s){this.gridmap;var r=t.el,o={size_y:t.size_y,size_x:t.size_x,col:i,row:e},a=!0,h=i+t.size_x-1;return h>this.cols?!1:s&&e+t.size_y-1>s?!1:(this.for_each_cell_occupied(o,function(i,e){var s=this.is_widget(i,e);!s||t.el&&!s.is(r)||(a=!1)}),a)},o.get_targeted_columns=function(t){for(var i=(t||this.player_grid_data.col)+(this.player_grid_data.size_x-1),e=[],s=t;i>=s;s++)e.push(s);return e},o.get_targeted_rows=function(t){for(var i=(t||this.player_grid_data.row)+(this.player_grid_data.size_y-1),e=[],s=t;i>=s;s++)e.push(s);return e},o.get_cells_occupied=function(i){var e,s={cols:[],rows:[]};for(arguments[1]instanceof t&&(i=arguments[1].coords().grid),e=0;i.size_x>e;e++){var r=i.col+e;s.cols.push(r)}for(e=0;i.size_y>e;e++){var o=i.row+e;s.rows.push(o)}return s},o.for_each_cell_occupied=function(t,i){return this.for_each_column_occupied(t,function(e){this.for_each_row_occupied(t,function(t){i.call(this,e,t)})}),this},o.for_each_column_occupied=function(t,i){for(var e=0;t.size_x>e;e++){var s=t.col+e;i.call(this,s,t)}},o.for_each_row_occupied=function(t,i){for(var e=0;t.size_y>e;e++){var s=t.row+e;i.call(this,s,t)}},o._traversing_widgets=function(i,e,s,r,o){var a=this.gridmap;if(a[s]){var h,n,_=i+"/"+e;if(arguments[2]instanceof t){var d=arguments[2].coords().grid;s=d.col,r=d.row,o=arguments[3]}var l=[],c=r,p={"for_each/above":function(){for(;c--&&!(c>0&&this.is_widget(s,c)&&-1===t.inArray(a[s][c],l)&&(h=o.call(a[s][c],s,c),l.push(a[s][c]),h)););},"for_each/below":function(){for(c=r+1,n=a[s].length;n>c&&(!this.is_widget(s,c)||-1!==t.inArray(a[s][c],l)||(h=o.call(a[s][c],s,c),l.push(a[s][c]),!h));c++);}};p[_]&&p[_].call(this)}},o.for_each_widget_above=function(t,i,e){return this._traversing_widgets("for_each","above",t,i,e),this},o.for_each_widget_below=function(t,i,e){return this._traversing_widgets("for_each","below",t,i,e),this},o.get_highest_occupied_cell=function(){for(var t,i=this.gridmap,e=i[1].length,s=[],r=[],o=i.length-1;o>=1;o--)for(t=e-1;t>=1;t--)if(this.is_widget(o,t)){s.push(t),r.push(o);break}return{col:Math.max.apply(Math,r),row:Math.max.apply(Math,s)}},o.get_widgets_from=function(i,e){this.gridmap;var s=t();return i&&(s=s.add(this.$widgets.filter(function(){var e=t(this).attr("data-col");return e===i||e>i}))),e&&(s=s.add(this.$widgets.filter(function(){var i=t(this).attr("data-row");return i===e||i>e}))),s},o.set_dom_grid_height=function(t){if(t===undefined){var i=this.get_highest_occupied_cell().row;t=i*this.min_widget_height}return this.container_height=t,this.$el.css("height",this.container_height),this},o.set_dom_grid_width=function(t){t===undefined&&(t=this.get_highest_occupied_cell().col);var i=this.options.autogrow_cols?this.options.max_cols:this.cols;return t=Math.min(i,Math.max(t,this.options.min_cols)),this.container_width=t*this.min_widget_width,this.$el.css("width",this.container_width),this},o.generate_stylesheet=function(i){var e,r="",o=this.options.max_size_x||this.cols;i||(i={}),i.cols||(i.cols=this.cols),i.rows||(i.rows=this.rows),i.namespace||(i.namespace=this.options.namespace),i.widget_base_dimensions||(i.widget_base_dimensions=this.options.widget_base_dimensions),i.widget_margins||(i.widget_margins=this.options.widget_margins),i.min_widget_width=2*i.widget_margins[0]+i.widget_base_dimensions[0],i.min_widget_height=2*i.widget_margins[1]+i.widget_base_dimensions[1];var a=t.param(i);if(t.inArray(a,s.generated_stylesheets)>=0)return!1;for(this.generated_stylesheets.push(a),s.generated_stylesheets.push(a),e=i.cols;e>=0;e--)r+=i.namespace+' [data-col="'+(e+1)+'"] { left:'+(e*i.widget_base_dimensions[0]+e*i.widget_margins[0]+(e+1)*i.widget_margins[0])+"px; }\n";for(e=i.rows;e>=0;e--)r+=i.namespace+' [data-row="'+(e+1)+'"] { top:'+(e*i.widget_base_dimensions[1]+e*i.widget_margins[1]+(e+1)*i.widget_margins[1])+"px; }\n";for(var h=1;i.rows>=h;h++)r+=i.namespace+' [data-sizey="'+h+'"] { height:'+(h*i.widget_base_dimensions[1]+(h-1)*2*i.widget_margins[1])+"px; }\n";for(var n=1;o>=n;n++)r+=i.namespace+' [data-sizex="'+n+'"] { width:'+(n*i.widget_base_dimensions[0]+(n-1)*2*i.widget_margins[0])+"px; }\n";return this.add_style_tag(r)},o.add_style_tag=function(t){var i=e,s=i.createElement("style");return i.getElementsByTagName("head")[0].appendChild(s),s.setAttribute("type","text/css"),s.styleSheet?s.styleSheet.cssText=t:s.appendChild(e.createTextNode(t)),this.$style_tags=this.$style_tags.add(s),this},o.remove_style_tags=function(){var i=s.generated_stylesheets,e=this.generated_stylesheets;this.$style_tags.remove(),s.generated_stylesheets=t.map(i,function(i){return-1===t.inArray(i,e)?i:undefined})},o.generate_faux_grid=function(t,i){this.faux_grid=[],this.gridmap=[];var e,s;for(e=i;e>0;e--)for(this.gridmap[e]=[],s=t;s>0;s--)this.add_faux_cell(s,e);return this},o.add_faux_cell=function(i,e){var s=t({left:this.baseX+(e-1)*this.min_widget_width,top:this.baseY+(i-1)*this.min_widget_height,width:this.min_widget_width,height:this.min_widget_height,col:e,row:i,original_col:e,original_row:i}).coords();return t.isArray(this.gridmap[e])||(this.gridmap[e]=[]),this.gridmap[e][i]=!1,this.faux_grid.push(s),this},o.add_faux_rows=function(t){for(var i=this.rows,e=i+(t||1),s=e;s>i;s--)for(var r=this.cols;r>=1;r--)this.add_faux_cell(s,r);return this.rows=e,this.options.autogenerate_stylesheet&&this.generate_stylesheet(),this},o.add_faux_cols=function(t){var i=this.cols,e=i+(t||1);e=Math.min(e,this.options.max_cols);for(var s=i+1;e>=s;s++)for(var r=this.rows;r>=1;r--)this.add_faux_cell(r,s);return this.cols=e,this.options.autogenerate_stylesheet&&this.generate_stylesheet(),this},o.recalculate_faux_grid=function(){var e=this.$wrapper.width();return this.baseX=(t(i).width()-e)/2,this.baseY=this.$wrapper.offset().top,t.each(this.faux_grid,t.proxy(function(t,i){this.faux_grid[t]=i.update({left:this.baseX+(i.data.col-1)*this.min_widget_width,top:this.baseY+(i.data.row-1)*this.min_widget_height})},this)),this},o.get_widgets_from_DOM=function(){return this.$widgets.each(t.proxy(function(i,e){this.register_widget(t(e))},this)),this},o.generate_grid_and_stylesheet=function(){var e=this.$wrapper.width(),s=this.options.max_cols,r=Math.floor(e/this.min_widget_width)+this.options.extra_cols,o=this.$widgets.map(function(){return t(this).attr("data-col")}).get();o.length||(o=[0]);var a=Math.max.apply(Math,o);this.cols=Math.max(a,r,this.options.min_cols),1/0!==s&&s>=a&&this.cols>s&&(this.cols=s);var h=this.options.extra_rows;return this.$widgets.each(function(i,e){h+=+t(e).attr("data-sizey")}),this.rows=Math.max(h,this.options.min_rows),this.baseX=(t(i).width()-e)/2,this.baseY=this.$wrapper.offset().top,this.options.autogenerate_stylesheet&&this.generate_stylesheet(),this.generate_faux_grid(this.rows,this.cols)},o.destroy=function(e){return this.$el.removeData("gridster"),t(i).unbind(".gridster"),this.drag_api&&this.drag_api.destroy(),this.remove_style_tags(),e&&this.$el.remove(),this},t.fn.gridster=function(i){return this.each(function(){t(this).data("gridster")||t(this).data("gridster",new s(this,i))})},t.Gridster=o}(jQuery,window,document); diff --git a/templates/project/assets/stylesheets/application.scss b/templates/project/assets/stylesheets/application.scss index 20e009f..fb1ba5d 100644 --- a/templates/project/assets/stylesheets/application.scss +++ b/templates/project/assets/stylesheets/application.scss @@ -143,9 +143,9 @@ h3 { } .widget { - padding: 25px 12px; text-align: center; - width: 100%; + width: inherit; + height: inherit; display: table-cell; vertical-align: middle; } diff --git a/templates/project/assets/stylesheets/jquery.gridster.css b/templates/project/assets/stylesheets/jquery.gridster.css deleted file mode 100644 index d512484..0000000 --- a/templates/project/assets/stylesheets/jquery.gridster.css +++ /dev/null @@ -1,57 +0,0 @@ -/*! gridster.js - v0.1.0 - 2012-08-14 -* http://gridster.net/ -* Copyright (c) 2012 ducksboard; Licensed MIT */ - -.gridster { - position:relative; -} - -.gridster > * { - margin: 0 auto; - -webkit-transition: height .4s; - -moz-transition: height .4s; - -o-transition: height .4s; - -ms-transition: height .4s; - transition: height .4s; -} - -.gridster .gs_w{ - z-index: 2; - position: absolute; -} - -.ready .gs_w:not(.preview-holder) { - -webkit-transition: opacity .3s, left .3s, top .3s; - -moz-transition: opacity .3s, left .3s, top .3s; - -o-transition: opacity .3s, left .3s, top .3s; - transition: opacity .3s, left .3s, top .3s; -} - -.gridster .preview-holder { - z-index: 1; - position: absolute; - background-color: #fff; - border-color: #fff; - opacity: 0.3; -} - -.gridster .player-revert { - z-index: 10!important; - -webkit-transition: left .3s, top .3s!important; - -moz-transition: left .3s, top .3s!important; - -o-transition: left .3s, top .3s!important; - transition: left .3s, top .3s!important; -} - -.gridster .dragging { - z-index: 10!important; - -webkit-transition: all 0s !important; - -moz-transition: all 0s !important; - -o-transition: all 0s !important; - transition: all 0s !important; -} - -/* Uncomment this if you set helper : "clone" in draggable options */ -/*.gridster .player { - opacity:0; -}*/ \ No newline at end of file diff --git a/templates/project/assets/stylesheets/jquery.gridster.min.css b/templates/project/assets/stylesheets/jquery.gridster.min.css new file mode 100644 index 0000000..4639de9 --- /dev/null +++ b/templates/project/assets/stylesheets/jquery.gridster.min.css @@ -0,0 +1,2 @@ +/*! gridster.js - v0.5.1 - 2014-03-26 - * http://gridster.net/ - Copyright (c) 2014 ducksboard; Licensed MIT */ +.gridster{position:relative}.gridster>*{margin:0 auto;-webkit-transition:height .4s,width .4s;-moz-transition:height .4s,width .4s;-o-transition:height .4s,width .4s;-ms-transition:height .4s,width .4s;transition:height .4s,width .4s}.gridster .gs-w{z-index:2;position:absolute}.ready .gs-w:not(.preview-holder){-webkit-transition:opacity .3s,left .3s,top .3s;-moz-transition:opacity .3s,left .3s,top .3s;-o-transition:opacity .3s,left .3s,top .3s;transition:opacity .3s,left .3s,top .3s}.ready .gs-w:not(.preview-holder),.ready .resize-preview-holder{-webkit-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-moz-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;-o-transition:opacity .3s,left .3s,top .3s,width .3s,height .3s;transition:opacity .3s,left .3s,top .3s,width .3s,height .3s}.gridster .preview-holder{z-index:1;position:absolute;background-color:#fff;border-color:#fff;opacity:.3}.gridster .player-revert{z-index:10!important;-webkit-transition:left .3s,top .3s!important;-moz-transition:left .3s,top .3s!important;-o-transition:left .3s,top .3s!important;transition:left .3s,top .3s!important}.gridster .dragging,.gridster .resizing{z-index:10!important;-webkit-transition:all 0s!important;-moz-transition:all 0s!important;-o-transition:all 0s!important;transition:all 0s!important}.gs-resize-handle{position:absolute;z-index:1}.gs-resize-handle-both{width:20px;height:20px;bottom:-8px;right:-8px;background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=);background-position:top left;background-repeat:no-repeat;cursor:se-resize;z-index:20}.gs-resize-handle-x{top:0;bottom:13px;right:-5px;width:10px;cursor:e-resize}.gs-resize-handle-y{left:0;right:13px;bottom:-5px;height:10px;cursor:s-resize}.gs-w:hover .gs-resize-handle,.resizing .gs-resize-handle{opacity:1}.gs-resize-handle,.gs-w.dragging .gs-resize-handle{opacity:0}.gs-resize-disabled .gs-resize-handle{display:none!important}[data-max-sizex="1"] .gs-resize-handle-x,[data-max-sizey="1"] .gs-resize-handle-y,[data-max-sizey="1"][data-max-sizex="1"] .gs-resize-handle{display:none!important} -- cgit v1.2.3 From 99277956e49b53e2829325a771034a6b0b1367ed Mon Sep 17 00:00:00 2001 From: Francois Chagnon Date: Tue, 27 May 2014 18:53:58 +0000 Subject: use default release task from bundler/gem_tasks --- Rakefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 765e5bd..fc91969 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,6 @@ require 'rubygems' require 'rake' +require 'bundler/gem_tasks' require 'rake/testtask' Rake::TestTask.new(:test) do |test| @@ -7,4 +8,4 @@ Rake::TestTask.new(:test) do |test| test.pattern = 'test/**/*_test.rb' end -task :default => [:test] \ No newline at end of file +task :default => [:test] -- cgit v1.2.3 From d773b370cad54dfff23d4be618a4f10a6acd1cb0 Mon Sep 17 00:00:00 2001 From: Francois Chagnon Date: Tue, 27 May 2014 18:55:35 +0000 Subject: deploy using shipit --- shipit.rubygems.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 shipit.rubygems.yml diff --git a/shipit.rubygems.yml b/shipit.rubygems.yml new file mode 100644 index 0000000..c3f42d3 --- /dev/null +++ b/shipit.rubygems.yml @@ -0,0 +1 @@ +# using the default shipit config -- cgit v1.2.3 From b5da76a5874f367d0f4af4d69244b9d9ab6f3c8b Mon Sep 17 00:00:00 2001 From: Francois Chagnon Date: Tue, 27 May 2014 18:56:16 +0000 Subject: Bump version to 1.3.3 --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 8ef27f8..a4cac13 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.3.2' + s.version = '1.3.3' s.date = '2013-11-21' s.executables << 'dashing' -- cgit v1.2.3 From a2ae80d1f27fdc6b25a24b56efcf362b91537692 Mon Sep 17 00:00:00 2001 From: Francois Chagnon Date: Wed, 28 May 2014 15:09:14 +0000 Subject: s.executables may be nil sometimes --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index a4cac13..08e7f2b 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = 'dashing' s.version = '1.3.3' s.date = '2013-11-21' - s.executables << 'dashing' + s.executables = %w(dashing) s.summary = "The exceptionally handsome dashboard framework." -- cgit v1.2.3 From f965d346d40ab69effa5dd333eebaa7ad0afb57e Mon Sep 17 00:00:00 2001 From: Marc Ignacio Date: Fri, 30 May 2014 07:58:22 +0800 Subject: Update ruby to 2.1.2 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0a28e78..66b5ca9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: ruby rvm: - - 2.1.0 + - 2.1.2 - 2.0.0 - 1.9.3 -- cgit v1.2.3 From d3ccecb096821b2df3b492dd349e5c650929a591 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 30 May 2014 14:28:51 -0400 Subject: Don't start the dashing app when you run the bin file. --- bin/dashing | 3 ++- lib/dashing.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/dashing b/bin/dashing index 97a7af5..cce9340 100755 --- a/bin/dashing +++ b/bin/dashing @@ -3,6 +3,7 @@ require "pathname" bin_file = Pathname.new(__FILE__).realpath $:.unshift File.expand_path("../../lib", bin_file) -require 'dashing' +require 'dashing/cli' +require 'dashing/downloader' Dashing::CLI.source_root(File.expand_path('../../templates', bin_file)) Dashing::CLI.start(ARGV) diff --git a/lib/dashing.rb b/lib/dashing.rb index 855aa36..3527034 100644 --- a/lib/dashing.rb +++ b/lib/dashing.rb @@ -3,4 +3,4 @@ require 'dashing/downloader' require 'dashing/app' module Dashing -end +end \ No newline at end of file -- cgit v1.2.3 From 391a2701f60868817f79a091afbbec24041a0814 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 30 May 2014 14:59:26 -0400 Subject: Updated to latest twitter gem. --- templates/project/Gemfile | 2 +- templates/project/jobs/twitter.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/project/Gemfile b/templates/project/Gemfile index 3c7e7a9..1235b37 100644 --- a/templates/project/Gemfile +++ b/templates/project/Gemfile @@ -3,4 +3,4 @@ source 'https://rubygems.org' gem 'dashing' ## Remove this if you don't need a twitter widget. -gem 'twitter', '>= 5.0.0' \ No newline at end of file +gem 'twitter', '>= 5.9.0' \ No newline at end of file diff --git a/templates/project/jobs/twitter.rb b/templates/project/jobs/twitter.rb index 26228bc..7b2bd6f 100644 --- a/templates/project/jobs/twitter.rb +++ b/templates/project/jobs/twitter.rb @@ -6,8 +6,8 @@ require 'twitter' twitter = Twitter::REST::Client.new do |config| config.consumer_key = 'YOUR_CONSUMER_KEY' config.consumer_secret = 'YOUR_CONSUMER_SECRET' - config.oauth_token = 'YOUR_OAUTH_TOKEN' - config.oauth_token_secret = 'YOUR_OAUTH_SECRET' + config.access_token = 'YOUR_OAUTH_TOKEN' + config.access_token_secret = 'YOUR_OAUTH_SECRET' end search_term = URI::encode('#todayilearned') -- cgit v1.2.3 From ea3730fa4e32d668449439c4ee1f39e69b9f1726 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 30 May 2014 15:00:22 -0400 Subject: Lock Dashing on Rufus Scheduler 2.0.24. There are some small issues from using the rewritten RS (3.0). So for now let's use this version until Dashing 2.0 comes out. --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 08e7f2b..4edb242 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -21,7 +21,7 @@ Gem::Specification.new do |s| s.add_dependency('sinatra', '~> 1.4.4') s.add_dependency('sinatra-contrib', '~> 1.4.2') s.add_dependency('thin', '~> 1.6.1') - s.add_dependency('rufus-scheduler', '~> 3.0.3') + s.add_dependency('rufus-scheduler', '~> 2.0.24') s.add_dependency('thor', '~> 0.18.1') s.add_dependency('sprockets', '~> 2.10.1') s.add_dependency('rack', '~> 1.5.2') -- cgit v1.2.3 From c49881072556821fc4730b44f1dd6f9afa1bc8d6 Mon Sep 17 00:00:00 2001 From: pushmatrix Date: Fri, 30 May 2014 15:00:35 -0400 Subject: Update Dashing to 1.3.4 --- dashing.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 4edb242..2f9df4a 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.3.3' - s.date = '2013-11-21' + s.version = '1.3.4' + s.date = '2014-05-30' s.executables = %w(dashing) @@ -32,4 +32,4 @@ Gem::Specification.new do |s| s.add_development_dependency('mocha', '~> 0.14.0') s.add_development_dependency('fakeweb', '~> 1.3.0') s.add_development_dependency('simplecov', '~> 0.8.2') -end +end \ No newline at end of file -- cgit v1.2.3 From a615548bf13ca517c3d991738cf611f2d6accf08 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Thu, 19 Jun 2014 02:24:53 -0400 Subject: Close event connections when the server is gracefully shutting down. --- lib/dashing/app.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 033849c..800f4c8 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -6,6 +6,7 @@ require 'coffee-script' require 'sass' require 'json' require 'yaml' +require 'thin' SCHEDULER = Rufus::Scheduler.new @@ -119,6 +120,16 @@ get '/views/:widget?.html' do end end +Thin::Server.class_eval do + def stop_with_connection_closing + Sinatra::Application.settings.connections.each(&:close) + stop_without_connection_closing + end + + alias_method :stop_without_connection_closing, :stop + alias_method :stop, :stop_with_connection_closing +end + def send_event(id, body, target=nil) body[:id] = id body[:updatedAt] ||= Time.now.to_i -- cgit v1.2.3 From 55f90939eae4d6eb64822fd3590f694418396510 Mon Sep 17 00:00:00 2001 From: Dylan Thacker-Smith Date: Fri, 20 Jun 2014 21:13:02 -0400 Subject: Duplicate array of connections before closing them on thin server stop. --- lib/dashing/app.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 800f4c8..921bf9c 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -122,7 +122,7 @@ end Thin::Server.class_eval do def stop_with_connection_closing - Sinatra::Application.settings.connections.each(&:close) + Sinatra::Application.settings.connections.dup.each(&:close) stop_without_connection_closing end -- cgit v1.2.3 From 3343a27eea09794d713f7ad8d712a18cf8b83654 Mon Sep 17 00:00:00 2001 From: hSATAC Date: Wed, 23 Jul 2014 18:37:49 +0800 Subject: .icon-background should not block click --- templates/project/assets/stylesheets/application.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/project/assets/stylesheets/application.scss b/templates/project/assets/stylesheets/application.scss index 20e009f..091ac69 100644 --- a/templates/project/assets/stylesheets/application.scss +++ b/templates/project/assets/stylesheets/application.scss @@ -117,6 +117,7 @@ h3 { } .icon-background { + pointer-events: none; width: 100%!important; height: 100%; position: absolute; -- cgit v1.2.3 From e42fc5d3b48b1dfe7d7ca9d60342727245842627 Mon Sep 17 00:00:00 2001 From: Fredrik Vihlborg Date: Thu, 28 Aug 2014 18:13:12 +0200 Subject: Possible to skip overwrites when installing widget. --- lib/dashing/cli.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/dashing/cli.rb b/lib/dashing/cli.rb index 27d8f6b..4b93f89 100644 --- a/lib/dashing/cli.rb +++ b/lib/dashing/cli.rb @@ -38,12 +38,12 @@ module Dashing puts "Invalid generator. Either use widget, dashboard, or job" end - desc "install GIST_ID", "Installs a new widget from a gist." - def install(gist_id) + desc "install GIST_ID [--skip]", "Installs a new widget from a gist (skip overwrite)." + def install(gist_id, *args) gist = Downloader.get_gist(gist_id) public_url = "https://gist.github.com/#{gist_id}" - install_widget_from_gist(gist) + install_widget_from_gist(gist, args.include?('--skip')) print set_color("Don't forget to edit the ", :yellow) print set_color("Gemfile ", :yellow, :bold) @@ -89,15 +89,15 @@ module Dashing system(command) end - def install_widget_from_gist(gist) + def install_widget_from_gist(gist, skip_overwrite) gist['files'].each do |file, details| if file =~ /\.(html|coffee|scss)\z/ widget_name = File.basename(file, '.*') new_path = File.join(Dir.pwd, 'widgets', widget_name, file) - create_file(new_path, details['content']) + create_file(new_path, details['content'], :skip => skip_overwrite) elsif file.end_with?('.rb') new_path = File.join(Dir.pwd, 'jobs', file) - create_file(new_path, details['content']) + create_file(new_path, details['content'], :skip => skip_overwrite) end end end -- cgit v1.2.3 From 8fe3a7ec617221a2387bfe9329e731b4cb836062 Mon Sep 17 00:00:00 2001 From: Fredrik Vihlborg Date: Thu, 28 Aug 2014 18:35:32 +0200 Subject: Updated tests accordingly. --- test/cli_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/cli_test.rb b/test/cli_test.rb index 567827e..4d82296 100644 --- a/test/cli_test.rb +++ b/test/cli_test.rb @@ -68,10 +68,10 @@ class CLITest < Dashing::Test Dir.stubs(:pwd).returns('') Dashing::Downloader.stubs(:get_gist).returns(JSON.parse(json_response)) - @cli.stubs(:create_file).with('/jobs/ruby_job.rb', 'some job content').once - @cli.stubs(:create_file).with('/widgets/num/num.html', 'some html content').once - @cli.stubs(:create_file).with('/widgets/num/num.scss', 'some sass content').once - @cli.stubs(:create_file).with('/widgets/num/num.coffee', 'some coffee content').once + @cli.stubs(:create_file).with('/jobs/ruby_job.rb', 'some job content', {:skip => false}).once + @cli.stubs(:create_file).with('/widgets/num/num.html', 'some html content', {:skip => false}).once + @cli.stubs(:create_file).with('/widgets/num/num.scss', 'some sass content', {:skip => false}).once + @cli.stubs(:create_file).with('/widgets/num/num.coffee', 'some coffee content', {:skip => false}).once capture_io { @cli.install(123) } end -- cgit v1.2.3 From aa997acbdbe0611eb072a27061e718f6878487e4 Mon Sep 17 00:00:00 2001 From: schinken Date: Tue, 9 Sep 2014 16:01:42 +0200 Subject: Enable data suffix --- templates/project/widgets/graph/graph.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/project/widgets/graph/graph.html b/templates/project/widgets/graph/graph.html index 456dd0f..786bbb7 100644 --- a/templates/project/widgets/graph/graph.html +++ b/templates/project/widgets/graph/graph.html @@ -1,5 +1,5 @@

    -

    +

    -- cgit v1.2.3 From cef86d22617476556644b83a5272c7c0c4d931c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Silkenb=C3=A4umer?= Date: Thu, 22 Jan 2015 23:07:45 +0100 Subject: Ignore log directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2d12c6d..259c923 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ /Gemfile.lock *.gem coverage/ +log/ .ruby-version -- cgit v1.2.3 From e16d4741510a674baedb498fa48d4c4971bda0d9 Mon Sep 17 00:00:00 2001 From: Tyler Mauthe Date: Wed, 28 Jan 2015 21:23:08 -0700 Subject: Padding on Graph widget to avoid cropping labels Fixes #484 --- templates/project/widgets/graph/graph.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/templates/project/widgets/graph/graph.coffee b/templates/project/widgets/graph/graph.coffee index 28ce88e..5d6b9ab 100644 --- a/templates/project/widgets/graph/graph.coffee +++ b/templates/project/widgets/graph/graph.coffee @@ -22,6 +22,7 @@ class Dashing.Graph extends Dashing.Widget data: [{x:0, y:0}] } ] + padding: {top: 0.02, left: 0.02, right: 0.02, bottom: 0.02} ) @graph.series[0].data = @get('points') if @get('points') -- cgit v1.2.3 From cfed24e9c4a59f8b911cc09396c35901c5152d5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karsten=20Silkenb=C3=A4umer?= Date: Thu, 29 Jan 2015 22:42:24 +0100 Subject: Ignore tmp/ and history.yml --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 259c923..65cbda8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ *.gem coverage/ log/ +tmp/ .ruby-version +history.yml -- cgit v1.2.3 From 6914d99bda53f7732988a61b639165b54d9b8cfd Mon Sep 17 00:00:00 2001 From: Adam Byrtek Date: Tue, 24 Feb 2015 20:18:14 +0000 Subject: Trigger onData on widget initialization --- javascripts/dashing.coffee | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index e5875d8..c66128d 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -40,7 +40,12 @@ class Dashing.Widget extends Batman.View @mixin($(@node).data()) Dashing.widgets[@id] ||= [] Dashing.widgets[@id].push(@) - @mixin(Dashing.lastEvents[@id]) # in case the events from the server came before the widget was rendered + + # In case the events from the server came before the widget was rendered + lastData = Dashing.lastEvents[@id] + if lastData + @mixin(lastData) + @onData(lastData) type = Batman.Filters.dashize(@view) $(@node).addClass("widget widget-#{type} #{@id}") -- cgit v1.2.3 From e18a162b663e5e0a924d3a884ad1c64f75e8cf8d Mon Sep 17 00:00:00 2001 From: Adam Byrtek Date: Tue, 24 Feb 2015 20:57:59 +0000 Subject: Store last events for all widgets Even the ones that haven't been initialized yet. --- javascripts/dashing.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index c66128d..f41a279 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -114,8 +114,8 @@ source.addEventListener 'message', (e) -> if lastEvents[data.id]?.updatedAt != data.updatedAt if Dashing.debugMode console.log("Received data for #{data.id}", data) + lastEvents[data.id] = data if widgets[data.id]?.length > 0 - lastEvents[data.id] = data for widget in widgets[data.id] widget.receiveData(data) -- cgit v1.2.3 From c49e181cdb13d3357d76759e5311746ffe00f281 Mon Sep 17 00:00:00 2001 From: Adam Byrtek Date: Tue, 24 Feb 2015 21:00:13 +0000 Subject: Send last event data when a widget is ready --- javascripts/dashing.coffee | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/javascripts/dashing.coffee b/javascripts/dashing.coffee index f41a279..20a9987 100644 --- a/javascripts/dashing.coffee +++ b/javascripts/dashing.coffee @@ -41,12 +41,6 @@ class Dashing.Widget extends Batman.View Dashing.widgets[@id] ||= [] Dashing.widgets[@id].push(@) - # In case the events from the server came before the widget was rendered - lastData = Dashing.lastEvents[@id] - if lastData - @mixin(lastData) - @onData(lastData) - type = Batman.Filters.dashize(@view) $(@node).addClass("widget widget-#{type} #{@id}") @@ -60,6 +54,12 @@ class Dashing.Widget extends Batman.View @::on 'ready', -> Dashing.Widget.fire 'ready' + # In case the events from the server came before the widget was rendered + lastData = Dashing.lastEvents[@id] + if lastData + @mixin(lastData) + @onData(lastData) + receiveData: (data) => @mixin(data) @onData(data) -- cgit v1.2.3 From 937fcce2dcca8010dbe8e9e26df954cb1330c1e0 Mon Sep 17 00:00:00 2001 From: Sven Dahlstrand Date: Mon, 27 Apr 2015 00:43:59 +0200 Subject: Pass `status` option to `send_file` and make sure a 404 is returned. --- lib/dashing/app.rb | 2 +- test/app_test.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 921bf9c..0e7f7bb 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -50,7 +50,7 @@ end end not_found do - send_file File.join(settings.public_folder, '404.html') + send_file File.join(settings.public_folder, '404.html'), status: 404 end at_exit do diff --git a/test/app_test.rb b/test/app_test.rb index 4101e91..4acb27a 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -129,6 +129,13 @@ class AppTest < Dashing::Test end end + def test_get_nonexistent_dashboard_sends_file_with_404_status + with_generated_project do + app.any_instance.expects(:send_file).with(anything, has_entry(:status, 404)) + get '/nodashboard' + end + end + def test_get_widget with_generated_project do get '/views/meter.html' -- cgit v1.2.3 From 5c4e62f0987bd900d0f2c510bb3cb9f35bfd28a7 Mon Sep 17 00:00:00 2001 From: Sven Dahlstrand Date: Wed, 29 Apr 2015 23:59:40 +0200 Subject: Set public folder setting for generated project. --- test/app_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/app_test.rb b/test/app_test.rb index 4acb27a..0ac66d0 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -152,6 +152,7 @@ class AppTest < Dashing::Test cli.stubs(:source_paths).returns([source_path]) silent { cli.new 'new_project' } + app.settings.public_folder = File.join(dir, 'new_project/public') app.settings.views = File.join(dir, 'new_project/dashboards') app.settings.root = File.join(dir, 'new_project') yield app.settings.root -- cgit v1.2.3 From 69554869db9f0273ef2e309ceca1e990b155bd68 Mon Sep 17 00:00:00 2001 From: Sven Dahlstrand Date: Thu, 30 Apr 2015 00:00:59 +0200 Subject: Remove redundant test. --- test/app_test.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/app_test.rb b/test/app_test.rb index 0ac66d0..36cd310 100644 --- a/test/app_test.rb +++ b/test/app_test.rb @@ -129,13 +129,6 @@ class AppTest < Dashing::Test end end - def test_get_nonexistent_dashboard_sends_file_with_404_status - with_generated_project do - app.any_instance.expects(:send_file).with(anything, has_entry(:status, 404)) - get '/nodashboard' - end - end - def test_get_widget with_generated_project do get '/views/meter.html' -- cgit v1.2.3 From 9d5fb04573cd00441f053d418d81320a8d019059 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Peters Date: Mon, 1 Jun 2015 17:40:57 +0200 Subject: add travis link and simplify link to license file --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 01010e0..4aee91f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # [Dashing](http://shopify.github.com/dashing) -![](https://api.travis-ci.org/Shopify/dashing.png) +[![Build Status](https://secure.travis-ci.org/Shopify/dashing.png?branch=master)](http://travis-ci.org/Shopify/dashing) Dashing is a Sinatra based framework that lets you build beautiful dashboards. It looks especially great on TVs. [Check out the homepage](http://shopify.github.com/dashing). # License -Distributed under the [MIT license](https://github.com/Shopify/dashing/blob/master/MIT-LICENSE) +Distributed under the [MIT license](MIT-LICENSE) -- cgit v1.2.3 From c33052f2d71765fdb11c5913eeb07b4fed389531 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 1 Jun 2015 11:50:37 -0400 Subject: Update License Copyright date --- MIT-LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIT-LICENSE b/MIT-LICENSE index 1cb4835..f85bef7 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014 Shopify +Copyright (c) 2015 Shopify Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the -- cgit v1.2.3 From e386ae84d9923e1c82c0441dbe5d9e17e48e0ddc Mon Sep 17 00:00:00 2001 From: Tyler Mauthe Date: Wed, 10 Jun 2015 18:59:03 -0600 Subject: Squashed commit of the following: commit 295006bd5ff723e9d79f61584cc645c19b6307d4 Author: Tyler Mauthe Date: Wed Jun 10 18:56:20 2015 -0600 :notebook: PR Feedback and normalize formatting commit 28858d2e7cbc59ff285174e0d95e17eccd054b66 Author: Tyler Mauthe Date: Wed Jun 10 00:09:38 2015 -0600 :notebook: Fix formatting and add icon for Docs commit 1557ce16a732e757d905eeb8cb917f6345a2c020 Author: Tyler Mauthe Date: Wed Jun 10 00:01:03 2015 -0600 :moyai: Initial Draft of Contribution Guidelines --- CONTRIBUTING.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d6deb4c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Welcome! +Thank you for your interest in Dashing! This exceptionally handsome +framework welcomes all input, but being stylish requires certain +protocols be followed. :bowtie: + +Below you will find a set of guidelines that will ensure the best outcome +for you _and_ Dashing. + + +## Have an Issue +If you run into problems with Dashing, please take these steps before +submitting an issue: + +1. Check the [Troubleshooting Guide](https://github.com/Shopify/dashing/wiki#how-tos) in the wiki. +2. Use the [GitHub Issue Search](https://help.github.com/articles/searching-issues/) to check if the issue has already been reported. +3. Submit your issue to our Issue Tracker. Please provide as much helpful information as possible, preferably making use of a [reduced test case](https://www.google.ca/search?#q=reduced%20test%20case). + +**Support requests should be directed to [Stack Overflow](http://stackoverflow.com/questions/tagged/dashing).** + + +## Feature Requests +Feature requests are welcome, but take a moment to consider whether your idea +fits with the scope and aim of the project. A good rule of thumb is to apply +the 80/20 rule: every feature should be useful to at least 80% of users. Adding +in every possible edge case will only make it more difficult to understand, maintain, +and hack on. + +If you feel that you have a really amazing, super neato idea that doesn't +quite fit with the core use of Dashing, it may be a good candidate for an +external Gem which supercharges a project. An excellent example of this is +[dashing-contrib](https://github.com/QubitProducts/dashing-contrib). If you +do create a third-party extension for Dashing, please add it [here](https://github.com/Shopify/dashing/wiki/Additional-Widgets#other-third-party-tools). + + +## Pull Requests + +Patches, improvements and new features are a fantastic +help -- thank you! + +**Please ask first** before embarking on any significant pull request (e.g. +implementing features, refactoring code, porting to a different language), +otherwise you risk spending a lot of time working on something that may +not be merged into the project. + +Please adhere to the coding conventions used throughout a project (indentation, +accurate comments, etc.) and any other requirements (such as test coverage). +All code submitted via Pull Request will be dicussed and critiqued in a +respectful manner. + +GitHub has [excellent documentation on how to use Pull Requests.](https://help.github.com/articles/using-pull-requests/) + + +## Git Commit Message Suggestions +* Consider starting the commit message with an applicable emoji: + * :art: `:art:` when improving the format/structure of the code + * :moyai: `:moyai:` when adding a new feature + * :wrench: `:wrench:` when dealing with the toolchain (Git, Travis, etc) + * :notebook: `:notebook` when dealing with docs + * :racehorse: `:racehorse:` when improving performance + * :penguin: `:penguin:` when fixing something on Linux + * :apple: `:apple:` when fixing something on Mac OS + * :bug: `:bug:` when fixing a bug + * :bomb: `:bomb:` when removing code or files + * :white_check_mark: `:white_check_mark:` when adding tests + * :lock: `:lock:` when dealing with security + * :arrow_up: `:arrow_up:` when upgrading dependencies + * :arrow_down: `:arrow_down:` when downgrading dependencies -- cgit v1.2.3 From b1962982ee0e6746d50942acb0f04f496143179d Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Wed, 10 Jun 2015 22:46:55 -0400 Subject: Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6deb4c..5c67793 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Below you will find a set of guidelines that will ensure the best outcome for you _and_ Dashing. -## Have an Issue +## Have an Issue? If you run into problems with Dashing, please take these steps before submitting an issue: -- cgit v1.2.3 From 07658254bd641603959d745af18fec14533c859b Mon Sep 17 00:00:00 2001 From: oren mazor Date: Wed, 17 Jun 2015 07:46:41 -0400 Subject: bump rack for security --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 2f9df4a..8694ff9 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -24,7 +24,7 @@ Gem::Specification.new do |s| s.add_dependency('rufus-scheduler', '~> 2.0.24') s.add_dependency('thor', '~> 0.18.1') s.add_dependency('sprockets', '~> 2.10.1') - s.add_dependency('rack', '~> 1.5.2') + s.add_dependency('rack', '~> 1.5.4') s.add_development_dependency('rake', '~> 10.1.0') s.add_development_dependency('haml', '~> 4.0.4') @@ -32,4 +32,4 @@ Gem::Specification.new do |s| s.add_development_dependency('mocha', '~> 0.14.0') s.add_development_dependency('fakeweb', '~> 1.3.0') s.add_development_dependency('simplecov', '~> 0.8.2') -end \ No newline at end of file +end -- cgit v1.2.3 From 581123f2e39d06459c335c94abdb3b5c0f4c0056 Mon Sep 17 00:00:00 2001 From: Hayden Ball Date: Wed, 1 Jul 2015 22:51:41 +0100 Subject: Allow thor 0.19.0 --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 8694ff9..4860465 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -22,7 +22,7 @@ Gem::Specification.new do |s| s.add_dependency('sinatra-contrib', '~> 1.4.2') s.add_dependency('thin', '~> 1.6.1') s.add_dependency('rufus-scheduler', '~> 2.0.24') - s.add_dependency('thor', '~> 0.18.1') + s.add_dependency('thor', '> 0.18.1') s.add_dependency('sprockets', '~> 2.10.1') s.add_dependency('rack', '~> 1.5.4') -- cgit v1.2.3 From c601933f800c124a8d4856a199b9af8056a57e9b Mon Sep 17 00:00:00 2001 From: Robert Reiz Date: Wed, 18 Nov 2015 22:45:46 +0100 Subject: Adding MIT license to the gemspec. --- dashing.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/dashing.gemspec b/dashing.gemspec index 4860465..33b5b17 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.author = "Daniel Beauchamp" s.email = 'daniel.beauchamp@shopify.com' s.homepage = 'http://shopify.github.com/dashing' + s.license = "MIT" s.files = Dir['README.md', 'javascripts/**/*', 'templates/**/*','templates/**/.[a-z]*', 'lib/**/*'] -- cgit v1.2.3 From 5b7ea3fd3e6f557230c79f600e08a20bba376836 Mon Sep 17 00:00:00 2001 From: Manuel Meurer Date: Wed, 2 Dec 2015 17:17:38 +0100 Subject: :art: fix indentation --- templates/project/config.ru | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/project/config.ru b/templates/project/config.ru index 6e1076a..624244e 100644 --- a/templates/project/config.ru +++ b/templates/project/config.ru @@ -5,8 +5,8 @@ configure do helpers do def protected! - # Put any authentication code you want in here. - # This method is run before accessing any resource. + # Put any authentication code you want in here. + # This method is run before accessing any resource. end end end @@ -15,4 +15,4 @@ map Sinatra::Application.assets_prefix do run Sinatra::Application.sprockets end -run Sinatra::Application \ No newline at end of file +run Sinatra::Application -- cgit v1.2.3 From f8d316e212d315a13f7d09149f1fd05624a20399 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 8 Dec 2015 15:49:55 -0500 Subject: Refactor and fix authentication --- lib/dashing/app.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/dashing/app.rb b/lib/dashing/app.rb index 0e7f7bb..b11352d 100644 --- a/lib/dashing/app.rb +++ b/lib/dashing/app.rb @@ -23,6 +23,11 @@ helpers do def protected! # override with auth logic end + + def authenticated?(token) + return true unless settings.auth_token + token && Rack::Utils.secure_compare(settings.auth_token, token) + end end set :root, Dir.pwd @@ -89,8 +94,7 @@ post '/dashboards/:id' do request.body.rewind body = JSON.parse(request.body.read) body['dashboard'] ||= params['id'] - auth_token = body.delete("auth_token") - if !settings.auth_token || settings.auth_token == auth_token + if authenticated?(body.delete("auth_token")) send_event(params['id'], body, 'dashboards') 204 # response without entity body else @@ -102,8 +106,7 @@ end post '/widgets/:id' do request.body.rewind body = JSON.parse(request.body.read) - auth_token = body.delete("auth_token") - if !settings.auth_token || settings.auth_token == auth_token + if authenticated?(body.delete("auth_token")) send_event(params['id'], body) 204 # response without entity body else -- cgit v1.2.3 From cffe4516963da30bb10def09c2f13fe1a01f3420 Mon Sep 17 00:00:00 2001 From: Prayag Verma Date: Sat, 16 Jan 2016 09:44:59 +0530 Subject: Update year to 2016 --- MIT-LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIT-LICENSE b/MIT-LICENSE index f85bef7..ac9f2bf 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015 Shopify +Copyright (c) 2016 Shopify Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the -- cgit v1.2.3 From d1d0309b1f9314828f4fa92af00f37b18119fdec Mon Sep 17 00:00:00 2001 From: Quentin Brossard Date: Mon, 15 Feb 2016 23:15:58 +0100 Subject: Update travis config to current ruby versions. This has the nice side effect of fixing the failing travis builds. :-) The build failures seen with older ruby versions (for example on 1.9.3) seem to be due to the following bundler bug: https://github.com/bundler/bundler/issues/3558 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 66b5ca9..f68ed76 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: ruby rvm: - - 2.1.2 - - 2.0.0 - - 1.9.3 + - 2.3.0 + - 2.2.4 + - 2.1.8 script: "rake test" -- cgit v1.2.3 From 1b1e390974f08a6dfd1bdae39a29175a2c480e08 Mon Sep 17 00:00:00 2001 From: Jonathan Batchelor Date: Mon, 22 Feb 2016 17:04:19 +0000 Subject: Updated to use FontAwesome 4.5.0 --- templates/project/assets/fonts/FontAwesome.otf | Bin 0 -> 109688 bytes .../project/assets/fonts/fontawesome-webfont.eot | Bin 37405 -> 70807 bytes .../project/assets/fonts/fontawesome-webfont.svg | 330 +++- .../project/assets/fonts/fontawesome-webfont.ttf | Bin 79076 -> 142072 bytes .../project/assets/fonts/fontawesome-webfont.woff | Bin 43572 -> 83588 bytes .../project/assets/fonts/fontawesome-webfont.woff2 | Bin 0 -> 66624 bytes .../project/assets/stylesheets/font-awesome.css | 1981 +++++++++++++------- templates/project/dashboards/sampletv.erb | 8 +- templates/project/widgets/number/number.coffee | 2 +- 9 files changed, 1592 insertions(+), 729 deletions(-) create mode 100644 templates/project/assets/fonts/FontAwesome.otf create mode 100644 templates/project/assets/fonts/fontawesome-webfont.woff2 diff --git a/templates/project/assets/fonts/FontAwesome.otf b/templates/project/assets/fonts/FontAwesome.otf new file mode 100644 index 0000000..3ed7f8b Binary files /dev/null and b/templates/project/assets/fonts/FontAwesome.otf differ diff --git a/templates/project/assets/fonts/fontawesome-webfont.eot b/templates/project/assets/fonts/fontawesome-webfont.eot index 0662cb9..9b6afae 100644 Binary files a/templates/project/assets/fonts/fontawesome-webfont.eot and b/templates/project/assets/fonts/fontawesome-webfont.eot differ diff --git a/templates/project/assets/fonts/fontawesome-webfont.svg b/templates/project/assets/fonts/fontawesome-webfont.svg index 2edb4ec..d05688e 100644 --- a/templates/project/assets/fonts/fontawesome-webfont.svg +++ b/templates/project/assets/fonts/fontawesome-webfont.svg @@ -14,10 +14,11 @@ + - + - + @@ -30,7 +31,7 @@ - + @@ -52,7 +53,7 @@ - + @@ -77,11 +78,11 @@ - - - - - + + + + + @@ -109,8 +110,8 @@ - - + + @@ -143,17 +144,17 @@ - - + + - + - + - + @@ -176,14 +177,14 @@ - + - + @@ -218,8 +219,8 @@ - - + + @@ -247,10 +248,10 @@ - + - + @@ -274,14 +275,14 @@ - + - - + + @@ -310,7 +311,7 @@ - + @@ -342,11 +343,11 @@ - + - - + + @@ -361,14 +362,14 @@ - + - - + + @@ -379,7 +380,7 @@ - + @@ -390,10 +391,265 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/project/assets/fonts/fontawesome-webfont.ttf b/templates/project/assets/fonts/fontawesome-webfont.ttf index d365924..26dea79 100644 Binary files a/templates/project/assets/fonts/fontawesome-webfont.ttf and b/templates/project/assets/fonts/fontawesome-webfont.ttf differ diff --git a/templates/project/assets/fonts/fontawesome-webfont.woff b/templates/project/assets/fonts/fontawesome-webfont.woff index b9bd17e..dc35ce3 100644 Binary files a/templates/project/assets/fonts/fontawesome-webfont.woff and b/templates/project/assets/fonts/fontawesome-webfont.woff differ diff --git a/templates/project/assets/fonts/fontawesome-webfont.woff2 b/templates/project/assets/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..500e517 Binary files /dev/null and b/templates/project/assets/fonts/fontawesome-webfont.woff2 differ diff --git a/templates/project/assets/stylesheets/font-awesome.css b/templates/project/assets/stylesheets/font-awesome.css index 69ae843..cf6fe78 100644 --- a/templates/project/assets/stylesheets/font-awesome.css +++ b/templates/project/assets/stylesheets/font-awesome.css @@ -1,1479 +1,2086 @@ /*! - * Font Awesome 3.2.1 - * the iconic font designed for Bootstrap - * ------------------------------------------------------------------------------ - * The full suite of pictographic icons, examples, and documentation can be - * found at http://fontawesome.io. Stay up to date on Twitter at - * http://twitter.com/fontawesome. - * - * License - * ------------------------------------------------------------------------------ - * - The Font Awesome font is licensed under SIL OFL 1.1 - - * http://scripts.sil.org/OFL - * - Font Awesome CSS, LESS, and SASS files are licensed under MIT License - - * http://opensource.org/licenses/mit-license.html - * - Font Awesome documentation licensed under CC BY 3.0 - - * http://creativecommons.org/licenses/by/3.0/ - * - Attribution is no longer required in Font Awesome 3.0, but much appreciated: - * "Font Awesome by Dave Gandy - http://fontawesome.io" - * - * Author - Dave Gandy - * ------------------------------------------------------------------------------ - * Email: dave@fontawesome.io - * Twitter: http://twitter.com/davegandy - * Work: Lead Product Designer @ Kyruus - http://kyruus.com + * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) */ /* FONT PATH * -------------------------- */ @font-face { font-family: 'FontAwesome'; - src: url('../assets/fontawesome-webfont.eot?v=3.2.1'); - src: url('../assets/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('../assets/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('../assets/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('../assets/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg'); + src: url('../assets/fontawesome-webfont.eot?v=4.5.0'); + src: url('../assets/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../assets/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../assets/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../assets/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../assets/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg'); font-weight: normal; font-style: normal; } -/* FONT AWESOME CORE - * -------------------------- */ -[class^="icon-"], -[class*=" icon-"] { - font-family: FontAwesome; - font-weight: normal; - font-style: normal; - text-decoration: inherit; - -webkit-font-smoothing: antialiased; - *margin-right: .3em; -} -[class^="icon-"]:before, -[class*=" icon-"]:before { - text-decoration: inherit; +.fa { display: inline-block; - speak: none; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } /* makes the font 33% larger relative to the icon container */ -.icon-large:before { - vertical-align: -10%; - font-size: 1.3333333333333333em; -} -/* makes sure icons active on rollover in links */ -a [class^="icon-"], -a [class*=" icon-"] { - display: inline; -} -/* increased font size for icon-large */ -[class^="icon-"].icon-fixed-width, -[class*=" icon-"].icon-fixed-width { - display: inline-block; - width: 1.1428571428571428em; - text-align: right; - padding-right: 0.2857142857142857em; +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; } -[class^="icon-"].icon-fixed-width.icon-large, -[class*=" icon-"].icon-fixed-width.icon-large { - width: 1.4285714285714286em; +.fa-2x { + font-size: 2em; } -.icons-ul { - margin-left: 2.142857142857143em; - list-style-type: none; +.fa-3x { + font-size: 3em; } -.icons-ul > li { - position: relative; +.fa-4x { + font-size: 4em; } -.icons-ul .icon-li { - position: absolute; - left: -2.142857142857143em; - width: 2.142857142857143em; +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; text-align: center; - line-height: inherit; } -[class^="icon-"].hide, -[class*=" icon-"].hide { - display: none; +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; } -.icon-muted { - color: #eeeeee; +.fa-ul > li { + position: relative; } -.icon-light { - color: #ffffff; +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; } -.icon-dark { - color: #333333; +.fa-li.fa-lg { + left: -1.85714286em; } -.icon-border { - border: solid 1px #eeeeee; +.fa-border { padding: .2em .25em .15em; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} -.icon-2x { - font-size: 2em; -} -.icon-2x.icon-border { - border-width: 2px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -.icon-3x { - font-size: 3em; -} -.icon-3x.icon-border { - border-width: 3px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; + border: solid 0.08em #eeeeee; + border-radius: .1em; } -.icon-4x { - font-size: 4em; +.fa-pull-left { + float: left; } -.icon-4x.icon-border { - border-width: 4px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; +.fa-pull-right { + float: right; } -.icon-5x { - font-size: 5em; +.fa.fa-pull-left { + margin-right: .3em; } -.icon-5x.icon-border { - border-width: 5px; - -webkit-border-radius: 7px; - -moz-border-radius: 7px; - border-radius: 7px; +.fa.fa-pull-right { + margin-left: .3em; } +/* Deprecated as of 4.4.0 */ .pull-right { float: right; } .pull-left { float: left; } -[class^="icon-"].pull-left, -[class*=" icon-"].pull-left { +.fa.pull-left { margin-right: .3em; } -[class^="icon-"].pull-right, -[class*=" icon-"].pull-right { +.fa.pull-right { margin-left: .3em; } -/* BOOTSTRAP SPECIFIC CLASSES - * -------------------------- */ -/* Bootstrap 2.0 sprites.less reset */ -[class^="icon-"], -[class*=" icon-"] { - display: inline; - width: auto; - height: auto; - line-height: normal; - vertical-align: baseline; - background-image: none; - background-position: 0% 0%; - background-repeat: repeat; - margin-top: 0; -} -/* more sprites.less reset */ -.icon-white, -.nav-pills > .active > a > [class^="icon-"], -.nav-pills > .active > a > [class*=" icon-"], -.nav-list > .active > a > [class^="icon-"], -.nav-list > .active > a > [class*=" icon-"], -.navbar-inverse .nav > .active > a > [class^="icon-"], -.navbar-inverse .nav > .active > a > [class*=" icon-"], -.dropdown-menu > li > a:hover > [class^="icon-"], -.dropdown-menu > li > a:hover > [class*=" icon-"], -.dropdown-menu > .active > a > [class^="icon-"], -.dropdown-menu > .active > a > [class*=" icon-"], -.dropdown-submenu:hover > a > [class^="icon-"], -.dropdown-submenu:hover > a > [class*=" icon-"] { - background-image: none; -} -/* keeps Bootstrap styles with and without icons the same */ -.btn [class^="icon-"].icon-large, -.nav [class^="icon-"].icon-large, -.btn [class*=" icon-"].icon-large, -.nav [class*=" icon-"].icon-large { - line-height: .9em; -} -.btn [class^="icon-"].icon-spin, -.nav [class^="icon-"].icon-spin, -.btn [class*=" icon-"].icon-spin, -.nav [class*=" icon-"].icon-spin { - display: inline-block; +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; } -.nav-tabs [class^="icon-"], -.nav-pills [class^="icon-"], -.nav-tabs [class*=" icon-"], -.nav-pills [class*=" icon-"], -.nav-tabs [class^="icon-"].icon-large, -.nav-pills [class^="icon-"].icon-large, -.nav-tabs [class*=" icon-"].icon-large, -.nav-pills [class*=" icon-"].icon-large { - line-height: .9em; -} -.btn [class^="icon-"].pull-left.icon-2x, -.btn [class*=" icon-"].pull-left.icon-2x, -.btn [class^="icon-"].pull-right.icon-2x, -.btn [class*=" icon-"].pull-right.icon-2x { - margin-top: .18em; -} -.btn [class^="icon-"].icon-spin.icon-large, -.btn [class*=" icon-"].icon-spin.icon-large { - line-height: .8em; -} -.btn.btn-small [class^="icon-"].pull-left.icon-2x, -.btn.btn-small [class*=" icon-"].pull-left.icon-2x, -.btn.btn-small [class^="icon-"].pull-right.icon-2x, -.btn.btn-small [class*=" icon-"].pull-right.icon-2x { - margin-top: .25em; -} -.btn.btn-large [class^="icon-"], -.btn.btn-large [class*=" icon-"] { - margin-top: 0; -} -.btn.btn-large [class^="icon-"].pull-left.icon-2x, -.btn.btn-large [class*=" icon-"].pull-left.icon-2x, -.btn.btn-large [class^="icon-"].pull-right.icon-2x, -.btn.btn-large [class*=" icon-"].pull-right.icon-2x { - margin-top: .05em; -} -.btn.btn-large [class^="icon-"].pull-left.icon-2x, -.btn.btn-large [class*=" icon-"].pull-left.icon-2x { - margin-right: .2em; -} -.btn.btn-large [class^="icon-"].pull-right.icon-2x, -.btn.btn-large [class*=" icon-"].pull-right.icon-2x { - margin-left: .2em; -} -/* Fixes alignment in nav lists */ -.nav-list [class^="icon-"], -.nav-list [class*=" icon-"] { - line-height: inherit; +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); } -/* EXTRAS - * -------------------------- */ -/* Stacked and layered icon */ -.icon-stack { - position: relative; - display: inline-block; - width: 2em; - height: 2em; - line-height: 2em; - vertical-align: -35%; -} -.icon-stack [class^="icon-"], -.icon-stack [class*=" icon-"] { - display: block; - text-align: center; - position: absolute; - width: 100%; - height: 100%; - font-size: 1em; - line-height: inherit; - *line-height: 2em; -} -.icon-stack .icon-stack-base { - font-size: 2em; - *line-height: 1em; -} -/* Animated rotating icon */ -.icon-spin { - display: inline-block; - -moz-animation: spin 2s infinite linear; - -o-animation: spin 2s infinite linear; - -webkit-animation: spin 2s infinite linear; - animation: spin 2s infinite linear; -} -/* Prevent stack and spinners from being taken inline when inside a link */ -a .icon-stack, -a .icon-spin { - display: inline-block; - text-decoration: none; -} -@-moz-keyframes spin { - 0% { - -moz-transform: rotate(0deg); - } - 100% { - -moz-transform: rotate(359deg); - } -} -@-webkit-keyframes spin { +@-webkit-keyframes fa-spin { 0% { -webkit-transform: rotate(0deg); + transform: rotate(0deg); } 100% { -webkit-transform: rotate(359deg); + transform: rotate(359deg); } } -@-o-keyframes spin { - 0% { - -o-transform: rotate(0deg); - } - 100% { - -o-transform: rotate(359deg); - } -} -@-ms-keyframes spin { - 0% { - -ms-transform: rotate(0deg); - } - 100% { - -ms-transform: rotate(359deg); - } -} -@keyframes spin { +@keyframes fa-spin { 0% { + -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { + -webkit-transform: rotate(359deg); transform: rotate(359deg); } } -/* Icon rotations and mirroring */ -.icon-rotate-90:before { +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); -webkit-transform: rotate(90deg); - -moz-transform: rotate(90deg); -ms-transform: rotate(90deg); - -o-transform: rotate(90deg); transform: rotate(90deg); - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); } -.icon-rotate-180:before { +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); -ms-transform: rotate(180deg); - -o-transform: rotate(180deg); transform: rotate(180deg); - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); } -.icon-rotate-270:before { +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); -webkit-transform: rotate(270deg); - -moz-transform: rotate(270deg); -ms-transform: rotate(270deg); - -o-transform: rotate(270deg); transform: rotate(270deg); - filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); } -.icon-flip-horizontal:before { +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); -webkit-transform: scale(-1, 1); - -moz-transform: scale(-1, 1); -ms-transform: scale(-1, 1); - -o-transform: scale(-1, 1); transform: scale(-1, 1); } -.icon-flip-vertical:before { +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); -webkit-transform: scale(1, -1); - -moz-transform: scale(1, -1); -ms-transform: scale(1, -1); - -o-transform: scale(1, -1); transform: scale(1, -1); } -/* ensure rotation occurs inside anchor tags */ -a .icon-rotate-90:before, -a .icon-rotate-180:before, -a .icon-rotate-270:before, -a .icon-flip-horizontal:before, -a .icon-flip-vertical:before { +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; } /* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen readers do not read off random characters that represent icons */ -.icon-glass:before { +.fa-glass:before { content: "\f000"; } -.icon-music:before { +.fa-music:before { content: "\f001"; } -.icon-search:before { +.fa-search:before { content: "\f002"; } -.icon-envelope-alt:before { +.fa-envelope-o:before { content: "\f003"; } -.icon-heart:before { +.fa-heart:before { content: "\f004"; } -.icon-star:before { +.fa-star:before { content: "\f005"; } -.icon-star-empty:before { +.fa-star-o:before { content: "\f006"; } -.icon-user:before { +.fa-user:before { content: "\f007"; } -.icon-film:before { +.fa-film:before { content: "\f008"; } -.icon-th-large:before { +.fa-th-large:before { content: "\f009"; } -.icon-th:before { +.fa-th:before { content: "\f00a"; } -.icon-th-list:before { +.fa-th-list:before { content: "\f00b"; } -.icon-ok:before { +.fa-check:before { content: "\f00c"; } -.icon-remove:before { +.fa-remove:before, +.fa-close:before, +.fa-times:before { content: "\f00d"; } -.icon-zoom-in:before { +.fa-search-plus:before { content: "\f00e"; } -.icon-zoom-out:before { +.fa-search-minus:before { content: "\f010"; } -.icon-power-off:before, -.icon-off:before { +.fa-power-off:before { content: "\f011"; } -.icon-signal:before { +.fa-signal:before { content: "\f012"; } -.icon-gear:before, -.icon-cog:before { +.fa-gear:before, +.fa-cog:before { content: "\f013"; } -.icon-trash:before { +.fa-trash-o:before { content: "\f014"; } -.icon-home:before { +.fa-home:before { content: "\f015"; } -.icon-file-alt:before { +.fa-file-o:before { content: "\f016"; } -.icon-time:before { +.fa-clock-o:before { content: "\f017"; } -.icon-road:before { +.fa-road:before { content: "\f018"; } -.icon-download-alt:before { +.fa-download:before { content: "\f019"; } -.icon-download:before { +.fa-arrow-circle-o-down:before { content: "\f01a"; } -.icon-upload:before { +.fa-arrow-circle-o-up:before { content: "\f01b"; } -.icon-inbox:before { +.fa-inbox:before { content: "\f01c"; } -.icon-play-circle:before { +.fa-play-circle-o:before { content: "\f01d"; } -.icon-rotate-right:before, -.icon-repeat:before { +.fa-rotate-right:before, +.fa-repeat:before { content: "\f01e"; } -.icon-refresh:before { +.fa-refresh:before { content: "\f021"; } -.icon-list-alt:before { +.fa-list-alt:before { content: "\f022"; } -.icon-lock:before { +.fa-lock:before { content: "\f023"; } -.icon-flag:before { +.fa-flag:before { content: "\f024"; } -.icon-headphones:before { +.fa-headphones:before { content: "\f025"; } -.icon-volume-off:before { +.fa-volume-off:before { content: "\f026"; } -.icon-volume-down:before { +.fa-volume-down:before { content: "\f027"; } -.icon-volume-up:before { +.fa-volume-up:before { content: "\f028"; } -.icon-qrcode:before { +.fa-qrcode:before { content: "\f029"; } -.icon-barcode:before { +.fa-barcode:before { content: "\f02a"; } -.icon-tag:before { +.fa-tag:before { content: "\f02b"; } -.icon-tags:before { +.fa-tags:before { content: "\f02c"; } -.icon-book:before { +.fa-book:before { content: "\f02d"; } -.icon-bookmark:before { +.fa-bookmark:before { content: "\f02e"; } -.icon-print:before { +.fa-print:before { content: "\f02f"; } -.icon-camera:before { +.fa-camera:before { content: "\f030"; } -.icon-font:before { +.fa-font:before { content: "\f031"; } -.icon-bold:before { +.fa-bold:before { content: "\f032"; } -.icon-italic:before { +.fa-italic:before { content: "\f033"; } -.icon-text-height:before { +.fa-text-height:before { content: "\f034"; } -.icon-text-width:before { +.fa-text-width:before { content: "\f035"; } -.icon-align-left:before { +.fa-align-left:before { content: "\f036"; } -.icon-align-center:before { +.fa-align-center:before { content: "\f037"; } -.icon-align-right:before { +.fa-align-right:before { content: "\f038"; } -.icon-align-justify:before { +.fa-align-justify:before { content: "\f039"; } -.icon-list:before { +.fa-list:before { content: "\f03a"; } -.icon-indent-left:before { +.fa-dedent:before, +.fa-outdent:before { content: "\f03b"; } -.icon-indent-right:before { +.fa-indent:before { content: "\f03c"; } -.icon-facetime-video:before { +.fa-video-camera:before { content: "\f03d"; } -.icon-picture:before { +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { content: "\f03e"; } -.icon-pencil:before { +.fa-pencil:before { content: "\f040"; } -.icon-map-marker:before { +.fa-map-marker:before { content: "\f041"; } -.icon-adjust:before { +.fa-adjust:before { content: "\f042"; } -.icon-tint:before { +.fa-tint:before { content: "\f043"; } -.icon-edit:before { +.fa-edit:before, +.fa-pencil-square-o:before { content: "\f044"; } -.icon-share:before { +.fa-share-square-o:before { content: "\f045"; } -.icon-check:before { +.fa-check-square-o:before { content: "\f046"; } -.icon-move:before { +.fa-arrows:before { content: "\f047"; } -.icon-step-backward:before { +.fa-step-backward:before { content: "\f048"; } -.icon-fast-backward:before { +.fa-fast-backward:before { content: "\f049"; } -.icon-backward:before { +.fa-backward:before { content: "\f04a"; } -.icon-play:before { +.fa-play:before { content: "\f04b"; } -.icon-pause:before { +.fa-pause:before { content: "\f04c"; } -.icon-stop:before { +.fa-stop:before { content: "\f04d"; } -.icon-forward:before { +.fa-forward:before { content: "\f04e"; } -.icon-fast-forward:before { +.fa-fast-forward:before { content: "\f050"; } -.icon-step-forward:before { +.fa-step-forward:before { content: "\f051"; } -.icon-eject:before { +.fa-eject:before { content: "\f052"; } -.icon-chevron-left:before { +.fa-chevron-left:before { content: "\f053"; } -.icon-chevron-right:before { +.fa-chevron-right:before { content: "\f054"; } -.icon-plus-sign:before { +.fa-plus-circle:before { content: "\f055"; } -.icon-minus-sign:before { +.fa-minus-circle:before { content: "\f056"; } -.icon-remove-sign:before { +.fa-times-circle:before { content: "\f057"; } -.icon-ok-sign:before { +.fa-check-circle:before { content: "\f058"; } -.icon-question-sign:before { +.fa-question-circle:before { content: "\f059"; } -.icon-info-sign:before { +.fa-info-circle:before { content: "\f05a"; } -.icon-screenshot:before { +.fa-crosshairs:before { content: "\f05b"; } -.icon-remove-circle:before { +.fa-times-circle-o:before { content: "\f05c"; } -.icon-ok-circle:before { +.fa-check-circle-o:before { content: "\f05d"; } -.icon-ban-circle:before { +.fa-ban:before { content: "\f05e"; } -.icon-arrow-left:before { +.fa-arrow-left:before { content: "\f060"; } -.icon-arrow-right:before { +.fa-arrow-right:before { content: "\f061"; } -.icon-arrow-up:before { +.fa-arrow-up:before { content: "\f062"; } -.icon-arrow-down:before { +.fa-arrow-down:before { content: "\f063"; } -.icon-mail-forward:before, -.icon-share-alt:before { +.fa-mail-forward:before, +.fa-share:before { content: "\f064"; } -.icon-resize-full:before { +.fa-expand:before { content: "\f065"; } -.icon-resize-small:before { +.fa-compress:before { content: "\f066"; } -.icon-plus:before { +.fa-plus:before { content: "\f067"; } -.icon-minus:before { +.fa-minus:before { content: "\f068"; } -.icon-asterisk:before { +.fa-asterisk:before { content: "\f069"; } -.icon-exclamation-sign:before { +.fa-exclamation-circle:before { content: "\f06a"; } -.icon-gift:before { +.fa-gift:before { content: "\f06b"; } -.icon-leaf:before { +.fa-leaf:before { content: "\f06c"; } -.icon-fire:before { +.fa-fire:before { content: "\f06d"; } -.icon-eye-open:before { +.fa-eye:before { content: "\f06e"; } -.icon-eye-close:before { +.fa-eye-slash:before { content: "\f070"; } -.icon-warning-sign:before { +.fa-warning:before, +.fa-exclamation-triangle:before { content: "\f071"; } -.icon-plane:before { +.fa-plane:before { content: "\f072"; } -.icon-calendar:before { +.fa-calendar:before { content: "\f073"; } -.icon-random:before { +.fa-random:before { content: "\f074"; } -.icon-comment:before { +.fa-comment:before { content: "\f075"; } -.icon-magnet:before { +.fa-magnet:before { content: "\f076"; } -.icon-chevron-up:before { +.fa-chevron-up:before { content: "\f077"; } -.icon-chevron-down:before { +.fa-chevron-down:before { content: "\f078"; } -.icon-retweet:before { +.fa-retweet:before { content: "\f079"; } -.icon-shopping-cart:before { +.fa-shopping-cart:before { content: "\f07a"; } -.icon-folder-close:before { +.fa-folder:before { content: "\f07b"; } -.icon-folder-open:before { +.fa-folder-open:before { content: "\f07c"; } -.icon-resize-vertical:before { +.fa-arrows-v:before { content: "\f07d"; } -.icon-resize-horizontal:before { +.fa-arrows-h:before { content: "\f07e"; } -.icon-bar-chart:before { +.fa-bar-chart-o:before, +.fa-bar-chart:before { content: "\f080"; } -.icon-twitter-sign:before { +.fa-twitter-square:before { content: "\f081"; } -.icon-facebook-sign:before { +.fa-facebook-square:before { content: "\f082"; } -.icon-camera-retro:before { +.fa-camera-retro:before { content: "\f083"; } -.icon-key:before { +.fa-key:before { content: "\f084"; } -.icon-gears:before, -.icon-cogs:before { +.fa-gears:before, +.fa-cogs:before { content: "\f085"; } -.icon-comments:before { +.fa-comments:before { content: "\f086"; } -.icon-thumbs-up-alt:before { +.fa-thumbs-o-up:before { content: "\f087"; } -.icon-thumbs-down-alt:before { +.fa-thumbs-o-down:before { content: "\f088"; } -.icon-star-half:before { +.fa-star-half:before { content: "\f089"; } -.icon-heart-empty:before { +.fa-heart-o:before { content: "\f08a"; } -.icon-signout:before { +.fa-sign-out:before { content: "\f08b"; } -.icon-linkedin-sign:before { +.fa-linkedin-square:before { content: "\f08c"; } -.icon-pushpin:before { +.fa-thumb-tack:before { content: "\f08d"; } -.icon-external-link:before { +.fa-external-link:before { content: "\f08e"; } -.icon-signin:before { +.fa-sign-in:before { content: "\f090"; } -.icon-trophy:before { +.fa-trophy:before { content: "\f091"; } -.icon-github-sign:before { +.fa-github-square:before { content: "\f092"; } -.icon-upload-alt:before { +.fa-upload:before { content: "\f093"; } -.icon-lemon:before { +.fa-lemon-o:before { content: "\f094"; } -.icon-phone:before { +.fa-phone:before { content: "\f095"; } -.icon-unchecked:before, -.icon-check-empty:before { +.fa-square-o:before { content: "\f096"; } -.icon-bookmark-empty:before { +.fa-bookmark-o:before { content: "\f097"; } -.icon-phone-sign:before { +.fa-phone-square:before { content: "\f098"; } -.icon-twitter:before { +.fa-twitter:before { content: "\f099"; } -.icon-facebook:before { +.fa-facebook-f:before, +.fa-facebook:before { content: "\f09a"; } -.icon-github:before { +.fa-github:before { content: "\f09b"; } -.icon-unlock:before { +.fa-unlock:before { content: "\f09c"; } -.icon-credit-card:before { +.fa-credit-card:before { content: "\f09d"; } -.icon-rss:before { +.fa-feed:before, +.fa-rss:before { content: "\f09e"; } -.icon-hdd:before { +.fa-hdd-o:before { content: "\f0a0"; } -.icon-bullhorn:before { +.fa-bullhorn:before { content: "\f0a1"; } -.icon-bell:before { - content: "\f0a2"; +.fa-bell:before { + content: "\f0f3"; } -.icon-certificate:before { +.fa-certificate:before { content: "\f0a3"; } -.icon-hand-right:before { +.fa-hand-o-right:before { content: "\f0a4"; } -.icon-hand-left:before { +.fa-hand-o-left:before { content: "\f0a5"; } -.icon-hand-up:before { +.fa-hand-o-up:before { content: "\f0a6"; } -.icon-hand-down:before { +.fa-hand-o-down:before { content: "\f0a7"; } -.icon-circle-arrow-left:before { +.fa-arrow-circle-left:before { content: "\f0a8"; } -.icon-circle-arrow-right:before { +.fa-arrow-circle-right:before { content: "\f0a9"; } -.icon-circle-arrow-up:before { +.fa-arrow-circle-up:before { content: "\f0aa"; } -.icon-circle-arrow-down:before { +.fa-arrow-circle-down:before { content: "\f0ab"; } -.icon-globe:before { +.fa-globe:before { content: "\f0ac"; } -.icon-wrench:before { +.fa-wrench:before { content: "\f0ad"; } -.icon-tasks:before { +.fa-tasks:before { content: "\f0ae"; } -.icon-filter:before { +.fa-filter:before { content: "\f0b0"; } -.icon-briefcase:before { +.fa-briefcase:before { content: "\f0b1"; } -.icon-fullscreen:before { +.fa-arrows-alt:before { content: "\f0b2"; } -.icon-group:before { +.fa-group:before, +.fa-users:before { content: "\f0c0"; } -.icon-link:before { +.fa-chain:before, +.fa-link:before { content: "\f0c1"; } -.icon-cloud:before { +.fa-cloud:before { content: "\f0c2"; } -.icon-beaker:before { +.fa-flask:before { content: "\f0c3"; } -.icon-cut:before { +.fa-cut:before, +.fa-scissors:before { content: "\f0c4"; } -.icon-copy:before { +.fa-copy:before, +.fa-files-o:before { content: "\f0c5"; } -.icon-paperclip:before, -.icon-paper-clip:before { +.fa-paperclip:before { content: "\f0c6"; } -.icon-save:before { +.fa-save:before, +.fa-floppy-o:before { content: "\f0c7"; } -.icon-sign-blank:before { +.fa-square:before { content: "\f0c8"; } -.icon-reorder:before { +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { content: "\f0c9"; } -.icon-list-ul:before { +.fa-list-ul:before { content: "\f0ca"; } -.icon-list-ol:before { +.fa-list-ol:before { content: "\f0cb"; } -.icon-strikethrough:before { +.fa-strikethrough:before { content: "\f0cc"; } -.icon-underline:before { +.fa-underline:before { content: "\f0cd"; } -.icon-table:before { +.fa-table:before { content: "\f0ce"; } -.icon-magic:before { +.fa-magic:before { content: "\f0d0"; } -.icon-truck:before { +.fa-truck:before { content: "\f0d1"; } -.icon-pinterest:before { +.fa-pinterest:before { content: "\f0d2"; } -.icon-pinterest-sign:before { +.fa-pinterest-square:before { content: "\f0d3"; } -.icon-google-plus-sign:before { +.fa-google-plus-square:before { content: "\f0d4"; } -.icon-google-plus:before { +.fa-google-plus:before { content: "\f0d5"; } -.icon-money:before { +.fa-money:before { content: "\f0d6"; } -.icon-caret-down:before { +.fa-caret-down:before { content: "\f0d7"; } -.icon-caret-up:before { +.fa-caret-up:before { content: "\f0d8"; } -.icon-caret-left:before { +.fa-caret-left:before { content: "\f0d9"; } -.icon-caret-right:before { +.fa-caret-right:before { content: "\f0da"; } -.icon-columns:before { +.fa-columns:before { content: "\f0db"; } -.icon-sort:before { +.fa-unsorted:before, +.fa-sort:before { content: "\f0dc"; } -.icon-sort-down:before { +.fa-sort-down:before, +.fa-sort-desc:before { content: "\f0dd"; } -.icon-sort-up:before { +.fa-sort-up:before, +.fa-sort-asc:before { content: "\f0de"; } -.icon-envelope:before { +.fa-envelope:before { content: "\f0e0"; } -.icon-linkedin:before { +.fa-linkedin:before { content: "\f0e1"; } -.icon-rotate-left:before, -.icon-undo:before { +.fa-rotate-left:before, +.fa-undo:before { content: "\f0e2"; } -.icon-legal:before { +.fa-legal:before, +.fa-gavel:before { content: "\f0e3"; } -.icon-dashboard:before { +.fa-dashboard:before, +.fa-tachometer:before { content: "\f0e4"; } -.icon-comment-alt:before { +.fa-comment-o:before { content: "\f0e5"; } -.icon-comments-alt:before { +.fa-comments-o:before { content: "\f0e6"; } -.icon-bolt:before { +.fa-flash:before, +.fa-bolt:before { content: "\f0e7"; } -.icon-sitemap:before { +.fa-sitemap:before { content: "\f0e8"; } -.icon-umbrella:before { +.fa-umbrella:before { content: "\f0e9"; } -.icon-paste:before { +.fa-paste:before, +.fa-clipboard:before { content: "\f0ea"; } -.icon-lightbulb:before { +.fa-lightbulb-o:before { content: "\f0eb"; } -.icon-exchange:before { +.fa-exchange:before { content: "\f0ec"; } -.icon-cloud-download:before { +.fa-cloud-download:before { content: "\f0ed"; } -.icon-cloud-upload:before { +.fa-cloud-upload:before { content: "\f0ee"; } -.icon-user-md:before { +.fa-user-md:before { content: "\f0f0"; } -.icon-stethoscope:before { +.fa-stethoscope:before { content: "\f0f1"; } -.icon-suitcase:before { +.fa-suitcase:before { content: "\f0f2"; } -.icon-bell-alt:before { - content: "\f0f3"; +.fa-bell-o:before { + content: "\f0a2"; } -.icon-coffee:before { +.fa-coffee:before { content: "\f0f4"; } -.icon-food:before { +.fa-cutlery:before { content: "\f0f5"; } -.icon-file-text-alt:before { +.fa-file-text-o:before { content: "\f0f6"; } -.icon-building:before { +.fa-building-o:before { content: "\f0f7"; } -.icon-hospital:before { +.fa-hospital-o:before { content: "\f0f8"; } -.icon-ambulance:before { +.fa-ambulance:before { content: "\f0f9"; } -.icon-medkit:before { +.fa-medkit:before { content: "\f0fa"; } -.icon-fighter-jet:before { +.fa-fighter-jet:before { content: "\f0fb"; } -.icon-beer:before { +.fa-beer:before { content: "\f0fc"; } -.icon-h-sign:before { +.fa-h-square:before { content: "\f0fd"; } -.icon-plus-sign-alt:before { +.fa-plus-square:before { content: "\f0fe"; } -.icon-double-angle-left:before { +.fa-angle-double-left:before { content: "\f100"; } -.icon-double-angle-right:before { +.fa-angle-double-right:before { content: "\f101"; } -.icon-double-angle-up:before { +.fa-angle-double-up:before { content: "\f102"; } -.icon-double-angle-down:before { +.fa-angle-double-down:before { content: "\f103"; } -.icon-angle-left:before { +.fa-angle-left:before { content: "\f104"; } -.icon-angle-right:before { +.fa-angle-right:before { content: "\f105"; } -.icon-angle-up:before { +.fa-angle-up:before { content: "\f106"; } -.icon-angle-down:before { +.fa-angle-down:before { content: "\f107"; } -.icon-desktop:before { +.fa-desktop:before { content: "\f108"; } -.icon-laptop:before { +.fa-laptop:before { content: "\f109"; } -.icon-tablet:before { +.fa-tablet:before { content: "\f10a"; } -.icon-mobile-phone:before { +.fa-mobile-phone:before, +.fa-mobile:before { content: "\f10b"; } -.icon-circle-blank:before { +.fa-circle-o:before { content: "\f10c"; } -.icon-quote-left:before { +.fa-quote-left:before { content: "\f10d"; } -.icon-quote-right:before { +.fa-quote-right:before { content: "\f10e"; } -.icon-spinner:before { +.fa-spinner:before { content: "\f110"; } -.icon-circle:before { +.fa-circle:before { content: "\f111"; } -.icon-mail-reply:before, -.icon-reply:before { +.fa-mail-reply:before, +.fa-reply:before { content: "\f112"; } -.icon-github-alt:before { +.fa-github-alt:before { content: "\f113"; } -.icon-folder-close-alt:before { +.fa-folder-o:before { content: "\f114"; } -.icon-folder-open-alt:before { +.fa-folder-open-o:before { content: "\f115"; } -.icon-expand-alt:before { - content: "\f116"; -} -.icon-collapse-alt:before { - content: "\f117"; -} -.icon-smile:before { +.fa-smile-o:before { content: "\f118"; } -.icon-frown:before { +.fa-frown-o:before { content: "\f119"; } -.icon-meh:before { +.fa-meh-o:before { content: "\f11a"; } -.icon-gamepad:before { +.fa-gamepad:before { content: "\f11b"; } -.icon-keyboard:before { +.fa-keyboard-o:before { content: "\f11c"; } -.icon-flag-alt:before { +.fa-flag-o:before { content: "\f11d"; } -.icon-flag-checkered:before { +.fa-flag-checkered:before { content: "\f11e"; } -.icon-terminal:before { +.fa-terminal:before { content: "\f120"; } -.icon-code:before { +.fa-code:before { content: "\f121"; } -.icon-reply-all:before { - content: "\f122"; -} -.icon-mail-reply-all:before { +.fa-mail-reply-all:before, +.fa-reply-all:before { content: "\f122"; } -.icon-star-half-full:before, -.icon-star-half-empty:before { +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { content: "\f123"; } -.icon-location-arrow:before { +.fa-location-arrow:before { content: "\f124"; } -.icon-crop:before { +.fa-crop:before { content: "\f125"; } -.icon-code-fork:before { +.fa-code-fork:before { content: "\f126"; } -.icon-unlink:before { +.fa-unlink:before, +.fa-chain-broken:before { content: "\f127"; } -.icon-question:before { +.fa-question:before { content: "\f128"; } -.icon-info:before { +.fa-info:before { content: "\f129"; } -.icon-exclamation:before { +.fa-exclamation:before { content: "\f12a"; } -.icon-superscript:before { +.fa-superscript:before { content: "\f12b"; } -.icon-subscript:before { +.fa-subscript:before { content: "\f12c"; } -.icon-eraser:before { +.fa-eraser:before { content: "\f12d"; } -.icon-puzzle-piece:before { +.fa-puzzle-piece:before { content: "\f12e"; } -.icon-microphone:before { +.fa-microphone:before { content: "\f130"; } -.icon-microphone-off:before { +.fa-microphone-slash:before { content: "\f131"; } -.icon-shield:before { +.fa-shield:before { content: "\f132"; } -.icon-calendar-empty:before { +.fa-calendar-o:before { content: "\f133"; } -.icon-fire-extinguisher:before { +.fa-fire-extinguisher:before { content: "\f134"; } -.icon-rocket:before { +.fa-rocket:before { content: "\f135"; } -.icon-maxcdn:before { +.fa-maxcdn:before { content: "\f136"; } -.icon-chevron-sign-left:before { +.fa-chevron-circle-left:before { content: "\f137"; } -.icon-chevron-sign-right:before { +.fa-chevron-circle-right:before { content: "\f138"; } -.icon-chevron-sign-up:before { +.fa-chevron-circle-up:before { content: "\f139"; } -.icon-chevron-sign-down:before { +.fa-chevron-circle-down:before { content: "\f13a"; } -.icon-html5:before { +.fa-html5:before { content: "\f13b"; } -.icon-css3:before { +.fa-css3:before { content: "\f13c"; } -.icon-anchor:before { +.fa-anchor:before { content: "\f13d"; } -.icon-unlock-alt:before { +.fa-unlock-alt:before { content: "\f13e"; } -.icon-bullseye:before { +.fa-bullseye:before { content: "\f140"; } -.icon-ellipsis-horizontal:before { +.fa-ellipsis-h:before { content: "\f141"; } -.icon-ellipsis-vertical:before { +.fa-ellipsis-v:before { content: "\f142"; } -.icon-rss-sign:before { +.fa-rss-square:before { content: "\f143"; } -.icon-play-sign:before { +.fa-play-circle:before { content: "\f144"; } -.icon-ticket:before { +.fa-ticket:before { content: "\f145"; } -.icon-minus-sign-alt:before { +.fa-minus-square:before { content: "\f146"; } -.icon-check-minus:before { +.fa-minus-square-o:before { content: "\f147"; } -.icon-level-up:before { +.fa-level-up:before { content: "\f148"; } -.icon-level-down:before { +.fa-level-down:before { content: "\f149"; } -.icon-check-sign:before { +.fa-check-square:before { content: "\f14a"; } -.icon-edit-sign:before { +.fa-pencil-square:before { content: "\f14b"; } -.icon-external-link-sign:before { +.fa-external-link-square:before { content: "\f14c"; } -.icon-share-sign:before { +.fa-share-square:before { content: "\f14d"; } -.icon-compass:before { +.fa-compass:before { content: "\f14e"; } -.icon-collapse:before { +.fa-toggle-down:before, +.fa-caret-square-o-down:before { content: "\f150"; } -.icon-collapse-top:before { +.fa-toggle-up:before, +.fa-caret-square-o-up:before { content: "\f151"; } -.icon-expand:before { +.fa-toggle-right:before, +.fa-caret-square-o-right:before { content: "\f152"; } -.icon-euro:before, -.icon-eur:before { +.fa-euro:before, +.fa-eur:before { content: "\f153"; } -.icon-gbp:before { +.fa-gbp:before { content: "\f154"; } -.icon-dollar:before, -.icon-usd:before { +.fa-dollar:before, +.fa-usd:before { content: "\f155"; } -.icon-rupee:before, -.icon-inr:before { +.fa-rupee:before, +.fa-inr:before { content: "\f156"; } -.icon-yen:before, -.icon-jpy:before { +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { content: "\f157"; } -.icon-renminbi:before, -.icon-cny:before { +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { content: "\f158"; } -.icon-won:before, -.icon-krw:before { +.fa-won:before, +.fa-krw:before { content: "\f159"; } -.icon-bitcoin:before, -.icon-btc:before { +.fa-bitcoin:before, +.fa-btc:before { content: "\f15a"; } -.icon-file:before { +.fa-file:before { content: "\f15b"; } -.icon-file-text:before { +.fa-file-text:before { content: "\f15c"; } -.icon-sort-by-alphabet:before { +.fa-sort-alpha-asc:before { content: "\f15d"; } -.icon-sort-by-alphabet-alt:before { +.fa-sort-alpha-desc:before { content: "\f15e"; } -.icon-sort-by-attributes:before { +.fa-sort-amount-asc:before { content: "\f160"; } -.icon-sort-by-attributes-alt:before { +.fa-sort-amount-desc:before { content: "\f161"; } -.icon-sort-by-order:before { +.fa-sort-numeric-asc:before { content: "\f162"; } -.icon-sort-by-order-alt:before { +.fa-sort-numeric-desc:before { content: "\f163"; } -.icon-thumbs-up:before { +.fa-thumbs-up:before { content: "\f164"; } -.icon-thumbs-down:before { +.fa-thumbs-down:before { content: "\f165"; } -.icon-youtube-sign:before { +.fa-youtube-square:before { content: "\f166"; } -.icon-youtube:before { +.fa-youtube:before { content: "\f167"; } -.icon-xing:before { +.fa-xing:before { content: "\f168"; } -.icon-xing-sign:before { +.fa-xing-square:before { content: "\f169"; } -.icon-youtube-play:before { +.fa-youtube-play:before { content: "\f16a"; } -.icon-dropbox:before { +.fa-dropbox:before { content: "\f16b"; } -.icon-stackexchange:before { +.fa-stack-overflow:before { content: "\f16c"; } -.icon-instagram:before { +.fa-instagram:before { content: "\f16d"; } -.icon-flickr:before { +.fa-flickr:before { content: "\f16e"; } -.icon-adn:before { +.fa-adn:before { content: "\f170"; } -.icon-bitbucket:before { +.fa-bitbucket:before { content: "\f171"; } -.icon-bitbucket-sign:before { +.fa-bitbucket-square:before { content: "\f172"; } -.icon-tumblr:before { +.fa-tumblr:before { content: "\f173"; } -.icon-tumblr-sign:before { +.fa-tumblr-square:before { content: "\f174"; } -.icon-long-arrow-down:before { +.fa-long-arrow-down:before { content: "\f175"; } -.icon-long-arrow-up:before { +.fa-long-arrow-up:before { content: "\f176"; } -.icon-long-arrow-left:before { +.fa-long-arrow-left:before { content: "\f177"; } -.icon-long-arrow-right:before { +.fa-long-arrow-right:before { content: "\f178"; } -.icon-apple:before { +.fa-apple:before { content: "\f179"; } -.icon-windows:before { +.fa-windows:before { content: "\f17a"; } -.icon-android:before { +.fa-android:before { content: "\f17b"; } -.icon-linux:before { +.fa-linux:before { content: "\f17c"; } -.icon-dribbble:before { +.fa-dribbble:before { content: "\f17d"; } -.icon-skype:before { +.fa-skype:before { content: "\f17e"; } -.icon-foursquare:before { +.fa-foursquare:before { content: "\f180"; } -.icon-trello:before { +.fa-trello:before { content: "\f181"; } -.icon-female:before { +.fa-female:before { content: "\f182"; } -.icon-male:before { +.fa-male:before { content: "\f183"; } -.icon-gittip:before { +.fa-gittip:before, +.fa-gratipay:before { content: "\f184"; } -.icon-sun:before { +.fa-sun-o:before { content: "\f185"; } -.icon-moon:before { +.fa-moon-o:before { content: "\f186"; } -.icon-archive:before { +.fa-archive:before { content: "\f187"; } -.icon-bug:before { +.fa-bug:before { content: "\f188"; } -.icon-vk:before { +.fa-vk:before { content: "\f189"; } -.icon-weibo:before { +.fa-weibo:before { content: "\f18a"; } -.icon-renren:before { +.fa-renren:before { content: "\f18b"; } +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} +.fa-space-shuttle:before { + content: "\f197"; +} +.fa-slack:before { + content: "\f198"; +} +.fa-envelope-square:before { + content: "\f199"; +} +.fa-wordpress:before { + content: "\f19a"; +} +.fa-openid:before { + content: "\f19b"; +} +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: "\f19c"; +} +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: "\f19d"; +} +.fa-yahoo:before { + content: "\f19e"; +} +.fa-google:before { + content: "\f1a0"; +} +.fa-reddit:before { + content: "\f1a1"; +} +.fa-reddit-square:before { + content: "\f1a2"; +} +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} +.fa-stumbleupon:before { + content: "\f1a4"; +} +.fa-delicious:before { + content: "\f1a5"; +} +.fa-digg:before { + content: "\f1a6"; +} +.fa-pied-piper:before { + content: "\f1a7"; +} +.fa-pied-piper-alt:before { + content: "\f1a8"; +} +.fa-drupal:before { + content: "\f1a9"; +} +.fa-joomla:before { + content: "\f1aa"; +} +.fa-language:before { + content: "\f1ab"; +} +.fa-fax:before { + content: "\f1ac"; +} +.fa-building:before { + content: "\f1ad"; +} +.fa-child:before { + content: "\f1ae"; +} +.fa-paw:before { + content: "\f1b0"; +} +.fa-spoon:before { + content: "\f1b1"; +} +.fa-cube:before { + content: "\f1b2"; +} +.fa-cubes:before { + content: "\f1b3"; +} +.fa-behance:before { + content: "\f1b4"; +} +.fa-behance-square:before { + content: "\f1b5"; +} +.fa-steam:before { + content: "\f1b6"; +} +.fa-steam-square:before { + content: "\f1b7"; +} +.fa-recycle:before { + content: "\f1b8"; +} +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} +.fa-tree:before { + content: "\f1bb"; +} +.fa-spotify:before { + content: "\f1bc"; +} +.fa-deviantart:before { + content: "\f1bd"; +} +.fa-soundcloud:before { + content: "\f1be"; +} +.fa-database:before { + content: "\f1c0"; +} +.fa-file-pdf-o:before { + content: "\f1c1"; +} +.fa-file-word-o:before { + content: "\f1c2"; +} +.fa-file-excel-o:before { + content: "\f1c3"; +} +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: "\f1c5"; +} +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: "\f1c6"; +} +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: "\f1c7"; +} +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} +.fa-file-code-o:before { + content: "\f1c9"; +} +.fa-vine:before { + content: "\f1ca"; +} +.fa-codepen:before { + content: "\f1cb"; +} +.fa-jsfiddle:before { + content: "\f1cc"; +} +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: "\f1cd"; +} +.fa-circle-o-notch:before { + content: "\f1ce"; +} +.fa-ra:before, +.fa-rebel:before { + content: "\f1d0"; +} +.fa-ge:before, +.fa-empire:before { + content: "\f1d1"; +} +.fa-git-square:before { + content: "\f1d2"; +} +.fa-git:before { + content: "\f1d3"; +} +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: "\f1d4"; +} +.fa-tencent-weibo:before { + content: "\f1d5"; +} +.fa-qq:before { + content: "\f1d6"; +} +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} +.fa-send:before, +.fa-paper-plane:before { + content: "\f1d8"; +} +.fa-send-o:before, +.fa-paper-plane-o:before { + content: "\f1d9"; +} +.fa-history:before { + content: "\f1da"; +} +.fa-circle-thin:before { + content: "\f1db"; +} +.fa-header:before { + content: "\f1dc"; +} +.fa-paragraph:before { + content: "\f1dd"; +} +.fa-sliders:before { + content: "\f1de"; +} +.fa-share-alt:before { + content: "\f1e0"; +} +.fa-share-alt-square:before { + content: "\f1e1"; +} +.fa-bomb:before { + content: "\f1e2"; +} +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: "\f1e3"; +} +.fa-tty:before { + content: "\f1e4"; +} +.fa-binoculars:before { + content: "\f1e5"; +} +.fa-plug:before { + content: "\f1e6"; +} +.fa-slideshare:before { + content: "\f1e7"; +} +.fa-twitch:before { + content: "\f1e8"; +} +.fa-yelp:before { + content: "\f1e9"; +} +.fa-newspaper-o:before { + content: "\f1ea"; +} +.fa-wifi:before { + content: "\f1eb"; +} +.fa-calculator:before { + content: "\f1ec"; +} +.fa-paypal:before { + content: "\f1ed"; +} +.fa-google-wallet:before { + content: "\f1ee"; +} +.fa-cc-visa:before { + content: "\f1f0"; +} +.fa-cc-mastercard:before { + content: "\f1f1"; +} +.fa-cc-discover:before { + content: "\f1f2"; +} +.fa-cc-amex:before { + content: "\f1f3"; +} +.fa-cc-paypal:before { + content: "\f1f4"; +} +.fa-cc-stripe:before { + content: "\f1f5"; +} +.fa-bell-slash:before { + content: "\f1f6"; +} +.fa-bell-slash-o:before { + content: "\f1f7"; +} +.fa-trash:before { + content: "\f1f8"; +} +.fa-copyright:before { + content: "\f1f9"; +} +.fa-at:before { + content: "\f1fa"; +} +.fa-eyedropper:before { + content: "\f1fb"; +} +.fa-paint-brush:before { + content: "\f1fc"; +} +.fa-birthday-cake:before { + content: "\f1fd"; +} +.fa-area-chart:before { + content: "\f1fe"; +} +.fa-pie-chart:before { + content: "\f200"; +} +.fa-line-chart:before { + content: "\f201"; +} +.fa-lastfm:before { + content: "\f202"; +} +.fa-lastfm-square:before { + content: "\f203"; +} +.fa-toggle-off:before { + content: "\f204"; +} +.fa-toggle-on:before { + content: "\f205"; +} +.fa-bicycle:before { + content: "\f206"; +} +.fa-bus:before { + content: "\f207"; +} +.fa-ioxhost:before { + content: "\f208"; +} +.fa-angellist:before { + content: "\f209"; +} +.fa-cc:before { + content: "\f20a"; +} +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: "\f20b"; +} +.fa-meanpath:before { + content: "\f20c"; +} +.fa-buysellads:before { + content: "\f20d"; +} +.fa-connectdevelop:before { + content: "\f20e"; +} +.fa-dashcube:before { + content: "\f210"; +} +.fa-forumbee:before { + content: "\f211"; +} +.fa-leanpub:before { + content: "\f212"; +} +.fa-sellsy:before { + content: "\f213"; +} +.fa-shirtsinbulk:before { + content: "\f214"; +} +.fa-simplybuilt:before { + content: "\f215"; +} +.fa-skyatlas:before { + content: "\f216"; +} +.fa-cart-plus:before { + content: "\f217"; +} +.fa-cart-arrow-down:before { + content: "\f218"; +} +.fa-diamond:before { + content: "\f219"; +} +.fa-ship:before { + content: "\f21a"; +} +.fa-user-secret:before { + content: "\f21b"; +} +.fa-motorcycle:before { + content: "\f21c"; +} +.fa-street-view:before { + content: "\f21d"; +} +.fa-heartbeat:before { + content: "\f21e"; +} +.fa-venus:before { + content: "\f221"; +} +.fa-mars:before { + content: "\f222"; +} +.fa-mercury:before { + content: "\f223"; +} +.fa-intersex:before, +.fa-transgender:before { + content: "\f224"; +} +.fa-transgender-alt:before { + content: "\f225"; +} +.fa-venus-double:before { + content: "\f226"; +} +.fa-mars-double:before { + content: "\f227"; +} +.fa-venus-mars:before { + content: "\f228"; +} +.fa-mars-stroke:before { + content: "\f229"; +} +.fa-mars-stroke-v:before { + content: "\f22a"; +} +.fa-mars-stroke-h:before { + content: "\f22b"; +} +.fa-neuter:before { + content: "\f22c"; +} +.fa-genderless:before { + content: "\f22d"; +} +.fa-facebook-official:before { + content: "\f230"; +} +.fa-pinterest-p:before { + content: "\f231"; +} +.fa-whatsapp:before { + content: "\f232"; +} +.fa-server:before { + content: "\f233"; +} +.fa-user-plus:before { + content: "\f234"; +} +.fa-user-times:before { + content: "\f235"; +} +.fa-hotel:before, +.fa-bed:before { + content: "\f236"; +} +.fa-viacoin:before { + content: "\f237"; +} +.fa-train:before { + content: "\f238"; +} +.fa-subway:before { + content: "\f239"; +} +.fa-medium:before { + content: "\f23a"; +} +.fa-yc:before, +.fa-y-combinator:before { + content: "\f23b"; +} +.fa-optin-monster:before { + content: "\f23c"; +} +.fa-opencart:before { + content: "\f23d"; +} +.fa-expeditedssl:before { + content: "\f23e"; +} +.fa-battery-4:before, +.fa-battery-full:before { + content: "\f240"; +} +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} +.fa-battery-2:before, +.fa-battery-half:before { + content: "\f242"; +} +.fa-battery-1:before, +.fa-battery-quarter:before { + content: "\f243"; +} +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} +.fa-mouse-pointer:before { + content: "\f245"; +} +.fa-i-cursor:before { + content: "\f246"; +} +.fa-object-group:before { + content: "\f247"; +} +.fa-object-ungroup:before { + content: "\f248"; +} +.fa-sticky-note:before { + content: "\f249"; +} +.fa-sticky-note-o:before { + content: "\f24a"; +} +.fa-cc-jcb:before { + content: "\f24b"; +} +.fa-cc-diners-club:before { + content: "\f24c"; +} +.fa-clone:before { + content: "\f24d"; +} +.fa-balance-scale:before { + content: "\f24e"; +} +.fa-hourglass-o:before { + content: "\f250"; +} +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} +.fa-hourglass:before { + content: "\f254"; +} +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: "\f255"; +} +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: "\f256"; +} +.fa-hand-scissors-o:before { + content: "\f257"; +} +.fa-hand-lizard-o:before { + content: "\f258"; +} +.fa-hand-spock-o:before { + content: "\f259"; +} +.fa-hand-pointer-o:before { + content: "\f25a"; +} +.fa-hand-peace-o:before { + content: "\f25b"; +} +.fa-trademark:before { + content: "\f25c"; +} +.fa-registered:before { + content: "\f25d"; +} +.fa-creative-commons:before { + content: "\f25e"; +} +.fa-gg:before { + content: "\f260"; +} +.fa-gg-circle:before { + content: "\f261"; +} +.fa-tripadvisor:before { + content: "\f262"; +} +.fa-odnoklassniki:before { + content: "\f263"; +} +.fa-odnoklassniki-square:before { + content: "\f264"; +} +.fa-get-pocket:before { + content: "\f265"; +} +.fa-wikipedia-w:before { + content: "\f266"; +} +.fa-safari:before { + content: "\f267"; +} +.fa-chrome:before { + content: "\f268"; +} +.fa-firefox:before { + content: "\f269"; +} +.fa-opera:before { + content: "\f26a"; +} +.fa-internet-explorer:before { + content: "\f26b"; +} +.fa-tv:before, +.fa-television:before { + content: "\f26c"; +} +.fa-contao:before { + content: "\f26d"; +} +.fa-500px:before { + content: "\f26e"; +} +.fa-amazon:before { + content: "\f270"; +} +.fa-calendar-plus-o:before { + content: "\f271"; +} +.fa-calendar-minus-o:before { + content: "\f272"; +} +.fa-calendar-times-o:before { + content: "\f273"; +} +.fa-calendar-check-o:before { + content: "\f274"; +} +.fa-industry:before { + content: "\f275"; +} +.fa-map-pin:before { + content: "\f276"; +} +.fa-map-signs:before { + content: "\f277"; +} +.fa-map-o:before { + content: "\f278"; +} +.fa-map:before { + content: "\f279"; +} +.fa-commenting:before { + content: "\f27a"; +} +.fa-commenting-o:before { + content: "\f27b"; +} +.fa-houzz:before { + content: "\f27c"; +} +.fa-vimeo:before { + content: "\f27d"; +} +.fa-black-tie:before { + content: "\f27e"; +} +.fa-fonticons:before { + content: "\f280"; +} +.fa-reddit-alien:before { + content: "\f281"; +} +.fa-edge:before { + content: "\f282"; +} +.fa-credit-card-alt:before { + content: "\f283"; +} +.fa-codiepie:before { + content: "\f284"; +} +.fa-modx:before { + content: "\f285"; +} +.fa-fort-awesome:before { + content: "\f286"; +} +.fa-usb:before { + content: "\f287"; +} +.fa-product-hunt:before { + content: "\f288"; +} +.fa-mixcloud:before { + content: "\f289"; +} +.fa-scribd:before { + content: "\f28a"; +} +.fa-pause-circle:before { + content: "\f28b"; +} +.fa-pause-circle-o:before { + content: "\f28c"; +} +.fa-stop-circle:before { + content: "\f28d"; +} +.fa-stop-circle-o:before { + content: "\f28e"; +} +.fa-shopping-bag:before { + content: "\f290"; +} +.fa-shopping-basket:before { + content: "\f291"; +} +.fa-hashtag:before { + content: "\f292"; +} +.fa-bluetooth:before { + content: "\f293"; +} +.fa-bluetooth-b:before { + content: "\f294"; +} +.fa-percent:before { + content: "\f295"; +} diff --git a/templates/project/dashboards/sampletv.erb b/templates/project/dashboards/sampletv.erb index cf4b39c..6f3cb60 100644 --- a/templates/project/dashboards/sampletv.erb +++ b/templates/project/dashboards/sampletv.erb @@ -14,7 +14,7 @@ $(function() {
    • - +
    • @@ -39,7 +39,7 @@ $(function() {
    • - +
    • @@ -48,9 +48,9 @@ $(function() {
    • - +
    Try this: curl -d '{ "auth_token": "YOUR_AUTH_TOKEN", "text": "Hey, Look what I can do!" }' \http://<%=request.host%>:<%=request.port%>/widgets/welcome
    - \ No newline at end of file + diff --git a/templates/project/widgets/number/number.coffee b/templates/project/widgets/number/number.coffee index 645ee7f..0e5950c 100644 --- a/templates/project/widgets/number/number.coffee +++ b/templates/project/widgets/number/number.coffee @@ -13,7 +13,7 @@ class Dashing.Number extends Dashing.Widget @accessor 'arrow', -> if @get('last') - if parseInt(@get('current')) > parseInt(@get('last')) then 'icon-arrow-up' else 'icon-arrow-down' + if parseInt(@get('current')) > parseInt(@get('last')) then 'fa fa-arrow-up' else 'fa fa-arrow-down' onData: (data) -> if data.status -- cgit v1.2.3 From c5bb69091704d5a38cf8c32072b155f3aa556471 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 11 Apr 2016 22:31:31 -0400 Subject: Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4aee91f..fd50c77 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,7 @@ Dashing is a Sinatra based framework that lets you build beautiful dashboards. I [Check out the homepage](http://shopify.github.com/dashing). +Note: Dashing is no longer being actively maintained. Read about it [here](https://github.com/Shopify/dashing/issues/711). + # License Distributed under the [MIT license](MIT-LICENSE) -- cgit v1.2.3 From 0daba0991667537948e3efc263107d469415089b Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 11 Apr 2016 22:41:31 -0400 Subject: Update CONTRIBUTING.md --- CONTRIBUTING.md | 59 ++++----------------------------------------------------- 1 file changed, 4 insertions(+), 55 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5c67793..c900ef6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,67 +1,16 @@ -# Welcome! -Thank you for your interest in Dashing! This exceptionally handsome -framework welcomes all input, but being stylish requires certain -protocols be followed. :bowtie: - -Below you will find a set of guidelines that will ensure the best outcome -for you _and_ Dashing. - ## Have an Issue? -If you run into problems with Dashing, please take these steps before -submitting an issue: + +Dashing is no longer being actively maintained. There are no guarantees that your issue will be looked at. Your best bet is to: 1. Check the [Troubleshooting Guide](https://github.com/Shopify/dashing/wiki#how-tos) in the wiki. 2. Use the [GitHub Issue Search](https://help.github.com/articles/searching-issues/) to check if the issue has already been reported. -3. Submit your issue to our Issue Tracker. Please provide as much helpful information as possible, preferably making use of a [reduced test case](https://www.google.ca/search?#q=reduced%20test%20case). +3. You can ask your issue on the tracker, but your best bet is to go to [Stack Overflow](http://stackoverflow.com/questions/tagged/dashing) -**Support requests should be directed to [Stack Overflow](http://stackoverflow.com/questions/tagged/dashing).** -## Feature Requests -Feature requests are welcome, but take a moment to consider whether your idea -fits with the scope and aim of the project. A good rule of thumb is to apply -the 80/20 rule: every feature should be useful to at least 80% of users. Adding -in every possible edge case will only make it more difficult to understand, maintain, -and hack on. -If you feel that you have a really amazing, super neato idea that doesn't -quite fit with the core use of Dashing, it may be a good candidate for an -external Gem which supercharges a project. An excellent example of this is +Dashing is no longer being actively maintained. If you feel that you have a really amazing, super neato idea that should be a part of Dashing, it may be a good candidate for an external Gem which supercharges a project. An excellent example of this is [dashing-contrib](https://github.com/QubitProducts/dashing-contrib). If you do create a third-party extension for Dashing, please add it [here](https://github.com/Shopify/dashing/wiki/Additional-Widgets#other-third-party-tools). - -## Pull Requests - -Patches, improvements and new features are a fantastic -help -- thank you! - -**Please ask first** before embarking on any significant pull request (e.g. -implementing features, refactoring code, porting to a different language), -otherwise you risk spending a lot of time working on something that may -not be merged into the project. - -Please adhere to the coding conventions used throughout a project (indentation, -accurate comments, etc.) and any other requirements (such as test coverage). -All code submitted via Pull Request will be dicussed and critiqued in a -respectful manner. - -GitHub has [excellent documentation on how to use Pull Requests.](https://help.github.com/articles/using-pull-requests/) - - -## Git Commit Message Suggestions -* Consider starting the commit message with an applicable emoji: - * :art: `:art:` when improving the format/structure of the code - * :moyai: `:moyai:` when adding a new feature - * :wrench: `:wrench:` when dealing with the toolchain (Git, Travis, etc) - * :notebook: `:notebook` when dealing with docs - * :racehorse: `:racehorse:` when improving performance - * :penguin: `:penguin:` when fixing something on Linux - * :apple: `:apple:` when fixing something on Mac OS - * :bug: `:bug:` when fixing a bug - * :bomb: `:bomb:` when removing code or files - * :white_check_mark: `:white_check_mark:` when adding tests - * :lock: `:lock:` when dealing with security - * :arrow_up: `:arrow_up:` when upgrading dependencies - * :arrow_down: `:arrow_down:` when downgrading dependencies -- cgit v1.2.3 From 8b634d195f778f5f079b11bccc4c9a4e5f6096a7 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 11 Apr 2016 22:41:57 -0400 Subject: Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c900ef6..502e157 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ ## Have an Issue? -Dashing is no longer being actively maintained. There are no guarantees that your issue will be looked at. Your best bet is to: +Dashing is no longer being actively maintained. 1. Check the [Troubleshooting Guide](https://github.com/Shopify/dashing/wiki#how-tos) in the wiki. 2. Use the [GitHub Issue Search](https://help.github.com/articles/searching-issues/) to check if the issue has already been reported. -- cgit v1.2.3 From 4a4b677b1f0a8cd8854e9078345c31a57eb58944 Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 11 Apr 2016 22:42:09 -0400 Subject: Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 502e157..6b22e83 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ Dashing is no longer being actively maintained. -Dashing is no longer being actively maintained. If you feel that you have a really amazing, super neato idea that should be a part of Dashing, it may be a good candidate for an external Gem which supercharges a project. An excellent example of this is +If you feel that you have a really amazing, super neato idea that should be a part of Dashing, it may be a good candidate for an external Gem which supercharges a project. An excellent example of this is [dashing-contrib](https://github.com/QubitProducts/dashing-contrib). If you do create a third-party extension for Dashing, please add it [here](https://github.com/Shopify/dashing/wiki/Additional-Widgets#other-third-party-tools). -- cgit v1.2.3 From 1d33b6fc4ad85fffd5b85ea9b8be1c5327581bac Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 11 Apr 2016 23:10:31 -0400 Subject: Bump gem spec to latest version. --- dashing.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dashing.gemspec b/dashing.gemspec index 33b5b17..52a1f3e 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,8 +2,8 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.3.4' - s.date = '2014-05-30' + s.version = '1.3.5' + s.date = '2015-04-11' s.executables = %w(dashing) -- cgit v1.2.3 From ed5463dce052852a5ace2d11a0265fff2244e60e Mon Sep 17 00:00:00 2001 From: Daniel Beauchamp Date: Mon, 11 Apr 2016 23:19:28 -0400 Subject: Update to latest version. --- dashing.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dashing.gemspec b/dashing.gemspec index 52a1f3e..a526d20 100644 --- a/dashing.gemspec +++ b/dashing.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = 'dashing' - s.version = '1.3.5' + s.version = '1.3.6' s.date = '2015-04-11' s.executables = %w(dashing) -- cgit v1.2.3