FeedBunch-app/app/assets/javascripts/ng-services/ng-LoadFeedsSvc.js.coffee.erb
########################################################
# AngularJS service to load feeds
########################################################
angular.module('feedbunch').service 'loadFeedsSvc',
['$rootScope', 'feedsPaginationSvc', 'favicoSvc', 'animationsSvc', 'timerFlagSvc', 'cleanupSvc', 'findSvc',
'csrfTokenSvc',
($rootScope, feedsPaginationSvc, favicoSvc, animationsSvc, timerFlagSvc, cleanupSvc, findSvc,
csrfTokenSvc)->
# Maximum number of feeds in each page.
# This MUST match the feeds page size set in the server!
feeds_page_size = 25
# Constants for the different operations the web worker can perform
LOAD_FEED = 'load_feed'
LOAD_FEEDS = 'load_feeds'
LOAD_FOLDER_FEEDS = 'load_folder_feeds'
# CSRF token
token = csrfTokenSvc.get_token()
# Web worker to load feeds
worker = new Worker '<%= asset_path 'workers/load_feeds_worker' %>'
worker.onmessage = (e) ->
if e.data.status == 200 || e.data.status == 304
if e.data.operation == LOAD_FEED
feed_loaded e.data.params, e.data.response
else if e.data.operation == LOAD_FEEDS
feeds_page_loaded e.data.params, e.data.response
else if e.data.operation == LOAD_FOLDER_FEEDS
folder_feeds_loaded e.data.params, e.data.response
else if e.data.status == 401 || e.data.status == 422
$window.location.href = '/login'
else
if e.data.operation == LOAD_FEED
feed_loading_error e.data.params, e.data.status
else if e.data.operation == LOAD_FEEDS
feeds_page_loading_error e.data.params, e.data.status
else if e.data.operation == LOAD_FOLDER_FEEDS
folder_feeds_loading_error e.data.params, e.data.status
$rootScope.$digest()
#--------------------------------------------
# PRIVATE FUNCTION: Operations after a single feed has been loaded
#--------------------------------------------
feed_loaded = (params, response)->
feed_id = params.feed_id
# Remove the flag indicating that this feed is loading
delete $rootScope.loading_single_feed[feed_id]
add_feed response
favicoSvc.update_unread_badge()
#--------------------------------------------
# PRIVATE FUNCTION: Operations after loading a single feed finishes with an error
#--------------------------------------------
feed_loading_error = (params, status)->
id = params.feed_id
delete $rootScope.loading_single_feed[id]
if status == 404
cleanupSvc.remove_feed id
else
timerFlagSvc.start 'error_loading_feeds'
#--------------------------------------------
# PRIVATE FUNCTION: Operations after a page of feeds has been loaded
#--------------------------------------------
feeds_page_loaded = (params, response)->
feedsPaginationSvc.load_feeds_page page, response.slice()
feedsPaginationSvc.set_busy false
# Load the next page of feeds until no more feeds are available
if response.length < feeds_page_size
# there are no more pages of feeds to retrieve
$rootScope.feeds_loaded = true
feedsPaginationSvc.pagination_finished()
favicoSvc.update_unread_badge()
animationsSvc.show_stats()
else
# There is probably at least one more page of feeds available
page = params.page
load_feeds page
#--------------------------------------------
# PRIVATE FUNCTION: Operations after loading a page of feeds finishes with an error
#--------------------------------------------
feeds_page_loading_error = (params, status)->
$rootScope.feeds_loaded = true
feedsPaginationSvc.set_busy false
if status == 404
# if a 404 is returned for the first page, there are no feeds at all. Set all unread counts to zero.
if params.page == 1
if $rootScope.feeds && $rootScope.feeds?.length > 0
for feed in $rootScope.feeds
feed.unread_entries = 0
# If a 404 is returned in a page >1, there are no more feeds and this is the last page.
else
feedsPaginationSvc.pagination_finished()
favicoSvc.update_unread_badge()
animationsSvc.show_stats()
else
timerFlagSvc.start 'error_loading_feeds'
#--------------------------------------------
# PRIVATE FUNCTION: Operations after feeds in a folder have been loaded
#--------------------------------------------
folder_feeds_loaded = (params, response)->
delete $rootScope.loading_single_folder_feeds[params.folder_id]
# Update unread counts with the received feeds. Set the unread counter for any feed in the folder but
# not in the received JSON to zero.
folder = findSvc.find_folder params.folder_id
update_folder_feeds folder, response.slice()
#--------------------------------------------
# PRIVATE FUNCTION: Operations after loading feeds in a folder finishes with an error
#--------------------------------------------
folder_feeds_loading_error = (params, status)->
id = params.folder_id
delete $rootScope.loading_single_folder_feeds[id]
if status == 404
# If the server returns a 404, there are no feeds to return; set unread count to zero for all feeds in the folder.
folder = findSvc.find_folder id
update_folder_feeds folder, null
else
timerFlagSvc.start 'error_loading_folders'
#--------------------------------------------
# PRIVATE FUNCTION: Load feeds. Depending on the value of the flag "show_read" it
# will load all feeds (if true) or only feeds with unread entries (if false).
#--------------------------------------------
load_feeds = (page=0)->
# If busy, do nothing
return if feedsPaginationSvc.is_busy()
# Indicate that AJAX request/response cycle is busy so no more calls are done until finished
feedsPaginationSvc.set_busy true
page += 1
worker.postMessage {operation: LOAD_FEEDS, token: token, show_read: $rootScope.show_read, page: page}
#--------------------------------------------
# PRIVATE FUNCTION: Load a single feed. Receives its id as argument.
#--------------------------------------------
load_feed = (id)->
# If feed pagination is busy, do nothing
# This keeps from trying to load a single feed while the list of feeds is loading.
return if feedsPaginationSvc.is_busy()
# If this feed is already being loaded, do nothing
$rootScope.loading_single_feed ||= {}
return if $rootScope.loading_single_feed[id]
$rootScope.loading_single_feed[id] = true
worker.postMessage {operation: LOAD_FEED, token: token, feed_id: id}
#---------------------------------------------
# PRIVATE FUNCTION: Push a feed in the feeds array if it isn't already present there.
#
# If the feeds array has not been created in the root scope, create it.
#
# If the feed is already in the feeds array, its unread_entries attribute is updated instead of
# pushing it in the array again.
#---------------------------------------------
add_feed = (feed)->
if !$rootScope.feeds || $rootScope.feeds?.length == 0
$rootScope.feeds = [feed]
else
feed_old = findSvc.find_feed feed.id
if feed_old?
feed_old.unread_entries = feed.unread_entries
else
$rootScope.feeds.push feed
#--------------------------------------------
# PRIVATE FUNCTION: Load feeds inside a single folder. Receives the folder as argument.
#--------------------------------------------
load_folder_feeds = (folder)->
# If feeds in this folder are already being loaded, do nothing
$rootScope.loading_single_folder_feeds ||= {}
return if $rootScope.loading_single_folder_feeds[folder.id]
$rootScope.loading_single_folder_feeds[folder.id] = true
worker.postMessage {operation: LOAD_FOLDER_FEEDS, token: token, folder_id: folder.id, show_read: $rootScope.show_read}
#---------------------------------------------
# PRIVATE FUNCTION: Update the feeds and their unread counts, for feeds in a folder.
#
# Receives as arguments the folder and an array of feeds.
#
# Operations in the scope:
# The unread_count for each feed passed in the array is updated with the value passed in the array.
# Those feeds in the folder which are not present in the passed array will have their unread_count set to zero.
#
# NOTE.- If a null is passed in the feeds argument, all feeds in the folder will have their unread counts set to zero.
#---------------------------------------------
update_folder_feeds = (folder, feeds)->
# Set unread count for all feeds in the folder to zero, then set the actual received value for each feed.
# Those feeds not present in the received JSON will be set to zero.
feeds_in_folder = findSvc.find_folder_feeds folder
for feed in feeds_in_folder
feed.unread_entries = 0
if feeds? && feeds?.length > 0
for feed in feeds
add_feed feed
service =
#---------------------------------------------
# Load a single feed
#---------------------------------------------
load_feed: load_feed
#---------------------------------------------
# Load all feeds
#---------------------------------------------
load_feeds: load_feeds
#---------------------------------------------
# Load feeds in a single folder via AJAX into the root scope.
#---------------------------------------------
load_folder_feeds: (folder)->
# If passed folder is "all", load all feeds in a paginated fashion.
if folder=='all' || folder?.id == 'all'
load_feeds()
# If any other folder is passed, load feeds in that folder only (not paginated)
else
load_folder_feeds folder
return service
]