Commit 5fa60d24 authored by Robert Knight's avatar Robert Knight

Convert `<annotation-share-dialog>` element directive to a component

As part of an effort to make it clearer how the client uses Angular,
register UI components with `component()` instead of `directive()`.

Components in Angular 1.x [1] are essentially directives with "best
practices" defaults set (restricted to elements, isolated scope, bound
to controller) and deprecated/discouraged features of $compile
disallowed. These defaults/restrictions match how we are already using
Angular for most UI components.

[1] See https://docs.angularjs.org/guide/component
parent 1c1d704c
...@@ -135,9 +135,10 @@ module.exports = angular.module('h', [ ...@@ -135,9 +135,10 @@ module.exports = angular.module('h', [
// The root component for the application // The root component for the application
.directive('hypothesisApp', require('./directive/app')) .directive('hypothesisApp', require('./directive/app'))
// UI components and helpers // UI components
.component('annotationShareDialog', require('./directive/annotation-share-dialog'))
.directive('annotation', require('./directive/annotation').directive) .directive('annotation', require('./directive/annotation').directive)
.directive('annotationShareDialog', require('./directive/annotation-share-dialog'))
.directive('annotationThread', require('./directive/annotation-thread')) .directive('annotationThread', require('./directive/annotation-thread'))
.directive('dropdownMenuBtn', require('./directive/dropdown-menu-btn')) .directive('dropdownMenuBtn', require('./directive/dropdown-menu-btn'))
.directive('excerpt', require('./directive/excerpt').directive) .directive('excerpt', require('./directive/excerpt').directive)
......
...@@ -4,73 +4,69 @@ var angular = require('angular'); ...@@ -4,73 +4,69 @@ var angular = require('angular');
var scopeTimeout = require('../util/scope-timeout'); var scopeTimeout = require('../util/scope-timeout');
module.exports = function () { module.exports = {
return { controllerAs: 'vm',
bindToController: true, template: require('../templates/annotation_share_dialog.html'),
controllerAs: 'vm', // @ngInject
restrict: 'E', controller: function ($scope, $element) {
template: require('../templates/annotation_share_dialog.html'), var shareLinkInput = $element.find('input')[0];
// @ngInject
controller: function ($scope, $element) {
var shareLinkInput = $element.find('input')[0];
$scope.$watch('vm.isOpen', function (isOpen) { $scope.$watch('vm.isOpen', function (isOpen) {
if (isOpen) { if (isOpen) {
// Focus the input and select it once the dialog has become visible // Focus the input and select it once the dialog has become visible
scopeTimeout($scope, function () { scopeTimeout($scope, function () {
shareLinkInput.focus(); shareLinkInput.focus();
shareLinkInput.select(); shareLinkInput.select();
}); });
var hideListener = function (event) { var hideListener = function (event) {
$scope.$apply(function () { $scope.$apply(function () {
if (!$element[0].contains(event.target)) { if (!$element[0].contains(event.target)) {
document.removeEventListener('click', hideListener); document.removeEventListener('click', hideListener);
this.onClose(); this.onClose();
} }
}.bind(this)); }.bind(this));
}.bind(this); }.bind(this);
// Stop listening for clicks outside the dialog once it is closed. // Stop listening for clicks outside the dialog once it is closed.
// The setTimeout() here is to ignore the initial click that opens // The setTimeout() here is to ignore the initial click that opens
// the dialog. // the dialog.
scopeTimeout($scope, function () { scopeTimeout($scope, function () {
document.addEventListener('click', hideListener); document.addEventListener('click', hideListener);
}, 0); }, 0);
} }
}.bind(this)); }.bind(this));
this.copyToClipboard = function (event) { this.copyToClipboard = function (event) {
var $container = angular.element(event.currentTarget).parent(); var $container = angular.element(event.currentTarget).parent();
var shareLinkInput = $container.find('input')[0]; var shareLinkInput = $container.find('input')[0];
try { try {
shareLinkInput.select(); shareLinkInput.select();
// In some browsers, execCommand() returns false if it fails, // In some browsers, execCommand() returns false if it fails,
// in others, it may throw an exception instead. // in others, it may throw an exception instead.
if (!document.execCommand('copy')) { if (!document.execCommand('copy')) {
throw new Error('Copying link failed'); throw new Error('Copying link failed');
}
this.copyToClipboardMessage = 'Link copied to clipboard!';
} catch (ex) {
this.copyToClipboardMessage = 'Select and copy to share.';
} finally {
setTimeout(function () {
this.copyToClipboardMessage = null;
$scope.$digest();
}.bind(this),
1000);
} }
}.bind(this);
}, this.copyToClipboardMessage = 'Link copied to clipboard!';
scope: { } catch (ex) {
group: '<', this.copyToClipboardMessage = 'Select and copy to share.';
uri: '<', } finally {
isPrivate: '<', setTimeout(function () {
isOpen: '<', this.copyToClipboardMessage = null;
onClose: '&', $scope.$digest();
}, }.bind(this),
}; 1000);
}
}.bind(this);
},
bindings: {
group: '<',
uri: '<',
isPrivate: '<',
isOpen: '<',
onClose: '&',
},
}; };
...@@ -13,7 +13,7 @@ describe('annotationShareDialog', function () { ...@@ -13,7 +13,7 @@ describe('annotationShareDialog', function () {
before(function () { before(function () {
angular.module('app', []) angular.module('app', [])
.directive('annotationShareDialog', .component('annotationShareDialog',
require('../annotation-share-dialog')) require('../annotation-share-dialog'))
.value('urlEncodeFilter', function (val) { return val; }); .value('urlEncodeFilter', function (val) { return val; });
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment