diff options
author | Bernhard Posselt <nukeawhale@gmail.com> | 2013-02-07 00:21:02 +0100 |
---|---|---|
committer | Bernhard Posselt <nukeawhale@gmail.com> | 2013-02-07 00:21:02 +0100 |
commit | 467f320d98fd9279d234b9aea1b8fbf19f710900 (patch) | |
tree | 347b6edf614236e3a239b9382f89720b3215eced | |
parent | 8c1ee2f48b040b8d679c2fc1d38e8b9582b6b691 (diff) |
moved from cakefile to grunt
-rw-r--r-- | README.rst | 17 | ||||
-rw-r--r-- | coffee/Makefile | 16 | ||||
-rw-r--r-- | coffee/grunt.coffee | 60 | ||||
-rw-r--r-- | coffee/lib/owncloud.coffee | 29 | ||||
-rw-r--r-- | coffee/lib/services/model.coffee | 131 | ||||
-rw-r--r-- | coffee/lib/services/publisher.coffee | 54 | ||||
-rw-r--r-- | coffee/lib/services/request.coffee | 74 | ||||
-rw-r--r-- | coffee/lib/services/router.coffee | 16 | ||||
-rw-r--r-- | coffee/package.json | 24 | ||||
-rw-r--r-- | js/app.js | 2396 |
10 files changed, 1809 insertions, 1008 deletions
diff --git a/README.rst b/README.rst new file mode 100644 index 000000000..487ca6104 --- /dev/null +++ b/README.rst @@ -0,0 +1,17 @@ +README +====== + + +CoffeeScript +------------ +To install the nodejs dependencies run :: + + make deps + +inside the **coffee/** directory. + +To compile and run all unittests run:: + + make + +inside the **coffee/** directory.
\ No newline at end of file diff --git a/coffee/Makefile b/coffee/Makefile new file mode 100644 index 000000000..966a6ba76 --- /dev/null +++ b/coffee/Makefile @@ -0,0 +1,16 @@ +all: watch + + +deps: + cd $(CURDIR) + npm install --save-dev + +watch: compile + $(CURDIR)/node_modules/.bin/grunt --config $(CURDIR)/grunt.coffee run + +compile: + mkdir -p $(CURDIR)/build + $(CURDIR)/node_modules/.bin/grunt --config $(CURDIR)/grunt.coffee compile + +clean: + rm -rf $(CURDIR)/build diff --git a/coffee/grunt.coffee b/coffee/grunt.coffee new file mode 100644 index 000000000..a236f1169 --- /dev/null +++ b/coffee/grunt.coffee @@ -0,0 +1,60 @@ +module.exports = (grunt) -> + + grunt.loadNpmTasks('grunt-contrib-coffee') + + grunt.initConfig + + meta: + pkg: '<json:package.json>' + version: '<config:meta.pkg.version>' + banner: '/*! <%= meta.pkg.description %> - v<%= meta.version %> - ' + + '<%= grunt.template.today("yyyy-mm-dd") %>\n' + + ' * https://github.com/owncloud/apps\n' + + '<% _.forEach(meta.pkg.contributors, function(contributor){ %>' + + ' * Copyright (c) <%= grunt.template.today("yyyy") %> ' + + '<%= contributor.name %> <<%= contributor.email %>>\n' + + '<% };) %>' + + ' * Licensed AGPL \n' + + ' */' + prefix: '(function(angular, $, OC, oc_requesttoken){' + suffix: '})(window.angular, jQuery, OC, oc_requesttoken);' + build: 'build/' + production: '../js/' + + concat: + app: + src: [ + '<banner:meta.prefix>' + '<%= meta.build %>main.js' + '<banner:meta.suffix>' + ] + dest: '<%= meta.production %>app.js' + owncloud: + src: ['lib/owncloud.coffee', 'lib/services/*.coffee'] + dest: '<%= meta.build %>owncloud.coffee' + news: + src: [ + 'app.coffee' + 'services/*.coffee' + 'controllers/*.coffee' + 'directives/*.coffee' + 'filters/*.coffee' + ] + dest: '<%= meta.build %>news.coffee' + + coffee: + compile: + files: + '<%= meta.build %>main.js': [ + '<%= meta.build %>owncloud.coffee' + '<%= meta.build %>news.coffee' + ] + + watch: + app: + files: './**/*.coffee', + tasks: 'compile' + + + grunt.registerTask('run', 'watch') + grunt.registerTask('compile', 'concat:owncloud concat:news coffee concat:app') diff --git a/coffee/lib/owncloud.coffee b/coffee/lib/owncloud.coffee new file mode 100644 index 000000000..c4cc2a336 --- /dev/null +++ b/coffee/lib/owncloud.coffee @@ -0,0 +1,29 @@ +### +# ownCloud +# +# @author Bernhard Posselt +# Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +# +# This file is licensed under the Affero General Public License version 3 or later. +# See the COPYING-README file +# +### + +### +# Various config stuff for owncloud +### +angular.module('OC', []).config ['$httpProvider', ($httpProvider) -> + + # Always send the CSRF token by default + $httpProvider.defaults.get['requesttoken'] = oc_requesttoken + $httpProvider.defaults.post['requesttoken'] = oc_requesttoken + + # needed because crap PHP does not understand JSON + $httpProvider.defaults.post['Content-Type'] = 'application/x-www-form-urlencoded' + $httpProvider.defaults.get['Content-Type'] = 'application/x-www-form-urlencoded' + $httpProvider.defaults.transformRequest = (data) -> + if angular.isDefined(data) + return data + else + return $.param(data) +]
\ No newline at end of file diff --git a/coffee/lib/services/model.coffee b/coffee/lib/services/model.coffee new file mode 100644 index 000000000..a1316e3bb --- /dev/null +++ b/coffee/lib/services/model.coffee @@ -0,0 +1,131 @@ +### +# ownCloud +# +# @author Bernhard Posselt +# Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +# +# This file is licensed under the Affero General Public License version 3 or later. +# See the COPYING-README file +# +### + +angular.module('OC').factory '_Model', -> + + # Parent model: inherit your model from this object + class Model + + constructor: -> + @foreignKeys = {} + @data = [] + @ids = {} + + + handle: (data) -> + if data['create'] != undefined + for item in data['create'] + @create(item) + + if data['update'] != undefined + for item in data['update'] + @update(item) + + if data['delete'] != undefined + for item in data['delete'] + @delete(item) + + + # @brief add a new foreign key name which caches data by foreign key + # @param string name: the name of the foreign key property on the object + # Foreign keys are caching items in a structure like + # name -> id -> [item1, item2] + hasForeignKey: (name) -> + @foreignKeys[name] = {} + + + # @brief adds a new object to the dataset + # @param object data: the data that we want to store + create: (data) -> + if @ids[data.id] != undefined + @update(data) + else + @data.push(data) + @ids[data.id] = data + + # fill indizes of foreign keys + for name, ids of @foreignKeys + id = data[name] + @foreignKeys[name][id] or= [] + @foreignKeys[name][id].push(data) + + + # @brief updates an existing item, the id must not change + # @param object item: the item which should be updated + update: (item) -> + currentItem = @ids[item.id] + for key, value of item + # if the foreignkey changed, we need to update the cache + if @foreignKeys[key] != undefined + if value != currentItem[key] + @_updateForeignKeyCache(key, currentItem, item) + if key != 'id' + currentItem[key] = value + + + delete: (item) -> + if @getById(item.id) != undefined + @removeById(item.id) + + + _updateForeignKeyCache: (name, currentItem, toItem) -> + fromValue = currentItem[name] + toValue = toItem[name] + foreignKeyItems = @foreignKeys[name][fromValue] + @_removeForeignKeyCacheItem(foreignKeyItems, currentItem) + @foreignKeys[name][toValue].push(item) + + + _removeForeignKeyCacheItem: (foreignKeyItems, item) -> + for fkItem, index in foreignKeyItems + if fkItem.id == id + @foreignKeys[key][item[key]].splice(index, 1) + + + # @brief removes an object + # @param int id: the id of the object + removeById: (id) -> + item = @getById(id) + + # remove from foreign key cache + for key, ids of @foreignKeys + foreignKeyItems = ids[item[key]] + @_removeForeignKeyCacheItem(foreignKeyItems, item) + + # remove from array + for item, index in @data + if item.id == id + @data.splice(index, 1) + + delete @ids[id] + + + # @brief returns a data object by its id + # @param int id: the id of the object that we want to fetch + getById: (id) -> + return @ids[id] + + + # @brief returns all stored data objects + getAll: -> + return @data + + + # @brief access the foreign key cache + # @param string foreignKeyName: the name of the foreign key that we want to + # look up + # @param string foreignKeyId: the id from that foreign key that we want to + # get + getAllOfForeignKeyWithId: (foreignKeyName, foreignKeyId) -> + return @foreignKeys[foreignKeyName][foreignKeyId] + + + return Model
\ No newline at end of file diff --git a/coffee/lib/services/publisher.coffee b/coffee/lib/services/publisher.coffee new file mode 100644 index 000000000..4d8788726 --- /dev/null +++ b/coffee/lib/services/publisher.coffee @@ -0,0 +1,54 @@ +### +# ownCloud +# +# @author Bernhard Posselt +# Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +# +# This file is licensed under the Affero General Public License version 3 or later. +# See the COPYING-README file +# +### + +### +# Used for properly distributing received model data from the server +### +angular.module('OC').factory '_Publisher', -> + + + class Publisher + + constructor: -> + @subscriptions = {} + + + # Use this to subscribe to a certain hashkey in the returned json data + # dictionary. + # If you send JSON from the server, you'll receive something like this + # + # { + # data: { + # modelName: { + # create: [{id: 1, name: 'john'}, {id: 2, name: 'ron'}], + # update: [], + # delete: [] + # } + # } + # } + # + # To get the array ['one', 'two'] passed to your model, just subscribe + # to the key: + # Publisher.subscribeModelTo('modelName', myModelInstance) + # + subscribeModelTo: (model, name) -> + @subscriptions[name] or= [] + @subscriptions[name].push(model) + + + # This will publish data from the server to all registered subscribers + # The parameter 'name' is the name under which subscribers have registered + publishDataTo: (data, name) -> + for subscriber in @subscriptions[name] || [] + subscriber.handle(data) + + + return Publisher
\ No newline at end of file diff --git a/coffee/lib/services/request.coffee b/coffee/lib/services/request.coffee new file mode 100644 index 000000000..15b4b9013 --- /dev/null +++ b/coffee/lib/services/request.coffee @@ -0,0 +1,74 @@ +### +# ownCloud +# +# @author Bernhard Posselt +# Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +# +# This file is licensed under the Affero General Public License version 3 or later. +# See the COPYING-README file +# +### + +angular.module('OC').factory '_Request', -> + + class Request + + constructor: (@_$http, @_$rootScope, @_publisher, @_token, @_router) -> + @_initialized = false + @_shelvedRequests = [] + + @_$rootScope.$on 'routesLoaded', => + @_executeShelvedRequests() + @_initialized = true + @_shelvedRequests = [] + + + request: (route, routeParams={}, data={}, onSuccess=null, onFailure=null, config={}) -> + # if routes are not ready yet, save the request + if not @_initialized + @_shelveRequest(route, routeParams, data, method, config) + return + + url = @_router.generate(route, routeParams) + + defaultConfig = + method: 'GET' + url: url + data: data + + # overwrite default values from passed in config + for key, value of config + defaultConfig[key] = value + + @_$http(config) + .success (data, status, headers, config) => + if onSuccess + onSuccess(data, status, headers, config) + + # publish data to models + for name, value of data.data + @publisher.publishDataTo(name, value) + + .error (data, status, headers, config) -> + if onFailure + onFailure(data, status, headers, config) + + + _shelveRequest: (route, routeParams, data, method, config) -> + request = + route: route + routeParams: routeParams + data: data + config: config + method: method + + @_shelvedRequests.push(request) + + + _executeShelvedRequests: -> + for req in @_shelvedRequests + @post(req.route, req.routeParams, req.data, req.method, req.config) + + + + return Request diff --git a/coffee/lib/services/router.coffee b/coffee/lib/services/router.coffee new file mode 100644 index 000000000..71ed24332 --- /dev/null +++ b/coffee/lib/services/router.coffee @@ -0,0 +1,16 @@ +### +# ownCloud +# +# @author Bernhard Posselt +# Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> +# +# This file is licensed under the Affero General Public License version 3 or later. +# See the COPYING-README file +# +### + +### +# Inject router into angular to make testing easier +### +angular.module('OC').factory 'Router', -> + return OC.Router
\ No newline at end of file diff --git a/coffee/package.json b/coffee/package.json new file mode 100644 index 000000000..0c528493f --- /dev/null +++ b/coffee/package.json @@ -0,0 +1,24 @@ +{ + "name": "owncloud-news-app", + "description": "ownCloud RSS reader app", + "version": "0.0.1", + "author": "ownCloud <owncloud@kde.org>", + "private": true, + "contributors": [ + { + "name": "Alessandro Cosentino", + "email": "cosenal@gmail.com" + }, + { + "name": "Bernhard Posselt", + "email": "nukeawhale@gmail.com" + } + ], + "devDependencies": { + "grunt": "~0.3.17", + "coffee-script": "~1.4.0", + "grunt-contrib-coffee": "~0.3.2", + "grunt-testacular": "~0.2.2" + }, + "engine": "node >= 0.8" +} @@ -1,7 +1,8 @@ -// Generated by CoffeeScript 1.3.3 +(function(angular, $, OC, oc_requesttoken){ + /* -# ownCloud - News app +# ownCloud # # @author Bernhard Posselt # Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> @@ -12,42 +13,31 @@ */ -(function() { - var app, markingRead, scrolling, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; +/* +# Various config stuff for owncloud +*/ - app = angular.module('News', []).config(function($provide) { - var config; - config = { - MarkReadTimeout: 500, - ScrollTimeout: 500, - initialLoadedItemsNr: 20, - FeedUpdateInterval: 6000000 - }; - return $provide.value('Config', config); - }); - app.run([ - 'PersistenceNews', function(PersistenceNews) { - return PersistenceNews.loadInitial(); +(function() { + + angular.module('OC', []).config([ + '$httpProvider', function($httpProvider) { + $httpProvider.defaults.get['requesttoken'] = oc_requesttoken; + $httpProvider.defaults.post['requesttoken'] = oc_requesttoken; + $httpProvider.defaults.post['Content-Type'] = 'application/x-www-form-urlencoded'; + $httpProvider.defaults.get['Content-Type'] = 'application/x-www-form-urlencoded'; + return $httpProvider.defaults.transformRequest = function(data) { + if (angular.isDefined(data)) { + return data; + } else { + return $.param(data); + } + }; } ]); - $(document).ready(function() { - $(this).keyup(function(e) { - if ((e.which === 116) || (e.which === 82 && e.ctrlKey)) { - document.location.reload(true); - return false; - } - }); - return $('#browselink').click(function() { - return $('#file_upload_start').trigger('click'); - }); - }); - /* - # ownCloud - News app + # ownCloud # # @author Bernhard Posselt # Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> @@ -58,75 +48,108 @@ */ - scrolling = true; - - markingRead = true; + angular.module('OC').factory('_Request', function() { + var Request; + Request = (function() { + + function Request(_$http, _$rootScope, _publisher, _token, _router) { + var _this = this; + this._$http = _$http; + this._$rootScope = _$rootScope; + this._publisher = _publisher; + this._token = _token; + this._router = _router; + this._initialized = false; + this._shelvedRequests = []; + this._$rootScope.$on('routesLoaded', function() { + _this._executeShelvedRequests(); + _this._initialized = true; + return _this._shelvedRequests = []; + }); + } - angular.module('News').directive('whenScrolled', [ - '$rootScope', 'Config', function($rootScope, Config) { - return function(scope, elm, attr) { - return elm.bind('scroll', function() { - if (scrolling) { - scrolling = false; - setTimeout(function() { - return scrolling = true; - }, Config.ScrollTimeout); - if (markingRead) { - markingRead = false; - setTimeout(function() { - var $elems, feed, feedItem, id, offset, _i, _len, _results; - markingRead = true; - $elems = $(elm).find('.feed_item:not(.read)'); - _results = []; - for (_i = 0, _len = $elems.length; _i < _len; _i++) { - feedItem = $elems[_i]; - offset = $(feedItem).position().top; - if (offset <= -50) { - id = parseInt($(feedItem).data('id'), 10); - feed = parseInt($(feedItem).data('feed'), 10); - _results.push($rootScope.$broadcast('read', { - id: id, - feed: feed - })); - } else { - break; - } - } - return _results; - }, Config.MarkReadTimeout); - } - return scope.$apply(attr.whenScrolled); + Request.prototype.request = function(route, routeParams, data, onSuccess, onFailure, config) { + var defaultConfig, key, url, value, + _this = this; + if (routeParams == null) { + routeParams = {}; + } + if (data == null) { + data = {}; + } + if (onSuccess == null) { + onSuccess = null; + } + if (onFailure == null) { + onFailure = null; + } + if (config == null) { + config = {}; + } + if (!this._initialized) { + this._shelveRequest(route, routeParams, data, method, config); + return; + } + url = this._router.generate(route, routeParams); + defaultConfig = { + method: 'GET', + url: url, + data: data + }; + for (key in config) { + value = config[key]; + defaultConfig[key] = value; + } + return this._$http(config).success(function(data, status, headers, config) { + var name, _ref, _results; + if (onSuccess) { + onSuccess(data, status, headers, config); + } + _ref = data.data; + _results = []; + for (name in _ref) { + value = _ref[name]; + _results.push(_this.publisher.publishDataTo(name, value)); + } + return _results; + }).error(function(data, status, headers, config) { + if (onFailure) { + return onFailure(data, status, headers, config); } }); }; - } - ]); - - /* - # ownCloud - News app - # - # @author Bernhard Posselt - # Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> - # - # This file is licensed under the Affero General Public License version 3 or later. - # See the COPYING-README file - # - */ + Request.prototype._shelveRequest = function(route, routeParams, data, method, config) { + var request; + request = { + route: route, + routeParams: routeParams, + data: data, + config: config, + method: method + }; + return this._shelvedRequests.push(request); + }; - angular.module('News').directive('onEnter', function() { - return function(scope, elm, attr) { - return elm.bind('keyup', function(e) { - if (e.keyCode === 13) { - e.preventDefault(); - return scope.$apply(attr.onEnter); + Request.prototype._executeShelvedRequests = function() { + var req, _i, _len, _ref, _results; + _ref = this._shelvedRequests; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + req = _ref[_i]; + _results.push(this.post(req.route, req.routeParams, req.data, req.method, req.config)); } - }); - }; + return _results; + }; + + return Request; + + })(); + return Request; }); /* - # ownCloud - News app + # ownCloud # # @author Bernhard Posselt # Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> @@ -137,126 +160,154 @@ */ - angular.module('News').directive('feedNavigation', function() { - return function(scope, elm, attr) { - var jumpTo, jumpToNextItem, jumpToPreviousItem; - jumpTo = function($scrollArea, $item) { - var position; - position = $item.offset().top - $scrollArea.offset().top + $scrollArea.scrollTop(); - return $scrollArea.scrollTop(position); - }; - jumpToPreviousItem = function(scrollArea) { - var $item, $items, $previous, $scrollArea, item, notJumped, _i, _len; - $scrollArea = $(scrollArea); - $items = $scrollArea.find('.feed_item'); - notJumped = true; - for (_i = 0, _len = $items.length; _i < _len; _i++) { - item = $items[_i]; - $item = $(item); - if ($item.position().top >= 0) { - $previous = $item.prev(); - if ($previous.length > 0) { - jumpTo($scrollArea, $previous); - } - notJumped = false; - break; + angular.module('OC').factory('_Model', function() { + var Model; + Model = (function() { + + function Model() { + this.foreignKeys = {}; + this.data = []; + this.ids = {}; + } + + Model.prototype.handle = function(data) { + var item, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; + if (data['create'] !== void 0) { + _ref = data['create']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + item = _ref[_i]; + this.create(item); } } - if ($items.length > 0 && notJumped) { - return jumpTo($scrollArea, $items.last()); + if (data['update'] !== void 0) { + _ref1 = data['update']; + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + item = _ref1[_j]; + this.update(item); + } + } + if (data['delete'] !== void 0) { + _ref2 = data['delete']; + _results = []; + for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { + item = _ref2[_k]; + _results.push(this["delete"](item)); + } + return _results; } }; - jumpToNextItem = function(scrollArea) { - var $item, $items, $scrollArea, item, _i, _len, _results; - $scrollArea = $(scrollArea); - $items = $scrollArea.find('.feed_item'); + + Model.prototype.hasForeignKey = function(name) { + return this.foreignKeys[name] = {}; + }; + + Model.prototype.create = function(data) { + var id, ids, name, _base, _ref, _results; + if (this.ids[data.id] !== void 0) { + return this.update(data); + } else { + this.data.push(data); + this.ids[data.id] = data; + _ref = this.foreignKeys; + _results = []; + for (name in _ref) { + ids = _ref[name]; + id = data[name]; + (_base = this.foreignKeys[name])[id] || (_base[id] = []); + _results.push(this.foreignKeys[name][id].push(data)); + } + return _results; + } + }; + + Model.prototype.update = function(item) { + var currentItem, key, value, _results; + currentItem = this.ids[item.id]; _results = []; - for (_i = 0, _len = $items.length; _i < _len; _i++) { - item = $items[_i]; - $item = $(item); - if ($item.position().top > 1) { - jumpTo($scrollArea, $item); - break; + for (key in item) { + value = item[key]; + if (this.foreignKeys[key] !== void 0) { + if (value !== currentItem[key]) { + this._updateForeignKeyCache(key, currentItem, item); + } + } + if (key !== 'id') { + _results.push(currentItem[key] = value); } else { _results.push(void 0); } } return _results; }; - return $(document).keydown(function(e) { - var focused, scrollArea; - focused = $(':focus'); - if (!(focused.is('input') || focused.is('select') || focused.is('textarea') || focused.is('checkbox') || focused.is('button'))) { - scrollArea = elm; - if (e.keyCode === 74 || e.keyCode === 39) { - return jumpToNextItem(scrollArea); - } else if (e.keyCode === 75 || e.keyCode === 37) { - return jumpToPreviousItem(scrollArea); - } + + Model.prototype["delete"] = function(item) { + if (this.getById(item.id) !== void 0) { + return this.removeById(item.id); } - }); - }; - }); + }; - /* - # ownCloud - News app - # - # @author Bernhard Posselt - # Copyright (c) 2012 - Bernhard Posselt <nukeawhale@gmail.com> - # - # This file is licensed under the Affero General Public License version 3 or later. - # See the COPYING-README file - # - */ + Model.prototype._updateForeignKeyCache = function(name, currentItem, toItem) { + var foreignKeyItems, fromValue, toValue; + fromValue = currentItem[name]; + toValue = toItem[name]; + foreignKeyItems = this.foreignKeys[name][fromValue]; + this._removeForeignKeyCacheItem(foreignKeyItems, currentItem); + return this.foreignKeys[name][toValue].push(item); + }; + Model.prototype._removeForeignKeyCacheItem = function(foreignKeyItems, item) { + var fkItem, index, _i, _len, _results; + _results = []; + for (index = _i = 0, _len = foreignKeyItems.length; _i < _len; index = ++_i) { + fkItem = foreignKeyItems[index]; + if (fkItem.id === id) { + _results.push(this.foreignKeys[key][item[key]].splice(index, 1)); + } else { + _results.push(void 0); + } + } + return _results; + }; - /* - # This is used to signal the settings bar that the app has been focused and that - # it should hide - */ + Model.prototype.removeById = function(id) { + var foreignKeyItems, ids, index, item, key, _i, _len, _ref, _ref1; + item = this.getById(id); + _ref = this.foreignKeys; + for (key in _ref) { + ids = _ref[key]; + foreignKeyItems = ids[item[key]]; + this._removeForeignKeyCacheItem(foreignKeyItems, item); + } + _ref1 = this.data; + for (index = _i = 0, _len = _ref1.length; _i < _len; index = ++_i) { + item = _ref1[index]; + if (item.id === id) { + this.data.splice(index, 1); + } + } + return delete this.ids[id]; + }; + Model.prototype.getById = function(id) { + return this.ids[id]; + }; - angular.module('News').directive('hideSettingsWhenFocusLost', [ - '$rootScope', function($rootScope) { - return function(scope, elm, attr) { - $(document.body).click(function() { - $rootScope.$broadcast('hidesettings'); - return scope.$apply(attr.hideSettingsWhenFocusLost); - }); - return $(elm).click(function(e) { - return e.stopPropagation(); - }); + Model.prototype.getAll = function() { |