Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/js/timeline/Timeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ class Timeline {
// Set TimeNav Height
this.options.timenav_height = this._calculateTimeNavHeight(this.options.timenav_height);

// Sanitize zoom sequence
this.options.zoom_sequence = this._sanitizeZoomSequence(this.options.zoom_sequence);

// Create TimeNav
this._timenav = new TimeNav(this._el.timenav, this.config, this.options, this.language);
this._timenav.on('loaded', this._onTimeNavLoaded, this);
Expand Down Expand Up @@ -724,6 +727,51 @@ class Timeline {
return height;
}

/**
* Sanitize value of zoom sequence.
* Should be an array with numeric values or respective string or
* undefined if not set by author
* @param {number[]|string} [zoomSequence] - Values intended as possible zoom levels
* @returns {number[]} Sanitized array of possible zoom levels.
*/
_sanitizeZoomSequence(zoomSequence) {
// Ensure string contains proper number array representation
if (typeof zoomSequence === 'string') {
// Forgive spaces in URL fragment
zoomSequence = decodeURI(zoomSequence).replace(/\s/g, '');

const validRegExp = /^\[([0-9]*[.])?[0-9]+(,([0-9]*[.])?[0-9]+)*\]$/;
if (!validRegExp.test(zoomSequence)) {
return Timeline.DEFAULT_ZOOM_SEQUENCE; // Not valid string representation of array with numbers
}

zoomSequence = zoomSequence
.substring(1, zoomSequence.length - 1)
.split(',');
}

if (!Array.isArray(zoomSequence)) {
return Timeline.DEFAULT_ZOOM_SEQUENCE; // Nothing that we can work with
}

// Remove invalid values and sort in ascending order
zoomSequence = zoomSequence.reduce((valid, value) => {
const numberValue = Number.parseFloat(value);
if (
Number.isNaN(numberValue) ||
numberValue < 0 || // Zoom factor must be greater than zero
valid.includes(numberValue) // Duplicate
) {
return valid;
}

return [...valid, numberValue];
}, []);
zoomSequence.sort((a, b) => a - b);

return zoomSequence;
}

_validateOptions() {
// assumes that this.options and this.config have been set.
var INTEGER_PROPERTIES = ['timenav_height', 'timenav_height_min', 'marker_height_min', 'marker_width_min', 'marker_padding', 'start_at_slide', 'slide_padding_lr'];
Expand Down Expand Up @@ -1023,6 +1071,9 @@ class Timeline {

}

/** @const {number[]} DEFAULT_ZOOM_SEQUENCE Array of Fibonacci numbers for TimeNav zoom levels */
Timeline.DEFAULT_ZOOM_SEQUENCE = [0.5, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89];

classMixin(Timeline, I18NMixins, Events)

export { Timeline }