123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- 'use strict';
- /**
- * Licensed Materials - Property of IBM
- * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 2018
- * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
- */
- define(['baglass/core-client/js/core-client/ui/core/View', 'jquery', 'underscore', 'gemini/app/util/ScreenReaderUtil', 'storytelling/nls/StringResources', 'text!./templates/TimeIndicator.html'], function (View, $, _, ScreenReaderUtil, stringResources, Template) {
- var TimelineTimeIndicatorView = View.extend({
- templateString: Template,
- _allowDrag: true,
- _isDragging: false,
- _dragInfo: null,
- _seekRefreshInterval: 200,
- _seekRefreshTimer: -1,
- _scrollEventHandler: null,
- lastScroll: 0,
- init: function init(options) {
- TimelineTimeIndicatorView.inherited('init', this, arguments);
- this.controller = options.controller;
- this.controller.on('time:update', this.onTimeUpdated, this);
- this.scaleManager = options.scaleManager;
- this.scaleManager.on('scale:change', this.onScaleChanged, this);
- this._ScreenReader = new ScreenReaderUtil();
- this._callOut = _.debounce(this._updateAriaLabel.bind(this), options.callOutDelay || 600);
- this._indicatorOnly = options.indicatorOnly === true;
- if (this._indicatorOnly && typeof options.progressBarCallback === 'function') {
- this.progressBarCallback = options.progressBarCallback;
- }
- },
- remove: function remove() {
- if (this.$handle) {
- this.$handle.off('focus touchstart touchend mousedown mouseup keydown');
- this.$handle.hammer().off('dragstart dragleft dragright dragend');
- this.$handle = null;
- }
- if (this.controller) {
- this.controller.off('time:update', this.onTimeUpdated, this);
- }
- if (this.scaleManager) {
- this.scaleManager.off('scale:change', this.onScaleChanged, this);
- }
- TimelineTimeIndicatorView.inherited('remove', this, arguments);
- },
- /**
- * Renders the film strip
- *
- * @returns
- */
- render: function render() {
- var sHtml = this.dotTemplate({
- allInfo: !this._indicatorOnly,
- handleLabel: stringResources.get('timelinePositionIndicator', { position: this.getCurrentTime() })
- });
- this.$el.html(sHtml);
- this.$handle = this.$el.find('div.handle');
- if (!this._indicatorOnly) {
- this.$handleValue = this.$handle.find('div:nth-of-type(1)');
- this.$handleArrow = this.$handle.find('div:nth-of-type(2)');
- }
- this.$handle.on('focus', this.handleTimelinePositionIndicatorMove.bind(this)).on('touchstart', this.onTouchStart.bind(this)).on('touchend', this.onTouchEnd.bind(this)).on('mousedown', this.onTouchStart.bind(this)).on('mouseup', this.onTouchEnd.bind(this)).on('keydown', this._onKeyDown.bind(this));
- this.$handle.hammer().on('dragstart', this.onDragStart.bind(this)).on('dragleft', this.onDragLeftRight.bind(this)).on('dragright', this.onDragLeftRight.bind(this)).on('dragend', this.onDragEnd.bind(this));
- // Set the initial position.
- this._moveIndicatorWithTime(this.controller.getCurrentTime());
- return this;
- },
- setFocus: function setFocus() {
- this.$handle.focus();
- },
- getCurrentTime: function getCurrentTime() {
- return this.controller.getTimeLabel(this.controller.getCurrentTime(), true);
- },
- getEndTime: function getEndTime() {
- return this.controller.getTimeLabel(this.controller.getDuration(), true);
- },
- onScroll: function onScroll(event) {
- this.lastScroll = event.scrollLeft;
- this.refresh();
- },
- refresh: function refresh() {
- this._moveIndicatorWithTime(this.controller.getCursorTime());
- },
- /*
- * View events
- */
- onTouchStart: function onTouchStart() {
- this.$el.addClass('dragging');
- this.wasPlaying = this.controller.isPlaying();
- // Pause when interacting with the indicator.
- if (this.wasPlaying) {
- this.controller.pause();
- }
- },
- onTouchEnd: function onTouchEnd() {
- this.$el.removeClass('dragging');
- // Start playing if we were originally playing before the drag.
- if (this.wasPlaying) {
- this.wasPlaying = false;
- this.controller.play();
- }
- },
- onDragStart: function onDragStart(event) {
- event.gesture.preventDefault();
- this.$el.addClass('dragging');
- this._setDragStartInfo();
- },
- onDragLeftRight: function onDragLeftRight(event) {
- event.gesture.preventDefault();
- var position = this._getBoundedPosition(event.gesture.deltaX);
- this._moveIndicatorWithPosition(position);
- },
- onDragEnd: function onDragEnd(event) {
- event.gesture.preventDefault();
- this._clearInterval();
- this.$el.removeClass('dragging');
- this._isDragging = false;
- var position = this._getBoundedPosition(event.gesture.deltaX);
- this._moveIndicatorWithPosition(position);
- this._updateTimeFromDrag();
- this._dragInfo = null;
- },
- _onKeyDown: function _onKeyDown(evt) {
- if (this._shouldScrub(evt)) {
- // Arrow key with no shift key
- this._onArrowKeyPress(evt);
- } else if (this._shouldJumpToNextMarker(evt)) {
- // Shift + (Left or Up) when parent view is the timeline or navigate markers is enabled
- this.controller.jumpToNextMarker();
- this.handlePositionMoveRight();
- evt.stopPropagation();
- } else if (this._shouldJumpToPreviousMarker(evt)) {
- // Shift + (Right or Down) when parent view is the timeline or navigate markers is enabled
- this.controller.jumpToPreviousMarker();
- this.handlePositionMoveLeft();
- evt.stopPropagation();
- } else if (this._shouldJumpToStartOfScene(evt)) {
- // Shift + (Left or Up) when parent view is the progress bar
- this.controller.setCurrentTime(0);
- this._updateAriaLabel('sceneStart');
- evt.stopPropagation();
- } else if (this._shouldJumpToEndOfScene(evt)) {
- // Shift + (Right or Down) when parent view is the progress bar
- this.controller.setCurrentTime(this.controller.getDuration());
- this._updateAriaLabel('sceneEnd');
- evt.stopPropagation();
- } else if (this._shouldPerformTogglePlayPause(evt)) {
- // Spacebar when parent view is the progress bar or the timeline
- this.controller.eventRouter.trigger('playback:togglePlayPause');
- evt.stopPropagation();
- }
- },
- // Left or Right with no shift key
- _shouldScrub: function _shouldScrub(evt) {
- return !evt.shiftKey && [37, 38, 39, 40].indexOf(evt.keyCode) !== -1;
- },
- // Shift + (Left or Up) when parent view is the timeline
- _shouldJumpToPreviousMarker: function _shouldJumpToPreviousMarker(evt) {
- var isTimeline = this.$el.hasClass('timelinePosition');
- return (isTimeline || this.controller.isNavigateMarkers()) && evt.shiftKey && [37, 38].indexOf(evt.keyCode) !== -1;
- },
- // Shift + (Right or Down) when parent view is the timeline
- _shouldJumpToNextMarker: function _shouldJumpToNextMarker(evt) {
- var isTimeline = this.$el.hasClass('timelinePosition');
- return (isTimeline || this.controller.isNavigateMarkers()) && evt.shiftKey && [39, 40].indexOf(evt.keyCode) !== -1;
- },
- // Shift + (Left or Up) when parent view is the progress bar
- _shouldJumpToStartOfScene: function _shouldJumpToStartOfScene(evt) {
- var isProgressBar = this.$el.hasClass('progressBarPosition');
- return isProgressBar && evt.shiftKey && [37, 38].indexOf(evt.keyCode) !== -1;
- },
- // Shift + (Right or Down) when parent view is the progress bar
- _shouldJumpToEndOfScene: function _shouldJumpToEndOfScene(evt) {
- var isProgressBar = this.$el.hasClass('progressBarPosition');
- return isProgressBar && evt.shiftKey && [39, 40].indexOf(evt.keyCode) !== -1;
- },
- // Space with parent view timeline or progress bar
- _shouldPerformTogglePlayPause: function _shouldPerformTogglePlayPause(evt) {
- return evt.keyCode === 32;
- },
- _onArrowKeyPress: function _onArrowKeyPress(evt) {
- var $target = $(evt.currentTarget);
- // Set as selected
- $target.focus();
- // The minimum we can move is 1 tick.
- // we are free to scale it with shift/ctrl later.
- var moveByDelta = this.controller.getTickDuration();
- switch (evt.keyCode) {
- // left key
- case 37:
- case 38:
- moveByDelta *= -1;
- break;
- // right key
- case 39:
- case 40:
- break;
- default:
- return;
- }
- evt.stopPropagation();
- evt.preventDefault();
- this.controller.setCurrentTime(this.controller.getCurrentTime() + moveByDelta);
- if (moveByDelta < 0) {
- this._callOut('timelinePositionIndicatorMoveLeftTo');
- } else {
- this._callOut('timelinePositionIndicatorMoveRightTo');
- }
- this._dragInfo = null;
- },
- /*
- * Controller events.
- */
- onScaleChanged: function onScaleChanged() {
- this._moveIndicatorWithTime(this.controller.getCurrentTime());
- },
- onTimeUpdated: function onTimeUpdated(event) {
- if (!this._isDragging) {
- this._moveIndicatorWithTime(event.currentTime);
- }
- },
- /*
- * Helpers
- */
- // Public Helpers
- handleTimelinePositionIndicatorMove: function handleTimelinePositionIndicatorMove() {
- this._callOut('timelinePositionIndicator');
- },
- handlePositionMoveLeft: function handlePositionMoveLeft() {
- var time = this.getCurrentTime();
- var translationKey = time === '0:00.0' ? 'sceneStart' : 'timelinePositionIndicatorMoveLeftTo';
- this._callOut(translationKey);
- },
- handlePositionMoveRight: function handlePositionMoveRight() {
- var translationKey = this.controller.isAtEndOfScene() ? 'sceneEnd' : 'timelinePositionIndicatorMoveRightTo';
- this._callOut(translationKey);
- },
- // Private Helpers
- _setDragStartInfo: function _setDragStartInfo() {
- this._isDragging = true;
- this._dragInfo = {};
- this._dragInfo.initialScroll = this.lastScroll;
- this._dragInfo.left = this.$el.position().left + this.lastScroll;
- this._dragInfo.currentLeft = this._dragInfo.left;
- this._clearInterval();
- this._seekRefreshTimer = setInterval(this._updateTimeFromDrag.bind(this), this._seekRefreshInterval);
- },
- _updateTimeFromDrag: function _updateTimeFromDrag() {
- // Calculate the time based on the position of the indicator
- var time = this.scaleManager.convertPositionToTime(this._dragInfo.currentLeft);
- this.controller.setCurrentTime(time);
- },
- _moveIndicatorWithTime: function _moveIndicatorWithTime(endTime) {
- var position = this.scaleManager.convertTimeToPosition(endTime);
- this._moveIndicatorWithPosition(position);
- },
- _moveIndicatorWithPosition: function _moveIndicatorWithPosition(position) {
- if (!this.$handle) {
- return;
- }
- if (!this._indicatorOnly) {
- //round to the nearest tick. This is the minimum amount we can deal with.
- var time = this.scaleManager.convertPositionToTime(position);
- var tick = this.controller.getTickDuration();
- time = Math.round(time / tick) * tick;
- position = this.scaleManager.convertTimeToPosition(time);
- }
- var leftVal = void 0;
- var percent = void 0;
- if (this._indicatorOnly) {
- var maxPos = this._getMaxPosition();
- if (maxPos === 0) {
- percent = 0;
- } else {
- percent = position / maxPos * 100;
- }
- leftVal = 'calc(' + percent + '% - ' + this.lastScroll + 'px)';
- } else {
- leftVal = position - this.lastScroll + 'px';
- }
- this.$el.css({
- 'left': leftVal
- });
- this._moveHelper(position);
- if (this._indicatorOnly && this.progressBarCallback) {
- this.progressBarCallback(percent);
- }
- },
- _moveHelper: function _moveHelper(position) {
- var halfWidth = this.$handle.outerWidth(false) / 2;
- var margin = position - halfWidth < 0 ? position : halfWidth;
- var marginLeft = Math.max(0, margin - 7);
- var borderLeftWidth = Math.max(0, Math.min(7, margin));
- // Get the cursor time.
- var time = this.scaleManager.convertPositionToTime(position);
- // _moveHelper is expensive (the two css() calls below) and gets called A LOT, so if nothing is changed, return immediately
- if (margin === this._prevMargin && marginLeft === this._preMarginLeft && borderLeftWidth === this._prevBorderLeftWidth && time === this._prevTime) {
- return;
- }
- this._preMarginLeft = marginLeft;
- this._prevMargin = margin;
- this._prevBorderLeftWidth = borderLeftWidth;
- this._prevTime = time;
- if (!this._indicatorOnly) {
- this.$handle.css('margin-left', -margin + 'px');
- this.$handleArrow.css({
- 'margin-left': marginLeft + 'px',
- 'border-left-width': borderLeftWidth + 'px'
- });
- // Update the cursor label.
- this._updateTimeLabel(time);
- }
- if (this._dragInfo) {
- this._dragInfo.currentLeft = position;
- }
- // Update the controller.
- this.controller.setCursorTime(time);
- },
- _getMaxPosition: function _getMaxPosition() {
- return this.scaleManager.convertTimeToPosition(this.controller.getDuration());
- },
- _getCursorPosition: function _getCursorPosition(delta) {
- return this._dragInfo.left + delta + this.lastScroll - this._dragInfo.initialScroll;
- },
- _getBoundedPosition: function _getBoundedPosition(delta) {
- return Math.max(0, Math.min(this._getCursorPosition(delta), this._getMaxPosition()));
- },
- _updateTimeLabel: function _updateTimeLabel(time) {
- this.$handleValue.text(this.controller.getTimeLabel(time, 1), true);
- },
- _updateAriaLabel: function _updateAriaLabel(msg) {
- if (this.$handle) {
- var sMessage = stringResources.get(msg, { position: this.getCurrentTime() });
- this.$handle.attr({ 'aria-label': sMessage });
- this._ScreenReader.callOut(sMessage);
- }
- },
- _clearInterval: function _clearInterval() {
- if (this._seekRefreshTimer >= 0) {
- clearInterval(this._seekRefreshTimer);
- this._seekRefreshTimer = -1;
- }
- }
- });
- return TimelineTimeIndicatorView;
- });
- //# sourceMappingURL=TimelineTimeIndicatorView.js.map
|