'use strict'; /** * Licensed Materials - Property of IBM * IBM Cognos Products: BI Cloud (C) Copyright IBM Corp. 2015, 2020 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['require', '../lib/@waca/core-client/js/core-client/ui/core/Class', '../lib/@waca/core-client/js/core-client/utils/Deferred', 'jquery', 'underscore', '../nls/StringResources'], function (require, Class, Deferred, $, _, stringResources) { /** * A helper that provides the event handlers typically used to add a widget. */ var WidgetAddUIHelper = Class.extend({ init: function init(options) { WidgetAddUIHelper.inherited('init', this, arguments); this.dashboardApi = options.dashboardApi; this.requireFn = options.requireFn || require; this.logger = this.dashboardApi.getGlassCoreSvc('.Logger'); }, fetchWidgetList: function fetchWidgetList(url) { var _this = this; return this.panelAttributes.glassContext.getCoreSvc('.Ajax').ajax({ url: url, // TODO: For some reason Safari on iOS was caching results, force off for now. This shouldn't be required. cache: false }).then(function (widgets) { return _this.fetchRequiredWidgetAttributes(widgets).then(function () { return widgets; }); }).catch(function () { var msg = stringResources.get('errorLoadingWidgetList'); return Promise.reject(msg); }); }, fetchWidgetListFromPerspective: function fetchWidgetListFromPerspective(collectionId, context) { var _this2 = this; return context.appController.findCollection(collectionId).then(function (collection) { var widgets = { list: collection ? JSON.parse(JSON.stringify(collection)) : collection }; return _this2.fetchRequiredWidgetAttributes(widgets).then(function () { return widgets; }); }).catch(function () { var msg = stringResources.get('errorLoadingWidgetList'); return Promise.reject(msg); }); }, fetchRequiredWidgetAttributes: function fetchRequiredWidgetAttributes(widgetList) { var _this3 = this; var deferredArray = []; _.each(widgetList.list, function (w) { w.options = w.options || {}; w.options.ext = _this3._hasExtensionTemplate(w); // extension templates are already localized from the perspective level if (!w.title && w.name) { w.title = w.options.ext ? w.name : stringResources.get(w.name); } if (!w.name) { w.name = w.title; } if (w.options.templatePath && !w.options.template) { deferredArray.push(_this3._loadTemplate(w)); } else if (w.options.imageLink) { deferredArray.push(_this3._loadImage(w)); } else { // ensure the deferred array maps with the widget list deferredArray.push(true); } if (w.url) { w.getEntries = _this3.fetchWidgetList.bind(_this3, w.url); } }); if (deferredArray.length) { return Promise.all(deferredArray).then(function (isLoaded) { // filter out any widgets that has failed to load widgetList.list = _.filter(widgetList.list, function (w, i) { return isLoaded[i]; }); }); } return Promise.resolve(); }, _loadImage: function _loadImage(widget) { return new Promise(function (resolve) { // eslint-disable-next-line no-undef var img = new Image(); img.onload = function () { resolve(true); }; img.onerror = function () { resolve(false); }; img.src = widget.options.imageLink; }); }, _loadTemplate: function _loadTemplate(widget) { var _this4 = this; var cdnUrl = ''; var extensionTemplate = this._hasExtensionTemplate(widget); if (!extensionTemplate) { cdnUrl = this.panelAttributes.cdnUrl || ''; } return new Promise(function (resolve) { _this4.requireFn(['text!' + cdnUrl + widget.options.templatePath], function (template) { if (extensionTemplate) { var xml = $.parseXML(template); var svgRoot = $(xml).find('svg'); if (svgRoot.length > 0) { if (typeof widget.options.viewBox === 'undefined') { // respect the viewbox defined in the svg var viewbox = svgRoot.attr('viewBox'); if (viewbox) { widget.options.viewBox = viewbox; widget.options.previewBox = widget.options.viewBox; } else { // create a viewbox based on the size var width = parseInt(svgRoot.attr('width'), 10) || 100; var height = parseInt(svgRoot.attr('height'), 10) || 100; widget.options.viewBox = '0 0 ' + width + ' ' + height; widget.options.previewBox = '-10 -10 ' + width * 1.2 + ' ' + height * 1.2; } } template = ''; var content = svgRoot.children(); _.each(content, function (node) { // eslint-disable-next-line no-undef template += new XMLSerializer().serializeToString(node); }); } } widget.options.template = template; // resolve as succeeded resolve(true); }, function (error) { _this4.logger.error('Failed to load widget', error); // resolve as failed - don't reject since we want continue with other successful widgets resolve(false); }); }); }, _hasExtensionTemplate: function _hasExtensionTemplate(widget) { if (widget && widget.options) { var ext = new RegExp('^v[0-9]+/ext/.+$'); return ext.test(widget.options.templatePath); } return false; }, _getDefaultSpec: function _getDefaultSpec(Widget, widget) { if (Widget.getDefaultSpec) { if (widget.options) { widget.options.dashboardApi = this.dashboardApi; } /** getDefaultSpec() is expected to return a promise that will be resolved with the default spec. for the widget. */ return Widget.getDefaultSpec(widget.name, widget.options); } else { var copyDefaultSpec = widget.defaultSpec ? JSON.parse(JSON.stringify(widget.defaultSpec)) : {}; return Promise.resolve(copyDefaultSpec); } }, _addFillAndBorderToAvatarIfNeeded: function _addFillAndBorderToAvatarIfNeeded(Widget, avatar, spec) { if (Widget.addFillAndBorderToAvatarIfNeeded) { Widget.addFillAndBorderToAvatarIfNeeded(avatar, spec); } }, addWidgetBySelection: function addWidgetBySelection(widget, ev, options) { var _this5 = this; options = options || {}; if (ev.gesture) { // prevent simulated click if we have a touch gesture. ev.gesture.preventDefault(); } var sWidget = widget.widget; var dndManagerFeature = this.dashboardApi.getFeature('DashboardDnd.internal'); return new Promise(function (resolve) { var api = _this5.dashboardApi.getCanvas(); var onAddDone = function onAddDone(id) { if (id) { api.selectWidget(id, { isTouch: ev.type === 'tap', options: options.selectOptions ? options.selectOptions : undefined }); } // Computers click very quickly (during functional tests). This call to // resetDragging() needs to happen *after* the call to startDrag() in // addWidgetByDrag, or else the drag started there won't be cancelled // and you can end up with a dragging widget hanging on the mouse after // clicking on a widget in a panel. dndManagerFeature.resetDragging(); resolve(id); }; // we are adding a dashboard fragment if (widget.fragment) { // add a copy of the fragment var id = api.addFragment({ model: JSON.parse(JSON.stringify(widget.fragment)) }); onAddDone(id); return; } _this5.requireFn([sWidget], function (Widget) { var id = null; if (!api.hasMaximizedWidget()) { _this5._getDefaultSpec(Widget, widget).then(function (spec) { // Remove properties piggy-backed on spec spec.model.avatarHtml = undefined; spec.model.visTypeLocked = true; //On create widget of specific type, lock that type in var content = { spec: spec.model }; if (spec.layoutProperties) { //liveWidget does not have layoutProperties in defaultSpec content.layout = spec.layoutProperties.style; } var transactionApi = _this5.dashboardApi.getFeature('Transaction'); var transactionToken = transactionApi.startTransaction(); api.addContent(content, transactionToken).then(function (content) { onAddDone(content.getId()); resolve(content.getId()); }).finally(transactionApi.endTransaction.bind(transactionApi, transactionToken)); }).catch(function (e) { _this5.logger.error(e); resolve(id); }); } else { resolve(id); } }); }); }, addWidgetByDrag: function addWidgetByDrag(widget, ev) { var _this6 = this; if (widget.fragment || widget.widget) { ev.stopPropagation(); var dndManagerFeature = this.dashboardApi.getFeature('DashboardDnd.internal'); return new Promise(function (resolve, reject) { var prepareDrag = function prepareDrag(type, dropInfo, ev, widget, spec, avatarStyle) { var avatar = $('
'); var moveX, moveY; moveX = moveY = ev.showAvatarImmediately ? 0 : 20; avatar.addClass('avatar'); avatar.addClass('widget'); // if avatarHtml is provided, it should take precedence if (spec) { if (spec.model.avatarHtml) { avatar.html(spec.model.avatarHtml); // Don't store the avatar HTML spec.model.avatarHtml = undefined; } else if (spec.model.content) { avatar.html(spec.model.content); } avatar.addClass(spec.model.type + 'Widget'); } if (widget) { _this6._addFillAndBorderToAvatarIfNeeded(widget, avatar, spec); } var style = avatarStyle || spec && spec.layoutProperties && spec.layoutProperties.style; if (style) { avatar.css(style); } // TODO: having widgetType and widgetSpec seems redundant since this information is is in the dropInfo // We need to revisit and cleanu the DnD payload var dragInfo = { event: ev, type: type, data: dropInfo, widgetSpec: spec || null, widgetType: spec && spec.model.type || null, avatar: avatar, moveXThreshold: moveX, moveYThreshold: moveY, showAvatarImmediately: ev.showAvatarImmediately || false }; return dragInfo; }; // wW are dragging a fragment // piggy back on the pin drag payload since it uses a fragment. // TODO: ideally we should make the fragment drag to be generic and not related to just pins. var fragment = widget.fragment; if (fragment) { var dropInfo = { operation: 'new', pinSpec: { contentType: 'boardFragment', content: JSON.parse(JSON.stringify(fragment)) } }; var dragInfo = prepareDrag('pin', dropInfo, ev, null, null, fragment.layout && fragment.layout.style); dndManagerFeature.startDrag(dragInfo); resolve(dragInfo); return; } _this6.requireFn([widget.widget], function (Widget) { _this6._getDefaultSpec(Widget, widget).then(function (spec) { //On create widget of specific type, lock that type in spec.model.visTypeLocked = true; var dropInfo = _.extend(spec, { operation: 'new' }); var dragInfo = prepareDrag('widget', dropInfo, ev, Widget, spec); dndManagerFeature.startDrag(dragInfo); resolve(dragInfo); }).catch(reject); }); }); } return Promise.reject(); } }); return WidgetAddUIHelper; }); //# sourceMappingURL=WidgetAddUIHelper.js.map