Best JavaScript code snippet using protractor
dashboardFormController.js
Source:dashboardFormController.js  
1/*******************************************************************************2 * Copyright ©2015. IT Services Jacek Kurasiewicz, Warsaw, Poland. All Rights3 * Reserved.4 *5 * Republication, redistribution, granting a license to other parties, using,6 * copying, modifying this software and its documentation is prohibited without the7 * prior written consent of IT Services Jacek Kurasiewicz.8 * Contact The Office of IT Services Jacek Kurasiewicz, ul. Koszykowa 60/62 lok.9 * 43, 00-673 Warszawa, jk@softpro.pl, +48 512-25-67-67, for commercial licensing10 * opportunities.11 *12 * IN NO EVENT SHALL IT SERVICES JACEK KURASIEWICZ BE LIABLE TO ANY PARTY FOR13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST14 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF15 * IT SERVICES JACEK KURASIEWICZ HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH16 * DAMAGE.17 *18 * IT SERVICES JACEK KURASIEWICZ SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A20 * PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY,21 * PROVIDED HEREUNDER IS PROVIDED "AS IS". IT SERVICES JACEK KURASIEWICZ HAS NO22 * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR23 * MODIFICATIONS.24 *******************************************************************************/25/* global formVisID */26(function() {27    'use strict';28    angular29        .module('dashboardFormApp.dashboardForm')30        .controller('DashboardFormController', DashboardFormController);31    /* @ngInject */32    function DashboardFormController($rootScope, $scope, DashboardFormService, $timeout, ImportService, TaskStatusService, CoreCommonsService, $modal, dashboardSpreadSheetService) {33        var rangePrototype = {34            sheetName: null,35            firstHeader: null,36            lastHeader: null,37            firstNumber: null,38            lastNumber: null,39            selectedRanges: {40                row: null,41                col: null,42                rowCount: null,43                colCount: null44            }45        };46        var selectionPrototype = {47            tab: {48                // title: null,49                // id: null,50                // isConfigured: false,51                // active: false52            },53            values: {54                // rows: null,55                // columns: null,56                // values: null57            },58            ranges: {59                // rows: angular.copy(rangePrototype),60                // cols: angular.copy(rangePrototype),61                // values: angular.copy(rangePrototype),62                // selected: dashboardSpreadSheetService.consts.none,63                // rows: rangePrototype,64                // columns: rangePrototype,65                // values: rangePrototype,66                //selected: dashboardSpreadSheetService.consts.none,67                // readHiddenCells: false68            },69            chartType: {70                // value: null,71                // label: null72            }73        };74        var url = $BASE_PATH;75        var oldChartDataValues = {};76        var oldContextData = {};77        var editionMode = false;78        var spread;79        var xmlForm;80        var highestID = 0;81        var fullHeightFlag = $(window).height();82        var redrawDelay;83        var hasChanged = true;84        var isValid = false;85        var formCtrl = this;86        formCtrl.editMode = ISEDIT;87        formCtrl.controllButtonsEnable = false;88        formCtrl.showOnlySpread = false;89        formCtrl.showCharts = false;90        formCtrl.readFromHiddenCells = false;91        formCtrl.tabID = -1;92        formCtrl.dashboardName; // = "Dashboard name..."93        formCtrl.tabs = [];94        formCtrl.values = null;95        formCtrl.chartAvailableTypes = [{96            value: 'column',97            label: 'Columns'98        }, {99            value: 'bar',100            label: 'Bars'101        }, {102            value: 'line',103            label: 'Lines'104        }, {105            value: 'pie',106            label: 'Pie'107        }];108        formCtrl.chartAvailableTypesNoPie = [formCtrl.chartAvailableTypes[0], formCtrl.chartAvailableTypes[1], formCtrl.chartAvailableTypes[2]];109        formCtrl.contextDataPlaceholder = {110            business: 'select Business...',111            account: 'select Account Dimension...',112            calendarfrom: 'select Calendar from...',113            calendarto: 'select Calendar to...',114            dataType: 'select Data Type...'115        };116        formCtrl.contextData = {117            ccTreeString: formCtrl.contextDataPlaceholder.business,118            expTreeString: formCtrl.contextDataPlaceholder.account,119            callFromTreeString: formCtrl.contextDataPlaceholder.calendarfrom,120            callToTreeString: formCtrl.contextDataPlaceholder.calendarto,121            dataTypeString: formCtrl.contextDataPlaceholder.dataType122        }123        // formCtrl.ccTreeString = formCtrl.contextDataPlaceholder.business;124        // formCtrl.expTreeString = formCtrl.contextDataPlaceholder.account;125        // formCtrl.callFromTreeString = formCtrl.contextDataPlaceholder.calendarfrom;126        // formCtrl.callToTreeString = formCtrl.contextDataPlaceholder.calendarto;127        // formCtrl.dataTypeString = formCtrl.contextDataPlaceholder.dataType;128        formCtrl.selectedFlatForm = {129            vis_id: "",130            xml_form_id: ""131        };132        formCtrl.consts = {133            rows: "rows",134            cols: "columns",135            vals: "values",136            none: "none"137        };138        formCtrl.views = {139            create: "create",140            edit: "edit",141            open: "open"142        };143        formCtrl.types = {144            hierarchy: "hierarchy",145            freeform: "freeform"146        }147        formCtrl.selected = formCtrl.consts.none;148        formCtrl.logout = logout;149        formCtrl.closeTab = closeTab;150        formCtrl.setRows = setRows;151        formCtrl.setColumns = setColumns;152        formCtrl.setValues = setValues;153        formCtrl.changeChartType = changeChartType;154        formCtrl.isSelected = isSelected;155        formCtrl.selectData = selectData;156        formCtrl.confirmDataSelect = confirmDataSelect;157        formCtrl.cancelDataSelect = cancelDataSelect;158        formCtrl.addTab = addTab;159        formCtrl.renameTab = renameTab;160        formCtrl.deleteTab = deleteTab;161        formCtrl.onTabSelect = onTabSelect;162        formCtrl.saveDashboard = saveDashboard;163        formCtrl.testDashboard = testDashboard;164        formCtrl.showModal = showModal;165        formCtrl.toggleAskIfReload = toggleAskIfReload;166        formCtrl.setContextData = setContextData;167        init();168        function init() {169            //var url = window.location.href;170            //var urlTab = window.location.href.split('/');171            var uuid = $UUID;172            if (VIEW === formCtrl.types.freeform) {173                switch (ISEDIT) {174                    case formCtrl.views.create:175                        {176                            showModal();177                            break;178                        }179                    case formCtrl.views.edit:180                        {181                            loadDashboardData(uuid);182                            break;183                        }184                    case formCtrl.views.open:185                        {186                            loadDashboardData(uuid);187                            break;188                        }189                    default:190                };191            } else if (VIEW === formCtrl.types.hierarchy) {192                switch (ISEDIT) {193                    case formCtrl.views.create:194                        {195                            showModal();196                            break;197                        }198                    case formCtrl.views.edit:199                        {200                            loadDashboardData(uuid);201                            break;202                        }203                    case formCtrl.views.open:204                        {205                            loadDashboardData(uuid);206                            break;207                        }208                    default:209                };210            }211            // if (VIEW == 'freeform') {212            //     console.log("I am freeform, edition:", ISEDIT, editionMode);213            //     iAmIn = 'FREEFORM';214            //     if (editionMode) {215            //         editionMode = true;216            //         loadDashboardData(uuid);217            //     } else {218            //         //loadForms();219            //         showModal();220            //     }221            //     // DO FREEFORM STUFF222            // } else if (VIEW == 'hierarchy') {223            //     console.log("I am hierarchy, edition:", ISEDIT, editionMode);224            //     iAmIn = 'HIERARCHY';225            //     // DO HIERARCHY STUFF226            //     if (editionMode) {227            //         loadDashboardData(uuid);228            //     } else {229            //         //loadForms();230            //         showModal();231            //     }232            // }233            $(document).ready(function() {234                redraw();235                $(window).resize(function() {236                    var actualFullHeight = $(window).height();237                    if (fullHeightFlag != actualFullHeight) {238                        fullHeightFlag = actualFullHeight;239                        redraw();240                    }241                });242            });243        }244        function logout() {245            window.location = url + "/logout.do";246        }247        function closeTab() {248            CoreCommonsService.closeTab($timeout);249        }250        function toggleAskIfReload() {251            CoreCommonsService.askIfReload = true;252        }253        function getCellPosition(unparsed) {254            var parsed = unparsed.split(':');255            return {256                col: parseInt(parsed[0]),257                row: parseInt(parsed[1])258            };259        }260        //return charttype{value:, label:}261        function getChartTypeByname(name) {262            for (var x = 0; x < formCtrl.chartAvailableTypes.length; x++) {263                if (formCtrl.chartAvailableTypes[x].value == name) {264                    return angular.copy(formCtrl.chartAvailableTypes[x]);265                }266            }267        }268        function setTab(dashboardTab, index) {269            var selection = angular.copy(selectionPrototype);270            selection.tab = {271                title: dashboardTab.tabName,272                id: 'chart' + index,273                isConfigured: true,274                active: false275            };276            selection.ranges.readHiddenCells = dashboardTab.hideCells === "true" ? false : true;277            selection.chartType = getChartTypeByname(dashboardTab.chartType);278            var firstCell = getCellPosition(dashboardTab.rowsRange.firstCell);279            var lastCell = getCellPosition(dashboardTab.rowsRange.lastCell);280            var firstHeader = dashboardSpreadSheetService.getColumnNameByIndex(firstCell.col + 1) + (firstCell.row + 1);281            var lastHeader = dashboardSpreadSheetService.getColumnNameByIndex(lastCell.col + 1) + (lastCell.row);282            var rowsRange = {283                sheetName: dashboardTab.rowsRange.sheetName,284                firstHeader: firstHeader,285                lastHeader: lastHeader,286                firstNumber: dashboardTab.rowsRange.firstCell,287                lastNumber: dashboardTab.rowsRange.lastCell,288                selectedRanges: {289                    rowCount: lastCell.row - firstCell.row,290                    colCount: lastCell.col - firstCell.col + 1,291                    row: firstCell.row,292                    col: firstCell.col293                }294            };295            selection.ranges.rows = rowsRange;296            //setCoulmns297            if (dashboardTab.chartType === 'pie') {298                // we will see299            } else {300                firstCell = getCellPosition(dashboardTab.colsRange.firstCell);301                lastCell = getCellPosition(dashboardTab.colsRange.lastCell);302                firstHeader = dashboardSpreadSheetService.getColumnNameByIndex(firstCell.col + 1) + (firstCell.row + 1);303                lastHeader = dashboardSpreadSheetService.getColumnNameByIndex(lastCell.col + 1) + (lastCell.row);304                var colsRange = {305                    sheetName: dashboardTab.colsRange.sheetName,306                    firstHeader: firstHeader,307                    lastHeader: lastHeader,308                    firstNumber: dashboardTab.colsRange.firstCell,309                    lastNumber: dashboardTab.colsRange.lastCell,310                    selectedRanges: {311                        rowCount: lastCell.row - firstCell.row,312                        colCount: lastCell.col - firstCell.col + 1,313                        row: firstCell.row,314                        col: firstCell.col315                    }316                };317                selection.ranges.columns = colsRange;318            }319            //setValues 320            firstCell = getCellPosition(dashboardTab.valuesRange.firstCell);321            lastCell = getCellPosition(dashboardTab.valuesRange.lastCell);322            firstHeader = dashboardSpreadSheetService.getColumnNameByIndex(firstCell.col + 1) + (firstCell.row + 1);323            lastHeader = dashboardSpreadSheetService.getColumnNameByIndex(lastCell.col + 1) + (lastCell.row);324            var valuesRange = {325                sheetName: dashboardTab.valuesRange.sheetName,326                firstHeader: firstHeader,327                lastHeader: lastHeader,328                firstNumber: dashboardTab.valuesRange.firstCell,329                lastNumber: dashboardTab.valuesRange.lastCell,330                selectedRanges: {331                    rowCount: lastCell.row - firstCell.row,332                    colCount: lastCell.col - firstCell.col + 1,333                    row: firstCell.row,334                    col: firstCell.col335                }336            };337            selection.ranges.values = valuesRange;338            return selection;339        }340        //load saved dashboard341        function loadDashboardData(uuid) {342            DashboardFormService.getDashboard(uuid)343                .then(function(response) {344                    var dashboardData = response.data;345                    formCtrl.dashboardName = dashboardData.dashboardTitle;346                    highestID = dashboardData.tabs.length;347                    //formCtrl.xmlFormId = dashboardData.formId;348                    //formCtrl.UUID = dashboardData.dashboardUUID;349                    formCtrl.selectedModelID = dashboardData.modelId;350                    DashboardFormService.getChosenForm(dashboardData.formId)351                        .then(function(responseSpread) {352                            var jsonForm = responseSpread.data.jsonForm;353                            if (!$('#spreadContainer').wijspread('spread')) {354                                $('#spreadContainer').wijspread({355                                    sheetCount: 3356                                });357                            }358//                            spreadSheetElement = angular.element(document.querySelector('#spreadContainer'));359//                          spreadSheet = spreadSheetElement.wijspread("spread");360//                            spread = new GC.Spread.Sheets.Workbook(document.getElementById("spreadContainer"),{sheetCount:3});361                            spread = $('#spreadContainer').wijspread('spread');362                            loadSpreadDocument(jsonForm, spread);363                            formCtrl.selectedFlatForm.xml_form_id = responseSpread.data.flatFormId;364                            formCtrl.selectedFlatForm.vis_id = responseSpread.data.visId;365                            formCtrl.xmlForm = responseSpread.data.xmlForm;366                            // var spread = $('#spreadContainer').wijspread('spread');367                            // spread.grayAreaBackColor("#FCFDFD");368                            for (var i = 0; i < dashboardData.tabs.length; i++) {369                                var selection = setTab(dashboardData.tabs[i], i);370                                formCtrl.tabs[i] = selection;371                            }372                            if (formCtrl.tabs != null && formCtrl.tabs.length > 0) {373                                formCtrl.tabID = 0;374                                formCtrl.controllButtonsEnable = true;375                            } else {376                                formCtrl.tabID = -1;377                            }378                            if (VIEW == 'hierarchy') {379                                if (dashboardData.contextData) {380                                    formCtrl.contextData.expTreeString = dashboardData.contextData.exp;381                                    formCtrl.contextData.callFromTreeString = dashboardData.contextData.calendarFrom;382                                    formCtrl.contextData.callToTreeString = dashboardData.contextData.calendarTo;383                                    formCtrl.contextData.dataTypeString = dashboardData.contextData.dataType;384                                    formCtrl.contextData.ccTreeString = dashboardData.contextData.cc;385                                }386                                formCtrl.xmlForm = clearXmlForm(formCtrl.xmlForm);387                                formCtrl.xmlForm = setContextInXmlForm(formCtrl.xmlForm);388                                DashboardFormService.getSecurityList(formCtrl.selectedModelID).then(function(response) {389                                    var securityList = response.data;390                                    var isAccess = false;391                                    for (var i = 0; i < securityList.length; i++) {392                                        if (securityList[i] === formCtrl.contextData.ccTreeString.trim()) {393                                            isAccess = true394                                            i = securityList.length;395                                        }396                                    }397                                    if (isAccess === false) {398                                        formCtrl.contextData.ccTreeString = formCtrl.contextDataPlaceholder.account;399                                        formCtrl.xmlForm.properties.DIMENSION_0_VISID = formCtrl.contextDataPlaceholder.account;400                                    } else {401                                        testDashboard();402                                        //confirmDataSelect(true);403                                    }404                                });405                            } else {406                                //confirmDataSelect(true);407                            }408                            if (formCtrl.tabs.length > 0) {409                                formCtrl.tabID = 0;410                                formCtrl.tabs[formCtrl.tabID].tab.active = true;411                                formCtrl.readFromHiddenCells = formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells;412                                confirmDataSelect(true);413                            }414                        });415                });416        }417        function redraw() {418            if (formCtrl.showOnlySpread) {419                $timeout.cancel(redrawDelay);420                redrawDelay = $timeout(function() {421                    var fullHeight = $(window).height();422                    var otherElementsHeight = $("#container-navbar").outerHeight(true) + $("#container-main").outerHeight(true) + 5;423                    $("#spreadContainer").height(fullHeight - otherElementsHeight);424                    $("#spreadContainer").wijspread("refresh");425                }, 5);426            }427        }428        //********************************* Tabs *********************************************************429        //************************************ Tabs ******************************************************430        //*************************************** Tabs ***************************************************431        function getTabIndex(tabID) {432            for (var i = 0; i < formCtrl.tabs.length; i++) {433                if (formCtrl.tabs[i] !== undefined && formCtrl.tabs[i].tab.id == tabID) {434                    return i;435                }436            }437            return -1;438        }439        function validateTabName(newTabName, addTab, tabID) {440            if (!newTabName) {441                swal.showInputError('Tab name can not be empty');442                return false;443            }444            if (getTabIndex(newTabName) > -1) {445                swal.showInputError('Tab name have to be unique');446                return false;447            }448            return true;449        }450        function addTab() {451            swal({452                title: 'Add new tab',453                text: 'Chart name:',454                type: 'input',455                showCancelButton: true,456                closeOnConfirm: false,457                animation: 'slide-from-top',458                inputPlaceholder: 'Chart name...'459            }, function(inputValue) {460                if (validateTabName(inputValue)) {461                    swal.close();462                    //TODO some init463                    var selection = {};464                    selection.tab = {465                        title: inputValue,466                        id: 'chart' + highestID,467                        isConfigured: false,468                        active: true469                    };470                    selection.ranges = {471                        readHiddenCells: false472                    };473                    selection.values = {};474                    selection.chartType = {475                        value: formCtrl.chartAvailableTypes[0].value,476                        label: formCtrl.chartAvailableTypes[0].label477                    };478                    formCtrl.tabs.push(selection);479                    //formCtrl.controllButtonsEnable = false;480                    formCtrl.tabID = formCtrl.tabs.length - 1;481                    highestID = highestID + 1;482                    isValid = false;483                    formCtrl.showCharts = false;484                    formCtrl.showOnlySpread = false;485                    toggleAskIfReload();486                    $scope.$apply();487                }488            });489        }490        function renameTab(tabID) {491            var inputValue = "";492            for (var tab in formCtrl.tabs) {493                if (formCtrl.tabs[tab].tab.id === tabID) {494                    inputValue = formCtrl.tabs[tab].tab.title;495                }496            }497            swal({498                title: 'Rename tab',499                text: 'Chart name:',500                type: 'input',501                inputValue: inputValue,502                showCancelButton: true,503                closeOnConfirm: false,504                animation: 'slide-from-top',505                inputPlaceholder: 'Chart name...'506            }, function(inputValue) {507                if (validateTabName(inputValue)) {508                    swal.close();509                    for (var i = 0; i < formCtrl.tabs.length; i++) {510                        if (formCtrl.tabs[i] != null && formCtrl.tabs[i].tab.id === tabID) {511                            formCtrl.tabs[i].tab.title = inputValue;512                            break;513                        }514                    }515                    toggleAskIfReload();516                    $scope.$apply();517                }518            });519        }520        function deleteTab(tabID) {521            swal({522                    title: 'Are you sure you want to delete this tab?',523                    text: 'You will not be able to recover this tab!',524                    type: 'warning',525                    showCancelButton: true,526                    confirmButtonColor: '#DD6B55',527                    confirmButtonText: 'Yes, delete it!',528                    cancelButtonText: 'No, cancel!',529                    closeOnConfirm: true,530                    closeOnCancel: true531                },532                function(isConfirm) {533                    if (isConfirm) {534                        var foundedIndex;535                        for (var i = 0; i < formCtrl.tabs.length; i++) {536                            if (formCtrl.tabs[i] != null && formCtrl.tabs[i].tab.id === tabID) {537                                foundedIndex = i;538                                break;539                            }540                        }541                        formCtrl.tabs.splice(foundedIndex, 1);542                        if ('chart' + (highestID - 1) === tabID) {543                            highestID--;544                        }545                        isValid = false;546                        formCtrl.showCharts = false;547                        formCtrl.showOnlySpread = false;548                        if (formCtrl.tabs.length > 0) {549                            formCtrl.tabID = 0;550                            formCtrl.tabs[formCtrl.tabID].tab.active = true;551                            formCtrl.readFromHiddenCells = formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells;552                            confirmDataSelect(true);553                        }554                        $scope.$apply();555                    }556                });557        }558        function onTabSelect(tabName) {559            formCtrl.tabID = getTabIndex(tabName);560            formCtrl.tabs[formCtrl.tabID].tab.active = true;561            formCtrl.readFromHiddenCells = formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells;562            confirmDataSelect(true);563        }564        function setTabConfigured(tabName) {565            var foundedIndex;566            for (var i = 0; i < formCtrl.tabs.length; i++) {567                if (formCtrl.tabs[i] !== undefined && formCtrl.tabs[i].tab.id == tabName) {568                    foundedIndex = i;569                    break;570                }571            }572            formCtrl.tabs[foundedIndex].tab.isConfigured = true;573        }574        //********************************* Chart *********************************************************575        //************************************ Chart ******************************************************576        //*************************************** Chart ***************************************************577        function clearAllChartsData() {578            var i;579            for (i = 0; i < formCtrl.tabs.length; i++) {580                var selection = formCtrl.tabs[i];581                selection.tab.isConfigured = false;582                selection.ranges = {583                    readHiddenCells: false584                };585                formCtrl.readFromHiddenCells = false;586                selection.values = {};587                selection.chartType = {588                    value: formCtrl.chartAvailableTypes[0].value,589                    label: formCtrl.chartAvailableTypes[0].label590                };591                if (oldChartDataValues == null) {592                    oldChartDataValues = {593                        ranges: null594                    };595                } else {596                    oldChartDataValues.ranges = {597                        readHiddenCells: false598                    };599                    formCtrl.readFromHiddenCells = formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells;600                    oldChartDataValues.chartType = {601                        value: formCtrl.chartAvailableTypes[0].value,602                        label: formCtrl.chartAvailableTypes[0].label603                    };604                }605                isValid = false;606                formCtrl.showCharts = false;607                toggleAskIfReload();608                //$scope.$apply();609            }610        }611        function changeChartType(tabName) {612            for (var index in formCtrl.chartAvailableTypes) {613                if (formCtrl.chartAvailableTypes[index].label === formCtrl.tabs[formCtrl.tabID].chartType.label) {614                    formCtrl.tabs[formCtrl.tabID].chartType.value = formCtrl.chartAvailableTypes[index].value;615                    break;616                }617            }618            if (formCtrl.showCharts == true) {619                drawChart4Tab(formCtrl.tabs[formCtrl.tabID], formCtrl.tabs[formCtrl.tabID].values);620            }621        }622        function selectData(tabName) {623            formCtrl.tabID = getTabIndex(tabName);624            //hide charts if visible625            formCtrl.showCharts = false;626            //create backup           627            if (oldChartDataValues == null) {628                oldChartDataValues = {629                    ranges: null630                };631            } else {632                oldChartDataValues.ranges = angular.copy(formCtrl.tabs[formCtrl.tabID].ranges);633                formCtrl.readFromHiddenCells = formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells;634                oldChartDataValues.chartType = angular.copy(formCtrl.tabs[formCtrl.tabID].chartType);635            }636            //show spread637            formCtrl.showOnlySpread = true;638            dashboardSpreadSheetService.setSelectionColor("rgba(0,0,0, 0.3)", spread);639            $timeout(function() {640                redraw();641            }, 0);642            // $timeout(function () {643            //     redraw();644            // }, 1000);645        }646        function confirmDataSelect(silently) {647            //validate648            var validationError = validateCellsSelection(formCtrl.tabs[formCtrl.tabID]);649            if (validationError !== "") {650                if (silently === false) {651                    showValidationError('Chart will not be draw:', validationError);652                }653                return;654            }655            formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells = formCtrl.readFromHiddenCells;656            var values = dashboardSpreadSheetService.refreshSpreadValues(spread, formCtrl.tabs[formCtrl.tabID].ranges);657            var isPie = formCtrl.tabs[formCtrl.tabID].chartType.value === "pie";658            validationError = validateChartData(values, isPie);659            if (validationError !== '') {660                if (silently === false) {661                    showValidationError('Chart will not be draw:', validationError);662                }663                return;664            }665            formCtrl.tabs[formCtrl.tabID].values = values;666            //formCtrl.values = values;667            //      set global values668            //      set isValid = true;669            formCtrl.selected = formCtrl.consts.none;670            isValid = true;671            //      draw charts672            drawChart4Tab(formCtrl.tabs[formCtrl.tabID], values);673            //      hide spread674            formCtrl.showOnlySpread = false;675            //      show charts676            formCtrl.showCharts = true;677        }678        function cancelDataSelect() {679            //copy backup to global680            if (oldChartDataValues == null) {681                oldChartDataValues = {682                    ranges: null683                };684            } else {685                if (oldChartDataValues.ranges != null) {686                    formCtrl.tabs[formCtrl.tabID].ranges = angular.copy(oldChartDataValues.ranges);687                    //formCtrl.tabs[formCtrl.tabID].ranges.readHiddenCells = formCtrl.readFromHiddenCells;688                }689                if (oldChartDataValues.chartType != null) {690                    // formCtrl.tabs[formCtrl.tabID].chartType = angular.copy(oldChartDataValues.chartType);691                    formCtrl.tabs[formCtrl.tabID].chartType.value = oldChartDataValues.chartType.value;692                    formCtrl.tabs[formCtrl.tabID].chartType.label = oldChartDataValues.chartType.label;693                }694            }695            formCtrl.selected = formCtrl.consts.none;696            //hide spread697            formCtrl.showOnlySpread = false;698            //check isValid699            if (isValid) {700                //redraw701                //show charts702                formCtrl.showCharts = true;703            }704        }705        function validateCellsSelection(selection) {706            if (selection.chartType == null) {707                return 'Chart type is not defined';708            }709            var validationError = '';710            var ranges = selection.ranges;711            if (validationError === '') {712                validationError = ranges.rows != null ? '' : 'Rows are not defined';713            } else {714                validationError += ranges.rows != null ? '' : ', rows are not defined';715            }716            if (validationError === '') {717                validationError = ranges.values != null ? '' : 'Values are not defined';718            } else {719                validationError += ranges.values != null ? '' : ', values are not defined';720            }721            if (selection.chartType.value !== 'pie') {722                if (validationError === '') {723                    validationError = ranges.columns != null ? '' : 'Columns are not defined';724                } else {725                    validationError += ranges.columns != null ? '' : ', columns are not defined';726                }727            }728            if (validationError !== '') {729                return validationError;730            }731            if (selection.chartType.value === 'pie') {732                var valRanges = selection.ranges.values.selectedRanges;733                var rowRanges = selection.ranges.rows.selectedRanges;734                if ((rowRanges.rowCount !== valRanges.rowCount && rowRanges.rowCount !== valRanges.colCount) ||735                    (rowRanges.rowCount === valRanges.rowCount && rowRanges.rowCount === valRanges.colCount && valRanges.rowCount !== 1) ||736                    (rowRanges.rowCount === valRanges.rowCount && valRanges.colCount !== 1) ||737                    (rowRanges.rowCount === valRanges.colCount && valRanges.rowCount !== 1)) {738                    validationError = 'Pie chart requires flat data, labels count need to be equal value count.';739                }740            } else {741                var valRanges = selection.ranges.values.selectedRanges;742                var colRanges = selection.ranges.columns.selectedRanges;743                var rowRanges = selection.ranges.rows.selectedRanges;744                if (rowRanges.rowCount !== valRanges.rowCount || colRanges.colCount !== valRanges.colCount) {745                    validationError = 'You selected labels with range size: ' + rowRanges.rowCount + 'x' + colRanges.colCount + ' but values range size is: ' + valRanges.rowCount + 'x' + valRanges.colCount;746                }747            }748            return validationError;749        }750        function validateChartData(values, isPie) {751            var validationError = '';752            if (isPie) {753                if (values.rows == null || values.values == null) {754                    validationError = "Null pointer exception";755                } else if (values.rows.length === 0) {756                    validationError = "Label for rows must be of a valid string";757                }758            } else {759                if (values.rows == null || values.columns == null || values.values == null) {760                    validationError = "Null pointer exception";761                } else if (values.rows.length === 0 || values.columns.length === 0) {762                    validationError = "Label for rows and columns must be of a valid string";763                }764            }765            return validationError;766        }767        function showValidationError(validationTitle, validationError) {768            swal({769                title: validationTitle,770                text: validationError,771                type: 'warning'772            });773        }774        function drawChart4Tab(selection, values) {775            var i;776            //var title = formCtrl.chartTitles[tabName];777            var title = selection.tab.title;778            var series = [];779            var categories = [];780            var isPie = selection.chartType ? selection.chartType.value === 'pie' : undefined;781            if (!isPie) {782                for (i = 0; i < values.rows.length; i++) {783                    series.push({784                        name: values.rows[i],785                        data: values.values[i]786                    });787                    if (selection.chartType.value != null) {788                        series[i].type = selection.chartType.value;789                    }790                }791                categories = values.columns;792            } else {793                var data = [];794                var length = values.values[0].length === 1 ? values.values.length : values.values[0].length;795                for (i = 0; i < length; i++) {796                    data.push({797                        category: values.rows[i],798                        // value: values.values.length == 1 ? values.values[0][i] : values.values[i][0]799                        value: values.values[0].length === 1 ? values.values[i][0] : values.values[0][i]800                    });801                }802                series.push({803                    data: data,804                    type: 'pie'805                });806                //categories = values.rows;807            }808            //var validationResult = validateChartData(selection.ranges, isPie);809            //if (!validationResult.validationOK) {810            // if (validationResult !== "") {811            //     showValidationError('Chart will not be draw:', validationResult);812            //     return;813            // } else {814            // formCtrl.setRowsFlag = false;815            // formCtrl.setColumnsFlag = false;816            // formCtrl.setValuesFlag = false;817            //setTabConfigured(id);818            selection.tab.isConfigured = true;819            //}820            if (!isPie) {821                $timeout(function() {822                    $('#myChart-' + selection.tab.id).kendoChart({823                        seriesColors: ["#5B9BD5", "#ED7D31", "#A5A5A5", "#FFC000", "#70AD47", "#C70A0A", "#8C12B8", "#980000", "#CFB53B", "#38B0DE", "#DB70DB", "#2F2F4F", "#32CD32", "#E47833", "#6B238E"],824                        title: {825                            text: title826                        },827                        legend: {828                            position: 'top'829                        },830                        series: series,831                        categoryAxis: {832                            categories: categories833                        },834                        tooltip: {835                            visible: true,836                            format: '{0}',837                            template: '#= series.name #: #= value #'838                        }839                    });840                }, 0);841            } else {842                $timeout(function() {843                    $('#myChart-' + selection.tab.id).kendoChart({844                        seriesColors: ["#5B9BD5", "#ED7D31", "#A5A5A5", "#FFC000", "#70AD47", "#C70A0A", "#8C12B8", "#980000", "#CFB53B", "#38B0DE", "#DB70DB", "#2F2F4F", "#32CD32", "#E47833", "#6B238E"],845                        plotArea: {846                            padding: 10847                        },848                        series: series,849                        tooltip: {850                            visible: true,851                            format: '{0}',852                            template: '#= category #: #= value #'853                        },854                        labels: {855                            visible: true856                        },857                        legend: {858                            position: 'top'859                        }860                    });861                }, 0);862            }863        }864        //********************************* SPREAD *********************************************************865        //************************************ SPREAD ******************************************************866        //*************************************** SPREAD ***************************************************867        function loadSpreadDocument(jsonForm) {868            if (jsonForm == null || jsonForm.trim() === "") {869                return;870            }871            if (!$('#spreadContainer').wijspread('spread')) {872                $('#spreadContainer').wijspread({873                    sheetCount: 3874                });875            }876            spread = $('#spreadContainer').wijspread('spread');877            //  else if (spreadIt != null) {878            // 	spread = spreadIt;879            // }880            spread.fromJSON(JSON.parse(jsonForm).spread);881            // block spread edition882            dashboardSpreadSheetService.blockSpreadEdition(spread);883            // bind spread selection884            for (var i = 0; i < spread.getSheetCount(); i++) {885                var sheet = spread.getSheet(i);886                sheet.bind($.wijmo.wijspread.Events.SelectionChanged, function(sender, args) {                    //nie wiem jak rozroznic zaznaczenie od rozwijania grupy887                    var selection = angular.copy(dashboardSpreadSheetService.getSelectedCellsAddresses(spread));888                    if (selection == null) {889                        return;890                    } else if (selection.isMultiselect) {891                        showValidationError('Chart will not be draw:', "Can't process multiselection.");892                    } else if (formCtrl.selected === formCtrl.consts.rows) {893                        if (selection.selectedRanges.colCount > 1) {894                            showValidationError('Selection error:', 'Rows can not be multidimensional');895                        } else {896                            formCtrl.tabs[formCtrl.tabID].ranges.rows = selection;897                            $scope.$apply();898                        }899                    } else if (formCtrl.selected === formCtrl.consts.cols) {900                        if (selection.selectedRanges.rowCount > 1) {901                            showValidationError('Selection error:', 'Columns can not be multidimensional');902                        } else {903                            formCtrl.tabs[formCtrl.tabID].ranges.columns = selection;904                            $scope.$apply();905                        }906                    } else if (formCtrl.selected === formCtrl.consts.vals) {907                        if (formCtrl.tabs[formCtrl.tabID].chartType.value != null && formCtrl.tabs[formCtrl.tabID].chartType.value === "pie" &&908                            selection.selectedRanges.colCount !== 1 && selection.selectedRanges.rowCount !== 1) {909                            showValidationError('Selection error:', 'Values can not be multidimensional');910                        } else {911                            formCtrl.tabs[formCtrl.tabID].ranges.values = selection;912                            $scope.$apply();913                        }914                    } else if (formCtrl.selected === formCtrl.consts.none) {915                        dashboardSpreadSheetService.setSelectionColor("rgba(0,0,0, 0.3)", spread);916                    }917                });918            }919        }920        function isSelected(type) {921            return formCtrl.selected === type;922        }923        function setRows() {924            dashboardSpreadSheetService.setSelectionColor("rgba(238,0,0, 0.3)", spread);925            formCtrl.selected = formCtrl.consts.rows;926            formCtrl.showOnlySpread = true;927            if (formCtrl.tabs[formCtrl.tabID].ranges != null && formCtrl.tabs[formCtrl.tabID].ranges.rows != null) {928                dashboardSpreadSheetService.addSelection(formCtrl.tabs[formCtrl.tabID].ranges.rows, spread);929            }930            //$scope.$apply();931        }932        function setColumns() {933            dashboardSpreadSheetService.setSelectionColor("rgba(0,238,0, 0.3)", spread);934            formCtrl.selected = formCtrl.consts.cols;935            formCtrl.showOnlySpread = true;936            if (formCtrl.tabs[formCtrl.tabID].ranges != null && formCtrl.tabs[formCtrl.tabID].ranges.columns != null) {937                dashboardSpreadSheetService.addSelection(formCtrl.tabs[formCtrl.tabID].ranges.columns, spread);938            }939            //$scope.$apply();940        }941        function setValues() {942            dashboardSpreadSheetService.setSelectionColor("rgba(0,0,238, 0.3)", spread);943            formCtrl.selected = formCtrl.consts.vals;944            formCtrl.showOnlySpread = true;945            if (formCtrl.tabs[formCtrl.tabID].ranges != null && formCtrl.tabs[formCtrl.tabID].ranges.values != null) {946                dashboardSpreadSheetService.addSelection(formCtrl.tabs[formCtrl.tabID].ranges.values, spread);947            }948            //$scope.$apply();949        }950        //********************************* Select Form *********************************************************951        //************************************ Select Form ******************************************************952        //*************************************** Select Form ***************************************************953        function showModal() {954            var modalInstance = $modal.open({955                backdrop: 'static',956                windowClass: 'softpro-modals',957                size: 'lg',958                template: '<dashboard-select-flat-form></dashboard-select-flat-form>',959                controller: ['$scope', '$modalInstance',960                    function($scope, $modalInstance) {961                        function close() {962                            $modalInstance.dismiss('cancel');963                            $scope.apply();964                        }965                        $scope.$on('dashboardSelectFlatForm:close', function(event, args) {966                            $modalInstance.close();967                        });968                    }969                ]970            });971        }972        $scope.$on('dashboardSelectFlatForm:formSelected', function(event, data) {973            // formCtrl.selectedFlatForm = {974            //     vis_id: formCtrl.item.vis_id,975            //     xml_form_id: formCtrl.item.xml_form_id976            // };977            // angular.copy(data, formCtrl.item);978            formSelected(data);979        });980        function manageFormChanged4Freeform(newModelID, jsonForm, form) {981            if (formCtrl.selectedModelID) {982                if (newModelID !== formCtrl.selectedModelID) {983                    swal({984                            title: "Are you sure?",985                            text: "You will have to select all chart data",986                            type: "warning",987                            showCancelButton: true,988                            confirmButtonClass: "btn-danger",989                            confirmButtonText: "Yes, change form.",990                            closeOnConfirm: false991                        },992                        function(isConfirm) {993                            if (isConfirm) {994                                formCtrl.selectedModelID = newModelID;995                                loadSpreadDocument(jsonForm);996                                formCtrl.selectedFlatForm = form;997                                clearAllChartsData();998                                toggleAskIfReload();999                            } else {1000                                formCtrl.selectedFlatForm = oldContextData.form;1001                                //formCtrl.item = oldContextData.form;1002                            }1003                            swal.close();1004                        });1005                } else {1006                    formCtrl.selectedFlatForm = form;1007                    loadSpreadDocument(jsonForm);1008                    clearAllChartsData();1009                }1010            } else {1011                formCtrl.selectedFlatForm = form;1012                formCtrl.selectedModelID = newModelID;1013                loadSpreadDocument(jsonForm);1014            }1015        }1016        function manageFormChanged4Hierarchy(newModelID, jsonForm, form) {1017            if (form == null || newModelID == null || jsonForm == null) {1018                return;1019            }1020            //modelId: string or number???1021            //parse to number and compare1022            var newId = parseInt(newModelID);1023            var oldId = parseInt(formCtrl.selectedModelID);1024            //check for NaN, NaN !== NaN1025            if (newId !== newId) {1026                newId = null;1027            }1028            if (oldId !== oldId) {1029                oldId = null;1030            }1031            if (newId == null) {1032                return;1033            }1034            //           if (newModelID !== formCtrl.selectedModelID) {1035            if (newId !== oldId) {1036                if (formCtrl.contextData.expTreeString !== formCtrl.contextDataPlaceholder.account ||1037                    formCtrl.contextData.callFromTreeString !== formCtrl.contextDataPlaceholder.calendarfrom ||1038                    formCtrl.contextData.callToTreeString !== formCtrl.contextDataPlaceholder.calendarto ||1039                    formCtrl.contextData.dataTypeString !== formCtrl.contextDataPlaceholder.dataType ||1040                    formCtrl.contextData.ccTreeString !== formCtrl.contextDataPlaceholder.business) {1041                    swal({1042                            title: "Are you sure?",1043                            text: "You will have to select all context and chart data",1044                            type: "warning",1045                            showCancelButton: true,1046                            confirmButtonClass: "btn-danger",1047                            confirmButtonText: "Yes, change form.",1048                            closeOnConfirm: false1049                        },1050                        function(isConfirm) {1051                            console.log('HANDLE IT!', isConfirm);1052                            if (isConfirm) {1053                                formCtrl.contextData.expTreeString = formCtrl.contextDataPlaceholder.account;1054                                formCtrl.contextData.callFromTreeString = formCtrl.contextDataPlaceholder.calendarfrom;1055                                formCtrl.contextData.callToTreeString = formCtrl.contextDataPlaceholder.calendarto;1056                                formCtrl.contextData.dataTypeString = formCtrl.contextDataPlaceholder.dataType;1057                                formCtrl.contextData.ccTreeString = formCtrl.contextDataPlaceholder.business;1058                                formCtrl.selectedModelID = newModelID;1059                                loadSpreadDocument(jsonForm);1060                                formCtrl.selectedFlatForm = form;1061                                clearAllChartsData();1062                                formCtrl.xmlForm = setContextInXmlForm(formCtrl.xmlForm);1063                            } else {1064                                formCtrl.selectedCcTree = oldContextData.selectedCcTree;1065                                formCtrl.selectedExpTree = oldContextData.selectedExpTree;1066                                formCtrl.selectedCallTree = oldContextData.selectedCallTree;1067                                formCtrl.selectedDataType = oldContextData.selectedDataType;1068                                formCtrl.contextData.expTreeString = oldContextData.expTreeString;1069                                formCtrl.contextData.callFromTreeString = oldContextData.callFromTreeString;1070                                formCtrl.contextData.callToTreeString = oldContextData.callToTreeString;1071                                formCtrl.contextData.dataTypeString = oldContextData.dataTypeString;1072                                formCtrl.contextData.ccTreeString = oldContextData.ccTreeString;1073                                formCtrl.selectedFlatForm = oldContextData.form;1074                                //formCtrl.item = oldContextData.form;1075                                formCtrl.xmlForm = oldContextData.workbook;1076                            }1077                            swal.close();1078                        });1079                } else {1080                    formCtrl.selectedModelID = newModelID;1081                    loadSpreadDocument(jsonForm);1082                    clearAllChartsData();1083                    formCtrl.selectedFlatForm = form;1084                }1085            } else {1086                loadSpreadDocument(jsonForm);1087                clearAllChartsData();1088                formCtrl.selectedFlatForm = form;1089            }1090            //hide chart1091        }1092        function formSelected(form) {1093            oldContextData = {1094                //back up context1095                workbook: formCtrl.xmlForm,1096                form: formCtrl.selectedFlatForm,1097                selectedCcTree: formCtrl.selectedCcTree,1098                selectedExpTree: formCtrl.selectedExpTree,1099                selectedCallTree: formCtrl.selectedCallTree,1100                selectedDataType: formCtrl.selectedDataType,1101                expTreeString: formCtrl.contextData.expTreeString,1102                callFromTreeString: formCtrl.contextData.callFromTreeString,1103                callToTreeString: formCtrl.contextData.callToTreeString,1104                dataTypeString: formCtrl.contextData.dataTypeString,1105                ccTreeString: formCtrl.contextData.ccTreeString1106            };1107            //formCtrl.xmlFormId = form.xml_form_id;1108            DashboardFormService.getChosenForm(form.xml_form_id)1109                .then(function(response) {1110                    var jsonForm = response.data.jsonForm;1111                    formCtrl.xmlForm = response.data.xmlForm;1112                    formCtrl.xmlForm = clearXmlForm(formCtrl.xmlForm);1113                    //clearAllChartsData();1114                    DashboardFormService.getModelId(response.data.financeCubeId)1115                        .then(function(response2) {1116                            if (VIEW === formCtrl.types.hierarchy) {1117                                manageFormChanged4Hierarchy(response2.data, jsonForm, form);1118                            } else {1119                                manageFormChanged4Freeform(response2.data, jsonForm, form);1120                            }1121                        });1122                    formCtrl.controllButtonsEnable = true;1123                });1124        }1125        function clearXmlForm(xmlForm) {1126            if (xmlForm != null) {1127                delete xmlForm.properties.DIMENSION_0_VISID;1128                delete xmlForm.properties.DIMENSION_1_VISID;1129                delete xmlForm.properties.DIMENSION_2_VISID;1130                delete xmlForm.properties.DATA_TYPE;1131            }1132            return xmlForm;1133        }1134        function setContextInXmlForm(xmlForm) {1135            xmlForm.properties.DIMENSION_1_VISID = formCtrl.contextData.expTreeString.trim();1136            xmlForm.properties.DIMENSION_2_VISID_FROM = formCtrl.contextData.callFromTreeString.trim();1137            xmlForm.properties.DIMENSION_2_VISID_TO = formCtrl.contextData.callToTreeString.trim();1138            xmlForm.properties.DATA_TYPE = formCtrl.contextData.dataTypeString.trim();1139            xmlForm.properties.DIMENSION_0_VISID = formCtrl.contextData.ccTreeString.trim();1140            return xmlForm;1141        }1142        // function isEqualChartSettings() {1143        //     var tabID = formCtrl.tabID;1144        //     if (formCtrl.tabs[tabID].ranges.rows != oldChartDataValues.ranges.rows)1145        //         return false;1146        //     if (formCtrl.tabs[tabID].ranges.columns != oldChartDataValues.ranges.columns)1147        //         return false;1148        //     if (formCtrl.tabs[tabID].ranges.values != oldChartDataValues.ranges.values)1149        //         return false;1150        //     if (formCtrl.tabs[tabID].charType != oldChartDataValues.charType)1151        //         return false;1152        //     if (formCtrl.tabs[tabID].ranges.readHiddenCells != oldChartDataValues.ranges.readHiddenCells) {1153        //         return false;1154        //     } else {1155        //         return true;1156        //     }1157        // }1158        //********************************* Test Dashboard *********************************************************1159        //************************************ Test Dashboard ******************************************************1160        //*************************************** Test Dashboard ***************************************************1161        function createErrorMessageForSheetName(chartTitle, sheetName) {1162            var errorMsg = 'Chart: \'' + chartTitle + '\' tries to use data from sheet: \'' + sheetName +1163                '\' but loaded form do not contain such sheet.';1164            return errorMsg;1165        }1166        function testDashboard() {1167            //formCtrl.xmlForm = setContextInXmlForm(formCtrl.xmlForm);1168            validateXmlFormProperties();1169        }1170        function loadTestDashboard() {1171            var showErrors = true;1172            // if (ISEDIT === formCtrl.views.open) {1173            //     showErrors = false;1174            // }1175            // else{1176            //     showErrors = true;1177            // }1178            DashboardFormService.testDashboard(formCtrl.xmlForm, showErrors).then(function(response) {1179                if (response.data.error === true) {1180                    swal("Error!", response.data.message, "error");1181                } else {1182                    //var xmlForm = response.data;1183                    // var xmlForm = clearXmlForm(response.data);1184                    // xmlForm = setContextInXmlForm(xmlForm);1185                    dashboardSpreadSheetService.setUpCells(response.data, spread);1186                    if (formCtrl.tabs.length > 0) {1187                        if (formCtrl.tabs[formCtrl.tabID].tab.active === true) {1188                            confirmDataSelect(true);1189                        }1190                    }1191                    //refreshSpreadValues();1192                    //swal("Success!", response.data.message, "success");1193                }1194            });1195        }1196        function validateXmlFormProperties() {1197            var props = formCtrl.xmlForm.properties;1198            var modelVisId = props.MODEL_VISID;1199            if (modelVisId == null || modelVisId === "") {1200                // if model is not set - don't allow run test1201                swal({1202                    title: "Model is not set.",1203                    text: "Please select Model in Workbook Properties window in Flat Form Editor.",1204                    type: "warning",1205                    confirmButtonColor: "#5cb85c",1206                }, function(isConfirm) {});1207            } else if (props.DIMENSION_0_VISID === undefined || props.DIMENSION_0_VISID === "" || props.DIMENSION_0_VISID === null || props.DIMENSION_0_VISID === formCtrl.contextDataPlaceholder.business ||1208                props.DIMENSION_1_VISID === undefined || props.DIMENSION_1_VISID === "" || props.DIMENSION_1_VISID === null || props.DIMENSION_1_VISID === formCtrl.contextDataPlaceholder.account ||1209                props.DIMENSION_2_VISID_FROM === undefined || props.DIMENSION_2_VISID_FROM === "" || props.DIMENSION_2_VISID_FROM === null || props.DIMENSION_2_VISID_FROM === formCtrl.contextDataPlaceholder.calendarfrom ||1210                props.DIMENSION_2_VISID_TO === undefined || props.DIMENSION_2_VISID_TO === "" || props.DIMENSION_2_VISID_TO === null || props.DIMENSION_2_VISID_TO === formCtrl.contextDataPlaceholder.calendarto ||1211                props.DATA_TYPE === undefined || props.DATA_TYPE === "" || props.DATA_TYPE === null || props.DATA_TYPE === formCtrl.contextDataPlaceholder.dataType1212            ) {1213                // if data type or any of dimension hierarchies is not set - ask if run test1214                swal({1215                    title: "Some test parameters \n are not set",1216                    text: "Please make sure that all context variables are set.",1217                    type: "warning",1218                    //showCancelButton: true,1219                    confirmButtonColor: "#5cb85c",1220                    confirmButtonText: "Ok"1221                }, function(isConfirm) {1222                    if (isConfirm) {1223                        //formCtrl.onTabSelect('Test');1224                    }1225                });1226            } else {1227                var from = props.DIMENSION_2_VISID_FROM.split("/");1228                var to = props.DIMENSION_2_VISID_TO.split("/");1229                var yearFrom = parseInt(from[1]);1230                var yearTo = parseInt(to[1]);1231                if (yearFrom > yearTo) {1232                    showWarning("Selected years are not overlapping", "No range for years " + yearFrom + " - " + yearTo, "warning", false, "Ok");1233                    return;1234                }1235                if (from.length === 3 && to.length === 3) {1236                    var monthFrom = parseInt(from[2]);1237                    var monthTo = parseInt(to[2]);1238                    if (yearFrom === yearTo) {1239                        if (monthFrom > monthTo && monthTo > 0) {1240                            showWarning("Selected months are not overlapping", "No range for months " + monthFrom + " - " + monthTo, "warning", false, "Ok");1241                            return;1242                        }1243                    }1244                }1245                // if all parameters are set - run test1246                //formCtrl.onTabSelect('Test');1247                loadTestDashboard();1248            }1249        }1250        function showWarning(title, message, type, showCancelButton, confirmButtontext, action) {1251            swal({1252                title: title,1253                text: message,1254                type: type,1255                showCancelButton: showCancelButton,1256                confirmButtonColor: "#5cb85c",1257                confirmButtonText: confirmButtontext1258            }, action);1259        }1260        // function changeHideCells() {1261        //     formCtrl.hideValues[formCtrl.tabID] = !formCtrl.hideCells;1262        // }1263        //********************************* Save Dashboard *********************************************************1264        //************************************ Save Dashboard ******************************************************1265        //*************************************** Save Dashboard ***************************************************1266        function validateContextDimensionsForHierarchy() {1267            if (formCtrl.contextData.expTreeString === formCtrl.contextDataPlaceholder.account) {1268                return false;1269            }1270            if (formCtrl.contextData.callFromTreeString === formCtrl.contextDataPlaceholder.calendarfrom) {1271                return false;1272            }1273            if (formCtrl.contextData.callToTreeString === formCtrl.contextDataPlaceholder.calendarto) {1274                return false;1275            }1276            if (formCtrl.contextData.dataTypeString === formCtrl.contextDataPlaceholder.dataType) {1277                return false;1278            }1279            if (formCtrl.contextData.ccTreeString === formCtrl.contextDataPlaceholder.business) {1280                return false;1281            }1282            return true;1283        }1284        function validateSaveDashboard() {1285            if (!formCtrl.tabs.length) {1286                return "You can not save dashboard with no tabs.";1287            }1288            if (formCtrl.dashboardName == null || formCtrl.dashboardName === "") {1289                return "Dashboard name can not be empty";1290            }1291            if (VIEW === formCtrl.types.hierarchy) {1292                if (!validateContextDimensionsForHierarchy()) {1293                    return "Please select all dimensions";1294                }1295            }1296            var validationError = '';1297            var notConfiguredTabs = '';1298            for (var i = 0; i < formCtrl.tabs.length; i++) {1299                if (!formCtrl.tabs[i].tab.isConfigured) {1300                    notConfiguredTabs = notConfiguredTabs === '' ? notConfiguredTabs + formCtrl.tabs[i].tab.title : notConfiguredTabs + ', ' + formCtrl.tabs[i].tab.title;1301                }1302            }1303            if (notConfiguredTabs !== '') {1304                validationError = 'You can not save, because those tabs are not configured: ' + notConfiguredTabs;1305                return validationError;1306            }1307            //var spread = $('#spreadContainer').wijspread('spread');1308            var sheet;1309            for (var i = 0; i < formCtrl.tabs.length; i++) {1310                //sheet = spread.getSheetFromName(formCtrl.rowsRange[formCtrl.tabs[i].id].sheetName);1311                sheet = spread.getSheetFromName(formCtrl.tabs[i].ranges.rows.sheetName);1312                if (sheet == null) {1313                    return createErrorMessageForSheetName(formCtrl.tabs[i].tab.title, formCtrl.tabs[i].ranges.rows.sheetName);1314                }1315                if (formCtrl.tabs[i].chartType.value !== 'pie') {1316                    sheet = spread.getSheetFromName(formCtrl.tabs[i].ranges.columns.sheetName);1317                    if (sheet == null) {1318                        return createErrorMessageForSheetName(formCtrl.tabs[i].tab.title, formCtrl.tabs[i].ranges.columns.sheetName);1319                    }1320                }1321                sheet = spread.getSheetFromName(formCtrl.tabs[i].ranges.values.sheetName);1322                if (sheet == null) {1323                    return createErrorMessageForSheetName(formCtrl.tabs[i].tab.title, formCtrl.tabs[i].ranges.values.sheetName);1324                }1325            }1326            return validationError;1327        }1328        //formVisId1329        //modelId1330        //context1331        //tabs1332        //dashboardname1333        function saveDashboard() {1334            var validationError = validateSaveDashboard();1335            if (validationError !== '') {1336                showValidationError('Can not save:', validationError);1337                return;1338            }1339            var tabFormSelected = formCtrl.selectedFlatForm.xml_form_id;1340            var dashboardToSave = {1341                formId: tabFormSelected,1342                modelId: formCtrl.selectedModelID,1343                contextData: {1344                    exp: formCtrl.contextData.expTreeString,1345                    calendarFrom: formCtrl.contextData.callFromTreeString,1346                    calendarTo: formCtrl.contextData.callToTreeString,1347                    dataType: formCtrl.contextData.dataTypeString,1348                    cc: formCtrl.contextData.ccTreeString1349                },1350                //contextData: formCtrl.contextData,1351                tabs: [],1352                type: VIEW.toUpperCase(),1353                dashboardUUID: $UUID === 'null' ? null : $UUID1354            };1355            dashboardToSave.dashboardTitle = formCtrl.dashboardName;1356            for (var i = 0; i < formCtrl.tabs.length; i++) {1357                if (formCtrl.tabs[i] != null) {1358                    //var tabID = formCtrl.tabs[i].tab.id;1359                    var tabRowsRange = formCtrl.tabs[i].ranges.rows;1360                    var tabColsRange = formCtrl.tabs[i].ranges.columns;1361                    var tabValuesRange = formCtrl.tabs[i].ranges.values;1362                    var tabTitle = formCtrl.tabs[i].tab.title;1363                    var tabChartType = formCtrl.tabs[i].chartType.value;1364                    var tabHideCell = "false";1365                    if (formCtrl.tabs[i].ranges.readHiddenCells != null) {1366                        tabHideCell = "" + !formCtrl.tabs[i].ranges.readHiddenCells;1367                    }1368                    dashboardToSave.tabs.push({1369                        tabName: tabTitle,1370                        rowsRange: {1371                            sheetName: tabRowsRange.sheetName,1372                            firstCell: tabRowsRange.firstNumber,1373                            lastCell: tabRowsRange.lastNumber1374                        },1375                        hideCells: tabHideCell,1376                        colsRange: {1377                            sheetName: tabChartType === 'pie' ? null : tabColsRange.sheetName,1378                            firstCell: tabChartType === 'pie' ? null : tabColsRange.firstNumber,1379                            lastCell: tabChartType === 'pie' ? null : tabColsRange.lastNumber1380                        },1381                        valuesRange: {1382                            sheetName: tabValuesRange.sheetName,1383                            firstCell: tabValuesRange.firstNumber,1384                            lastCell: tabValuesRange.lastNumber1385                        },1386                        chartType: tabChartType1387                    });1388                }1389            }1390            DashboardFormService.saveDashboard(dashboardToSave).then(function(response) {1391                if (response.data.error === true) {1392                    swal("Error!", response.data.message, "error");1393                } else {1394                    swal("Success!", response.data.message, "success");1395                    if (response.data.data.uuid != null && response.data.data.uuid != "") {1396                        $UUID = response.data.data.uuid;1397                    }1398                    CoreCommonsService.askIfReload = false;1399                }1400            });1401        }1402        //********************************* Context Data *********************************************************1403        //************************************ Context Data ******************************************************1404        //*************************************** Context Data ***************************************************1405        function setContextData(type) {1406            var modelId = formCtrl.selectedModelID;1407            if (modelId === null || modelId === undefined) {1408                sweetAlert("Not selected Flat Form", "Please select Flat Form first");1409                return;1410            }1411            var selectedExpTree, selectedCallTree, selectedDataType, selectedCcTree;1412            var treesVisibility, modalTitle, checkboxState, tabIndex;1413            var multiple = false;1414            switch (type) {1415                case "account":1416                    selectedExpTree = [];1417                    modalTitle = "Choose Account Dimension";1418                    treesVisibility = [false, true, false, false];1419                    tabIndex = 0;1420                    break;1421                case "calendarfrom":1422                    selectedCallTree = [];1423                    modalTitle = "Choose Calendar Dimension (from...)";1424                    treesVisibility = [false, false, true, false];1425                    tabIndex = 1;1426                    break;1427                case "calendarto":1428                    selectedCallTree = [];1429                    modalTitle = "Choose Calendar Dimension (to...)";1430                    treesVisibility = [false, false, true, false];1431                    tabIndex = 1;1432                    break;1433                case "dataType":1434                    selectedDataType = [];1435                    modalTitle = "Choose Data Type";1436                    treesVisibility = [false, false, false, true];1437                    tabIndex = 2;1438                    break;1439                case "business":1440                    selectedCcTree = [];1441                    modalTitle = "Choose Business Dimension";1442                    treesVisibility = [true, false, false, false];1443                    tabIndex = 2;1444                    break;1445            }1446            if (type === "business") {1447                var modalInstance = $modal.open({1448                    template: '<business-chooser modal-title="modalTitle" selected-cc-tree="selectedCcTree" model-id="modelId" ok="ok()" close="close()"></business-chooser>',1449                    windowClass: 'sub-system-modals softpro-modals',1450                    backdrop: 'static',1451                    size: 'lg',1452                    controller: ['$scope', '$modalInstance',1453                        function($scope, $modalInstance) {1454                            $scope.modalTitle = "Choose Business Dimension";1455                            $scope.selectedCcTree = selectedCcTree;1456                            $scope.modelId = modelId;1457                            $scope.ok = function() {1458                                updateContextData($scope.selectedCcTree, "business");1459                                $scope.close();1460                            };1461                            $scope.close = function() {1462                                $modalInstance.dismiss('cancel');1463                            };1464                        }1465                    ]1466                });1467            } else {1468                var modalInstance = $modal.open({1469                    template: '<trees-chooser modal-title="modalTitle" selected-exp-tree="selectedExpTree" selected-call-tree="selectedCallTree" selected-data-type="selectedDataType" model-id="modelId" tab-index="tabIndex" multiple="multiple" ok="ok()" trees-visibility="treesVisibility" close="close()" checkbox-state="checkboxState"></trees-chooser>',1470                    windowClass: 'sub-system-modals softpro-modals',1471                    backdrop: 'static',1472                    size: 'lg',1473                    controller: ['$scope', '$modalInstance',1474                        function($scope, $modalInstance) {1475                            $scope.modalTitle = modalTitle;1476                            $scope.selectedExpTree = selectedExpTree;1477                            $scope.selectedCallTree = selectedCallTree;1478                            $scope.selectedDataType = selectedDataType;1479                            $scope.modelId = modelId;1480                            $scope.tabIndex = tabIndex;1481                            $scope.multiple = multiple;1482                            $scope.treesVisibility = treesVisibility;1483                            $scope.checkboxState = checkboxState;1484                            //formCtrl.multiple = true;1485                            $scope.ok = function() {1486                                var dimensions;1487                                switch (type) {1488                                    case "account":1489                                        updateContextData($scope.selectedExpTree, "account");1490                                        break;1491                                    case "calendarfrom":1492                                        updateContextData($scope.selectedCallTree, "calendarfrom");1493                                        break;1494                                    case "calendarto":1495                                        updateContextData($scope.selectedCallTree, "calendarto");1496                                        break;1497                                    case "dataType":1498                                        updateContextData($scope.selectedDataType, "dataType");1499                                        break;1500                                }1501                                $scope.close();1502                            };1503                            $scope.close = function() {1504                                $modalInstance.dismiss('cancel');1505                            };1506                        }1507                    ]1508                });1509            }1510        }1511        function updateContextData(dimensions, type) {1512            var str = "";1513            for (var i = 0; i < dimensions.length; i++) {1514                var dimension = dimensions[i];1515                if (type === "calendarfrom" || type === "calendarto") {1516                    if (dimension.parentVisId) {1517                        str += " /" + dimension.parentVisId + "/" + dimension.structureElementVisId;1518                    } else {1519                        str += " /" + dimension.structureElementVisId;1520                    }1521                } else {1522                    str += " " + dimension.structureElementVisId;1523                }1524                if (i !== dimensions.length - 1) {1525                    str += ",";1526                }1527            }1528            switch (type) {1529                case "account":1530                    if (str == "") {1531                        formCtrl.contextData.expTreeString = formCtrl.contextDataPlaceholder.account;1532                        formCtrl.xmlForm.properties.DIMENSION_1_VISID = null;1533                    } else {1534                        if (str != formCtrl.xmlForm.properties.DIMENSION_1_VISID) {1535                            toggleAskIfReload();1536                        }1537                        formCtrl.contextData.expTreeString = str;1538                        formCtrl.xmlForm.properties.DIMENSION_1_VISID = str.trim();1539                    }1540                    break;1541                case "calendarfrom":1542                    if (str == "") {1543                        formCtrl.contextData.callFromTreeString = formCtrl.contextDataPlaceholder.calendarfrom;1544                        formCtrl.xmlForm.properties.DIMENSION_2_VISID_FROM = null;1545                    } else {1546                        if (str != formCtrl.xmlForm.properties.DIMENSION_2_VISID_FROM) {1547                            toggleAskIfReload();1548                        }1549                        formCtrl.contextData.callFromTreeString = str;1550                        formCtrl.xmlForm.properties.DIMENSION_2_VISID_FROM = str.trim();1551                        if (formCtrl.contextData.callToTreeString === formCtrl.contextDataPlaceholder.calendarto) {1552                            formCtrl.contextData.callToTreeString = str;1553                            formCtrl.xmlForm.properties.DIMENSION_2_VISID_TO = str.trim();1554                        }1555                    }1556                    break;1557                case "calendarto":1558                    if (str == "") {1559                        formCtrl.contextData.callToTreeString = formCtrl.contextDataPlaceholder.calendarto;1560                        formCtrl.xmlForm.properties.DIMENSION_2_VISID_TO = null;1561                    } else {1562                        if (str != formCtrl.xmlForm.properties.DIMENSION_2_VISID_TO) {1563                            toggleAskIfReload();1564                        }1565                        formCtrl.contextData.callToTreeString = str;1566                        formCtrl.xmlForm.properties.DIMENSION_2_VISID_TO = str.trim();1567                        if (formCtrl.contextData.callFromTreeString === formCtrl.contextDataPlaceholder.calendarfrom) {1568                            formCtrl.contextData.callFromTreeString = str;1569                            formCtrl.xmlForm.properties.DIMENSION_2_VISID_FROM = str.trim();1570                        }1571                    }1572                    break;1573                case "dataType":1574                    if (str == "") {1575                        formCtrl.contextData.dataTypeString = formCtrl.contextDataPlaceholder.dataType;1576                        formCtrl.xmlForm.properties.DATA_TYPE = null;1577                    } else {1578                        if (str != formCtrl.xmlForm.properties.DATA_TYPE) {1579                            toggleAskIfReload();1580                        }1581                        formCtrl.contextData.dataTypeString = str;1582                        formCtrl.xmlForm.properties.DATA_TYPE = str.trim();1583                    }1584                    break;1585                case "business":1586                    if (str == "") {1587                        formCtrl.contextData.ccTreeString = formCtrl.contextDataPlaceholder.business;1588                        formCtrl.xmlForm.properties.DIMENSION_0_VISID = null;1589                    } else {1590                        if (str != formCtrl.xmlForm.properties.DIMENSION_0_VISID) {1591                            toggleAskIfReload();1592                        }1593                        formCtrl.contextData.ccTreeString = str;1594                        formCtrl.xmlForm.properties.DIMENSION_0_VISID = str.trim();1595                    }1596                    break;1597            }1598            if (ISEDIT === formCtrl.views.open) {1599                testDashboard();1600            }1601        }1602    }...w5cValidator.js
Source:w5cValidator.js  
1/*! ng-w5c-validator v2.4.25 2017-03-06 */2(function(){3    var w5cValidator = angular.module("w5c.validator", ["ng"])4        .provider('w5cValidator', [function () {5            var defaultRules = {6                    required      : "该é项ä¸è½ä¸ºç©º",7                    maxlength     : "该é项è¾å
¥å¼é¿åº¦ä¸è½å¤§äº{maxlength}",8                    minlength     : "该é项è¾å
¥å¼é¿åº¦ä¸è½å°äº{minlength}",9                    email         : "è¾å
¥é®ä»¶çæ ¼å¼ä¸æ£ç¡®",10                    repeat        : "两次è¾å
¥ä¸ä¸è´",11                    pattern       : "该é项è¾å
¥æ ¼å¼ä¸æ£ç¡®",12                    number        : "å¿
é¡»è¾å
¥æ°å",13                    w5cuniquecheck: "该è¾å
¥å¼å·²ç»åå¨ï¼è¯·éæ°è¾å
¥",14                    url           : "è¾å
¥URLæ ¼å¼ä¸æ£ç¡®",15                    max           : "该é项è¾å
¥å¼ä¸è½å¤§äº{max}",16                    min           : "该é项è¾å
¥å¼ä¸è½å°äº{min}",17                    customizer    : "èªå®ä¹éªè¯ä¸éè¿"18                },19                elemTypes = ['text', 'password', 'email', 'number', 'url', 'tel', 'hidden', ['textarea'], ['select'], ['select-multiple'], ['select-one'], 'radio', 'checkbox'];20            var getParentGroup = function (elem) {21                if (elem[0].tagName === "FORM" || elem[0].nodeType == 11) {22                    return null;23                }24                if (elem && elem.hasClass("form-group")) {25                    return elem;26                } else {27                    return getParentGroup(elem.parent())28                }29            };30            var validatorFn = function () {31                this.elemTypes = elemTypes;32                this.rules = {};33                this.isEmpty = function (object) {34                    if (!object) {35                        return true;36                    }37                    if (object instanceof Array && object.length === 0) {38                        return true;39                    }40                    return false;41                };42                this.defaultShowError = function (elem, errorMessages) {43                    var $elem = angular.element(elem),44                        $group = getParentGroup($elem);45                    if (!this.isEmpty($group) && !$group.hasClass("has-error")) {46                        $group.addClass("has-error");47                    }48                    var $next = $elem.next();49                    if (!$next || !$next.hasClass("w5c-error")) {50                        $elem.after('<span class="w5c-error">' + errorMessages[0] + '</span>');51                    }52                };53                this.defaultRemoveError = function (elem) {54                    var $elem = angular.element(elem),55                        $group = getParentGroup($elem);56                    if (!this.isEmpty($group) && $group.hasClass("has-error")) {57                        $group.removeClass("has-error");58                    }59                    var $next = $elem.next();60                    if ($next.hasClass && $next.hasClass("w5c-error")) {61                        $next.remove();62                    }63                };64                this.options = {65                    blurTrig   : false,66                    showError  : true,67                    removeError: true68                }69            };70            validatorFn.prototype = {71                constructor     : validatorFn,72                config          : function (options) {73                    this.options = angular.extend(this.options, options);74                },75                setRules        : function (rules) {76                    this.rules = angular.extend(this.rules, rules);77                },78                getErrorMessage : function (validationName, elem) {79                    var msgTpl = null, elementName = elem.name;80                    if (elementName && /\$\d+\$/i.test(elementName)) {81                        elementName = elementName.replace(/\$\d+\$/i, '');82                    }83                    if (!this.isEmpty(this.rules[elementName]) && !this.isEmpty(this.rules[elementName][validationName])) {84                        msgTpl = this.rules[elementName][validationName];85                    }86                    switch (validationName) {87                        case "maxlength":88                            return (msgTpl || defaultRules.maxlength).replace("{maxlength}", elem.getAttribute("ng-maxlength"));89                            break;90                        case "minlength":91                            return (msgTpl || defaultRules.minlength).replace("{minlength}", elem.getAttribute("ng-minlength"));92                            break;93                        case "max":94                            return (msgTpl || defaultRules.max).replace("{max}", elem.getAttribute("max"));95                            break;96                        case "min":97                            return (msgTpl || defaultRules.min).replace("{min}", elem.getAttribute("min"));98                        default :99                        {100                            if (msgTpl !== null) {101                                return msgTpl;102                            }103                            if (defaultRules[validationName] === null) {104                                throw new Error("该éªè¯è§å(" + validationName + ")é»è®¤éè¯¯ä¿¡æ¯æ²¡æè®¾ç½®ï¼");105                            }106                            return defaultRules[validationName];107                        }108                    }109                },110                getErrorMessages: function (elem, errors) {111                    var elementErrors = [];112                    for (var err in errors) {113                        if (errors[err]) {114                            var msg = this.getErrorMessage(err, elem);115                            elementErrors.push(msg);116                        }117                    }118                    return elementErrors;119                },120                showError       : function (elem, errorMessages, options) {121                    var useOptions = angular.extend({}, this.options, options);122                    angular.element(elem).removeClass("valid").addClass("error");123                    if (useOptions.showError === false) {124                        return;125                    }126                    if (angular.isFunction(useOptions.showError)) {127                        return useOptions.showError(elem, errorMessages);128                    }129                    if (useOptions.showError === true) {130                        return this.defaultShowError(elem, errorMessages);131                    }132                },133                removeError     : function (elem, options) {134                    var useOptions = angular.extend({}, this.options, options);135                    angular.element(elem).removeClass("error").addClass("valid");136                    if (useOptions.removeError === false) {137                        return;138                    }139                    if (angular.isFunction(useOptions.removeError)) {140                        return useOptions.removeError(elem);141                    }142                    if (useOptions.removeError === true) {143                        return this.defaultRemoveError(elem);144                    }145                }146            };147            var validator = new validatorFn();148            /**149             * é
ç½®éªè¯å±æ§150             * @param options151             */152            this.config = function (options) {153                validator.config(options);154            };155            /**156             * 设置éªè¯è§åï¼æç¤ºä¿¡æ¯157             * @param rules158             */159            this.setRules = function (rules) {160                validator.setRules(rules);161            };162            /**163             * 设置é»è®¤è§å164             * @param rules165             */166            this.setDefaultRules = function (rules) {167                defaultRules = angular.extend(defaultRules, rules);168            };169            /**170             * get method171             * @returns {validatorFn}172             */173            this.$get = function () {174                return validator;175            }176        }]);177    /* commonjs package manager support (eg componentjs) */178    if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){179        module.exports = w5cValidator.name;180    }181})();182(function () {183    angular.module("w5c.validator")184        .directive("w5cFormValidate", [185            '$parse', 'w5cValidator', '$timeout',186            function ($parse, w5cValidator, $timeout) {187                return {188                    require   : ['w5cFormValidate', '^?form'],189                    controller: [190                        '$scope', '$element', '$attrs',191                        function ($scope, $element, $attrs) {192                            var _self = this;193                            var _formElem = $element[0];194                            this.needBindKeydown = false;195                            this.formCtrl = null;196                            this.submitSuccessFn = null;197                            this.validElements = [];198                            /**199                             * 设置éªè¯æ¹æ³,å¹¶æ doValidate æ¹æ³æè½½å¨ form ctrl ä¸200                             * @param formCtrl201                             */202                            this.setValidate = function (formCtrl) {203                                this.formCtrl = formCtrl;204                                var doValidate = function () {205                                    var errorMessages = [];206                                    //循ç¯éªè¯207                                    for (var i = 0; i < _formElem.elements.length; i++) {208                                        var elemName = _formElem.elements[i].name;209                                        if (elemName && _self.validElements.indexOf(elemName) >= 0) {210                                            var elem = _formElem[elemName];211                                            if (formCtrl[elemName] && elem && w5cValidator.elemTypes.toString().indexOf(elem.type) > -1 && !w5cValidator.isEmpty(elemName)) {212                                                if (formCtrl[elemName].$valid) {213                                                    angular.element(elem).removeClass("error").addClass("valid");214                                                    continue;215                                                } else {216                                                    var elementErrors = w5cValidator.getErrorMessages(elem, formCtrl[elem.name].$error);217                                                    errorMessages.push(elementErrors[0]);218                                                    w5cValidator.removeError(elem, _self.options);219                                                    w5cValidator.showError(elem, elementErrors, _self.options);220                                                    formCtrl[elemName].w5cError = true;221                                                }222                                            }223                                        }224                                    }225                                    if (!w5cValidator.isEmpty(errorMessages) && errorMessages.length > 0) {226                                        formCtrl.$errors = errorMessages;227                                    } else {228                                        formCtrl.$errors = [];229                                    }230                                    if (!$scope.$$phase) {231                                        $scope.$apply(formCtrl.$errors);232                                    }233                                };234                                formCtrl.doValidate = doValidate;235                                formCtrl.reset = function () {236                                    $timeout(function () {237                                        formCtrl.$setPristine();238                                        for (var i = 0; i < _formElem.elements.length; i++) {239                                            var elem = _formElem.elements[i];240                                            var $elem = angular.element(elem);241                                            w5cValidator.removeError($elem, _self.options);242                                        }243                                        formCtrl.$errors = [];244                                    });245                                };246                                //w5cSubmit is function247                                var formSubmitFn = $parse($attrs.w5cSubmit);248                                if ($attrs.w5cSubmit && angular.isFunction(formSubmitFn)) {249                                    $element.bind("submit", function (event) {250                                        doValidate();251                                        if (formCtrl.$valid && angular.isFunction(formSubmitFn)) {252                                            $scope.$apply(function () {253                                                formSubmitFn($scope, {$event: event});254                                            });255                                        }256                                    });257                                    //_self.submitSuccessFn = formSubmitFn;258                                    this.needBindKeydown = true;259                                }260                                if (this.needBindKeydown) {261                                    $element.bind("keydown keypress", function (event) {262                                        if (event.which === 13) {263                                            var currentInput = document.activeElement;264                                            if (currentInput.type && currentInput.type !== "textarea") {265                                                var button = $element.find("button");266                                                if (button && button[0]) {267                                                    button[0].focus();268                                                }269                                                currentInput.focus();270                                                doValidate();271                                                event.preventDefault();272                                                if (formCtrl.$valid && angular.isFunction(_self.submitSuccessFn)) {273                                                    $scope.$apply(function () {274                                                        _self.submitSuccessFn($scope, {$event: event});275                                                    });276                                                }277                                            }278                                        }279                                    });280                                }281                            };282                            /**283                             * ç¨æ·åå
¶ä»ç»ä»¶äº¤äºä½¿ç¨, ç®åæ w5cFormSubmitåw5cDynamicElement æä»¤è°ç¨284                             * @param success éªè¯æååè°ç¨å½æ°285                             * @param event äºä»¶åè°286                             */287                            this.doValidate = function (success, event) {288                                if (angular.isFunction(this.formCtrl.doValidate)) {289                                    this.formCtrl.doValidate();290                                }291                                if (this.formCtrl.$valid && angular.isFunction(success)) {292                                    $scope.$apply(function () {293                                        success($scope, {$event: event});294                                    });295                                }296                            };297                            /**298                             * æ ¹æ® name ç§»é¤æä¸ªå
ç´ çéªè¯299                             * @param name300                             */301                            this.removeElementValidation = function (name) {302                                var index = this.validElements.indexOf(name);303                                if (index >= 0) {304                                    this.validElements.splice(index, 1);305                                    if (!w5cValidator.isEmpty(this.formCtrl.$errors)) {306                                        this.doValidate(angular.noop);307                                    }308                                }309                            };310                            /**311                             * æ ¹æ®$elementç§»é¤æä¸ªå
ç´ çé误信æ¯312                             * @param $elem313                             */314                            this.removeError = function ($elem) {315                                this.formCtrl.$errors = [];316                                this.formCtrl[$elem[0].name] && (this.formCtrl[$elem[0].name].w5cError = false);317                                w5cValidator.removeError($elem, this.options);318                            };319                            /**320                             * åå§åå
ç´ çéªè¯321                             * @param elem322                             */323                            this.initElement = function (elem) {324                                var $elem = angular.element(elem);325                                var ctrl = this;326                                if (w5cValidator.elemTypes.toString().indexOf(elem.type) > -1 && !w5cValidator.isEmpty(elem.name) && !/^\d/.test(elem.name)) {327                                    var disabled = $elem.attr('disabled');328                                    if (disabled && (disabled === 'true' || disabled === 'disabled')) {329                                        return;330                                    }331                                    //formCtrl[elem.name].$viewChangeListeners.push(function () {332                                    //    formCtrl.$errors = [];333                                    //    w5cValidator.removeError($elem, options);334                                    //});335                                    if (this.validElements.indexOf(elem.name) < 0) {336                                        this.validElements.push(elem.name);337                                    } else {338                                        return;339                                    }340                                    var $viewValueName = this.formName + "." + elem.name + ".$viewValue";341                                    //çæ§è¾å
¥æ¡çvalueå¼å½æååæ¶ç§»é¤é误信æ¯342                                    //å¯ä»¥ä¿®æ¹æå½è¾å
¥æ¡éªè¯éè¿æ¶æç§»é¤é误信æ¯ï¼åªè¦çæ§$valid屿§å³å¯343                                    $scope.$watch($viewValueName, function () {344                                        ctrl.removeError($elem);345                                    }, true);346                                    //å
æ ç§»èµ°çæ¶å触åéªè¯ä¿¡æ¯347                                    if (ctrl.options && ctrl.options.blurTrig) {348                                        $elem.bind("blur", function () {349                                            if (!ctrl.options.blurTrig) {350                                                return;351                                            }352                                            var element = this;353                                            var $elem = angular.element(this);354                                            $timeout(function () {355                                                if (!_self.formCtrl[element.name].$valid) {356                                                    var errorMessages = w5cValidator.getErrorMessages(element, _self.formCtrl[element.name].$error);357                                                    w5cValidator.showError($elem, errorMessages, _self.options);358                                                    if (_self.formCtrl[$elem[0].name]) {359                                                        _self.formCtrl[$elem[0].name].w5cError = true;360                                                    }361                                                } else {362                                                    w5cValidator.removeError($elem, _self.options);363                                                }364                                            }, 50);365                                        });366                                    }367                                }368                            };369                            /**370                             * åå§åforméªè¯åæ°åå
é¨å
ç´ 371                             * @private372                             */373                            this._init = function () {374                                this.formName = $element.attr("name");375                                if (!this.formName) {376                                    throw Error("form must has name when use w5cFormValidate");377                                }378                                var options = $scope.$eval($attrs.w5cFormValidate);379                                if ($attrs.w5cFormValidate) {380                                    $scope.$watch($attrs.w5cFormValidate, function (newValue) {381                                        if (newValue) {382                                            _self.options = options = angular.extend({}, w5cValidator.options, newValue);383                                        }384                                    }, true)385                                }386                                this.options = angular.extend({}, w5cValidator.options, options);387                                //åå§åéªè¯è§åï¼å¹¶æ¶æ¶çæ§è¾å
¥å¼çåè¯388                                for (var i = 0; i < $element[0].elements.length; i++) {389                                    this.initElement($element[0].elements[i]);390                                }391                            };392                            this._init();393                        }],394                    link      : function (scope, form, attr, ctrls) {395                        var ctrl = ctrls[0], formCtrl = ctrls[1];396                        ctrl.setValidate(formCtrl);397                    }398                };399            }])400        .directive("w5cFormSubmit", ['$parse', function ($parse) {401            return {402                require: "^w5cFormValidate",403                link   : function (scope, element, attr, ctrl) {404                    var validSuccessFn = $parse(attr.w5cFormSubmit);405                    element.bind("click", function (event) {406                        ctrl.doValidate(validSuccessFn, event);407                    });408                    ctrl.needBindKeydown = true;409                    ctrl.submitSuccessFn = validSuccessFn;410                }411            };412        }])413        .directive("w5cRepeat", ['$timeout', function ($timeout) {414            'use strict';415            return {416                require: ["ngModel", "^w5cFormValidate"],417                link   : function (scope, elem, attrs, ctrls) {418                    $timeout(function () {419                        var otherInput = elem.inheritedData("$formController")[attrs.w5cRepeat];420                        var ngModel = ctrls[0], w5cFormCtrl = ctrls[1];421                        ngModel.$parsers.push(function (value) {422                            if (value === otherInput.$viewValue) {423                                ngModel.$setValidity("repeat", true);424                            } else {425                                ngModel.$setValidity("repeat", false);426                            }427                            return value;428                        });429                        otherInput.$parsers.push(function (value) {430                            ngModel.$setValidity("repeat", value === ngModel.$viewValue);431                            if (value === ngModel.$viewValue) {432                                w5cFormCtrl.removeError(elem);433                            }434                            return value;435                        });436                    });437                }438            };439        }])440        .directive("w5cCustomizer", ['$timeout', function ($timeout) {441            'use strict';442            return {443                require: ["^form", "?ngModel"],444                link   : function (scope, elem, attrs, ctrls) {445                    var ngModelCtrl = ctrls[1];446                    var $validate = function () {447                        var validate = scope.$eval(attrs.w5cCustomizer);448                        if (validate === true) {449                            ngModelCtrl.$setValidity("customizer", true);450                        } else {451                            ngModelCtrl.$setValidity("customizer", false);452                        }453                    };454                    var associate = ctrls[0][attrs.associate];455                    associate && associate.$viewChangeListeners.push($validate);456                    ngModelCtrl.$viewChangeListeners.push($validate);457                    $validate();458                }459            };460        }])461        .directive("w5cUniqueCheck", ['$timeout', '$http', 'w5cValidator', function ($timeout, $http, w5cValidator) {462            return {463                require: ["ngModel", "?^w5cFormValidate", "?^form"],464                link   : function (scope, elem, attrs, ctrls) {465                    var ngModelCtrl = ctrls[0], w5cFormCtrl = ctrls[1], formCtrl = ctrls[2];466                    var doValidate = function () {467                        var attValues = scope.$eval(attrs.w5cUniqueCheck);468                        var url = attValues.url;469                        var isExists = attValues.isExists;//default is true470                        $http.get(url).success(function (data) {471                            var state = isExists === false ? (data == 'true' || data == true) : !(data == 'true' || data == true);472                            ngModelCtrl.$setValidity('w5cuniquecheck', state);473                            if (!state) {474                                var errorMsg = w5cValidator.getErrorMessage("w5cuniquecheck", elem[0]);475                                w5cValidator.showError(elem[0], [errorMsg], w5cFormCtrl.options);476                                if (formCtrl[elem[0].name]) {477                                    formCtrl[elem[0].name].w5cError = true;478                                }479                                if (!formCtrl.$errors) {480                                    formCtrl.$errors = [errorMsg];481                                } else {482                                    formCtrl.$errors.unshift(errorMsg);483                                }484                            }485                        });486                    };487                    ngModelCtrl.$viewChangeListeners.push(function () {488                        formCtrl.$errors = [];489                        ngModelCtrl.$setValidity('w5cuniquecheck', true);490                        if (ngModelCtrl.$invalid && !ngModelCtrl.$error.w5cuniquecheck) {491                            return;492                        }493                        if (ngModelCtrl.$dirty) {494                            doValidate();495                        }496                    });497                    var firstValue = scope.$eval(attrs.ngModel);498                    if (firstValue) {499                        if (ngModelCtrl.$invalid && !ngModelCtrl.$error.w5cuniquecheck) {500                            return;501                        }502                        doValidate();503                    }504                }505            };506        }])507        .directive('w5cDynamicName', [function () {508            return {509                restrict: 'A',510                require : "?ngModel",511                link    : function (scope, elm, attrs, ngModelCtr) {512                    var _name = scope.$eval(attrs.w5cDynamicName) || attrs.w5cDynamicName;513                    if (_name) {514                        ngModelCtr.$name = _name;515                        elm.attr('name', _name);516                        var _formController = elm.controller('form') || {517                                $addControl: angular.noop518                            };519                        _formController.$addControl(ngModelCtr);520                    }521                }522            };523        }])524        .directive('w5cDynamicElement', ["$timeout", function ($timeout) {525            return {526                restrict: 'A',527                require : ["?ngModel", "?^w5cFormValidate", "?^form"],528                link    : function (scope, elm, attrs, ctrls) {529                    var name = elm[0].name, formCtrl = ctrls[2];530                    if (name) {531                        elm.on("$destroy", function (e) {532                            // if formCtrl is destroyed No need to do anything533                            if (scope[formCtrl.$name]) {534                                ctrls[1].removeElementValidation(name);535                            }536                        });537                        if (!formCtrl[name]) {538                            formCtrl.$addControl(ctrls[0]);539                        }540                        var needValidate = false;541                        if (ctrls[2].$errors && ctrls[2].$errors.length > 0) {542                            needValidate = true;543                        }544                        ctrls[1].initElement(elm[0]);545                        if (needValidate) {546                            $timeout(function () {547                                ctrls[1].doValidate(angular.noop);548                            });549                        }550                    }551                }552            };553        }]);...directive.js
Source:directive.js  
1(function () {2    function W5cFormValidateCtrl($scope, $element, $attrs, w5cValidator, $parse, $timeout) {3        var _self = this;4        var _formElem = $element[0];5        this.formCtrl = null;6        // Enter é®æäº¤7        this.needBindKeydown = false;8        this.enterKeydownFn = null;9        this.validElements = [];10        this.setElementErrorMessage = function (elemName, errorMessage) {11            var self = this;12            var elem = _formElem[elemName];13            if (elemName && self.validElements.indexOf(elemName) >= 0) {14                w5cValidator.removeError(elem, self.options);15                w5cValidator.showError(elem, [errorMessage], self.options);16            }17        };18        this.validateFormElement = function (elemName) {19            var self = this;20            var elem = _formElem[elemName];21            if (elemName && self.validElements.indexOf(elemName) >= 0) {22                if (self.formCtrl[elemName] && elem && w5cValidator.elemTypes.toString().indexOf(elem.type) > -1 && !w5cValidator.isEmpty(elemName)) {23                    if (self.formCtrl[elemName].$valid) {24                        w5cValidator.removeError(elem, self.options);25                        self.formCtrl[elemName].w5cError = false;26                    } else {27                        var elementErrors = w5cValidator.getErrorMessages(elem, self.formCtrl[elem.name].$error);28                        w5cValidator.removeError(elem, self.options);29                        w5cValidator.showError(elem, elementErrors, self.options);30                        self.formCtrl[elemName].w5cError = true;31                        return elementErrors;32                    }33                }34            }35            return null;36        };37        this.validateForm = function () {38            var self = this;39            var formCtrl = this.formCtrl;40            var errorMessages = [];41            //循ç¯éªè¯42            for (var i = 0; i < _formElem.elements.length; i++) {43                var elementErrorMessages = self.validateFormElement(_formElem.elements[i].name);44                if (elementErrorMessages && elementErrorMessages.length >= 1) {45                    errorMessages.push(elementErrorMessages[0])46                }47            }48            if (!w5cValidator.isEmpty(errorMessages) && errorMessages.length > 0) {49                formCtrl.$errors = errorMessages;50            } else {51                formCtrl.$errors = [];52            }53            if (!$scope.$$phase) {54                $scope.$apply(formCtrl.$errors);55            }56        };57        /**58         * 设置éªè¯æ¹æ³,å¹¶æ doValidate æ¹æ³æè½½å¨ form ctrl ä¸59         * @param formCtrl60         */61        this.setValidate = function (formCtrl) {62            this.formCtrl = formCtrl;63            var doValidate = formCtrl.doValidate = this.validateForm.bind(this);64            formCtrl.validateElement = this.validateFormElement.bind(this);65            formCtrl.setElementErrorMessage = this.setElementErrorMessage.bind(this);66            formCtrl.reset = function () {67                $timeout(function () {68                    formCtrl.$setPristine();69                    for (var i = 0; i < _formElem.elements.length; i++) {70                        var elem = _formElem.elements[i];71                        var $elem = angular.element(elem);72                        w5cValidator.removeError($elem, _self.options);73                    }74                    formCtrl.$errors = [];75                });76            };77            //w5cSubmit is function78            var formSubmitFn = $parse($attrs.w5cSubmit);79            if ($attrs.w5cSubmit && angular.isFunction(formSubmitFn)) {80                $element.bind("submit", function (event) {81                    doValidate();82                    if (formCtrl.$valid && angular.isFunction(formSubmitFn)) {83                        $scope.$apply(function () {84                            formSubmitFn($scope, {$event: event});85                        });86                    }87                });88                //_self.submitSuccessFn = formSubmitFn;89                this.needBindKeydown = true;90            }91            if (this.needBindKeydown) {92                $element.bind("keydown keypress", function (event) {93                    if (event.which === 13) {94                        var currentInput = document.activeElement;95                        if (currentInput.type && currentInput.type !== "textarea") {96                            var button = $element.find("button");97                            if (button && button[0]) {98                                button[0].focus();99                            }100                            currentInput.focus();101                            event.preventDefault();102                            if(angular.isFunction(_self.enterKeydownFn)){103                                _self.enterKeydownFn(event);104                            }105                            //106                            // if (formCtrl.$valid && angular.isFunction(_self.submitSuccessFn)) {107                            //     $scope.$apply(function () {108                            //         _self.submitSuccessFn($scope, {$event: event});109                            //     });110                            // }111                        }112                    }113                });114            }115        };116        /**117         * ç¨æ·åå
¶ä»ç»ä»¶äº¤äºä½¿ç¨, ç®åæ w5cFormSubmitåw5cDynamicElement æä»¤è°ç¨118         * @param success éªè¯æååè°ç¨å½æ°119         * @param event äºä»¶åè°120         */121        this.doValidate = function (success, error) {122            var self = this;123            if (angular.isFunction(self.formCtrl.doValidate)) {124                self.formCtrl.doValidate();125            }126            if (self.formCtrl.$valid && angular.isFunction(success)) {127                $scope.$apply(function () {128                    success();129                });130            } else if (!self.formCtrl.$valid && angular.isFunction(error)) {131                var invalidElements = self._getInvalidElements();132                $scope.$apply(function () {133                    error(self.formCtrl.$errors, invalidElements);134                });135            }136        };137        this._getInvalidElements = function () {138            var invalidElements = [];139            for (var i = 0; i < $element[0].elements.length; i++) {140                var element = $element[0].elements[i];141                if (this.validElements.indexOf(element.name) >= 0142                    && this.formCtrl[element.name]143                    && this.formCtrl[element.name].$invalid) {144                    invalidElements.push(element);145                }146            }147            return invalidElements;148        };149        /**150         * æ ¹æ® name ç§»é¤æä¸ªå
ç´ çéªè¯151         * @param name152         */153        this.removeElementValidation = function (name) {154            var index = this.validElements.indexOf(name);155            if (index >= 0) {156                this.validElements.splice(index, 1);157                if (!w5cValidator.isEmpty(this.formCtrl.$errors)) {158                    this.doValidate(angular.noop);159                }160            }161        };162        /**163         * æ ¹æ®$elementç§»é¤æä¸ªå
ç´ çé误信æ¯164         * @param $elem165         */166        this.removeError = function ($elem) {167            this.formCtrl.$errors = [];168            this.formCtrl[$elem[0].name] && (this.formCtrl[$elem[0].name].w5cError = false);169            w5cValidator.removeError($elem, this.options);170        };171        /**172         * åå§åå
ç´ çéªè¯173         * @param elem174         */175        this.initElement = function (elem) {176            var $elem = angular.element(elem);177            var ctrl = this;178            if (w5cValidator.elemTypes.toString().indexOf(elem.type) > -1 && !w5cValidator.isEmpty(elem.name) && !/^\d/.test(elem.name)) {179                var disabled = $elem.attr('disabled');180                if (disabled && (disabled === 'true' || disabled === 'disabled')) {181                    return;182                }183                //formCtrl[elem.name].$viewChangeListeners.push(function () {184                //    formCtrl.$errors = [];185                //    w5cValidator.removeError($elem, options);186                //});187                if (this.validElements.indexOf(elem.name) < 0) {188                    this.validElements.push(elem.name);189                } else {190                    return;191                }192                var $viewValueName = this.formName + "." + elem.name + ".$viewValue";193                //çæ§è¾å
¥æ¡çvalueå¼å½æååæ¶ç§»é¤é误信æ¯194                //å¯ä»¥ä¿®æ¹æå½è¾å
¥æ¡éªè¯éè¿æ¶æç§»é¤é误信æ¯ï¼åªè¦çæ§$valid屿§å³å¯195                $scope.$watch($viewValueName, function () {196                    ctrl.removeError($elem);197                }, true);198                //å
æ ç§»èµ°çæ¶å触åéªè¯ä¿¡æ¯199                if (ctrl.options && ctrl.options.blurTrig) {200                    $elem.bind("blur", function () {201                        if (!ctrl.options.blurTrig) {202                            return;203                        }204                        var element = this;205                        $timeout(function () {206                            ctrl.validateFormElement(element.name);207                            // if (!_self.formCtrl[element.name].$valid) {208                            //     var errorMessages = w5cValidator.getErrorMessages(element, _self.formCtrl[element.name].$error);209                            //     w5cValidator.showError($elem, errorMessages, _self.options);210                            //     if (_self.formCtrl[$elem[0].name]) {211                            //         _self.formCtrl[$elem[0].name].w5cError = true;212                            //     }213                            // } else {214                            //     w5cValidator.removeError($elem, _self.options);215                            // }216                        }, 50);217                    });218                }219            }220        };221        /**222         * åå§åforméªè¯åæ°åå
é¨å
ç´ 223         * @private224         */225        this._init = function () {226            this.formName = $element.attr("name");227            if (!this.formName) {228                throw Error("form must has name when use w5cFormValidate");229            }230            var options = $scope.$eval($attrs.w5cFormValidate);231            if ($attrs.w5cFormValidate) {232                $scope.$watch($attrs.w5cFormValidate, function (newValue) {233                    if (newValue) {234                        _self.options = options = angular.extend({}, w5cValidator.options, newValue);235                    }236                }, true)237            }238            this.options = angular.extend({}, w5cValidator.options, options);239            //åå§åéªè¯è§åï¼å¹¶æ¶æ¶çæ§è¾å
¥å¼çåè¯240            for (var i = 0; i < $element[0].elements.length; i++) {241                this.initElement($element[0].elements[i]);242            }243        };244        this._init();245    }246    angular.module("w5c.validator")247        .directive("w5cFormValidate", [function () {248                return {249                    require: ['w5cFormValidate', '^?form'],250                    controller: [251                        '$scope',252                        '$element',253                        '$attrs',254                        'w5cValidator',255                        '$parse',256                        '$timeout',257                        W5cFormValidateCtrl258                    ],259                    link: function (scope, form, attr, ctrls) {260                        var ctrl = ctrls[0], formCtrl = ctrls[1];261                        ctrl.setValidate(formCtrl);262                    }263                };264            }])265        .directive("w5cFormSubmit", ['$parse', function ($parse) {266            return {267                require: "^w5cFormValidate",268                link: function (scope, element, attr, ctrl) {269                    var validSuccessFn = $parse(attr.w5cFormSubmit);270                    var errorCallback = $parse(attr.errorCallback);271                    var submitFn = function (event) {272                        ctrl.doValidate(function () {273                            validSuccessFn(scope, {$event: event});274                        }, function ($errors, invalidElements) {275                            if (errorCallback) {276                                errorCallback(scope, {277                                    $event: event,278                                    $errors: $errors,279                                    $invalidElements: invalidElements280                                });281                            }282                        });283                    };284                    element.bind("click", submitFn);285                    ctrl.needBindKeydown = true;286                    ctrl.enterKeydownFn = submitFn;287                }288            };289        }])290        .directive("w5cRepeat", ['$timeout', function ($timeout) {291            'use strict';292            return {293                require: ["ngModel", "^w5cFormValidate"],294                link: function (scope, elem, attrs, ctrls) {295                    $timeout(function () {296                        var otherInput = elem.inheritedData("$formController")[attrs.w5cRepeat];297                        var ngModel = ctrls[0], w5cFormCtrl = ctrls[1];298                        ngModel.$parsers.push(function (value) {299                            if (value === otherInput.$modelValue) {300                                ngModel.$setValidity("repeat", true);301                            } else {302                                ngModel.$setValidity("repeat", false);303                            }304                            return value;305                        });306                        otherInput.$parsers.push(function (value) {307                            ngModel.$setValidity("repeat", value === ngModel.$modelValue);308                            if (value === ngModel.$modelValue) {309                                w5cFormCtrl.removeError(elem);310                            }311                            return value;312                        });313                    });314                }315            };316        }])317        .directive("w5cCustomizer", ['$timeout', function ($timeout) {318            'use strict';319            return {320                require: ["^form", "?ngModel"],321                link: function (scope, elem, attrs, ctrls) {322                    var ngModelCtrl = ctrls[1];323                    var $validate = function () {324                        var validate = scope.$eval(attrs.w5cCustomizer);325                        if (validate === true) {326                            ngModelCtrl.$setValidity("customizer", true);327                        } else {328                            ngModelCtrl.$setValidity("customizer", false);329                        }330                    };331                    var associate = ctrls[0][attrs.associate];332                    associate && associate.$viewChangeListeners.push($validate);333                    ngModelCtrl.$viewChangeListeners.push($validate);334                    $validate();335                }336            };337        }])338        .directive("w5cUniqueCheck", ['$timeout', '$http', 'w5cValidator', function ($timeout, $http, w5cValidator) {339            return {340                require: ["ngModel", "?^w5cFormValidate", "?^form"],341                link: function (scope, elem, attrs, ctrls) {342                    var ngModelCtrl = ctrls[0], w5cFormCtrl = ctrls[1], formCtrl = ctrls[2];343                    var doValidate = function () {344                        var attValues = scope.$eval(attrs.w5cUniqueCheck);345                        var url = attValues.url;346                        var isExists = attValues.isExists;//default is true347                        $http.get(url).success(function (data) {348                            var state = isExists === false ? (data == 'true' || data == true) : !(data == 'true' || data == true);349                            ngModelCtrl.$setValidity('w5cuniquecheck', state);350                            if (!state) {351                                var errorMsg = w5cValidator.getErrorMessage("w5cuniquecheck", elem[0]);352                                w5cValidator.showError(elem[0], [errorMsg], w5cFormCtrl.options);353                                if (formCtrl[elem[0].name]) {354                                    formCtrl[elem[0].name].w5cError = true;355                                }356                                if (!formCtrl.$errors) {357                                    formCtrl.$errors = [errorMsg];358                                } else {359                                    formCtrl.$errors.unshift(errorMsg);360                                }361                            }362                        });363                    };364                    ngModelCtrl.$viewChangeListeners.push(function () {365                        formCtrl.$errors = [];366                        ngModelCtrl.$setValidity('w5cuniquecheck', true);367                        if (ngModelCtrl.$invalid && !ngModelCtrl.$error.w5cuniquecheck) {368                            return;369                        }370                        if (ngModelCtrl.$dirty) {371                            doValidate();372                        }373                    });374                    var firstValue = scope.$eval(attrs.ngModel);375                    if (firstValue) {376                        if (ngModelCtrl.$invalid && !ngModelCtrl.$error.w5cuniquecheck) {377                            return;378                        }379                        doValidate();380                    }381                }382            };383        }])384        .directive('w5cDynamicName', [function () {385            return {386                restrict: 'A',387                require: "?ngModel",388                link: function (scope, elm, attrs, ngModelCtr) {389                    var _name = scope.$eval(attrs.w5cDynamicName) || attrs.w5cDynamicName;390                    if (_name) {391                        ngModelCtr.$name = _name;392                        elm.attr('name', _name);393                        var _formController = elm.controller('form') || {394                                $addControl: angular.noop395                            };396                        _formController.$addControl(ngModelCtr);397                    }398                }399            };400        }])401        .directive('w5cDynamicElement', ["$timeout", function ($timeout) {402            return {403                restrict: 'A',404                require: ["?ngModel", "?^w5cFormValidate", "?^form"],405                link: function (scope, elm, attrs, ctrls) {406                    var name = elm[0].name, formCtrl = ctrls[2];407                    if (name) {408                        scope.$on("$destroy", function (e) {409                            // if formCtrl is destroyed No need to do anything410                            if (scope[formCtrl.$name]) {411                                ctrls[1].removeElementValidation(name);412                            }413                        });414                        if (!formCtrl[name]) {415                            formCtrl.$addControl(ctrls[0]);416                        }417                        var needValidate = false;418                        if (ctrls[2].$errors && ctrls[2].$errors.length > 0) {419                            needValidate = true;420                        }421                        ctrls[1].initElement(elm[0]);422                        if (needValidate) {423                            $timeout(function () {424                                ctrls[1].doValidate(angular.noop);425                            });426                        }427                    }428                }429            };430        }]);...ValidatorCtrl.js
Source:ValidatorCtrl.js  
1/**2 * @author Kuitos3 * @homepage https://github.com/kuitos/4 * @since 2016-03-175 */6import {Inject} from 'angular-es-utils/decorators';7import Tooltip from '../tooltip/Tooltip';8import {TOOLTIP_TYPE} from '../tooltip/Contants';9import {closestTagParent, closestAttrParent} from '../../common/utils/style-helper';10import {DEFAULT_VALIDATORS, formatValidator} from './Constant';11/*12 * 夿éè¦æ ¡éªçè¡¨åæ¯å¦åæ³13 * å¦æä½¿ç¨çæ¯ngèªå¸¦çformæä»¤,åç´æ¥è¿åformCtrl.$valid,å¦åæ£æ¥æ¯ä¸ä¸ªéè¦æ ¡éªçngModel14 */15const isFormValid = formCtrl => {16	if (formCtrl.$valid !== undefined) {17		return formCtrl.$valid;18	} else {19		return formCtrl.$$ngModelCtrls.every(ctrl => {20			return ctrl.$valid;21		});22	}23};24/**25 * <pre>æ ¡éªæç¤ºæä»¤</pre>26 * <pre>27 * 声æå½åè¾å
¥ä¼ç»å®æ ¡éªæç¤º28 * èªå¨è§¦åçæ¶æºå¤äºç»å®çmodelæ´æ°æ¶å». ä¹å°±æ¯å¯ä»¥éè¿é
ç½®{@link ng-model-options}æ¥æ§å¶modelæ´æ°æ¶æº,ä»èæ§å¶èªå¨æ ¡éªçæ¶æº.29 * 妿éè¦æå¨è§¦åæ ¡éª,å¯ä»¥è°ç¨$Validator.validateæ¹æ³æ¥å®ç°.30 * æ¯æå¼æ¥æ ¡éª(æ¯å¦æ ¡éªè¾å
¥çç¨æ·åæ¯å¦åå¨).31 * </pre>32 *33 * <a href="/demos/form" target="_blank">DEMO</a>34 * @example35 * <caption>å
æ ç§»é¤æ¶æè§¦åæ ¡éª</caption>36 * <div validators name="formCtrl">37 *  <input ng-model="model" ng-model-options="{updateOn:'default blur'}" type="input" validator>38 * </div>39 */40@Inject('$element', '$attrs')41export default class ValidatorCtrl {42	$onInit() {43		// dependency check44		if (!this.formCtrl) {45			console.warn('䏿¨èç´æ¥ä½¿ç¨validatoræä»¤,建议é
åform/ngForm使ç¨!');46			if (!this.validatorsCtrl) {47				throw new Error('validatoræä»¤å¿
é¡»é
åform/ngFrom/validatorså
¶ä¸è³å°ä¸ä¸ªæä»¤ä½¿ç¨!');48			} else {49				this.formCtrl = this.validatorsCtrl;50			}51		} else {52			// 妿æªä½¿ç¨validators声æéè¦æ ¡éªçåºå,表æè¿æ¶åè¯å®æ¯éè¿form/ngFormæ¥å®ç°ç表å53			if (!this.validatorsCtrl) {54				this.validatorsCtrl = this._initNonValidatorsDeclaredCtrl();55			}56			// attention! å¿
é¡»ä¿è¯formCtrlè·åå§formCtrlææåä¸ä¸ªå¼ç¨57			this.formCtrl = Object.assign(this.formCtrl, this.validatorsCtrl);58		}59		this.tooltip = null;60		this.tooltipType = this.formCtrl.element.getAttribute('tooltip-type');61		this.tooltipPlacement = this.formCtrl.element.getAttribute('tooltip-placement');62		// æ ¹æ®å½åå
ç´ ç»å®çéªè¯å¨id,å°ç¸åºçvalidatorèµç»ctrl.$validators63		// angular private api64		if (this.validator) {65			const validators = this.formCtrl.validators;66			this.validator.split(',').forEach(prop => {67				const field = prop.trim();68				if (validators[field]) {69					this.ngModelCtrl.$validators[field] = validators[field];70				}71			});72		}73	}74	$postLink() {75		const {formCtrl, ngModelCtrl} = this;76		/*77		 * ä¿ångModelCtrlå°è¡¨åæ§å¶å¨ä¸78		 */79		formCtrl.$$ngModelCtrls = formCtrl.$$ngModelCtrls || [];80		formCtrl.$$ngModelCtrls.push(ngModelCtrl);81		/*82		 * éångModelCtrlçsetPristineæ¹æ³83		 */84		const originalSetPristine = ngModelCtrl.$setPristine;85		ngModelCtrl.$setPristine = () => {86			originalSetPristine();87			this._closeTooltip();88		};89		/*90		 * aop91		 * å¨è§¦åæ ¡éªå¨çåå§æ¹æ³ä¸å å
¥é误æç¤ºé©å92		 * é»éæ³,å°å©åä¸è¦é便ç¨93		 * @see https://github.com/angular/angular.js/blob/master/src%2Fng%2Fdirective%2FngModel.js#L58494		 */95		const originValidatorFn = ngModelCtrl.$$runValidators;96		ngModelCtrl.$$runValidators = (modelValue, viewValue, doneCallback) => {97			// æ¹åæ ¡éªå®æçåè°,å å
¥åç½®æ¹æ³98			const originCb = doneCallback;99			doneCallback = allValid => {100				originCb(allValid);101				// ç¨æ·å·²ç»æè¿è¾å
¥äº¤äºæå¼å§æ ¡éªé»è¾102				// æè
å½åvalidateæ¯ç¨æ·æå¨è§¦åç103				if (ngModelCtrl.$dirty || formCtrl.$$invalidCount > 0) {104					this._toggleTooltip();105				}106				// 妿已ç»å
¨é¨æ ¡éªå®æ(å
æ¬$$invalidCountä¸å¼å§å°±ä¸º0çæ
åµ),åæ ¹æ®æ ¡éªç»æè§¦ådeferç¸åºçå¨ä½107				if (--formCtrl.$$invalidCount <= 0) {108					formCtrl.$$validatedDefer[isFormValid(formCtrl) ? 'resolve' : 'reject']();109				}110			};111			originValidatorFn(modelValue, viewValue, doneCallback);112		};113	}114	$onDestroy() {115		const {formCtrl, ngModelCtrl} = this;116		const index = formCtrl.$$ngModelCtrls.indexOf(ngModelCtrl);117		formCtrl.$$ngModelCtrls.splice(index, 1);118	}119	/**120	 * åå§åæªä½¿ç¨validators声æçè¡¨åæ ¡éªæ§å¶å¨121	 * @return {{element}, validators, errorMsg}122	 */123	_initNonValidatorsDeclaredCtrl() {124		let formEl = closestTagParent(this._$element[0], 'form');125		if (!formEl) {126			formEl = closestAttrParent(this._$element[0], 'ng-form');127		}128		return {...formatValidator(DEFAULT_VALIDATORS), element: formEl};129	}130	_openTooltip(msg) {131		this.tooltip = this.tooltip || new Tooltip(this._$element[0], this.tooltipType ? `error-${this.tooltipType}` : TOOLTIP_TYPE.ERROR_MINOR, null, this.tooltipPlacement ? this.tooltipPlacement : undefined);132		this.tooltip.open(msg);133	}134	_closeTooltip() {135		if (this.tooltip) {136			this.tooltip.close();137			this.tooltip = null;138		}139	}140	_toggleTooltip() {141		const {ngModelCtrl, formCtrl, _$attrs} = this;142		for (let id in ngModelCtrl.$error) {143			if (ngModelCtrl.$error.hasOwnProperty(id)) {144				let msg = _$attrs[`${id}Msg`] || formCtrl.errorMsg[id];145				if (ngModelCtrl.$error.hasOwnProperty(id) && msg) {146					this._openTooltip(msg);147					return;148				}149			}150		}151		this._closeTooltip();152	}...AvCheckboxGroup.js
Source:AvCheckboxGroup.js  
1import React, { Component } from 'react';2import { findDOMNode } from 'react-dom';3import PropTypes from 'prop-types';4import isEqual from 'lodash/isEqual';5import isUndefined from 'lodash/isUndefined';6import { FormGroup } from 'reactstrap';7import classNames from 'classnames';8import AvFeedback from './AvFeedback';9const htmlValidationAttrs = ['required'];10const noop = () => {};11export default class AvCheckboxGroup extends Component {12  static propTypes = Object.assign({}, FormGroup.propTypes, {13    name: PropTypes.string.isRequired,14  });15  static contextTypes = {16    FormCtrl: PropTypes.object.isRequired,17  };18  static childContextTypes = {19    Group: PropTypes.object.isRequired,20    FormCtrl: PropTypes.object.isRequired,21  };22  state = {23    invalidInputs: {},24    dirtyInputs: {},25    touchedInputs: {},26    badInputs: {},27    validate: {},28    value: [],29  };30  getChildContext() {31    if (!this.FormCtrl) {32      this.FormCtrl = { ...this.context.FormCtrl };33      this.FormCtrl.register = this.registerInput.bind(this);34      this.FormCtrl.unregister = this.unregisterInput.bind(this);35      this.FormCtrl.validate = noop;36    }37    const updateGroup = async(e, value) => {38      if (e.target.checked) {39        this.value.push(value);40      } else {41        this.value = this.value.filter(item => item !== value);42      }43      this.setState({value: this.value});44      await this.validate();45      !this.context.FormCtrl.isTouched(this.props.name) &&46        this.context.FormCtrl.setTouched(this.props.name);47      !this.context.FormCtrl.isDirty(this.props.name) &&48        this.context.FormCtrl.setDirty(this.props.name);49      this.props.onChange && this.props.onChange(e, this.value);50    };51    return {52      Group: {53        getProps: () => ({54          name: this.props.name,55          inline: this.props.inline,56          required:57            this.props.required ||58            !!(this.validations.required && this.validations.required.value),59          value: this.value,60        }),61        update: updateGroup,62        getValue: () => this.value,63        getInputState: this.getInputState.bind(this),64      },65      FormCtrl: this.FormCtrl,66    };67  }68  componentWillMount() {69    this.value = this.props.value || this.getDefaultValue().value;70    this.setState({ value: this.value });71    this.updateValidations();72  }73  componentWillReceiveProps(nextProps) {74    if (nextProps.name !== this.props.name) {75      this.context.FormCtrl.unregister(this);76    }77    if (nextProps.value !== this.props.value) {78      this.value = nextProps.value;79      this.setState({ value: nextProps.value });80    }81    if (!isEqual(nextProps, this.props)) {82      this.updateValidations(nextProps);83    }84  }85  componentWillUnmount() {86    this.context.FormCtrl.unregister(this);87  }88  getValue() {89    return this.value;90  }91  getInputState() {92    return this.context.FormCtrl.getInputState(this.props.name);93  }94  getDefaultValue() {95    const key = 'defaultValue';96    let value = [];97    if (!isUndefined(this.props[key])) {98      value = this.props[key];99    } else if (!isUndefined(this.context.FormCtrl.getDefaultValue(this.props.name))) {100      value = this.context.FormCtrl.getDefaultValue(this.props.name);101    }102    return { key, value };103  }104  async validate() {105    await this.context.FormCtrl.validate(this.props.name);106    this.updateInputs();107  }108  update() {109    this.setState({});110    this.updateInputs();111  }112  _inputs = [];113  value = [];114  updateValidations(props = this.props) {115    this.validations = Object.assign({}, props.validate);116    Object.keys(props)117      .filter(val => htmlValidationAttrs.indexOf(val) > -1)118      .forEach(attr => {119        if (props[attr]) {120          this.validations[attr] = this.validations[attr] || {121            value: props[attr],122          };123        } else {124          delete this.validations[attr];125        }126      });127    this.context.FormCtrl.register(this, this.update.bind(this));128    this.validate();129  }130  updateInputs() {131    this._inputs.forEach(input =>132      findDOMNode(input).firstChild.setCustomValidity('Invalid.') &&133      input.setState.call(input, {})134    );135    this.setState({});136  }137  reset() {138    this.value = this.getDefaultValue().value;139    this.context.FormCtrl.setDirty(this.props.name, false);140    this.context.FormCtrl.setTouched(this.props.name, false);141    this.context.FormCtrl.setBad(this.props.name, false);142    this.setState({ value: this.value });143    this.validate();144    this.props.onReset && this.props.onReset(this.value);145  }146  registerInput(input) {147    if (this._inputs.indexOf(input) < 0) {148      this._inputs.push(input);149    }150  }151  unregisterInput(input) {152    this._inputs = this._inputs.filter(ipt => {153      return ipt !== input;154    });155  }156  render() {157    const legend = this.props.label ? <legend>{this.props.label}</legend> : '';158    const validation = this.getInputState();159    const {160      errorMessage: omit1,161      validate: omit2,162      validationEvent: omit3,163      state: omit4,164      label: omit5,165      required: omit6,166      inline: omit7,167      children,168      ...attributes169    } = this.props;170    const touched = this.context.FormCtrl.isTouched(this.props.name);171    const hasError = this.context.FormCtrl.hasError(this.props.name);172    const classes = classNames(173      'form-control border-0 p-0 h-auto',174      touched ? 'is-touched' : 'is-untouched',175      this.context.FormCtrl.isDirty(this.props.name)176        ? 'is-dirty'177        : 'is-pristine',178      this.context.FormCtrl.isBad(this.props.name) ? 'is-bad-input' : null,179      hasError ? 'av-invalid' : 'av-valid',180      touched && hasError && 'is-invalid'181    );182    const groupClass = classNames(183      attributes.className,184      touched && hasError && 'was-validated'185    );186    return (187      <FormGroup tag="fieldset" {...attributes} className={groupClass}>188        {legend}189        <div className={classes}>{children}</div>190        <AvFeedback>{validation.errorMessage}</AvFeedback>191      </FormGroup>192    );193  }...AvRadioGroup.js
Source:AvRadioGroup.js  
1import React, { Component } from 'react';2import PropTypes from 'prop-types';3import isEqual from 'lodash/isEqual';4import isUndefined from 'lodash/isUndefined';5import { FormGroup } from 'reactstrap';6import classNames from 'classnames';7import AvFeedback from './AvFeedback';8const htmlValidationAttrs = ['required'];9const noop = () => {};10export default class AvRadioGroup extends Component {11  static propTypes = Object.assign({}, FormGroup.propTypes, {12    name: PropTypes.string.isRequired,13  });14  static contextTypes = {15    FormCtrl: PropTypes.object.isRequired,16  };17  static childContextTypes = {18    Group: PropTypes.object.isRequired,19    FormCtrl: PropTypes.object.isRequired,20  };21  state = {22    invalidInputs: {},23    dirtyInputs: {},24    touchedInputs: {},25    badInputs: {},26    validate: {},27    value: '',28  };29  getChildContext() {30    if (!this.FormCtrl) {31      this.FormCtrl = { ...this.context.FormCtrl };32      this.FormCtrl.register = this.registerInput.bind(this);33      this.FormCtrl.unregister = this.unregisterInput.bind(this);34      this.FormCtrl.validate = noop;35    }36    const updateGroup = async(e, value) => {37      this.setState({ value });38      this.value = value;39      await this.validate();40      !this.context.FormCtrl.isTouched(this.props.name) &&41        this.context.FormCtrl.setTouched(this.props.name);42      !this.context.FormCtrl.isDirty(this.props.name) &&43        this.context.FormCtrl.setDirty(this.props.name);44      this.props.onChange && this.props.onChange(e, value);45    };46    return {47      Group: {48        getProps: () => ({49          name: this.props.name,50          inline: this.props.inline,51          required:52            this.props.required ||53            !!(this.validations.required && this.validations.required.value),54          value: this.value,55        }),56        update: updateGroup,57        getValue: () => this.value,58        getInputState: this.getInputState.bind(this),59      },60      FormCtrl: this.FormCtrl,61    };62  }63  componentWillMount() {64    this.value = this.props.value || this.getDefaultValue().value;65    this.setState({ value: this.value });66    this.updateValidations();67  }68  componentWillReceiveProps(nextProps) {69    if (nextProps.name !== this.props.name) {70      this.context.FormCtrl.unregister(this);71    }72    if (nextProps.value !== this.props.value) {73      this.value = nextProps.value;74      this.setState({ value: nextProps.value });75    }76    if (!isEqual(nextProps, this.props)) {77      this.updateValidations(nextProps);78    }79  }80  componentWillUnmount() {81    this.context.FormCtrl.unregister(this);82  }83  getValue() {84    return this.value;85  }86  getInputState() {87    return this.context.FormCtrl.getInputState(this.props.name);88  }89  getDefaultValue() {90    const key = 'defaultValue';91    let value = '';92    if (!isUndefined(this.props[key])) {93      value = this.props[key];94    } else if (!isUndefined(this.context.FormCtrl.getDefaultValue(this.props.name))) {95      value = this.context.FormCtrl.getDefaultValue(this.props.name);96    }97    return { key, value };98  }99  async validate() {100    await this.context.FormCtrl.validate(this.props.name);101    this.updateInputs();102  }103  update() {104    this.setState({});105    this.updateInputs();106  }107  _inputs = [];108  value = '';109  updateValidations(props = this.props) {110    this.validations = Object.assign({}, props.validate);111    Object.keys(props)112      .filter(val => htmlValidationAttrs.indexOf(val) > -1)113      .forEach(attr => {114        if (props[attr]) {115          this.validations[attr] = this.validations[attr] || {116            value: props[attr],117          };118        } else {119          delete this.validations[attr];120        }121      });122    this.context.FormCtrl.register(this, this.update.bind(this));123    this.validate();124  }125  updateInputs() {126    this._inputs.forEach(input => input.setState.call(input, {}));127    this.setState({});128  }129  reset() {130    this.value = this.getDefaultValue().value;131    this.context.FormCtrl.setDirty(this.props.name, false);132    this.context.FormCtrl.setTouched(this.props.name, false);133    this.context.FormCtrl.setBad(this.props.name, false);134    this.setState({ value: this.value });135    this.validate();136    this.props.onReset && this.props.onReset(this.value);137  }138  registerInput(input) {139    if (this._inputs.indexOf(input) < 0) {140      this._inputs.push(input);141    }142  }143  unregisterInput(input) {144    this._inputs = this._inputs.filter(ipt => {145      return ipt !== input;146    });147  }148  render() {149    const legend = this.props.label ? <legend>{this.props.label}</legend> : '';150    const validation = this.getInputState();151    const {152      errorMessage: omit1,153      validate: omit2,154      validationEvent: omit3,155      state: omit4,156      label: omit5,157      required: omit6,158      inline: omit7,159      children,160      ...attributes161    } = this.props;162    const touched = this.context.FormCtrl.isTouched(this.props.name);163    const hasError = this.context.FormCtrl.hasError(this.props.name);164    const classes = classNames(165      'form-control border-0 p-0 h-auto',166      touched ? 'is-touched' : 'is-untouched',167      this.context.FormCtrl.isDirty(this.props.name)168        ? 'is-dirty'169        : 'is-pristine',170      this.context.FormCtrl.isBad(this.props.name) ? 'is-bad-input' : null,171      hasError ? 'av-invalid' : 'av-valid',172      touched && hasError && 'is-invalid'173    );174    const groupClass = classNames(175      attributes.className,176      touched && hasError && 'was-validated'177    );178    return (179      <FormGroup tag="fieldset" {...attributes} className={groupClass}>180        {legend}181        <div className={classes}>{children}</div>182        <AvFeedback>{validation.errorMessage}</AvFeedback>183      </FormGroup>184    );185  }...QuestionFormController.js
Source:QuestionFormController.js  
1(function() {2    'use strict';3    var questionFormController = function(questionsFactory) {4        var formCtrl = this;5        formCtrl.config = {6            number: 1,7            step: 0,8            filled: 0,9            isNextQuestion: true,10            maxStep: questionsFactory.countQuestions(),11            path: []12        };13        var getPrevStep = function() {14            formCtrl.config.path.pop();15            return formCtrl.config.path[formCtrl.config.path.length - 1];16        };17        var saveStep = function() {18            formCtrl.config.path.push(formCtrl.config.step);19        };20        var updateNextQuestionExistence = function() {21            formCtrl.config.isNextQuestion = questionsFactory.isNextQuestionExist(formCtrl.currentQuestion, formCtrl.config.step);22        };23        var updateProgress = function() {24            formCtrl.config.step = !formCtrl.config.isNextQuestion ? formCtrl.config.maxStep - 1 : formCtrl.config.step;25            formCtrl.config.filled = (formCtrl.config.step + 1) * 100 / formCtrl.config.maxStep;26        };27        formCtrl.init = function() {28            formCtrl.setQuestion();29            saveStep();30        };31        formCtrl.isErrorMessageVisible = function() {32            return formCtrl.qForm.$invalid && formCtrl.qForm.$dirty;33        };34        formCtrl.isNextButtonVisible = function() {35            return formCtrl.config.isNextQuestion;36        };37        formCtrl.isPrevButtonVisible = function() {38            return formCtrl.config.step > 0;39        };40        formCtrl.isShowOverviewButtonVisible = function() {41            return !formCtrl.config.isNextQuestion;42        };43        formCtrl.next = function() {44            if (formCtrl.qForm.$valid) {45                formCtrl.config.step = questionsFactory.getNextIndex(formCtrl.currentQuestion, formCtrl.config.step);46                formCtrl.setQuestion();47                formCtrl.qForm.$setPristine();48                formCtrl.config.number++;49                saveStep();50                if (formCtrl.currentQuestion.result !== null) {51                    formCtrl.currentQuestion.triggered = true;52                    updateProgress();53                }54            } else {55                formCtrl.qForm.$setDirty();56            }57        };58        formCtrl.prev = function() {59            formCtrl.currentQuestion.triggered = false;60            formCtrl.config.number--;61            formCtrl.config.step = getPrevStep();62            formCtrl.setQuestion();63        };64        formCtrl.selectAnswer = function() {65            formCtrl.currentQuestion.triggered = true;66            updateNextQuestionExistence();67            updateProgress();68        };69        formCtrl.setQuestion = function() {70            var question = questionsFactory.getQuestion(formCtrl.config.step);71            if (question) {72                formCtrl.currentQuestion = question;73                updateNextQuestionExistence();74            }75        };76    };77    questionFormController.$inject = ['questionsFactory'];78    angular.module('app').controller('QuestionFormController', questionFormController);...ValidatorService.js
Source:ValidatorService.js  
1/**2 * @author Kuitos3 * @homepage https://github.com/kuitos/4 * @since 2016-03-185 */6import injector from 'angular-es-utils/injector';7/**8 * <pre>9 *     è¡¨åæ ¡éªæå¡,ç¨äºæå¨è§¦åæ ¡éªé»è¾10 *     module: ccms.components.form11 *     service: $Validator12 * </pre>13 */14export default {15	/**16	 * éªè¯æå®è¡¨å17	 * @param {controller} formCtrl è¦æ ¡éªçè¡¨åæ§å¶å¨.éè¿å¨è¡¨ååºå声ænameçæ¹å¼å°å
¶èªå¨åå
¥å½åscopeä¸18	 * @return {Promise} æ ¡éªç»æpromise,æ ¡éªæåä¼è§¦åresolve,失败reject19	 */20	validate(formCtrl) {21		const $q = injector.get('$q');22		let deferred = $q.defer();23		formCtrl.$$validatedDefer = deferred;24		// è·åå½åæªæ ¡éªéè¿çngModelæ°é25		formCtrl.$$invalidNgModelCtrls = formCtrl.$$ngModelCtrls.filter(ctrl => ctrl.$invalid);26		formCtrl.$$invalidCount = formCtrl.$$invalidNgModelCtrls.length;27		if (formCtrl.$$invalidCount) {28			formCtrl.$$invalidNgModelCtrls.forEach(ctrl => {29				ctrl.$validate();30			});31		} else {32			deferred.resolve();33		}34		return deferred.promise;35	},36	setPristine(formCtrl) {37		if (formCtrl.$setPristine) {38			formCtrl.$setPristine();39		} else {40			formCtrl.$$ngModelCtrls.forEach(ctrl => ctrl.$setPristine());41		}42	}...Using AI Code Generation
1var FormCtrl = require('./formCtrl.js');2describe('Protractor Demo App', function() {3  var formCtrl = new FormCtrl();4  it('should have a title', function() {5    expect(browser.getTitle()).toEqual('Super Calculator');6  });7  it('should add one and two', function() {8    formCtrl.firstNumber.sendKeys(1);9    formCtrl.secondNumber.sendKeys(2);10    formCtrl.goButton.click();11    expect(formCtrl.latestResult.getText()).toEqual('3');12  });13  it('should add four and six', function() {14    formCtrl.firstNumber.sendKeys(4);15    formCtrl.secondNumber.sendKeys(6);16    formCtrl.goButton.click();17    expect(formCtrl.latestResult.getText()).toEqual('10');18  });19  it('should read the value from an input', function() {20    formCtrl.firstNumber.sendKeys(1);21    expect(formCtrl.firstNumber.getAttribute('value')).toEqual('1');22  });23});24var FormCtrl = function() {25  this.firstNumber = element(by.model('first'));26  this.secondNumber = element(by.model('second'));27  this.goButton = element(by.id('gobutton'));28  this.latestResult = element(by.binding('latest'));29};30module.exports = FormCtrl;31describe('angularjs homepage todo list', function() {32  it('should add a todo', function() {33    element(by.model('todoList.todoText')).sendKeys('write first protractor test');34    element(by.css('[value="add"]')).click();35    var todoList = element.all(by.repeater('todo in todoList.todos'));36    expect(todoList.count()).toEqual(3);37    expect(todoList.get(2).getText()).toEqual('write first protractor test');38    todoList.get(2).element(by.css('input')).click();39    var completedAmount = element.all(by.css('.done-true'));40    expect(completedAmount.count()).toEqual(2);41  });42});43describe('angularjs homepage todo list', function() {44  it('Using AI Code Generation
1var FormCtrl = require('../page-objects/FormCtrl.js');2var formCtrl = new FormCtrl();3describe('Protractor Demo App', function() {4  it('should have a title', function() {5    expect(browser.getTitle()).toEqual('Protractor Demo App');6  });7  it('should add one and two', function() {8    formCtrl.enterFirstNumber(1);9    formCtrl.enterSecondNumber(2);10    formCtrl.clickGo();11    expect(formCtrl.latestResult.getText()).toEqual('3');12  });13  it('should add four and six', function() {14    formCtrl.enterFirstNumber(4);15    formCtrl.enterSecondNumber(6);16    formCtrl.clickGo();17    expect(formCtrl.latestResult.getText()).toEqual('10');18  });19  it('should read the value from an input', function() {20    formCtrl.enterFirstNumber(1);21    expect(formCtrl.firstNumber.getAttribute('value')).toEqual('1');22  });23});24var FormCtrl = function() {25  this.firstNumber = element(by.model('first'));26  this.secondNumber = element(by.model('second'));27  this.goButton = element(by.id('gobutton'));28  this.latestResult = element(by.binding('latest'));29  this.enterFirstNumber = function(number) {30    this.firstNumber.sendKeys(number);31  };32  this.enterSecondNumber = function(number) {33    this.secondNumber.sendKeys(number);34  };35  this.clickGo = function() {36    this.goButton.click();37  };38};39module.exports = FormCtrl;Using AI Code Generation
1var FormCtrl = require('../pageObjects/formCtrl.js');2var formCtrl = new FormCtrl();3describe('Protractor Demo App', function() {4  it('should add one and two', function() {5    formCtrl.enterFirstNumber(1);6    formCtrl.enterSecondNumber(2);7    formCtrl.clickGo();8    expect(formCtrl.getResult()).toEqual('3');9  });10});11var FormCtrl = function() {12  this.enterFirstNumber = function(firstNumber) {13    element(by.model('first')).sendKeys(firstNumber);14  };15  this.enterSecondNumber = function(secondNumber) {16    element(by.model('second')).sendKeys(secondNumber);17  };18  this.clickGo = function() {19    element(by.id('gobutton')).click();20  };21  this.getResult = function() {22    return element(by.binding('latest')).getText();23  };24};25module.exports = FormCtrl;Using AI Code Generation
1var FormCtrl = require('./formCtrl.js');2var formCtrl = new FormCtrl();3var FormCtrl = require('./formCtrl.js');4var formCtrl = new FormCtrl();5var FormCtrl = require('./formCtrl.js');6var formCtrl = new FormCtrl();7var FormCtrl = require('./formCtrl.js');8var formCtrl = new FormCtrl();9var FormCtrl = require('./formCtrl.js');10var formCtrl = new FormCtrl();11var FormCtrl = require('./formCtrl.js');12var formCtrl = new FormCtrl();13var FormCtrl = require('./formCtrl.js');14var formCtrl = new FormCtrl();15var FormCtrl = require('./formCtrl.js');16var formCtrl = new FormCtrl();17var FormCtrl = require('./formCtrl.js');18var formCtrl = new FormCtrl();19var FormCtrl = require('./formCtrl.js');20var formCtrl = new FormCtrl();21var FormCtrl = require('./formCtrl.js');22var formCtrl = new FormCtrl();23var FormCtrl = require('./formCtrl.js');24var formCtrl = new FormCtrl();25var FormCtrl = require('./formCtrl.js');26var formCtrl = new FormCtrl();Using AI Code Generation
1var FormCtrl = require('./formCtrl.js');2var formCtrl = new FormCtrl();3describe('Form', function() {4  it('should have a title', function() {5    expect(browser.getTitle()).toEqual('AngularJS');6  });7  it('should allow adding a new user', function() {8    formCtrl.addUser('John Doe', 'Using AI Code Generation
1var FormCtrl = require('./form-ctrl.js');2var formCtrl = new FormCtrl();3describe('form', function() {4  it('should be valid', function() {5    formCtrl.setName('Jane');6    formCtrl.setEmail('Using AI Code Generation
1var FormCtrl = require('./form.ctrl.js');2var formCtrl = new FormCtrl();3formCtrl.enterFirstName();4formCtrl.enterLastName();5formCtrl.enterEmail();6formCtrl.enterPassword();7formCtrl.enterConfirmPassword();8formCtrl.clickRegisterButton();9function FormCtrl() {10    this.enterFirstName = function () {11        element(by.model('user.firstName')).sendKeys('John');12    };13    this.enterLastName = function () {14        element(by.model('user.lastName')).sendKeys('Doe');15    };16    this.enterEmail = function () {17        element(by.model('user.email')).sendKeys('Using AI Code Generation
1var FormCtrl = require('./formCtrl');2var formCtrl = new FormCtrl();3describe('Test FormCtrl', function () {4    it('should have a title', function () {5        expect(browser.getTitle()).toEqual('AngularJS Protractor Demo');6    });7    it('should have a name', function () {8        formCtrl.setName('Test');9        expect(formCtrl.getName()).toEqual('Test');10    });11    it('should have a password', function () {12        formCtrl.setPassword('Test');13        expect(formCtrl.getPassword()).toEqual('Test');14    });15    it('should have a email', function () {16        formCtrl.setEmail('Test');17        expect(formCtrl.getEmail()).toEqual('Test');18    });19    it('should have a phone', function () {20        formCtrl.setPhone('Test');21        expect(formCtrl.getPhone()).toEqual('Test');22    });23    it('should have a select', function () {24        formCtrl.setSelect('Test');25        expect(formCtrl.getSelect()).toEqual('Test');26    });27    it('should have a radio', function () {28        formCtrl.setRadio('Test');29        expect(formCtrl.getRadio()).toEqual('Test');30    });31    it('should have a checkbox', function () {32        formCtrl.setCheckbox('Test');33        expect(formCtrl.getCheckbox()).toEqual('Test');34    });35    it('should have a textarea', function () {36        formCtrl.setTextarea('Test');37        expect(formCtrl.getTextarea()).toEqual('Test');38    });39    it('should have a submit button', function () {40        formCtrl.submit();41    });42});Protractor is developed by Google Developers to test Angular and AngularJS code. Today, it is used to test non-Angular applications as well. It performs a real-world user-like test against your application in a real browser. It comes under an end-to-end testing framework. As of now, Selenium Protractor has proved to be a popular framework for end-to-end automation for AngularJS.
Let’s talk about what it does:
 Protractor is a JavaScript framework, end-to-end test automation framework for Angular and AngularJS applications.
Protractor Selenium provides new locator methods that actually make it easier to find elements in the DOM.
Two files are required to execute Protractor Selenium tests for end-to-end automation: Specs & Config. Go through the link above to understand in a better way.
To carry out extensive, automated cross browser testing, you can't imagine installing thousands of the available browsers on your own workstation. The only way to increase browser usage is through remote execution on the cloud. To execute your automation test scripts across a variety of platforms and browser versions, LambdaTest offers more than 3000 browsers.
We recommend Selenium for end-to-end automation for AngularJS because both are maintained and owned by Google, and they build JavaScript test automation framework to handle AngularJS components in a way that better matches how developers use it.
For scripting, selenium locators are essential since if they're off, your automation scripts won't run. Therefore, in any testing framework, these Selenium locators are the foundation of your Selenium test automation efforts.
To make sure that your Selenium automation tests function as intended, debugging can be an effective option. Check the blog to know more.
If you are not familiar with writing Selenium test automation on Protractor, here is a blog for you to get you understand in depth.
Selenium tests are asynchronous and there are various reasons for a timeout to occur in a Protractor test. Find out how to handle timeouts in this Protractor tutorial.
In this Protractor tutorial, learn how to handle frames or iframes in Selenium with Protractor for automated browser testing.
Handle alerts and popups in Protractor more efficiently. It can be confusing. Here's a simple guide to understand how to handle alerts and popups in Selenium.
Get 100 minutes of automation test minutes FREE!!
