1. 18 Dec, 2015 1 commit
    • Robert Knight's avatar
      Consolidate /app and /app/features endpoints · 6d10a5eb
      Robert Knight authored
      Experience has taught us that the client needs the session
      data (current user, list of groups) and set of enabled feature
      flags at the same time, and also needs to invalidate them
      in the same scenarios (eg. account switching).
      
      Fetching this data via two separate requests made it more complicated
      to ensure the client had a consistent view of session and feature-flag
      data. To simplify things and also same a network request:
      
       * On the server, put the feature flag data into the session data payload.
      
       * On the client, use the existing central storage and cache management
         for the session data payload to manage feature flags as well.
      
         The features service now becomes a thin wrapper around part of
         the session state.
      6d10a5eb
  2. 16 Dec, 2015 1 commit
  3. 15 Dec, 2015 3 commits
  4. 14 Dec, 2015 35 commits
    • Robert Knight's avatar
      Merge pull request #2800 from hypothesis/2799-dont-update-wrong-annotations · d1c0b894
      Robert Knight authored
      Don't update annotations with contents of others
      d1c0b894
    • Sean Hammond's avatar
      Don't update annotations with contents of others · b96d1749
      Sean Hammond authored
      When listening to the 'annotationUpdated' event, AnnotationController
      needs to check that it's this annotation that the event refers to before
      acting on it.
      
      Fixes #2799.
      b96d1749
    • Robert Knight's avatar
      Merge pull request #2781 from hypothesis/AnnotationController-domain-model-view-model-refactor · 9b3ef75c
      Robert Knight authored
      Annotation controller domain model view model refactor
      9b3ef75c
    • Sean Hammond's avatar
      Delete an out-of-date comment · 2874e51a
      Sean Hammond authored
      2874e51a
    • Sean Hammond's avatar
      Don't document @returns undefined · 8183f821
      Sean Hammond authored
      8183f821
    • Sean Hammond's avatar
      Fix annotating while signed out · 5d198168
      Sean Hammond authored
      If the user creates annotations while signed out and then signs in, we
      want those annotations to still be present in the sidebar after sign in,
      rather than being lost.
      
      Commit 7a1b5ca8d99252d3a086a8a8103fca4702521d06 had inadvertently broken
      this.
      
      The problem is that app.coffee destroys all AnnotationController
      instances on sign in, and only creates new instances for those
      annotations that have drafts.
      
      7a1b5ca8d99252d3a086a8a8103fca4702521d06 removed a spurious call to
      saveToDrafts() in vm.edit() but it turns out that this call was
      (apparently inadvertently) the only thing that was causing drafts of
      annotations created while signed out to be saved, and hence the only
      thing causing these annotations to persist across sign ins.
      
      So add a listener for the USER_CHANGED event and save drafts of
      annotations on sign in, just before the AnnotationControllers get
      destroyed.
      5d198168
    • Sean Hammond's avatar
      Remove a couple of duplicate comments · 67e127e0
      Sean Hammond authored
      67e127e0
    • Sean Hammond's avatar
      Update AnnotationController on annotationUpdated · 56e99757
      Sean Hammond authored
      Update AnnotationController's view model on the "annotationUpdated" event.
      
      This fixes an issue that "live updates" were not being shown on annotation
      cards.
      
      The "annotationUpdated" event is fired by AnnotationController itself after
      successfully saving updates to an already-saved annotation. It's also fired by
      annotationMapper after received an updated annotation from the server (that was
      updated by a different client - the "live updates" feature).
      
      Subscribing to this event allows one function in AnnotationController to handle
      updating the view model in both cases.
      56e99757
    • Sean Hammond's avatar
      Update view model after save · ac8e5483
      Sean Hammond authored
      Update AnnotationController's view model (vm) after successfully saving
      a new annotation to the server for the first time.
      
      This fixes two issues:
      
      1. vm.annotationURI (which depends on the annotation's id, which is not
      present until the save to the server succeeds) was not being set
      correctly after successful save, so the annotation permalinks were not
      correct until you reload them.
      
      2. If you created a highlight while logged out, then logged in,
      (AnnotationController automatically saves the highlight to the server
      for you on login) the "Only Me" icon was not being shown on the
      highlight until you reloaded it because vm.isPrivate wasn't set.
      ac8e5483
    • Sean Hammond's avatar
      Only call drafts at the correct times · 76ed603a
      Sean Hammond authored
      We only need to save an annotation to drafts when the focused group
      changes while editing it, and not at other times (e.g. when opening the
      editor??).
      
      We only need to restore an annotation from drafts when editing it, and
      not at other random times.
      
      Also, don't call updateViewModel() in init() after calling edit(),
      because this will overwrite the draft changes that you just restored.
      76ed603a
    • Sean Hammond's avatar
      Don't change domainModel.group on group focused · fe565c8a
      Sean Hammond authored
      Don't change the value of domainModel.group when the focused group changes.
      
      Instead, change it to groups.focusedGroup() in updatedDomainModel() before the
      annotation is sent to the server.
      
      This fits with the idea that domainModel is a read-only copy of the annotation
      that we received from the server, and vm is the read-write copy. But there's no
      vm.group as this would always be the same as groups.focusedGroup().
      fe565c8a
    • Sean Hammond's avatar
      Add vm.isPrivate boolean · 1f4718b7
      Sean Hammond authored
      Recent changes broke the reverting of unsaved changes to annotations
      (AnnotationController.vm.revert()) when the user presses the _Cancel_ button on
      the annotation editor. The annotation's privacy was not being restored to its
      previously saved value.
      
      We can't set domainModel.permissions when the user changes the privacy of an
      annotation that they're editing, because if the user clicks _Cancel_ we need
      to revert the privacy back to its previous value (which we've just overwriten).
      
      So instead add a new vm.isPrivate boolean and set that instead:
      
      - vm.isPrivate() method (which returned true or false based on the value of
        domainModel.permissions) is replaced with a vm.isPrivate boolean.
      
      - updateViewModel() now sets vm.isPrivate according to the value of
        domainModel.permissions.
      
      - updatedDomainModel() nows sets domainModel.permissions according to the
        value of vm.isPrivate.
      
      - setPrivacy() nows sets vm.isPrivate instead of domainModel.permissions.
      
      - We no longer change domainModel.permissions when the focused group
        changes (it will continue to hold shared permissions for the previous group,
        but these will be updated by updatedDomainModel() before saving them to the
        server).
      
        vm.isPrivate doesn't need to be changed when the focused group changes
        because its value is independent of the focused group.
      
      - saveToDrafts() now saves vm.isPrivate instead of vm.isPrivate()
      
      - restoreFromDrafts() now restores vm.isPrivate instead of
        domainModel.permissions
      1f4718b7
    • Sean Hammond's avatar
      Simplify storage of draft tags · fa12712c
      Sean Hammond authored
      These were being converted from view model to domain model format before
      being stored in drafts, and back again after being retrieved, which of
      course is pointless.
      fa12712c
    • Sean Hammond's avatar
      Insert spaces · 139a2313
      Sean Hammond authored
      139a2313
    • Sean Hammond's avatar
      Tweak the drafts.update() API · 8a39bb77
      Sean Hammond authored
      8a39bb77
    • Sean Hammond's avatar
      Add trailing comma · 0b7c3122
      Sean Hammond authored
      0b7c3122
    • Sean Hammond's avatar
      Rename private -> isPrivate · bdff3874
      Sean Hammond authored
      bdff3874
    • Sean Hammond's avatar
      Correct a docstring · 18833085
      Sean Hammond authored
      18833085
    • Sean Hammond's avatar
      Simplify a boolean return · c9f74e9a
      Sean Hammond authored
      c9f74e9a
    • Sean Hammond's avatar
      Simplify a boolean return · 77d7008e
      Sean Hammond authored
      77d7008e
    • Sean Hammond's avatar
      Change vm.document to vm.document() · e282ebe3
      Sean Hammond authored
      vm.document was a variable containing data duplicated from domainModel (not an
      exact copy, but data extracted from domainModel anyway).
      
      It's just easier to have a method for getting this - saves having to manage
      another variable and update it at the correct times.
      
      In making this change I noticed that there were several tests for
      updateViewModel() that were actually tests for extractDocumentMetadata()
      (which updateViewModel() was calling). These tests are no longer valud since
      updateViewModel() no longer calls extractDocumentMetadata(), and there are
      already duplicate unit tests of extractDocumentMetadata() itself.
      
      This leaves the describe('updateViewModel()') empty of tests, and since
      updateViewModel() is now pretty trivial, I decided just to delete the
      describe() rather then leave it empty or think up some tests to add to it.
      e282ebe3
    • Sean Hammond's avatar
      Remove a docstring description · 872626f6
      Sean Hammond authored
      I'm not sure this description adds much, and the comment about using
      annotationMapper for persistence is wrong.
      872626f6
    • Sean Hammond's avatar
      Remove vm.annotation -> vm.form · bf4a07a1
      Sean Hammond authored
      Clarify what this object actually is: the read-write variables for the
      templates to write via ng-model.
      bf4a07a1
    • Sean Hammond's avatar
      Remove vm.tags · d1bd2b9a
      Sean Hammond authored
      This variable is just duplication of vm.annotation.tags and is not used by the
      templates.
      d1bd2b9a
    • Sean Hammond's avatar
      Fix a bug when changing the privacy of an annotation · bd337f28
      Sean Hammond authored
      A bug had crept in where if you changed the privacy of an annotation
      that you were creating or editing (by changing the selection in the
      _Post_ dropdown) then the privacy would not change and your text and tags edits
      would be deleted.
      
      This was happening because when you change the selection in the Post
      dropdown then onSetPrivacy() makes a change to the domain model which
      triggers onDomainModelChange() which copies the domainModel over
      vm.annotation, overwriting your changes.
      
      To fix this get rid of onDomainModelChange(). These sorts of functions
      (ones that are triggered by events or changes) create confusion by
      making it difficult to predict or trace the flow of execution, and I
      can't see why onDomainModelChange() needs to exist.
      
      This does deliberately remove one feature:
      
      If you had saved edits for an annotation in the drafts service (for
      example if you edited an annotation, made some changes, then changed the
      focus to a different group without saving the annotation) and _then_
      someone using a different instance of the client (e.g. yourself on a
      different device, I guess) saved a change to that same annotation to the
      server, then this change would be communicated from the server to the
      first client (via the WebSocket I guess) and the first client would
      *delete your saved edits from the drafts service*.
      
      This behaviour was deliberate but I'm not sure why it was considered a
      good idea, and removing it simplifies things.
      bd337f28
    • Sean Hammond's avatar
      Deduplicate and correct "is reply" code · e7f099c6
      Sean Hammond authored
      Deduplicate and correct code in AnnotationController for deciding
      whether an annotation is a reply.
      e7f099c6
    • Sean Hammond's avatar
      Minimize what data is stored in vm.annotation · 60966d3a
      Sean Hammond authored
      Remove all the properties that don't need to be in vm.annotation from
      vm.annotation.
      
      This means removing all the read-only properties (id, target, updated, user)
      and leaving only the read-write ones that the templates write via `ng-model`
      (vm.annotation.tags and vm.annotation.text).
      
      The templates still do need read-only access to id, target, updated and user,
      but rather than _duplicating_ these values by copying them from domainModel
      to vm.annotation, instead add accessor methods vm.id() etc that just return
      the values from domainModel.
      
      This has two advantages:
      
      1. Data is not duplicated between domainModel and vm.annotation.
      2. It's clear that these fields are read-only, since the templates literally
         can't write them, at least in the case of id, user and updated
      
         target is unfortunately a mutable object so the templates could still
         mutate it. vm.target() could return a copy to avoid this but I haven't gone
         that far.
      60966d3a
    • Sean Hammond's avatar
      Validate domainModel not vm.annotation · c32fedcd
      Sean Hammond authored
      When saving an annotation to the server, the object that we actually send to
      the server is:
      
      1. `domainModel`, after being updated by `updateDomainModel()`, in the case
         of creating a new annotation, or
      
      2. The temporary local variable `updatedDomainModel` in the case of editing
         an existing annotation
      
      `vm.annotation` is never the object that gets sent to the server.
      
      So pass `domainModel` or `updatedDomainModel` to `validate()`, not
      `vm.annotation`.
      c32fedcd
    • Sean Hammond's avatar
      Separate updating view model from restoring draft · 803aaa6b
      Sean Hammond authored
      Separate updateViewModel() and restoreFromDrafts() into two separate functions.
      803aaa6b
    • Sean Hammond's avatar
      Lint · 6a7e7964
      Sean Hammond authored
      6a7e7964
    • Sean Hammond's avatar
      Make what's stored in drafts explicit · 743b28dc
      Sean Hammond authored
      Explicitly store `private` (boolean), `tags` (array of strings) and `text`
      (string) in drafts instead of a "black box" `changes` object.
      
      Also rename the updateDraft() function to saveToDrafts() and move it out of
      AnnotationController.
      743b28dc
    • Sean Hammond's avatar
      Extract domainModel<->vm tags translation · 3178f917
      Sean Hammond authored
      Extract the translation of tags in AnnotationController from domainModel.tags
      format to vm.tags format and vice-versa into functions.
      
      This is for clarity, and so that the transformations can be used in multiple
      places in the code without duplication.
      3178f917
    • Sean Hammond's avatar
      Be explicit about what goes into vm.annotation · 0e3d3921
      Sean Hammond authored
      Copy individual properties into vm.annotation explicitly, instead of blindly
      copying all of domainModel into it. This allows us to see what's in there and
      start making decisions about what should/shouldn't be in there.
      0e3d3921
    • Sean Hammond's avatar
      Fix AnnotationController permissions validation · 0fd89fbf
      Sean Hammond authored
      Since vm.annotation.permissions is (soon) no longer going to be used,
      don't validate it in validate(), validate model.permissions instead.
      0fd89fbf
    • Sean Hammond's avatar
      f70fa0b2