Mercurial > hg > digilib-old
comparison webapp/src/main/webapp/jquery/jquery.digilib.annotator.js @ 1113:7affda55c10e
using annotator in digilib works somewhat now.
author | robcast |
---|---|
date | Thu, 01 Nov 2012 18:38:11 +0100 |
parents | |
children | 1525c820ee27 |
comparison
equal
deleted
inserted
replaced
1112:121d3aadfa1e | 1113:7affda55c10e |
---|---|
1 /** | |
2 digilib plugin for annotations. | |
3 | |
4 currently only point-like annotations (like marks). | |
5 | |
6 Annotations are stored on a Annotator http://annotateit.org compatible server. | |
7 | |
8 */ | |
9 | |
10 (function($) { | |
11 | |
12 // affine geometry | |
13 var geom; | |
14 // plugin object with digilib data | |
15 var digilib; | |
16 // our Annotator instance | |
17 var annotator; | |
18 | |
19 var FULL_AREA; | |
20 | |
21 var buttons = { | |
22 annotations : { | |
23 onclick : "toggleAnnotations", | |
24 tooltip : "show or hide annotations", | |
25 icon : "annotations.png" | |
26 }, | |
27 annotationuser : { | |
28 onclick : "setAnnotationUser", | |
29 tooltip : "set user account for annotations", | |
30 icon : "annotation-user.png" | |
31 }, | |
32 annotationmark : { | |
33 onclick : "setAnnotationMark", | |
34 tooltip : "create an annotation for a point", | |
35 icon : "annotation-mark.png" | |
36 } | |
37 }; | |
38 | |
39 var defaults = { | |
40 'annotatorInstance' : null, | |
41 // are annotations active? | |
42 'isAnnotationsVisible' : true, | |
43 // buttonset of this plugin | |
44 'annotationSet' : ['annotations', 'annotationuser', 'annotationmark', 'lessoptions'], | |
45 // URL of annotation server | |
46 'annotationServerUrl' : 'http://virtuoso.mpiwg-berlin.mpg.de:8080/AnnotationManager/annotator', | |
47 // URL of authentication token server | |
48 'annotationTokenUrl' : 'http://localhost:8080/test/annotator/token', | |
49 // annotation user name | |
50 'annotationUser' : 'anonymous', | |
51 // function to translate user name from annotation server format | |
52 'annotationServerUserString' : function() { | |
53 if (this.user && this.user.name) { | |
54 return this.user.name; | |
55 } | |
56 return this.user; | |
57 }, | |
58 | |
59 }; | |
60 | |
61 var actions = { | |
62 /** | |
63 * show/hide annotations | |
64 */ | |
65 toggleAnnotations : function (data) { | |
66 var show = !data.settings.isAnnotationsVisible; | |
67 data.settings.isAnnotationsVisible = show; | |
68 digilib.fn.highlightButtons(data, 'annotations', show); | |
69 renderAnnotations(data); | |
70 }, | |
71 | |
72 /** | |
73 * set user account for annotations | |
74 */ | |
75 setAnnotationUser : function (data, user, password) { | |
76 var settings = data.settings; | |
77 if (user == null) { | |
78 // user name entered in JS-prompt | |
79 user = window.prompt("User name:", settings.annotationUser); | |
80 if (user != null) { | |
81 // password entered in JS-prompt | |
82 password = window.prompt("Password:", ''); | |
83 settings.annotationUser = user; | |
84 data.dlOpts.annotationUser = user; | |
85 digilib.fn.storeOptions(data); | |
86 loadAnnotationToken(data, password); | |
87 } | |
88 } else { | |
89 settings.annotationUser = user; | |
90 data.dlOpts.annotationUser = user; | |
91 digilib.fn.storeOptions(data); | |
92 loadAnnotationToken(data, password); | |
93 } | |
94 }, | |
95 | |
96 /** | |
97 * set a mark-annotation by clicking (or giving a position and a text) | |
98 * | |
99 * @param data | |
100 * @param mpos | |
101 * @param text | |
102 */ | |
103 setAnnotationMark : function (data, mpos, text) { | |
104 if (mpos == null) { | |
105 // interactive | |
106 setAnnotationMark(data); | |
107 } else { | |
108 // use position and text (and user-id) | |
109 var annotation = newAnnotation(data, mpos, text, null, null, data.settings.annotationUser); | |
110 storeAnnotation(data, annotation); | |
111 // TODO: replace with annotation returned by server | |
112 data.annotations.push(annotation); | |
113 digilib.fn.redisplay(data); | |
114 } | |
115 }, | |
116 }; | |
117 | |
118 /** | |
119 * create a new annotation object | |
120 */ | |
121 var newAnnotation = function (data, mpos, text, id, uri, user, permissions, tags) { | |
122 var annot = { | |
123 pos : mpos, | |
124 text : text, | |
125 id : id, | |
126 uri : uri, | |
127 user : user, | |
128 permissions : permissions, | |
129 tags : tags | |
130 }; | |
131 // TODO: use prototype? | |
132 annot.getUserName = data.settings.annotationServerUserString; | |
133 return annot; | |
134 }; | |
135 | |
136 /** | |
137 * returns an annotatable url to this digilib image | |
138 */ | |
139 var getAnnotationPageUrl = function(data) { | |
140 var url = data.settings.digilibBaseUrl + '/jquery/digilib.html?'; | |
141 url += digilib.fn.getParamString(data.settings, ['fn', 'pn'], digilib.defaults); | |
142 return url; | |
143 }; | |
144 | |
145 /** | |
146 * add a mark-annotation where clicked. | |
147 */ | |
148 var setAnnotationMark = function(data) { | |
149 var $scaler = data.$scaler; | |
150 annotator = data.settings.annotatorInstance; | |
151 // unbind other handler TODO: do we need to do this? | |
152 $scaler.off(".dlZoomDrag"); | |
153 // start event capturing | |
154 $scaler.one('mousedown.dlSetAnnotationMark', function(evt) { | |
155 // event handler adding a new mark | |
156 console.log("setAnnotationMark at=", evt); | |
157 var mpos = geom.position(evt); | |
158 var pos = data.imgTrafo.invtransform(mpos); | |
159 | |
160 console.debug("showing annotator editor!"); | |
161 var annotation = annotator.createAnnotation(); | |
162 annotation.areas = [geom.rectangle(pos)]; | |
163 annotator.showEditor(annotation, mpos.getAsCss()); | |
164 | |
165 return false; | |
166 // Annotation text entered in JS-prompt | |
167 var text = window.prompt("Annotation text:"); | |
168 if (text == null) return false; | |
169 var annotation = newAnnotation(data, pos, text, null, null, data.settings.annotationUser); | |
170 storeAnnotation(data, annotation); | |
171 data.annotations.push(annotation); | |
172 digilib.fn.redisplay(data); | |
173 return false; | |
174 }); | |
175 }; | |
176 | |
177 /** | |
178 * place annotations on the image | |
179 */ | |
180 var renderAnnotations = function(data) { | |
181 console.debug("renderAnnotations: annotator=", annotator); | |
182 if (annotator == null || data.$img == null || data.imgTrafo == null) | |
183 return; | |
184 var annotations = annotator.plugins['Store'].annotations; | |
185 var cssPrefix = data.settings.cssPrefix; | |
186 var $elem = data.$elem; | |
187 // try to show annotation user state | |
188 $elem.find('div#'+cssPrefix+'button-annotationuser').attr('title', 'annotation user: '+data.settings.annotationUser); | |
189 // clear annotations | |
190 $elem.find('div.' + cssPrefix + 'annotationmark').remove(); | |
191 if (!data.settings.isAnnotationsVisible) return; | |
192 for (var i = 0; i < annotations.length; i++) { | |
193 var annotation = annotations[i]; | |
194 renderAnnotation(data, annotation); | |
195 } | |
196 }; | |
197 | |
198 /** | |
199 * place annotation on the image | |
200 */ | |
201 var renderAnnotation = function(data, annotation) { | |
202 console.debug("renderAnnotation: annotation=", annotation); | |
203 if (annotation == null || data.$img == null || data.imgTrafo == null) | |
204 return; | |
205 var cssPrefix = data.settings.cssPrefix; | |
206 var $elem = data.$elem; | |
207 // try to show annotation user state | |
208 $elem.find('div#'+cssPrefix+'button-annotationuser').attr('title', 'annotation user: '+data.settings.annotationUser); | |
209 if (!data.settings.isAnnotationsVisible) return; | |
210 var pos = geom.position(annotation.areas[0]); | |
211 if (data.zoomArea.containsPosition(pos)) { | |
212 var mpos = data.imgTrafo.transform(pos); | |
213 console.debug("renderannotations: pos=", mpos); | |
214 // create annotation | |
215 var html = '<div class="' + cssPrefix + 'annotationmark ' + cssPrefix + 'overlay">?</div>'; | |
216 // set text as tooltip | |
217 var $annotation = $(html); | |
218 $annotation.attr('title', "Annotation: " + annotation.text); | |
219 $elem.append($annotation); | |
220 mpos.adjustDiv($annotation); | |
221 } | |
222 }; | |
223 | |
224 /** | |
225 * Get an authentication token from the token server. | |
226 * | |
227 * Stores the token and loads annotations on success. | |
228 */ | |
229 var loadAnnotationToken = function(data, password) { | |
230 var settings = data.settings; | |
231 var url = settings.annotationTokenUrl; | |
232 var params = {'user': settings.annotationUser}; | |
233 if (password != null) { | |
234 params.password = password; | |
235 } | |
236 // TODO: better error handling | |
237 $.post(url, params) | |
238 .done(function (authToken, authStatus) { | |
239 console.debug("got auth token data=", authToken); | |
240 data.annotationToken = authToken; | |
241 data.dlOpts.annotationToken = authToken; | |
242 digilib.fn.storeOptions(data); | |
243 //loadAnnotations(data); | |
244 }) | |
245 .fail(function (xhr, status) { | |
246 console.error("got auth token error:", xhr); | |
247 data.annotationToken = null; | |
248 data.settings.annotationUser = "anonymous"; | |
249 //loadAnnotations(data); | |
250 }); | |
251 }; | |
252 | |
253 /** | |
254 * loads all annotations for this url from the annotation server. | |
255 */ | |
256 var loadAnnotations = function(data) { | |
257 var settings = data.settings; | |
258 // we use the search API | |
259 var url = settings.annotationServerUrl + '/search'; | |
260 var pageUrl = getAnnotationPageUrl(data); | |
261 // send authentication token in header | |
262 headers = {}; | |
263 if (data.annotationToken != null) { | |
264 headers['x-annotator-auth-token'] = data.annotationToken; | |
265 } | |
266 // get only 20 annotations with this url | |
267 var query = { | |
268 limit : 20, | |
269 uri : pageUrl | |
270 }; | |
271 $.ajax(url, { | |
272 dataType : 'json', | |
273 data : query, | |
274 headers : headers, | |
275 success : function(annotData, annotStatus) { | |
276 console.debug("got annotation data=", annotData); | |
277 data.annotationData = annotData; | |
278 parseAnnotations(data, annotData); | |
279 renderAnnotations(data); | |
280 } | |
281 }); | |
282 }; | |
283 | |
284 /** | |
285 * parse all JSON-annotations in annotationData.rows and put in data.annotations | |
286 */ | |
287 var parseAnnotations = function(data, annotationData) { | |
288 var annotations = []; | |
289 for (var i = 0; i < annotationData.rows.length; ++i) { | |
290 var ann = annotationData.rows[i]; | |
291 var annot = parseAnnotation(data, ann); | |
292 if (annot != null) { | |
293 annotations.push(annot); | |
294 } | |
295 } | |
296 data.annotations = annotations; | |
297 }; | |
298 | |
299 /** | |
300 * Parse a JSON-annotation. | |
301 * | |
302 * Returns an annotation object. | |
303 */ | |
304 var parseAnnotation = function(data, ann) { | |
305 // TODO: check validity of annotation data | |
306 if (ann.areas != null && ann.areas.length > 0) { | |
307 var area = ann.areas[0]; | |
308 // currently only point annotations | |
309 var pos = geom.position(area.x, area.y); | |
310 return newAnnotation(data, pos, ann.text, ann.id, ann.uri, ann.user, ann.permissions, ann.tags); | |
311 } | |
312 return null; | |
313 }; | |
314 | |
315 /** | |
316 * Store an annotation on the annotation server. | |
317 */ | |
318 var storeAnnotation = function(data, annotation) { | |
319 console.debug("storeAnnotation:", annotation); | |
320 var settings = data.settings; | |
321 var url = settings.annotationServerUrl + '/annotations'; | |
322 var pageUrl = getAnnotationPageUrl(data); | |
323 // send authentication token in header | |
324 headers = { | |
325 'x-annotator-auth-token' : data.annotationToken | |
326 }; | |
327 // create annotation object to send | |
328 var annotData = { | |
329 areas : [{ | |
330 x : annotation.pos.x, | |
331 y : annotation.pos.y | |
332 }], | |
333 text : annotation.text, | |
334 uri : pageUrl, | |
335 user : settings.annotationUser | |
336 }; | |
337 var dataString = JSON.stringify(annotData); | |
338 $.ajax(url, { | |
339 type : 'POST', | |
340 dataType : 'json', | |
341 contentType : 'application/json', | |
342 data : dataString, | |
343 headers : headers, | |
344 success : function(annotData, annotStatus) { | |
345 console.debug("sent annotation data, got=", annotData, " status=" + annotStatus); | |
346 var annot = parseAnnotation(data, annotData); | |
347 // TODO: we have to add the returned data to the real annotation! | |
348 //renderAnnotations(data); | |
349 } | |
350 }); | |
351 | |
352 }; | |
353 | |
354 /** | |
355 * install additional buttons | |
356 */ | |
357 var installButtons = function(data) { | |
358 var settings = data.settings; | |
359 var mode = settings.interactionMode; | |
360 var buttonSettings = settings.buttonSettings[mode]; | |
361 // configure buttons through digilib "annotationSet" option | |
362 var buttonSet = settings.annotationSet || annotationSet; | |
363 // set annotationSet to [] or '' for no buttons (when showing annotations only) | |
364 if (buttonSet.length && buttonSet.length > 0) { | |
365 buttonSettings.annotationSet = buttonSet; | |
366 buttonSettings.buttonSets.push('annotationSet'); | |
367 } | |
368 }; | |
369 | |
370 /** | |
371 * plugin installation. called by digilib on plugin object. | |
372 */ | |
373 var install = function(plugin) { | |
374 digilib = plugin; | |
375 console.debug('installing annotations plugin. digilib:', digilib); | |
376 // import geometry classes | |
377 geom = digilib.fn.geometry; | |
378 FULL_AREA = geom.rectangle(0, 0, 1, 1); | |
379 // add defaults, actins, buttons | |
380 $.extend(digilib.defaults, defaults); | |
381 $.extend(digilib.actions, actions); | |
382 $.extend(digilib.buttons, buttons); | |
383 }; | |
384 | |
385 /** plugin initialization */ | |
386 var init = function(data) { | |
387 console.debug('initialising annotations plugin. data:', data); | |
388 var $data = $(data); | |
389 // set up | |
390 data.annotations = []; | |
391 if (digilib.plugins.buttons != null) { | |
392 installButtons(data); | |
393 } | |
394 if (data.dlOpts.annotationUser != null) { | |
395 // get annotation user from cookie | |
396 data.settings.annotationUser = data.dlOpts.annotationUser; | |
397 } | |
398 if (data.dlOpts.annotationToken != null) { | |
399 // get annotation token from cookie | |
400 data.annotationToken = data.dlOpts.annotationToken; | |
401 } | |
402 // install event handler | |
403 $data.bind('setup', handleSetup); | |
404 $data.bind('update', handleUpdate); | |
405 }; | |
406 | |
407 /** | |
408 * setup loads all annotations. | |
409 */ | |
410 var handleSetup = function(evt) { | |
411 console.debug("annotations: handleSetup"); | |
412 var data = this; | |
413 if (data.annotationToken == null) { | |
414 loadAnnotationToken(data); | |
415 } | |
416 // set up annotator (after html has been set up) | |
417 var uri = getAnnotationPageUrl(data); | |
418 annotator = new Annotator(data.$elem.get(0)) | |
419 //.addPlugin('Tags') | |
420 .addPlugin('Auth', { | |
421 token : data.annotationToken, | |
422 //tokenUrl: 'http://annotateit.org/api/token' | |
423 //tokenUrl: 'http://localhost:8080/test/annotator/token?user=anonymous' | |
424 //autoFetch: false | |
425 }) | |
426 .addPlugin('Permissions', { | |
427 user: data.settings.annotationUser, | |
428 userString: function (user) { | |
429 if (user && user.name) { | |
430 return user.name; | |
431 } | |
432 return user; | |
433 }, | |
434 userId: function (user) { | |
435 if (user && user.id) { | |
436 return user.id; | |
437 } | |
438 return user; | |
439 } | |
440 }) | |
441 .addPlugin('Store', { | |
442 prefix : data.settings.annotationServerUrl, | |
443 //prefix: 'http://localhost:18080/AnnotationManager/annotator', | |
444 //prefix: 'http://tuxserve03.mpiwg-berlin.mpg.de/AnnotationManager/annotator', | |
445 //prefix: 'http://annotateit.org/api', | |
446 annotationData: { | |
447 'uri': uri | |
448 }, | |
449 loadFromSearch: { | |
450 'limit': 20, | |
451 'uri': uri | |
452 } | |
453 }) | |
454 ; | |
455 | |
456 // monkey-patch Annotator.setupAnnotation | |
457 annotator.setupAnnotation = function(annotation, fireEvents) { | |
458 if (fireEvents == null) { | |
459 fireEvents = true; | |
460 } | |
461 | |
462 renderAnnotation(data, annotation); | |
463 | |
464 if (fireEvents) { | |
465 this.publish('annotationCreated', [annotation]); | |
466 } | |
467 return annotation; | |
468 }; | |
469 | |
470 | |
471 data.settings.annotatorInstance = annotator; | |
472 /* load annotations from server | |
473 if (data.annotationToken != null) { | |
474 loadAnnotations(data); | |
475 } else { | |
476 loadAnnotationToken(data); | |
477 } */ | |
478 }; | |
479 | |
480 /** | |
481 * update renders all annotations. | |
482 */ | |
483 var handleUpdate = function(evt) { | |
484 console.debug("annotations: handleUpdate"); | |
485 var data = this; | |
486 renderAnnotations(data); | |
487 }; | |
488 | |
489 // plugin object with name and init | |
490 // shared objects filled by digilib on registration | |
491 var plugin = { | |
492 name : 'annotations', | |
493 install : install, | |
494 init : init, | |
495 buttons : {}, | |
496 actions : {}, | |
497 fn : {}, | |
498 plugins : {} | |
499 }; | |
500 | |
501 if ($.fn.digilib == null) { | |
502 $.error("jquery.digilib.annotations must be loaded after jquery.digilib!"); | |
503 } else { | |
504 $.fn.digilib('plugin', plugin); | |
505 } | |
506 })(jQuery); |