123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774 |
- 'use strict';
- /**
- * Licensed Materials - Property of IBM
- * IBM Cognos Products: BI Cloud (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(['../lib/@waca/dashboard-common/dist/ui/SearchableListView', '../lib/@waca/core-client/js/core-client/utils/Deferred', 'text!./templates/PinView.html', 'text!./templates/PinListItem.html', 'text!./templates/EmptyPinsList.html', '../app/nls/StringResources', 'jquery', 'underscore', 'doT', '../lib/@waca/core-client/js/core-client/utils/Utils', '../lib/@waca/core-client/js/core-client/utils/BidiUtil', '../lib/@waca/core-client/js/core-client/utils/ContentFormatter', '../lib/@waca/dashboard-common/dist/ui/toolbar_components/ToggleMenuBar', '../lib/@waca/dashboard-common/dist/lib/@ba-ui-toolkit/ba-graphics/dist/illustrations-js/no-pins_128'], function (SearchableListView, Deferred, ViewTemplate, PinListItem, EmptyPinsList, StringResources, $, _, dot, Utils, BidiUtil, ContentFormatter, ToggleMenuBar, noPinIcon) {
- var DEFAULT_DELAY = 500;
- /**
- * The Panel which shows the pinned content
- */
- var View = SearchableListView.extend({
- events: {
- 'mousedown .pinItem>div:not(.prop-deleteButton-item)': 'onDragStart',
- 'mouseup .pinItem>div:not(.prop-deleteButton-item)': 'onMouseUp',
- 'dragstart .pinItem': 'onDragStart',
- 'primaryaction .prop-deleteButton-item': 'onSingleRemove',
- 'deleteaction .pinItem': 'onSingleRemove'
- },
- itemTemplate: PinListItem,
- templateString: ViewTemplate,
- init: function init(attributes) {
- View.inherited('init', this, arguments);
- this.ajaxSvc = attributes.ajaxSvc;
- this.glassContext = attributes.glassContext;
- this.canvasController = attributes.canvasController;
- this.dashboardApi = this.canvasController.dashboardApi;
- this._icons = this.dashboardApi.getFeature('Icons');
- this.logger = this.glassContext.getCoreSvc('.Logger');
- this.dndManager = attributes.dndManager;
- this.dashboardPinningService = attributes.dashboardPinningService;
- this.smartNamingSvc = attributes.smartNamingSvc;
- this.promiseMap = {};
- this.pinCount = 0;
- this.viewMode = attributes.viewMode;
- this.elementClass = 'pinsPanel';
- this.dateFilterString = 'all';
- if (this.dashboardPinningService) {
- //register creating-pin handler
- this.addHandler = this.dashboardPinningService.on('pin:created', this.addPin.bind(this));
- //register deleting-pin handler
- this.postDeletionHandler = this.dashboardPinningService.on('pin:deleted', this.postDeletion.bind(this));
- //register fake-deleting-pin handler
- this.fakeDeletionHandler = this.dashboardPinningService.on('pin:fakeDeleted', this.fakeDeletion.bind(this));
- //register undo-deleting-pin handler
- this.undoDeletionHandler = this.dashboardPinningService.on('pin:undoDeletion', this.undoDeletion.bind(this));
- } else {
- throw new Error('Pinning service not provided to PinsPanel constructor');
- }
- },
- /**
- * Click event handler
- *
- * @param event:
- * The event to process
- * @public
- */
- onItemClick: function onItemClick(event) {
- // stop more events
- event.stopPropagation();
- //clear the existing selection as we only supports single selection for now
- this._clearSelections();
- // get target
- var $target = $(this.getTarget(event.currentTarget, 'pinItem'));
- this._toggleSelection($target);
- // update action buttons
- this._updateActionButtons();
- },
- onKeyDown: function onKeyDown(event) {
- var $target = $(this.getTarget(event.currentTarget, 'pinItem'));
- if (['Enter', ' '].indexOf(event.key) !== -1) {
- // Tab into the item does not select it so do the selection here and create on key
- if (!$target.hasClass('selected')) {
- this._toggleSelection($target);
- }
- this.onKeyDownToCreatePin(event);
- } else {
- View.inherited('onKeyDown', this, arguments);
- }
- },
- /**
- * Alias for the click event handler
- *
- * @param event:
- * The event to process
- * @public
- */
- onSelectItem: function onSelectItem(event) {
- this.onItemClick(event);
- },
- /**
- * Click handler for the remove button. It handles deleting the pins and updating the UI.
- *
- * @public
- * @return promise
- */
- onRemoveClick: function onRemoveClick() {
- // get selected pin
- var pinId = this._getSelectedPin();
- return this.deletePin(pinId);
- },
- /**
- * primary action handler for clicking/tapping the remove icon on a single pin in the list.
- * delete action handler for deleting a single list item in the list
- * it creates a pin object with the selected pin id and jQuery element, and calls deletePin() to delete the selected single pin
- *
- * @public
- *
- * @param {Event} EventObject - the event object to process
- * @return promise
- */
- onSingleRemove: function onSingleRemove(event) {
- var pinEl = $(event.currentTarget).parents('.listitem')[0] || event.target;
- var pinToRemove = pinEl.getAttribute('data-id');
- return this.deletePin(pinToRemove);
- },
- /**
- * Called by the DnD manager to check if this drop zone accept the dragged object
- *
- * @returns {Boolean}
- */
- accepts: function accepts(dragObject) {
- return dragObject.type === 'pin';
- },
- /**
- * Handles dragging action.
- * The function sends the id of a pin to pinning service and calls the dnd manager with the pin spec result
- *
- * @public
- *
- * @param {object} event - The event to process
- */
- onDragStart: function onDragStart(event) {
- var _this = this;
- this._mouseUp = false;
- if (this.dashboardApi.getMode() !== this.dashboardApi.MODES.EDIT) {
- return Promise.resolve(true);
- }
- var pinEl = $(event.currentTarget).parents('.listitem')[0] || event.target;
- var id = pinEl.getAttribute('data-id');
- if (id) {
- return this.getPin(id).then(function (pinSpec) {
- // If the mouse is up before we start dragging then just return
- if (_this._mouseUp) {
- return;
- }
- pinSpec = JSON.parse(JSON.stringify(pinSpec));
- if (!_.isEmpty(pinSpec) && !_this._stoppedDrag) {
- _this.dndManager.startDrag({
- event: event,
- type: 'pin',
- data: _this._buildDropInfo(pinSpec),
- avatar: _this._buildAvatar(pinSpec),
- moveXThreshold: 20,
- moveYThreshold: 20,
- callerCallbacks: {
- onDragDone: _this.onDragStop.bind(_this)
- }
- });
- }
- });
- } else {
- return Promise.resolve();
- }
- },
- // User might of single clicked, so stop the drag from starting
- onMouseUp: function onMouseUp() {
- this._mouseUp = true;
- this.onDragStop();
- },
- onDragStop: function onDragStop() {
- this._clearSelections();
- },
- /**
- * Gets a pin spec from calling glassContext using a pin id
- *
- * @public
- *
- * @param {stirng} id - The id of a pin
- * @return {string} pinSpec - The spec of a pin
- */
- getPin: function getPin(id) {
- return this.dashboardPinningService.getPin(id);
- },
- /**
- * A helper function to build avatar for a pin
- * @param {string} pinSpec - the spec of a pin
- * @return {object} - a jquery object with an img of the pin if present.
- */
- _buildAvatar: function _buildAvatar(pinSpec) {
- var avatar = $('<img/>', {
- class: 'avatar pin'
- });
- avatar.attr('src', pinSpec.thumbUri);
- return avatar;
- },
- /**
- * a helper method to build drop info based on the pin spec that was received from the server
- *
- * @private
- *
- * @param {object} pinSpec - description of a pin
- * @return {object} dropInfo
- */
- _buildDropInfo: function _buildDropInfo(pinSpec) {
- return {
- operation: 'new',
- pinSpec: pinSpec
- };
- },
- /**
- * Deletes pins by sending an ajax request and updates the UI
- *
- * @param id:
- * string - a pin id to delete
- * @public
- */
- deletePin: function deletePin(id) {
- this.dashboardPinningService.deletePin(id);
- },
- /**
- * Undo deletion handler. It gets called if the undo deletion event is triggered.
- * The selected pin slides down and the pin count increments by 1
- * @param id:
- * string - a pin id to delete
- * @public
- * @return promise
- */
- undoDeletion: function undoDeletion(pinId) {
- var that = this;
- var deferred = new Deferred();
- this.promiseMap[pinId].promise.done(function () {
- var $pinItem = that.$el.find('.pinItem[data-id=' + pinId + ']');
- $pinItem.slideDown(DEFAULT_DELAY, function () {
- // increment the pin count
- that.pinCount++;
- that._updatePinCount();
- // remove from the promise map
- delete that.promiseMap[pinId];
- deferred.resolve();
- });
- });
- return deferred.promise;
- },
- /**
- * Fake deletion handler. It gets called if the fake deletion event is triggered.
- * The selected pin slides up and the pin count decrements by 1
- *
- * @param id:
- * string - a pin id to delete
- * @public
- */
- fakeDeletion: function fakeDeletion(pinId) {
- var _this2 = this;
- var deferred = new Deferred();
- //save the promise into the promise map
- this.promiseMap[pinId] = deferred;
- var $pinItem = this.$el.find('.pinItem[data-id=' + pinId + ']');
- $pinItem.slideUp(DEFAULT_DELAY, function () {
- //decrement the pin count by one in the panel
- _this2.pinCount--;
- _this2._updatePinCount();
- //clear the selection state and update the action button
- _this2._clearSelections();
- _this2._updateActionButtons();
- deferred.resolve();
- });
- },
- /**
- * post deletion handler. It gets called if a pin:deleted event is triggered.
- * The pin item gets removed from the DOM after fake deletion finishes
- *
- * @param id:
- * string - a pin id to delete
- * @public
- * @returns promise
- */
- postDeletion: function postDeletion(pinId) {
- var view = this;
- var deferred = new Deferred();
- if (this.promiseMap[pinId]) {
- this.promiseMap[pinId].promise.done(function () {
- var $el = view.$el.find('.pinItem[data-id=' + pinId + ']');
- $el.remove();
- //make the first item in the list tabbable after deletion
- var firstEl = view.$el.find('.pinItem:first');
- if (firstEl.length) {
- firstEl.attr('tabindex', '0');
- }
- //remove from the promise map
- delete view.promiseMap[pinId];
- deferred.resolve();
- });
- } else {
- deferred.resolve();
- }
- return deferred.promise;
- },
- /**
- * primary action handler for adding pin to canvas
- *
- * @public
- * @param {event} event - The event object to process
- */
- onKeyDownToCreatePin: function onKeyDownToCreatePin(event) {
- // get selected pin
- var pinId = this._getSelectedPin();
- if (pinId) {
- return this.getPin(pinId).then(function (pinSpec) {
- pinSpec = JSON.parse(JSON.stringify(pinSpec)); //Clone the pin spec, as the add operation is side-effecting, and we don't want any updates to change the cached pin.
- if (!_.isEmpty(pinSpec)) {
- var fragmentModel = {
- layout: pinSpec.content.layout,
- widgets: pinSpec.content.widgets,
- dataSources: pinSpec.content.dataSources,
- version: pinSpec.version ? pinSpec.content.specVersion : 6,
- sourceName: pinSpec.sourceName
- };
- if (pinSpec.content.episodes) {
- fragmentModel.episodes = pinSpec.content.episodes;
- }
- var options = {
- model: fragmentModel
- };
- if (pinSpec.content.layout && pinSpec.content.layout.style) {
- options.layoutProperties = {
- style: _.omit(pinSpec.content.layout.style, 'top', 'left')
- };
- }
- var isTouch = event.type === 'tap';
- this._addPinToLayout(options, isTouch);
- this._clearSelections();
- }
- }.bind(this));
- } else {
- return Promise.resolve();
- }
- },
- _addPinToLayout: function _addPinToLayout(options, isTouch) {
- this.canvasController.addPin(options, isTouch);
- },
- /**
- * Callback function for when the render is completed. This one updates the pin count in the UI and puts the focus on the first pin.
- *
- * @public
- */
- renderComplete: function renderComplete() {
- // update the pin count
- this._updatePinCount();
- this._middleShortenPins();
- this._setIcons();
- this._setFocus();
- },
- renderList: function renderList(items) {
- this.pinCount = items ? items.length : 0;
- View.inherited('renderList', this, arguments);
- },
- render: function render() {
- var deferred = new Deferred();
- this.dndManager.removeDropTarget(this.el);
- View.inherited('render', this).done(function () {
- this.dndManager.addDropTarget(this.el, {
- accepts: this.accepts
- });
- this._renderDateFilterDropdown().then(function () {
- deferred.resolve();
- });
- }.bind(this));
- return deferred.promise;
- },
- _filterByDate: function _filterByDate(filterString) {
- var _this3 = this;
- if (!filterString) {
- return;
- }
- this.dateFilterString = filterString;
- if (this.dateFilterString !== 'all') {
- this.$el.find('.filterWrapper').addClass('filtered');
- } else {
- this.$el.find('.filterWrapper').removeClass('filtered');
- }
- return this._getPins().then(function (pins) {
- _this3.pinCount = pins.length;
- _this3.renderList(pins);
- // re-apply any search that may already be in place.
- _this3.$el.find('.treeSearchInput').trigger('input');
- _this3.renderComplete();
- });
- },
- _renderDateFilterDropdown: function _renderDateFilterDropdown() {
- var _this4 = this;
- var $filterWrapper = this.$el.find('.filterWrapper');
- var menuItems = [{
- 'name': 'all',
- 'label': StringResources.get('pinDateFilterAll'),
- 'cssStyleClass': 'blueSelectedBar',
- 'action': function action() {
- _this4._filterByDate('all');
- }
- }, {
- 'name': 'today',
- 'label': StringResources.get('pinDateFilterToday'),
- 'cssStyleClass': 'blueSelectedBar',
- 'action': function action() {
- _this4._filterByDate('today');
- }
- }, {
- 'name': 'yesterday',
- 'label': StringResources.get('pinDateFilterYesterday'),
- 'cssStyleClass': 'blueSelectedBar',
- 'action': function action() {
- _this4._filterByDate('yesterday');
- }
- }, {
- 'name': 'pastWeek',
- 'label': StringResources.get('pinDateFilterPastWeek'),
- 'cssStyleClass': 'blueSelectedBar',
- 'action': function action() {
- _this4._filterByDate('pastWeek');
- }
- }, {
- 'name': 'pastMonth',
- 'label': StringResources.get('pinDateFilterPastMonth'),
- 'cssStyleClass': 'blueSelectedBar',
- 'action': function action() {
- _this4._filterByDate('pastMonth');
- }
- }, {
- 'name': 'earlier',
- 'label': StringResources.get('pinDateFilterEarlier'),
- 'cssStyleClass': 'blueSelectedBar',
- 'action': function action() {
- _this4._filterByDate('earlier');
- }
- }];
- this.ddMenu = new ToggleMenuBar({
- 'label': StringResources.get('pinDateFilter'),
- 'items': menuItems,
- 'actionElement': $filterWrapper,
- 'ddMenuPlacement': 'bottom-left',
- 'showTitle': false,
- 'updateLabel': true,
- 'icon': 'common-filter'
- });
- return this.ddMenu.render().then(function ($el) {
- Utils.setIcon($el.find('.common-filter'), _this4._icons.getIcon('filter').id, StringResources.get('pinDateFilter'));
- _this4.$el.find('.filterWrapper').append($el);
- });
- },
- _setFocus: function _setFocus() {
- this.$el.find('.searchWrapper input').focus();
- this.$el.find('.pinItem:first').attr('tabindex', '0');
- },
- _setIcons: function _setIcons() {
- var $deleteIcon = this.$el.find('.deleteButtonHolder:not(:has(svg))');
- Utils.setIcon($deleteIcon, 'dashboard-remove', StringResources.get('pinRemove'));
- },
- /**
- * shows an empty pins list with IBM bee when there is no pins
- * otherwise remove the empty content list
- */
- _updateEmptyPinsList: function _updateEmptyPinsList() {
- if (!this.pinCount) {
- this.$el.find('.list').append(dot.template(EmptyPinsList)({
- text: StringResources.get('NoPinsCollected'),
- emptyBeeIcon: noPinIcon.default.id
- }));
- } else {
- this.$el.find('.list .emptyTableContent').remove();
- }
- },
- _middleShortenPins: function _middleShortenPins() {
- if (this.pinCount) {
- var $pinTexts = this.$el.find('.pinName, .pinSource, .pinAge');
- for (var i = 0; i < $pinTexts.length; i++) {
- ContentFormatter.middleShortenString($pinTexts[i]);
- }
- }
- },
- /**
- * overridden method providing pin specific properties for dot.
- */
- getCustomRenderProperties: function getCustomRenderProperties() {
- return {
- searchText: StringResources.get('pinSearchOld'),
- lbl_listView: StringResources.get('pinListView'),
- lbl_iconView: StringResources.get('pinIconView'),
- lbl_remove: StringResources.get('pinRemove'),
- lbl_add: StringResources.get('add'),
- roleType: 'listitem',
- searchIcon: this._icons.getIcon('search').id
- };
- },
- /**
- * This function is called by the renderer. It fetches the list of pins
- *
- * @public
- * @return promise
- */
- getListItems: function getListItems() {
- var _this5 = this;
- return this._getPins().then(function (pins) {
- _this5.pinCount = pins.length;
- return pins;
- });
- },
- _getPins: function _getPins() {
- return this.dashboardPinningService.getPins(this.dateFilterString);
- },
- /**
- * Add a pin to this view
- *
- * @public
- */
- addPin: function addPin(pin) {
- if (!pin) {
- return;
- }
- // render
- if (this.dateFilterString !== 'yesterday' && this.dateFilterString !== 'earlier') {
- this.pinCount++;
- this._renderPin(pin);
- }
- this.$el.find('.treeSearchInput').trigger('input');
- },
- /**
- * Add a new pin to the rendered list.
- * @private
- */
- _renderPin: function _renderPin(pin) {
- var sHtml = this._getListItemsHtml([pin]);
- var $list = this.$el.find(this.controlClassSelector);
- var view = this;
- // queue up pin to be added to the list
- $list.queue(function () {
- var $item = $(this);
- $(sHtml).hide().css('opacity', 0.0).prependTo($list).delay(200).slideDown('slow', function () {
- $(this).animate({
- opacity: 1.0
- }).show();
- view.renderComplete();
- // allow animations to complete before kicking off the next one.
- window.setTimeout(function () {
- $item.dequeue();
- }, 500);
- });
- });
- },
- /**
- * Callback function for each list item to process it before rendering
- *
- * @param item:
- * list item object to process
- * @public
- * @return Object: The processed list object
- */
- prepareListItem: function prepareListItem(item) {
- item.cssClass = 'pinItem';
- item.selected = false;
- item.canSingleDelete = true;
- item.label_delete = StringResources.get('pinRemove');
- item.isSingleGroup = true;
- return item;
- },
- /**
- * Helper function to toggle the users pin selection.
- *
- * @param item: JQuery list item object to select
- * @private
- */
- _toggleSelection: function _toggleSelection($item) {
- // see if the item is selected and toggle accordingly
- this._selectItem($item, !$item.hasClass('selected'));
- },
- /**
- * Helper function to select the given item
- *
- * @param item: JQuery list item object to select
- * @param select: Boolean flag to indicate select or deselect
- * @private
- */
- _selectItem: function _selectItem($item, select) {
- if (select) {
- // style the item as selected
- $item.addClass('selected');
- } else {
- // remove selected styling
- $item.removeClass('selected');
- }
- },
- /**
- * Helper function to set the disabled status of the action buttons
- *
- * @private
- */
- _updateActionButtons: function _updateActionButtons() {
- // get buttons
- var $buttons = this.$el.find('.actionButton');
- // check if there are selected pins
- if (this.$el.find('.pinItem.selected').length > 0 && this.dashboardApi.getMode() === this.dashboardApi.MODES.EDIT) {
- // enable action buttons
- $buttons.removeClass('disabled');
- $buttons.prop('disabled', false);
- $buttons.attr('tabindex', '0');
- } else {
- // disable action buttons
- $buttons.addClass('disabled');
- $buttons.prop('disabled', true);
- $buttons.attr('tabindex', '-1');
- }
- },
- /**
- * Helper function to get the selected pin
- *
- * @private
- * @return the id of a pin
- */
- _getSelectedPin: function _getSelectedPin() {
- // get selected pin list elements
- var $listItems = this.$el.find('.pinItem.selected');
- if ($listItems.length === 1) {
- return $listItems[0].getAttribute('data-id');
- }
- },
- /**
- * Helper function to update the UI to indicate the number of pins
- *
- * @private
- */
- _updatePinCount: function _updatePinCount() {
- // get the pin count element
- var formattedCount = BidiUtil.enforceNumericShaping(this.pinCount);
- this.$el.find('.pinCount').text(StringResources.get('pinCount', {
- smart_count: formattedCount,
- count: formattedCount
- }));
- this._updateEmptyPinsList();
- },
- /**
- * Overridden method to provide a list of items that are searchable for this view
- */
- _getSearchableItems: function _getSearchableItems() {
- return this.dashboardPinningService.getCachedPins(this.dateFilterString);
- },
- /**
- * Overridden method to provide the searchable string for a view object
- */
- _getSearchableFieldValue: function _getSearchableFieldValue(value) {
- var _this6 = this;
- // concatenate multiple values to search
- var separator = '___';
- var fields = value.displayName + separator + value.sourceName;
- if (value.contentType === 'boardFragment' && value.content.widgets) {
- // if looking at a boardFragment with widgets, use the mapping labels
- _.each(value.content.widgets, function (widget) {
- fields = fields + separator + _this6.smartNamingSvc.getLocalizedWidgetType(widget);
- _.each(widget.mapping, function (mapping) {
- fields = fields + separator + mapping.label;
- });
- // check live widgets
- var items = widget.data && widget.data.dataViews && widget.data.dataViews[0] && widget.data.dataViews[0].dataItems;
- _.each(items, function (item) {
- fields = fields + separator + item.itemLabel;
- });
- });
- }
- return fields;
- },
- _clearSelections: function _clearSelections() {
- this.$el.find('.listitem').removeClass('selected');
- },
- /**
- * Un-registers all of the handlers
- */
- remove: function remove() {
- this.addHandler.remove();
- this.postDeletionHandler.remove();
- this.fakeDeletionHandler.remove();
- this.undoDeletionHandler.remove();
- View.inherited('remove', this, arguments);
- }
- });
- return View;
- });
- //# sourceMappingURL=PinsPanel.js.map
|