PolyAnno: Further Product Development 1

This is part of my series of posts about the PolyAnno project – more here

Having clarified the general shape of the project and egun experimenting with each component, building the one package became interesting. Eventually it split into several separate pieces for individual release but all combined together in the one final website for the University of Edinburgh Collections. The bulk of this final code is held in the polyanno.js file, currently at the time of writing held in the original Polyglot project repo here. The structure of it is described in more detail in this post. (

WARNING: this post is mostly code that was been copied over to here at the time of originally writing to understand the evolution of the project better.

Basic and Setup Functions

So to identify what is currently being handled on the page, both for database handling and events, I’ve been primarily using global variables. I’m aware that this is not necessarily the best methodology but it was more a result of evolving earlier experimentation with individual components that just evolved along with the project than any planned code design.

var imageSelected; //info.json format URL

var vectorSelected = ""; //API URL
var vectorSelectedParent; //API URL
var currentCoords;

var polyanno_text_selected = ""; //API URL
var polyanno_text_selectedParent = ""; //API URL
var polyanno_text_selectedID; //DOM id
var polyanno_text_selectedHash; //parent API URL + ID
var polyanno_text_selectedFragment; //HTML Selection Object
var polyanno_text_type_selected = "";

//URLs
var targetSelected; //array
var targetType = ""; 
var childrenArray;

///[editor, vector, span] colours
var polyanno_highlight_colours_array = ["#EC0028","#EC0028","#EC0028"];
var polyanno_default_colours_array = ["buttonface","#03f","transparent"]; 

var editorsOpen = []; //those targets currently open in editors
var selectingVector = false; //used to indicate if the user is currently searching for a vector to link or not

 

This is followed by the basic setup of LeafletJS framework with Leaflet Draw and Leaflet IIIF, and then the variables containing the HTML that enable the package to be dynamically loaded into the page on initialising Polyanno (as long as the Polyanno CSS file is included in the page as well of course):

  • polyanno_top_bar_HTML
  • popupVectorMenuHTML
  • polyanno_image_viewer_HTML
  • addNewAnnoHTML
  • voteButtonsHTML
  • closeButtonHTML
  • linkButtonHTML
  • transcriptionIconHTML
  • translationIconHTML
  • popupLinkVectorMenuHTML
  • popupVectorParentMenuHTML
  • popupTranscriptionNewMenuHTML
  • popupTranslationNewMenuHTML
  • popupTranscriptionChildrenMenuHTML
  • popupTranslationChildrenMenuHTML
  • polyannoFavouriteBtnHTML
  • polyannoEditorHandlebarHTML
  • polyannoEditorHTML
  • polyannoEditorHTMLFull

Then these are followed by generic functions for validation and handling REST API calls etc.

Generic Annotation Functions

These were the functions that collectively allowed generic functions involved with handling the annotations.

var findClassID = function(classString, IDstring) {
  var IDindex = classString.search(IDstring) + IDstring.length;
  var IDstart = classString.substring(IDindex);
  var theID = IDstart.split(" ", 1);
  return theID[0];
};

var checkForVectorTarget = function(theText, the_target_type) {

  var findByBodyURL = polyanno_urls.annotation + "body/"+encodeURIComponent(theText);
  alert("the URL to check "+findByBodyURL);
  var the_regex = '/.*'+the_target_type+'.*/';
  var theChecking = checkFor(findByBodyURL, "target");
  if (  isUseless(theChecking[0])  ) { return false } 
  else {   return fieldMatching(theChecking, "format", 'image/SVG').body.id;  };

};

var lookupTargetChildren = function(target, baseURL) {
  var childTexts;
  var targetParam = encodeURIComponent(target);
  var aSearch = baseURL.concat("targets/"+targetParam);
  $.ajax({
    type: "GET",
    dataType: "json",
    url: aSearch,
    async: false,
    success: 
      function (data) {
        childTexts = data.list;
      }
  });

  alert("searching annos by "+aSearch+" and returned with "+encodeURIComponent(childTexts));

  if ((isUseless(childTexts))||(isUseless(childTexts[0]))) {
    return false;
  }
  else {

    var ids = [];
    childTexts.forEach(function(doc){
        ids.push(doc.body.id);
    });

    var theSearch = baseURL.concat("ids/"+encodeURIComponent(ids)+"/target/"+encodeURIComponent(target));
    var theDocs;
    $.ajax({
      type: "GET",
      dataType: "json",
      url: theSearch,
      async: false,
      success: 
        function (data) {
          theDocs = data.list;
        }
    });

    alert("searching the targets by "+theSearch+" and returned with "+JSON.stringify(theDocs));
    return theDocs;

  };
};

var updateVectorSelection = function(the_vector_url) {

  var textData = {target: [{id: the_vector_url, format: "SVG"}]};
  selectingVector.forEach(function(child){
    ////check selectingVector is not anno
    updateAnno(child[0].body.id, textData);
  });
  var editorID = fieldMatching(editorsOpen, "tSelectedParent", selectingVector[0][0].parent).editor;
  selectingVector = false;

  /////remove linkVector button

  closeEditorMenu(editorID);
  setTargets(openEditorMenu);

};


var votingFunction = function(vote, votedID, currentTopText, editorID) {
  var theVote = findBaseURL() + "voting/" + vote;
  var targetID = findBaseURL().concat(votedID); ///API URL of the annotation voted on
  var votedTextBody = $("#"+votedID).html(); 
  var targetData = {
    parent: polyanno_text_selectedParent, ///it is this that is updated containing the votedText within its body
    children: [{
      id: polyanno_text_selectedID, //ID of span location
      fragments: [{
        id: targetID
      }]
    }],
    votedText: votedTextBody,  topText: currentTopText
  };
  var updatedTranscription;
  $.ajax({
    type: "PUT",
    url: theVote,
    async: false,
    dataType: "json",
    data: targetData,
    success:
      function (data) {
        updatedTranscription = data.reloadText;
      }
  });

  if (updatedTranscription) {    polyanno_text_selected = targetID;  };
  if (updatedTranscription && (!isUseless(vectorSelected))) {
    var updateTargetData = {};
    updateTargetData[polyanno_text_type_selected] = targetID;
    updateAnno(vectorSelected, updateTargetData);
  };

  closeEditorMenu(editorID);
  setTargets(openEditorMenu);

///////if the parent is open in an editor rebuild carousel with new transcription 
  editorsOpen.forEach(function(editorOpen){
    editorOpen.children.forEach(function(eachChild){
      if ( eachChild.id == polyanno_text_selectedID ){
        closeEditorMenu(editorOpen.editor);
        ////reopen???
        //$(editorOpen.editor).effect("shake");
      };
    });
  });

};


var findHighestRankingChild = function(parent, locationID) {
  var theLocation = fieldMatching(getTargetJSON(parent).children, "id", locationID);
  var the_child = fieldMatching(theLocation.fragments, "rank", 0); 
  return findField(the_child, "id");
};

Text Selection Functions

This code is designed to enable the selection of text within certain elements to trigger events, and handling of the text selection and its associated information. It is based on the very helpful code

var outerElementTextIDstring;
var newContent;
var newNodeInsertID;
var startParentID;

function getSelected() {
  if(window.getSelection) { return window.getSelection() }
  else if(document.getSelection) { return document.getSelection(); }
  else {
    var selection = document.selection && document.selection.createRange();
    if(selection.text) { return selection.text; }
    return false;
  }
  return false;
};

var insertSpanDivs = function() {
  $(outerElementTextIDstring).html(newContent); 
  polyanno_text_selectedID = newNodeInsertID;
};

var findBaseURL = function() {
  if (polyanno_text_type_selected == "transcription") {  return polyanno_urls.transcription;  }
  else if (polyanno_text_type_selected == "translation") {  return polyanno_urls.translation;  };
};

var newAnnotationFragment = function(baseURL) {

  polyanno_text_selectedHash = polyanno_text_selectedParent.concat("#"+polyanno_text_selectedID); //need to refer specifically to body text of that transcription - make body independent soon so no need for the ridiculously long values??
  targetSelected = [polyanno_text_selectedHash];
  //polyanno_text_selectedFragment 
  var targetData = {text: polyanno_text_selectedFragment, parent: polyanno_text_selectedParent};
  var createdText;
  
  $.ajax({
    type: "POST",
    url: baseURL,
    async: false,
    data: targetData,
    success: 
      function (data) {
        createdText = data.url;
      }
  });

  polyanno_text_selected = createdText;
  var annoData = { body: { id: createdText }, target: [{id: polyanno_text_selectedHash, format: "text/html"}, {id: polyanno_text_selectedParent, format: "application/json"} ] };

  $.ajax({
    type: "POST",
    url: polyanno_urls.annotation,
    async: false,
    data: annoData,
    success: 
      function (data) {  }
  });

  var newHTML = $(outerElementTextIDstring).html();
  var parentData = {text: newHTML, children: [{id: polyanno_text_selectedID, fragments: [{id: polyanno_text_selected}]}]};
  updateAnno(polyanno_text_selectedParent, parentData);

};


var setpolyanno_text_selectedID = function(theText) {

  var findByBodyURL = polyanno_urls.annotation + "body/"+encodeURIComponent(theText);
  var the_regex = '/.*'+findBaseURL()+'.*/';
  var theTarget = fieldMatching(checkFor(findByBodyURL, "target"), "format", "text/html");
  if ( theTarget != false ) { 
    polyanno_text_selectedHash = theTarget.id;
    polyanno_text_selectedID = polyanno_text_selectedHash.substring(polyanno_text_selectedParent.length + 1); //the extra one for the hash        
  };

};

var newSpanClass = function(startParentClass) {
  if (startParentClass.includes('transcription-text')) {
    return "transcription-text opentranscriptionChildrenPopup";
  }
  else if (startParentClass.includes('translation-text')) {
    return "translation-text opentranslationChildrenPopup";
  }
  else {
    //alert("Please select transcription translation text");
    return null;
  };
};

var strangeTrimmingFunction = function(thetext) {
  if(thetext && (thetext = new String(thetext).replace(/^\s+|\s+$/g,''))) {
    return thetext.toString();
  }; 
};

var newTextPopoverOpen = function(theTextIDstring, theParent) {
  $('#polyanno-page-body').on("click", function(event) {
    if ($(event.target).hasClass("popupAnnoMenu") == false) {
      $(theTextIDstring).popover("hide");
    }
  });

  $('.openTranscriptionMenuNew').one("click", function(event) {
    insertSpanDivs();
    polyanno_text_selectedParent = polyanno_urls.transcription.concat(theParent);
    newAnnotationFragment(polyanno_urls.transcription);
    polyanno_text_type_selected = "transcription";
    targetType = "transcription";
    setTargets(openEditorMenu);
    $(theTextIDstring).popover('hide');    
  });

  $('.closeThePopover').on("click", function(event){
    $(theTextIDstring).popover("hide");
  });
};

var initialiseNewTextPopovers = function(theTextIDstring, theParent) {
  $(theTextIDstring).popover({ 
    trigger: 'manual',
    placement: 'top',
    html : true,
    container: 'body',
    title: closeButtonHTML,
    content: popupTranscriptionNewMenuHTML
  });
  $(theTextIDstring).popover('show');
  $(theTextIDstring).on("shown.bs.popover", function(ev) {
    newTextPopoverOpen(theTextIDstring, theParent);
  });
};

var initialiseOldTextPopovers = function(theTextIDstring) {
  $(theTextIDstring).popover({ 
    trigger: 'manual', //////
    placement: 'top',
    html : true,
    title: closeButtonHTML,
    content: popupTranscriptionChildrenMenuHTML
  });
  $(theTextIDstring).popover('show');
};

var setOESC = function(outerElementHTML, previousSpanContent, previousSpan) {
  var outerElementStartContent;
  if (previousSpan == "null" || previousSpan == null) {outerElementStartContent = previousSpanContent}
  else {
    var previousSpanAll = previousSpan.outerHTML;
    var StartIndex = outerElementHTML.indexOf(previousSpanAll) + previousSpanAll.length;
    outerElementStartContent = outerElementHTML.slice(0, StartIndex).concat(previousSpanContent);
  };
  return outerElementStartContent;
};

var setOEEC = function(outerElementHTML, nextSpanContent, nextSpan) {
    var outerElementEndContent;
    if (nextSpan == "null" || nextSpan == null) {outerElementEndContent = nextSpanContent}
    else {
      var EndIndex = outerElementHTML.indexOf(nextSpan.outerHTML);
      outerElementEndContent = nextSpanContent.concat(outerElementHTML.substring(EndIndex));
    };
    return outerElementEndContent;
};

var setNewTextVariables = function(selection, classCheck) {

  var startNode = selection.anchorNode; // the text type Node that the beginning of the selection was in
  var startNodeText = startNode.textContent; // the actual textual body of the startNode - removes all html element tags contained
  var startNodeTextEndIndex = startNodeText.toString().length;
  startParentID = startNode.parentElement.id;
  var startParentClass = startNode.parentElement.className;

  var nodeLocationStart = selection.anchorOffset; //index from within startNode text where selection starts
  var nodeLocationEnd = selection.focusOffset; //index from within endNode text where selection ends

  var endNode = selection.focusNode; //the text type Node that end of the selection was in 
  var endNodeText = endNode.textContent;
  var endParentID = endNode.parentElement.id; //the ID of the element type Node that the text ends in

  outerElementTextIDstring = "#" + startParentID; //will be encoded URI of API?

  if (classCheck.includes('opentranscriptionChildrenPopup')) { 
    initialiseOldTextPopovers(outerElementTextIDstring);
  }
  else if (classCheck.includes('opentranslationChildrenPopup')) { 
    initialiseOldTextPopovers(outerElementTextIDstring);
  }    
  else if (startParentID != endParentID) {
   // alert("you can't select across existing fragments' borders sorry");
  }
  else {

    newNodeInsertID = Math.random().toString().substring(2);

    var newSpan = "<a class='" + newSpanClass(startParentClass) + " ' id='" + newNodeInsertID + "' >" + selection + "</a>";
    var outerElementHTML = $(outerElementTextIDstring).html().toString(); //includes any spans that are contained within this selection 

    ///CONTENT BEFORE HIGHLIGHT IN THE TEXT TYPE NODE
    var previousSpanContent = startNodeText.slice(0, nodeLocationStart);

    //CONTENT BEFORE HIGHLIGHT IN THE ELEMENT TYPE NODE
    var previousSpan = startNode.previousElementSibling; //returns null if none i.e. this text node is first node in element node
    var outerElementStartContent = setOESC(outerElementHTML, previousSpanContent, previousSpan);

    ///CONTENT AFTER HIGHLIGHT IN THE TEXT TYPE NODE
    var nextSpanContent;
    if (endNode == startNode) { nextSpanContent = startNodeText.slice(nodeLocationEnd, startNodeTextEndIndex)}
    else {nextSpanContent = endNodeText.slice(0, nodeLocationEnd)};

    ///CONTENT AFTER HIGHLIGHT IN ELEMENT TYPE NODE
    var nextSpan = endNode.nextElementSibling; //returns null if none i.e. this text node is the last in the element node
    var outerElementEndContent = setOEEC(outerElementHTML, nextSpanContent, nextSpan );

    newContent = outerElementStartContent + newSpan + outerElementEndContent;
    polyanno_text_selectedFragment = strangeTrimmingFunction(selection);

    initialiseNewTextPopovers(outerElementTextIDstring, startParentID);

  };
};

 

Viewer Windows

Then the code handles the machinery of the different “viewer windows” – the Dragon Drop boxes containing the images or other data.

var setChildrenArray = function(callback_function) {  
  alert("the target selected is "+JSON.stringify(targetSelected));
  childrenArray = lookupTargetChildren(targetSelected[0], findBaseURL()); 
//  alert("the childrenArray is "+JSON.stringify(childrenArray));
  if (!isUseless(callback_function)) { callback_function(); };
};

var buildCarousel = function(existingChildren, popupIDstring, extraHTML) {

  var openingHTML = "

 

Highlighting

As discussed in Verification, I decided to highlight the data of the same nature when hovered over, and this is implemented with the following code:

var highlightVectorChosen = function(chosenVector, colourChange) {
  allDrawnItems.eachLayer(function(layer){
    if(layer._leaflet_id == chosenVector) {
      layer.setStyle({color: colourChange});
    };
  });
};

var highlightEditorsChosen = function(chosenEditor, colourChange) {
  if (!chosenEditor.includes("#")) {  chosenEditor = "#"+chosenEditor; }
  $(chosenEditor).find(".polyanno-colour-change").css("background-color", colourChange);
};

var highlightSpanChosen = function(chosenSpan, colourChange) {
  $(chosenSpan).css("background-color", colourChange);
};

var findAndHighlight = function(searchField, searchFieldValue, highlightColours) {
  var thisEditor = checkingItself(searchField, searchFieldValue, "editor");
  if (!isUseless(thisEditor)) {  highlightEditorsChosen(thisEditor, highlightColours[0]);  };
  var thisVector = checkingItself(searchField, searchFieldValue, "vSelected");
  if (!isUseless(thisVector)) {  highlightVectorChosen(thisVector, highlightColours[1]);  };
  var thisSpan = checkingItself(searchField, searchFieldValue, "tSelectedID");
  if (!isUseless(thisSpan)) {  
    if (!thisSpan.includes("#")) {  thisSpan = "#"+thisSpan; };
    if (!isUseless($(thisSpan))) {  highlightSpanChosen(thisSpan, highlightColours[2]);  };
  };
};

var resetVectorHighlight = function(thisEditor) {
  var thisVector = fieldMatching(editorsOpen, "editor", thisEditor).vSelected; 
  if(!isUseless(thisVector)){ highlightVectorChosen("#"+thisVector, polyanno_default_colours_array[1]); };
};

Where the colours are specified in two variable arrays, with the defaults defined at the top of the file but can be changed by the users.

///[editor, vector, span] colours
var polyanno_highlight_colours_array = ["#EC0028","#EC0028","#EC0028"];
var polyanno_default_colours_array = ["buttonface","#03f","transparent"];

 

Leaflet

The details of the specific functionality around Leaflet and its packages are then written in:

var polyanno_leaflet_basic_setup = function() {
  popupVectorMenu = L.popup()
      .setContent(popupVectorMenuHTML()); /////

  polyanno_map = L.map('polyanno_map');
  polyanno_map.options.crs = L.CRS.Simple;
  polyanno_map.setView(
    [0, 0], //centre coordinates
    0 //zoom needs to vary according to size of object in viewer but whatever
  );
  polyanno_map.options.crs = L.CRS.Simple;

  baseLayer = L.tileLayer.iiif(imageSelected);

  polyanno_map.addLayer(baseLayer);

  polyanno_map.addLayer(allDrawnItems);
  new L.Control.Draw(controlOptions).addTo(polyanno_map);

  polyanno_map.whenReady(function(){
    mapset = true;
  });
};

//load the existing vectors
var polyanno_load_existing_vectors = function() {

  var existingVectors = lookupTargetChildren(imageSelected, polyanno_urls.vector);

  var tempGeoJSON = {  "type": "Feature",  "properties":{},  "geometry":{}  };
  var currentVectorLayers = {};

  if (!isUseless(existingVectors)) {
    existingVectors.forEach(function(vector) {

      var oldData = tempGeoJSON;
      oldData.geometry.type = vector.notFeature.notGeometry.notType;
      oldData.geometry.coordinates = [vector.notFeature.notGeometry.notCoordinates];
      oldData.properties.transcription = findField(vector, "transcription");
      oldData.properties.translation = findField(vector, "translation");
      oldData.properties.parent = findField(vector, "parent");

      var existingVectorFeature = L.geoJson(oldData, 
        { onEachFeature: function (feature, layer) {
            layer._leaflet_id = vector.id,
            allDrawnItems.addLayer(layer),
            layer.bindPopup(popupVectorMenu)
          }
        }).addTo(polyanno_map);

    });
  };
};

var polyanno_creating_vec = function() {
  polyanno_map.on('draw:created', function(evt) {

    var layer = evt.layer;
    var shape = layer.toGeoJSON();
    var vectorOverlapping = searchForVectorParents(allDrawnItems, shape.geometry.coordinates[0]); 
    allDrawnItems.addLayer(layer);
    if (  (vectorOverlapping != false) && (selectingVector == false)  ) { 
      allDrawnItems.removeLayer(layer);
      vectorSelected = vectorOverlapping;
      $("#map").popover();
      $("#map").popover('show');
    }
    else {
      var annoData = {geometry: shape.geometry, metadata: imageSelectedMetadata, parent: vectorOverlapping };

      if (selectingVector != false) { 
        var theTopText = findHighestRankingChild(polyanno_text_selectedParent, polyanno_text_selectedID);
        annoData[polyanno_text_type_selected] = theTopText;  
      };

      $.ajax({
        type: "POST",
        url: polyanno_urls.vector,
        async: false,
        data: annoData,
        success: 
          function (data) {
            vectorSelected = data.url;
          }
      });

      var targetData = {target: [], body: {}};
      var IIIFsection = getIIIFsectionURL(imageSelected, shape.geometry.coordinates[0], "jpg");
      targetData.target.push({
          "id": imageSelected,
          "format": "application/json"
      });
      targetData.target.push({
          "id": IIIFsection,
          "format": "jpg" ////official jpg file type???
      });

      targetData.body.id = vectorSelected;

      $.ajax({
        type: "POST",
        url: polyanno_urls.annotation,
        async: false,
        data: targetData,
        success: 
          function (data) {}
      });

      layer._leaflet_id = vectorSelected;
      if (selectingVector == false) { layer.bindPopup(popupVectorMenu).openPopup(); }
      else {  updateVectorSelection(vectorSelected); };
    };

  });
};

var polyanno_vec_select = function() {

  polyanno_map.on('draw:deletestart', function(){
    currentlyDeleting = true;
  });
  polyanno_map.on('draw:deletestop', function(){
    currentlyDeleting = false;
  });
  polyanno_map.on('draw:editstart', function(){
    currentlyEditing = true;
  });
  polyanno_map.on('draw:editstop', function(){
    currentlyEditing = false;
  });

  allDrawnItems.on('click', function(vec) {
    vectorSelected = vec.layer._leaflet_id;
    if (currentlyEditing || currentlyDeleting) {}
    else if (selectingVector != false) {  alert("make a new vector!");  }
    else {  vec.layer.openPopup();  };

  });

};

var polyanno_vector_edit_setup = function() {
  //////update DB whenever vector coordinates are changed
  allDrawnItems.on('edit', function(vec){
    var shape = vec.layer.toGeoJSON();
    /////
    updateAnno(vectorSelected, shape); ////////////
    /////
  });

  //////update DB whenever vector is deleted
  allDrawnItems.on('remove', function(vec){

  });
};

var polyanno_image_popovers_setup = function() {
  polyanno_map.on('popupopen', function() {

    $('.openTranscriptionMenu').one("click", function(event) {
      checkEditorsOpen("vector", "transcription");
      polyanno_map.closePopup();
    });

    $('.openTranslationMenu').one("click", function(event) {
      checkEditorsOpen("vector", "translation");
      polyanno_map.closePopup();
    });

  });

  /////maybe change to be more specific to the drawing?
  /*
  $('#imageViewer').popover({ 
    trigger: 'manual',
    placement: 'top',
    html : true,
    title: closeButtonHTML,
    content: popupLinkVectorMenuHTML
  });

  $('#imageViewer').on("shown.bs.popover", function(event) {
      $('#polyanno-page-body').on("click", function(event) {
        if ($(event.target).hasClass("popupAnnoMenu") == false) {
          $('#map').popover("hide");
        }
      });
      $('.closeThePopover').on("click", function(event){
        $('#map').popover("hide");
      });
  });
  */
  $('#map').popover({ 
    trigger: 'manual',
    placement: 'top',
    html : true,
    title: closeButtonHTML,
    content: popupVectorParentMenuHTML
  });

  $('#map').on("shown.bs.popover", function(event) {

    $('#polyanno-page-body').one("click", '.openTranscriptionMenuParent', function(event) {
      checkEditorsOpen("vector", "transcription");
      $('#map').popover('hide');
    });
    $('#polyanno-page-body').one("click", '.openTranslationMenuParent', function(event) {
      checkEditorsOpen("vector", "translation");
      $('#map').popover('hide');
    });

    $('.closeThePopover').on("click", function(event){
      $('#map').popover("hide");
    });
  });
};

Polyanno Initialising

To enable the dynamic setup of Polyanno within a page, all the event listeners need to be setup, which is divided up into several functions which are then triggered by the polyanno_setup function (varying depending on the options input) as shown below:

var polyanno_setup = function(opts) {

  if (opts.minimising == false) {  polyanno_minimising = false;  };
  addIMEs(true, true, true); //why is this not working??????

  document.getElementById("polyanno-top-bar").innerHTML = polyanno_top_bar_HTML;

  polyanno_setup_storage(opts.storage);

  if (!isUseless(opts.highlighting)) {  polyanno_setup_highlighting();  };

  if (opts.voting == false) {  polyanno_voting = false;  }
  else {  polyanno_setup_voting()  };

  var polyanno_metadata_title_search = $.grep(imageSelectedMetadata, function(e){ return e.label == "Repro Title"; });
  var polyanno_image_title = polyanno_metadata_title_search[0].value;
  var polyanno_image_title_HTML = "<span>"+polyanno_image_title+"</span>";

  var image_viewer_id = add_dragondrop_pop( "polyanno-image-box", polyanno_image_viewer_HTML , "polyanno-page-body", polyanno_minimising, polyanno_image_title_HTML );
  //$(".polyanno-image-box").find("") find handlebar and remove close button
  $(image_viewer_id).attr("id", "imageViewer");

  polyanno_leaflet_basic_setup();
  polyanno_load_existing_vectors();
  polyanno_creating_vec();
  polyanno_vec_select();
  polyanno_vector_edit_setup();
  polyanno_image_popovers_setup();

  initialise_dragondrop("polyanno-page-body", {"minimise": polyanno_minimising });

  if (!isUseless(opts.users)) { polyanno_setup_users(opts.users); };

  polyanno_setup_editor_events();

};

 

Next: Dragon Drop

This is part of my series of posts about the PolyAnno project – more here

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s