'use strict'; /** * Licensed Materials - Property of IBM * IBM Cognos Products: Storytelling * (C) Copyright IBM Corp. 2014, 2020 * 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', 'baglass/core-client/js/core-client/utils/ContentFormatter', 'text!./templates/TimelineSliderContentView.html', 'baglass/core-client/js/core-client/utils/dom-utils', 'baglass/core-client/js/core-client/utils/Utils', '../lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/resize-panel_16'], function (View, $, _, ScreenReaderUtil, ContentFormatter, template, DomUtils, Utils, resizePanelIcon) { var TimelineSliderContentView = View.extend({ templateString: template, //should match _endBufferTime in TimeQueue _endBufferTime: 200, dragValue: null, value: null, min: 0, max: 0, scale: 1, title: null, notifyChangedInterval: 200, draggingElement: null, events: {}, init: function init(options) { TimelineSliderContentView.inherited('init', this, arguments); this.id = options.id; this.min = options.min || 0; this.max = options.max || 0; this.value = options.value; this.scale = options.scale || 1; this.title = options.title; this.dndManager = options.dndManager; this.cssClassSelector = options.cssClassSelector; this.stringResources = options.services.getSvcSync('.StringResources'); this.timelineController = options.timelineController; // convert to seconds this._minimumDuration = this._endBufferTime / 1000; this._ScreenReader = new ScreenReaderUtil(); }, render: function render() { var leftHandleLabel = this.title ? this.stringResources.get('timelineLeftHandle', { name: this.title }) : this.stringResources.get('timelineLeftHandleNoTitle'); var rightHandleLabel = this.title ? this.stringResources.get('timelineRightHandle', { name: this.title }) : this.stringResources.get('timelineRightHandleNoTitle'); var sHtml = this.dotTemplate({ id: this.id, leftHandleLabel: leftHandleLabel, rightHandleLabel: rightHandleLabel }); this.$el.html(sHtml); this.$highlightsEl = this.$el.find('.highlights-container'); this.$selection = this.$el.find('.slider-selection'); this.$handles = this.$selection.find('.handle'); this.$content = this.$selection.find('.content'); this.$content = this.$el.find('.content'); this.$title = this.$content.find('.title'); Utils.setIcon(this.$el.find('.svgHandleIcon'), resizePanelIcon.default.id); var isTouch = this._isTouchMode(); this._toggleDragEvents(!isTouch); if (isTouch) { this._addHoldEvents(); } else { this._addKeyDownEvents(); } this._addClickEvents(); this._update(); this._updateTitle(); return this; }, setTitle: function setTitle(title) { this.title = title; this._updateTitle(); }, /** Sets the title and middle-shortens it if the title is too long for the container. */ middleShortenTitle: function middleShortenTitle(title) { this.setTitle(title); ContentFormatter.middleShortenString(this.$title[0]); }, setScale: function setScale(scale) { this.scale = scale; this._update(); }, setValue: function setValue(value, preventNotify) { this.value = value; if (this.$content) { this._update(); if (!preventNotify) { this._notifyValueChanged(); } } }, getValue: function getValue() { return this.value; }, getDragValue: function getDragValue() { return this.dragValue; }, setMax: function setMax(max) { this.max = max; }, toggleSelected: function toggleSelected(toggle) { this.$el.toggleClass('selected', toggle); if (this._isTouchMode()) { this._toggleDragEvents(this.isSelected()); } }, isSelected: function isSelected() { return this.$el.hasClass('selected'); }, move: function move(value) { this._move(value[0], value[1] - value[0]); }, /* * View events. */ onHold: function onHold(event) { this._select(event); }, onClick: function onClick(event) { this._select(event); }, /* * Helpers. */ _startArrowKeyMove: function _startArrowKeyMove() { this.dragValue = this.value; this._notifyValueChangeBegin(); }, _select: function _select(event) { this.toggleSelected(true); this.trigger('dragSlider:select', event); }, _move: function _move(start, length, visualOnly) { // on playback we move forward by tick duration each time. // when play on click is enabled it shows in certain cases. // to resolve this display issue we round down to the nearest tick. // (We need the value in seconds) var tick = this.timelineController.getTickDuration() / 1000; var round = function round(value) { return Math.round(value / tick) * tick; }; start = round(start); length = round(length); // Boundary check the values. if (start < 0) { start = 0; } if (length < this._minimumDuration) { length = this._minimumDuration; } var properties = { left: start * this.scale + 'px', width: length * this.scale + 'px' }; this.$selection.css(properties); var value = [start, start + length]; if (!visualOnly) { this.value = value; } var timelineMax = this._roundValueForScreenReader(this.$el.width() / this.scale); this.$handles.eq(0).attr('aria-valuenow', this._roundValueForScreenReader(value[0])); this.$handles.eq(0).attr('aria-valuemin', 0); this.$handles.eq(0).attr('aria-valuemax', this._roundValueForScreenReader(value[1] - this._minimumDuration)); this.$handles.eq(1).attr('aria-valuenow', this._roundValueForScreenReader(value[1])); this.$handles.eq(1).attr('aria-valuemin', this._roundValueForScreenReader(value[0] + this._minimumDuration)); this.$handles.eq(1).attr('aria-valuemax', timelineMax); this.$content.attr('aria-valuenow', this._roundValueForScreenReader((value[0] + value[1]) / 2)); this.$content.attr('aria-valuemin', 0); this.$content.attr('aria-valuemax', timelineMax); return value; }, _update: function _update() { this.move(this.value); }, _updateTitle: function _updateTitle() { var leftHandleLabel = this.title ? this.stringResources.get('timelineLeftHandle', { name: this.title }) : this.stringResources.get('timelineLeftHandleNoTitle'); var rightHandleLabel = this.title ? this.stringResources.get('timelineRightHandle', { name: this.title }) : this.stringResources.get('timelineRightHandleNoTitle'); this.$title.text(this.title); this.$handles.eq(0).attr('aria-label', leftHandleLabel); this.$handles.eq(1).attr('aria-label', rightHandleLabel); }, _notifyValueChangeBegin: function _notifyValueChangeBegin() { this.trigger('value:willChange'); }, _notifyValueChanged: function _notifyValueChanged(extraOptions) { this.trigger('value:changed', _.extend({ value: this.value, min: this.min, max: this.max }, extraOptions)); }, _addHoldEvents: function _addHoldEvents() { var handler = this.onHold.bind(this); this.$handles.hammer().on('hold', handler); this.$content.hammer().on('hold', handler); }, _addClickEvents: function _addClickEvents() { var mouseDownHandler = function () { this.isDragging = false; }.bind(this); var clickHandler = function (event) { if (!this.isDragging) { this.onClick(event); } }.bind(this); this.$handles.on('mousedown', mouseDownHandler); this.$content.on('mousedown', mouseDownHandler); this.$handles.on('click', clickHandler); this.$content.on('click', clickHandler); }, _addKeyDownEvents: function _addKeyDownEvents() { this.$handles.on('keydown', this._onKeyPress.bind(this)); this.$content.on('keydown', this._onKeyPress.bind(this)); }, _toggleDragEvents: function _toggleDragEvents(toggle) { this._toggleDragEvent(this.$handles.eq(0), toggle, this._leftHandleDragHandler); this._toggleDragEvent(this.$handles.eq(1), toggle, this._rightHandleDragHandler); this._toggleDragEvent(this.$content, toggle, this._contentDragHandler); }, _toggleDragEvent: function _toggleDragEvent($node, enable, handler) { if (enable) { $node.hammer().on('dragstart', this._dragHandler.bind(this, handler)); } else { $node.hammer().off('dragstart'); } }, _dragHandler: function _dragHandler(wrapped, event) { this.trigger('dragSlider:dragStarted'); var extraOptions = { payloadData: { undoRedoTransactionId: _.uniqueId('dragSlider') } }; var config = { type: 'timelineSlider', data: { slider: this }, restrictToXAxis: true, avatar: null, event: event, callerCallbacks: { onDragStart: function (event, options) { $('body').addClass('overflowHidden'); this.dragValue = this.value; if (wrapped.onDragStart) { wrapped.onDragStart.bind(this)(event, options); } this._notifyValueChangeBegin(); }.bind(this), onMove: function (event, options) { if (wrapped.onMove) { wrapped.onMove.bind(this)(event, options); } }.bind(this), onDragDone: function (event, options) { if (wrapped.onDragDone) { wrapped.onDragDone.bind(this)(event, _.extend({}, options, extraOptions)); } if (this.dragValue) { this._move(this.dragValue[0], this.dragValue[1] - this.dragValue[0]); this.dragValue = null; this._notifyValueChanged(extraOptions); } this.draggingElement = null; $('body').removeClass('overflowHidden'); this._select(event); }.bind(this) } }; if (wrapped.getConfig) { var wrapperConfig = wrapped.getConfig.bind(this)(event); _.extend(config, wrapperConfig); } this.dndManager.startDrag(config); }, _leftHandleDragHandler: { onDragStart: function onDragStart() { this.draggingElement = 'leftHandle'; this.isDragging = true; }, onMove: function onMove(event, options) { var deltaX = options.dragObject.position.x - options.dragObject.startPosition.x; var x = deltaX / this.scale; var start = x + this.value[0]; var length = this.value[1] - this.value[0] - x; if (start < 0) { length += start; } else if (start + this._minimumDuration > this.value[1]) { start = this.value[1] - this._minimumDuration; } this.dragValue = this._move(start, length, true); } }, _rightHandleDragHandler: { onDragStart: function onDragStart() { this.draggingElement = 'rightHandle'; this.isDragging = true; }, onMove: function onMove(event, options) { var deltaX = options.dragObject.position.x - options.dragObject.startPosition.x; this.dragValue = this._move(this.value[0], deltaX / this.scale + (this.value[1] - this.value[0]), true); } }, _contentDragHandler: { getConfig: function getConfig(event) { var $avatar = $('
').addClass('dragAvatar timelineContent bringToFront selected').hide(); $('body').append($avatar); $avatar.append(this.$selection.clone()); if (this.cssClassSelector) { $avatar.append(this.$el.find('.' + this.cssClassSelector).clone()); } var offset = this.$selection.offset(); var eventPos = DomUtils.getEventPos(event); var avatarYOffset = offset.top - eventPos.pageY; var avatarXOffset = offset.left - eventPos.pageX - this.value[0] * this.scale; return { type: 'dragSliderContent', dragLockToAxis: true, restrictToXAxis: false, restrictToYAxis: false, moveXThreshold: 20, moveYThreshold: 20, data: { slider: this, avatar: $avatar }, avatar: $avatar[0], avatarXOffset: avatarXOffset, avatarYOffset: avatarYOffset }; }, onDragStart: function onDragStart(event, options) { this.draggingElement = 'content'; // show the avatar and hide the real slider options.dragObject.data.avatar.show(); if (this.cssClassSelector) { this.$cssClassSelector = this.$el.find('.' + this.cssClassSelector); this.$cssClassSelector.hide(); } this.$selection.hide(); this.isDragging = true; }, onMove: function onMove(event, options) { var deltaX = options.dragObject.position.x - options.dragObject.startPosition.x; this.dragValue = this._move(deltaX / this.scale + this.value[0], this.value[1] - this.value[0], true); }, onDragDone: function onDragDone(event, options) { // restore the slider and hide the avatar this.$selection.show(); if (this.cssClassSelector) { this.$cssClassSelector.show(); } options.dragObject.data.avatar.hide(); this.trigger('dragSlider:isDropped', _.extend({ id: this.id }, options)); } }, _onKeyPress: function _onKeyPress(evt) { var $target = $(evt.currentTarget); var isLeftHandle = $target.hasClass('lefthandle'); var isRightHandle = $target.hasClass('righthandle'); // Select the selection with white space or return key if (evt.keyCode === 13 || evt.keyCode === 32) { this._select(evt); $target.toggleClass('active', isLeftHandle || isRightHandle); $target.focus(); return; } var messageOptions = { title: this.title }; // Set moveby amount and message for move var xMoveByDelta = 0; var yMoveByDelta = 0; var sMessage = ''; switch (evt.keyCode) { case 9: // Tab $target.toggleClass('active', false); return; case 37: // Left arrow xMoveByDelta = -0.1; break; case 39: // Right arrow xMoveByDelta = 0.1; break; case 38: // up arrow if (isLeftHandle || isRightHandle) { //handles can't be moved up evt.stopPropagation(); evt.preventDefault(); return; } yMoveByDelta = -1; break; case 40: //down arrow if (isLeftHandle || isRightHandle) { //handles can't be moved down evt.stopPropagation(); evt.preventDefault(); return; } yMoveByDelta = 1; break; default: return; } evt.stopPropagation(); evt.preventDefault(); $target.toggleClass('active', isLeftHandle || isRightHandle); // Start arrow key move this._startArrowKeyMove(); if (isLeftHandle) { var start = xMoveByDelta + this.value[0]; var length = this.value[1] - this.value[0] - xMoveByDelta; if (start < 0) { length += start; } else if (start > this.value[1]) { start = this.value[1]; } this.dragValue = this._move(start, length, true); } else if (isRightHandle) { this.dragValue = this._move(this.value[0], xMoveByDelta + (this.value[1] - this.value[0]), true); } else { if (xMoveByDelta != 0) { this.dragValue = this._move(xMoveByDelta + this.value[0], this.value[1] - this.value[0], true); } else { var options = { id: this.id, payloadData: { undoRedoTransactionId: _.uniqueId('dragSlider') } }; var event = yMoveByDelta > 0 ? 'dragSlider:movingDown' : 'dragSlider:movingUp'; this.trigger(event, options); this.trigger('dragSlider:isDropped', options); } } // End move update if (this.dragValue) { messageOptions.newStartTime = this._roundValueForScreenReader(this.dragValue[0]); messageOptions.newEndTime = this._roundValueForScreenReader(this.dragValue[1]); this._move(this.dragValue[0], this.dragValue[1] - this.dragValue[0]); this.dragValue = null; this._notifyValueChanged(); } if (isLeftHandle) { messageOptions.resourceName = 'timelineMoveWidgetStartTime'; } else if (isRightHandle) { messageOptions.resourceName = 'timelineMoveWidgetEndTime'; } else if (yMoveByDelta < 0) { messageOptions.resourceName = 'timelineMoveWidgetUp'; } else if (yMoveByDelta > 0) { messageOptions.resourceName = 'timelineMoveWidgetDown'; } else { messageOptions.resourceName = 'timelineMoveWidget'; } // update the move this._update(); sMessage = this.stringResources.get(messageOptions.resourceName, messageOptions); // update screenreader input this._ScreenReader.callOut(sMessage); }, _roundValueForScreenReader: function _roundValueForScreenReader(value) { return Math.round(value * 100) / 100; }, _isTouchMode: function _isTouchMode() { return 'ontouchstart' in document.documentElement; } }); return TimelineSliderContentView; }); //# sourceMappingURL=TimelineSliderContentView.js.map