changeset 1102:8878c6e36fd5

refactoring; define regions in JS
author hertzhaft
date Fri, 26 Oct 2012 10:32:14 +0200
parents 34f893492adb
children d8c380faa347
files webapp/src/main/webapp/jquery/jquery.digilib.regions.js
diffstat 1 files changed, 129 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/webapp/src/main/webapp/jquery/jquery.digilib.regions.js	Thu Oct 25 19:35:33 2012 +0200
+++ b/webapp/src/main/webapp/jquery/jquery.digilib.regions.js	Fri Oct 26 10:32:14 2012 +0200
@@ -2,8 +2,8 @@
 
 Mark up a digilib image with rectangular regions.
 
-If hasRegionInfo=true reads regions from page HTML.
-Element with regions has to be in digilib element, e.g.
+If the parameter "processHtmlRegions" is set, the plugin reads region data from HTML.
+Region data should be declared inside in the digilib element, like so:
 
 <map class="dl-keep dl-regioncontent">
    <area href="http://www.mpiwg-berlin.mpg.de" coords="0.1,0.1,0.4,0.1" alt="MPI fuer Wissenschaftsgeschichte"/>
@@ -13,7 +13,7 @@
 
 According to the HTML specs, "area" and "a" elements are allowed inside of a "map".
 Both can have a "coords" attribute, but "area" elements can't contain child nodes.
-To have regions with content use "a" tags, e.g.
+To have regions with content use "a" tags, like so:.
 
 <map class="dl-keep dl-regioncontent">
    <a href="http://www.mpiwg-berlin.mpg.de" coords="0.4907,0.3521,0.1458,0.107">
@@ -25,6 +25,19 @@
    <area coords="0.3,0.5,0.15,0.1" />
 </map>
 
+Regions can also be defined in Javascript:
+Set the parameter "regions" to an array with items.
+Each item should be an object containing the following fields:
+
+rect
+    a retangle with relative coordinates (0..1);
+index (optional)
+    a number to display in the region
+attributes (optional)
+    HTML attributes for the region (id, class, title)
+inner (optional)
+    inner HTML (has to be a jQuery object)
+
 */
 
 (function($) {
@@ -41,6 +54,8 @@
         };
     // affine geometry plugin
     var geom = null;
+    // convenience variable, set in init()
+    var CSS = '';
 
     var buttons = {
         defineregion : {
@@ -105,14 +120,17 @@
         'regionSet' : ['regions', 'defineregion', 'removeregion', 'removeallregions', 'regioninfo', 'findcoords', 'finddata', 'lessoptions'],
         // url param for regions
         'rg' : null,
+        // array with region data
+        'regions' : null,
         // region attributes to copy from HTML
         'regionAttributes' : {
             'id'    :1,
             'href'  :1,
-            'title' :1,
+            'name'  :1,
+            'alt'   :1,
             'target':1,
-            'style' :1,
-            'class' :1
+            'title' :1,
+            'style' :1
             }
         };
 
@@ -124,7 +142,6 @@
                 alert("Please turn on regions visibility!");
                 return;
             }
-            var cssPrefix = data.settings.cssPrefix;
             var $elem = data.$elem;
             var $body = $('body');
             var bodyRect = geom.rectangle($body);
@@ -132,11 +149,11 @@
             var scalerRect = geom.rectangle($scaler);
             var pt1, pt2;
             // overlay prevents other elements from reacting to mouse events 
-            var $overlay = $('<div class="'+cssPrefix+'overlay" style="position:absolute"/>');
+            var $overlay = $('<div class="'+CSS+'overlay" style="position:absolute"/>');
             $body.append($overlay);
             bodyRect.adjustDiv($overlay);
-            var $regionDiv = newRegionDiv(data);
-            addRegionAttributes(data, $regionDiv, {'class' : cssPrefix+"regionURL"});
+            var attr = {'class' : CSS+"regionURL"};
+            var $regionDiv = newRegionDiv(data, attr);
 
             // mousedown handler: start sizing
             var regionStart = function (evt) {
@@ -192,7 +209,7 @@
                 alert("Please turn on regions visibility!");
                 return;
             }
-            var selector = 'div.'+data.settings.cssPrefix+'regionURL';
+            var selector = 'div.'+CSS+'regionURL';
             var $regionDiv = data.$elem.find(selector).last();
             $regionDiv.remove();
             redisplay(data);
@@ -204,7 +221,7 @@
                 alert("Please turn on regions visibility!");
                 return;
             }
-            var selector = 'div.'+data.settings.cssPrefix+'regionURL';
+            var selector = 'div.'+CSS+'regionURL';
             var $regionDivs = data.$elem.find(selector);
             $regionDivs.remove();
             redisplay(data);
@@ -221,18 +238,17 @@
         // show region info in a window
         showRegionInfo : function (data) {
             var $elem = data.$elem;
-            var cssPrefix = data.settings.cssPrefix;
-            var infoSelector = '#'+cssPrefix+'regionInfo';
+            var infoSelector = '#'+CSS+'regionInfo';
             if (fn.isOnScreen(data, infoSelector)) return; // already onscreen
             var html = '\
-                <div id="'+cssPrefix+'regionInfo" class="'+cssPrefix+'keep '+cssPrefix+'regionInfo">\
-                    <table class="'+cssPrefix+'infoheader">\
+                <div id="'+CSS+'regionInfo" class="'+CSS+'keep '+CSS+'regionInfo">\
+                    <table class="'+CSS+'infoheader">\
                         <tr>\
-                            <td class="'+cssPrefix+'infobutton html">HTML</td>\
-                            <td class="'+cssPrefix+'infobutton svgattr">SVG</td>\
-                            <td class="'+cssPrefix+'infobutton csv">CSV</td>\
-                            <td class="'+cssPrefix+'infobutton digilib">Digilib</td>\
-                            <td class="'+cssPrefix+'infobutton x">X</td>\
+                            <td class="'+CSS+'infobutton html">HTML</td>\
+                            <td class="'+CSS+'infobutton svgattr">SVG</td>\
+                            <td class="'+CSS+'infobutton csv">CSV</td>\
+                            <td class="'+CSS+'infobutton digilib">Digilib</td>\
+                            <td class="'+CSS+'infobutton x">X</td>\
                         </tr>\
                     </table>\
                 </div>';
@@ -245,8 +261,8 @@
             $info.append(regionInfoDigilib(data, $regions));
             var bind = function(name) {
                 $info.find('.'+name).on('click.regioninfo', function () {
-                    $info.find('div.'+cssPrefix+'info').hide();
-                    $info.find('div.'+cssPrefix+name).show();
+                    $info.find('div.'+CSS+'info').hide();
+                    $info.find('div.'+CSS+name).show();
                     fn.centerOnScreen(data, $info);
                     });
                 };
@@ -264,12 +280,11 @@
         // display region coordinates in an edit line
         showRegionCoords : function (data, $regionDiv) {
             var $elem = data.$elem;
-            var cssPrefix = data.settings.cssPrefix;
             var rect = $regionDiv.data('rect');
             var text = $regionDiv.data('text');
             var coordString = packCoords(rect, ',');
             var html = '\
-                <div id="'+cssPrefix+'regionInfo" class="'+cssPrefix+'keep '+cssPrefix+'regionInfo">\
+                <div id="'+CSS+'regionInfo" class="'+CSS+'keep '+CSS+'regionInfo">\
                     <div>'+text+'</div>\
                     <input name="coords" type="text" size="30" maxlength="40" value="'+coordString+'"/>\
                 </div>';
@@ -302,9 +317,9 @@
                 alert('invalid coordinates: ' + coords);
                 return;
                 }
-            var cssPrefix = data.settings.cssPrefix;
-            var attr = { 'class' : cssPrefix+'regionURL '+cssPrefix+'findregion' };
-            addRegionDiv(data, rect, attr);
+            var attr = { 'class' : CSS+'regionURL '+CSS+'findregion' };
+            var item = { 'rect' : rect, 'attributes' : attr };
+            var $regionDiv = addRegionDiv(data, item);
             var za = data.zoomArea;
             if (!fn.isFullArea(za)) {
                 za.setCenter(rect.getCenter()).stayInside(FULL_AREA);
@@ -320,35 +335,34 @@
         // find coordinates and display as new region
         findCoords : function (data) {
             var $elem = data.$elem;
-            var cssPrefix = data.settings.cssPrefix;
-            var findSelector = '#'+cssPrefix+'regionFindCoords';
+            var findSelector = '#'+CSS+'regionFindCoords';
             if (fn.isOnScreen(data, findSelector)) return; // already onscreen
             var html = '\
-                <div id="'+cssPrefix+'regionFindCoords" class="'+cssPrefix+'keep '+cssPrefix+'regionInfo">\
+                <div id="'+CSS+'regionFindCoords" class="'+CSS+'keep '+CSS+'regionInfo">\
                     <div>coordinates to find:</div>\
-                    <form class="'+cssPrefix+'form">\
+                    <form class="'+CSS+'form">\
                         <div>\
-                            <input class="'+cssPrefix+'input" name="coords" type="text" size="30" maxlength="40"/> \
+                            <input class="'+CSS+'input" name="coords" type="text" size="30" maxlength="40"/> \
                         </div>\
-                        <input class="'+cssPrefix+'submit" type="submit" name="sub" value="Ok"/>\
-                        <input class="'+cssPrefix+'cancel" type="button" value="Cancel"/>\
+                        <input class="'+CSS+'submit" type="submit" name="sub" value="Ok"/>\
+                        <input class="'+CSS+'cancel" type="button" value="Cancel"/>\
                     </form>\
                 </div>';
             var $info = $(html);
             $info.appendTo($elem);
             var $form = $info.find('form');
-            var $input = $info.find('input.'+cssPrefix+'input');
+            var $input = $info.find('input.'+CSS+'input');
             // handle submit
             $form.on('submit', function () {
                 var coords = $input.val();
                 actions.regionFromCoords(data, coords);
                 fn.withdraw($info);
                 return false;
-            });
+                });
             // handle cancel
-            $form.find('.'+cssPrefix+'cancel').on('click', function () {
+            $form.find('.'+CSS+'cancel').on('click', function () {
                 fn.withdraw($info);
-            });
+                });
             $info.fadeIn();
             fn.centerOnScreen(data, $info);
             $input.focus();
@@ -357,28 +371,27 @@
         // find text data and display as new region
         findData : function (data) {
             var $elem = data.$elem;
-            var cssPrefix = data.settings.cssPrefix;
-            var findSelector = '#'+cssPrefix+'regionFindData';
+            var findSelector = '#'+CSS+'regionFindData';
             if (fn.isOnScreen(data, findSelector)) return; // already onscreen
             var textOptions = getTextOptions(data, 'regionHTML');
             var html = '\
-                <div id="'+cssPrefix+'regionFindData" class="'+cssPrefix+'keep '+cssPrefix+'regionInfo">\
+                <div id="'+CSS+'regionFindData" class="'+CSS+'keep '+CSS+'regionInfo">\
                     <div>text to find:</div>\
-                    <form class="'+cssPrefix+'form">\
+                    <form class="'+CSS+'form">\
                         <div>\
-                            <select class="'+cssPrefix+'findData">\
+                            <select class="'+CSS+'findData">\
                             '+textOptions+'\
                             </select>\
                         </div>\
-                        <input class="'+cssPrefix+'input" name="data" type="text" size="30" maxlength="40"/> \
-                        <input class="'+cssPrefix+'submit" type="submit" name="sub" value="Ok"/>\
-                        <input class="'+cssPrefix+'cancel" type="button" value="Cancel"/>\
+                        <input class="'+CSS+'input" name="data" type="text" size="30" maxlength="40"/> \
+                        <input class="'+CSS+'submit" type="submit" name="sub" value="Ok"/>\
+                        <input class="'+CSS+'cancel" type="button" value="Cancel"/>\
                     </form>\
                 </div>';
             var $info = $(html);
             $info.appendTo($elem);
             var $form = $info.find('form');
-            var $input = $info.find('input.'+cssPrefix+'input');
+            var $input = $info.find('input.'+CSS+'input');
             var $select = $info.find('select');
             var findRegion = function () {
                 var coords = $select.val();
@@ -390,9 +403,9 @@
             $form.on('submit', findRegion);
             $select.on('change', findRegion);
             // handle cancel
-            $form.find('.'+cssPrefix+'cancel').on('click', function () {
+            $form.find('.'+CSS+'cancel').on('click', function () {
                 fn.withdraw($info);
-            });
+                });
             $info.fadeIn();
             fn.centerOnScreen(data, $info);
             $input.focus();
@@ -430,11 +443,10 @@
     };
 
     // create a new regionDiv and add it to data.$elem
-    var newRegionDiv = function (data) {
-        var settings = data.settings;
-        var cssPrefix = settings.cssPrefix;
-        var cls = cssPrefix+'region '+cssPrefix+'overlay';
+    var newRegionDiv = function (data, attr) {
+        var cls = CSS+'region';
         var $regionDiv = $('<div class="'+cls+'" style="display:none"/>');
+        addRegionAttributes(data, $regionDiv, attr);
         data.$elem.append($regionDiv);
         return $regionDiv;
     };
@@ -451,14 +463,12 @@
     // copy attributes to a region div
     var addRegionAttributes = function (data, $regionDiv, attributes) {
         if (attributes == null) return;
-        var settings = data.settings;
-        var cssPrefix = settings.cssPrefix;
         if (attributes['class']) {
             $regionDiv.addClass(attributes['class']);
             delete attributes['class'];
         }
         if (attributes['href']) {
-            $regionDiv.data('href', attributes['href']); // TODO: href from HTML?
+            $regionDiv.data('href', attributes['href']);
             delete attributes['href'];
         }
         if (attributes['title']) {
@@ -469,91 +479,91 @@
 
     // set region number
     var addRegionNumber = function (data, $regionDiv, index) {
-        var settings = data.settings;
-        var cssPrefix = settings.cssPrefix;
-        var $number = $('<a class="'+cssPrefix+'regionnumber">'+index+'</a>');
+        var $number = $('<a class="'+CSS+'regionnumber">'+index+'</a>');
         $regionDiv.append($number);
         return $regionDiv;
     };
 
     // construct a region from a rectangle
-    var addRegionDiv = function (data, rect, attributes, number) { // ###
+    var addRegionDiv = function (data, item) {
+        var $regionDiv = newRegionDiv(data, item.attributes);
         var settings = data.settings;
-        var cssPrefix = settings.cssPrefix;
-        var $regionDiv = newRegionDiv(data);
-        addRegionAttributes(data, $regionDiv, attributes);
-        if (settings.showRegionNumbers && number) {
-            addRegionNumber(data, $regionDiv, number);
+        // add region number
+        if (settings.showRegionNumbers && item.index) {
+            addRegionNumber(data, $regionDiv, item.index);
+        }
+        // add inner HTML
+        if (item.inner) {
+            $regionDiv.append(item.inner);
         }
-        $regionDiv.data('rect', rect);
-        // handle click events on div
+        // store the coordinates in data
+        $regionDiv.data('rect', item.rect);
+        // trigger a region event on click
         $regionDiv.on('click.dlRegion', function(evt) {
-                $(data).trigger('regionClick', [$regionDiv]);
-        });
+            $(data).trigger('regionClick', [$regionDiv]);
+            });
         return $regionDiv;
     };
 
+    // create regions from a Javascript array of items
+    var createRegionsFromJS = function (data, items) {
+        $.each(items, function(index, item) {
+            addRegionDiv(data, item);
+            });
+    };
+
     // create regions from URL parameters
     var createRegionsFromURL = function (data) {
-        var cssPrefix = data.settings.cssPrefix;
-        var attr = {'class' : cssPrefix+"regionURL"};
         var userRegions = unpackRegions(data);
-        $.each(userRegions, function(index, rect) {
-            addRegionDiv(data, rect, attr, index+1);
-        });
+        if (!userRegions) return;
+        createRegionsFromJS(data, userRegions);
     };
 
     // create regions from HTML
     var createRegionsFromHTML = function (data) {
         // regions are defined in "area" tags
-        var $content = data.$elem.find(data.settings.areaSelector);
-        var cssPrefix = data.settings.cssPrefix;
-        console.debug("createRegionsFromHTML. elems found: ", $content.length);
-        $content.each(function(index, area) {
+        var $areas = data.$elem.find(data.settings.areaSelector);
+        console.debug("createRegionsFromHTML - elems found: ", $areas.length);
+        $areas.each(function(index, area) {
             var $area = $(area);
+            // the "title" attribute contains the text for the tooltip
+            var title = $area.attr('title');
             // the "coords" attribute contains the region coords (0..1)
             var coords = $area.attr('coords');
-            var title = $area.attr('title');
             // create the rectangle
             var rect = parseCoords(data, coords);
             if (rect == null) {
                 return console.error('bad coords in HTML:', title, coords);
             }
+            // mark div class as regionHTML
+            var cls = $area.attr('class') || '';
+            cls += ' '+CSS+'regionHTML';
+            var attr = {'class' : cls};
             // copy attributes
-            var attributes = {};
             for (var n in data.settings.regionAttributes) {
-                attributes[n] = $area.attr(n);
+                attr[n] = $area.attr(n);
             }
-            var $regionDiv = addRegionDiv(data, rect, attributes);
-            // mark div as regionHTML
-            $regionDiv.addClass(cssPrefix+'regionHTML');
-            var $contents = $area.contents().clone();
-            if (attributes.href != null) { // TODO: href set in region???
+            // copy inner HTML
+            var $inner = $area.contents().clone();
+            if (attr.href != null) {
                 // wrap contents in a-tag
-                var $ca = $('<a href="'+attributes.href+'"/>');
-                $ca.append($contents);
-                // alt attribute is also content (BTW: area-tag has no content())
-                $ca.append($area.attr('alt'));
-                $regionDiv.append($ca);
-            } else {
-                $regionDiv.append($contents);
-                // alt attribute is also content (BTW: area-tag has no content())
-                $regionDiv.append($area.attr('alt'));
+                var $a = $('<a href="'+attr.href+'"/>');
+                $inner = $a.append($inner);
             }
+            var item = {'rect' : rect, 'attributes' : attr, 'inner' : $inner};
+            var $regionDiv = addRegionDiv(data, item);
         });
     };
 
     // select region divs (HTML or URL)
     var getRegions = function (data, selector) {
-        var cssPrefix = data.settings.cssPrefix;
-        var $regions = data.$elem.find('div.'+cssPrefix+selector);
+        var $regions = data.$elem.find('div.'+CSS+selector);
         return $regions;
     };
 
     // make text data options html
     var getTextOptions = function (data, selector) {
-        var cssPrefix = data.settings.cssPrefix;
-        var makeOptionHTML = function(item, index) {
+        var createOption = function(item, index) {
             var $item = $(item);
             var rect = $item.data('rect');
             if (rect == null)
@@ -563,7 +573,7 @@
             return '<option value="'+coords+'">'+text+'</option>';
             };
         var $regions = getRegions(data, selector);
-        var options = $.map($regions, makeOptionHTML);
+        var options = $.map($regions, createOption);
         return options.join('');
     };
 
@@ -578,9 +588,8 @@
 
     // html for later insertion
     var regionInfoHTML = function (data, $regions) {
-        var cssPrefix = data.settings.cssPrefix;
-        var $infoDiv = $('<div class="'+cssPrefix+'info '+cssPrefix+'html"/>');
-        $infoDiv.append($('<div/>').text('<map class="'+cssPrefix+'keep '+cssPrefix+'regioncontent">'));
+        var $infoDiv = $('<div class="'+CSS+'info '+CSS+'html"/>');
+        $infoDiv.append($('<div/>').text('<map class="'+CSS+'keep '+CSS+'regioncontent">'));
         $regions.each(function(index, region) {
             var rect = $(region).data('rect');
             var coords = packCoords(rect, ',');
@@ -592,8 +601,7 @@
 
     // SVG-style
     var regionInfoSVG = function (data, $regions) {
-        var cssPrefix = data.settings.cssPrefix;
-        var $infoDiv = $('<div class="'+cssPrefix+'info '+cssPrefix+'svgattr"/>');
+        var $infoDiv = $('<div class="'+CSS+'info '+CSS+'svgattr"/>');
         $regions.each(function(index, region) {
             var rect = $(region).data('rect');
             var coords = packCoords(rect, ',');
@@ -604,8 +612,7 @@
 
     // CSV-style
     var regionInfoCSV = function (data, $regions) {
-        var cssPrefix = data.settings.cssPrefix;
-        var $infoDiv = $('<div class="'+cssPrefix+'info '+cssPrefix+'csv"/>');
+        var $infoDiv = $('<div class="'+CSS+'info '+CSS+'csv"/>');
         $regions.each(function(index, region) {
             var rect = $(region).data('rect');
             var coords = packCoords(rect, ',');
@@ -616,8 +623,7 @@
 
     // digilib-style (h,w@x,y)
     var regionInfoDigilib = function (data, $regions) {
-        var cssPrefix = data.settings.cssPrefix;
-        var $infoDiv = $('<div class="'+cssPrefix+'info '+cssPrefix+'digilib"/>');
+        var $infoDiv = $('<div class="'+CSS+'info '+CSS+'digilib"/>');
         $regions.each(function(index, region) {
             var rect = $(region).data('rect');
             var coords = packCoords(rect, ',');
@@ -669,24 +675,27 @@
         var regions = $.map(coords, function(coord, index) {
             var pos = coord.split("/", 4);
             var rect = geom.rectangle(pos[0], pos[1], pos[2], pos[3]);
-            return rect;
+            var attr = {'class' : CSS+"regionURL"};
+            var item = {'rect' : rect, 'index' : index+1, 'attributes' : attr};
+            return item;
             });
         return regions;
     };
 
     // pack user regions array into a URL parameter string
     var packRegions = function (data) {
-        var $regions = getRegions(data, 'regionsURL');
+        var $regions = getRegions(data, 'regionURL');
         if ($regions.length == 0) {
             data.settings.rg = null;
             return;
         }
-        var packRegion = function(region, index) {
+        var pack = function(region, index) {
             var $region = $(region);
             var rect = $region.data('rect');
-            packCoords(rect, '/');
+            var packed = packCoords(rect, '/');
+            return packed;
             };
-        var coords = $.map($regions, packRegion);
+        var coords = $.map($regions, pack);
         var rg = coords.join(',');
         data.settings.rg = rg;
         console.debug('pack regions:', rg);
@@ -744,6 +753,10 @@
         var data = this;
         var settings = data.settings;
         console.debug("regions: handleSetup", settings.rg);
+        // regions with content are given in a Javascript array
+        if (settings.regions) {
+            createRegionsFromJS(data, settings.regions);
+        }
         // regions with content are given in HTML divs
         if (settings.processHtmlRegions) {
             createRegionsFromHTML(data);
@@ -796,7 +809,7 @@
         console.debug('initialising regions plugin. data:', data);
         var $elem = data.$elem;
         var settings = data.settings;
-        var cssPrefix = data.settings.cssPrefix;
+        CSS = settings.cssPrefix;
         FULL_AREA  = geom.rectangle(0, 0, 1, 1);
         // install event handlers
         var $data = $(data);