yaz/commit

UPDATE

authorMichiel Hildebrand
Tue Nov 8 00:59:22 2011 +0100
committerMichiel Hildebrand
Tue Nov 8 00:59:22 2011 +0100
commit31d62264d117631f634b9d37e8b290ef11d05a87
treec0096801ac10bae6323aa56079127b73051e6fb8
parent737b013692fbf969b807718cd07bfa307184291a
Diff style: patch stat
diff --git a/applications/yaz_shot_annotation.pl b/applications/yaz_shot_annotation.pl
index ffe3c96..7ee4e99 100644
--- a/applications/yaz_shot_annotation.pl
+++ b/applications/yaz_shot_annotation.pl
@@ -12,6 +12,7 @@
 :- use_module(library(http/http_json)).
 :- use_module(library(http/js_write)).
 :- use_module(library(http/json)).
+:- use_module(library(http/json_convert)).
 :- use_module(library(http/http_session)).
 :- use_module(user(user_db)).
 :- use_module(library(semweb/rdf_db)).
@@ -212,8 +213,9 @@ html_video_page_yui(Video, Shots, Sources) -->
 		  \js_yui3_render(annotationForm, #(annotationform)),
 		  \js_yui3_on(videoFrames, frameSelect, \js_frame_select(Video)),
 		  \js_yui3_on(tagList, itemSelect, \js_tag_select),
-		  \js_yui3_on(tagLinker, conceptSelect, \js_concept_select(Video)),
+		  \js_yui3_on(tagLinker, submit, \js_concept_submit),
 		  \js_yui3_on(tagLinker, cancel, \js_concept_cancel),
+		  \js_yui3_on(annotationForm, delete, \js_annotation_remove),
 		  \js_yui3_on(videoPlayer, timeChange, \js_video_time_change)
 		]).
 
@@ -249,22 +251,32 @@ js_concept_cancel -->
 '   Y.one("#select-concept").addClass("hidden");
     Y.one("#select-tag").removeClass("hidden");\n'
 		     ]).
-js_concept_select(Video) -->
+js_concept_submit -->
 	{ http_location_by_id(http_data_shot_set_annotation, Server)
 	},
 	js_function([e],
 		    \[
-'   var source = e.source,
-	concept = e.concept,
+'   var concepts = e.concepts,
+	tag = e.tag,
 	shot = videoFrames.get("selected").uri;
     Y.one("#select-concept").addClass("hidden");
     Y.one("#select-tag").removeClass("hidden");\n',
 '   if(shot) {
-       Y.io("',Server,'?video=',Video,'&shot="+encodeURIComponent(shot)+"&value="+encodeURIComponent(concept.id)+"&label="+concept.name+"&type="+source,
-	    {on:{success:function(e,o){annotationForm.addAnnotation(source, Y.JSON.parse(o.response)) }}});
+       Y.io("',Server,'?shot="+encodeURIComponent(shot)+"&tag="+Y.JSON.stringify(tag)+"&concepts="+Y.JSON.stringify(concepts),
+	    {on:{success:function(e,o){annotationForm.addAnnotations(concepts) }}});
     }\n'
 		     ]).
 
+js_annotation_remove -->
+	{ http_location_by_id(http_data_shot_delete_annotation, Server)
+	},
+	js_function([e],
+		    \[
+'    var shot = videoFrames.get("selected").uri\n',
+'    Y.io("',Server,'?shot="+encodeURIComponent(shot)+"&source="+e.source+"&value="+encodeURIComponent(e.value),
+	    {on:{success:function(e,o){}}});'
+		     ]).
+
 
 js_video_time_change -->
 	js_function([e],
@@ -282,6 +294,8 @@ js_video_time_change -->
 :- http_handler(yaz(data/shot/suggest/tags), http_data_shot_suggest_tags, []).
 :- http_handler(yaz(data/shot/get/annotations), http_data_shot_get_annotations, []).
 :- http_handler(yaz(data/shot/set/annotation), http_data_shot_set_annotation, []).
+:- http_handler(yaz(data/shot/delete/annotation), http_data_shot_delete_annotation, []).
+
 
 
 %%	http_data_shot_suggest_tags(+Request)
@@ -330,42 +344,76 @@ http_data_shot_get_annotations(Request) :-
 	current_user_process(Process),
 	findall(Type-json([entry=E, value=Value, label=Label]),
 		shot_annotation(Shot, Value, Label, Type, Process, E),
-		As),
+		As0),
+	keysort(As0, As),
 	group_pairs_by_key(As, Annotations),
 	reply_json(json(Annotations)).
 
 http_data_shot_set_annotation(Request) :-
 	ensure_logged_on(_),
 	http_parameters(Request,
-			[ video(_Video,
-				[description('URI of the video')]),
-			  shot(Shot,
+			[ shot(Shot,
+			       [description('URI of the shot')]),
+			  concepts(Concepts,
+				   [json_shot_annotation,
+				    description('Array with concept annotations')]),
+			  tag(Tag,
+			      [optional(true),
+			       description('tag used to make annotations')])
+			]),
+	rdfh_transaction(assert_shot_annotations(Concepts, Shot, Tag)),
+	reply_json(json([shot=Shot,tag=Tag])).
+
+http_data_shot_delete_annotation(Request) :-
+	ensure_logged_on(_),
+	http_parameters(Request,
+			[ shot(Shot,
 			       [description('URI of the shot')]),
 			  value(Value,
-			      [description('Annotation value')]),
-			  label(Label,
-				[description('Preferred display label')]),
-			  type(Type,
-				[description('type of annotation')])
+				   [description('URI of annotation value')]),
+			  source(Source,
+			      [description('Source identifier')])
 			]),
-	rdfh_transaction(assert_shot_annotation(Shot, Value, Label, Type, Event)),
-	reply_json(json([shot=Shot,value=Value,label=Label,entry=Event])).
+	current_user_process(Process),
+	rdfh_transaction(retract_shot_annotation(Shot, Source, Value, Process)),
+	reply_json(json([shot=Shot,value=Value,soure=Source])).
 
+http:convert_parameter(json_shot_annotation, Atom, Term) :-
+	atom_json_term(Atom, JSON, []),
+	json_to_prolog(JSON, Term).
 
+:- json_object
+	concept(value:atom, label:atom, source:atom).
 
-shot_annotation(Shot, Value, Label, Type, Process, R) :-
-	rdf(R, pprime:shot, Shot, Process),
-	rdf(R, pprime:value, Value, Process),
-	rdf(R, pprime:type, Type, Process),
-	rdf(R, pprime:label, Label, Process).
 
-assert_shot_annotation(Shot, Value, Label, Type, R) :-
+assert_shot_annotations([], _, _).
+assert_shot_annotations([C|Cs], Shot, Tag) :-
+	C = concept(Value, Label, Type),
+	assert_shot_annotation(Shot, Value, Label, Type, Tag, _),
+	assert_shot_annotations(Cs, Shot, Tag).
+
+assert_shot_annotation(Shot, Value, Label, Type, Tag, R) :-
 	rdf_bnode(R),
 	rdfh_assert(R, rdf:type, pprime:'ShotAnnotation'),
+	rdfh_assert(R, pprime:tag, literal(Tag)),
 	rdfh_assert(R, pprime:shot, Shot),
 	rdfh_assert(R, pprime:value, Value),
 	rdfh_assert(R, pprime:type, Type),
-	rdfh_assert(R, pprime:label, Label).
+	rdfh_assert(R, pprime:label, literal(Label)).
+
+retract_shot_annotation(Shot, Type, Value, Process) :-
+	(   rdf(R, pprime:shot, Shot, Process),
+	    rdf(R, pprime:value, Value, Process),
+	    rdf(R, pprime:type, Type, Process)
+	->  rdfh_retractall(R, _, _)
+	;   true
+	).
+
+shot_annotation(Shot, Value, Label, Type, Process, R) :-
+	rdf(R, pprime:shot, Shot, Process),
+	rdf(R, pprime:value, Value, Process),
+	rdf(R, pprime:type, Type, Process),
+	rdf(R, pprime:label, literal(Label), Process).
 
 :- dynamic
 	video/2.
diff --git a/web/css/shotgarden.css b/web/css/shotgarden.css
index da9c2e8..8448c1d 100644
--- a/web/css/shotgarden.css
+++ b/web/css/shotgarden.css
@@ -212,15 +212,21 @@
 /* annotation form */
 .yui3-annotation-form-content {
 	border: 1px solid #CCCCCC;
+	padding: 7px 0;
 }
 .yui3-annotation-form .an-list {
 	min-height: 25px;
 	padding-left: 6px;
 	overflow: auto;
 }
+.yui3-annotation-form .an-source {
+	padding: 6px 0;
+}
 .yui3-annotation-form .an-hd {
 	font-weight: bold;
-	margin: 4px 4px 0;
+	margin: 6px 4px 0;
+	float: left;
+	min-width: 50px;
 }
 .yui3-annotation-form ul {
 	margin: 0;
@@ -230,5 +236,16 @@
 	list-style: none;
 	padding: 4px;
 	float: left;
+	margin: 1px 2px;
+	background-color: #EEE;
+	border: 1px solid #CCC;
+	-moz-border-radius: 5px;
+	border-radius: 5px;
 }
-
+.yui3-annotation-form li .delete {
+	display: none;
+	padding: 0 4px;
+}	
+.yui3-annotation-form li:hover .delete {
+	display: inline;
+}
\ No newline at end of file
diff --git a/web/js/annotation/annotation_form.js b/web/js/annotation/annotation_form.js
index acfc048..e328a7b 100644
--- a/web/js/annotation/annotation_form.js
+++ b/web/js/annotation/annotation_form.js
@@ -58,7 +58,11 @@ YUI.add('annotation-form', function(Y) {
 		},
 
 		bindUI : function() {
+			var fields = this.get("fields");
 			this.after("annotationsChange", function(e) {this.syncUI()});
+			for(var key in fields) {
+				Y.delegate("click", this._itemDelete, fields[key].list, "li .delete", this, key);
+			}
 		},
 
 		syncUI : function() {
@@ -67,21 +71,28 @@ YUI.add('annotation-form', function(Y) {
 			
 			for (var key in fields) {
 				if(key) {
-					this._setAnnotations(fields[key], annotations[key]);
+					this._setAnnotation(fields[key], annotations[key]);
 				}	
 			}
 		},
 		
-		_renderField : function(a) {
+		_itemDelete : function(e, field) {
+			var node = e.currentTarget,
+				parent = node.get("parentNode");
+			parent.remove();
+			this.fire("delete", {source:field, value:parent.get("id")});
+		},
+		
+		_renderField : function(field) {
 			var content = this.get("contentBox"),
-				label = a.label;
+				label = field.label;
 				
 			var box = content.appendChild(Node.create('<div class="an-source"></div>'));
 			box.appendChild('<div class="an-hd">'+label+'</div>');
-			a.list = box.appendChild(Node.create('<ul class="an-list"></ul>'));
+			field.list = box.appendChild(Node.create('<ul class="an-list"></ul>'));
 		},
 	
-		_setAnnotations : function(field, annotations) {
+		_setAnnotation : function(field, annotations) {
 			var list = field.list;
 			list.setContent("");
 			if(annotations) {
@@ -96,20 +107,20 @@ YUI.add('annotation-form', function(Y) {
 				label = item.label;
 				
 			var url = (value.substr(0,1)=='/') ? 'http://www.freebase.com'+value : value;	
-			var html = "<li class='annotation'>";
+			var html = "<li class='annotation' id='"+value+"'>";
 			html += "<a target='info' href='"+url+"' class='name'>"+label+"</a>";
-			if(item.desc) { 
-				html += "<div class='desc'>"+item.desc+"</div>";
-			}
+			html += "<a href='javascript:void(0)' class='delete'>[x]</a>"
+			html += "</li>"
 			return html;
 		},
 		
-		addAnnotation: function(field, annotation) {
+		addAnnotations: function(annotations) {
 			var fields = this.get("fields");
-			//	annotations = this.get("annotations");
-			//annotations[field].push[annotation];
-			//this.set("annotations", annotations);
-			fields[field].list.appendChild(this.formatItem(annotation));
+			for (var i=0; i < annotations.length; i++) {
+				var a = annotations[i],
+					field = fields[a.source];
+				field.list.appendChild(this.formatItem(a));
+			}
 		}
 	})
 	  
diff --git a/web/js/tagplayer/tagLinker.js b/web/js/tagplayer/tagLinker.js
index 90bec6a..dfcba76 100644
--- a/web/js/tagplayer/tagLinker.js
+++ b/web/js/tagplayer/tagLinker.js
@@ -82,22 +82,25 @@ YUI.add('tag-linker', function(Y) {
 			var tag = this.get("tag");
 			this.fire("cancel", {"tag":tag});
 		},
-		_submit: function() {
-			var tag = this.get("tag");
-			this.fire("cancel", {"tag":tag});
-		},
 		
-		_itemSelect: function(e, type) {
+		_submit: function() {
 			var tag = this.get("tag"),
-				source = this.get("sources")[type],
-				items = source.items;
-
-			var node = e.currentTarget.get("parentNode"),
-				index = e.container.all("li").indexOf(node),
-				item = items[index];
-
-			Y.log('selected concept '+item);
-	        this.fire("conceptSelect", {"tag":tag, concept:item, source:type});
+				sources = this.get("sources"),
+				selected = [];
+				
+			for(var key in sources) {
+				var source = sources[key],
+					items = source.items,
+					nodes = source._list.all("li");
+					
+				nodes.each(function(node, i) {
+					var concept = items[i];
+					if(node.one(".check:checked")) {
+						selected.push({value:concept.id, label:concept.name, source:key});
+					}	
+				})
+			}	
+			this.fire("submit", {"tag":tag, concepts:selected});
 		},
 		
 		_renderSources : function(node) {
@@ -178,7 +181,7 @@ YUI.add('tag-linker', function(Y) {
 			
 			var url = (id.substr(0,1)=='/') ? 'http://www.freebase.com'+id : id;
 			
-			var html = "<input type=checkbox name='reconcileItem' value='"+id+"'>";
+			var html = "<input type='checkbox' class='check'>";
 			html += "<span class='name'><a target='info' href='"+url+"'>"+name+"</a></span>";
 			if(types&&!item.desc) {
 				html += "<div class='types'>";