Skip to content

Commit

Permalink
Fix display and update of the privacy selector
Browse files Browse the repository at this point in the history
This commit reworks the privacy directive in order to make management of
the privacy state of individual annotations (and their privacy dropdown)
much clearer. It fixes a bug where the privacy dropdown didn't make any
distinction between publishing to a group and publishing to "world".

In addition, it makes the implementation of the groups dropdown more
consistent with the rest of the application.
  • Loading branch information
nickstenning committed Sep 11, 2015
1 parent dc76973 commit 9be6890
Show file tree
Hide file tree
Showing 21 changed files with 605 additions and 537 deletions.
1 change: 1 addition & 0 deletions h/assets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ app_js:
- h:static/scripts/*.coffee
- h:static/scripts/auth.js
- h:static/scripts/features.js
- h:static/scripts/groups.js
- h:static/scripts/session.js
- h:static/scripts/service-url.js
- h:static/scripts/directive/*.coffee
Expand Down
6 changes: 3 additions & 3 deletions h/static/scripts/app.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ module.exports = angular.module('h', [
.controller('AnnotationViewerController', require('./annotation-viewer-controller'))
.controller('StreamController', require('./stream-controller'))
.controller('WidgetController', require('./widget-controller'))
.controller('GroupListController', require('./group-list-controller'))

.directive('annotation', require('./directive/annotation'))
.directive('deepCount', require('./directive/deep-count'))
.directive('formInput', require('./directive/form-input'))
.directive('formValidate', require('./directive/form-validate'))
.directive('groupList', require('./directive/group-list'))
.directive('markdown', require('./directive/markdown'))
.directive('privacy', require('./directive/privacy'))
.directive('privacy', require('./directive/privacy').directive)
.directive('simpleSearch', require('./directive/simple-search'))
.directive('statusButton', require('./directive/status-button'))
.directive('thread', require('./directive/thread'))
Expand Down Expand Up @@ -117,6 +117,7 @@ module.exports = angular.module('h', [
.service('features', require('./features'))
.service('flash', require('./flash'))
.service('formRespond', require('./form-respond'))
.service('groups', require('./groups'))
.service('host', require('./host'))
.service('localStorage', require('./local-storage'))
.service('permissions', require('./permissions'))
Expand All @@ -135,7 +136,6 @@ module.exports = angular.module('h', [
.service('viewFilter', require('./view-filter'))

.factory('serviceUrl', require('./service-url'))
.factory('group', require('./group-service'))

.value('AnnotationSync', require('./annotation-sync'))
.value('AnnotationUISync', require('./annotation-ui-sync'))
Expand Down
18 changes: 11 additions & 7 deletions h/static/scripts/directive/annotation.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ errorMessage = (reason) ->
AnnotationController = [
'$scope', '$timeout', '$q', '$rootScope', '$document',
'drafts', 'flash', 'permissions', 'tags', 'time',
'annotationUI', 'annotationMapper', 'session', 'group'
'annotationUI', 'annotationMapper', 'session', 'groups'
($scope, $timeout, $q, $rootScope, $document,
drafts, flash, permissions, tags, time,
annotationUI, annotationMapper, session, group) ->
annotationUI, annotationMapper, session, groups) ->

@annotation = {}
@action = 'view'
Expand All @@ -56,17 +56,24 @@ AnnotationController = [
@embedded = false
@hasDiff = false
@showDiff = undefined
@privacyLevel = null
@timestamp = null

model = $scope.annotationGet()
if not model.group
model.group = group.focusedGroup().id
model.group = groups.focused().id

highlight = model.$highlight
original = null
vm = this

###*
# @ngdoc method
# @name annotation.AnnotationController#group.
# @returns {Object} The full group object associated with the annotation.
###
this.group = ->
groups.get(model.group)

###*
# @ngdoc method
# @name annotation.AnnotationController#tagsAutoComplete.
Expand Down Expand Up @@ -166,9 +173,6 @@ AnnotationController = [
this.render()
this.view()

this.group = ->
group.getGroup(model.group)

# Calculates the visual diff flags from the targets
#
# hasDiff is set to true is there are any targets with a difference
Expand Down
11 changes: 7 additions & 4 deletions h/static/scripts/directive/group-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
* @restrict AE
* @description Displays a list of groups of which the user is a member.
*/
module.exports = function () {

// @ngInject
module.exports = function (groups) {
return {
restrict: 'AE',
scope: {
groups: '='
link: function (scope, elem, attrs) {
scope.groups = groups;
},
restrict: 'AE',
scope: {},
templateUrl: 'group_list.html'
};
};
77 changes: 0 additions & 77 deletions h/static/scripts/directive/privacy.coffee

This file was deleted.

152 changes: 152 additions & 0 deletions h/static/scripts/directive/privacy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
'use strict';

// This is called visibility for backwards compatibility
var STORAGE_KEY = 'hypothesis.visibility';

var PUBLIC = 'public';
var PRIVATE = 'private';


// Return a descriptor object for the passed group.
function describeGroup(group) {
var type;
if (group.public) {
type = 'public';
} else {
type = 'group';
}
return {
name: group.name,
type: type
};
}


// Determine the privacy level for an annotation with permissions and group
// fields as passed. If the permissions object is empty, return null.
function annotationLevel(permissions, group) {
if (permissions === null || typeof permissions === 'undefined') {
return null;
}
if (permissions.read === null || typeof permissions.read === 'undefined') {
return null;
}

var entry;
if (group === null || typeof group === 'undefined') {
entry = 'group:__world__';
} else {
entry = 'group:' + group;
}
if (permissions.read.indexOf(entry) !== -1) {
return PUBLIC;
} else {
return PRIVATE;
}
}


// @ngInject
function PrivacyController($scope, groups, localStorage, permissions) {
this._level = null;

/**
* @ngdoc method
* @name PrivacyController#level
*
* Returns the current privacy level descriptor.
*/
this.level = function () {
// If the privacy level isn't set yet, we first try and set it from the
// annotation model
if (this._level === null) {
this._level = annotationLevel($scope.model.permissions,
$scope.model.group);
}

// If the privacy level still isn't set, try and retrieve it from
// localStorage, falling back to public.
if (this._level === null) {
var fromStorage = localStorage.getItem(STORAGE_KEY);
if ([PUBLIC, PRIVATE].indexOf(fromStorage) !== -1) {
this._level = fromStorage;
} else {
this._level = PUBLIC;
}
}

if (this._level === PUBLIC) {
return this.public();
}
return this.private();
};

/**
* @ngdoc method
* @name PrivacyController#setLevel
*
* @param {String} level
*
* Sets the current privacy level. `level` may be either 'private' or
* 'public'.
*/
this.setLevel = function (level) {
if (level === PUBLIC) {
this._level = PUBLIC;
localStorage.setItem(STORAGE_KEY, PUBLIC);
$scope.model.permissions = permissions.public($scope.model.group);
} else if (level === PRIVATE) {
this._level = PRIVATE;
localStorage.setItem(STORAGE_KEY, PRIVATE);
$scope.model.permissions = permissions.private();
}
};

/**
* @ngdoc method
* @name PrivacyController#public
*
* Returns a descriptor object for the current 'public' privacy level.
*/
this.public = function () {
// If the annotation has a group set on it, then return the data for that
// group, otherwise just use the currently-focused group.
if ($scope.model.group) {
return describeGroup(groups.get($scope.model.group));
} else {
return describeGroup(groups.focused());
}
};

/**
* @ngdoc method
* @name PrivacyController#private
*
* Returns a descriptor object for the current 'private' privacy level.
*/
this.private = function () {
return {
name: 'Only Me',
type: 'private'
};
};

return this;
}


var directive = function () {
return {
controller: PrivacyController,
controllerAs: 'vm',
restrict: 'E',
scope: {
model: '='
},
templateUrl: 'privacy.html'
};
};


exports.PrivacyController = PrivacyController;
exports.directive = directive;
Loading

0 comments on commit 9be6890

Please sign in to comment.