yaz/commit
UPDATE
author | Michiel Hildebrand |
---|---|
Tue Nov 8 00:59:22 2011 +0100 | |
committer | Michiel Hildebrand |
Tue Nov 8 00:59:22 2011 +0100 | |
commit | 31d62264d117631f634b9d37e8b290ef11d05a87 |
tree | c0096801ac10bae6323aa56079127b73051e6fb8 |
parent | 737b013692fbf969b807718cd07bfa307184291a |
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'>";