form-builder.js 14.3 KB
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

angular.module('flowableModeler')
    .controller('FormBuilderController', ['$rootScope', '$scope', '$translate', '$http', '$timeout', '$location', '$modal', '$routeParams', '$popover', 'FormBuilderService',
        function ($rootScope, $scope, $translate, $http, $timeout, $location, $modal, $routeParams, $popover, FormBuilderService) {

            // Main page (needed for visual indicator of current page)
            $rootScope.setMainPageById('forms');

            // Needs to be on root scope to be available in the toolbar controller
            $rootScope.formBuilder = {activeTab: 'design'};

            $scope.model = {
                useOutcomes: false
            };

            $rootScope.currentReadonlyFields = {fields: {}};

            $scope.$watch('model.useOutcomes', function (value) {
                if (value) {
                    if (!$rootScope.currentOutcomes || $rootScope.currentOutcomes.length === 0) {
                        $rootScope.currentOutcomes = [{name: ''}];
                    }
                } else {
                    $rootScope.currentOutcomes = [];
                }
            });

            // tabs for tab-control. NOT using templates for the tabs, we control the view
            // ourselves, based on the active tab binding
            $scope.tabs = [
                {
                    id: 'design',
                    title: 'FORM-BUILDER.TITLE.DESIGN'
                },
                {
                    id: 'outcome',
                    title: 'FORM-BUILDER.TITLE.OUTCOME'
                }
            ];

            $scope.form = {
            	name: '', 
            	key: '',
            	description: '', 
            	version: 1
           	};

            $scope.formElements = [];
            $rootScope.currentOutcomes = [];

            $rootScope.formChanges = false;

            var guidSequence = 0;

            function setFieldDragDropAttributes (field, prefix) {
                if (!field._guid) {
                    field._guid = prefix + guidSequence++;
                }

                if (!field._width) {
                    field._width = 1;
                }
            }

            var lastDropArrayTarget = null;

            $scope.onFieldMoved = function (field, fieldArraySource) {
            	
            };


            $scope.onFieldDrop = function (paletteElementOrField, dropArrayTarget, event, index) {

				// Is it an existing object?
                if (paletteElementOrField.hasOwnProperty('_guid')) {

                    lastDropArrayTarget = dropArrayTarget;

                    if (dropArrayTarget) {
                        var i = -1;
                        dropArrayTarget.forEach(function (f, index) {
                            if (paletteElementOrField._guid == f._guid) {
                                i = index;
                            }
                        });
                        if (i != -1) {
                            dropArrayTarget.splice(i, 1);
                        }
                    }

                    if (navigator.appVersion.indexOf("MSIE 9") != -1) {
                        // update _guid which is what ngRepeat is tracking by to force dom updates
                        paletteElementOrField._guid += '_';
                    }
                    return paletteElementOrField;
                }

                lastDropArrayTarget = null;

                var fieldId = paletteElementOrField.type;
                var fieldType;
                
                if (fieldId === 'radio-buttons' || fieldId === 'dropdown') {
                    fieldType = 'OptionFormField';
                    
                } else if (fieldId === 'expression') {
                    fieldType = 'ExpressionFormField';
                }

                var field = {
                    type: fieldId,
                    fieldType: fieldType,
                    name: 'Label',
                    required: false,
                    readOnly: false
                };
                setFieldDragDropAttributes(field, 'newField');

                if (fieldId === 'radio-buttons') {
                    field.options = [{ 
                    	name: $translate.instant('FORM-BUILDER.COMPONENT.RADIO-BUTTON-DEFAULT')
                    }];
                }

                if (fieldId === 'dropdown') {
                    field.options = [
                        {name: $translate.instant('FORM-BUILDER.COMPONENT.DROPDOWN-DEFAULT-EMPTY-SELECTION')}
                    ];
                    field.value = field.options[0];
                    field.hasEmptyValue = true;
                }
                
                return field;
            };


            if ($routeParams.modelId) {

                var url;
                if ($routeParams.modelHistoryId) {
                    url = FLOWABLE.APP_URL.getFormModelHistoryUrl($routeParams.modelId, $routeParams.modelHistoryId);
                } else {
                    url = FLOWABLE.APP_URL.getFormModelUrl($routeParams.modelId);
                }

                $http({method: 'GET', url: url}).
                    success(function (response, status, headers, config) {
                        if (response.formDefinition.fields) {

                            for (var i = 0; i < response.formDefinition.fields.length; i++) {
                                var field = response.formDefinition.fields[i];
                                if (!field.params) {
                                    field.params = {};
                                }
                                setFieldDragDropAttributes(field, 'savedField');
                            }

                            $scope.formElements = response.formDefinition.fields;
                        } else {
                            $scope.formElements = [];
                        }
                        if (response.formDefinition.outcomes) {
                            $rootScope.currentOutcomes = response.formDefinition.outcomes;
                            if ($rootScope.currentOutcomes.length > 0) {
                                $scope.model.useOutcomes = true;
                            }
                        } else {
                            $rootScope.currentOutcomes = [];
                        }
                        $rootScope.currentForm = response;
                        delete $rootScope.currentForm.formDefinition;

                        $rootScope.formItems = $scope.formElements;

                        $rootScope.formChanges = false;
                        $timeout(function () {
                            // Flip switch in timeout to start watching all form-related models
                            // after next digest cycle, to prevent first false-positive
                            $scope.formLoaded = true;
                        }, 200);
                        
                    }).
                    error(function (response, status, headers, config) {
                        $scope.model.loading = false;
                    });
            } else {
                $scope.formLoaded = true;
            }

            $scope.palletteElements = [
                {'type': 'text', 'title': $translate.instant('FORM-BUILDER.PALLETTE.TEXT'), 'icon': 'images/form-builder/textfield-icon.png', 'width': 1},
                {'type': 'password', 'title': $translate.instant('FORM-BUILDER.PALLETTE.PASSWORD'), 'icon': 'images/form-builder/password-icon.png', 'width': 1},
                {'type': 'multi-line-text', 'title': $translate.instant('FORM-BUILDER.PALLETTE.MULTILINE-TEXT'), 'icon': 'images/form-builder/multi-line-textfield-icon.png', 'width': 1},
                {'type': 'integer', 'title': $translate.instant('FORM-BUILDER.PALLETTE.NUMBER'), 'icon': 'images/form-builder/numberfield-icon.png', 'width': 1},
                {'type': 'decimal', 'title': $translate.instant('FORM-BUILDER.PALLETTE.DECIMAL'), 'icon': 'images/form-builder/decimalfield-icon.png', 'width': 1},
                {'type': 'boolean', 'title': $translate.instant('FORM-BUILDER.PALLETTE.CHECKBOX'), 'icon': 'images/form-builder/booleanfield-icon.png', 'width': 1},
                {'type': 'date', 'title': $translate.instant('FORM-BUILDER.PALLETTE.DATE'), 'icon': 'images/form-builder/datefield-icon.png', 'width': 1},
                {'type': 'dropdown', 'title': $translate.instant('FORM-BUILDER.PALLETTE.DROPDOWN'), 'icon': 'images/form-builder/dropdownfield-icon.png', 'width': 1},
                {'type': 'radio-buttons', 'title': $translate.instant('FORM-BUILDER.PALLETTE.RADIO'), 'icon': 'images/form-builder/choicefield-icon.png', 'width': 1},
                {'type': 'people', 'title': $translate.instant('FORM-BUILDER.PALLETTE.PEOPLE'), 'icon': 'images/form-builder/peoplefield-icon.png', 'width': 1},
                {'type': 'functional-group', 'title': $translate.instant('FORM-BUILDER.PALLETTE.GROUP-OF-PEOPLE'), 'icon': 'images/form-builder/peoplefield-icon.png', 'width': 1},
                {'type': 'upload', 'title': $translate.instant('FORM-BUILDER.PALLETTE.UPLOAD'), 'icon': 'images/form-builder/uploadfield-icon.png', 'width': 1},
                {'type': 'expression', 'title': $translate.instant('FORM-BUILDER.PALLETTE.EXPRESSION'), 'icon': 'images/form-builder/readonly-icon.png', 'width': 1},
                {'type': 'hyperlink', 'title': $translate.instant('FORM-BUILDER.PALLETTE.HYPERLINK'), 'icon': 'images/form-builder/hyperlink-icon.png', 'width':1},
				{'type': 'spacer', 'title': $translate.instant('FORM-BUILDER.PALLETTE.SPACER'), 'icon': 'images/form-builder/spacer-icon.png', 'width':1},
				{'type': 'horizontal-line', 'title': $translate.instant('FORM-BUILDER.PALLETTE.HORIZONTAL-LINE'), 'icon': 'images/form-builder/horizontal-line-icon.png', 'width':1},
				{'type': 'headline', 'title': $translate.instant('FORM-BUILDER.PALLETTE.HEADLINE'), 'icon': 'images/form-builder/headline-icon.png', 'width':1},
				{'type': 'headline-with-line', 'title': $translate.instant('FORM-BUILDER.PALLETTE.HEADLINE-WITH-LINE'), 'icon': 'images/form-builder/headline-with-line-icon.png', 'width':1}
            ];

            $scope.$watch('formItems', function () {
                if ($scope.formLoaded) {
                    $rootScope.formChanges = true;
                }
            }, true);

            $scope.$watch('currentOutcomes', function () {
                if ($scope.formLoaded) {
                    $rootScope.formChanges = true;
                }
            }, true);

            $scope.addOutcome = function () {
                $rootScope.currentOutcomes[$rootScope.currentOutcomes.length] = {name: ''};
            };

            $scope.removeOutcome = function (index) {
                $rootScope.currentOutcomes.splice(index, 1);
            };

            $scope.$on('$locationChangeStart', function (event, next, current) {
                if (!$rootScope.ignoreChanges && $rootScope.formChanges) {
                    // Always prevent location from changing. We'll use a popup to determine the action we want to take
                    event.preventDefault();

                    var discardCallback = function () {
                        $rootScope.ignoreChanges = true;
                        $location.url(next.substring(next.indexOf('/#') + 2));
                    };

                    var continueEditingCallback = function () {
                        // Don't change the location and make sure "main navigation" is still correct
                        $rootScope.ignoreChanges = false;
                        $rootScope.setMainPageById('forms');
                    };

                    $scope.yesNoCancel = false;
                    showDiscardPopup($scope, null, discardCallback, continueEditingCallback);

                } else {
                    // Clear marker
                    $rootScope.ignoreChanges = false;
                }

            });

            $scope.$on("formChangesEvent", function () {
                var discardCallback = function () {
                    $scope.$broadcast("discardDataEvent");
                };

                var saveDataCallback = function () {
                    $scope.$broadcast("mustSaveEvent");
                };

                var continueEditingCallback = function () {
                    $scope.$broadcast("continueEditingEvent");
                };

                $scope.yesNoCancel = true;
                showDiscardPopup($scope, saveDataCallback, discardCallback, continueEditingCallback);
            });

            function showDiscardPopup($scope, saveCallback, discardCallback, cancelCallback) {
                if (!$scope.unsavedChangesModalInstance) {

                    $scope.handleResponseFunction = function (discard) {
                        $scope.unsavedChangesModalInstance = undefined;
                        if (discard == true) {
                            if (discardCallback) {
                                discardCallback();
                            }

                        } else if (discard == false) {
                            if (saveCallback) {
                                saveCallback();
                            }
                        } else {
                            if (cancelCallback) {
                                cancelCallback();
                            }
                        }
                    };

                    _internalCreateModal({
                        template: 'editor-app/popups/unsaved-changes.html',
                        scope: $scope
                    }, $modal, $scope);
                }
            };

            // get current step and sequential steps for form field resolving
            if ($rootScope.editorHistory && $rootScope.editorHistory.length > 0) {
                $scope.stepId = $rootScope.editorHistory[0].stepId;
                $scope.allSteps = $rootScope.editorHistory[0].allSteps;
            }

        }]);