diff --git a/assets_helper.py b/assets_helper.py index 681362cc0..dec694f1d 100644 --- a/assets_helper.py +++ b/assets_helper.py @@ -28,7 +28,7 @@ def is_active(asset, at_time=None): if asset['is_enabled'] and asset['start_date'] and asset['end_date']: at = at_time or get_time() - return asset['start_date'] < at and asset['end_date'] > at + return asset['start_date'] <= at <= asset['end_date'] return False diff --git a/static/coffee/specs/screenly-spec.coffee b/static/coffee/specs/screenly-spec.coffee index f2f0efcb1..a37e7dc43 100644 --- a/static/coffee/specs/screenly-spec.coffee +++ b/static/coffee/specs/screenly-spec.coffee @@ -1,76 +1,113 @@ describe "Screenly Open Source", -> - it "should have a screenly object at its root", -> - expect(screenly).toBeDefined() - - it "should have an instance of Assets on the screenly object", -> - expect(screenly.Assets).toBeDefined() - expect(screenly.Assets).toEqual jasmine.any(screenly.collections.Assets) - expect(screenly.ActiveAssets).toEqual jasmine.any(screenly.collections.ActiveAssets) - expect(screenly.InactiveAssets).toEqual jasmine.any(screenly.collections.InactiveAssets) - - describe "Models", -> - - it "should exist", -> - expect(screenly.models).toBeDefined() + it "should have a Screenly object at its root", -> + expect(Screenly).toBeDefined() - describe "Asset model", -> - it "should exist", -> - expect(screenly.models.Asset).toBeDefined() - describe "Collections", -> + describe "date_to", -> - it "should exist", -> - expect(screenly.collections).toBeDefined() + test_date = new Date(2014, 5, 6, 14, 20, 0, 0); + a_date = Screenly.date_to(test_date); - describe "Assets", -> - it "should exist", -> - expect(screenly.collections.Assets).toBeDefined() - expect(screenly.collections.ActiveAssets).toBeDefined() - expect(screenly.collections.InactiveAssets).toBeDefined() + it "should format date and time as 'MM/DD/YYYY hh:mm:ss A'", -> + expect(a_date.string()).toBe '06/06/2014 02:20:00 PM' + + it "should format date as 'MM/a_date/YYYY'", -> + expect(a_date.date()).toBe '06/06/2014' + + it "should format date as 'hh:mm:ss A'", -> + expect(a_date.time()).toBe '02:20 PM' - it "should use the Asset model", -> - assets = new screenly.collections.Assets() - expect(assets.model).toBe screenly.models.Asset - it "should populate ActiveAssets and InactiveAssets when fetched", -> - screenly.Assets.reset [ - {name: "zacharytamas.com", mimetype:"webpage", is_active: true}, - ] + describe "Models", -> - # ActiveAssets should have one model now - expect(screenly.ActiveAssets.models.length).toEqual 1 + describe "Asset model", -> + it "should exist", -> + expect(Screenly.Asset).toBeDefined() + + start_date = new Date(2014, 4, 6, 14, 20, 0, 0); + end_date = new Date(); + end_date.setMonth(end_date.getMonth() + 2) + asset = new Screenly.Asset({ + asset_id: 2 + duration: "8" + end_date: end_date + is_enabled: true + mimetype: 'webpage' + name: 'Test' + start_date: start_date + uri: 'http://www.screenlyapp.com' + }) + + it "should be active if enabled and date is in range", -> + expect(asset.active()).toBe true + + it "should be inactive if disabled and date is in range", -> + asset.set 'is_enabled', false + expect(asset.active()).toBe false + + it "should be inactive if enabled and date is out of range", -> + asset.set 'is_enabled', true + asset.set 'start_date', asset.get 'end_date' + expect(asset.active()).toBe false + + it "should rollback to backup data if it exists", -> + + asset.set 'start_date', start_date + asset.set 'end_date', end_date + asset.backup() + + asset.set({ + is_enabled: false + name: "Test 2" + start_date: new Date(2011, 4, 6, 14, 20, 0, 0) + end_date: new Date(2011, 4, 6, 14, 20, 0, 0) + uri: "http://www.wireload.net" + }) + + asset.rollback() + + expect(asset.get 'is_enabled').toBe true + expect(asset.get 'name').toBe 'Test' + expect(asset.get 'start_date').toBe start_date + expect(asset.get 'uri').toBe "http://www.screenlyapp.com" + + it "should erase backup date after rollback", -> + asset.set({ + is_enabled: false + name: "Test 2" + start_date: new Date(2011, 4, 6, 14, 20, 0, 0) + end_date: new Date(2011, 4, 6, 14, 20, 0, 0) + uri: "http://www.wireload.net" + }) + + asset.rollback() + + expect(asset.get 'is_enabled').toBe false + expect(asset.get 'name').toBe 'Test 2' + expect(asset.get('start_date').toISOString()).toBe (new Date(2011, 4, 6, 14, 20, 0, 0)).toISOString() + expect(asset.get 'uri').toBe "http://www.wireload.net" - # InactiveAssets should still be empty - expect(screenly.InactiveAssets.models.length).toEqual 0 - # Now make the page inactive and confirm that ActiveAssets - # is empty (the previous information is wiped away on a - # new data load) and the InactiveAssets collection contains - # the new asset. + describe "Collections", -> - screenly.Assets.reset [ - {name: "zacharytamas.com", mimetype:"webpage", is_active: false}, - ] + describe "Assets", -> + it "should exist", -> + expect(Screenly.Assets).toBeDefined() - # ActiveAssets should be empty now - expect(screenly.ActiveAssets.models.length).toEqual 0 + it "should use the Asset model", -> + assets = new Screenly.Assets() + expect(assets.model).toBe Screenly.Asset - # InactiveAssets should have a model - expect(screenly.InactiveAssets.models.length).toEqual 1 - screenly.Assets.reset [ - {name: "zacharytamas.com", mimetype:"webpage", is_active: false}, - {name: "Hacker News", mimetype: "webpage", is_active: true} - ] + describe "Views", -> - # They should both have a model now - expect(screenly.ActiveAssets.models.length).toEqual 1 - expect(screenly.InactiveAssets.models.length).toEqual 1 - expect(screenly.Assets.models.length).toEqual 2 + it "should have EditAssetView", -> + expect(Screenly.View.EditAssetView).toBeDefined() - describe "Views", -> + it "should have AssetRowView", -> + expect(Screenly.View.AssetRowView).toBeDefined() - it "should exist", -> - expect(screenly.views).toBeDefined() + it "should have AssetsView", -> + expect(Screenly.View.AssetsView).toBeDefined() \ No newline at end of file diff --git a/static/js/main.js b/static/js/main.js new file mode 100644 index 000000000..fd5dbaedf --- /dev/null +++ b/static/js/main.js @@ -0,0 +1,5 @@ +jQuery(function() { + Screenly.app = new Screenly.App({ + el: $('body') + }); +}); diff --git a/static/js/screenly-ose.coffee b/static/js/screenly-ose.coffee index ccee8244e..a8115da1c 100644 --- a/static/js/screenly-ose.coffee +++ b/static/js/screenly-ose.coffee @@ -34,11 +34,29 @@ API.Asset = class Asset extends Backbone.Model name: '' mimetype: 'webpage' uri: '' + is_active: false start_date: now() end_date: (moment().add 'days', 7).toDate() duration: default_duration is_enabled: 0 nocache: 0 + active: => + if @get('is_enabled') and @get('start_date') and @get('end_date') + at = now() + start_date = new Date(@get('start_date')); + end_date = new Date(@get('end_date')); + return start_date <= at <= end_date + else + return false + + backup: => + @backup_attributes = @toJSON() + + rollback: => + if @backup_attributes + @set @backup_attributes + @backup_attributes = undefined + API.Assets = class Assets extends Backbone.Collection url: "/api/assets" @@ -46,7 +64,8 @@ API.Assets = class Assets extends Backbone.Collection # Views -class EditAssetView extends Backbone.View +API.View = {}; +API.View.EditAssetView = class EditAssetView extends Backbone.View $f: (field) => @$ "[name='#{field}']" # get field element $fv: (field, val...) => (@$f field).val val... # get or set filed value @@ -59,7 +78,11 @@ class EditAssetView extends Backbone.View (@$ 'input[name="nocache"]').prop 'checked', @model.get 'nocache' (@$ '.modal-header .close').remove() (@$el.children ":first").modal() + + @model.backup() + @model.bind 'change', @render + @render() @validate() _.delay (=> (@$f 'uri').focus()), 300 @@ -179,7 +202,7 @@ class EditAssetView extends Backbone.View cancel: (e) => - @model.set @model.previousAttributes() + @model.rollback() unless @edit then @model.destroy() (@$el.children ":first").modal 'hide' @@ -224,7 +247,7 @@ class EditAssetView extends Backbone.View (@$ '.advanced-accordion').toggle has_nocache is on -class AssetRowView extends Backbone.View +API.View.AssetRowView = class AssetRowView extends Backbone.View tagName: "tr" initialize: (options) => @@ -296,7 +319,7 @@ class AssetRowView extends Backbone.View no -class AssetsView extends Backbone.View +API.View.AssetsView = class AssetsView extends Backbone.View initialize: (options) => @collection.bind event, @render for event in ('reset add remove sync'.split ' ') @sorted = (@$ '#active-assets').sortable @@ -312,7 +335,7 @@ class AssetsView extends Backbone.View (@$ "##{which}-assets").html '' for which in ['active', 'inactive'] @collection.each (model) => - which = if model.get 'is_active' then 'active' else 'inactive' + which = if model.active() then 'active' else 'inactive' (@$ "##{which}-assets").append (new AssetRowView model: model).render() for which in ['inactive', 'active'] @@ -347,6 +370,3 @@ API.App = class App extends Backbone.View new Asset {}, {collection: API.assets} no - -jQuery -> API.app = new App el: $ 'body' - diff --git a/static/js/screenly-ose.js b/static/js/screenly-ose.js index 8320ce930..7df11ff15 100644 --- a/static/js/screenly-ose.js +++ b/static/js/screenly-ose.js @@ -1,14 +1,11 @@ -//@ sourceMappingURL=screenly-ose.map -// Generated by CoffeeScript 1.6.1 - -/* screenly-ose ui -*/ +// Generated by CoffeeScript 1.7.1 +/* screenly-ose ui */ (function() { var API, App, Asset, AssetRowView, Assets, AssetsView, EditAssetView, date_to, delay, get_filename, get_mimetype, get_template, insertWbr, mimetypes, now, url_test, - _this = this, __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; }, + __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; @@ -45,18 +42,20 @@ mimetypes = [['jpg jpeg png pnm gif bmp'.split(' '), 'image'], ['avi mkv mov mpg mpeg mp4 ts flv'.split(' '), 'video']]; - get_mimetype = function(filename) { - var ext, mt; - ext = (_.last(filename.split('.'))).toLowerCase(); - mt = _.find(mimetypes, function(mt) { - return __indexOf.call(mt[0], ext) >= 0; - }); - if (mt) { - return mt[1]; - } else { - return null; - } - }; + get_mimetype = (function(_this) { + return function(filename) { + var ext, mt; + ext = (_.last(filename.split('.'))).toLowerCase(); + mt = _.find(mimetypes, function(mt) { + return __indexOf.call(mt[0], ext) >= 0; + }); + if (mt) { + return mt[1]; + } else { + return null; + } + }; + })(this); url_test = function(v) { return /(http|https):\/\/[\w-]+(\.?[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/.test(v); @@ -73,14 +72,13 @@ Backbone.emulateJSON = true; API.Asset = Asset = (function(_super) { - __extends(Asset, _super); function Asset() { - var _this = this; - this.defaults = function() { - return Asset.prototype.defaults.apply(_this, arguments); - }; + this.rollback = __bind(this.rollback, this); + this.backup = __bind(this.backup, this); + this.active = __bind(this.active, this); + this.defaults = __bind(this.defaults, this); return Asset.__super__.constructor.apply(this, arguments); } @@ -93,6 +91,7 @@ name: '', mimetype: 'webpage', uri: '', + is_active: false, start_date: now(), end_date: (moment().add('days', 7)).toDate(), duration: default_duration, @@ -101,12 +100,34 @@ }; }; + Asset.prototype.active = function() { + var at, end_date, start_date; + if (this.get('is_enabled') && this.get('start_date') && this.get('end_date')) { + at = now(); + start_date = new Date(this.get('start_date')); + end_date = new Date(this.get('end_date')); + return (start_date <= at && at <= end_date); + } else { + return false; + } + }; + + Asset.prototype.backup = function() { + return this.backup_attributes = this.toJSON(); + }; + + Asset.prototype.rollback = function() { + if (this.backup_attributes) { + this.set(this.backup_attributes); + return this.backup_attributes = void 0; + } + }; + return Asset; })(Backbone.Model); API.Assets = Assets = (function(_super) { - __extends(Assets, _super); function Assets() { @@ -121,62 +142,28 @@ })(Backbone.Collection); - EditAssetView = (function(_super) { + API.View = {}; + API.View.EditAssetView = EditAssetView = (function(_super) { __extends(EditAssetView, _super); function EditAssetView() { - var _this = this; - this.displayAdvanced = function() { - return EditAssetView.prototype.displayAdvanced.apply(_this, arguments); - }; - this.toggleAdvanced = function() { - return EditAssetView.prototype.toggleAdvanced.apply(_this, arguments); - }; - this.updateMimetype = function(filename) { - return EditAssetView.prototype.updateMimetype.apply(_this, arguments); - }; - this.updateFileUploadMimetype = function() { - return EditAssetView.prototype.updateFileUploadMimetype.apply(_this, arguments); - }; - this.updateUriMimetype = function() { - return EditAssetView.prototype.updateUriMimetype.apply(_this, arguments); - }; - this.clickTabNavUpload = function(e) { - return EditAssetView.prototype.clickTabNavUpload.apply(_this, arguments); - }; - this.clickTabNavUri = function(e) { - return EditAssetView.prototype.clickTabNavUri.apply(_this, arguments); - }; - this.cancel = function(e) { - return EditAssetView.prototype.cancel.apply(_this, arguments); - }; - this.validate = function(e) { - return EditAssetView.prototype.validate.apply(_this, arguments); - }; - this.change = function(e) { - return EditAssetView.prototype.change.apply(_this, arguments); - }; - this.save = function(e) { - return EditAssetView.prototype.save.apply(_this, arguments); - }; - this.viewmodel = function() { - return EditAssetView.prototype.viewmodel.apply(_this, arguments); - }; - this.render = function() { - return EditAssetView.prototype.render.apply(_this, arguments); - }; - this.initialize = function(options) { - return EditAssetView.prototype.initialize.apply(_this, arguments); - }; - this.$fv = function() { - var field, val; - field = arguments[0], val = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - return EditAssetView.prototype.$fv.apply(_this, arguments); - }; - this.$f = function(field) { - return EditAssetView.prototype.$f.apply(_this, arguments); - }; + this.displayAdvanced = __bind(this.displayAdvanced, this); + this.toggleAdvanced = __bind(this.toggleAdvanced, this); + this.updateMimetype = __bind(this.updateMimetype, this); + this.updateFileUploadMimetype = __bind(this.updateFileUploadMimetype, this); + this.updateUriMimetype = __bind(this.updateUriMimetype, this); + this.clickTabNavUpload = __bind(this.clickTabNavUpload, this); + this.clickTabNavUri = __bind(this.clickTabNavUri, this); + this.cancel = __bind(this.cancel, this); + this.validate = __bind(this.validate, this); + this.change = __bind(this.change, this); + this.save = __bind(this.save, this); + this.viewmodel = __bind(this.viewmodel, this); + this.render = __bind(this.render, this); + this.initialize = __bind(this.initialize, this); + this.$fv = __bind(this.$fv, this); + this.$f = __bind(this.$f, this); return EditAssetView.__super__.constructor.apply(this, arguments); } @@ -191,7 +178,6 @@ }; EditAssetView.prototype.initialize = function(options) { - var _this = this; this.edit = options.edit; ($('body')).append(this.$el.html(get_template('asset-modal'))); (this.$('input.time')).timepicker({ @@ -203,12 +189,15 @@ (this.$('input[name="nocache"]')).prop('checked', this.model.get('nocache')); (this.$('.modal-header .close')).remove(); (this.$el.children(":first")).modal(); + this.model.backup(); this.model.bind('change', this.render); this.render(); this.validate(); - _.delay((function() { - return (_this.$f('uri')).focus(); - }), 300); + _.delay(((function(_this) { + return function() { + return (_this.$f('uri')).focus(); + }; + })(this)), 300); return false; }; @@ -287,8 +276,7 @@ }; EditAssetView.prototype.save = function(e) { - var save, - _this = this; + var save; e.preventDefault(); this.viewmodel(); save = null; @@ -300,11 +288,13 @@ (this.$('.progress')).show(); this.$el.fileupload({ url: this.model.url(), - progressall: function(e, data) { - if (data.loaded && data.total) { - return (_this.$('.progress .bar')).css('width', "" + (data.loaded / data.total * 100) + "%"); - } - } + progressall: (function(_this) { + return function(e, data) { + if (data.loaded && data.total) { + return (_this.$('.progress .bar')).css('width', "" + (data.loaded / data.total * 100) + "%"); + } + }; + })(this) }); save = this.$el.fileupload('send', { fileInput: this.$f('file_upload') @@ -328,60 +318,72 @@ save = this.model.save(); } (this.$('input, select')).prop('disabled', true); - save.done(function(data) { - _this.model.id = data.asset_id; - if (!_this.model.collection) { - _this.collection.add(_this.model); - } - (_this.$el.children(":first")).modal('hide'); - _.extend(_this.model.attributes, data); - if (!_this.edit) { - return _this.model.collection.add(_this.model); - } - }); - save.fail(function() { - (_this.$('.progress')).hide(); - return (_this.$('input, select')).prop('disabled', false); - }); + save.done((function(_this) { + return function(data) { + _this.model.id = data.asset_id; + if (!_this.model.collection) { + _this.collection.add(_this.model); + } + (_this.$el.children(":first")).modal('hide'); + _.extend(_this.model.attributes, data); + if (!_this.edit) { + return _this.model.collection.add(_this.model); + } + }; + })(this)); + save.fail((function(_this) { + return function() { + (_this.$('.progress')).hide(); + return (_this.$('input, select')).prop('disabled', false); + }; + })(this)); return false; }; EditAssetView.prototype.change = function(e) { - var _this = this; - this._change || (this._change = _.throttle((function() { - _this.viewmodel(); - _this.model.trigger('change'); - _this.validate(); - return true; - }), 500)); + this._change || (this._change = _.throttle(((function(_this) { + return function() { + _this.viewmodel(); + _this.model.trigger('change'); + _this.validate(); + return true; + }; + })(this)), 500)); return this._change.apply(this, arguments); }; EditAssetView.prototype.validate = function(e) { - var errors, field, fn, that, v, validators, _i, _len, _ref, _results, - _this = this; + var errors, field, fn, that, v, validators, _i, _len, _ref, _results; that = this; validators = { - duration: function(v) { - if (('video' !== _this.model.get('mimetype')) && (!(_.isNumber(v * 1)) || v * 1 < 1)) { - return 'please enter a valid number'; - } - }, - uri: function(v) { - if (_this.model.isNew() && ((that.$('#tab-uri')).hasClass('active')) && !url_test(v)) { - return 'please enter a valid URL'; - } - }, - file_upload: function(v) { - if (_this.model.isNew() && !v && !(that.$('#tab-uri')).hasClass('active')) { - return 'please select a file'; - } - }, - end_date: function(v) { - if (!((new Date(_this.$fv('start_date'))) < (new Date(_this.$fv('end_date'))))) { - return 'end date should be after start date'; - } - } + duration: (function(_this) { + return function(v) { + if (('video' !== _this.model.get('mimetype')) && (!(_.isNumber(v * 1)) || v * 1 < 1)) { + return 'please enter a valid number'; + } + }; + })(this), + uri: (function(_this) { + return function(v) { + if (_this.model.isNew() && ((that.$('#tab-uri')).hasClass('active')) && !url_test(v)) { + return 'please enter a valid URL'; + } + }; + })(this), + file_upload: (function(_this) { + return function(v) { + if (_this.model.isNew() && !v && !(that.$('#tab-uri')).hasClass('active')) { + return 'please select a file'; + } + }; + })(this), + end_date: (function(_this) { + return function(v) { + if (!((new Date(_this.$fv('start_date'))) < (new Date(_this.$fv('end_date'))))) { + return 'end date should be after start date'; + } + }; + })(this) }; errors = (function() { var _results; @@ -408,7 +410,7 @@ }; EditAssetView.prototype.cancel = function(e) { - this.model.set(this.model.previousAttributes()); + this.model.rollback(); if (!this.edit) { this.model.destroy(); } @@ -442,17 +444,19 @@ }; EditAssetView.prototype.updateUriMimetype = function() { - var _this = this; - return _.defer(function() { - return _this.updateMimetype(_this.$fv('uri')); - }); + return _.defer((function(_this) { + return function() { + return _this.updateMimetype(_this.$fv('uri')); + }; + })(this)); }; EditAssetView.prototype.updateFileUploadMimetype = function() { - var _this = this; - return _.defer(function() { - return _this.updateMimetype(_this.$fv('file_upload')); - }); + return _.defer((function(_this) { + return function() { + return _this.updateMimetype(_this.$fv('file_upload')); + }; + })(this)); }; EditAssetView.prototype.updateMimetype = function(filename) { @@ -483,36 +487,18 @@ })(Backbone.View); - AssetRowView = (function(_super) { - + API.View.AssetRowView = AssetRowView = (function(_super) { __extends(AssetRowView, _super); function AssetRowView() { - var _this = this; - this.hidePopover = function() { - return AssetRowView.prototype.hidePopover.apply(_this, arguments); - }; - this.showPopover = function() { - return AssetRowView.prototype.showPopover.apply(_this, arguments); - }; - this["delete"] = function(e) { - return AssetRowView.prototype.delete.apply(_this, arguments); - }; - this.edit = function(e) { - return AssetRowView.prototype.edit.apply(_this, arguments); - }; - this.setEnabled = function(enabled) { - return AssetRowView.prototype.setEnabled.apply(_this, arguments); - }; - this.toggleIsEnabled = function(e) { - return AssetRowView.prototype.toggleIsEnabled.apply(_this, arguments); - }; - this.render = function() { - return AssetRowView.prototype.render.apply(_this, arguments); - }; - this.initialize = function(options) { - return AssetRowView.prototype.initialize.apply(_this, arguments); - }; + this.hidePopover = __bind(this.hidePopover, this); + this.showPopover = __bind(this.showPopover, this); + this["delete"] = __bind(this["delete"], this); + this.edit = __bind(this.edit, this); + this.setEnabled = __bind(this.setEnabled, this); + this.toggleIsEnabled = __bind(this.toggleIsEnabled, this); + this.render = __bind(this.render, this); + this.initialize = __bind(this.initialize, this); return AssetRowView.__super__.constructor.apply(this, arguments); } @@ -556,24 +542,27 @@ }; AssetRowView.prototype.toggleIsEnabled = function(e) { - var save, val, - _this = this; + var save, val; val = (1 + this.model.get('is_enabled')) % 2; this.model.set({ is_enabled: val }); this.setEnabled(false); save = this.model.save(); - save.done(function() { - return _this.setEnabled(true); - }); - save.fail(function() { - _this.model.set(_this.model.previousAttributes(), { - silent: true - }); - _this.setEnabled(true); - return _this.render(); - }); + save.done((function(_this) { + return function() { + return _this.setEnabled(true); + }; + })(this)); + save.fail((function(_this) { + return function() { + _this.model.set(_this.model.previousAttributes(), { + silent: true + }); + _this.setEnabled(true); + return _this.render(); + }; + })(this)); return true; }; @@ -599,13 +588,14 @@ }; AssetRowView.prototype["delete"] = function(e) { - var xhr, - _this = this; + var xhr; this.hidePopover(); if ((xhr = this.model.destroy()) === !false) { - xhr.done(function() { - return _this.remove(); - }); + xhr.done((function(_this) { + return function() { + return _this.remove(); + }; + })(this)); } else { this.remove(); } @@ -630,21 +620,13 @@ })(Backbone.View); - AssetsView = (function(_super) { - + API.View.AssetsView = AssetsView = (function(_super) { __extends(AssetsView, _super); function AssetsView() { - var _this = this; - this.render = function() { - return AssetsView.prototype.render.apply(_this, arguments); - }; - this.update_order = function() { - return AssetsView.prototype.update_order.apply(_this, arguments); - }; - this.initialize = function(options) { - return AssetsView.prototype.initialize.apply(_this, arguments); - }; + this.render = __bind(this.render, this); + this.update_order = __bind(this.update_order, this); + this.initialize = __bind(this.initialize, this); return AssetsView.__super__.constructor.apply(this, arguments); } @@ -670,19 +652,20 @@ }; AssetsView.prototype.render = function() { - var which, _i, _j, _len, _len1, _ref, _ref1, - _this = this; + var which, _i, _j, _len, _len1, _ref, _ref1; _ref = ['active', 'inactive']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { which = _ref[_i]; (this.$("#" + which + "-assets")).html(''); } - this.collection.each(function(model) { - which = model.get('is_active') ? 'active' : 'inactive'; - return (_this.$("#" + which + "-assets")).append((new AssetRowView({ - model: model - })).render()); - }); + this.collection.each((function(_this) { + return function(model) { + which = model.active() ? 'active' : 'inactive'; + return (_this.$("#" + which + "-assets")).append((new AssetRowView({ + model: model + })).render()); + }; + })(this)); _ref1 = ['inactive', 'active']; for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { which = _ref1[_j]; @@ -702,32 +685,29 @@ })(Backbone.View); API.App = App = (function(_super) { - __extends(App, _super); function App() { - var _this = this; - this.add = function(e) { - return App.prototype.add.apply(_this, arguments); - }; - this.initialize = function() { - return App.prototype.initialize.apply(_this, arguments); - }; + this.add = __bind(this.add, this); + this.initialize = __bind(this.initialize, this); return App.__super__.constructor.apply(this, arguments); } App.prototype.initialize = function() { - var _this = this; - ($(window)).ajaxError(function(e, r) { - var err, j; - ($('#request-error')).html((get_template('request-error'))()); - if ((j = $.parseJSON(r.responseText)) && (err = j.error)) { - return ($('#request-error .msg')).text('Server Error: ' + err); - } - }); - ($(window)).ajaxSuccess(function(data) { - return ($('#request-error')).html(''); - }); + ($(window)).ajaxError((function(_this) { + return function(e, r) { + var err, j; + ($('#request-error')).html((get_template('request-error'))()); + if ((j = $.parseJSON(r.responseText)) && (err = j.error)) { + return ($('#request-error .msg')).text('Server Error: ' + err); + } + }; + })(this)); + ($(window)).ajaxSuccess((function(_this) { + return function(data) { + return ($('#request-error')).html(''); + }; + })(this)); (API.assets = new Assets()).fetch(); return API.assetsView = new AssetsView({ collection: API.assets, @@ -752,10 +732,4 @@ })(Backbone.View); - jQuery(function() { - return API.app = new App({ - el: $('body') - }); - }); - }).call(this); diff --git a/static/spec/runner.html b/static/spec/runner.html index 6384f6f9d..fd24f13e0 100644 --- a/static/spec/runner.html +++ b/static/spec/runner.html @@ -8,9 +8,18 @@ + + - + + + + + + diff --git a/static/spec/screenly-spec.js b/static/spec/screenly-spec.js index 65ec9eed8..ef3c9956f 100644 --- a/static/spec/screenly-spec.js +++ b/static/spec/screenly-spec.js @@ -1,2 +1,110 @@ -// Generated by CoffeeScript 1.4.0 -(function(){describe("Screenly Open Source",function(){it("should have a screenly object at its root",function(){return expect(screenly).toBeDefined()});it("should have an instance of Assets on the screenly object",function(){expect(screenly.Assets).toBeDefined();expect(screenly.Assets).toEqual(jasmine.any(screenly.collections.Assets));expect(screenly.ActiveAssets).toEqual(jasmine.any(screenly.collections.ActiveAssets));return expect(screenly.InactiveAssets).toEqual(jasmine.any(screenly.collections.InactiveAssets))});describe("Models",function(){it("should exist",function(){return expect(screenly.models).toBeDefined()});return describe("Asset model",function(){return it("should exist",function(){return expect(screenly.models.Asset).toBeDefined()})})});describe("Collections",function(){it("should exist",function(){return expect(screenly.collections).toBeDefined()});return describe("Assets",function(){it("should exist",function(){expect(screenly.collections.Assets).toBeDefined();expect(screenly.collections.ActiveAssets).toBeDefined();return expect(screenly.collections.InactiveAssets).toBeDefined()});it("should use the Asset model",function(){var e;e=new screenly.collections.Assets;return expect(e.model).toBe(screenly.models.Asset)});return it("should populate ActiveAssets and InactiveAssets when fetched",function(){screenly.Assets.reset([{name:"zacharytamas.com",mimetype:"webpage",is_active:!0}]);expect(screenly.ActiveAssets.models.length).toEqual(1);expect(screenly.InactiveAssets.models.length).toEqual(0);screenly.Assets.reset([{name:"zacharytamas.com",mimetype:"webpage",is_active:!1}]);expect(screenly.ActiveAssets.models.length).toEqual(0);expect(screenly.InactiveAssets.models.length).toEqual(1);screenly.Assets.reset([{name:"zacharytamas.com",mimetype:"webpage",is_active:!1},{name:"Hacker News",mimetype:"webpage",is_active:!0}]);expect(screenly.ActiveAssets.models.length).toEqual(1);expect(screenly.InactiveAssets.models.length).toEqual(1);return expect(screenly.Assets.models.length).toEqual(2)})})});return describe("Views",function(){return it("should exist",function(){return expect(screenly.views).toBeDefined()})})})}).call(this); \ No newline at end of file +// Generated by CoffeeScript 1.7.1 +(function() { + describe("Screenly Open Source", function() { + it("should have a Screenly object at its root", function() { + return expect(Screenly).toBeDefined(); + }); + describe("date_to", function() { + var a_date, test_date; + test_date = new Date(2014, 5, 6, 14, 20, 0, 0); + a_date = Screenly.date_to(test_date); + it("should format date and time as 'MM/DD/YYYY hh:mm:ss A'", function() { + return expect(a_date.string()).toBe('06/06/2014 02:20:00 PM'); + }); + it("should format date as 'MM/a_date/YYYY'", function() { + return expect(a_date.date()).toBe('06/06/2014'); + }); + return it("should format date as 'hh:mm:ss A'", function() { + return expect(a_date.time()).toBe('02:20 PM'); + }); + }); + describe("Models", function() { + return describe("Asset model", function() { + var asset, end_date, start_date; + it("should exist", function() { + return expect(Screenly.Asset).toBeDefined(); + }); + start_date = new Date(2014, 4, 6, 14, 20, 0, 0); + end_date = new Date(); + end_date.setMonth(end_date.getMonth() + 2); + asset = new Screenly.Asset({ + asset_id: 2, + duration: "8", + end_date: end_date, + is_enabled: true, + mimetype: 'webpage', + name: 'Test', + start_date: start_date, + uri: 'http://www.screenlyapp.com' + }); + it("should be active if enabled and date is in range", function() { + return expect(asset.active()).toBe(true); + }); + it("should be inactive if disabled and date is in range", function() { + asset.set('is_enabled', false); + return expect(asset.active()).toBe(false); + }); + it("should be inactive if enabled and date is out of range", function() { + asset.set('is_enabled', true); + asset.set('start_date', asset.get('end_date')); + return expect(asset.active()).toBe(false); + }); + it("should rollback to backup data if it exists", function() { + asset.set('start_date', start_date); + asset.set('end_date', end_date); + asset.backup(); + asset.set({ + is_enabled: false, + name: "Test 2", + start_date: new Date(2011, 4, 6, 14, 20, 0, 0), + end_date: new Date(2011, 4, 6, 14, 20, 0, 0), + uri: "http://www.wireload.net" + }); + asset.rollback(); + expect(asset.get('is_enabled')).toBe(true); + expect(asset.get('name')).toBe('Test'); + expect(asset.get('start_date')).toBe(start_date); + return expect(asset.get('uri')).toBe("http://www.screenlyapp.com"); + }); + return it("should erase backup date after rollback", function() { + asset.set({ + is_enabled: false, + name: "Test 2", + start_date: new Date(2011, 4, 6, 14, 20, 0, 0), + end_date: new Date(2011, 4, 6, 14, 20, 0, 0), + uri: "http://www.wireload.net" + }); + asset.rollback(); + expect(asset.get('is_enabled')).toBe(false); + expect(asset.get('name')).toBe('Test 2'); + expect(asset.get('start_date').toISOString()).toBe((new Date(2011, 4, 6, 14, 20, 0, 0)).toISOString()); + return expect(asset.get('uri')).toBe("http://www.wireload.net"); + }); + }); + }); + describe("Collections", function() { + return describe("Assets", function() { + it("should exist", function() { + return expect(Screenly.Assets).toBeDefined(); + }); + return it("should use the Asset model", function() { + var assets; + assets = new Screenly.Assets(); + return expect(assets.model).toBe(Screenly.Asset); + }); + }); + }); + return describe("Views", function() { + it("should have EditAssetView", function() { + return expect(Screenly.View.EditAssetView).toBeDefined(); + }); + it("should have AssetRowView", function() { + return expect(Screenly.View.AssetRowView).toBeDefined(); + }); + return it("should have AssetsView", function() { + return expect(Screenly.View.AssetsView).toBeDefined(); + }); + }); + }); + +}).call(this); diff --git a/views/index.haml b/views/index.haml index 967b9afc7..8182eb459 100644 --- a/views/index.haml +++ b/views/index.haml @@ -30,6 +30,7 @@ %script(src="/static/js/moment.js") %script(src="/static/js/screenly-ose.js") + %script(src="/static/js/main.js") %script(type="text/template", id="asset-row-template") %td.asset_row_name