Implement loading indicator
This commit is contained in:
parent
1e45e0c10e
commit
d4e03ef980
|
@ -170,6 +170,7 @@ class PageViewController extends AbstractController
|
|||
tx_dlf_viewer = new dlfViewer({
|
||||
controls: ["' . implode('", "', $this->controls) . '"],
|
||||
div: "' . $this->settings['elementId'] . '",
|
||||
progressElementId: "' . $this->settings['progressElementId'] . '",
|
||||
images: ' . json_encode($this->images) . ',
|
||||
fulltexts: ' . json_encode($this->fulltexts) . ',
|
||||
annotationContainers: ' . json_encode($this->annotationContainers) . ',
|
||||
|
|
|
@ -65,6 +65,17 @@
|
|||
</config>
|
||||
</TCEforms>
|
||||
</settings.elementId>
|
||||
<settings.elementId>
|
||||
<TCEforms>
|
||||
<exclude>1</exclude>
|
||||
<label>LLL:EXT:dlf/Resources/Private/Language/locallang_be.xlf:plugins.pageview.flexform.progressElementId</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<eval>required,alphanum_x,nospace</eval>
|
||||
<default>tx-dlf-page-progress</default>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.elementId>
|
||||
<settings.useInternalProxy>
|
||||
<TCEforms>
|
||||
<exclude>1</exclude>
|
||||
|
|
|
@ -93,6 +93,40 @@ Additional OpenLayers controls may be configured in TypoScript:
|
|||
|
||||
These are created in ``dlfViewer::createControls_()``.
|
||||
|
||||
Loading Indicator
|
||||
-----------------
|
||||
|
||||
A progress element may be configured to be used as loading indicator for static images.
|
||||
This requires CORS and possibly a non-mixed context, and the server must send a ``Content-Length`` header.
|
||||
|
||||
In TypoScript, set ``progressElementId`` to the ID of the ``<progress>`` element:
|
||||
|
||||
.. code-block:: typoscript
|
||||
|
||||
plugin.tx_dlf_pageview {
|
||||
settings {
|
||||
progressElementId = tx-dlf-page-progress
|
||||
}
|
||||
}
|
||||
|
||||
The element may be placed anywhere on the page.
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<progress id="tx-dlf-page-progress"></progress>
|
||||
|
||||
For styling, the CSS class ``loading`` is added whenever the loading indicator is in use:
|
||||
|
||||
.. code-block:: css
|
||||
|
||||
#tx-dlf-page-progress {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#tx-dlf-page-progress.loading {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
Tools for Basket Plugin
|
||||
-----------------------
|
||||
|
||||
|
|
|
@ -631,6 +631,13 @@ Page View
|
|||
:Default:
|
||||
tx-dlf-map
|
||||
|
||||
- :Property:
|
||||
progressElementId
|
||||
:Data Type:
|
||||
:ref:`t3tsref:data-type-string`
|
||||
:Default:
|
||||
tx-dlf-page-progress
|
||||
|
||||
- :Property:
|
||||
crop
|
||||
:Data Type:
|
||||
|
|
|
@ -373,6 +373,10 @@
|
|||
<source><![CDATA[Activate magnifier]]></source>
|
||||
<target><![CDATA[Lupenfunktion aktivieren]]></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="plugins.pageview.flexform.progressElementId" approved="yes">
|
||||
<source><![CDATA[@ID value of the <progress> element used for loading indicator]]></source>
|
||||
<target><![CDATA[@ID-Wert des für den Ladebalken genutzen <progress>-Elements]]></target>
|
||||
</trans-unit>
|
||||
<trans-unit id="plugins.pageview.flexform.useInternalProxy" approved="yes">
|
||||
<source><![CDATA[Use Internal Proxy]]></source>
|
||||
<target><![CDATA[Internen Proxy verwenden]]></target>
|
||||
|
|
|
@ -233,6 +233,9 @@
|
|||
<trans-unit id="plugins.pageview.flexform.magnifier">
|
||||
<source><![CDATA[Activate magnifier]]></source>
|
||||
</trans-unit>
|
||||
<trans-unit id="plugins.pageview.flexform.progressElementId">
|
||||
<source><![CDATA[@ID value of the <progress> element used for loading indicator]]></source>
|
||||
</trans-unit>
|
||||
<trans-unit id="plugins.pageview.flexform.useInternalProxy">
|
||||
<source><![CDATA[Use Internal Proxy]]></source>
|
||||
</trans-unit>
|
||||
|
|
|
@ -8,6 +8,13 @@
|
|||
* LICENSE.txt file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} LoadingIndicator
|
||||
* @property {(value: number) => void} progress
|
||||
* @property {() => void} indeterminate
|
||||
* @property {() => void} done
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* url: string;
|
||||
|
@ -20,6 +27,7 @@
|
|||
*
|
||||
* @typedef {{
|
||||
* div: string;
|
||||
* progressElementId?: string;
|
||||
* images?: ImageDesc[] | [];
|
||||
* fulltexts?: FulltextDesc[] | [];
|
||||
* controls?: ('OverviewMap' | 'ZoomPanel')[];
|
||||
|
@ -61,6 +69,13 @@ var dlfViewer = function(settings){
|
|||
*/
|
||||
this.images = [];
|
||||
|
||||
/**
|
||||
* The <progress> element for loading indicator.
|
||||
* @type {LoadingIndicator}
|
||||
* @private
|
||||
*/
|
||||
this.loadingIndicator = this.makeLoadingIndicator(settings.progressElementId);
|
||||
|
||||
/**
|
||||
* Fulltext information (e.g. URL)
|
||||
* @type {Array.<string|?>}
|
||||
|
@ -170,6 +185,37 @@ var dlfViewer = function(settings){
|
|||
this.init(dlfUtils.exists(settings.controls) ? settings.controls : []);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string | undefined}
|
||||
* @returns {LoadingIndicator}
|
||||
*/
|
||||
dlfViewer.prototype.makeLoadingIndicator = function (progressElementId) {
|
||||
// Query progress element on demand because it may only become available at a later point (Zeitungsportal)
|
||||
return {
|
||||
indeterminate() {
|
||||
var progressElement = document.getElementById(progressElementId);
|
||||
if (progressElement instanceof HTMLProgressElement) {
|
||||
progressElement.classList.add('loading');
|
||||
progressElement.removeAttribute("value");
|
||||
}
|
||||
},
|
||||
progress(value) {
|
||||
var progressElement = document.getElementById(progressElementId);
|
||||
if (progressElement instanceof HTMLProgressElement) {
|
||||
progressElement.classList.add('loading');
|
||||
progressElement.value = value * progressElement.max;
|
||||
}
|
||||
},
|
||||
done() {
|
||||
var progressElement = document.getElementById(progressElementId);
|
||||
if (progressElement instanceof HTMLProgressElement) {
|
||||
progressElement.classList.remove('loading');
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get number of shown pages. Typically 1 (single page) or 2 (double page mode).
|
||||
*
|
||||
|
@ -528,7 +574,7 @@ dlfViewer.prototype.initLayer = function(imageSourceObjs) {
|
|||
deferredResponse.resolve(layers);
|
||||
}, this);
|
||||
|
||||
dlfUtils.fetchImageData(imageSourceObjs)
|
||||
dlfUtils.fetchImageData(imageSourceObjs, this.loadingIndicator)
|
||||
.done(function(imageSourceData) {
|
||||
resolveCallback(imageSourceData, dlfUtils.createOlLayers(imageSourceData));
|
||||
});
|
||||
|
|
|
@ -222,9 +222,10 @@ dlfUtils.exists = function (val) {
|
|||
* Fetch image data for given image sources.
|
||||
*
|
||||
* @param {ImageDesc[]} imageSourceObjs
|
||||
* @param {LoadingIndicator} loadingIndicator
|
||||
* @return {JQueryStatic.Deferred}
|
||||
*/
|
||||
dlfUtils.fetchImageData = function (imageSourceObjs) {
|
||||
dlfUtils.fetchImageData = function (imageSourceObjs, loadingIndicator) {
|
||||
|
||||
// use deferred for async behavior
|
||||
var deferredResponse = new $.Deferred();
|
||||
|
@ -264,7 +265,7 @@ dlfUtils.fetchImageData = function (imageSourceObjs) {
|
|||
});
|
||||
} else {
|
||||
// In the worse case expect static image file
|
||||
dlfUtils.fetchStaticImageData(imageSourceObj)
|
||||
dlfUtils.fetchStaticImageData(imageSourceObj, loadingIndicator)
|
||||
.done(function (imageSourceDataObj) {
|
||||
imageSourceData[index] = imageSourceDataObj;
|
||||
finishLoading();
|
||||
|
@ -280,9 +281,10 @@ dlfUtils.fetchImageData = function (imageSourceObjs) {
|
|||
* Fetches the image data for static images source.
|
||||
*
|
||||
* @param {ImageDesc} imageSourceObj
|
||||
* @param {LoadingIndicator} loadingIndicator
|
||||
* @return {JQueryStatic.Deferred}
|
||||
*/
|
||||
dlfUtils.fetchStaticImageData = function (imageSourceObj) {
|
||||
dlfUtils.fetchStaticImageData = function (imageSourceObj, loadingIndicator) {
|
||||
// Load the image while trying to reconcile the following constraints:
|
||||
//
|
||||
// - Determine width/height of the image before passing it to OpenLayers.
|
||||
|
@ -305,12 +307,13 @@ dlfUtils.fetchStaticImageData = function (imageSourceObj) {
|
|||
// -> Fall back to a "data:" URL.
|
||||
//
|
||||
// TODO: Revisit this. Perhaps we find a way to pass the Image directly to OpenLayers.
|
||||
// Even so, loading via XHR is beneficial in that it will allow implementing a loading indicator.
|
||||
// Even so, loading via XHR is beneficial in that it allows implementing a loading indicator.
|
||||
|
||||
// use deferred for async behavior
|
||||
var deferredResponse = new $.Deferred();
|
||||
|
||||
var loadFailed = function () {
|
||||
loadingIndicator.done();
|
||||
deferredResponse.reject();
|
||||
};
|
||||
|
||||
|
@ -322,6 +325,8 @@ dlfUtils.fetchStaticImageData = function (imageSourceObj) {
|
|||
var makeImage = function (src, mimetype) {
|
||||
var image = new Image();
|
||||
image.onload = function () {
|
||||
loadingIndicator.done();
|
||||
|
||||
var imageDataObj = {
|
||||
src: this.src,
|
||||
mimetype,
|
||||
|
@ -357,6 +362,13 @@ dlfUtils.fetchStaticImageData = function (imageSourceObj) {
|
|||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.responseType = 'blob';
|
||||
xhr.onprogress = function (e) {
|
||||
if (e.lengthComputable) {
|
||||
loadingIndicator.progress(e.loaded / e.total);
|
||||
} else {
|
||||
loadingIndicator.indeterminate();
|
||||
}
|
||||
};
|
||||
xhr.onload = function () {
|
||||
if (200 <= xhr.status && xhr.status < 300) {
|
||||
var blob = xhr.response;
|
||||
|
@ -367,6 +379,7 @@ dlfUtils.fetchStaticImageData = function (imageSourceObj) {
|
|||
};
|
||||
xhr.onerror = function () {
|
||||
// Mixed content or bad CORS headers? Try again using passive content.
|
||||
loadingIndicator.indeterminate();
|
||||
makeImage(imageSourceObj.url, imageSourceObj.mimetype);
|
||||
};
|
||||
xhr.open('GET', imageSourceObj.url);
|
||||
|
|
Loading…
Reference in New Issue