amatriain/feedbunch

View on GitHub
FeedBunch-app/app/assets/javascripts/ng-services/ng-EntrySvc.js.coffee.erb

Summary

Maintainability
Test Coverage
########################################################
# AngularJS service to manage entries
########################################################

angular.module('feedbunch').service 'entrySvc',
['$rootScope', '$window', 'openEntrySvc', 'timerFlagSvc', 'changeUnreadCountSvc',
'currentFolderSvc', 'currentFeedSvc', 'findSvc', 'loadEntriesSvc', 'feedsFoldersTimerSvc', 'loadFeedsSvc',
'lazyLoadingSvc', 'tourSvc', 'animationsSvc', 'menuCollapseSvc', 'csrfTokenSvc',
($rootScope, $window, openEntrySvc, timerFlagSvc, changeUnreadCountSvc,
currentFolderSvc, currentFeedSvc, findSvc, loadEntriesSvc, feedsFoldersTimerSvc, loadFeedsSvc,
lazyLoadingSvc, tourSvc, animationsSvc, menuCollapseSvc, csrfTokenSvc)->

  # Constants for the different operations the web worker can perform
  CHANGE_SINGLE_ENTRY = 'change_single_entry'
  CHANGE_MULTIPLE_ENTRIES = 'change_multiple_entries'

  # CSRF token for POST
  token = csrfTokenSvc.get_token()

  # Web worker to change the state of entries in a different thread
  worker = new Worker '<%= asset_path 'workers/change_entry_state_worker' %>'
  worker.onmessage = (e) ->
    if e.data.status == 200
      feedsFoldersTimerSvc.reset_refresh_timer()
      if e.data.operation == CHANGE_SINGLE_ENTRY
        entry_state_changed e.data.params.entry.id
      else if e.data.operation == CHANGE_MULTIPLE_ENTRIES
        entries_states_changed()
    else if e.data.status == 401 || e.data.status == 422
      $window.location.href = '/login'
    else
      timerFlagSvc.start 'error_changing_entry_state'
    $rootScope.$digest()

  #--------------------------------------------
  # PRIVATE FUNCTION - Operations to perform after a single entry has changed state
  #--------------------------------------------
  entry_state_changed = (id)->
    entry = findSvc.find_entry id
    entry.changing_state = false if entry?

  #--------------------------------------------
  # PRIVATE FUNCTION - Operations to perform after multiple entries have changed state
  #--------------------------------------------
  entries_states_changed = ->
    for entry in $rootScope.entries
      entry.changing_state = false
    timerFlagSvc.start 'success_mark_all_read'

  #--------------------------------------------
  # PRIVATE FUNCTION - Mark a single entry as read or unread.
  # Receives as arguments an entry and a boolean indicating whether to mark
  # it as read (true) or unread (false).
  #--------------------------------------------
  change_entry_state = (entry, read)->
    # If entry is already in the requested state, nothing to be done
    if entry.read != read
      # Mark entry as read or unread in the model
      entry.read = read
      entry.changing_state = true

      if read
        state = "read"
        changeUnreadCountSvc.update_unread_count entry, false
      else
        state = "unread"
        changeUnreadCountSvc.update_unread_count entry, true

      # Change the entry state in a separate thread using a web worker
      worker.postMessage {operation: CHANGE_SINGLE_ENTRY, token: token, id: entry.id, state: state}

  #--------------------------------------------
  # PRIVATE FUNCTION - Set the feed with the passed ID as the currently selected one, and
  # load its list of entries
  #--------------------------------------------
  read_feed = (feed_id)->
    feed = findSvc.find_feed feed_id
    if feed?
      currentFeedSvc.set feed
      loadEntriesSvc.read_entries_page()

  #--------------------------------------------
  # PRIVATE FUNCTION - Mark all entries in the currently selected feed or folder as read.
  #--------------------------------------------
  change_entries_read = ->
    if $rootScope.entries && $rootScope.entries?.length > 0
      # Mark entries as read in the model
      first_entry = $rootScope.entries[0]
      for entry in $rootScope.entries
        entry.read = true
        entry.changing_state = true

      # Find out if the user wants to mark as read a whole feed, a whole folder, or all entries in
      # all subscribed feeds.
      current_feed = currentFeedSvc.get()
      current_folder = currentFolderSvc.get()
      if current_feed
        whole_feed = "true"
        whole_folder = "false"
        all_entries = "false"
        changeUnreadCountSvc.zero_feed_count current_feed.id
      else if current_folder && current_folder?.id != "all"
        whole_feed = "false"
        whole_folder = "true"
        all_entries = "false"
        changeUnreadCountSvc.zero_folder_count current_folder
      else if current_folder && current_folder?.id == "all"
        whole_feed = "false"
        whole_folder = "false"
        all_entries = "true"
        changeUnreadCountSvc.zero_folder_count 'all'
      else
        return

      # Change entries state in a separate thread using a web worker
      worker.postMessage {operation: CHANGE_MULTIPLE_ENTRIES, token: token, id: first_entry.id, state: 'read', whole_feed: whole_feed, whole_folder: whole_folder, all_entries: all_entries}

  service =

    #--------------------------------------------
    # Set (if opening) or unset (if closing) the currently open entry. If opening, mark it as read.
    # Receives as arguments:
    # - entry to be opened or closed
    #--------------------------------------------
    toggle_open_entry: (entry)->
      if entry?
        if openEntrySvc.is_open entry
          openEntrySvc.close entry
        else
          openEntrySvc.open entry
          change_entry_state entry, true
          lazyLoadingSvc.load_entry_images entry
          tourSvc.show_entry_tour()

    #--------------------------------------------
    # Mark a single entry as unread
    #--------------------------------------------
    read_entry: (entry)->
      if entry?
        change_entry_state entry, true if !entry.read

    #--------------------------------------------
    # Mark a single entry as unread
    #--------------------------------------------
    unread_entry: (entry)->
      if entry?
        change_entry_state entry, false if entry.read

    #--------------------------------------------
    # Mark all entries as read
    #--------------------------------------------
    mark_all_read: ->
      animationsSvc.highlight_read_all_button()
      menuCollapseSvc.close()
      change_entries_read()

    #--------------------------------------------
    # Return the title of the feed to which an entry belongs
    #--------------------------------------------
    entry_feed_title: (entry)->
      feed = findSvc.find_feed entry.feed_id
      if feed
        return feed.title
      else
        # If an entry is retrieved without a corresponding feed in the scope,
        # immediately load it from the server
        loadFeedsSvc.load_feed entry.feed_id
        return ''

  return service
]