vumix/commit
add editable title field
author | Michiel Hildebrand |
---|---|
Thu Mar 22 15:28:48 2012 +0100 | |
committer | Michiel Hildebrand |
Thu Mar 22 15:28:48 2012 +0100 | |
commit | ac13796633d18df9339d54b611b8bbaa998b977b |
tree | 15b2f61538276f2406ece24d6c903fa08914b305 |
parent | 5be29de9bff80e21d3f39eb74ff5777955d11307 |
Diff style: patch stat
diff --git a/applications/vumix.pl b/applications/vumix.pl index 438730c..d970d83 100644 --- a/applications/vumix.pl +++ b/applications/vumix.pl @@ -72,9 +72,9 @@ http_vumix(Request) :- % HTML page html_page(Target, Fields) :- - rdf_display_label(Target, Title), + rdf_global_id(_:Id, Target), reply_html_page( - [ title(['Annotate -- ', Title]) + [ title(['Annotate -- ', Id]) ], [ \html_requires(yui3('cssgrids/grids-min.css')), \html_requires(css('annotation.css')), @@ -86,8 +86,7 @@ html_page(Target, Fields) :- [ div([id(fields), class('yui3-u')], \html_annotation_fields(Fields)), div([id(media), class('yui3-u')], - [ div([id(title),class(title)], - h3(Title)), + [ div(id(title), []), div(id(video), []) ]) ]) @@ -150,12 +149,17 @@ yui_script(Target, Fields) --> yui3([json([modules(json(Modules))])], ['recordset-base'|Includes], [\js_video(Target), + \js_title_edit(Target), \js_annotation_fields(Fields, Target)]). js_module('videoplayer', json([fullpath(Path), requires([node,event,widget]) ])) :- http_absolute_location(js('videoplayer/videoplayer.js'), Path, []). +js_module('textedit', json([fullpath(Path), + requires([node,event,io,plugin,'querystring-stringify-simple']) + ])) :- + http_absolute_location(js('textedit.js'), Path, []). js_module('annotation', json([fullpath(Path), requires(['recordset-base', autocomplete, @@ -167,6 +171,25 @@ js_module('annotation', json([fullpath(Path), http_absolute_location(js('annotation.js'), Path, []). +js_title_edit(Target) --> + { http_location_by_id(http_update_annotation, Update), + rdf_equal(dcterms:title, Field), + ( annotation_in_field(Target, Field, Annotation, _Body, Text) + -> true + ; Annotation = @null, + Text = @null + ) + }, + yui3_plug(one(id(title)), + 'Y.Plugin.TextEdit', + {target:Target, + field:Field, + annotation:Annotation, + text:Text, + store:{update:Update + } + }). + js_video(Target) --> { http_absolute_location(js('videoplayer/'), FilePath, []), video_source(Target, Src) @@ -175,8 +198,8 @@ js_video(Target) --> 'Y.VideoPlayer', {filepath:FilePath, src:Src, - width:710, - height:450, + width:730, + height:460, autoplay:symbol(false), controls:symbol(true) }), @@ -222,7 +245,7 @@ annotation_in_field(Target, FieldURI, Annotation, Body, Label) :- rdf(Annotation, oac:hasTarget, Target, Graph), rdf(Annotation, an:annotationField, FieldURI, Graph), rdf(Annotation, oac:hasBody, Body, Graph), - rdf(Annotation, dc:title, Lit, Graph), + rdf(Annotation, dcterms:title, Lit, Graph), literal_text(Lit, Label). diff --git a/applications/vumix.pl~ b/applications/vumix.pl~ deleted file mode 100644 index 4ae4c12..0000000 --- a/applications/vumix.pl~ +++ /dev/null @@ -1,228 +0,0 @@ -:- module(vumix, - []). - - -% semweb -:- use_module(library('semweb/rdf_db')). -:- use_module(library('semweb/rdfs')). -:- use_module(library('semweb/rdf_label')). -:- use_module(library(yui3_beta)). - -% http libraries -:- use_module(library('http/http_dispatch')). -:- use_module(library('http/http_parameters')). -:- use_module(library('http/html_write')). -:- use_module(library('http/html_head')). -:- use_module(library('http/http_path')). -:- use_module(library('http/http_json')). -:- use_module(components(label)). -:- use_module(library(settings)). -:- use_module(user(user_db)). -:- use_module(library(instance_search)). -:- use_module(library(graph_version)). - - -/*************************************************** -* http handlers -***************************************************/ - -:- http_handler(cliopatria(vumix), http_vumix, []). - - -/*************************************************** -* settings -***************************************************/ - -:- setting(login, boolean, true, 'Require login'). -:- setting(min_query_length, integer, 3, - 'Minimum number of characters that must be entered before a query event will be fired. A value of 0 allows empty queries; a negative value will effectively disable all query events and turn AutoComplete off. '). - - -/*************************************************** -* http replies -***************************************************/ - -%% http_vumix(+Request) -% -% Generate page to annotate a vumix. - -http_vumix(Request) :- - http_parameters(Request, - [ target(Target, - [uri, - description('URI of the object to be annotated') - ]), - field(Fields, - [zero_or_more, - description('URI of annotation field') - ]) - ]), - ( setting(login, true) - -> authorized(write(_,_)) - ; true - ), - html_page(Target, Fields). - -/*************************************************** -* annotation page -***************************************************/ - -%% html_page(+Target, +Fields) -% -% HTML page - -html_page(Target, Fields) :- - rdf_display_label(Target, Title), - reply_html_page( - [ title(['Annotate -- ', Title]) - ], - [ \html_requires(yui3('cssgrids/grids-min.css')), - \html_requires(css('annotation.css')), - \html_requires(css('vumix.css')), - div(class('yui3-skin-sam yui-skin-sam'), - [ div(id(hd), []), - div(id(bd), - div([id(layout), class('yui3-g')], - [ div([id(fields), class('yui3-u')], - \html_annotation_fields(Fields)), - div([id(media), class('yui3-u')], - [ div(id(video), []), - div([id(title),class(title)], - h3(Title)) - ]) - ]) - ), - div(id(ft), []) - ]), - script(type('text/javascript'), - \yui_script(Target, Fields)) - ]). - -% hack -video_source(R, Video) :- - rdf_has(R, pprime:source, Video). - - -%% html_annotation_fields(+FieldURIs) -% -% Write html for annotation fields. - -html_annotation_fields([]) --> !. -html_annotation_fields([URI|T]) --> - html(div(class('annotate-field'), - \html_annotation_field(URI))), - html_annotation_fields(T). - -html_annotation_field(URI) --> - { rdf_global_id(_:Id, URI), - rdf_label(URI, L), - literal_text(L, Label) - }, - html([ div(class('annotate-header'), - [ h3(Label), - \html_annotation_field_desc(URI) - ]), - input([id(Id), type(text)]) - ]). - -html_annotation_field_desc(URI) --> - { rdf(URI, dc:comment, D), - literal_text(D, Desc) - }, - !, - html(div([class('annotate-description')], Desc)). -html_annotation_field_desc(_URI) --> !. - - - - /******************************* - * JavaScript * - *******************************/ - -%% yui_script(+Graph) -% -% Emit YUI object. - -yui_script(Target, Fields) --> - { findall(M-C, js_module(M,C), Modules), - pairs_keys(Modules, Includes) - }, - yui3([json([modules(json(Modules))])], - ['recordset-base'|Includes], - [\js_video(Target), - \js_annotation_fields(Fields, Target)]). - -js_module('videoplayer', json([fullpath(Path), - requires([node,event,widget]) - ])) :- - http_absolute_location(js('videoplayer/videoplayer.js'), Path, []). -js_module('annotation', json([fullpath(Path), - requires(['recordset-base', - autocomplete, - 'autocomplete-highlighters', - 'io','json-parse', - 'querystring-stringify-simple' - ]) - ])) :- - http_absolute_location(js('annotation.js'), Path, []). - - -js_video(Target) --> - { http_absolute_location(js('videoplayer/'), FilePath, []), - video_source(Target, Src) - }, - yui3_new(videoPlayer, - 'Y.VideoPlayer', - {filepath:FilePath, - src:Src, - width:710, - height:450, - autoplay:symbol(false), - controls:symbol(true) - }), - yui3_render(videoPlayer, one(id(video))). - -%% js_annotation_fields(+FieldURIs, +AnnotationTarget) -% -% Write JavaScript to init annotation fields - -js_annotation_fields([], _) --> !. -js_annotation_fields([URI|T], Target) --> - js_annotation_field(URI, Target), - js_annotation_fields(T, Target). - -js_annotation_field(FieldURI, Target) --> - { http_location_by_id(http_add_annotation, Add), - http_location_by_id(http_remove_annotation, Remove), - rdf_global_id(_:Id, FieldURI), - setting(min_query_length, MinQueryLength), - rdf(FieldURI, an:source, literal(Source)), - findall({annotation:A, uri:R, label:L}, - annotation_in_field(Target, FieldURI, A, R, L), - Tags) - }, - yui3_plug(one(id(Id)), - 'Y.Plugin.Annotation', - {target:Target, - field:FieldURI, - source:Source, - store:{add:Add, - remove:Remove - }, - tags:Tags, - minQueryLength:MinQueryLength, - resultListLocator: results, - resultTextLocator: label, - resultHighlighter: phraseMatch}). - - -annotation_in_field(Target, FieldURI, Annotation, Body, Label) :- - gv_resource_head(Target, Commit), - gv_resource_graph(Commit, Graph), - rdf(Annotation, oac:hasTarget, Target, Graph), - rdf(Annotation, an:annotationField, FieldURI, Graph), - rdf(Annotation, oac:hasBody, Body, Graph), - rdf(Annotation, dc:title, Lit, Graph), - literal_text(Lit, Label). - - diff --git a/config-available/load_mbh_example.pl b/config-available/load_mbh_example.pl index d5db651..f50c797 100644 --- a/config-available/load_mbh_example.pl +++ b/config-available/load_mbh_example.pl @@ -4,16 +4,16 @@ :- use_module(library('semweb/rdf_db')). :- use_module(library(http/http_dispatch)). -:- rdf_load(rdf('mbh_example.ttl')). % load example video and config file -:- rdf_attach_library(vocs). -:- rdf_load_library(gtaa). - -:- http_link_to_id(http_vumix, [target('http://semanticweb.cs.vu.nl/prestoprime/video18702'), - field('http://semanticweb.cs.vu.nl/prestoprime/personAnnotation'), - field('http://semanticweb.cs.vu.nl/prestoprime/placeAnnotation'), - field('http://semanticweb.cs.vu.nl/prestoprime/subjectAnnotation') - ], - Location), +load_mbh_example :- + rdf_load(rdf('mbh_example.ttl')), % load example video and config file + rdf_attach_library(vocs), + rdf_load_library(gtaa), + http_link_to_id(http_vumix, [target('http://semanticweb.cs.vu.nl/prestoprime/video18702'), + field('http://semanticweb.cs.vu.nl/prestoprime/personAnnotation'), + field('http://semanticweb.cs.vu.nl/prestoprime/placeAnnotation'), + field('http://semanticweb.cs.vu.nl/prestoprime/subjectAnnotation') + ], + Location), http_handler(cliopatria(p0), http_redirect(moved, Location), []). diff --git a/config-available/vumix.pl b/config-available/vumix.pl index edd1bd1..2e45d22 100644 --- a/config-available/vumix.pl +++ b/config-available/vumix.pl @@ -3,3 +3,9 @@ /** <module> Video annotation prototype */ +:- use_module(library('semweb/rdf_db')). + +% hack namespace + :- rdf_register_ns(pprime, 'http://semanticweb.cs.vu.nl/prestoprime/'). + +:- use_module(applications(vumix)). diff --git a/web/css/vumix.css b/web/css/vumix.css index 7919957..fe92cd5 100644 --- a/web/css/vumix.css +++ b/web/css/vumix.css @@ -1,5 +1,35 @@ #title { background-color: #EEE; - padding: 5px 5px; - margin: 10px 0; + padding: 5px; + margin: 0 0 10px; +} +#title .text { + font-size: 125%; + font-weight: bold; + padding: 5px 0; +} +.textedit .inputField { + display: none; +} +.textedit .inputLabel { + font-weight: bold; +} +.textedit .text:hover { + background-color: #F5F46C; +} +.textedit textarea { + width: 100%; +} +.textedit .info { + display: none; +} +.textedit:hover .info { + display: block; +} +.textedit.edit .text, +.textedit.edit:hover .info { + display: none; +} +.textedit.edit .inputField { + display: block; } \ No newline at end of file diff --git a/web/js/textedit.js b/web/js/textedit.js new file mode 100644 index 0000000..843d30a --- /dev/null +++ b/web/js/textedit.js @@ -0,0 +1,113 @@ +YUI.add('textedit', function(Y) { + + var Node = Y.Node; + + function TextEdit(config) { + TextEdit.superclass.constructor.apply(this, arguments); + } + TextEdit.NAME = "TextEdit"; + TextEdit.NS = "TextEdit"; + TextEdit.ATTRS = { + text: { + value: null + }, + inputLabel: { + value: "Title" + }, + infoText: { + value: "click to edit title" + }, + target: { + value: null + }, + field: { + value: null + }, + annotation: { + value: null + }, + store: { + value: null + } + }; + + Y.extend(TextEdit, Y.Plugin.Base, { + + initializer: function(args) { + var parentNode = this.get("host"), + text = this.get("text"); + + parentNode.addClass("textedit"); + var textNode = parentNode.appendChild(Node.create('<div class="text"></div>')), + infoNode = parentNode.appendChild(Node.create('<div class="info">'+ + this.get("infoText")+'</div>')) + inputNode = parentNode.appendChild(Node.create('<div class="inputField"></div>')), + inputLabel = inputNode.appendChild(Node.create('<div class="inputLabel">' + +this.get('inputLabel')+'</div>')), + inputField = inputNode.appendChild(Node.create('<textarea></textarea>')), + submitButton = inputNode.appendChild(Node.create('<button>save</button>')); + + this._setText({newVal:text}); + this.on("textChange", this._setText, this); + textNode.on("click", this._enableEdit, this); + submitButton.on("click", this._submitText, this); + }, + + _setText : function(e) { + var host = this.get("host"), + text = e.newVal; + if(text) { + host.one('.text').setContent(text); + host.removeClass("edit"); + } else { + this._enableEdit(); + } + }, + + _enableEdit : function(e) { + var host = this.get("host"), + text = this.get("text"), + input = host.one('textarea'); + input.set("value", text); + host.addClass("edit"); + input.focus(); + }, + + _submitText : function(e) { + var oSelf = this, + oldText = this.get("text"), + newText = this.get("host").one('textarea').get("value"), + updateService = this.get("store").update; + + var data = { + target:this.get("target"), + field:this.get("field"), + body:newText + }; + if(this.get("annotation")) { + data.annotation = this.get("annotation"); + } + if(oldText!==newText) { + Y.io(updateService, { + data:data, + on:{success: function(e,o) { + var r = Y.JSON.parse(o.responseText); + console.log(r.annotation); + oSelf.set("annotation", r.annotation); + oSelf.set("text", newText) } + } + }); + } else { + this.get("host").removeClass("edit"); + } + } + + + }); + + Y.Plugin.TextEdit = TextEdit; + +}, '0.0.1', { requires: [ + 'node','event','plugin','io-base','querystring-stringify-simple' + ] +});