http://git-wip-us.apache.org/repos/asf/nifi/blob/bf3b1640/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js index be4dde8..97be460 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js @@ -15,94 +15,61 @@ * limitations under the License. */ -/* global nf, d3 */ - -$(document).ready(function () { - if (nf.Canvas.SUPPORTS_SVG) { - - //Create Angular App - var app = angular.module('ngCanvasApp', ['ngResource', 'ngRoute', 'ngMaterial', 'ngMessages']); - - //Define Dependency Injection Annotations - nf.ng.AppConfig.$inject = ['$mdThemingProvider', '$compileProvider']; - nf.ng.AppCtrl.$inject = ['$scope', 'serviceProvider', '$compile', 'headerCtrl', 'graphControlsCtrl']; - nf.ng.ServiceProvider.$inject = []; - nf.ng.BreadcrumbsCtrl.$inject = ['serviceProvider']; - nf.ng.Canvas.HeaderCtrl.$inject = ['serviceProvider', 'toolboxCtrl', 'globalMenuCtrl', 'flowStatusCtrl']; - nf.ng.Canvas.FlowStatusCtrl.$inject = ['serviceProvider']; - nf.ng.Canvas.GlobalMenuCtrl.$inject = ['serviceProvider']; - nf.ng.Canvas.ToolboxCtrl.$inject = ['processorComponent', - 'inputPortComponent', - 'outputPortComponent', - 'groupComponent', - 'remoteGroupComponent', - 'funnelComponent', - 'templateComponent', - 'labelComponent']; - nf.ng.ProcessorComponent.$inject = ['serviceProvider']; - nf.ng.InputPortComponent.$inject = ['serviceProvider']; - nf.ng.OutputPortComponent.$inject = ['serviceProvider']; - nf.ng.GroupComponent.$inject = ['serviceProvider']; - nf.ng.RemoteProcessGroupComponent.$inject = ['serviceProvider']; - nf.ng.FunnelComponent.$inject = ['serviceProvider']; - nf.ng.TemplateComponent.$inject = ['serviceProvider']; - nf.ng.LabelComponent.$inject = ['serviceProvider']; - nf.ng.Canvas.GraphControlsCtrl.$inject = ['serviceProvider', 'navigateCtrl', 'operateCtrl']; - nf.ng.Canvas.NavigateCtrl.$inject = []; - nf.ng.Canvas.OperateCtrl.$inject = []; - nf.ng.BreadcrumbsDirective.$inject = ['breadcrumbsCtrl']; - nf.ng.DraggableDirective.$inject = []; - - //Configure Angular App - app.config(nf.ng.AppConfig); - - //Define Angular App Controllers - app.controller('ngCanvasAppCtrl', nf.ng.AppCtrl); - - //Define Angular App Services - app.service('serviceProvider', nf.ng.ServiceProvider); - app.service('breadcrumbsCtrl', nf.ng.BreadcrumbsCtrl); - app.service('headerCtrl', nf.ng.Canvas.HeaderCtrl); - app.service('globalMenuCtrl', nf.ng.Canvas.GlobalMenuCtrl); - app.service('toolboxCtrl', nf.ng.Canvas.ToolboxCtrl); - app.service('flowStatusCtrl', nf.ng.Canvas.FlowStatusCtrl); - app.service('processorComponent', nf.ng.ProcessorComponent); - app.service('inputPortComponent', nf.ng.InputPortComponent); - app.service('outputPortComponent', nf.ng.OutputPortComponent); - app.service('groupComponent', nf.ng.GroupComponent); - app.service('remoteGroupComponent', nf.ng.RemoteProcessGroupComponent); - app.service('funnelComponent', nf.ng.FunnelComponent); - app.service('templateComponent', nf.ng.TemplateComponent); - app.service('labelComponent', nf.ng.LabelComponent); - app.service('graphControlsCtrl', nf.ng.Canvas.GraphControlsCtrl); - app.service('navigateCtrl', nf.ng.Canvas.NavigateCtrl); - app.service('operateCtrl', nf.ng.Canvas.OperateCtrl); - - //Define Angular App Directives - app.directive('nfBreadcrumbs', nf.ng.BreadcrumbsDirective); - app.directive('nfDraggable', nf.ng.DraggableDirective); - - //Manually Boostrap Angular App - nf.ng.Bridge.injector = angular.bootstrap($('body'), ['ngCanvasApp'], { strictDi: true }); - - // initialize the NiFi - nf.Canvas.init(); - - //initialize toolbox components tooltips - $('.component-button').qtip($.extend({}, nf.Common.config.tooltipConfig)); +/* global define, module, require, exports */ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery', + 'd3', + 'nf.Common', + 'nf.Graph', + 'nf.Shell', + 'nf.ng.Bridge', + 'nf.ClusterSummary', + 'nf.ErrorHandler', + 'nf.Storage', + 'nf.CanvasUtils', + 'nf.Birdseye', + 'nf.ContextMenu', + 'nf.Actions', + 'nf.ProcessGroup'], + function ($, d3, common, nfGraph, nfShell, angularBridge, nfClusterSummary, errorHandler, storage, canvasUtils, birdseye, contextMenu, actions, processGroup) { + return (nf.Canvas = factory($, d3, common, nfGraph, nfShell, angularBridge, nfClusterSummary, errorHandler, storage, canvasUtils, birdseye, contextMenu, actions, processGroup)); + }); + } else if (typeof exports === 'object' && typeof module === 'object') { + module.exports = (nf.Canvas = + factory(require('jquery'), + require('d3'), + require('nf.Common'), + require('nf.Graph'), + require('nf.Shell'), + require('nf.ng.Bridge'), + require('nf.ClusterSummary'), + require('nf.ErrorHandler'), + require('nf.Storage'), + require('nf.CanvasUtils'), + require('nf.Birdseye'), + require('nf.ContextMenu'), + require('nf.Actions'), + require('nf.ProcessGroup'))); } else { - $('#message-title').text('Unsupported Browser'); - $('#message-content').text('Flow graphs are shown using SVG. Please use a browser that supports rendering SVG.'); - - // show the error pane - $('#message-pane').show(); - - // hide the splash screen - nf.Canvas.hideSplash(); + nf.Canvas = factory(root.$, + root.d3, + root.nf.Common, + root.nf.Graph, + root.nf.Shell, + root.nf.ng.Bridge, + root.nf.ClusterSummary, + root.nf.ErrorHandler, + root.nf.Storage, + root.nf.CanvasUtils, + root.nf.Birdseye, + root.nf.ContextMenu, + root.nf.Actions, + root.nf.ProcessGroup); } -}); - -nf.Canvas = (function () { +}(this, function ($, d3, common, nfGraph, nfShell, angularBridge, nfClusterSummary, errorHandler, storage, canvasUtils, birdseye, contextMenu, actions, processGroup) { + 'use strict'; var SCALE = 1; var TRANSLATE = [0, 0]; @@ -131,23 +98,11 @@ nf.Canvas = (function () { controllerBulletins: '../nifi-api/flow/controller/bulletins', kerberos: '../nifi-api/access/kerberos', revision: '../nifi-api/flow/revision', - banners: '../nifi-api/flow/banners', - flowConfig: '../nifi-api/flow/config' + banners: '../nifi-api/flow/banners' } }; /** - * Starts polling. - * - * @argument {int} autoRefreshInterval The auto refresh interval - */ - var startPolling = function (autoRefreshInterval) { - // set polling flag - polling = true; - poll(autoRefreshInterval); - }; - - /** * Register the poller. * * @argument {int} autoRefreshInterval The auto refresh interval @@ -156,7 +111,7 @@ nf.Canvas = (function () { // ensure we're suppose to poll if (polling) { // reload the status - nf.Canvas.reload({ + nfCanvas.reload({ 'transition': true }).done(function () { // start the wait to poll again @@ -168,497 +123,6 @@ nf.Canvas = (function () { }; /** - * Initializes the canvas. - */ - var initCanvas = function () { - var canvasContainer = $('#canvas-container'); - - // create the canvas - svg = d3.select('#canvas-container').append('svg') - .on('contextmenu', function () { - // reset the canvas click flag - canvasClicked = false; - - // since the context menu event propagated back to the canvas, clear the selection - nf.CanvasUtils.getSelection().classed('selected', false); - - // show the context menu on the canvas - nf.ContextMenu.show(); - - // prevent default browser behavior - d3.event.preventDefault(); - }); - - // create the definitions element - var defs = svg.append('defs'); - - // create arrow definitions for the various line types - defs.selectAll('marker') - .data(['normal', 'ghost', 'unauthorized', 'full']) - .enter().append('marker') - .attr({ - 'id': function (d) { - return d; - }, - 'viewBox': '0 0 6 6', - 'refX': 5, - 'refY': 3, - 'markerWidth': 6, - 'markerHeight': 6, - 'orient': 'auto', - 'fill': function (d) { - if (d === 'ghost') { - return '#aaaaaa'; - } else if (d === 'unauthorized') { - return '#ba554a'; - } else if (d === 'full') { - return '#ba554a'; - } else { - return '#000000'; - } - } - }) - .append('path') - .attr('d', 'M2,3 L0,6 L6,3 L0,0 z'); - - // filter for drop shadow - var componentDropShadowFilter = defs.append('filter') - .attr({ - 'id': 'component-drop-shadow', - 'height': '140%', - 'y': '-20%' - }); - - // blur - componentDropShadowFilter.append('feGaussianBlur') - .attr({ - 'in': 'SourceAlpha', - 'stdDeviation': 3, - 'result': 'blur' - }); - - // offset - componentDropShadowFilter.append('feOffset') - .attr({ - 'in': 'blur', - 'dx': 0, - 'dy': 1, - 'result': 'offsetBlur' - }); - - // color/opacity - componentDropShadowFilter.append('feFlood') - .attr({ - 'flood-color': '#000000', - 'flood-opacity': 0.4, - 'result': 'offsetColor' - }); - - // combine - componentDropShadowFilter.append('feComposite') - .attr({ - 'in': 'offsetColor', - 'in2': 'offsetBlur', - 'operator': 'in', - 'result': 'offsetColorBlur' - }); - - // stack the effect under the source graph - var componentDropShadowFeMerge = componentDropShadowFilter.append('feMerge'); - componentDropShadowFeMerge.append('feMergeNode') - .attr('in', 'offsetColorBlur'); - componentDropShadowFeMerge.append('feMergeNode') - .attr('in', 'SourceGraphic'); - - // filter for drop shadow - var connectionFullDropShadowFilter = defs.append('filter') - .attr({ - 'id': 'connection-full-drop-shadow', - 'height': '140%', - 'y': '-20%' - }); - - // blur - connectionFullDropShadowFilter.append('feGaussianBlur') - .attr({ - 'in': 'SourceAlpha', - 'stdDeviation': 3, - 'result': 'blur' - }); - - // offset - connectionFullDropShadowFilter.append('feOffset') - .attr({ - 'in': 'blur', - 'dx': 0, - 'dy': 1, - 'result': 'offsetBlur' - }); - - // color/opacity - connectionFullDropShadowFilter.append('feFlood') - .attr({ - 'flood-color': '#ba554a', - 'flood-opacity': 1, - 'result': 'offsetColor' - }); - - // combine - connectionFullDropShadowFilter.append('feComposite') - .attr({ - 'in': 'offsetColor', - 'in2': 'offsetBlur', - 'operator': 'in', - 'result': 'offsetColorBlur' - }); - - // stack the effect under the source graph - var connectionFullFeMerge = connectionFullDropShadowFilter.append('feMerge'); - connectionFullFeMerge.append('feMergeNode') - .attr('in', 'offsetColorBlur'); - connectionFullFeMerge.append('feMergeNode') - .attr('in', 'SourceGraphic'); - - // create the canvas element - canvas = svg.append('g') - .attr({ - 'transform': 'translate(' + TRANSLATE + ') scale(' + SCALE + ')', - 'pointer-events': 'all', - 'id': 'canvas' - }); - - // handle canvas events - svg.on('mousedown.selection', function () { - canvasClicked = true; - - if (d3.event.button !== 0) { - // prevent further propagation (to parents and others handlers - // on the same element to prevent zoom behavior) - d3.event.stopImmediatePropagation(); - return; - } - - // show selection box if shift is held down - if (d3.event.shiftKey) { - var position = d3.mouse(canvas.node()); - canvas.append('rect') - .attr('rx', 6) - .attr('ry', 6) - .attr('x', position[0]) - .attr('y', position[1]) - .attr('class', 'selection') - .attr('width', 0) - .attr('height', 0) - .attr('stroke-width', function () { - return 1 / nf.Canvas.View.scale(); - }) - .attr('stroke-dasharray', function () { - return 4 / nf.Canvas.View.scale(); - }) - .datum(position); - - // prevent further propagation (to parents and others handlers - // on the same element to prevent zoom behavior) - d3.event.stopImmediatePropagation(); - - // prevents the browser from changing to a text selection cursor - d3.event.preventDefault(); - } - }) - .on('mousemove.selection', function () { - // update selection box if shift is held down - if (d3.event.shiftKey) { - // get the selection box - var selectionBox = d3.select('rect.selection'); - if (!selectionBox.empty()) { - // get the original position - var originalPosition = selectionBox.datum(); - var position = d3.mouse(canvas.node()); - - var d = {}; - if (originalPosition[0] < position[0]) { - d.x = originalPosition[0]; - d.width = position[0] - originalPosition[0]; - } else { - d.x = position[0]; - d.width = originalPosition[0] - position[0]; - } - - if (originalPosition[1] < position[1]) { - d.y = originalPosition[1]; - d.height = position[1] - originalPosition[1]; - } else { - d.y = position[1]; - d.height = originalPosition[1] - position[1]; - } - - // update the selection box - selectionBox.attr(d); - - // prevent further propagation (to parents) - d3.event.stopPropagation(); - } - } - }) - .on('mouseup.selection', function () { - // ensure this originated from clicking the canvas, not a component. - // when clicking on a component, the event propagation is stopped so - // it never reaches the canvas. we cannot do this however on up events - // since the drag events break down - if (canvasClicked === false) { - return; - } - - // reset the canvas click flag - canvasClicked = false; - - // get the selection box - var selectionBox = d3.select('rect.selection'); - if (!selectionBox.empty()) { - var selectionBoundingBox = { - x: parseInt(selectionBox.attr('x'), 10), - y: parseInt(selectionBox.attr('y'), 10), - width: parseInt(selectionBox.attr('width'), 10), - height: parseInt(selectionBox.attr('height'), 10) - }; - - // see if a component should be selected or not - d3.selectAll('g.component').classed('selected', function (d) { - // consider it selected if its already selected or enclosed in the bounding box - return d3.select(this).classed('selected') || - d.position.x >= selectionBoundingBox.x && (d.position.x + d.dimensions.width) <= (selectionBoundingBox.x + selectionBoundingBox.width) && - d.position.y >= selectionBoundingBox.y && (d.position.y + d.dimensions.height) <= (selectionBoundingBox.y + selectionBoundingBox.height); - }); - - // see if a connection should be selected or not - d3.selectAll('g.connection').classed('selected', function (d) { - // consider all points - var points = [d.start].concat(d.bends, [d.end]); - - // determine the bounding box - var x = d3.extent(points, function (pt) { - return pt.x; - }); - var y = d3.extent(points, function (pt) { - return pt.y; - }); - - // consider it selected if its already selected or enclosed in the bounding box - return d3.select(this).classed('selected') || - x[0] >= selectionBoundingBox.x && x[1] <= (selectionBoundingBox.x + selectionBoundingBox.width) && - y[0] >= selectionBoundingBox.y && y[1] <= (selectionBoundingBox.y + selectionBoundingBox.height); - }); - - // remove the selection box - selectionBox.remove(); - } else if (panning === false) { - // deselect as necessary if we are not panning - nf.CanvasUtils.getSelection().classed('selected', false); - } - - // inform Angular app values have changed - nf.ng.Bridge.digest(); - }); - - // define a function for update the graph dimensions - var updateGraphSize = function () { - // get the location of the bottom of the graph - var footer = $('#banner-footer'); - var bottom = 0; - if (footer.is(':visible')) { - bottom = footer.height(); - } - - // calculate size - var top = parseInt(canvasContainer.css('top'), 10); - var windowHeight = $(window).height(); - var canvasHeight = (windowHeight - (bottom + top)); - - // canvas/svg - canvasContainer.css({ - 'height': canvasHeight + 'px', - 'bottom': bottom + 'px' - }); - svg.attr({ - 'height': canvasContainer.height(), - 'width': $(window).width() - }); - - //breadcrumbs - nf.ng.Bridge.injector.get('breadcrumbsCtrl').updateBreadcrumbsCss({'bottom': bottom + 'px'}); - - // body - $('#canvas-body').css({ - 'height': windowHeight + 'px', - 'width': $(window).width() + 'px' - }); - }; - - // define a function for update the flow status dimensions - var updateFlowStatusContainerSize = function () { - $('#flow-status-container').css({ - 'width': ((($('#nifi-logo').width() + $('#component-container').width())/$(window).width())*100)*2 + '%' - }); - }; - updateFlowStatusContainerSize(); - - // listen for events to go to components - $('body').on('GoTo:Component', function (e, item) { - nf.CanvasUtils.showComponent(item.parentGroupId, item.id); - }); - - // listen for events to go to process groups - $('body').on('GoTo:ProcessGroup', function (e, item) { - nf.CanvasUtils.enterGroup(item.id).done(function () { - nf.CanvasUtils.getSelection().classed('selected', false); - - // inform Angular app that values have changed - nf.ng.Bridge.digest(); - }); - }); - - // listen for browser resize events to reset the graph size - $(window).on('resize', function (e) { - if (e.target === window) { - // close the hamburger menu if open - if($('.md-menu-backdrop').is(':visible') === true){ - $('.md-menu-backdrop').click(); - } - - updateGraphSize(); - updateFlowStatusContainerSize(); - - // resize shell when appropriate - var shell = $('#shell-dialog'); - if (shell.is(':visible')){ - setTimeout(function(shell){ - nf.Shell.resizeContent(shell); - if(shell.find('#shell-iframe').is(':visible')) { - nf.Shell.resizeIframe(shell); - } - }, 50, shell); - } - - // resize dialogs when appropriate - var dialogs = $('.dialog'); - for (var i = 0, len = dialogs.length; i < len; i++) { - if ($(dialogs[i]).is(':visible')){ - setTimeout(function(dialog){ - dialog.modal('resize'); - }, 50, $(dialogs[i])); - } - } - - // resize grids when appropriate - var gridElements = $('*[class*="slickgrid_"]'); - for (var j = 0, len = gridElements.length; j < len; j++) { - if ($(gridElements[j]).is(':visible')){ - setTimeout(function(gridElement){ - gridElement.data('gridInstance').resizeCanvas(); - }, 50, $(gridElements[j])); - } - } - - // toggle tabs .scrollable when appropriate - var tabsContainers = $('.tab-container'); - var tabsContents = []; - for (var k = 0, len = tabsContainers.length; k < len; k++) { - if ($(tabsContainers[k]).is(':visible')){ - tabsContents.push($('#' + $(tabsContainers[k]).attr('id') + '-content')); - } - } - $.each(tabsContents, function (index, tabsContent) { - nf.Common.toggleScrollable(tabsContent.get(0)); - }); - } - }).on('keydown', function (evt) { - // if a dialog is open, disable canvas shortcuts - if ($('.dialog').is(':visible') || $('#search-field').is(':focus')) { - return; - } - - // get the current selection - var selection = nf.CanvasUtils.getSelection(); - - // handle shortcuts - var isCtrl = evt.ctrlKey || evt.metaKey; - if (isCtrl) { - if (evt.keyCode === 82) { - if (allowPageRefresh === true) { - location.reload(); - return; - } - // ctrl-r - nf.Actions.reload(); - - // default prevented in nf-universal-capture.js - } else if (evt.keyCode === 65) { - // ctrl-a - nf.Actions.selectAll(); - nf.ng.Bridge.digest(); - - // only want to prevent default if the action was performed, otherwise default select all would be overridden - evt.preventDefault(); - } else if (evt.keyCode === 67) { - // ctrl-c - if (nf.Canvas.canWrite() && nf.CanvasUtils.isCopyable(selection)) { - nf.Actions.copy(selection); - } - } else if (evt.keyCode === 86) { - // ctrl-v - if (nf.Canvas.canWrite() && nf.CanvasUtils.isPastable()) { - nf.Actions.paste(selection); - - // only want to prevent default if the action was performed, otherwise default paste would be overridden - evt.preventDefault(); - } - } - } else { - if (evt.keyCode === 8 || evt.keyCode === 46) { - // backspace or delete - if (nf.Canvas.canWrite() && nf.CanvasUtils.areDeletable(selection)) { - nf.Actions['delete'](selection); - } - - // default prevented in nf-universal-capture.js - } - } - }); - - // get the banners and update the page accordingly - $.ajax({ - type: 'GET', - url: config.urls.banners, - dataType: 'json' - }).done(function (response) { - // ensure the banners response is specified - if (nf.Common.isDefinedAndNotNull(response.banners)) { - if (nf.Common.isDefinedAndNotNull(response.banners.headerText) && response.banners.headerText !== '') { - // update the header text and show it - $('#banner-header').addClass('banner-header-background').text(response.banners.headerText).show(); - $('#canvas-container').css('top', '98px'); - } - - if (nf.Common.isDefinedAndNotNull(response.banners.footerText) && response.banners.footerText !== '') { - // update the footer text and show it - var bannerFooter = $('#banner-footer').text(response.banners.footerText).show(); - - var updateBottom = function (elementId) { - var element = $('#' + elementId); - element.css('bottom', parseInt(bannerFooter.css('height'), 10) + 'px'); - }; - - // update the position of elements affected by bottom banners - updateBottom('graph'); - } - } - - // update the graph dimensions - updateGraphSize(); - }).fail(nf.ErrorHandler.handleAjaxError); - }; - - /** * Refreshes the graph. * * @argument {string} processGroupId The process group id @@ -677,46 +141,48 @@ nf.Canvas = (function () { var processGroupFlow = flowResponse.processGroupFlow; // set the group details - nf.Canvas.setGroupId(processGroupFlow.id); + nfCanvas.setGroupId(processGroupFlow.id); // get the current group name from the breadcrumb var breadcrumb = processGroupFlow.breadcrumb; if (breadcrumb.permissions.canRead) { - nf.Canvas.setGroupName(breadcrumb.breadcrumb.name); + nfCanvas.setGroupName(breadcrumb.breadcrumb.name); } else { - nf.Canvas.setGroupName(breadcrumb.id); + nfCanvas.setGroupName(breadcrumb.id); } // update the access policies permissions = flowResponse.permissions; // update the breadcrumbs - nf.ng.Bridge.injector.get('breadcrumbsCtrl').resetBreadcrumbs(); - nf.ng.Bridge.injector.get('breadcrumbsCtrl').generateBreadcrumbs(breadcrumb); - nf.ng.Bridge.injector.get('breadcrumbsCtrl').resetScrollPosition(); + angularBridge.injector.get('breadcrumbsCtrl').resetBreadcrumbs(); + // inform Angular app values have changed + angularBridge.digest(); + angularBridge.injector.get('breadcrumbsCtrl').generateBreadcrumbs(breadcrumb); + angularBridge.injector.get('breadcrumbsCtrl').resetScrollPosition(); // update the timestamp $('#stats-last-refreshed').text(processGroupFlow.lastRefreshed); // set the parent id if applicable - if (nf.Common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) { - nf.Canvas.setParentGroupId(processGroupFlow.parentGroupId); + if (common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) { + nfCanvas.setParentGroupId(processGroupFlow.parentGroupId); } else { - nf.Canvas.setParentGroupId(null); + nfCanvas.setParentGroupId(null); } // refresh the graph - nf.Graph.expireCaches(now); - nf.Graph.set(processGroupFlow.flow, $.extend({ + nfGraph.expireCaches(now); + nfGraph.set(processGroupFlow.flow, $.extend({ 'selectAll': false }, options)); // update component visibility - nf.Canvas.View.updateVisibility(); + nfCanvas.View.updateVisibility(); // update the birdseye - nf.Birdseye.refresh(); - }).fail(nf.ErrorHandler.handleAjaxError); + birdseye.refresh(); + }).fail(errorHandler.handleAjaxError); }; /** @@ -732,11 +198,11 @@ nf.Canvas = (function () { dataType: 'json' }).done(function (currentUser) { // set the current user - nf.Common.setCurrentUser(currentUser); + common.setCurrentUser(currentUser); }); }; - return { + var nfCanvas = { CANVAS_OFFSET: 0, /** @@ -768,32 +234,32 @@ nf.Canvas = (function () { /** * Reloads the flow from the server based on the currently specified group id. - * To load another group, update nf.Canvas.setGroupId, clear the canvas, and call nf.Canvas.reload. + * To load another group, update nfCanvas.setGroupId, clear the canvas, and call nfCanvas.reload. */ reload: function (options) { return $.Deferred(function (deferred) { // issue the requests - var processGroupXhr = reloadProcessGroup(nf.Canvas.getGroupId(), options); - var statusXhr = nf.ng.Bridge.injector.get('flowStatusCtrl').reloadFlowStatus(); + var processGroupXhr = reloadProcessGroup(nfCanvas.getGroupId(), options); + var statusXhr = angularBridge.injector.get('flowStatusCtrl').reloadFlowStatus(); var currentUserXhr = loadCurrentUser(); var controllerBulletins = $.ajax({ type: 'GET', url: config.urls.controllerBulletins, dataType: 'json' }).done(function (response) { - nf.ng.Bridge.injector.get('flowStatusCtrl').updateBulletins(response); + angularBridge.injector.get('flowStatusCtrl').updateBulletins(response); }); - var clusterSummary = nf.ClusterSummary.loadClusterSummary().done(function (response) { + var clusterSummary = nfClusterSummary.loadClusterSummary().done(function (response) { var clusterSummary = response.clusterSummary; // update the cluster summary - nf.ng.Bridge.injector.get('flowStatusCtrl').updateClusterSummary(clusterSummary); + angularBridge.injector.get('flowStatusCtrl').updateClusterSummary(clusterSummary); }); // wait for all requests to complete $.when(processGroupXhr, statusXhr, currentUserXhr, controllerBulletins, clusterSummary).done(function (processGroupResult) { // inform Angular app values have changed - nf.ng.Bridge.digest(); + angularBridge.digest(); // resolve the deferred deferred.resolve(processGroupResult); @@ -804,12 +270,503 @@ nf.Canvas = (function () { }, /** + * Initializes the canvas. + */ + initCanvas: function () { + var canvasContainer = $('#canvas-container'); + + // create the canvas + svg = d3.select('#canvas-container').append('svg') + .on('contextmenu', function () { + // reset the canvas click flag + canvasClicked = false; + + // since the context menu event propagated back to the canvas, clear the selection + canvasUtils.getSelection().classed('selected', false); + + // show the context menu on the canvas + contextMenu.show(); + + // prevent default browser behavior + d3.event.preventDefault(); + }); + + // create the definitions element + var defs = svg.append('defs'); + + // create arrow definitions for the various line types + defs.selectAll('marker') + .data(['normal', 'ghost', 'unauthorized', 'full']) + .enter().append('marker') + .attr({ + 'id': function (d) { + return d; + }, + 'viewBox': '0 0 6 6', + 'refX': 5, + 'refY': 3, + 'markerWidth': 6, + 'markerHeight': 6, + 'orient': 'auto', + 'fill': function (d) { + if (d === 'ghost') { + return '#aaaaaa'; + } else if (d === 'unauthorized') { + return '#ba554a'; + } else if (d === 'full') { + return '#ba554a'; + } else { + return '#000000'; + } + } + }) + .append('path') + .attr('d', 'M2,3 L0,6 L6,3 L0,0 z'); + + // filter for drop shadow + var componentDropShadowFilter = defs.append('filter') + .attr({ + 'id': 'component-drop-shadow', + 'height': '140%', + 'y': '-20%' + }); + + // blur + componentDropShadowFilter.append('feGaussianBlur') + .attr({ + 'in': 'SourceAlpha', + 'stdDeviation': 3, + 'result': 'blur' + }); + + // offset + componentDropShadowFilter.append('feOffset') + .attr({ + 'in': 'blur', + 'dx': 0, + 'dy': 1, + 'result': 'offsetBlur' + }); + + // color/opacity + componentDropShadowFilter.append('feFlood') + .attr({ + 'flood-color': '#000000', + 'flood-opacity': 0.4, + 'result': 'offsetColor' + }); + + // combine + componentDropShadowFilter.append('feComposite') + .attr({ + 'in': 'offsetColor', + 'in2': 'offsetBlur', + 'operator': 'in', + 'result': 'offsetColorBlur' + }); + + // stack the effect under the source graph + var componentDropShadowFeMerge = componentDropShadowFilter.append('feMerge'); + componentDropShadowFeMerge.append('feMergeNode') + .attr('in', 'offsetColorBlur'); + componentDropShadowFeMerge.append('feMergeNode') + .attr('in', 'SourceGraphic'); + + // filter for drop shadow + var connectionFullDropShadowFilter = defs.append('filter') + .attr({ + 'id': 'connection-full-drop-shadow', + 'height': '140%', + 'y': '-20%' + }); + + // blur + connectionFullDropShadowFilter.append('feGaussianBlur') + .attr({ + 'in': 'SourceAlpha', + 'stdDeviation': 3, + 'result': 'blur' + }); + + // offset + connectionFullDropShadowFilter.append('feOffset') + .attr({ + 'in': 'blur', + 'dx': 0, + 'dy': 1, + 'result': 'offsetBlur' + }); + + // color/opacity + connectionFullDropShadowFilter.append('feFlood') + .attr({ + 'flood-color': '#ba554a', + 'flood-opacity': 1, + 'result': 'offsetColor' + }); + + // combine + connectionFullDropShadowFilter.append('feComposite') + .attr({ + 'in': 'offsetColor', + 'in2': 'offsetBlur', + 'operator': 'in', + 'result': 'offsetColorBlur' + }); + + // stack the effect under the source graph + var connectionFullFeMerge = connectionFullDropShadowFilter.append('feMerge'); + connectionFullFeMerge.append('feMergeNode') + .attr('in', 'offsetColorBlur'); + connectionFullFeMerge.append('feMergeNode') + .attr('in', 'SourceGraphic'); + + // create the canvas element + canvas = svg.append('g') + .attr({ + 'transform': 'translate(' + TRANSLATE + ') scale(' + SCALE + ')', + 'pointer-events': 'all', + 'id': 'canvas' + }); + + // handle canvas events + svg.on('mousedown.selection', function () { + canvasClicked = true; + + if (d3.event.button !== 0) { + // prevent further propagation (to parents and others handlers + // on the same element to prevent zoom behavior) + d3.event.stopImmediatePropagation(); + return; + } + + // show selection box if shift is held down + if (d3.event.shiftKey) { + var position = d3.mouse(canvas.node()); + canvas.append('rect') + .attr('rx', 6) + .attr('ry', 6) + .attr('x', position[0]) + .attr('y', position[1]) + .attr('class', 'selection') + .attr('width', 0) + .attr('height', 0) + .attr('stroke-width', function () { + return 1 / nfCanvas.View.scale(); + }) + .attr('stroke-dasharray', function () { + return 4 / nfCanvas.View.scale(); + }) + .datum(position); + + // prevent further propagation (to parents and others handlers + // on the same element to prevent zoom behavior) + d3.event.stopImmediatePropagation(); + + // prevents the browser from changing to a text selection cursor + d3.event.preventDefault(); + } + }) + .on('mousemove.selection', function () { + // update selection box if shift is held down + if (d3.event.shiftKey) { + // get the selection box + var selectionBox = d3.select('rect.selection'); + if (!selectionBox.empty()) { + // get the original position + var originalPosition = selectionBox.datum(); + var position = d3.mouse(canvas.node()); + + var d = {}; + if (originalPosition[0] < position[0]) { + d.x = originalPosition[0]; + d.width = position[0] - originalPosition[0]; + } else { + d.x = position[0]; + d.width = originalPosition[0] - position[0]; + } + + if (originalPosition[1] < position[1]) { + d.y = originalPosition[1]; + d.height = position[1] - originalPosition[1]; + } else { + d.y = position[1]; + d.height = originalPosition[1] - position[1]; + } + + // update the selection box + selectionBox.attr(d); + + // prevent further propagation (to parents) + d3.event.stopPropagation(); + } + } + }) + .on('mouseup.selection', function () { + // ensure this originated from clicking the canvas, not a component. + // when clicking on a component, the event propagation is stopped so + // it never reaches the canvas. we cannot do this however on up events + // since the drag events break down + if (canvasClicked === false) { + return; + } + + // reset the canvas click flag + canvasClicked = false; + + // get the selection box + var selectionBox = d3.select('rect.selection'); + if (!selectionBox.empty()) { + var selectionBoundingBox = { + x: parseInt(selectionBox.attr('x'), 10), + y: parseInt(selectionBox.attr('y'), 10), + width: parseInt(selectionBox.attr('width'), 10), + height: parseInt(selectionBox.attr('height'), 10) + }; + + // see if a component should be selected or not + d3.selectAll('g.component').classed('selected', function (d) { + // consider it selected if its already selected or enclosed in the bounding box + return d3.select(this).classed('selected') || + d.position.x >= selectionBoundingBox.x && (d.position.x + d.dimensions.width) <= (selectionBoundingBox.x + selectionBoundingBox.width) && + d.position.y >= selectionBoundingBox.y && (d.position.y + d.dimensions.height) <= (selectionBoundingBox.y + selectionBoundingBox.height); + }); + + // see if a connection should be selected or not + d3.selectAll('g.connection').classed('selected', function (d) { + // consider all points + var points = [d.start].concat(d.bends, [d.end]); + + // determine the bounding box + var x = d3.extent(points, function (pt) { + return pt.x; + }); + var y = d3.extent(points, function (pt) { + return pt.y; + }); + + // consider it selected if its already selected or enclosed in the bounding box + return d3.select(this).classed('selected') || + x[0] >= selectionBoundingBox.x && x[1] <= (selectionBoundingBox.x + selectionBoundingBox.width) && + y[0] >= selectionBoundingBox.y && y[1] <= (selectionBoundingBox.y + selectionBoundingBox.height); + }); + + // remove the selection box + selectionBox.remove(); + } else if (panning === false) { + // deselect as necessary if we are not panning + canvasUtils.getSelection().classed('selected', false); + } + + // inform Angular app values have changed + angularBridge.digest(); + }); + + // define a function for update the graph dimensions + var updateGraphSize = function () { + // get the location of the bottom of the graph + var footer = $('#banner-footer'); + var bottom = 0; + if (footer.is(':visible')) { + bottom = footer.height(); + } + + // calculate size + var top = parseInt(canvasContainer.css('top'), 10); + var windowHeight = $(window).height(); + var canvasHeight = (windowHeight - (bottom + top)); + + // canvas/svg + canvasContainer.css({ + 'height': canvasHeight + 'px', + 'bottom': bottom + 'px' + }); + svg.attr({ + 'height': canvasContainer.height(), + 'width': $(window).width() + }); + + //breadcrumbs + angularBridge.injector.get('breadcrumbsCtrl').updateBreadcrumbsCss({'bottom': bottom + 'px'}); + + // body + $('#canvas-body').css({ + 'height': windowHeight + 'px', + 'width': $(window).width() + 'px' + }); + }; + + // define a function for update the flow status dimensions + var updateFlowStatusContainerSize = function () { + $('#flow-status-container').css({ + 'width': ((($('#nifi-logo').width() + $('#component-container').width())/$(window).width())*100)*2 + '%' + }); + }; + updateFlowStatusContainerSize(); + + // listen for events to go to components + $('body').on('GoTo:Component', function (e, item) { + canvasUtils.showComponent(item.parentGroupId, item.id); + }); + + // listen for events to go to process groups + $('body').on('GoTo:ProcessGroup', function (e, item) { + processGroup.enterGroup(item.id).done(function () { + canvasUtils.getSelection().classed('selected', false); + + // inform Angular app that values have changed + angularBridge.digest(); + }); + }); + + // listen for browser resize events to reset the graph size + $(window).on('resize', function (e) { + if (e.target === window) { + // close the hamburger menu if open + if($('.md-menu-backdrop').is(':visible') === true){ + $('.md-menu-backdrop').click(); + } + + updateGraphSize(); + updateFlowStatusContainerSize(); + + // resize shell when appropriate + var shell = $('#shell-dialog'); + if (shell.is(':visible')){ + setTimeout(function(shell){ + nfShell.resizeContent(shell); + if(shell.find('#shell-iframe').is(':visible')) { + nfShell.resizeIframe(shell); + } + }, 50, shell); + } + + // resize dialogs when appropriate + var dialogs = $('.dialog'); + for (var i = 0, len = dialogs.length; i < len; i++) { + if ($(dialogs[i]).is(':visible')){ + setTimeout(function(dialog){ + dialog.modal('resize'); + }, 50, $(dialogs[i])); + } + } + + // resize grids when appropriate + var gridElements = $('*[class*="slickgrid_"]'); + for (var j = 0, len = gridElements.length; j < len; j++) { + if ($(gridElements[j]).is(':visible')){ + setTimeout(function(gridElement){ + gridElement.data('gridInstance').resizeCanvas(); + }, 50, $(gridElements[j])); + } + } + + // toggle tabs .scrollable when appropriate + var tabsContainers = $('.tab-container'); + var tabsContents = []; + for (var k = 0, len = tabsContainers.length; k < len; k++) { + if ($(tabsContainers[k]).is(':visible')){ + tabsContents.push($('#' + $(tabsContainers[k]).attr('id') + '-content')); + } + } + $.each(tabsContents, function (index, tabsContent) { + common.toggleScrollable(tabsContent.get(0)); + }); + } + }).on('keydown', function (evt) { + // if a dialog is open, disable canvas shortcuts + if ($('.dialog').is(':visible') || $('#search-field').is(':focus')) { + return; + } + + // get the current selection + var selection = canvasUtils.getSelection(); + + // handle shortcuts + var isCtrl = evt.ctrlKey || evt.metaKey; + if (isCtrl) { + if (evt.keyCode === 82) { + if (allowPageRefresh === true) { + location.reload(); + return; + } + // ctrl-r + actions.reload(); + + // default prevented in nf-universal-capture.js + } else if (evt.keyCode === 65) { + // ctrl-a + actions.selectAll(); + angularBridge.digest(); + + // only want to prevent default if the action was performed, otherwise default select all would be overridden + evt.preventDefault(); + } else if (evt.keyCode === 67) { + // ctrl-c + if (nfCanvas.canWrite() && canvasUtils.isCopyable(selection)) { + actions.copy(selection); + } + } else if (evt.keyCode === 86) { + // ctrl-v + if (nfCanvas.canWrite() && canvasUtils.isPastable()) { + actions.paste(selection); + + // only want to prevent default if the action was performed, otherwise default paste would be overridden + evt.preventDefault(); + } + } + } else { + if (evt.keyCode === 8 || evt.keyCode === 46) { + // backspace or delete + if (nfCanvas.canWrite() && canvasUtils.areDeletable(selection)) { + actions['delete'](selection); + } + + // default prevented in nf-universal-capture.js + } + } + }); + + // get the banners and update the page accordingly + $.ajax({ + type: 'GET', + url: config.urls.banners, + dataType: 'json' + }).done(function (response) { + // ensure the banners response is specified + if (common.isDefinedAndNotNull(response.banners)) { + if (common.isDefinedAndNotNull(response.banners.headerText) && response.banners.headerText !== '') { + // update the header text and show it + $('#banner-header').addClass('banner-header-background').text(response.banners.headerText).show(); + $('#canvas-container').css('top', '98px'); + } + + if (common.isDefinedAndNotNull(response.banners.footerText) && response.banners.footerText !== '') { + // update the footer text and show it + var bannerFooter = $('#banner-footer').text(response.banners.footerText).show(); + + var updateBottom = function (elementId) { + var element = $('#' + elementId); + element.css('bottom', parseInt(bannerFooter.css('height'), 10) + 'px'); + }; + + // update the position of elements affected by bottom banners + updateBottom('graph'); + } + } + + // update the graph dimensions + updateGraphSize(); + }).fail(errorHandler.handleAjaxError); + }, + + /** * Initialize NiFi. */ init: function () { // attempt kerberos authentication var ticketExchange = $.Deferred(function (deferred) { - if (nf.Storage.hasItem('jwt')) { + if (storage.hasItem('jwt')) { deferred.resolve(); } else { $.ajax({ @@ -818,9 +775,9 @@ nf.Canvas = (function () { dataType: 'text' }).done(function (jwt) { // get the payload and store the token with the appropriate expiration - var token = nf.Common.getJwtPayload(jwt); - var expiration = parseInt(token['exp'], 10) * nf.Common.MILLIS_PER_SECOND; - nf.Storage.setItem('jwt', jwt, expiration); + var token = common.getJwtPayload(jwt); + var expiration = parseInt(token['exp'], 10) * common.MILLIS_PER_SECOND; + storage.setItem('jwt', jwt, expiration); deferred.resolve(); }).fail(function () { deferred.reject(); @@ -829,7 +786,7 @@ nf.Canvas = (function () { }).promise(); // load the current user - var userXhr = $.Deferred(function (deferred) { + return $.Deferred(function (deferred) { ticketExchange.always(function () { loadCurrentUser().done(function (currentUser) { // if the user is logged, we want to determine if they were logged in using a certificate @@ -838,12 +795,12 @@ nf.Canvas = (function () { $('#current-user').text(currentUser.identity).show(); // render the logout button if there is a token locally - if (nf.Storage.getItem('jwt') !== null) { + if (storage.getItem('jwt') !== null) { $('#logout-link-container').show(); } } else { // set the anonymous user label - nf.Common.setAnonymousUserLabel(); + common.setAnonymousUserLabel(); } deferred.resolve(); }).fail(function (xhr, status, error) { @@ -856,96 +813,6 @@ nf.Canvas = (function () { }); }); }).promise(); - - userXhr.done(function () { - // load the client id - var clientXhr = nf.Client.init(); - - // get the controller config to register the status poller - var configXhr = $.ajax({ - type: 'GET', - url: config.urls.flowConfig, - dataType: 'json' - }); - - // ensure the config requests are loaded - $.when(configXhr, nf.ClusterSummary.loadClusterSummary(), userXhr, clientXhr).done(function (configResult) { - var configResponse = configResult[0]; - - // calculate the canvas offset - var canvasContainer = $('#canvas-container'); - nf.Canvas.CANVAS_OFFSET = canvasContainer.offset().top; - - // get the config details - var configDetails = configResponse.flowConfiguration; - - // show disconnected message on load if necessary - if (nf.ClusterSummary.isClustered() && !nf.ClusterSummary.isConnectedToCluster()) { - nf.Dialog.showDisconnectedFromClusterMessage(); - } - - // get the auto refresh interval - var autoRefreshIntervalSeconds = parseInt(configDetails.autoRefreshIntervalSeconds, 10); - - // record whether we can configure the authorizer - configurableAuthorizer = configDetails.supportsConfigurableAuthorizer; - - // init storage - nf.Storage.init(); - - // initialize the application - initCanvas(); - nf.Canvas.View.init(); - nf.ContextMenu.init(); - nf.ng.Bridge.injector.get('headerCtrl').init(); - nf.Settings.init(); - nf.Actions.init(); - nf.QueueListing.init(); - nf.ComponentState.init(); - - // initialize the component behaviors - nf.Draggable.init(); - nf.Selectable.init(); - nf.Connectable.init(); - - // initialize the chart - nf.StatusHistory.init(configDetails.timeOffset); - - // initialize the birdseye - nf.Birdseye.init(); - - // initialize components - nf.ConnectionConfiguration.init(); - nf.ControllerService.init(); - nf.ReportingTask.init(); - nf.PolicyManagement.init(); - nf.ProcessorConfiguration.init(); - nf.ProcessGroupConfiguration.init(); - nf.RemoteProcessGroupConfiguration.init(); - nf.RemoteProcessGroupPorts.init(); - nf.PortConfiguration.init(); - nf.LabelConfiguration.init(); - nf.ProcessorDetails.init(true); - nf.PortDetails.init(); - nf.ConnectionDetails.init(); - nf.RemoteProcessGroupDetails.init(); - nf.GoTo.init(); - nf.Graph.init().done(function () { - nf.ng.Bridge.injector.get('graphControlsCtrl').init(); - - // determine the split between the polling - var pollingSplit = autoRefreshIntervalSeconds / 2; - - // register the polling - setTimeout(function () { - startPolling(autoRefreshIntervalSeconds); - }, pollingSplit * 1000); - - // hide the splash screen - nf.Canvas.hideSplash(); - }).fail(nf.ErrorHandler.handleAjaxError); - }).fail(nf.ErrorHandler.handleAjaxError); - }).fail(nf.ErrorHandler.handleAjaxError); }, /** @@ -997,6 +864,15 @@ nf.Canvas = (function () { }, /** + * Set whether the authorizer is configurable. + * + * @param bool The boolean value representing whether the authorizer is configurable. + */ + setConfigurableAuthorizer: function(bool){ + configurableAuthorizer = bool; + }, + + /** * Returns whether the authorizer is configurable. */ isConfigurableAuthorizer: function () { @@ -1004,7 +880,7 @@ nf.Canvas = (function () { }, /** - * Whether the current user can write in this group. + * Whether the current user can read from this group. * * @returns {boolean} can write */ @@ -1029,6 +905,17 @@ nf.Canvas = (function () { } }, + /** + * Starts polling. + * + * @argument {int} autoRefreshInterval The auto refresh interval + */ + startPolling: function (autoRefreshInterval) { + // set polling flag + polling = true; + poll(autoRefreshInterval); + }, + View: (function () { /** @@ -1036,8 +923,8 @@ nf.Canvas = (function () { */ var updateComponentVisibility = function () { var canvasContainer = $('#canvas-container'); - var translate = nf.Canvas.View.translate(); - var scale = nf.Canvas.View.scale(); + var translate = nfCanvas.View.translate(); + var scale = nfCanvas.View.scale(); // scale the translation translate = [translate[0] / scale, translate[1] / scale]; @@ -1054,7 +941,7 @@ nf.Canvas = (function () { // detects whether a component is visible and should be rendered var isComponentVisible = function (d) { - if (!nf.Canvas.View.shouldRenderPerScale()) { + if (!nfCanvas.View.shouldRenderPerScale()) { return false; } @@ -1069,7 +956,7 @@ nf.Canvas = (function () { // detects whether a connection is visible and should be rendered var isConnectionVisible = function (d) { - if (!nf.Canvas.View.shouldRenderPerScale()) { + if (!nfCanvas.View.shouldRenderPerScale()) { return false; } @@ -1102,7 +989,7 @@ nf.Canvas = (function () { }; // get the all components - var graph = nf.Graph.get(); + var graph = nfGraph.get(); // update the visibility for each component $.each(graph.processors, function (_, d) { @@ -1137,7 +1024,7 @@ nf.Canvas = (function () { .scale(SCALE) .on('zoomstart', function () { // hide the context menu - nf.ContextMenu.hide(); + contextMenu.hide(); }) .on('zoom', function () { // if we have zoomed, indicate that we are panning @@ -1154,7 +1041,7 @@ nf.Canvas = (function () { var transition = d3.event.sourceEvent.type === 'wheel' || d3.event.sourceEvent.type === 'mousewheel'; // refresh the canvas - refreshed = nf.Canvas.View.refresh({ + refreshed = nfCanvas.View.refresh({ persist: false, transition: transition, refreshComponents: false, @@ -1163,16 +1050,16 @@ nf.Canvas = (function () { }) .on('zoomend', function () { // ensure the canvas was actually refreshed - if (nf.Common.isDefinedAndNotNull(refreshed)) { - nf.Canvas.View.updateVisibility(); + if (common.isDefinedAndNotNull(refreshed)) { + nfCanvas.View.updateVisibility(); // refresh the birdseye refreshed.done(function () { - nf.Birdseye.refresh(); + birdseye.refresh(); }); // persist the users view - nf.CanvasUtils.persistUserView(); + canvasUtils.persistUserView(); // reset the refreshed deferred refreshed = null; @@ -1192,7 +1079,7 @@ nf.Canvas = (function () { * @returns {Boolean} */ shouldRenderPerScale: function () { - return nf.Canvas.View.scale() >= MIN_SCALE_TO_RENDER; + return nfCanvas.View.scale() >= MIN_SCALE_TO_RENDER; }, /** @@ -1200,7 +1087,7 @@ nf.Canvas = (function () { */ updateVisibility: function () { updateComponentVisibility(); - nf.Graph.pan(); + nfGraph.pan(); }, /** @@ -1209,7 +1096,7 @@ nf.Canvas = (function () { * @param {array} translate [x, y] */ translate: function (translate) { - if (nf.Common.isUndefined(translate)) { + if (common.isUndefined(translate)) { return behavior.translate(); } else { behavior.translate(translate); @@ -1222,7 +1109,7 @@ nf.Canvas = (function () { * @param {number} scale The new scale */ scale: function (scale) { - if (nf.Common.isUndefined(scale)) { + if (common.isUndefined(scale)) { return behavior.scale(); } else { behavior.scale(scale); @@ -1233,8 +1120,8 @@ nf.Canvas = (function () { * Zooms in a single zoom increment. */ zoomIn: function () { - var translate = nf.Canvas.View.translate(); - var scale = nf.Canvas.View.scale(); + var translate = nfCanvas.View.translate(); + var scale = nfCanvas.View.scale(); var newScale = Math.min(scale * INCREMENT, MAX_SCALE); // get the canvas normalized width and height @@ -1243,10 +1130,10 @@ nf.Canvas = (function () { var screenHeight = canvasContainer.height() / scale; // adjust the scale - nf.Canvas.View.scale(newScale); + nfCanvas.View.scale(newScale); // center around the center of the screen accounting for the translation accordingly - nf.CanvasUtils.centerBoundingBox({ + canvasUtils.centerBoundingBox({ x: (screenWidth / 2) - (translate[0] / scale), y: (screenHeight / 2) - (translate[1] / scale), width: 1, @@ -1258,8 +1145,8 @@ nf.Canvas = (function () { * Zooms out a single zoom increment. */ zoomOut: function () { - var translate = nf.Canvas.View.translate(); - var scale = nf.Canvas.View.scale(); + var translate = nfCanvas.View.translate(); + var scale = nfCanvas.View.scale(); var newScale = Math.max(scale / INCREMENT, MIN_SCALE); // get the canvas normalized width and height @@ -1268,10 +1155,10 @@ nf.Canvas = (function () { var screenHeight = canvasContainer.height() / scale; // adjust the scale - nf.Canvas.View.scale(newScale); + nfCanvas.View.scale(newScale); // center around the center of the screen accounting for the translation accordingly - nf.CanvasUtils.centerBoundingBox({ + canvasUtils.centerBoundingBox({ x: (screenWidth / 2) - (translate[0] / scale), y: (screenHeight / 2) - (translate[1] / scale), width: 1, @@ -1283,8 +1170,8 @@ nf.Canvas = (function () { * Zooms to fit the entire graph on the canvas. */ fit: function () { - var translate = nf.Canvas.View.translate(); - var scale = nf.Canvas.View.scale(); + var translate = nfCanvas.View.translate(); + var scale = nfCanvas.View.scale(); var newScale; // get the canvas normalized width and height @@ -1297,7 +1184,7 @@ nf.Canvas = (function () { var graphWidth = graphBox.width / scale; var graphHeight = graphBox.height / scale; var graphLeft = graphBox.left / scale; - var graphTop = (graphBox.top - nf.Canvas.CANVAS_OFFSET) / scale; + var graphTop = (graphBox.top - nfCanvas.CANVAS_OFFSET) / scale; // adjust the scale to ensure the entire graph is visible @@ -1315,10 +1202,10 @@ nf.Canvas = (function () { } // set the new scale - nf.Canvas.View.scale(newScale); + nfCanvas.View.scale(newScale); // center as appropriate - nf.CanvasUtils.centerBoundingBox({ + canvasUtils.centerBoundingBox({ x: graphLeft - (translate[0] / scale), y: graphTop - (translate[1] / scale), width: canvasWidth / newScale, @@ -1330,14 +1217,14 @@ nf.Canvas = (function () { * Zooms to the actual size (1 to 1). */ actualSize: function () { - var translate = nf.Canvas.View.translate(); - var scale = nf.Canvas.View.scale(); + var translate = nfCanvas.View.translate(); + var scale = nfCanvas.View.scale(); // get the first selected component - var selection = nf.CanvasUtils.getSelection(); + var selection = canvasUtils.getSelection(); // set the updated scale - nf.Canvas.View.scale(1); + nfCanvas.View.scale(1); // box to zoom towards var box; @@ -1350,7 +1237,7 @@ nf.Canvas = (function () { // get the bounding box for the selected components box = { x: (selectionBox.left / scale) - (translate[0] / scale), - y: ((selectionBox.top - nf.Canvas.CANVAS_OFFSET) / scale) - (translate[1] / scale), + y: ((selectionBox.top - nfCanvas.CANVAS_OFFSET) / scale) - (translate[1] / scale), width: selectionBox.width / scale, height: selectionBox.height / scale }; @@ -1372,7 +1259,7 @@ nf.Canvas = (function () { } // center as appropriate - nf.CanvasUtils.centerBoundingBox(box); + canvasUtils.centerBoundingBox(box); }, /** @@ -1389,21 +1276,21 @@ nf.Canvas = (function () { var refreshBirdseye = true; // extract the options if specified - if (nf.Common.isDefinedAndNotNull(options)) { - persist = nf.Common.isDefinedAndNotNull(options.persist) ? options.persist : persist; - transition = nf.Common.isDefinedAndNotNull(options.transition) ? options.transition : transition; - refreshComponents = nf.Common.isDefinedAndNotNull(options.refreshComponents) ? options.refreshComponents : refreshComponents; - refreshBirdseye = nf.Common.isDefinedAndNotNull(options.refreshBirdseye) ? options.refreshBirdseye : refreshBirdseye; + if (common.isDefinedAndNotNull(options)) { + persist = common.isDefinedAndNotNull(options.persist) ? options.persist : persist; + transition = common.isDefinedAndNotNull(options.transition) ? options.transition : transition; + refreshComponents = common.isDefinedAndNotNull(options.refreshComponents) ? options.refreshComponents : refreshComponents; + refreshBirdseye = common.isDefinedAndNotNull(options.refreshBirdseye) ? options.refreshBirdseye : refreshBirdseye; } // update component visibility if (refreshComponents) { - nf.Canvas.View.updateVisibility(); + nfCanvas.View.updateVisibility(); } // persist if appropriate if (persist === true) { - nf.CanvasUtils.persistUserView(); + canvasUtils.persistUserView(); } // update the canvas @@ -1416,7 +1303,7 @@ nf.Canvas = (function () { .each('end', function () { // refresh birdseye if appropriate if (refreshBirdseye === true) { - nf.Birdseye.refresh(); + birdseye.refresh(); } deferred.resolve(); @@ -1428,7 +1315,7 @@ nf.Canvas = (function () { // refresh birdseye if appropriate if (refreshBirdseye === true) { - nf.Birdseye.refresh(); + birdseye.refresh(); } deferred.resolve(); @@ -1438,4 +1325,6 @@ nf.Canvas = (function () { }; }()) }; -}()); \ No newline at end of file + + return nfCanvas; +})); \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/nifi/blob/bf3b1640/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-clipboard.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-clipboard.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-clipboard.js index ce0ea1d..d5dd80c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-clipboard.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-clipboard.js @@ -15,12 +15,28 @@ * limitations under the License. */ -/* global nf */ +/* global define, module, require, exports */ /** * Clipboard used for copying and pasting content. */ -nf.Clipboard = (function () { +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery', + 'nf.Common'], + function ($, common) { + return (nf.Clipboard = factory($, common)); + }); + } else if (typeof exports === 'object' && typeof module === 'object') { + module.exports = (nf.Clipboard = + factory(require('jquery'), + require('nf.Common'))); + } else { + nf.Clipboard = factory(root.$, + root.nf.Common); + } +}(this, function ($, common) { + 'use strict'; var COPY = 'copy'; var PASTE = 'paste'; @@ -30,28 +46,28 @@ nf.Clipboard = (function () { return { /** * Add a listener to receive copy and paste events. - * + * * @argument {object} listener A clipboard listener * @argument {function} funct Callback when clipboard events occur */ addListener: function (listener, funct) { listeners[listener] = funct; }, - + /** * Remove the specified listener. - * + * * @argument {object} listener A clipboard listener */ removeListener: function (listener) { - if (nf.Common.isDefinedAndNotNull(listeners[listener])) { + if (common.isDefinedAndNotNull(listeners[listener])) { delete listeners[listener]; } }, - + /** * Copy the specified data. - * + * * @argument {object} d The data to copy to the clipboard */ copy: function (d) { @@ -62,14 +78,14 @@ nf.Clipboard = (function () { listeners[listener].call(listener, COPY, data); } }, - + /** * Checks to see if any data has been copied. */ isCopied: function () { - return nf.Common.isDefinedAndNotNull(data); + return common.isDefinedAndNotNull(data); }, - + /** * Gets the most recent data thats copied. This operation * will remove the corresponding data from the clipboard. @@ -77,7 +93,7 @@ nf.Clipboard = (function () { paste: function () { return $.Deferred(function (deferred) { // ensure there was data - if (nf.Common.isDefinedAndNotNull(data)) { + if (common.isDefinedAndNotNull(data)) { var clipboardData = data; // resolve the deferred @@ -96,4 +112,4 @@ nf.Clipboard = (function () { }).promise(); } }; -}()); \ No newline at end of file +})); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/bf3b1640/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-state.js ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-state.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-state.js index 0d5c198..e362b46 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-state.js +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-component-state.js @@ -15,12 +15,40 @@ * limitations under the License. */ -/* global nf */ +/* global define, module, require, exports */ /** * Views state for a given component. */ -nf.ComponentState = (function () { +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(['jquery', + 'Slick', + 'nf.ClusterSummary', + 'nf.ErrorHandler', + 'nf.Dialog', + 'nf.Common'], + function ($, Slick, clusterSummary, errorHandler, dialog, common) { + return (nf.ComponentState = factory($, Slick, clusterSummary, errorHandler, dialog, common)); + }); + } else if (typeof exports === 'object' && typeof module === 'object') { + module.exports = (nf.ComponentState = + factory(require('jquery'), + require('Slick'), + require('nf.ClusterSummary'), + require('nf.ErrorHandler'), + require('nf.Dialog'), + require('nf.Common'))); + } else { + nf.ComponentState = factory(root.$, + root.Slick, + root.nf.ClusterSummary, + root.nf.ErrorHandler, + root.nf.Dialog, + root.nf.Common); + } +}(this, function ($, Slick, clusterSummary, errorHandler, dialog, common) { + 'use strict'; /** * Filters the component state table. @@ -30,7 +58,7 @@ nf.ComponentState = (function () { var componentStateTable = $('#component-state-table').data('gridInstance'); // ensure the grid has been initialized - if (nf.Common.isDefinedAndNotNull(componentStateTable)) { + if (common.isDefinedAndNotNull(componentStateTable)) { var componentStateData = componentStateTable.getData(); // update the search criteria @@ -67,7 +95,7 @@ nf.ComponentState = (function () { // conditionally consider the scope var matchesScope = false; - if (nf.Common.isDefinedAndNotNull(item['scope'])) { + if (common.isDefinedAndNotNull(item['scope'])) { matchesScope = item['scope'].search(filterExp) >= 0; } @@ -83,8 +111,8 @@ nf.ComponentState = (function () { var sort = function (sortDetails, data) { // defines a function for sorting var comparer = function (a, b) { - var aString = nf.Common.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : ''; - var bString = nf.Common.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : ''; + var aString = common.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : ''; + var bString = common.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : ''; return aString === bString ? 0 : aString > bString ? 1 : -1; }; @@ -134,7 +162,7 @@ nf.ComponentState = (function () { componentStateData.beginUpdate(); // local state - if (nf.Common.isDefinedAndNotNull(localState)) { + if (common.isDefinedAndNotNull(localState)) { $.each(localState.state, function (i, stateEntry) { componentStateData.addItem($.extend({ id: count++, @@ -143,12 +171,12 @@ nf.ComponentState = (function () { }); totalEntries += localState.totalEntryCount; - if (nf.Common.isDefinedAndNotNull(localState.state) && localState.totalEntryCount !== localState.state.length) { + if (common.isDefinedAndNotNull(localState.state) && localState.totalEntryCount !== localState.state.length) { showPartialDetails = true; } } - if (nf.Common.isDefinedAndNotNull(clusterState)) { + if (common.isDefinedAndNotNull(clusterState)) { $.each(clusterState.state, function (i, stateEntry) { componentStateData.addItem($.extend({ id: count++, @@ -157,7 +185,7 @@ nf.ComponentState = (function () { }); totalEntries += clusterState.totalEntryCount; - if (nf.Common.isDefinedAndNotNull(clusterState.state) && clusterState.totalEntryCount !== clusterState.state.length) { + if (common.isDefinedAndNotNull(clusterState.state) && clusterState.totalEntryCount !== clusterState.state.length) { showPartialDetails = true; } } @@ -171,7 +199,7 @@ nf.ComponentState = (function () { } // update the total number of state entries - $('#total-component-state-entries').text(nf.Common.formatInteger(totalEntries)); + $('#total-component-state-entries').text(common.formatInteger(totalEntries)); }; /** @@ -253,9 +281,9 @@ nf.ComponentState = (function () { // reload the table with no state loadComponentState() - }).fail(nf.ErrorHandler.handleAjaxError); + }).fail(errorHandler.handleAjaxError); } else { - nf.Dialog.showOkDialog({ + dialog.showOkDialog({ headerText: 'Component State', dialogContent: 'This component has no state to clear.' }); @@ -282,7 +310,7 @@ nf.ComponentState = (function () { ]; // conditionally show the cluster node identifier - if (nf.ClusterSummary.isClustered()) { + if (clusterSummary.isClustered()) { componentStateColumns.push({ id: 'scope', field: 'scope', @@ -390,7 +418,7 @@ nf.ComponentState = (function () { // reset the grid size var componentStateGrid = componentStateTable.data('gridInstance'); componentStateGrid.resizeCanvas(); - }).fail(nf.ErrorHandler.handleAjaxError); + }).fail(errorHandler.handleAjaxError); } }; -}()); \ No newline at end of file +})); \ No newline at end of file