зеркало из https://github.com/nextcloud/news.git
removed old files from the previous news version
This commit is contained in:
Родитель
8f637cfb85
Коммит
503817875b
|
@ -1,102 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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
|
||||
#
|
||||
###
|
||||
|
||||
module.exports = (grunt) ->
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-coffee')
|
||||
grunt.loadNpmTasks('grunt-contrib-concat')
|
||||
grunt.loadNpmTasks('grunt-contrib-watch')
|
||||
grunt.loadNpmTasks('grunt-coffeelint')
|
||||
grunt.loadNpmTasks('gruntacular');
|
||||
|
||||
grunt.initConfig
|
||||
|
||||
meta:
|
||||
pkg: grunt.file.readJSON('package.json')
|
||||
version: '<%= meta.pkg.version %>'
|
||||
banner: '/**\n' +
|
||||
' * <%= meta.pkg.description %> - v<%= meta.version %>\n' +
|
||||
' *\n' +
|
||||
'<% _.forEach(meta.pkg.contributors, function(contributor){ %>' +
|
||||
' * Copyright (c) <%= grunt.template.today("yyyy") %> - ' +
|
||||
'<%= contributor.name %> <<%= contributor.email %>>\n' +
|
||||
'<% }) %>' +
|
||||
' *\n' +
|
||||
' * This file is licensed under the Affero General Public License version 3 or later.\n' +
|
||||
' * See the COPYING-README file\n' +
|
||||
' *\n' +
|
||||
' */'
|
||||
prefix: '(function(angular, $, OC, oc_requesttoken){'
|
||||
suffix: '})(window.angular, jQuery, OC, oc_requesttoken);'
|
||||
build: 'build/'
|
||||
production: '../js/'
|
||||
|
||||
concat:
|
||||
app:
|
||||
options:
|
||||
banner: '<%= meta.banner %>\n'
|
||||
src: '<%= meta.build %>main.js'
|
||||
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'
|
||||
]
|
||||
coffeelint:
|
||||
app: [
|
||||
'app.coffee'
|
||||
'services/*.coffee'
|
||||
'controllers/*.coffee'
|
||||
'directives/*.coffee'
|
||||
'filters/*.coffee'
|
||||
'lib/**/*.coffee'
|
||||
]
|
||||
coffeelintOptions:
|
||||
'no_tabs':
|
||||
'level': 'ignore'
|
||||
'indentation':
|
||||
'level': 'ignore'
|
||||
|
||||
watch:
|
||||
app:
|
||||
files: './**/*.coffee',
|
||||
tasks: 'compile'
|
||||
|
||||
|
||||
grunt.registerTask('run', ['watch'])
|
||||
grunt.registerTask('lint', ['coffeelint'])
|
||||
grunt.registerTask('compile', [
|
||||
#'coffeelint'
|
||||
'concat:owncloud'
|
||||
'concat:news'
|
||||
'coffee'
|
||||
'concat:app'
|
||||
]
|
||||
)
|
|
@ -1,16 +0,0 @@
|
|||
all: watch
|
||||
|
||||
|
||||
deps:
|
||||
cd $(CURDIR)
|
||||
npm install --save-dev
|
||||
|
||||
watch: compile
|
||||
$(CURDIR)/node_modules/.bin/grunt --config $(CURDIR)/Gruntfile.coffee run
|
||||
|
||||
compile:
|
||||
mkdir -p $(CURDIR)/build
|
||||
$(CURDIR)/node_modules/.bin/grunt --config $(CURDIR)/Gruntfile.coffee compile
|
||||
|
||||
clean:
|
||||
rm -rf $(CURDIR)/build
|
|
@ -1,42 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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
|
||||
#
|
||||
###
|
||||
|
||||
app = angular.module('News', ['ui']).config ($provide) ->
|
||||
# enter your config values in here
|
||||
config =
|
||||
MarkReadTimeout: 500
|
||||
ScrollTimeout: 500
|
||||
initialLoadedItemsNr: 20
|
||||
FeedUpdateInterval: 6000000
|
||||
|
||||
$provide.value('Config', config)
|
||||
|
||||
|
||||
app.run ['PersistenceNews', (PersistenceNews) ->
|
||||
PersistenceNews.loadInitial()
|
||||
]
|
||||
|
||||
|
||||
$(document).ready ->
|
||||
# this is used to forces browser to reload content after refreshing
|
||||
# and thus clearing the scroll cache
|
||||
$(this).keyup (e) ->
|
||||
if (e.which == 116) || (e.which == 82 && e.ctrlKey)
|
||||
document.location.reload(true)
|
||||
return false
|
||||
|
||||
# click on upload button should trigger the file input
|
||||
$('#browselink').click ->
|
||||
$('#file_upload_start').trigger('click')
|
|
@ -1,18 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory 'Controller', ->
|
||||
class Controller
|
||||
constructor: () ->
|
|
@ -1,43 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').controller 'SettingsController',
|
||||
['_SettingsController', '$scope', '$rootScope', 'PersistenceNews', 'OPMLParser', 'FeedModel',
|
||||
(_SettingsController, $scope, $rootScope, PersistenceNews, OPMLParser, FeedModel) ->
|
||||
return new _SettingsController($scope, $rootScope, PersistenceNews,
|
||||
OPMLParser, FeedModel)
|
||||
]
|
||||
|
||||
angular.module('News').controller 'ItemController',
|
||||
['_ItemController', '$scope', 'ItemModel', 'ActiveFeed', 'PersistenceNews', 'FeedModel',
|
||||
'StarredCount', 'GarbageRegistry', 'ShowAll', 'Loading', '$rootScope', 'FeedType',
|
||||
(_ItemController, $scope, ItemModel, ActiveFeed, PersistenceNews, FeedModel,
|
||||
StarredCount, GarbageRegistry, ShowAll, Loading, $rootScope, FeedType) ->
|
||||
return new _ItemController($scope, ItemModel, ActiveFeed, PersistenceNews
|
||||
FeedModel, StarredCount, GarbageRegistry,
|
||||
ShowAll, Loading, $rootScope, FeedType)
|
||||
]
|
||||
|
||||
angular.module('News').controller 'FeedController',
|
||||
['_FeedController', '$scope', 'FeedModel', 'FeedType', 'FolderModel', 'ActiveFeed', 'PersistenceNews',
|
||||
'StarredCount', 'ShowAll', 'ItemModel', 'GarbageRegistry', '$rootScope', 'Loading',
|
||||
'Config',
|
||||
(_FeedController, $scope, FeedModel, FeedType, FolderModel, ActiveFeed, PersistenceNews
|
||||
StarredCount, ShowAll, ItemModel, GarbageRegistry, $rootScope, Loading, Config) ->
|
||||
return new _FeedController($scope, FeedModel, FolderModel, FeedType,
|
||||
ActiveFeed, PersistenceNews, StarredCount, ShowAll,
|
||||
ItemModel, GarbageRegistry, $rootScope, Loading,
|
||||
Config)
|
||||
]
|
|
@ -1,281 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_FeedController', ['Controller', (Controller) ->
|
||||
|
||||
class FeedController extends Controller
|
||||
|
||||
constructor: (@$scope, @feedModel, @folderModel, @feedType, @activeFeed,
|
||||
@persistence, @starredCount, @showAll, @itemModel,
|
||||
@garbageRegistry, @$rootScope, @loading, @config) ->
|
||||
|
||||
@showSubscriptions = true
|
||||
|
||||
@$scope.feeds = @feedModel.getItems()
|
||||
@$scope.folders = @folderModel.getItems()
|
||||
@$scope.feedType = @feedType
|
||||
|
||||
@$scope.getShowAll = =>
|
||||
return @showAll.showAll
|
||||
|
||||
@$scope.setShowAll = (value) =>
|
||||
@showAll.showAll = value
|
||||
@persistence.showAll(value)
|
||||
@$rootScope.$broadcast('triggerHideRead')
|
||||
|
||||
@$scope.addFeed = (url, folder) =>
|
||||
@$scope.feedEmptyError = false
|
||||
@$scope.feedExistsError = false
|
||||
@$scope.feedError = false
|
||||
|
||||
if url == undefined or url.trim() == ''
|
||||
@$scope.feedEmptyError = true
|
||||
else
|
||||
url = url.trim()
|
||||
for feed in @feedModel.getItems()
|
||||
if url == feed.url # FIXME: can we really compare this
|
||||
@$scope.feedExistsError = true
|
||||
|
||||
if not (@$scope.feedEmptyError or @$scope.feedExistsError)
|
||||
if folder == undefined
|
||||
folderId = 0
|
||||
else
|
||||
folderId = folder.id
|
||||
@$scope.adding = true
|
||||
onSuccess = =>
|
||||
@$scope.feedUrl = ''
|
||||
@$scope.adding = false
|
||||
onError = =>
|
||||
@$scope.feedError = true
|
||||
@$scope.adding = false
|
||||
@persistence.createFeed(url, folderId, onSuccess, onError)
|
||||
|
||||
|
||||
@$scope.addFolder = (name) =>
|
||||
@$scope.folderEmptyError = false
|
||||
@$scope.folderExistsError = false
|
||||
|
||||
if name == undefined or name.trim() == ''
|
||||
@$scope.folderEmptyError = true
|
||||
else
|
||||
name = name.trim()
|
||||
for folder in @folderModel.getItems()
|
||||
if name.toLowerCase() == folder.name.toLowerCase()
|
||||
@$scope.folderExistsError = true
|
||||
|
||||
if not (@$scope.folderEmptyError or @$scope.folderExistsError)
|
||||
@addingFolder = true
|
||||
onSuccess = =>
|
||||
@$scope.folderName = ''
|
||||
@addingFolder = false
|
||||
@persistence.createFolder(name, onSuccess)
|
||||
|
||||
@$scope.toggleFolder = (folderId) =>
|
||||
folder = @folderModel.getItemById(folderId)
|
||||
folder.open = !folder.open
|
||||
@persistence.collapseFolder(folder.id, folder.open)
|
||||
|
||||
|
||||
@$scope.isFeedActive = (type, id) =>
|
||||
if type == @activeFeed.type && id == @activeFeed.id
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
||||
|
||||
@$scope.loadFeed = (type, id) =>
|
||||
@loadFeed(type, id)
|
||||
|
||||
|
||||
@$scope.getUnreadCount = (type, id) =>
|
||||
count = @getUnreadCount(type, id)
|
||||
if count > 999
|
||||
return "999+"
|
||||
else
|
||||
return count
|
||||
|
||||
|
||||
@$scope.renameFolder = ->
|
||||
alert 'not implemented yet, needs better solution'
|
||||
|
||||
|
||||
@$scope.triggerHideRead = =>
|
||||
@triggerHideRead()
|
||||
|
||||
|
||||
@$scope.isShown = (type, id) =>
|
||||
switch type
|
||||
when @feedType.Subscriptions then return @showSubscriptions
|
||||
when @feedType.Starred then return @starredCount.count > 0
|
||||
|
||||
|
||||
@$scope.delete = (type, id) =>
|
||||
switch type
|
||||
when @feedType.Folder
|
||||
@folderModel.removeById(id)
|
||||
@persistence.deleteFolder(id)
|
||||
|
||||
when @feedType.Feed
|
||||
@feedModel.removeById(id)
|
||||
@persistence.deleteFeed(id)
|
||||
|
||||
|
||||
@$scope.markAllRead = (type, id) =>
|
||||
switch type
|
||||
when @feedType.Feed
|
||||
for itemId, item of @itemModel.getItemsByTypeAndId(type, id)
|
||||
item.isRead = true
|
||||
feed = @feedModel.getItemById(id)
|
||||
feed.unreadCount = 0
|
||||
mostRecentItemId = @itemModel.getHighestId(type, id)
|
||||
@persistence.setAllItemsRead(feed.id, mostRecentItemId)
|
||||
|
||||
when @feedType.Folder
|
||||
for itemId, item of @itemModel.getItemsByTypeAndId(type, id)
|
||||
item.isRead = true
|
||||
for feedId in @itemModel.getFeedsOfFolderId(id)
|
||||
feed = @feedModel.getItemById(feedId)
|
||||
feed.unreadCount = 0
|
||||
mostRecentItemId = @itemModel.getHighestId(type, feedId)
|
||||
@persistence.setAllItemsRead(feedId, mostRecentItemId)
|
||||
|
||||
when @feedType.Subscriptions
|
||||
for itemId, item of @itemModel.getItemsByTypeAndId(type, id)
|
||||
item.isRead = true
|
||||
for feed in @feedModel.getItems()
|
||||
feed.unreadCount = 0
|
||||
mostRecentItemId = @itemModel.getHighestId(type, feed.id)
|
||||
@persistence.setAllItemsRead(feed.id, mostRecentItemId)
|
||||
|
||||
@$scope.$on 'triggerHideRead', =>
|
||||
@itemModel.clearCache()
|
||||
@triggerHideRead()
|
||||
@loadFeed(activeFeed.type, activeFeed.id)
|
||||
|
||||
@$scope.$on 'loadFeed', (scope, params) =>
|
||||
@loadFeed(params.type, params.id)
|
||||
|
||||
@$scope.$on 'moveFeedToFolder', (scope, params) =>
|
||||
@moveFeedToFolder(params.feedId, params.folderId)
|
||||
|
||||
setInterval =>
|
||||
@updateFeeds()
|
||||
, @config.FeedUpdateInterval
|
||||
|
||||
|
||||
|
||||
updateFeeds: ->
|
||||
for feed in @feedModel.getItems()
|
||||
@persistence.updateFeed(feed.id)
|
||||
|
||||
|
||||
moveFeedToFolder: (feedId, folderId) ->
|
||||
feed = @feedModel.getItemById(feedId)
|
||||
if feed.folderId != folderId
|
||||
feed.folderId = folderId
|
||||
@feedModel.markAccessed()
|
||||
@persistence.moveFeedToFolder(feedId, folderId)
|
||||
|
||||
|
||||
loadFeed: (type, id) ->
|
||||
# to not go crazy with autopaging, clear the caches if we switch the
|
||||
# type of the feed. if the caches only contain seperate feeds, the
|
||||
# cache and autopage logic works fine. if the feed contains more than
|
||||
# one
|
||||
if type != @activeFeed.type or id != @activeFeed.id
|
||||
if not (type == @feedType.Feed && @activeFeed.type == @feedType.Feed)
|
||||
@itemModel.clearCache()
|
||||
|
||||
@activeFeed.id = id
|
||||
@activeFeed.type = type
|
||||
@$scope.triggerHideRead()
|
||||
@persistence.loadFeed(type, id,
|
||||
@itemModel.getHighestId(type, id),
|
||||
@itemModel.getHighestTimestamp(type, id), @config.initialLoadedItemsNr)
|
||||
|
||||
|
||||
triggerHideRead: () ->
|
||||
preventParentFolder = 0
|
||||
|
||||
# feeds
|
||||
for feed in @feedModel.getItems()
|
||||
if @showAll.showAll == false && @getUnreadCount(@feedType.Feed, feed.id) == 0
|
||||
|
||||
# we dont hide the selected feed and folder. But we also dont hide
|
||||
# the parent folder of the selcted feed
|
||||
if @activeFeed.type == @feedType.Feed && @activeFeed.id == feed.id
|
||||
feed.show = true
|
||||
preventParentFolder = feed.folderId
|
||||
else
|
||||
feed.show = false
|
||||
else
|
||||
feed.show = true
|
||||
|
||||
# folders
|
||||
for folder in @folderModel.getItems()
|
||||
if @showAll.showAll == false && @getUnreadCount(@feedType.Folder, folder.id) == 0
|
||||
# prevent hiding when childfeed is active
|
||||
if (@activeFeed.type == @feedType.Folder && @activeFeed.id == folder.id) || preventParentFolder == folder.id
|
||||
folder.show = true
|
||||
else
|
||||
folder.show = false
|
||||
else
|
||||
folder.show = true
|
||||
|
||||
# subscriptions
|
||||
if @showAll.showAll == false && @getUnreadCount(@feedType.Subscriptions, 0) == 0
|
||||
if @activeFeed.type == @feedType.Subscriptions
|
||||
@showSubscriptions = true
|
||||
else
|
||||
@showSubscriptions = false
|
||||
else
|
||||
@showSubscriptions = true
|
||||
|
||||
# starred
|
||||
if @showAll.showAll == false && @getUnreadCount(@feedType.Starred, 0) == 0
|
||||
if @activeFeed.type == @feedType.Starred
|
||||
@showStarred = true
|
||||
else
|
||||
@showStarred = false
|
||||
else
|
||||
@showStarred = true
|
||||
|
||||
@garbageRegistry.clear()
|
||||
|
||||
|
||||
|
||||
getUnreadCount: (type, id) ->
|
||||
switch type
|
||||
when @feedType.Feed
|
||||
return @feedModel.getItemById(id).unreadCount
|
||||
|
||||
when @feedType.Folder
|
||||
counter = 0
|
||||
for feed in @feedModel.getItems()
|
||||
if feed.folderId == id
|
||||
counter += feed.unreadCount
|
||||
return counter
|
||||
|
||||
when @feedType.Starred
|
||||
return @starredCount.count
|
||||
|
||||
when @feedType.Subscriptions
|
||||
counter = 0
|
||||
for feed in @feedModel.getItems()
|
||||
counter += feed.unreadCount
|
||||
return counter
|
||||
|
||||
|
||||
return FeedController
|
||||
]
|
|
@ -1,97 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_ItemController', ['Controller', (Controller) ->
|
||||
|
||||
class ItemController extends Controller
|
||||
|
||||
constructor: (@$scope, @itemModel, @activeFeed, @persistence, @feedModel,
|
||||
@starredCount, @garbageRegistry, @showAll, @loading
|
||||
@$rootScope, @feedType) ->
|
||||
|
||||
@batchSize = 4
|
||||
@loaderQueue = 0
|
||||
|
||||
@$scope.getItems = (type, id) =>
|
||||
return @itemModel.getItemsByTypeAndId(type, id)
|
||||
|
||||
@$scope.items = @itemModel.getItems()
|
||||
@$scope.loading = @loading
|
||||
|
||||
|
||||
@$scope.scroll = =>
|
||||
|
||||
@$scope.activeFeed = @activeFeed
|
||||
|
||||
@$scope.$on 'read', (scope, params) =>
|
||||
@$scope.markRead(params.id, params.feed)
|
||||
|
||||
|
||||
@$scope.loadFeed = (feedId) =>
|
||||
params =
|
||||
id: feedId
|
||||
type: @feedType.Feed
|
||||
@$rootScope.$broadcast 'loadFeed', params
|
||||
|
||||
|
||||
@$scope.markRead = (itemId, feedId) =>
|
||||
item = @itemModel.getItemById(itemId)
|
||||
feed = @feedModel.getItemById(feedId)
|
||||
|
||||
if not item.keptUnread && !item.isRead
|
||||
item.isRead = true
|
||||
feed.unreadCount -= 1
|
||||
|
||||
# this item will be completely deleted if showAll is false
|
||||
if not @showAll.showAll
|
||||
@garbageRegistry.register(item)
|
||||
|
||||
@persistence.markRead(itemId, true)
|
||||
|
||||
|
||||
@$scope.keepUnread = (itemId, feedId) =>
|
||||
item = @itemModel.getItemById(itemId)
|
||||
feed = @feedModel.getItemById(feedId)
|
||||
|
||||
|
||||
item.keptUnread = !item.keptUnread
|
||||
|
||||
if item.isRead
|
||||
item.isRead = false
|
||||
feed.unreadCount += 1
|
||||
|
||||
@persistence.markRead(itemId, false)
|
||||
|
||||
|
||||
@$scope.isKeptUnread = (itemId) =>
|
||||
return @itemModel.getItemById(itemId).keptUnread
|
||||
|
||||
|
||||
@$scope.toggleImportant = (itemId) =>
|
||||
item = @itemModel.getItemById(itemId)
|
||||
|
||||
# cache
|
||||
@itemModel.setImportant(itemId, !item.isImportant)
|
||||
|
||||
if item.isImportant
|
||||
@starredCount.count += 1
|
||||
else
|
||||
@starredCount.count -= 1
|
||||
|
||||
@persistence.setImportant(itemId, item.isImportant)
|
||||
|
||||
|
||||
return ItemController
|
||||
]
|
|
@ -1,60 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_SettingsController', ['Controller',
|
||||
(Controller) ->
|
||||
|
||||
class SettingsController extends Controller
|
||||
|
||||
constructor: (@$scope, @$rootScope, @persistence, @opmlParser, @feedModel) ->
|
||||
|
||||
@$scope.feeds = @feedModel.getItems()
|
||||
|
||||
@$scope.$on 'readFile', (scope, fileContent) =>
|
||||
structure = @opmlParser.parseXML(fileContent)
|
||||
@parseOPMLStructure(structure)
|
||||
|
||||
@$scope.$on 'hidesettings', =>
|
||||
@$scope.showSettings = false
|
||||
|
||||
@$scope.export = =>
|
||||
@export()
|
||||
|
||||
|
||||
export: ->
|
||||
# FIXME: this should only work when the routes are loaded
|
||||
# and be put into a directive
|
||||
url = OC.Router.generate('news_export_opml')
|
||||
window.open url, '_blank'
|
||||
|
||||
|
||||
# recursively create folders
|
||||
parseOPMLStructure: (structure, folderId=0) ->
|
||||
for item in structure.getItems()
|
||||
if item.isFolder()
|
||||
onSuccess = (data) =>
|
||||
console.log data
|
||||
folderId = data.folders[0].id
|
||||
@parseOPMLStructure(item, folderId)
|
||||
@persistence.createFolder(item.getName(), onSuccess)
|
||||
else
|
||||
# FIXME: handle errors
|
||||
onSuccess = ->
|
||||
onError = ->
|
||||
@persistence.createFeed(item.getUrl(), folderId, onSuccess, onError)
|
||||
|
||||
|
||||
return SettingsController
|
||||
]
|
|
@ -1,33 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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
|
||||
#
|
||||
###
|
||||
|
||||
###
|
||||
Turns a normal select into a folder select with the ability to create new folders
|
||||
###
|
||||
angular.module('News').directive 'addFolderSelect', ['$rootScope', ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
|
||||
options =
|
||||
singleSelect: true
|
||||
selectedFirst: true
|
||||
createText: $(elm).data('create')
|
||||
createdCallback: (selected, value) ->
|
||||
console.log selected
|
||||
console.log value
|
||||
|
||||
$(elm).multiSelect(options)
|
||||
|
||||
]
|
|
@ -1,55 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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 to slide up an area and can be customized by passing an expression.
|
||||
If selector is defined, a different area is slid up on click
|
||||
If hideOnFocusLost is defined, the slid up area will hide when the focus is lost
|
||||
###
|
||||
angular.module('News').directive 'clickSlideToggle',
|
||||
['$rootScope', ($rootScope) ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
options = scope.$eval(attr.clickSlideToggle)
|
||||
|
||||
if angular.isDefined(options.selector)
|
||||
slideArea = $(options.selector)
|
||||
else
|
||||
slideArea = elm
|
||||
|
||||
elm.click ->
|
||||
if slideArea.is(':visible') and not slideArea.is(':animated')
|
||||
slideArea.slideUp()
|
||||
else
|
||||
slideArea.slideDown()
|
||||
|
||||
if angular.isDefined(options.hideOnFocusLost) and options.hideOnFocusLost
|
||||
$(document.body).click ->
|
||||
$rootScope.$broadcast 'lostFocus'
|
||||
|
||||
$rootScope.$on 'lostFocus', (scope, params) ->
|
||||
if params != slideArea
|
||||
if slideArea.is(':visible') and not slideArea.is(':animated')
|
||||
slideArea.slideUp()
|
||||
|
||||
slideArea.click (e) ->
|
||||
$rootScope.$broadcast 'lostFocus', slideArea
|
||||
e.stopPropagation()
|
||||
|
||||
elm.click (e) ->
|
||||
$rootScope.$broadcast 'lostFocus', slideArea
|
||||
e.stopPropagation()
|
||||
|
||||
]
|
|
@ -1,28 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').directive 'draggable', ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
|
||||
details =
|
||||
revert: true
|
||||
stack: '> li'
|
||||
zIndex: 1000
|
||||
axis: 'y'
|
||||
helper: 'clone'
|
||||
|
||||
$(elm).draggable(details)
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').directive 'droppable', ['$rootScope', ($rootScope) ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
$elem = $(elm)
|
||||
|
||||
details =
|
||||
accept: '.feed'
|
||||
hoverClass: 'drag-and-drop'
|
||||
greedy: true
|
||||
drop: (event, ui) ->
|
||||
# in case jquery ui did something weird
|
||||
$('.drag-and-drop').removeClass('drag-and-drop')
|
||||
|
||||
data =
|
||||
folderId: parseInt($elem.data('id'), 10)
|
||||
feedId: parseInt($(ui.draggable).data('id'), 10)
|
||||
|
||||
$rootScope.$broadcast('moveFeedToFolder', data)
|
||||
scope.$apply attr.droppable
|
||||
|
||||
$elem.droppable(details)
|
||||
]
|
|
@ -1,70 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').directive 'feedNavigation', ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
|
||||
jumpTo = ($scrollArea, $item) ->
|
||||
position = $item.offset().top - $scrollArea.offset().top + $scrollArea.scrollTop()
|
||||
$scrollArea.scrollTop(position)
|
||||
|
||||
jumpToPreviousItem = (scrollArea) ->
|
||||
$scrollArea = $(scrollArea)
|
||||
$items = $scrollArea.find('.feed_item')
|
||||
notJumped = true
|
||||
for item in $items
|
||||
$item = $(item)
|
||||
if $item.position().top >= 0
|
||||
$previous = $item.prev()
|
||||
# if there are no items before the current one
|
||||
if $previous.length > 0
|
||||
jumpTo($scrollArea, $previous)
|
||||
|
||||
notJumped = false
|
||||
break
|
||||
|
||||
# in case we didnt jump
|
||||
if $items.length > 0 and notJumped
|
||||
jumpTo($scrollArea, $items.last())
|
||||
|
||||
|
||||
jumpToNextItem = (scrollArea) ->
|
||||
$scrollArea = $(scrollArea)
|
||||
$items = $scrollArea.find('.feed_item')
|
||||
for item in $items
|
||||
$item = $(item)
|
||||
if $item.position().top > 1
|
||||
jumpTo($scrollArea, $item)
|
||||
break
|
||||
|
||||
|
||||
$(document).keydown (e) ->
|
||||
# only activate if no input elements is focused
|
||||
focused = $(':focus')
|
||||
|
||||
if not (focused.is('input') or focused.is('select') or
|
||||
focused.is('textarea') or focused.is('checkbox') or focused.is('button'))
|
||||
|
||||
scrollArea = elm
|
||||
# j or right
|
||||
if e.keyCode == 74 or e.keyCode == 39
|
||||
jumpToNextItem(scrollArea)
|
||||
|
||||
# k or left
|
||||
else if e.keyCode == 75 or e.keyCode == 37
|
||||
jumpToPreviousItem(scrollArea)
|
||||
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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 to forward clicks to another element via jquery selector
|
||||
|
||||
The expression which can be passed looks like this {selector:'#opml-upload'}
|
||||
###
|
||||
|
||||
angular.module('News').directive 'forwardClick', ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
options = scope.$eval(attr.forwardClick)
|
||||
|
||||
if angular.isDefined(options.selector)
|
||||
elm.click ->
|
||||
$(options.selector).trigger('click')
|
|
@ -1,24 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').directive 'onEnter', ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
|
||||
elm.bind 'keyup', (e) ->
|
||||
if e.keyCode == 13
|
||||
e.preventDefault()
|
||||
scope.$apply attr.onEnter
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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
|
||||
#
|
||||
###
|
||||
|
||||
###
|
||||
Thise directive can be bound on an input element with type file and name files []
|
||||
When a file is input, the content will be broadcasted as a readFile event
|
||||
###
|
||||
angular.module('News').directive 'readFile', ['$rootScope', ($rootScope) ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
$(elm).change ->
|
||||
if window.File and window.FileReader and window.FileList
|
||||
file = elm[0].files[0]
|
||||
|
||||
reader = new FileReader()
|
||||
|
||||
reader.onload = (e) ->
|
||||
content = e.target.result
|
||||
$rootScope.$broadcast 'readFile', content
|
||||
|
||||
reader.readAsText(file)
|
||||
|
||||
else
|
||||
alert 'Your browser does not support the FileReader API!'
|
||||
]
|
|
@ -1,56 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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
|
||||
#
|
||||
###
|
||||
|
||||
scrolling = true
|
||||
markingRead = true
|
||||
|
||||
angular.module('News').directive 'whenScrolled',
|
||||
['$rootScope', 'Config',
|
||||
($rootScope, Config) ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
|
||||
elm.bind 'scroll', ->
|
||||
# prevent from doing to many scroll actions
|
||||
# the first timeout prevents accidental and too early marking as read
|
||||
if scrolling
|
||||
scrolling = false
|
||||
setTimeout ->
|
||||
scrolling = true
|
||||
, Config.ScrollTimeout
|
||||
|
||||
if markingRead
|
||||
markingRead = false
|
||||
setTimeout ->
|
||||
markingRead = true
|
||||
# only broadcast elements that are not already read
|
||||
# and that are beyond the top border
|
||||
$elems = $(elm).find('.feed_item:not(.read)')
|
||||
|
||||
for feedItem in $elems
|
||||
offset = $(feedItem).position().top
|
||||
if offset <= -50
|
||||
id = parseInt($(feedItem).data('id'), 10)
|
||||
feed = parseInt($(feedItem).data('feed'), 10)
|
||||
$rootScope.$broadcast('read', {id: id, feed: feed})
|
||||
else
|
||||
break
|
||||
|
||||
, Config.MarkReadTimeout
|
||||
|
||||
scope.$apply attr.whenScrolled
|
||||
|
||||
]
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').filter 'feedInFolder', ->
|
||||
return (feeds, folderId) ->
|
||||
result = []
|
||||
for feed in feeds
|
||||
if feed.folderId == folderId
|
||||
result.push(feed)
|
||||
return result
|
|
@ -1,27 +0,0 @@
|
|||
###
|
||||
# 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 to forward clicks to another element via jquery selector
|
||||
|
||||
The expression which can be passed looks like this {selector:'#opml-upload'}
|
||||
###
|
||||
|
||||
angular.module('OC').directive 'forwardClick', ->
|
||||
|
||||
return (scope, elm, attr) ->
|
||||
options = scope.$eval(attr.forwardClick)
|
||||
|
||||
if angular.isDefined(options.selector)
|
||||
elm.click ->
|
||||
$(options.selector).trigger('click')
|
|
@ -1,44 +0,0 @@
|
|||
###
|
||||
# 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)
|
||||
]
|
||||
|
||||
angular.module('OC').run ['$rootScope', 'Router', ($rootScope, Router) ->
|
||||
init = ->
|
||||
$rootScope.$broadcast('routesLoaded')
|
||||
|
||||
# this registers a callback that is executed once the routes have
|
||||
# finished loading. Before this you cant really do request
|
||||
Router.registerLoadedCallback(init)
|
||||
]
|
|
@ -1,18 +0,0 @@
|
|||
###
|
||||
# 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 notification into angular to make testing easier
|
||||
###
|
||||
angular.module('OC').factory 'Notification', ->
|
||||
return OC.Notification
|
|
@ -1,56 +0,0 @@
|
|||
###
|
||||
# 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
|
|
@ -1,76 +0,0 @@
|
|||
###
|
||||
# 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
|
|
@ -1,18 +0,0 @@
|
|||
###
|
||||
# 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
|
|
@ -1,28 +0,0 @@
|
|||
{
|
||||
"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.4.0rc8",
|
||||
"grunt-cli": "~0.1.6",
|
||||
"coffee-script": "~1.4.0",
|
||||
"grunt-contrib-coffee": "~0.4.0rc7",
|
||||
"grunt-contrib-concat": "~0.1.2rc6",
|
||||
"grunt-contrib-watch": "~0.2.0rc7",
|
||||
"grunt-coffeelint": "0.0.4",
|
||||
"gruntacular": "~0.1.1"
|
||||
},
|
||||
"engine": "node >= 0.8"
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_ActiveFeed', ->
|
||||
|
||||
class ActiveFeed
|
||||
|
||||
constructor: ->
|
||||
@id = 0
|
||||
@type = 3
|
||||
|
||||
handle: (data) ->
|
||||
@id = data.id
|
||||
@type = data.type
|
||||
|
||||
return ActiveFeed
|
|
@ -1,164 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_Cache', ->
|
||||
|
||||
class Cache
|
||||
|
||||
constructor: (@feedType, @feedModel, @folderModel) ->
|
||||
@clear()
|
||||
|
||||
|
||||
clear: ->
|
||||
@feedCache = []
|
||||
@folderCache = {}
|
||||
@folderCacheLastModified = 0
|
||||
@importantCache = []
|
||||
@highestId = 0
|
||||
@lowestId = 0
|
||||
@highestTimestamp = 0
|
||||
@lowestTimestamp = 0
|
||||
@highestIds = {}
|
||||
@lowestIds = {}
|
||||
@highestTimestamps = {}
|
||||
@lowestTimestamps = {}
|
||||
|
||||
|
||||
add: (item) ->
|
||||
# cache for feed access
|
||||
if not @feedCache[item.feedId]
|
||||
@feedCache[item.feedId] = []
|
||||
@feedCache[item.feedId].push(item)
|
||||
|
||||
# cache for non feeds
|
||||
if @highestTimestamp < item.date
|
||||
@highestTimestamp = item.date
|
||||
if @lowestTimestamp > item.date
|
||||
@lowestTimestamp = item.date
|
||||
if @highestId < item.id
|
||||
@highestId = item.id
|
||||
if @lowestId > item.id
|
||||
@lowestId = item.id
|
||||
|
||||
|
||||
# cache for important
|
||||
if item.isImportant
|
||||
@importantCache.push(item)
|
||||
|
||||
# cache lowest and highest ids and timestamps for only fetching new
|
||||
# items
|
||||
if @highestTimestamps[item.feedId] == undefined or item.id > @highestTimestamps[item.feedId]
|
||||
@highestTimestamps[item.feedId] = item.date
|
||||
if @lowestTimestamps[item.feedId] == undefined or item.id > @lowestTimestamps[item.feedId]
|
||||
@lowestTimestamps[item.feedId] = item.date
|
||||
if @highestIds[item.feedId] == undefined or item.id > @highestIds[item.feedId]
|
||||
@highestIds[item.feedId] = item.id
|
||||
if @lowestIds[item.feedId] == undefined or item.id > @lowestIds[item.feedId]
|
||||
@lowestIds[item.feedId] = item.id
|
||||
|
||||
|
||||
getItemsOfFeed: (feedId) ->
|
||||
return @feedCache[feedId]
|
||||
|
||||
|
||||
getFeedIdsOfFolder: (folderId) ->
|
||||
@buildFolderCache(folderId)
|
||||
return @folderCache[folderId]
|
||||
|
||||
|
||||
getImportantItems: ->
|
||||
return @importantCache
|
||||
|
||||
|
||||
buildFolderCache: (id) ->
|
||||
# invalidate the foldercache if the last modified date is
|
||||
# not the currently used one
|
||||
if @folderCacheLastModified != @feedModel.getLastModified()
|
||||
@folderCache = {}
|
||||
@folderCacheLastModified = @feedModel.getLastModified()
|
||||
|
||||
# if the folderarray does not yet exist, build it
|
||||
# otherwise use the last generated one
|
||||
if @folderCache[id] == undefined
|
||||
@folderCache[id] = []
|
||||
for feed in @feedModel.getItems()
|
||||
if feed.folderId == id
|
||||
@folderCache[id].push(feed.id)
|
||||
|
||||
|
||||
getFeedsOfFolderId: (id) ->
|
||||
@buildFolderCache(id)
|
||||
return @folderCache[id]
|
||||
|
||||
|
||||
removeItemInArray: (id, array) ->
|
||||
removeItemIndex = null
|
||||
counter = 0
|
||||
for element in array
|
||||
if element.id == id
|
||||
removeItemIndex = counter
|
||||
break
|
||||
counter += 1
|
||||
|
||||
if removeItemIndex != null
|
||||
array.splice(removeItemIndex, 1)
|
||||
|
||||
|
||||
remove: (item) ->
|
||||
@removeItemInArray(item.id, @feedCache[item.feedId])
|
||||
@removeItemInArray(item.id, @importantCache)
|
||||
|
||||
|
||||
setImportant: (item, isImportant) ->
|
||||
if isImportant
|
||||
@importantCache.push(item)
|
||||
else
|
||||
@removeItemInArray(item.id, @importantCache)
|
||||
|
||||
getHighestId: (type, id) ->
|
||||
if @isFeed(type)
|
||||
return @highestIds[id] || 0
|
||||
else
|
||||
return @highestId
|
||||
|
||||
|
||||
getHighestTimestamp: (type, id) ->
|
||||
if @isFeed(type)
|
||||
return @highestTimestamps[id] || 0
|
||||
else
|
||||
return @highestTimestamp
|
||||
|
||||
|
||||
getLowestId: (type, id) ->
|
||||
if @isFeed(type)
|
||||
return @lowestIds[id] || 0
|
||||
else
|
||||
return @lowestId
|
||||
|
||||
|
||||
getLowestTimestamp: (type, id) ->
|
||||
if @isFeed(type)
|
||||
return @lowestTimestamps[id] || 0
|
||||
else
|
||||
return @lowestTimestamp
|
||||
|
||||
|
||||
isFeed: (type) ->
|
||||
return type == @feedType.Feed
|
||||
|
||||
|
||||
return Cache
|
||||
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_FeedModel', ['Model', (Model) ->
|
||||
|
||||
class FeedModel extends Model
|
||||
|
||||
constructor: () ->
|
||||
super()
|
||||
|
||||
|
||||
add: (item) ->
|
||||
super(@bindAdditional(item))
|
||||
|
||||
|
||||
bindAdditional: (item) ->
|
||||
if item.icon == "url()"
|
||||
item.icon = 'url(' + OC.imagePath('news', 'rss.svg') + ')'
|
||||
return item
|
||||
|
||||
|
||||
return FeedModel
|
||||
]
|
|
@ -1,22 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory 'FeedType', ->
|
||||
feedType =
|
||||
Feed: 0
|
||||
Folder: 1
|
||||
Starred: 2
|
||||
Subscriptions: 3
|
||||
Shared: 4
|
|
@ -1,25 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_FolderModel', ['Model', (Model, $rootScope) ->
|
||||
|
||||
class FolderModel extends Model
|
||||
|
||||
constructor: ->
|
||||
super()
|
||||
|
||||
|
||||
return FolderModel
|
||||
]
|
|
@ -1,42 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_GarbageRegistry', ->
|
||||
|
||||
class GarbageRegistry
|
||||
|
||||
constructor: (@itemModel) ->
|
||||
@registeredItemIds = {}
|
||||
|
||||
register: (item) ->
|
||||
itemId = item.id
|
||||
@registeredItemIds[itemId] = item
|
||||
|
||||
|
||||
unregister: (item) ->
|
||||
itemId = item.id
|
||||
delete @registeredItemIds[itemId]
|
||||
|
||||
|
||||
clear: () ->
|
||||
# delete read items for performance reasons when showAll == false
|
||||
for id, item of @registeredItemIds
|
||||
if not item.keptUnread
|
||||
@itemModel.removeById(parseInt(id, 10))
|
||||
item.keptUnread = false
|
||||
@registeredItemIds = {}
|
||||
|
||||
|
||||
return GarbageRegistry
|
|
@ -1,101 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_ItemModel', ['Model', (Model) ->
|
||||
|
||||
class ItemModel extends Model
|
||||
|
||||
constructor: (@cache, @feedType) ->
|
||||
super()
|
||||
|
||||
|
||||
clearCache: () ->
|
||||
@cache.clear()
|
||||
super()
|
||||
|
||||
|
||||
add: (item) ->
|
||||
item = @bindAdditional(item)
|
||||
if super(item)
|
||||
@cache.add(@getItemById(item.id))
|
||||
|
||||
|
||||
bindAdditional: (item) ->
|
||||
item.getRelativeDate = ->
|
||||
return moment.unix(this.date).fromNow();
|
||||
|
||||
item.getAuthorLine = ->
|
||||
if this.author != null and this.author.trim() != ""
|
||||
return "by " + this.author
|
||||
else
|
||||
return ""
|
||||
return item
|
||||
|
||||
|
||||
removeById: (itemId) ->
|
||||
item = @getItemById(itemId)
|
||||
if item != undefined
|
||||
@cache.remove(item)
|
||||
super(itemId)
|
||||
|
||||
|
||||
getHighestId: (type, id) ->
|
||||
@cache.getHighestId(type, id)
|
||||
|
||||
|
||||
getHighestTimestamp: (type, id) ->
|
||||
@cache.getHighestTimestamp(type, id)
|
||||
|
||||
|
||||
getLowestId: (type, id) ->
|
||||
@cache.getLowestId(type, id)
|
||||
|
||||
|
||||
getLowestTimestamp: (type, id) ->
|
||||
@cache.getLowestTimestamp(type, id)
|
||||
|
||||
|
||||
getFeedsOfFolderId: (id) ->
|
||||
@cache.getFeedsOfFolderId(id)
|
||||
|
||||
|
||||
getItemsByTypeAndId: (type, id) ->
|
||||
switch type
|
||||
when @feedType.Feed
|
||||
items = @cache.getItemsOfFeed(id) || []
|
||||
return items
|
||||
|
||||
when @feedType.Subscriptions
|
||||
return @getItems()
|
||||
|
||||
when @feedType.Folder
|
||||
items = []
|
||||
for feedId in @cache.getFeedIdsOfFolder(id)
|
||||
items = items.concat(@cache.getItemsOfFeed(feedId) || [])
|
||||
return items
|
||||
|
||||
when @feedType.Starred
|
||||
return @cache.getImportantItems()
|
||||
|
||||
|
||||
setImportant: (itemId, isImportant) ->
|
||||
item = @getItemById(itemId)
|
||||
@cache.setImportant(item, isImportant)
|
||||
item.isImportant = isImportant
|
||||
|
||||
|
||||
return ItemModel
|
||||
|
||||
]
|
|
@ -1,21 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_Loading', ->
|
||||
|
||||
class Loading
|
||||
|
||||
constructor: ->
|
||||
@loading = 0
|
|
@ -1,84 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory 'Model', ->
|
||||
|
||||
class Model
|
||||
|
||||
constructor: () ->
|
||||
@clearCache()
|
||||
|
||||
handle: (data) ->
|
||||
for item in data
|
||||
@add(item)
|
||||
|
||||
|
||||
clearCache: () ->
|
||||
@items = []
|
||||
@itemIds = {}
|
||||
@markAccessed()
|
||||
|
||||
|
||||
markAccessed: () ->
|
||||
@lastAccessed = new Date().getTime()
|
||||
|
||||
|
||||
getLastModified: () ->
|
||||
return @lastAccessed
|
||||
|
||||
|
||||
add: (item) ->
|
||||
if @itemIds[item.id] == undefined
|
||||
@items.push(item)
|
||||
@itemIds[item.id] = item
|
||||
@markAccessed()
|
||||
return true
|
||||
else
|
||||
@update(item)
|
||||
return false
|
||||
|
||||
|
||||
update: (item) ->
|
||||
updatedItem = @itemIds[item.id]
|
||||
for key, value of item
|
||||
if key != 'id'
|
||||
updatedItem[key] = value
|
||||
@markAccessed()
|
||||
|
||||
|
||||
removeById: (id) ->
|
||||
removeItemIndex = null
|
||||
counter = 0
|
||||
for item in @items
|
||||
if item.id == id
|
||||
removeItemIndex = counter
|
||||
break
|
||||
counter += 1
|
||||
|
||||
if removeItemIndex != null
|
||||
@items.splice(removeItemIndex, 1)
|
||||
delete @itemIds[id]
|
||||
@markAccessed()
|
||||
|
||||
|
||||
getItemById: (id) ->
|
||||
return @itemIds[id]
|
||||
|
||||
|
||||
getItems: () ->
|
||||
return @items
|
||||
|
||||
|
||||
return Model
|
|
@ -1,71 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_OPMLParser', ->
|
||||
|
||||
class Feed
|
||||
|
||||
constructor: (@name, @url) ->
|
||||
|
||||
getName: ->
|
||||
return @name
|
||||
|
||||
getUrl: ->
|
||||
return @url
|
||||
|
||||
isFolder: ->
|
||||
return false
|
||||
|
||||
|
||||
class Folder
|
||||
|
||||
constructor: (@name) ->
|
||||
@items = []
|
||||
|
||||
add: (feed) ->
|
||||
@items.push(feed)
|
||||
|
||||
getItems: ->
|
||||
return @items
|
||||
|
||||
getName: ->
|
||||
return @name
|
||||
|
||||
isFolder: ->
|
||||
return true
|
||||
|
||||
|
||||
class OPMLParser
|
||||
|
||||
parseXML: (xml) ->
|
||||
$xml = $($.parseXML(xml))
|
||||
$root = $xml.find('body')
|
||||
structure = new Folder('root')
|
||||
@_recursivelyParse($root, structure)
|
||||
return structure
|
||||
|
||||
_recursivelyParse: ($xml, structure) ->
|
||||
for outline in $xml.children('outline')
|
||||
$outline = $(outline)
|
||||
if $outline.attr('type') != undefined
|
||||
feed = new Feed($outline.attr('text'), $outline.attr('xmlUrl'))
|
||||
structure.add(feed)
|
||||
else
|
||||
folder = new Folder($outline.attr('text'))
|
||||
structure.add(folder)
|
||||
@_recursivelyParse($outline, folder)
|
||||
|
||||
|
||||
return OPMLParser
|
|
@ -1,77 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory 'Persistence', ->
|
||||
|
||||
class Persistence
|
||||
|
||||
constructor: (@appName, @$http) ->
|
||||
@appInitialized = false
|
||||
@shelvedRequests = []
|
||||
|
||||
|
||||
setInitialized: (isInitialized) ->
|
||||
if isInitialized
|
||||
@executePostRequests()
|
||||
@appInitialized = isInitialized
|
||||
|
||||
|
||||
executePostRequests: () ->
|
||||
for request in @shelvedRequests
|
||||
@post(request.route, request.data, request.callback)
|
||||
console.log request
|
||||
@shelvedRequests = []
|
||||
|
||||
|
||||
isInitialized: ->
|
||||
return @appInitialized
|
||||
|
||||
|
||||
post: (route, data={}, callback, errorCallback, init=false, contentType='application/x-www-form-urlencoded') ->
|
||||
if @isInitialized == false && init == false
|
||||
request =
|
||||
route: route
|
||||
data: data
|
||||
callback: callback
|
||||
@shelvedRequests.push(request)
|
||||
return
|
||||
|
||||
if not callback
|
||||
callback = ->
|
||||
if not errorCallback
|
||||
errorCallback = ->
|
||||
|
||||
url = OC.Router.generate("news_ajax_" + route)
|
||||
|
||||
data = $.param(data)
|
||||
|
||||
# csrf token
|
||||
headers =
|
||||
requesttoken: oc_requesttoken
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
|
||||
@$http.post(url, data, {headers: headers}).
|
||||
success((data, status, headers, config) ->
|
||||
if data.status == "error"
|
||||
errorCallback(data.msg)
|
||||
else
|
||||
callback(data)
|
||||
).
|
||||
error (data, status, headers, config) ->
|
||||
console.warn('Error occured: ')
|
||||
console.warn(status)
|
||||
console.warn(headers)
|
||||
console.warn(config)
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_PersistenceNews', ['Persistence', (Persistence) ->
|
||||
|
||||
class PersistenceNews extends Persistence
|
||||
|
||||
constructor: ($http, @$rootScope, @loading, @publisher) ->
|
||||
super('news', $http)
|
||||
|
||||
|
||||
updateModels: (data) ->
|
||||
for type, value of data
|
||||
@publisher.publish(type, value)
|
||||
|
||||
|
||||
loadInitial: () ->
|
||||
@loading.loading += 1
|
||||
OC.Router.registerLoadedCallback =>
|
||||
@post 'init', {}, (json) =>
|
||||
@loading.loading -= 1
|
||||
@updateModels(json.data)
|
||||
@$rootScope.$broadcast('triggerHideRead')
|
||||
@setInitialized(true)
|
||||
, null, true
|
||||
|
||||
|
||||
loadFeed: (type, id, latestFeedId, latestTimestamp, limit=20) ->
|
||||
data =
|
||||
type: type
|
||||
id: id
|
||||
latestFeedId: latestFeedId
|
||||
latestTimestamp: latestTimestamp
|
||||
limit: limit
|
||||
|
||||
@loading.loading += 1
|
||||
@post 'loadfeed', data, (json) =>
|
||||
@loading.loading -= 1
|
||||
@updateModels(json.data)
|
||||
|
||||
|
||||
createFeed: (feedUrl, folderId, onSuccess, onError) ->
|
||||
data =
|
||||
feedUrl: feedUrl
|
||||
folderId: folderId
|
||||
@post 'createfeed', data, (json) =>
|
||||
onSuccess(json.data)
|
||||
@updateModels(json.data)
|
||||
, onError
|
||||
|
||||
|
||||
deleteFeed: (feedId, onSuccess) ->
|
||||
data =
|
||||
feedId: feedId
|
||||
@post 'deletefeed', data, onSuccess
|
||||
|
||||
|
||||
moveFeedToFolder: (feedId, folderId) ->
|
||||
data =
|
||||
feedId: feedId
|
||||
folderId: folderId
|
||||
@post 'movefeedtofolder', data
|
||||
|
||||
|
||||
createFolder: (folderName, onSuccess) ->
|
||||
data =
|
||||
folderName: folderName
|
||||
@post 'createfolder', data, (json) =>
|
||||
onSuccess(json.data)
|
||||
@updateModels(json.data)
|
||||
|
||||
|
||||
deleteFolder: (folderId) ->
|
||||
data =
|
||||
folderId: folderId
|
||||
@post 'deletefolder', data
|
||||
|
||||
|
||||
changeFolderName: (folderId, newFolderName) ->
|
||||
data =
|
||||
folderId: folderId
|
||||
newFolderName: newFolderName
|
||||
@post 'folderName', data
|
||||
|
||||
|
||||
showAll: (isShowAll) ->
|
||||
data =
|
||||
showAll: isShowAll
|
||||
@post 'setshowall', data
|
||||
|
||||
|
||||
markRead: (itemId, isRead) ->
|
||||
if isRead
|
||||
status = 'read'
|
||||
else
|
||||
status = 'unread'
|
||||
|
||||
data =
|
||||
itemId: itemId
|
||||
status: status
|
||||
|
||||
@post 'setitemstatus', data
|
||||
|
||||
|
||||
setImportant: (itemId, isImportant) ->
|
||||
if isImportant
|
||||
status = 'important'
|
||||
else
|
||||
status = 'unimportant'
|
||||
|
||||
data =
|
||||
itemId: itemId
|
||||
status: status
|
||||
|
||||
@post 'setitemstatus', data
|
||||
|
||||
|
||||
collapseFolder: (folderId, value) ->
|
||||
data =
|
||||
folderId: folderId
|
||||
opened: value
|
||||
@post 'collapsefolder', data
|
||||
|
||||
|
||||
updateFeed: (feedId) ->
|
||||
data =
|
||||
feedId: feedId
|
||||
|
||||
@post 'updatefeed', data, (json) =>
|
||||
@updateModels(json.data)
|
||||
|
||||
|
||||
setAllItemsRead: (feedId, mostRecentItemId) ->
|
||||
data =
|
||||
feedId: feedId
|
||||
mostRecentItemId: mostRecentItemId
|
||||
@post 'setallitemsread', data
|
||||
|
||||
|
||||
|
||||
return PersistenceNews
|
||||
]
|
|
@ -1,34 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_Publisher', ->
|
||||
|
||||
class Publisher
|
||||
|
||||
constructor: () ->
|
||||
@subscriptions = {}
|
||||
|
||||
|
||||
subscribeTo: (type, object) ->
|
||||
@subscriptions[type] or= []
|
||||
@subscriptions[type].push(object)
|
||||
|
||||
|
||||
publish: (type, message) ->
|
||||
for subscriber in @subscriptions[type] || []
|
||||
subscriber.handle(message)
|
||||
|
||||
|
||||
return Publisher
|
|
@ -1,94 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory 'Loading',
|
||||
['_Loading', (_Loading) ->
|
||||
return new _Loading()
|
||||
]
|
||||
|
||||
# Models
|
||||
angular.module('News').factory 'ActiveFeed',
|
||||
['_ActiveFeed', 'Publisher', (_ActiveFeed, Publisher) ->
|
||||
model = new _ActiveFeed()
|
||||
Publisher.subscribeTo('activeFeed', model)
|
||||
return model
|
||||
]
|
||||
|
||||
angular.module('News').factory 'ShowAll',
|
||||
['_ShowAll', 'Publisher', (_ShowAll, Publisher) ->
|
||||
model = new _ShowAll()
|
||||
Publisher.subscribeTo('showAll', model)
|
||||
return model
|
||||
]
|
||||
|
||||
angular.module('News').factory 'StarredCount',
|
||||
['_StarredCount', 'Publisher', (_StarredCount, Publisher) ->
|
||||
model = new _StarredCount()
|
||||
Publisher.subscribeTo('starredCount', model)
|
||||
return model
|
||||
]
|
||||
|
||||
angular.module('News').factory 'FeedModel',
|
||||
['_FeedModel', 'Publisher',
|
||||
(_FeedModel, Publisher) ->
|
||||
model = new _FeedModel()
|
||||
Publisher.subscribeTo('feeds', model)
|
||||
return model
|
||||
]
|
||||
|
||||
angular.module('News').factory 'FolderModel',
|
||||
['_FolderModel', 'Publisher',
|
||||
(_FolderModel, Publisher) ->
|
||||
model = new _FolderModel()
|
||||
Publisher.subscribeTo('folders', model)
|
||||
return model
|
||||
]
|
||||
|
||||
angular.module('News').factory 'ItemModel',
|
||||
['_ItemModel', 'Publisher', 'Cache', 'FeedType',
|
||||
(_ItemModel, Publisher, Cache, FeedType) ->
|
||||
model = new _ItemModel(Cache, FeedType)
|
||||
Publisher.subscribeTo('items', model)
|
||||
return model
|
||||
]
|
||||
|
||||
# Classes
|
||||
angular.module('News').factory 'Cache',
|
||||
['_Cache', 'FeedType', 'FeedModel', 'FolderModel',
|
||||
(_Cache, FeedType, FeedModel, FolderModel) ->
|
||||
return new _Cache(FeedType, FeedModel, FolderModel)
|
||||
]
|
||||
|
||||
angular.module('News').factory 'PersistenceNews',
|
||||
['_PersistenceNews', '$http', '$rootScope', 'Loading', 'Publisher',
|
||||
(_PersistenceNews, $http, $rootScope, Loading, Publisher) ->
|
||||
return new _PersistenceNews($http, $rootScope, Loading, Publisher)
|
||||
]
|
||||
|
||||
angular.module('News').factory 'GarbageRegistry',
|
||||
['_GarbageRegistry', 'ItemModel',
|
||||
(_GarbageRegistry, ItemModel) ->
|
||||
return new _GarbageRegistry(ItemModel)
|
||||
]
|
||||
|
||||
angular.module('News').factory 'Publisher',
|
||||
['_Publisher', (_Publisher) ->
|
||||
return new _Publisher()
|
||||
]
|
||||
|
||||
angular.module('News').factory 'OPMLParser',
|
||||
['_OPMLParser', (_OPMLParser) ->
|
||||
return new _OPMLParser()
|
||||
]
|
|
@ -1,27 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_ShowAll', ->
|
||||
|
||||
class ShowAll
|
||||
|
||||
constructor: ->
|
||||
@showAll = false
|
||||
|
||||
handle: (data) ->
|
||||
@showAll = data
|
||||
|
||||
|
||||
return ShowAll
|
|
@ -1,28 +0,0 @@
|
|||
###
|
||||
# ownCloud news app
|
||||
#
|
||||
# @author Alessandro Cosentino
|
||||
# @author Bernhard Posselt
|
||||
# Copyright (c) 2012 - Alessandro Cosentino <cosenal@gmail.com>
|
||||
# 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('News').factory '_StarredCount', ->
|
||||
|
||||
class StarredCount
|
||||
|
||||
constructor: ->
|
||||
@count = 0
|
||||
|
||||
|
||||
handle: (data) ->
|
||||
@count = data
|
||||
|
||||
|
||||
return StarredCount
|
Двоичные данные
doc/.mapper spec.md.kate-swp
Двоичные данные
doc/.mapper spec.md.kate-swp
Двоичный файл не отображается.
|
@ -1,81 +0,0 @@
|
|||
# GUI Specification
|
||||
|
||||
This should be a document which specifies the GUI for testing purposes.
|
||||
|
||||
**This specification is not yet final and only reflects the current state**
|
||||
|
||||
## General
|
||||
* When the programs is being launched the last viewed feed is being loaded by default
|
||||
|
||||
## Feed List
|
||||
* You can click on the following entries:
|
||||
* folders that contain feeds
|
||||
* starred
|
||||
* new articles
|
||||
|
||||
* When you click on a feed or folder it should:
|
||||
* get the css class 'active'
|
||||
* load the folder or feed into the right view
|
||||
|
||||
* When you hover over a feed it should:
|
||||
* show a css hint that you hovered over it
|
||||
* show the delete and mark all read button
|
||||
|
||||
* When you hover over a folder it should:
|
||||
* show a css hint that you hovered over it
|
||||
* show the edit, delete, mark all read button
|
||||
|
||||
* When you hover over a folder with feeds it should:
|
||||
* show the collapse/open button (open button if opened, collapse button if collapsed
|
||||
|
||||
* When an entry has only read items it should have the all_read class
|
||||
|
||||
## Controls
|
||||
* When you click on the plus button it should show a Menu which shows Feed and Folder
|
||||
|
||||
* When you click on the Settings symbol it should show the settings popup
|
||||
|
||||
* When you click on the eye symbol it should toggle the SHOW_ALL and SHOW_UNREAD mode
|
||||
|
||||
## Modes
|
||||
|
||||
### SHOW_ALL
|
||||
* When you activate it it should
|
||||
* Tell the server that its activated
|
||||
* Empty the cache and reload the current items
|
||||
* Show all feeds and folders in the feedlist
|
||||
* Show all items in the itemslist
|
||||
* Change the title of the eye button to "Show everything"
|
||||
* Show empty folders
|
||||
|
||||
* When you click on a feed load read and unread items and show items with the read class
|
||||
|
||||
### SHOW_UNREAD
|
||||
* When you activate it it should
|
||||
* Tell the server that its activated
|
||||
* Empty the cache and reload the current items
|
||||
* Hide all feeds with all_read class in the feedlist. If all feeds of a folder are all_read, hide the folder.
|
||||
* Hide empty folders
|
||||
* Hide all items with read class in the itemslist
|
||||
* Change the title of the eye button to "Show only unread"
|
||||
* When the feed is selected (active class) and has the all_read class dont hide it and neither hide its parent folder but do so if it is deselected
|
||||
|
||||
* When you click on a feed only unread items and hide items with the read class
|
||||
|
||||
## Items
|
||||
* Hover over a item should show the bottom util bar (keep unread)
|
||||
|
||||
* Click on the starred item should make it starred (add the class important) and tell the server that its starred and increase the unread count for starred items by 1
|
||||
|
||||
* Click on the header link or
|
||||
Click on the text body or
|
||||
Scrolling a feed beyond the top edge
|
||||
* should mark it as read (add css read class) and tell the server that its marked read and decrease the unread count of the item and its top folder and unread articles by 1
|
||||
|
||||
|
||||
* click on keep unread text or keep unread checkbox should
|
||||
* **When not marked yet**:
|
||||
* tell the server to make it unread
|
||||
* prevent it from being marked read
|
||||
* **When marked yet**:
|
||||
* dont prevent it from being marked read
|
|
@ -1,31 +0,0 @@
|
|||
|
||||
request: get just starred items of a user
|
||||
SELECT * FROM items
|
||||
WHERE user_id = ? AND status = ?
|
||||
(AND id < ? LIMIT ?)
|
||||
(AND items.lastmodified >= ?)
|
||||
|
||||
request: get all items of a user (unread and read)
|
||||
SELECT * FROM items
|
||||
WHERE user_id = ? AND status = ?
|
||||
(AND id < ? LIMIT ?)
|
||||
(AND items.lastmodified >= ?)
|
||||
|
||||
request: get all items of a folder of a user (unread and read)
|
||||
SELECT * FROM items
|
||||
JOIN feeds
|
||||
ON feed.id = feed_id
|
||||
WHERE user_id = ? AND status = ? AND feed.folder_id = ?
|
||||
(AND id < ? LIMIT ?)
|
||||
(AND items.lastmodified >= ?)
|
||||
|
||||
|
||||
request: get all items of a feed of a user (unread and read)
|
||||
SELECT * FROM items
|
||||
WHERE user_id = ? AND status = ? AND feed_id = ?
|
||||
(AND id < ? LIMIT ?)
|
||||
(AND items.lastmodified >= ?)
|
||||
|
||||
|
||||
all requests: can be specified using an (offset (id), limit) or (updatedSince (timestamp))
|
||||
|
Загрузка…
Ссылка в новой задаче