-
{{tag.typeOfTag.replace('_',' ')}}
@@ -53,11 +53,12 @@ Details
taxonomic
{{tag.text}} (ID {{tag.id}})
-
- Reference Tag
+ Reference Annotation
@@ -76,7 +77,12 @@ Details
Site: {{annotation.siteName}}
-
+
+
+ Audio recording: {{annotation.audioRecordingId}}
+
+
+
{{annotation.ownerName }}
@@ -92,11 +98,99 @@
Details
-
Comments
+
+
+ {{comments.length == 0 ? 'No Comments Yet' : (comments.length == 1 ? '1 Comment' : comments.length + ' Comments') }}
diff --git a/src/app/annotationLibrary/annotationLibrary.js b/src/app/annotationLibrary/annotationLibrary.js
index ba90da59..43770a72 100644
--- a/src/app/annotationLibrary/annotationLibrary.js
+++ b/src/app/annotationLibrary/annotationLibrary.js
@@ -9,20 +9,25 @@ baw.annotationLibrary.addCalculatedProperties = function addCalculatedProperties
audioEvent.calcOffsetStart = Math.floor(audioEvent.startTimeSeconds / 30) * 30;
audioEvent.calcOffsetEnd = (Math.floor(audioEvent.startTimeSeconds / 30) * 30) + 30;
+ var roundedDuration = Math.round10(audioEvent.annotationDuration, -3);
+ var roundedFreqLow = Math.round(audioEvent.lowFrequencyHertz);
+ var roundedFreqHigh = Math.round(audioEvent.highFrequencyHertz);
+
audioEvent.urls = {
site: $url.formatUri(paths.api.links.siteAbsolute, {projectId: audioEvent.projects[0].id, siteId: audioEvent.siteId}),
user: $url.formatUri(paths.api.links.userAccountsAbsolute, {userId: audioEvent.ownerId}),
- tagSearch: $url.formatUri(paths.site.ngRoutes.library, {tagsPartial: audioEvent.priorityTag.text}),
- similar: $url.formatUri(paths.site.ngRoutes.library,
+ tagSearch: $url.formatUri(paths.site.ngRoutes.libraryAbsolute, {tagsPartial: audioEvent.priorityTag.text}),
+ isReference: $url.formatUri(paths.site.ngRoutes.libraryAbsolute, {reference: audioEvent.isReference}),
+ similar: $url.formatUri(paths.site.ngRoutes.libraryAbsolute,
{
- annotationDuration: Math.round10(audioEvent.annotationDuration, -3),
- freqMin: Math.round(audioEvent.lowFrequencyHertz),
- freqMax: Math.round(audioEvent.highFrequencyHertz)
+ annotationDuration: roundedDuration,
+ freqMin: roundedFreqLow,
+ freqMax: roundedFreqHigh
}),
singleItem: $url.formatUri(paths.site.ngRoutes.libraryItem,
{
recordingId: audioEvent.audioRecordingId,
- audioEventId: audioEvent.audioEventId
+ audioEventId: audioEvent.audioEventId
}),
listen: $url.formatUri(paths.site.ngRoutes.listen,
{
@@ -38,6 +43,25 @@ baw.annotationLibrary.addCalculatedProperties = function addCalculatedProperties
})
};
+ audioEvent.tags.forEach(
+ function (currentvalue, index, array) {
+ currentvalue.similarPartial = $url.formatUri(paths.site.ngRoutes.libraryAbsolute,
+ {
+ tagsPartial: currentvalue.text,
+ annotationDuration: roundedDuration,
+ freqMin: roundedFreqLow,
+ freqMax: roundedFreqHigh
+ });
+ }
+ );
+
+ audioEvent.projects.forEach(
+ function (currentvalue, index, array) {
+ currentvalue.link = $url.formatUri(paths.api.links.projectAbsolute, {projectId: currentvalue.id});
+ }
+ );
+
+
return audioEvent;
};
@@ -155,7 +179,7 @@ angular.module('bawApp.annotationLibrary', ['bawApp.configuration'])
$scope.createFilterUrl = function createFilterUrl(paramObj) {
- return $url.formatUri(paths.site.ngRoutes.libraryAbsolute,paramObj);
+ return $url.formatUri(paths.site.ngRoutes.libraryAbsolute, paramObj);
};
function getEmptyFilterSettings() {
@@ -191,7 +215,7 @@ angular.module('bawApp.annotationLibrary', ['bawApp.configuration'])
$scope.filterSettings[currentvalue] = isVoid ? null : Number(stringValue);
}
);
-
+
// disable other options for reference filter
$scope.filterSettings.reference = 'true';
}
@@ -289,15 +313,38 @@ angular.module('bawApp.annotationLibrary', ['bawApp.configuration'])
}])
.controller('AnnotationItemCtrl',
['$scope', '$location', '$resource', '$routeParams', '$url',
- 'conf.paths', 'conf.constants', 'bawApp.unitConverter',
- 'AudioEvent', 'Tag', 'Media', 'baw.models.Media',
- function ($scope, $location, $resource, $routeParams, $url, paths, constants, unitConverter, AudioEvent, Tag, MediaService, Media) {
+ 'conf.paths', 'conf.constants', 'bawApp.unitConverter', 'moment',
+ 'AudioEvent', 'Tag',
+ 'Media', 'baw.models.Media', 'UserProfileEvents', 'UserProfile', 'AudioEventComment',
+ function ($scope, $location, $resource, $routeParams, $url,
+ paths, constants, unitConverter, moment,
+ AudioEvent, Tag,
+ MediaService, Media, UserProfileEvents, UserProfile, AudioEventComment) {
+
+ $scope.$on(UserProfileEvents.loaded, profileLoaded);
+ if (UserProfile.profile && UserProfile.profile.preferences) {
+ profileLoaded(null, UserProfile);
+ }
+
var parameters = {
audioEventId: $routeParams.audioEventId,
recordingId: $routeParams.recordingId
};
+ // new comment text and errors
+ $scope.newComment = {
+ // bind to new comment textarea
+ text: '',
+ errors: []
+ };
+
+ $scope.editComment = {
+ id: null,
+ text: null,
+ errors: []
+ };
+
AudioEvent.get(parameters,
function annotationShowSuccess(audioEventValue, responseHeaders) {
@@ -310,6 +357,9 @@ angular.module('bawApp.annotationLibrary', ['bawApp.configuration'])
$scope.annotation.gridConfig = {};
+ // comments
+ reloadComments();
+
// paging
if ($scope.annotation.paging.nextEvent.hasOwnProperty('audioEventId')) {
$scope.annotation.paging.nextEvent.link =
@@ -337,11 +387,126 @@ angular.module('bawApp.annotationLibrary', ['bawApp.configuration'])
});
$scope.createFilterUrl = function createFilterUrl(paramObj) {
- return $url.formatUri(paths.site.ngRoutes.libraryAbsolute,paramObj);
+ return $url.formatUri(paths.site.ngRoutes.libraryAbsolute, paramObj);
};
- $scope.createProjectUrl = function createProjectUrl(projectId){
+ $scope.createProjectUrl = function createProjectUrl(projectId) {
return $url.formatUri(paths.api.links.projectAbsolute, {projectId: projectId});
};
+ $scope.createCommentLinkUrl = function createCommentLinkUrl(audioEventCommentId) {
+ return '/library/' + $routeParams.recordingId + '/audio_events/' +
+ $routeParams.audioEventId + '#' + audioEventCommentId
+ };
+
+ $scope.formatTimeAgo = function formatTimeAgo(date) {
+ if (date) {
+ return moment(date).fromNow();
+ }
+ else {
+ return "unknown";
+ }
+ };
+
+ $scope.createComment = function createComment() {
+ if($scope.createCommentForm.$valid) {
+ AudioEventComment.save(
+ {audioEventId: $routeParams.audioEventId}, // parameters
+ {comment: $scope.newComment.text}, // post data
+ function createCommentSuccess(value, responseHeaders) {
+ console.log('create success', arguments);
+ $scope.newComment.errors = [];
+ $scope.newComment.text = '';
+ reloadComments();
+ },
+ function createCommentError(httpResponse) {
+ console.log('create failure', arguments);
+ $scope.newComment.errors = httpResponse.data.comment;
+ });
+ }
+ };
+
+ $scope.deleteComment = function deleteComment(commentText, audioEventCommentId) {
+ var isConfirmed = confirm('Are you sure you want to delete this comment? "' + commentText + '"');
+ if (isConfirmed === true) {
+ AudioEventComment.delete(
+ {
+ audioEventId: $routeParams.audioEventId,
+ audioEventCommentId: audioEventCommentId
+ }, // parameters
+ null, // post data
+ function deleteCommentSuccess(value, responseHeaders) {
+ console.log('delete success', arguments);
+ $scope.newComment.errors = [];
+ $scope.newComment.text = '';
+ reloadComments();
+ },
+ function deleteCommentError(httpResponse) {
+ console.log('delete failure', arguments);
+ $scope.newComment.errors = httpResponse.data.comment;
+ });
+ }
+ };
+
+ function updateCommentBase(id, body) {
+ AudioEventComment.update(
+ // url parameters
+ {
+ audioEventId: $routeParams.audioEventId,
+ audioEventCommentId: id
+ },
+ // body
+ body,
+ function updateCommentSuccess(value, responseHeaders) {
+ console.log('update success', arguments);
+ $scope.editComment.errors = [];
+ $scope.editComment.text = null;
+ $scope.editComment.id = null;
+ reloadComments();
+ },
+ function updateCommentError(httpResponse) {
+ console.log('update failure', arguments);
+ $scope.editComment.errors = httpResponse.data.comment;
+ });
+ }
+
+ $scope.updateComment = function updateComment(comment, updateForm) {
+ if(updateForm.$valid) {
+ updateCommentBase(comment.id, {
+ comment: comment.comment
+ });
+ comment.editing = false;
+ }
+ };
+
+ $scope.editComment = function editComment(comment) {
+ comment.editing = true;
+ };
+
+ $scope.reportComment = function reportComment(comment) {
+ comment.flag = "report";
+ updateCommentBase(comment.id, {
+ flag: comment.flag
+ });
+
+ };
+
+ function profileLoaded(event, userProfile) {
+ $scope.profile = userProfile.profile;
+ }
+
+ function reloadComments() {
+ // get array of comment for the current audio event
+ AudioEventComment.query(
+ {audioEventId: $routeParams.audioEventId},
+ function audioEventCommentSuccess(value, responseHeaders) {
+ $scope.comments = value.data;
+
+ $scope.comments.forEach(function(value) {
+
+ });
+ });
+
+ }
+
}]);
\ No newline at end of file
diff --git a/src/app/annotationLibrary/comments/_comments.scss b/src/app/annotationLibrary/comments/_comments.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/annotationLibrary/comments/comments.js b/src/app/annotationLibrary/comments/comments.js
new file mode 100644
index 00000000..015e0ff9
--- /dev/null
+++ b/src/app/annotationLibrary/comments/comments.js
@@ -0,0 +1,11 @@
+var bawCs = angular
+ .module('bawApp.annotationLibrary.comments', ['bawApp.configuration'])
+ .directive('comments', ['conf.paths', function (paths) {
+ var commentDefinition = {
+ restrict: 'E',
+ templateUrl: paths.site.files.annotationComments,
+ link: function postLink(scope, $element, attributes) {
+ }
+ };
+ return commentDefinition;
+ }]);
\ No newline at end of file
diff --git a/src/app/annotationLibrary/comments/comments.tpl.html b/src/app/annotationLibrary/comments/comments.tpl.html
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/listen/listen.js b/src/app/listen/listen.js
index 782d9e3b..6150ab74 100644
--- a/src/app/listen/listen.js
+++ b/src/app/listen/listen.js
@@ -46,6 +46,7 @@ angular.module('bawApp.listen', ['decipher.tags', 'ui.bootstrap.typeahead'])
* @param UserProfile
* @param Bookmark
* @param UserProfileEvents
+ * @param moment
*/
function ListenCtrl(
$scope, $resource, $location, $routeParams, $route, $q, paths, constants, $url, ngAudioEvents,
diff --git a/src/baw.configuration.tpl.js b/src/baw.configuration.tpl.js
index a5914432..fb520e03 100644
--- a/src/baw.configuration.tpl.js
+++ b/src/baw.configuration.tpl.js
@@ -56,6 +56,9 @@ angular.module('bawApp.configuration', ['url'])
profile: "/my_account",
settings: "/my_account/prefs"
},
+ audioEventComment: {
+ show: '/audio_events/{audioEventId}/comments/{audioEventCommentId}'
+ },
bookmark: {
show: "/bookmarks/{bookmarkId}"
}
@@ -83,6 +86,7 @@ angular.module('bawApp.configuration', ['url'])
listen: 'listen/listen.tpl.html',
annotationViewer: 'annotationViewer/annotationViewer.tpl.html',
gridLines: 'annotationViewer/gridLines/gridLines.tpl.html',
+ annotationComments: 'annotationLibrary/comments/comments.tpl.html',
library: {
list: 'annotationLibrary/annotationLibrary.tpl.html',
item: 'annotationLibrary/annotationItem.tpl.html'
diff --git a/src/components/services/bawResource.js b/src/components/services/bawResource.js
index cfdd5394..0be93e0d 100644
--- a/src/components/services/bawResource.js
+++ b/src/components/services/bawResource.js
@@ -25,6 +25,7 @@ angular.module("bawApp.services.resource", ["ngResource"])
var a = actions || {};
a.update = a.update || { method: 'PUT' };
+ a.query = {method: "GET", isArray: false};
var resource = $resource(convertedPath, paramDefaults, a);
resource.modifiedPath = convertedPath;
diff --git a/src/components/services/bawResource.spec.js b/src/components/services/bawResource.spec.js
index 1a61a57b..325ab077 100644
--- a/src/components/services/bawResource.spec.js
+++ b/src/components/services/bawResource.spec.js
@@ -1,17 +1,22 @@
describe("The bawResource service", function () {
- var Bookmark;
+ var $httpBackend, bawResource, $rootScope;
beforeEach(module('bawApp.services'));
- beforeEach(inject(["Bookmark", function (providedBookmark) {
- Bookmark = providedBookmark;
+ beforeEach(inject(["$injector", "bawResource", "$rootScope", function ($injector, providedBawResource, _$rootScope) {
+ $httpBackend = $injector.get('$httpBackend');
+
+ $httpBackend.when("GET", "/test").respond({data:[], meta:{}});
+
+ bawResource = providedBawResource;
+ $rootScope = _$rootScope;
}]));
it("should return a resource constructor that includes update/put", function () {
- expect(Bookmark).toImplement({
+ expect(bawResource("/test")).toImplement({
"get": null,
"save": null,
"query": null,
@@ -21,4 +26,24 @@ describe("The bawResource service", function () {
"modifiedPath": null
});
});
+
+ it("should override $resource's query", function(done) {
+
+ // make "new" resource
+ var testResource = bawResource("/test");
+
+ var pass;
+ var result = testResource
+ .query().$promise
+ .then(function() {
+ pass = true;
+ }, function() {
+ pass = false;
+ });
+ $httpBackend.flush();
+
+ expect(pass).toBeTrue();
+
+ done();
+ });
});
\ No newline at end of file
diff --git a/src/components/services/services.js b/src/components/services/services.js
index e6428ec4..85c8d74b 100644
--- a/src/components/services/services.js
+++ b/src/components/services/services.js
@@ -92,7 +92,17 @@
// NOTE: deleted user resource, API for users no longer exposed
- bawss.factory('AudioRecording', [ '$resource', '$http', 'conf.paths', 'QueryBuilder', function ($resource, $http, paths, QueryBuilder) {
+
+ bawss.factory('AudioEventComment', [ "bawResource", 'conf.paths', function (bawResource, paths) {
+ return bawResource(
+ paths.api.routes.audioEventComment.showAbsolute,
+ {audioEventId: "@audioEventId", audioEventCommentId: '@audioEventCommentId'});
+ }]);
+
+ bawss.factory(
+ 'AudioRecording',
+ [ '$resource', '$http', 'conf.paths', 'QueryBuilder',
+ function ($resource, $http, paths, QueryBuilder) {
var resource = resourcePut($resource, uriConvert(paths.api.routes.audioRecording.showAbsolute),
{projectId: "@projectId", siteId: "@siteId", recordingId: '@recordingId'});