diff --git a/drupal_annotation/annotation.module b/drupal_annotation/annotation.module index bab491f..7674f5b 100644 --- a/drupal_annotation/annotation.module +++ b/drupal_annotation/annotation.module @@ -281,6 +281,21 @@ function annotation_menu() { 'file' => 'annotation.store.inc', ); + $items['annotation/api/tags'] = array( + 'page callback' => 'annotation_api_tags', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + 'file' => 'annotation.store.inc', + ); + + $items['annotation/api/quotation_list'] = array( + 'page callback' => 'annotation_api_quotation_list', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + 'file' => 'annotation.store.inc', + ); + + return $items; } @@ -1026,7 +1041,6 @@ function annotation_export_rqda($uid, $filename) { * @return String containing HTML that renders the annotated text in its context. */ function annotation_extract($annotation, $len_before, $len_after){ - // Get the HTML source text of the annotated field. $entity = entity_load_single($annotation->entity_type, $annotation->entity_id); $field_items = field_get_items($annotation->entity_type, $entity, $annotation->field_name, $annotation->field_language); diff --git a/drupal_annotation/annotation.store.inc b/drupal_annotation/annotation.store.inc index e533c68..25fd822 100644 --- a/drupal_annotation/annotation.store.inc +++ b/drupal_annotation/annotation.store.inc @@ -37,16 +37,43 @@ function annotation_api_endpoint($id = NULL) { } /** - * Annotation API root + * API for tags, to populate the sidebar */ -function annotation_api() { - drupal_json_output( - array( - 'name' => 'Annotator Store API', - 'version' => ANNOTATOR_VERSION, - ) - ); +function visible_tags($nid){ + $vocabulary = taxonomy_vocabulary_machine_name_load('openethnographer'); + $tree = taxonomy_get_tree($vocabulary->vid); + // XXX this needs to handle public/private tags + if(!user_access('view any annotations') ) { + $tree = array_filter($tree, function($k){ + return $k->uid != $USER->uid;}); + } + //$parents = array_filter($tree, function($k){ + return $tree; +} + + +function annotation_api_quotation_list(){ + $tid = $_GET['tid']; + $term = taxonomy_term_load($tid); + print("

Content tagged $term->name


");# " + $term->name + ""); + print(annotation_quotation_list($term)); +} + + + +function annotation_api_tags(){ + //XXX filter tags to those present on a page + // -- complication is that we also need all their ancestors + if(!empty($_GET['nid'])){ + $nid = $_GET['nid']; + } + + $vocabulary = taxonomy_vocabulary_machine_name_load('openethnographer'); + $tree = taxonomy_get_tree($vocabulary->vid); + watchdog('oeth', 'I am a teapot'); + return drupal_json_output(visible_tags()); } + /** * Annotation API index diff --git a/drupal_annotator/annotator.module b/drupal_annotator/annotator.module index ca8798b..f543793 100644 --- a/drupal_annotator/annotator.module +++ b/drupal_annotator/annotator.module @@ -243,15 +243,20 @@ class OpenethnographerTaxonomy extends TaxonomyDisplayTermDisplayHandler { public function displayTerm($term, $options = NULL) { $build = array(); $build['term'] = array( - '#markup' => $this->quotation_list($term), + '#markup' => annotation_quotation_list($term), '#weight' => 0, ); return $build; } - function annotations_by_node($nid, $termdivs, $term){ + + public function formFieldset(&$form, &$values, $options = NULL) {} + public function formSubmit($form, &$values) {} +} + + +function annotation_annotations_by_node($nid, $termdivs, $term){ $nd = node_load($nid); - $short_title = 'fubar'; $divs = implode('', $termdivs); $header = '
Annotations on ' . $nd->title .':
'; $inner = '
' . $divs . '
'; @@ -259,22 +264,18 @@ class OpenethnographerTaxonomy extends TaxonomyDisplayTermDisplayHandler { return $wrapped; } - function quotation_list($term){ +function annotation_quotation_list($term){ $annots_by_nid = array(); $ans = db_query("SELECT * from {annotation} where tid = :tid", array(':tid' => $term->tid)); if($ans){ while($row = $ans->fetchAssoc()){ - $ent = current(entity_load('annotation', array($row['id']))); - $annots_by_nid[$ent->nid][] = annotation_extract($ent, 35, 25); + $annot = current(entity_load('annotation', array($row['id']))); + $annots_by_nid[$annot->entity_id][] = annotation_extract($annot, 35, 25); } } $nodedivs = array(); foreach($annots_by_nid as $k=>$v){ - $nodedivs[] = $this->annotations_by_node($k, $v, $term); + $nodedivs[] = annotation_annotations_by_node($k, $v, $term); } return implode(", ", $nodedivs); } - - public function formFieldset(&$form, &$values, $options = NULL) {} - public function formSubmit($form, &$values) {} -} diff --git a/drupal_annotator/annotator_view/view_annotator.js b/drupal_annotator/annotator_view/view_annotator.js index a4d7cae..e4f9644 100644 --- a/drupal_annotator/annotator_view/view_annotator.js +++ b/drupal_annotator/annotator_view/view_annotator.js @@ -36,18 +36,6 @@ $ = jQuery; Annotator.Plugin.AnnotatorViewer = (function(_super) { __extends(AnnotatorViewer, _super); - AnnotatorViewer.prototype.events = { - 'annotationsLoaded': 'onAnnotationsLoaded', - 'annotationCreated': 'onAnnotationCreated', - 'annotationDeleted': 'onAnnotationDeleted', - 'annotationUpdated': 'onAnnotationUpdated', - ".annotator-viewer-delete click": "onDeleteClick", - ".annotator-viewer-edit click": "onEditClick", - ".annotator-viewer-delete mouseover": "onDeleteMouseover", - ".annotator-viewer-delete mouseout": "onDeleteMouseout", - }; - - AnnotatorViewer.prototype.field = null; AnnotatorViewer.prototype.input = null; @@ -60,13 +48,35 @@ $ = jQuery; function AnnotatorViewer(element, options) { if($('.annotations-list-uoc').length == 0){ $( "body" ).append( this.createAnnotationPanel() ); + $('#annotator-tabs').tabs(); + $(".container-anotacions").toggle(); $("#annotations-panel").click(function(event) { $(".container-anotacions").toggle("slide"); }); - } + // set selected nodes according to the radio buttons + $('input[type=radio][name=showtags]').on('change', function(){ + selectors = { + 'mine': '.annotator-taglist-mytag', + 'all': '.annotator-taglist-mytag,.annotator-taglist-notmytag'} + cls = selectors[$(this).val()]; + $tree = jQuery('.annotator-taglist'); + state = $tree.tree('getState'); + state['selected_node'] = jQuery(cls).map( + function(){ + return jQuery(this).data('id') + }); + // deselect all nodes + while($tree.tree('getSelectedNode')){ + $tree.tree('selectNode', null); + } + $tree.tree('setState', state); + + // change which tags are highlighted + AnnotatorViewer.prototype.showSelectedTags(); + }); }; AnnotatorViewer.prototype.pluginInit = function() { @@ -76,94 +86,148 @@ $ = jQuery; $('#type_share').click(this.onFilter); $('#type_own').click(this.onFilter); - - }; - - /* - Check the checkboxes filter to search the annotations to show. - Shared annotations have the class shared - My annotations have the me class - */ - AnnotatorViewer.prototype.onFilter = function(event) { - }; - - AnnotatorViewer.prototype.onDeleteClick = function(event) { - }; - - AnnotatorViewer.prototype.onEditClick = function(event) { - }; - - AnnotatorViewer.prototype.onButtonClick = function(event, type) { - }; - - //Textarea editor controller - AnnotatorViewer.prototype.textareaEditor = function(annotator_textArea,item) { - }; - - AnnotatorViewer.prototype.tinymceActivation = function(selector) { - } - - //Event triggered when save the content of the annotation - AnnotatorViewer.prototype.onSavePanel = function(event) { - var current_annotation = event.data.annotation; - var textarea = $('li#annotation-'+current_annotation.id).find('textarea.panelTextArea'); - current_annotation.text = textarea.val(); - this.annotator.updateAnnotation(current_annotation); - this.normalEditor(current_annotation,textarea); + this.annotator.subscribe( + 'annotationViewerShown', + this.onAnnotationViewerShown); }; - //Event triggered when save the content of the annotation - AnnotatorViewer.prototype.onCancelPanel = function(event) { - var current_annotation = event.data.annotation; - var textarea = $('li#annotation-'+current_annotation.id).find('textarea.panelTextArea'); - this.normalEditor(current_annotation,textarea); - - }; - - //Annotator in a non editable state - AnnotatorViewer.prototype.normalEditor = function(annotation,editableTextArea) { - }; - - AnnotatorViewer.prototype.onDeleteMouseover = function(event) { - }; - - AnnotatorViewer.prototype.onDeleteMouseout = function(event) { - }; - - AnnotatorViewer.prototype.onAnnotationCreated = function(annotation) { - }; + AnnotatorViewer.prototype.onAnnotationViewerShown = function(event){ + $('.annotator-tag a').click(function(){ + tid = jQuery(this).attr('href').split('/').pop(); + AnnotatorViewer.prototype.displayTag(tid); + return false; + }); + } + } - AnnotatorViewer.prototype.onAnnotationUpdated = function(annotation) { - }; - AnnotatorViewer.prototype.onAnnotationsLoaded = function(annotations) { - }; - - AnnotatorViewer.prototype.onAnnotationDeleted = function(annotation) { - }; - - AnnotatorViewer.prototype.mascaraAnnotation = function(annotation) { - return ''; - }; AnnotatorViewer.prototype.createAnnotationPanel = function(annotation) { - var sidebar_label = 'OPEN SIDEBAR'; - var panel_content = 'YOUR CONTENT HERE'; - var annotation_layer = '
'+ sidebar_label +'0
'; + var sidebar_label = 'Open Ethnographer'; + var radios = 'Show my tags
Show all tags
' + var panel_content = '

Open Ethnographer

' + radios + '
Click a tag name to see where it has been used
'; + var annotation_layer = '
'+ sidebar_label +'
'; + // nodeid is ignored on the backend for now, + // but we may want to filter nodes present on the current node + nodeid = window.location.pathname.split('/').pop() + jQuery.get('/annotation/api/tags?node=' + nodeid, this.onTagJSON); return annotation_layer; }; - - AnnotatorViewer.prototype.createReferenceAnnotation = function(annotation) { - }; - - AnnotatorViewer.prototype.uniqId = function() { - return Math.round(new Date().getTime() + (Math.random() * 100)); - } + AnnotatorViewer.prototype.showSelectedTags = function(){ + tids = $('.annotator-taglist').tree('getState')['selected_node']; + //disable all tags + jQuery('.annotator-hl').addClass('annotator-hl-disabled').removeClass('annotator-hl'); + + //then re-enable tags with the right ids + for(i in tids){ + selector = '[data-tid=' + tids[i] + ']'; + jQuery(selector).addClass('annotator-hl'); + } + } + + AnnotatorViewer.prototype.displayTag = function(tid){ + jQuery('.annotator-termdetail').load('/annotation/api/quotation_list?tid=' + tid); + jQuery('#annotator-tabs').tabs({active: 1}); + jQuery(".container-anotacions").slideDown(); + } + + AnnotatorViewer.prototype.onTagJSON = function(data){ + var html = ''; + for(var i in data){ + var tag = data[i]; + var classes = ['annotator-tag']; + if( tag.uid == Drupal.settings.annotator_permissions.user.uid){ + classes.push('annotator-tag-mine'); + } + else { + classes.push('annotator-tag-others'); + } + } + //jQuery('.annotator-taglist').html(html); + + // make some tweaks to the tag data while it's still conveniently flat + jQuery(data).each(function(i,v){ + // tid -> id (for benefit of jqtree) + v['id'] = v['tid']; + // don't let long tag names mess up the layout + v['label'] = v['name'].substr(0,25); + // separate tags whether this user created them + v['is_mine'] = v['uid'] == Drupal.settings.annotator_permissions.user.uid; + }); + + // recursively find a term, so we can give it children + findNode = function(node, nid){ + if(node['tid'] == nid) + return node; + if(!node.hasOwnProperty('children')) return null; + for(cid in node['children']){ + found = findNode(node['children'][cid]); + if(found) + return found; + } + return null; + } + + // turn the taxonomy into a real tree + for(var k = data.length-1; k >= 0; k--){ + leaf = data[k]; + parentid = leaf['parents'][0]; // ignore multiple inheritance + if(parentid == "0") // skip roots without parents + continue; + // look for a node with the right id + for(var n in data){ + parent = findNode(data[n], parentid); + // add this node as a child + if(parent){ + if(!parent.hasOwnProperty('children')){ + parent['children'] = [];} + parent['children'].push(leaf); + data.splice(k, 1); + } + } + } + $tree = jQuery('.annotator-taglist') + $tree.tree( + {data: data, + autoOpen: true, + keyboardSupport: false, + dragAndDrop: false, + onCreateLi: function(node, li){ + li.attr('data-id', node.id); + li.addClass('annotator-taglist-tag'); + if(node['is_mine']) + li.addClass('annotator-taglist-mytag'); + else + li.addClass('annotator-taglist-notmytag'); + } + }); + $tree.bind( + 'tree.click', + function(e) { + // Disable single selection + e.preventDefault(); + AnnotatorViewer.prototype.displayTag(e.node.id); + return; + var selected_node = e.node; + if (selected_node.id == undefined) { + console.log('The multiple selection functions require that nodes have an id'); + } + if ($tree.tree('isNodeSelected', selected_node)) { + $tree.tree('removeFromSelection', selected_node); + } + else { + $tree.tree('addToSelection', selected_node); + } + AnnotatorViewer.prototype.showSelectedTags(); + } + ); + // use the radio button to select all + jQuery('input[value=all]').click(); + } - return AnnotatorViewer; })(Annotator.Plugin); diff --git a/drupal_annotator/css/openethnographer.css b/drupal_annotator/css/openethnographer.css index 1989d0c..eae29e5 100644 --- a/drupal_annotator/css/openethnographer.css +++ b/drupal_annotator/css/openethnographer.css @@ -79,3 +79,32 @@ } +.annotator-taglist-tag {} + +.annotator-taglist-mytag {} + +.annotator-taglist-notmytag {} + +/* stop jquery-ui changing our background color */ + +.ui-widget-content { + background: #ddd; + border: 0px; + } + +/* tidy up the sidebar */ + +#anotacions-uoc-panel { + overflow-x: hidden; + overflow-y: default; + } + +.jqtree-element { + font-weight: lighter; + } + + +ul.jqtree-tree li.jqtree-selected > .jqtree-element, +ul.jqtree-tree li.jqtree-selected > .jqtree-element:hover { + font-weight: bold; + } \ No newline at end of file diff --git a/drupal_annotator/jqtree/jqtree.css b/drupal_annotator/jqtree/jqtree.css index aa52c00..24a0410 100644 --- a/drupal_annotator/jqtree/jqtree.css +++ b/drupal_annotator/jqtree/jqtree.css @@ -130,14 +130,16 @@ ul.jqtree-tree .jqtree-element { ul.jqtree-tree li.jqtree-selected > .jqtree-element, ul.jqtree-tree li.jqtree-selected > .jqtree-element:hover { + /* background-color: #97BDD6; background: -webkit-gradient(linear, left top, left bottom, from(#BEE0F5), to(#89AFCA)); background: -moz-linear-gradient(top, #BEE0F5, #89AFCA); background: -ms-linear-gradient(top, #BEE0F5, #89AFCA); background: -o-linear-gradient(top, #BEE0F5, #89AFCA); - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7); + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);*/ } + ul.jqtree-tree .jqtree-moving > .jqtree-element .jqtree-title { outline: dashed 1px #0000ff; } diff --git a/drupal_annotator/jqtree/tree.jquery.js b/drupal_annotator/jqtree/tree.jquery.js index 9de0d0c..942fa8c 100644 --- a/drupal_annotator/jqtree/tree.jquery.js +++ b/drupal_annotator/jqtree/tree.jquery.js @@ -3385,4 +3385,4 @@ limitations under the License. }).call(this); -},{}]},{},[3]) \ No newline at end of file +},{}]},{},[3]) diff --git a/drupal_annotator/js/annotator_drupalnode.js b/drupal_annotator/js/annotator_drupalnode.js index 0bcc4c1..7af860b 100644 --- a/drupal_annotator/js/annotator_drupalnode.js +++ b/drupal_annotator/js/annotator_drupalnode.js @@ -43,6 +43,9 @@ Annotator.Plugin.DrupalNode = (function(_super) { 'annotationsLoaded', function(annotations) { jQuery('.annotator-hl').each(function() { + tid = jQuery(this).data('annotation')['tid']; + jQuery(this).attr('data-tid', tid); + if (jQuery(this).data('annotation').user.uid == Drupal.settings.annotator_permissions.user.uid) { jQuery(this).addClass('annotator-own-annotation'); } diff --git a/drupal_annotator/plugins/annotator/SidebarAnnotatorPlugin.class.inc b/drupal_annotator/plugins/annotator/SidebarAnnotatorPlugin.class.inc index fe113e7..fc137d4 100644 --- a/drupal_annotator/plugins/annotator/SidebarAnnotatorPlugin.class.inc +++ b/drupal_annotator/plugins/annotator/SidebarAnnotatorPlugin.class.inc @@ -5,7 +5,7 @@ */ class SidebarAnnotatorPlugin extends AnnotatorPlugin { public function setup() { - watchdog('oeth', 'annotator setup'); + drupal_add_library('system', 'ui.tabs'); drupal_add_js(drupal_get_path('module', 'annotator') . '/annotator_view/view_annotator.js'); drupal_add_js(drupal_get_path('module', 'annotator') . '/annotator_view/categories.js'); drupal_add_js(drupal_get_path('module', 'annotator') . '/annotator_view/lib/jquery-i18n-master/jquery.i18n.js'); @@ -16,5 +16,9 @@ class SidebarAnnotatorPlugin extends AnnotatorPlugin { drupal_add_css( drupal_get_path('module', 'annotator') . '/annotator_view/css/style.css', array('type' => 'file', 'basename' => 'annotator_view_style.css')); + + //for tree view of tags + drupal_add_js(drupal_get_path('module', 'annotator') . '/jqtree/tree.jquery.js'); + drupal_add_css(drupal_get_path('module', 'annotator') . '/jqtree/jqtree.css'); } }