525 lines
16 KiB
JavaScript
525 lines
16 KiB
JavaScript
/**
|
|
* (c) Kitodo. Key to digital objects e.V. <contact@kitodo.org>
|
|
*
|
|
* This file is part of the Kitodo and TYPO3 projects.
|
|
*
|
|
* @license GNU General Public License version 3 or later.
|
|
* For the full copyright and license information, please read the
|
|
* LICENSE.txt file that was distributed with this source code.
|
|
*/
|
|
|
|
/**
|
|
* This is necessary to support the scrolling of the element into the viewport
|
|
* in case of text hover on the map.
|
|
*
|
|
* @param elem
|
|
* @param speed
|
|
* @returns {jQuery}
|
|
*/
|
|
jQuery.fn.scrollTo = function(elem, speed) {
|
|
var manualOffsetTop = $(elem).parent().height() / 2;
|
|
$(this).animate({
|
|
scrollTop: $(this).scrollTop() - $(this).offset().top + $(elem).offset().top - manualOffsetTop
|
|
}, speed === undefined ? 1000 : speed);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Encapsulates especially the fulltext behavior
|
|
* @constructor
|
|
* @param {ol.Map} map
|
|
* @param {Object} image
|
|
* @param {string} fulltextUrl
|
|
*/
|
|
var dlfViewerFullTextControl = function(map, image, fulltextUrl) {
|
|
|
|
/**
|
|
* @private
|
|
* @type {ol.Map}
|
|
*/
|
|
this.map = map;
|
|
|
|
/**
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
this.image = image;
|
|
|
|
/**
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
this.url = fulltextUrl;
|
|
|
|
/**
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
this.dic = $('#tx-dlf-tools-fulltext').length > 0 && $('#tx-dlf-tools-fulltext').attr('data-dic') ?
|
|
dlfUtils.parseDataDic($('#tx-dlf-tools-fulltext')) :
|
|
{
|
|
'fulltext':'Fulltext',
|
|
'fulltext-on':'Activate Fulltext',
|
|
'fulltext-off':'Deactivate Fulltext',
|
|
'activate-full-text-initially':'0',
|
|
'full-text-scroll-element':'html, body',
|
|
'search-hl-parameters':'tx_dlf[highlight_word]'};
|
|
|
|
/**
|
|
* @type {number}
|
|
* @private
|
|
*/
|
|
this.activateFullTextInitially = this.dic['activate-full-text-initially'] === "1" ? 1 : 0;
|
|
|
|
/**
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
this.fullTextScrollElement = this.dic['full-text-scroll-element'];
|
|
|
|
/**
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
this.searchHlElements = this.dic['search-hl-elements'];
|
|
|
|
/**
|
|
* @type {ol.Feature|undefined}
|
|
* @private
|
|
*/
|
|
this.fulltextData_ = undefined;
|
|
|
|
/**
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
this.layers_ = {
|
|
textblock: new ol.layer.Vector({
|
|
'source': new ol.source.Vector(),
|
|
'style': dlfViewerOL3Styles.defaultStyle()
|
|
}),
|
|
textline: new ol.layer.Vector({
|
|
'source': new ol.source.Vector(),
|
|
'style': dlfViewerOL3Styles.invisibleStyle()
|
|
}),
|
|
select: new ol.layer.Vector({
|
|
'source': new ol.source.Vector(),
|
|
'style': dlfViewerOL3Styles.selectStyle()
|
|
}),
|
|
hoverTextblock: new ol.layer.Vector({
|
|
'source': new ol.source.Vector(),
|
|
'style': dlfViewerOL3Styles.hoverStyle()
|
|
}),
|
|
hoverTextline: new ol.layer.Vector({
|
|
'source': new ol.source.Vector(),
|
|
'style': dlfViewerOL3Styles.textlineStyle()
|
|
})
|
|
};
|
|
|
|
/**
|
|
* @type {ol.Feature}
|
|
* @private
|
|
*/
|
|
this.selectedFeature_ = undefined;
|
|
|
|
/**
|
|
* @type {Object}
|
|
* @private
|
|
*/
|
|
this.handlers_ = {
|
|
mapClick: $.proxy(function(event) {
|
|
// the click handler adds the clicked feature to a
|
|
// select layer which could be used to create a highlight
|
|
// effect on the map
|
|
|
|
var feature = this.map.forEachFeatureAtPixel(event['pixel'], function(feature, layer) {
|
|
if (feature.get('type') === 'textblock') {
|
|
return feature;
|
|
}
|
|
});
|
|
|
|
// deselect all
|
|
if (feature === undefined) {
|
|
this.layers_.select.getSource().clear();
|
|
this.selectedFeature_ = undefined;
|
|
this.showFulltext(undefined);
|
|
return;
|
|
}
|
|
|
|
this.handleLayersForClick(feature);
|
|
|
|
this.selectedFeature_ = feature;
|
|
|
|
|
|
if (dlfUtils.exists(feature)) {
|
|
this.showFulltext([feature]);
|
|
}
|
|
|
|
},
|
|
this),
|
|
mapHover: $.proxy(function(event) {
|
|
// hover in case of dragging
|
|
if (event['dragging']) {
|
|
return;
|
|
}
|
|
|
|
var hoverSourceTextblock_ = this.layers_.hoverTextblock.getSource(),
|
|
hoverSourceTextline_ = this.layers_.hoverTextline.getSource(),
|
|
selectSource_ = this.layers_.select.getSource(),
|
|
map_ = this.map,
|
|
textblockFeature,
|
|
textlineFeature;
|
|
|
|
map_.forEachFeatureAtPixel(event['pixel'], function(feature, layer) {
|
|
if (feature.get('type') === 'textblock') {
|
|
textblockFeature = feature;
|
|
}
|
|
if (feature.get('type') === 'textline') {
|
|
textlineFeature = feature;
|
|
}
|
|
});
|
|
|
|
this.handleTextBlockElements(textblockFeature, selectSource_, hoverSourceTextblock_);
|
|
this.handleTextLineElements(textlineFeature, hoverSourceTextline_);
|
|
},
|
|
this)
|
|
};
|
|
|
|
this.changeActiveBehaviour();
|
|
};
|
|
|
|
/**
|
|
* Add active / deactive behavior in case of click on control depending if the full text should be activated initially.
|
|
*/
|
|
dlfViewerFullTextControl.prototype.changeActiveBehaviour = function() {
|
|
if (this.activateFullTextInitially === 1) {
|
|
this.addActiveBehaviourForSwitchOn();
|
|
} else {
|
|
this.addActiveBehaviourForSwitchOff();
|
|
}
|
|
};
|
|
|
|
dlfViewerFullTextControl.prototype.addActiveBehaviourForSwitchOn = function() {
|
|
var anchorEl = $('#tx-dlf-tools-fulltext');
|
|
if (anchorEl.length > 0){
|
|
var toogleFulltext = $.proxy(function(event) {
|
|
event.preventDefault();
|
|
|
|
this.activateFullTextInitially = 0;
|
|
|
|
if ($(event.target).hasClass('active')) {
|
|
this.deactivate();
|
|
return;
|
|
}
|
|
|
|
this.activate();
|
|
}, this);
|
|
|
|
anchorEl.on('click', toogleFulltext);
|
|
anchorEl.on('touchstart', toogleFulltext);
|
|
}
|
|
|
|
// set initial title of fulltext element
|
|
$("#tx-dlf-tools-fulltext")
|
|
.text(this.dic['fulltext'])
|
|
.attr('title', this.dic['fulltext']);
|
|
|
|
this.activate();
|
|
};
|
|
|
|
dlfViewerFullTextControl.prototype.addActiveBehaviourForSwitchOff = function() {
|
|
var anchorEl = $('#tx-dlf-tools-fulltext');
|
|
if (anchorEl.length > 0){
|
|
var toogleFulltext = $.proxy(function(event) {
|
|
event.preventDefault();
|
|
|
|
if ($(event.target).hasClass('active')) {
|
|
this.deactivate();
|
|
return;
|
|
}
|
|
|
|
this.activate();
|
|
}, this);
|
|
|
|
anchorEl.on('click', toogleFulltext);
|
|
anchorEl.on('touchstart', toogleFulltext);
|
|
}
|
|
|
|
// set initial title of fulltext element
|
|
$("#tx-dlf-tools-fulltext")
|
|
.text(this.dic['fulltext-on'])
|
|
.attr('title', this.dic['fulltext-on']);
|
|
|
|
// if fulltext is activated via cookie than run activation methode
|
|
if (dlfUtils.getCookie("tx-dlf-pageview-fulltext-select") === 'enabled') {
|
|
// activate the fulltext behavior
|
|
this.activate();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle layers for click
|
|
* @param {ol.Feature|undefined} feature
|
|
*/
|
|
dlfViewerFullTextControl.prototype.handleLayersForClick = function(feature) {
|
|
// highlight features
|
|
if (this.selectedFeature_) {
|
|
// remove old clicks
|
|
this.layers_.select.getSource().removeFeature(this.selectedFeature_);
|
|
}
|
|
|
|
if (feature) {
|
|
// remove hover for preventing an adding of styles
|
|
this.layers_.hoverTextblock.getSource().clear();
|
|
|
|
// add feature
|
|
this.layers_.select.getSource().addFeature(feature);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle TextBlock elements
|
|
* @param {ol.Feature|undefined} textblockFeature
|
|
* @param {ol.Feature|undefined} selectSource_
|
|
* @param {any} hoverSourceTextblock_
|
|
*/
|
|
dlfViewerFullTextControl.prototype.handleTextBlockElements = function(textblockFeature, selectSource_, hoverSourceTextblock_) {
|
|
var activeSelectTextBlockEl_ = dlfFullTextUtils.getFeature(selectSource_),
|
|
activeHoverTextBlockEl_ = dlfFullTextUtils.getFeature(hoverSourceTextblock_),
|
|
isFeatureEqualSelectFeature_ = dlfFullTextUtils.isFeatureEqual(activeSelectTextBlockEl_, textblockFeature),
|
|
isFeatureEqualToOldHoverFeature_ = dlfFullTextUtils.isFeatureEqual(activeHoverTextBlockEl_);
|
|
|
|
if (!isFeatureEqualToOldHoverFeature_ && !isFeatureEqualSelectFeature_) {
|
|
// remove old textblock hover features
|
|
hoverSourceTextblock_.clear();
|
|
|
|
if (textblockFeature) {
|
|
// add textblock feature to hover
|
|
hoverSourceTextblock_.addFeature(textblockFeature);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Handle TextLine elements
|
|
* @param {ol.Feature|undefined} textlineFeature
|
|
* @param {any} hoverSourceTextline_
|
|
*/
|
|
dlfViewerFullTextControl.prototype.handleTextLineElements = function(textlineFeature, hoverSourceTextline_) {
|
|
var activeHoverTextBlockEl_ = dlfFullTextUtils.getFeature(hoverSourceTextline_);
|
|
isFeatureEqualToOldHoverFeature_ = dlfFullTextUtils.isFeatureEqual(activeHoverTextBlockEl_, textlineFeature);
|
|
|
|
if (!isFeatureEqualToOldHoverFeature_) {
|
|
this.removeHighlightEffect(activeHoverTextBlockEl_, hoverSourceTextline_);
|
|
this.addHighlightEffect(textlineFeature, hoverSourceTextline_);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Remove highlight effect from full text view
|
|
* @param {ol.Feature|undefined} activeHoverTextBlockEl_
|
|
* @param {any} hoverSourceTextline_
|
|
*/
|
|
dlfViewerFullTextControl.prototype.removeHighlightEffect = function(activeHoverTextBlockEl_, hoverSourceTextline_) {
|
|
if (activeHoverTextBlockEl_) {
|
|
var oldTargetElem = $('#' + activeHoverTextBlockEl_.getId());
|
|
|
|
if (oldTargetElem.hasClass('highlight') ) {
|
|
oldTargetElem.removeClass('highlight');
|
|
}
|
|
|
|
// remove old textline hover features
|
|
hoverSourceTextline_.clear();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Add highlight effect from full text view
|
|
* @param {ol.Feature|undefined} textlineFeature
|
|
* @param {any} hoverSourceTextline_
|
|
*/
|
|
dlfViewerFullTextControl.prototype.addHighlightEffect = function(textlineFeature, hoverSourceTextline_) {
|
|
if (textlineFeature) {
|
|
var targetElem = $('#' + textlineFeature.getId());
|
|
|
|
if (targetElem.length > 0 && !targetElem.hasClass('highlight')) {
|
|
targetElem.addClass('highlight');
|
|
setTimeout(this.scrollToText, 1000, targetElem, this.fullTextScrollElement);
|
|
hoverSourceTextline_.addFeature(textlineFeature);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Scroll to full text element if it is highlighted
|
|
* @param {any} element
|
|
* @param {string} fullTextScrollElement
|
|
*/
|
|
dlfViewerFullTextControl.prototype.scrollToText = function(element, fullTextScrollElement) {
|
|
if (element.hasClass('highlight')) {
|
|
$(fullTextScrollElement).animate({
|
|
scrollTop: element.offset().top
|
|
}, 500);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Activate Fulltext Features
|
|
*/
|
|
dlfViewerFullTextControl.prototype.activate = function() {
|
|
|
|
var controlEl = $('#tx-dlf-tools-fulltext');
|
|
|
|
// if the activate method is called for the first time fetch
|
|
// fulltext data from server
|
|
if (this.fulltextData_ === undefined) {
|
|
this.fulltextData_ = dlfFullTextUtils.fetchFullTextDataFromServer(this.url, this.image);
|
|
|
|
if (this.fulltextData_ !== undefined) {
|
|
// add features to fulltext layer
|
|
this.layers_.textblock.getSource().addFeatures(this.fulltextData_.getTextblocks());
|
|
this.layers_.textline.getSource().addFeatures(this.fulltextData_.getTextlines());
|
|
|
|
// add first feature of textBlockFeatures to map
|
|
if (this.fulltextData_.getTextblocks().length > 0) {
|
|
this.layers_.select.getSource().addFeature(this.fulltextData_.getTextblocks()[0]);
|
|
this.selectedFeature_ = this.fulltextData_.getTextblocks()[0];
|
|
this.showFulltext(this.fulltextData_.getTextblocks());
|
|
}
|
|
}
|
|
}
|
|
|
|
// now activate the fulltext overlay and map behavior
|
|
this.enableFulltextSelect();
|
|
dlfUtils.setCookie("tx-dlf-pageview-fulltext-select", 'enabled');
|
|
$(controlEl).addClass('active');
|
|
|
|
// trigger event
|
|
$(this).trigger("activate-fulltext", this);
|
|
};
|
|
|
|
/**
|
|
* Activate Fulltext Features
|
|
*/
|
|
dlfViewerFullTextControl.prototype.deactivate = function() {
|
|
|
|
var controlEl = $('#tx-dlf-tools-fulltext');
|
|
|
|
// deactivate fulltext
|
|
this.disableFulltextSelect();
|
|
dlfUtils.setCookie("tx-dlf-pageview-fulltext-select", 'disabled');
|
|
$(controlEl).removeClass('active');
|
|
|
|
// trigger event
|
|
$(this).trigger("deactivate-fulltext", this);
|
|
};
|
|
|
|
/**
|
|
* Disable Fulltext Features
|
|
*
|
|
* @return void
|
|
*/
|
|
dlfViewerFullTextControl.prototype.disableFulltextSelect = function() {
|
|
|
|
// register event listeners
|
|
this.map.un('click', this.handlers_.mapClick);
|
|
this.map.un('pointermove', this.handlers_.mapHover);
|
|
|
|
// remove layers
|
|
for (var key in this.layers_) {
|
|
if (this.layers_.hasOwnProperty(key)) {
|
|
this.map.removeLayer(this.layers_[String(key)]);
|
|
}
|
|
}
|
|
|
|
var className = 'fulltext-visible';
|
|
$("#tx-dlf-tools-fulltext").removeClass(className)
|
|
|
|
if(this.activateFullTextInitially === 0) {
|
|
$("#tx-dlf-tools-fulltext")
|
|
.text(this.dic['fulltext-on'])
|
|
.attr('title', this.dic['fulltext-on']);
|
|
}
|
|
|
|
$('#tx-dlf-fulltextselection').removeClass(className);
|
|
$('#tx-dlf-fulltextselection').hide();
|
|
$('body').removeClass(className);
|
|
|
|
};
|
|
|
|
/**
|
|
* Activate Fulltext Features
|
|
*/
|
|
dlfViewerFullTextControl.prototype.enableFulltextSelect = function() {
|
|
|
|
// register event listeners
|
|
this.map.on('click', this.handlers_.mapClick);
|
|
this.map.on('pointermove', this.handlers_.mapHover);
|
|
|
|
// add layers to map
|
|
for (var key in this.layers_) {
|
|
if (this.layers_.hasOwnProperty(key)) {
|
|
this.map.addLayer(this.layers_[String(key)]);
|
|
}
|
|
};
|
|
|
|
// show fulltext container
|
|
var className = 'fulltext-visible';
|
|
$("#tx-dlf-tools-fulltext").addClass(className);
|
|
|
|
if(this.activateFullTextInitially=== 0) {
|
|
$("#tx-dlf-tools-fulltext")
|
|
.text(this.dic['fulltext-off'])
|
|
.attr('title', this.dic['fulltext-off']);
|
|
}
|
|
|
|
$('#tx-dlf-fulltextselection').addClass(className);
|
|
$('#tx-dlf-fulltextselection').show();
|
|
$('body').addClass(className);
|
|
};
|
|
|
|
/**
|
|
* Show full text
|
|
*
|
|
* @param {Array.<ol.Feature>|undefined} features
|
|
*/
|
|
dlfViewerFullTextControl.prototype.showFulltext = function(features) {
|
|
|
|
if (features !== undefined) {
|
|
$('#tx-dlf-fulltextselection').children().remove();
|
|
for (feature of features) {
|
|
var textLines = feature.get('textlines');
|
|
for (textLine of textLines) {
|
|
this.appendTextLineSpan(textLine);
|
|
}
|
|
$('#tx-dlf-fulltextselection').append('<br /><br />');
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Append text line span
|
|
*
|
|
* @param {Object} textLine
|
|
*/
|
|
dlfViewerFullTextControl.prototype.appendTextLineSpan = function(textLine) {
|
|
var textLineSpan = $('<span class="textline" id="' + textLine.getId() + '">');
|
|
var content = textLine.get('content');
|
|
|
|
for (item of content) {
|
|
var span = $('<span class="' + item.get('type') + '" id="' + item.getId() + '"/>');
|
|
var spanText = item.get('fulltext');
|
|
var spanTextLines = spanText.split(/\n/g);
|
|
for (const [i, spanTextLine] of spanTextLines.entries()) {
|
|
span.append(document.createTextNode(spanTextLine));
|
|
if (i < spanTextLines.length - 1) {
|
|
span.append($('<br />'));
|
|
}
|
|
}
|
|
textLineSpan.append(span);
|
|
}
|
|
|
|
textLineSpan.append('<span class="textline" id="sp"> </span>');
|
|
$('#tx-dlf-fulltextselection').append(textLineSpan);
|
|
};
|