/* * Activiti Modeler component part of the Activiti project * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 'use strict'; var activitiModeler = angular.module('activitiModeler', [ 'ngCookies', 'ngResource', 'ngSanitize', 'ngRoute', 'ngDragDrop', 'mgcrea.ngStrap', 'ngGrid', 'ngAnimate', 'pascalprecht.translate', 'duScroll' ]); var activitiModule = activitiModeler; activitiModeler // Initialize routes .config(['$selectProvider', '$translateProvider', function ($selectProvider, $translateProvider) { // Override caret for bs-select directive angular.extend($selectProvider.defaults, { caretHtml: ' ' }); // Initialize angular-translate $translateProvider.useStaticFilesLoader({ prefix: './editor-app/i18n/', suffix: '.json' }); $translateProvider.preferredLanguage('en'); // remember language $translateProvider.useCookieStorage(); }]) .run(['$rootScope', '$timeout', '$modal', '$translate', '$location', '$window', '$http', '$q', function($rootScope, $timeout, $modal, $translate, $location, $window, $http, $q) { $rootScope.config = ACTIVITI.CONFIG; $rootScope.editorInitialized = false; $rootScope.editorFactory = $q.defer(); $rootScope.forceSelectionRefresh = false; $rootScope.ignoreChanges = false; // by default never ignore changes $rootScope.validationErrors = []; $rootScope.staticIncludeVersion = Date.now(); /** * A 'safer' apply that avoids concurrent updates (which $apply allows). */ $rootScope.safeApply = function(fn) { var phase = this.$root.$$phase; if(phase == '$apply' || phase == '$digest') { if(fn && (typeof(fn) === 'function')) { fn(); } } else { this.$apply(fn); } }; /** * Initialize the event bus: couple all Oryx events with a dispatch of the * event of the event bus. This way, it gets much easier to attach custom logic * to any event. */ /* Helper method to fetch model from server (always needed) */ function fetchModel(modelId) { var modelUrl = KISBPM.URL.getModel(modelId); $http({method: 'GET', url: modelUrl}). success(function (data, status, headers, config) { $rootScope.editor = new ORYX.Editor(data); $rootScope.modelData = angular.fromJson(data); $rootScope.editorFactory.resolve(); }). error(function (data, status, headers, config) { console.log('Error loading model with id ' + modelId + ' ' + data); }); } function initScrollHandling() { var canvasSection = jQuery('#canvasSection'); canvasSection.scroll(function() { // Hides the resizer and quick menu items during scrolling var selectedElements = $rootScope.editor.selection; var subSelectionElements = $rootScope.editor._subSelection; $rootScope.selectedElements = selectedElements; $rootScope.subSelectionElements = subSelectionElements; if (selectedElements && selectedElements.length > 0) { $rootScope.selectedElementBeforeScrolling = selectedElements[0]; } jQuery('.Oryx_button').each(function(i, obj) { $rootScope.orginalOryxButtonStyle = obj.style.display; obj.style.display = 'none'; }); jQuery('.resizer_southeast').each(function(i, obj) { $rootScope.orginalResizerSEStyle = obj.style.display; obj.style.display = 'none'; }); jQuery('.resizer_northwest').each(function(i, obj) { $rootScope.orginalResizerNWStyle = obj.style.display; obj.style.display = 'none'; }); $rootScope.editor.handleEvents({type:ORYX.CONFIG.EVENT_CANVAS_SCROLL}); }); canvasSection.scrollStopped(function(){ // Puts the quick menu items and resizer back when scroll is stopped. $rootScope.editor.setSelection([]); // needed cause it checks for element changes and does nothing if the elements are the same $rootScope.editor.setSelection($rootScope.selectedElements, $rootScope.subSelectionElements); $rootScope.selectedElements = undefined; $rootScope.subSelectionElements = undefined; function handleDisplayProperty(obj) { if (jQuery(obj).position().top > 0) { obj.style.display = 'block'; } else { obj.style.display = 'none'; } } jQuery('.Oryx_button').each(function(i, obj) { handleDisplayProperty(obj); }); jQuery('.resizer_southeast').each(function(i, obj) { handleDisplayProperty(obj); }); jQuery('.resizer_northwest').each(function(i, obj) { handleDisplayProperty(obj); }); }); } /** * Initialize the Oryx Editor when the content has been loaded */ $rootScope.$on('$includeContentLoaded', function (event) { if (!$rootScope.editorInitialized) { ORYX._loadPlugins(); var modelId = EDITOR.UTIL.getParameterByName('modelId'); fetchModel(modelId); $rootScope.window = {}; var updateWindowSize = function() { $rootScope.window.width = $window.innerWidth; $rootScope.window.height = $window.innerHeight; }; // Window resize hook angular.element($window).bind('resize', function() { $rootScope.safeApply(updateWindowSize()); }); $rootScope.$watch('window.forceRefresh', function(newValue) { if(newValue) { $timeout(function() { updateWindowSize(); $rootScope.window.forceRefresh = false; }); } }); updateWindowSize(); // Hook in resizing of main panels when window resizes // TODO: perhaps move to a separate JS-file? jQuery(window).resize(function () { // Calculate the offset based on the bottom of the module header var offset = jQuery("#editor-header").offset(); var propSectionHeight = jQuery('#propertySection').height(); var canvas = jQuery('#canvasSection'); var mainHeader = jQuery('#main-header'); if (offset == undefined || offset === null || propSectionHeight === undefined || propSectionHeight === null || canvas === undefined || canvas === null || mainHeader === null) { return; } if ($rootScope.editor) { var selectedElements = $rootScope.editor.selection; var subSelectionElements = $rootScope.editor._subSelection; $rootScope.selectedElements = selectedElements; $rootScope.subSelectionElements = subSelectionElements; if (selectedElements && selectedElements.length > 0) { $rootScope.selectedElementBeforeScrolling = selectedElements[0]; $rootScope.editor.setSelection([]); // needed cause it checks for element changes and does nothing if the elements are the same $rootScope.editor.setSelection($rootScope.selectedElements, $rootScope.subSelectionElements); $rootScope.selectedElements = undefined; $rootScope.subSelectionElements = undefined; } } var totalAvailable = jQuery(window).height() - offset.top - mainHeader.height() - 21; canvas.height(totalAvailable - propSectionHeight); jQuery('#paletteSection').height(totalAvailable); // Update positions of the resize-markers, according to the canvas var actualCanvas = null; if (canvas && canvas[0].children[1]) { actualCanvas = canvas[0].children[1]; } var canvasTop = canvas.position().top; var canvasLeft = canvas.position().left; var canvasHeight = canvas[0].clientHeight; var canvasWidth = canvas[0].clientWidth; var iconCenterOffset = 8; var widthDiff = 0; var actualWidth = 0; if(actualCanvas) { // In some browsers, the SVG-element clientwidth isn't available, so we revert to the parent actualWidth = actualCanvas.clientWidth || actualCanvas.parentNode.clientWidth; } if(actualWidth < canvas[0].clientWidth) { widthDiff = actualWidth - canvas[0].clientWidth; // In case the canvas is smaller than the actual viewport, the resizers should be moved canvasLeft -= widthDiff / 2; canvasWidth += widthDiff; } var iconWidth = 17; var iconOffset = 20; var north = jQuery('#canvas-grow-N'); north.css('top', canvasTop + iconOffset + 'px'); north.css('left', canvasLeft - 10 + (canvasWidth - iconWidth) / 2 + 'px'); var south = jQuery('#canvas-grow-S'); south.css('top', (canvasTop + canvasHeight - iconOffset - iconCenterOffset) + 'px'); south.css('left', canvasLeft - 10 + (canvasWidth - iconWidth) / 2 + 'px'); var east = jQuery('#canvas-grow-E'); east.css('top', canvasTop - 10 + (canvasHeight - iconWidth) / 2 + 'px'); east.css('left', (canvasLeft + canvasWidth - iconOffset - iconCenterOffset) + 'px'); var west = jQuery('#canvas-grow-W'); west.css('top', canvasTop -10 + (canvasHeight - iconWidth) / 2 + 'px'); west.css('left', canvasLeft + iconOffset + 'px'); north = jQuery('#canvas-shrink-N'); north.css('top', canvasTop + iconOffset + 'px'); north.css('left', canvasLeft + 10 + (canvasWidth - iconWidth) / 2 + 'px'); south = jQuery('#canvas-shrink-S'); south.css('top', (canvasTop + canvasHeight - iconOffset - iconCenterOffset) + 'px'); south.css('left', canvasLeft +10 + (canvasWidth - iconWidth) / 2 + 'px'); east = jQuery('#canvas-shrink-E'); east.css('top', canvasTop + 10 + (canvasHeight - iconWidth) / 2 + 'px'); east.css('left', (canvasLeft + canvasWidth - iconOffset - iconCenterOffset) + 'px'); west = jQuery('#canvas-shrink-W'); west.css('top', canvasTop + 10 + (canvasHeight - iconWidth) / 2 + 'px'); west.css('left', canvasLeft + iconOffset + 'px'); }); jQuery(window).trigger('resize'); jQuery.fn.scrollStopped = function(callback) { jQuery(this).scroll(function(){ var self = this, $this = jQuery(self); if ($this.data('scrollTimeout')) { clearTimeout($this.data('scrollTimeout')); } $this.data('scrollTimeout', setTimeout(callback,50,self)); }); }; // Always needed, cause the DOM element on which the scroll event listeners are attached are changed for every new model initScrollHandling(); $rootScope.editorInitialized = true; } }); /** * Initialize the event bus: couple all Oryx events with a dispatch of the * event of the event bus. This way, it gets much easier to attach custom logic * to any event. */ $rootScope.editorFactory.promise.then(function() { KISBPM.eventBus.editor = $rootScope.editor; var eventMappings = [ { oryxType : ORYX.CONFIG.EVENT_SELECTION_CHANGED, kisBpmType : KISBPM.eventBus.EVENT_TYPE_SELECTION_CHANGE }, { oryxType : ORYX.CONFIG.EVENT_DBLCLICK, kisBpmType : KISBPM.eventBus.EVENT_TYPE_DOUBLE_CLICK }, { oryxType : ORYX.CONFIG.EVENT_MOUSEOUT, kisBpmType : KISBPM.eventBus.EVENT_TYPE_MOUSE_OUT }, { oryxType : ORYX.CONFIG.EVENT_MOUSEOVER, kisBpmType : KISBPM.eventBus.EVENT_TYPE_MOUSE_OVER } ]; eventMappings.forEach(function(eventMapping) { $rootScope.editor.registerOnEvent(eventMapping.oryxType, function(event) { KISBPM.eventBus.dispatch(eventMapping.kisBpmType, event); }); }); $rootScope.editor.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED, function (event) { var validateButton = document.getElementById(event.shape.resourceId + "-validate-button"); if (validateButton) { validateButton.style.display = 'none'; } }); // The Oryx canvas is ready (we know since we're in this promise callback) and the // event bus is ready. The editor is now ready for use KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_EDITOR_READY, {type : KISBPM.eventBus.EVENT_TYPE_EDITOR_READY}); }); // Alerts $rootScope.alerts = { queue: [] }; $rootScope.showAlert = function(alert) { if(alert.queue.length > 0) { alert.current = alert.queue.shift(); // Start timout for message-pruning alert.timeout = $timeout(function() { if (alert.queue.length == 0) { alert.current = undefined; alert.timeout = undefined; } else { $rootScope.showAlert(alert); } }, (alert.current.type == 'error' ? 5000 : 1000)); } else { $rootScope.alerts.current = undefined; } }; $rootScope.addAlert = function(message, type) { var newAlert = {message: message, type: type}; if (!$rootScope.alerts.timeout) { // Timeout for message queue is not running, start one $rootScope.alerts.queue.push(newAlert); $rootScope.showAlert($rootScope.alerts); } else { $rootScope.alerts.queue.push(newAlert); } }; $rootScope.dismissAlert = function() { if (!$rootScope.alerts.timeout) { $rootScope.alerts.current = undefined; } else { $timeout.cancel($rootScope.alerts.timeout); $rootScope.alerts.timeout = undefined; $rootScope.showAlert($rootScope.alerts); } }; $rootScope.addAlertPromise = function(promise, type) { if (promise) { promise.then(function(data) { $rootScope.addAlert(data, type); }); } }; } ]) // Moment-JS date-formatting filter .filter('dateformat', function() { return function(date, format) { if (date) { if (format) { return moment(date).format(format); } else { return moment(date).calendar(); } } return ''; }; });