'use strict'; /** * Licensed Materials - Property of IBM * * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2014, 2019, 2020 * * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['../../lib/@waca/core-client/js/core-client/ui/core/View', '../../app/nls/StringResources', 'jquery', 'underscore', '../../lib/@waca/core-client/js/core-client/utils/Utils', 'text!./templates/LayoutPickerView.html', 'text!../layout/templates/listing.json', '../../lib/@waca/core-client/js/core-client/utils/Deferred', '../../lib/@waca/core-client/js/core-client/ui/KeyCodes', '../../lib/@waca/core-client/js/core-client/ui/Menu', '../../lib/@waca/core-client/js/core-client/utils/ContentFormatter', '../../lib/@waca/dashboard-common/dist/ui/dialogs/MessageBox', '../../lib/@waca/dashboard-common/dist/lib/@ba-ui-toolkit/ba-graphics/dist/icons-js/overflow-menu--horizontal_16', '../../lib/@waca/dashboard-common/dist/lib/@ba-ui-toolkit/ba-graphics/dist/illustrations-js/connect-images_128'], function (BaseView, stringResources, $, _, Utils, template, templateListing, Deferred, KeyCodes, Menu, ContentFormatter, MessageBox, contextMenuIcon, thumbnailPlaceholderIcon) { var LayoutPickerView = BaseView.extend({ templateString: template, events: { 'primaryaction .layoutTemplateItem': 'onSelect', 'dblclick .layoutTemplateItem': 'onDoubleClick', 'keydown .layoutTemplateItem': 'onKeyDown', 'click .selected .layoutContextMenuButton': 'onContextMenuButtonClick' }, init: function init(options) { options = options || {}; LayoutPickerView.inherited('init', this, arguments); this.stringResources = options.stringResources || stringResources; var templates = options.templateListing || templateListing; this._showContextMenu = options.showContextMenu; this._dashboardTemplatesApi = options.dashboardTemplatesApi; // process the templates var defaultTemplates = this._processTemplates(JSON.parse(templates)); // remove items from defaultTemplates that were passed in the excludeTemplates array if (options.excludeTemplates) { var newList = defaultTemplates.templates.filter(function (element) { return !_.contains(options.excludeTemplates, element.name); }); defaultTemplates.templates = newList; } _.extend(this, _.defaults(options, defaultTemplates)); this._thumbnailCache = []; this._addCustomTemplates(options.customTemplates); this._whenReady = new Deferred(); this.whenReady = this._whenReady.promise; }, _addCustomTemplates: function _addCustomTemplates(customTemplates) { var _this = this; (customTemplates || []).forEach(function (customTemplate) { _this.templates.push({ label: customTemplate.defaultName, ariaLabel: customTemplate.defaultName, navigationTemplates: 'custom', location: customTemplate.location, isSelected: false, name: customTemplate.id, type: 'custom' }); }); }, /** * This function takes the template object and sorts the array of templates so that the ones with * descriptions are on top as well as translates any labels and descriptions. * * @param templateListObj: Template object to sort. * @private * @returns Object: the sorted template object. **/ _processTemplates: function _processTemplates(templateListObj) { var templateList = templateListObj.templates; var aWithDesc = []; var aWithoutDesc = []; for (var i = 0; i < templateList.length; i++) { // get the next template object var template = templateList[i]; // translate the label if (template.label) { template.label = this.stringResources.get(template.label); } if (template.name) { template.ariaLabel = this.stringResources.get(template.name); } // sort by description into separate arrays if (template.description) { // translate the description and add to the array template.description = this.stringResources.get(template.description); aWithDesc.push(template); } else { // no description so just push to that array aWithoutDesc.push(template); } } return { 'templates': aWithDesc.concat(aWithoutDesc) }; }, render: function render() { this.$el.empty().addClass('layoutPickerView').attr('role', 'listbox').attr('aria-multiselectable', 'false').html(this.dotTemplate(this)); this.filterTemplates(); this.generatePreviews(); }, onSelect: function onSelect(event) { if (event.type === 'keydown' && event.keyCode === 32) { // keydown and spacebar // Stops the scroll bar from scrolling the page event.preventDefault(); } if ((event.type === 'keyup' || event.type === 'keydown') && event.keyCode !== 13 && event.keyCode !== 32) { // ignore anything other than enter or space return; } else { event.stopPropagation(); if (event.keyCode === 13 && $(event.currentTarget).hasClass('selected')) { // if the layout was already selected, enter key submits the layout form this.action(); } else { this.selectLayout(event.currentTarget.dataset.id); if (_.isFunction(this.selectAction)) { this.selectAction(event); } } } }, onDoubleClick: function onDoubleClick(event) { this.onSelect(event); this.action(); }, /** Enter and Space calling stopPropagation is a very specific fix for defect 255098. Solution with the least risk. *call stop propagation when Enter or Space is clicked, so that BaseBoardView.onKeyDown is not called *Those are the keys that trigger primaryaction *TODO: Please revisit after Endor release **/ onKeyDown: function onKeyDown(event) { var items = this.$('.layoutEntry .layoutTemplateItem:not(.filtered)'); var focusedItem = this.$('.layoutEntry .layoutTemplateItem[tabindex=0]'); var focusIndex = items.index(focusedItem); switch (event.keyCode) { case KeyCodes.DOWN_ARROW: case KeyCodes.RIGHT_ARROW: focusIndex++; if (focusIndex >= items.length) { focusIndex = items.length - 1; } break; case KeyCodes.UP_ARROW: case KeyCodes.LEFT_ARROW: focusIndex--; if (focusIndex < 0) { focusIndex = 0; } break; case KeyCodes.HOME: focusIndex = 0; break; case KeyCodes.END: focusIndex = items.length - 1; break; case KeyCodes.ENTER: case KeyCodes.SPACE: event.stopPropagation(); return; default: return; //For non-matched keys, stop processing immediately. } //Update tabindex and focus event.preventDefault(); focusedItem.attr('tabindex', -1); items.eq(focusIndex).attr('tabindex', 0).focus(); }, setNavigationTemplate: function setNavigationTemplate(navTemplate, description) { var _this2 = this; var result = void 0; var animate = this.navTemplate; this.navTemplate = navTemplate; if (!animate) { this.setLabel(); this.setFooter(description); this.filterTemplates(); result = Promise.resolve(); } else { // TODO: Probably shouldn't use jquery animation anymore. Switch to CSS var duration = 300; // show some animation if we are switching to a different navigation template result = new Promise(function (resolve, reject) { try { _this2.$el.fadeOut({ complete: function complete() { _this2.setLabel(); _this2.setFooter(description); _this2.filterTemplates(); _this2.$el.fadeIn({ complete: function complete() { _this2.checkSelection(); resolve(); }, duration: duration }); }, duration: duration }); } catch (error) { reject(error); } }); } return result; }, setLabel: function setLabel() { if (!this.disableHeaderSection) { this.layoutLabel = this.stringResources.get(this.navTemplate + 'LayoutLabel'); var $header = this.$('.layoutHeader'); $header.text(this.layoutLabel); var $view = $header.parent('.layoutPickerView'); $view.attr('aria-label', this.stringResources.get('selectTemplateLabel')); } }, setFooter: function setFooter(description) { this.$('.layoutFooter').text(description); }, filterTemplates: function filterTemplates() { var posInSet = 1; var setSize = 0; _.each(this.templates, function (template) { var node = this.$('*[data-id=' + template.name + ']'); if (template.navigationTemplates && template.navigationTemplates.indexOf(this.navTemplate) === -1) { node.addClass('filtered'); node.closest('.layoutEntry').css('display', 'none').find('.layoutTemplateItem').attr('aria-posinset', null); if (node.hasClass('selected')) { node.removeClass('selected'); } } else { node.removeClass('filtered'); node.closest('.layoutEntry').css('display', '').find('.layoutTemplateItem').attr('aria-posinset', posInSet); setSize++; posInSet++; } }.bind(this)); this.$('.layoutTemplateItem').attr('aria-setsize', setSize); this.checkSelection(); }, checkSelection: function checkSelection() { if (this.$('.selected:not(.filtered)').length === 0) { var firstTemplate, template; for (var i = 0; i < this.templates.length; i++) { template = this.templates[i]; if (!template.navigationTemplates || template.navigationTemplates.indexOf(this.navTemplate) !== -1) { firstTemplate = template.name; break; } } this.selectLayout(firstTemplate); } }, getNumberOfPossibleTemplates: function getNumberOfPossibleTemplates() { var navTemplate = this.navTemplate; var count = 0; _.each(this.templates, function (template) { if (!template.navigationTemplates || template.navigationTemplates.indexOf(navTemplate) !== -1) { count++; } }); return count; }, selectLayoutNode: function selectLayoutNode(node) { var $selected = this.$('.selected'); $selected.attr('aria-checked', false).attr('tabindex', -1); $selected.removeClass('selected'); $(node).attr('aria-checked', true).attr('tabindex', 0); $(node).addClass('selected').focus(); }, onOpen: function onOpen() { var _this3 = this; this.whenReady.then(function () { _this3.$('.selected').focus(); }); }, selectLayout: function selectLayout(name) { Menu.hideOpenMenus(); _.each(this.templates, function (template) { template.isSelected = template.name === name; }.bind(this)); var selectedTemplate = this.$('.layoutTemplateItem[data-id=' + name + ']')[0]; this.selectLayoutNode(selectedTemplate); if (this.navTemplate === 'custom') { this.applyContextMenuPermissions(name, selectedTemplate); } }, /** * Asynch method that will load and return the selected page layout template */ getSelectedLayoutSpec: function getSelectedLayoutSpec() { var selected = this.$('.selected').attr('data-id'); return this.getLayoutSpecByName(selected); }, getSelectedTemplate: function getSelectedTemplate() { return this.$('.layoutTemplateItem.selected'); }, getSelectedLayoutId: function getSelectedLayoutId() { var $selectedLayoutTemplate = this.$('.selected'); if ($selectedLayoutTemplate.length > 0) { return $selectedLayoutTemplate[0].dataset.id; } return null; }, _findLayoutByName: function _findLayoutByName(name) { return _.find(this.templates, function (template) { return template.name === name; }); }, getLayoutSpecByName: function getLayoutSpecByName(layoutName) { var _this4 = this; var layout = this._findLayoutByName(layoutName); if (!layout) { // Error loading the theme. We resolve with no definition. this.displayErrorMessage(); return Promise.resolve(); } return this.getLayoutSpec(layout, function () { // Error loading the theme. We resolve with no definition. _this4.displayErrorMessage(); }); }, getLayoutSpec: function getLayoutSpec(template, errorHandler) { if (template.type === 'custom') { return Promise.resolve({ layout: template }); } return new Promise(function (resolve, reject) { try { var requireFilePath = template.type === 'js' ? '' : 'text!'; template.type = template.type ? template.type : 'json'; requireFilePath += template.path + '/' + template.name; requireFilePath += template.type === 'js' ? '' : '.' + template.type; require([requireFilePath], function (layoutFileContent) { var layout = typeof layoutFileContent === 'string' ? JSON.parse(layoutFileContent) : layoutFileContent; resolve({ layout: layout }); }, function () { if (errorHandler) { errorHandler(); } resolve(); }); } catch (error) { reject(error); } }); }, displayErrorMessage: function displayErrorMessage() { var msgBox = new MessageBox('error', this.stringResources.get('errorMessageTitle'), this.stringResources.get('errorLoadingLayoutFile')); msgBox.open(); }, generatePreviews: function generatePreviews() { var _this5 = this; var whenAllLoaded = []; _.each(this.templates, function (template) { if (template.type === 'custom') { var templateLayoutItem = _this5.$('*[data-id=' + template.name + ']').parent(); ContentFormatter.middleShortenString(templateLayoutItem.find('.layoutLocation')[0]); ContentFormatter.middleShortenString(templateLayoutItem.find('.layoutThumbnailLabel')[0]); Utils.setIcon(templateLayoutItem.find('.layoutContextMenuButton'), contextMenuIcon.default.id); Utils.setIcon(templateLayoutItem.find('.layoutThumbnailContainer'), thumbnailPlaceholderIcon.default.id); var cachedThumbnail = _this5._thumbnailCache.find(function (thumbnail) { return thumbnail.name == template.name; }); if (cachedThumbnail) { _this5._setTemplateThumbnail(template.name, cachedThumbnail.thumbnail); } else { _this5._dashboardTemplatesApi.getThumbnail(template.name).then(function (thumbnail) { _this5._thumbnailCache.push({ name: template.name, thumbnail: thumbnail }); _this5._setTemplateThumbnail(template.name, thumbnail); }); } } else { var promise = _this5.getLayoutSpec(template).then(function (_ref) { var layout = _ref.layout; var previewNode = _this5.$('*[data-id=' + template.name + ']'); if (!template.label && !template.icon) { previewNode.append(_this5.getPreview(layout)); } // set icon - webfont or svg if (template.icon) { var $templateIcon = _this5.$el.find('[data-id="' + template.name + '"]').find('.layoutIcon'); Utils.setIcon($templateIcon, template.icon); } }); whenAllLoaded.push(promise); } }); Promise.all(whenAllLoaded).then(this._whenReady.resolve.bind(this.whenReady)); }, getPreview: function getPreview(layout) { var style = ''; if (layout.style) { for (var name in layout.style) { if (layout.style.hasOwnProperty(name)) { style += name + ':' + layout.style[name] + ';'; } } } var css = layout.css || ''; css += ' ' + layout.type; var preview = '
'; if (layout.items) { for (var i = 0; i < layout.items.length; i++) { preview += this.getPreview(layout.items[i]); } } preview += '
'; return preview; }, applyContextMenuPermissions: function applyContextMenuPermissions(templateId, selectedTemplateElement) { var _this6 = this; this._dashboardTemplatesApi.getTemplate(templateId).then(function (template) { _this6._selectedCustomTemplate = template; var contextMenuPermissions = ['write', 'execute']; if (_.intersection(template.permissions, contextMenuPermissions).length) { $(selectedTemplateElement).find('.layoutContextMenuButton').addClass('isVisible'); } }); }, _setTemplateThumbnail: function _setTemplateThumbnail(id, image) { if (!id || !image) { return; } var templateItem = id && this.$('*[data-id=' + id + ']'); var thumbnailContainer = templateItem.find('.layoutThumbnailContainer'); var thumbnailImage = thumbnailContainer && thumbnailContainer.find('.layoutThumbnail'); if (thumbnailImage && thumbnailImage.length) { thumbnailImage.attr('src', 'data:image/png;base64,' + image); var thumbnailPlaceholder = thumbnailContainer.find('svg').first(); thumbnailPlaceholder && thumbnailPlaceholder.remove(); } }, onDeleteActionDone: function onDeleteActionDone(templateId) { var templateItem = templateId && this.$('*[data-id=' + templateId + ']'); templateItem && templateItem.closest('.layoutEntry').remove(); this.templates = this.templates.filter(function (template) { return template.name !== templateId; }); }, onContextMenuButtonClick: function onContextMenuButtonClick(event) { this._selectedCustomTemplate && this._showContextMenu(this._selectedCustomTemplate, event.pageX, event.pageY); }, addMoreCustomTemplates: function addMoreCustomTemplates(customTemplates) { this._addCustomTemplates(customTemplates); this.render(); } }); return LayoutPickerView; }); //# sourceMappingURL=LayoutPickerView.js.map