From 83e642155953e6d5a5180959ce0e76d2a42f2e4a Mon Sep 17 00:00:00 2001 From: "bo.wu@finesys.com.cn" Date: Mon, 15 Dec 2025 11:20:18 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 8196 bytes .gitignore | 47 + LICENSE | 201 + README.en.md | 36 + README.md | 42 + bin/clean.bat | 12 + bin/package.bat | 12 + bin/run.bat | 14 + doc/若依环境使用手册.docx | Bin 0 -> 428430 bytes package-lock.json | 6 + pom.xml | 248 + ry.bat | 67 + ry.sh | 86 + sql/Menu.sql | 3 + sql/README.md | 2 + sql/quartz.sql | 174 + sql/ry_20231130.sql | 700 + sql/tony-flowable.sql | 3637 ++ zbf-admin/pom.xml | 149 + .../src/main/java/com/zbf/ZbfApplication.java | 34 + .../java/com/zbf/ZbfServletInitializer.java | 18 + .../controller/common/CaptchaController.java | 94 + .../controller/common/CommonController.java | 168 + .../common/FileUploadController.java | 50 + .../flowable/DynamicFlowController.java | 233 + .../controller/flowable/FlowController.java | 224 + .../flowable/FlowDesignerController.java | 143 + .../flowable/FlowMonitorController.java | 456 + .../flowable/LeaveapplyController.java | 231 + .../flowable/MeetingController.java | 133 + .../flowable/ModelManageController.java | 161 + .../flowable/OutBoundController.java | 286 + .../flowable/PurchaseController.java | 221 + .../controller/flowable/TaskController.java | 370 + .../controller/monitor/CacheController.java | 120 + .../controller/monitor/ServerController.java | 27 + .../monitor/SysLogininforController.java | 82 + .../monitor/SysOperlogController.java | 69 + .../monitor/SysUserOnlineController.java | 83 + .../controller/section/DataListAspect.java | 73 + .../controller/section/EnhanceDataList.java | 12 + .../web/controller/section/ListColumns.java | 15 + .../controller/system/AppVerController.java | 42 + .../system/DeviceLogController.java | 129 + .../system/InventoryCheckController.java | 132 + .../system/LargeScreenController.java | 4469 +++ .../controller/system/RestClientConfig.java | 35 + .../system/SysConfigController.java | 133 + .../controller/system/SysDeptController.java | 155 + .../system/SysDictDataController.java | 134 + .../system/SysDictTypeController.java | 131 + .../system/SysExpressionController.java | 104 + .../controller/system/SysIndexController.java | 29 + .../system/SysListenerController.java | 104 + .../controller/system/SysLoginController.java | 142 + .../controller/system/SysMenuController.java | 150 + .../system/SysNoticeController.java | 91 + .../controller/system/SysPostController.java | 129 + .../system/SysProfileController.java | 141 + .../system/SysRegisterController.java | 38 + .../controller/system/SysRoleController.java | 275 + .../SysUserBusinessColumnController.java | 144 + .../controller/system/SysUserController.java | 302 + .../web/controller/system/TAgvController.java | 135 + .../system/TBaseFinancialClassController.java | 131 + .../system/TBaseGoodsBomController.java | 132 + .../system/TBaseGoodsController.java | 169 + .../system/TBasePalletController.java | 141 + .../system/TBaseProviderController.java | 142 + .../system/TBaseStorageAreaController.java | 125 + .../TBaseStorageAreaLocationController.java | 171 + .../system/TBaseStorageController.java | 176 + .../system/TCallNoticeController.java | 184 + .../system/TCallNoticeOrderController.java | 155 + .../system/TCkOrderdetailController.java | 159 + .../system/TCkOrdersController.java | 291 + .../TCkPickingwavegoodsBakController.java | 147 + .../system/TCkPickingwavegoodsController.java | 214 + .../system/TErrorLogController.java | 138 + .../system/TMiBatchAdjustmentController.java | 103 + .../system/TMiStockBakController.java | 140 + .../controller/system/TMiStockController.java | 342 + .../system/TMiStockFController.java | 53 + .../system/TMiXnStockController.java | 338 + .../system/TOngoodsshelfBakController.java | 152 + .../system/TOngoodsshelfController.java | 148 + .../system/TPanDetailController.java | 132 + .../system/TPanOrderController.java | 178 + .../system/TRkReceivingGoodsController.java | 145 + .../system/TRkWareNoticeBakController.java | 138 + .../system/TRkWareNoticeController.java | 344 + .../system/TRkWareNoticeTabBakController.java | 193 + .../system/TRkWareNoticeTabController.java | 141 + .../TRkXnWareNoticeTabBakController.java | 208 + .../system/TSafetyStockController.java | 62 + .../system/TStockCheckController.java | 105 + .../system/TUserConfigController.java | 135 + .../system/TUserFavoritesController.java | 129 + .../system/TckOrderdetailBakController.java | 247 + .../system/TckOrdersBakController.java | 155 + .../system/TckXnOrderdetailBakController.java | 233 + .../system/TransferOrderController.java | 128 + .../web/controller/tool/TestController.java | 183 + .../zbf/web/core/config/SwaggerConfig.java | 125 + .../java/com/zbf/web/mqtt/MqttConfig.java | 172 + .../com/zbf/web/mqtt/MqttMessageHandler.java | 257 + .../com/zbf/web/mqtt/MqttMessageSender.java | 38 + .../java/com/zbf/web/mqtt/MqttProperties.java | 19 + .../zbf/web/util/ActivitiTracingChart.java | 88 + .../src/main/java/com/zbf/web/util/Check.java | 23 + .../src/main/java/com/zbf/web/util/RID.java | 36 + .../META-INF/spring-devtools.properties | 1 + .../src/main/resources/application-druid.yml | 82 + zbf-admin/src/main/resources/application.yml | 183 + zbf-admin/src/main/resources/banner.txt | 24 + .../main/resources/i18n/messages.properties | 38 + zbf-admin/src/main/resources/logback.xml | 107 + .../main/resources/mybatis/mybatis-config.xml | 20 + .../processes/Flowable_Pickingout.bpmn20.xml | 105 + .../processes/Pickingout_Audit.bpmn20.xml | 125 + .../src/main/resources/processes/leave.bpmn | 143 + .../src/main/resources/processes/meeting.bpmn | 42 + .../resources/processes/purchase.bpmn20.xml | 240 + .../main/resources/static/designer/404.html | 157 + .../static/designer/browserconfig.xml | 9 + .../static/designer/display-cmmn/cmmn-draw.js | 491 + .../designer/display-cmmn/cmmn-icons.js | 180 + .../designer/display-cmmn/displaymodel.css | 24 + .../designer/display-cmmn/displaymodel.html | 15 + .../designer/display-cmmn/displaymodel.js | 272 + .../static/designer/display/.gitignore | 3 + .../static/designer/display/Gruntfile.js | 153 + .../static/designer/display/Polyline.js | 387 + .../static/designer/display/bpmn-draw.js | 866 + .../static/designer/display/bpmn-icons.js | 342 + .../static/designer/display/displaymodel.css | 24 + .../static/designer/display/displaymodel.html | 19 + .../static/designer/display/displaymodel.js | 317 + .../designer/display/jquery.qtip.min.css | 2 + .../designer/display/jquery.qtip.min.js | 5 + .../static/designer/display/package.json | 37 + .../static/designer/display/raphael.min.js | 1 + .../configuration/flowable-header-custom.js | 19 + .../flowable-toolbar-custom-actions.js | 47 + .../properties-assignment-controller.js | 507 + ...properties-calledelementtype-controller.js | 28 + .../properties-case-reference-controller.js | 80 + ...perties-condition-expression-controller.js | 59 + .../properties-custom-controllers.js | 12 + .../properties-data-properties-controller.js | 330 + ...ties-decisiontable-reference-controller.js | 288 + .../properties-default-controllers.js | 118 + .../properties-duedate-controller.js | 126 + .../properties-event-listeners-controller.js | 263 + ...operties-execution-listeners-controller.js | 358 + .../properties-fields-controller.js | 206 + .../properties-form-properties-controller.js | 327 + .../properties-form-reference-controller.js | 261 + .../properties-httprequest-controller.js | 24 + .../properties-in-parameters-controller.js | 184 + ...operties-message-definitions-controller.js | 145 + .../properties-message-scope-controller.js | 41 + .../properties-multiinstance-controller.js | 24 + .../properties-ordering-controller.js | 28 + .../properties-out-parameters-controller.js | 180 + ...lan-item-lifecycle-listeners-controller.js | 357 + ...properties-planitem-dropdown-controller.js | 82 + ...perties-process-historylevel-controller.js | 24 + ...properties-process-reference-controller.js | 80 + ...roperties-sequenceflow-order-controller.js | 126 + ...roperties-signal-definitions-controller.js | 151 + .../properties-signal-scope-controller.js | 42 + .../properties-task-listeners-controller.js | 356 + .../properties-transition-event-controller.js | 27 + .../properties-trigger-mode-controller.js | 23 + .../editor-app/configuration/properties.js | 157 + .../assignment-display-template.html | 15 + .../properties/assignment-popup.html | 268 + .../properties/assignment-write-template.html | 4 + .../properties/boolean-property-template.html | 4 + ...edelementtype-property-write-template.html | 7 + .../case-reference-display-template.html | 3 + .../properties/case-reference-popup.html | 45 + .../case-reference-write-template.html | 2 + ...condition-expression-display-template.html | 3 + .../condition-expression-popup.html | 26 + .../condition-expression-write-template.html | 4 + .../data-properties-display-template.html | 3 + .../properties/data-properties-popup.html | 64 + .../data-properties-write-template.html | 4 + ...isiontable-reference-display-template.html | 3 + .../decisiontable-reference-popup.html | 74 + ...ecisiontable-reference-write-template.html | 2 + .../default-value-display-template.html | 4 + .../properties/duedate-display-template.html | 6 + .../properties/duedate-popup.html | 120 + .../properties/duedate-write-template.html | 4 + .../properties/errorgrid-critical.html | 5 + .../event-listeners-display-template.html | 3 + .../properties/event-listeners-popup.html | 143 + .../event-listeners-write-template.html | 4 + .../execution-listeners-display-template.html | 3 + .../properties/execution-listeners-popup.html | 101 + .../execution-listeners-write-template.html | 4 + .../properties/feedback-popup.html | 17 + .../properties/fields-display-template.html | 3 + .../properties/fields-popup.html | 58 + .../properties/fields-write-template.html | 4 + .../form-properties-display-template.html | 3 + .../properties/form-properties-popup.html | 121 + .../form-properties-write-template.html | 4 + .../form-reference-display-template.html | 4 + .../properties/form-reference-popup.html | 74 + .../form-reference-write-template.html | 4 + .../http-request-method-display-template.html | 3 + ...equest-method-property-write-template.html | 8 + .../in-parameters-display-template.html | 3 + .../properties/in-parameters-popup.html | 57 + .../in-parameters-write-template.html | 4 + .../message-definitions-display-template.html | 3 + .../properties/message-definitions-popup.html | 49 + .../message-definitions-write-template.html | 4 + .../message-property-write-template.html | 4 + ...multiinstance-property-write-template.html | 8 + .../ordering-property-write-template.html | 7 + .../out-parameters-display-template.html | 3 + .../properties/out-parameters-popup.html | 57 + .../out-parameters-write-template.html | 4 + ...-lifecycle-listeners-display-template.html | 3 + .../plan-item-lifecycle-listeners-popup.html | 125 + ...em-lifecycle-listeners-write-template.html | 2 + .../planitem-dropdown-read-template.html | 4 + .../planitem-dropdown-write-template.html | 5 + ...-historylevel-property-write-template.html | 10 + .../process-reference-display-template.html | 3 + .../properties/process-reference-popup.html | 45 + .../process-reference-write-template.html | 4 + .../sequenceflow-order-display-template.html | 3 + .../properties/sequenceflow-order-popup.html | 47 + .../sequenceflow-order-write-template.html | 4 + .../signal-definitions-display-template.html | 3 + .../properties/signal-definitions-popup.html | 56 + .../signal-definitions-write-template.html | 3 + .../signal-property-write-template.html | 4 + .../string-property-write-mode-template.html | 9 + .../task-listeners-display-template.html | 3 + .../properties/task-listeners-popup.html | 102 + .../task-listeners-write-template.html | 4 + .../configuration/properties/text-popup.html | 17 + .../text-property-write-template.html | 4 + .../transition-event-write-template.html | 10 + .../trigger-mode-read-template.html | 3 + .../trigger-mode-write-template.html | 7 + .../configuration/toolbar-custom-actions.js | 12 + .../configuration/toolbar-default-actions.js | 556 + .../editor-app/configuration/toolbar.js | 187 + .../editor-app/configuration/url-config.js | 41 + .../static/designer/editor-app/css/style.css | 1210 + .../editor-app/define-data-controller.js | 105 + .../designer/editor-app/editor-config.js | 27 + .../designer/editor-app/editor-controller.js | 462 + .../designer/editor-app/editor-utils.js | 314 + .../static/designer/editor-app/editor.html | 168 + .../designer/editor-app/editor/css/editor.css | 216 + .../editor-app/editor/i18n/translation_de.js | 413 + .../editor/i18n/translation_en_us.js | 453 + .../editor/i18n/translation_signavio_de.js | 136 + .../editor/i18n/translation_signavio_en_us.js | 138 + .../designer/editor-app/editor/oryx.debug.js | 25549 ++++++++++++++ .../static/designer/editor-app/editor/oryx.js | 30 + .../designer/editor-app/editormanager.js | 325 + .../static/designer/editor-app/eventbus.js | 137 + .../designer/editor-app/fonts/FontAwesome.otf | Bin 0 -> 93888 bytes .../fonts/activiti-admin-webfont.eot | Bin 0 -> 5029 bytes .../fonts/activiti-admin-webfont.svg | 43 + .../fonts/activiti-admin-webfont.ttf | Bin 0 -> 8628 bytes .../fonts/activiti-admin-webfont.woff | Bin 0 -> 5624 bytes .../editor-app/fonts/fontawesome-webfont.eot | Bin 0 -> 60767 bytes .../editor-app/fonts/fontawesome-webfont.svg | 565 + .../editor-app/fonts/fontawesome-webfont.ttf | Bin 0 -> 122092 bytes .../editor-app/fonts/fontawesome-webfont.woff | Bin 0 -> 71508 bytes .../fonts/fontawesome-webfont.woff2 | Bin 0 -> 56780 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20290 bytes .../fonts/glyphicons-halflings-regular.svg | 229 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 41236 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23292 bytes .../designer/editor-app/header-controller.js | 25 + .../designer/editor-app/images/bpmn-error.png | Bin 0 -> 492 bytes .../editor-app/images/bpmn-warning.png | Bin 0 -> 469 bytes .../editor-app/images/datadefinition.png | Bin 0 -> 778 bytes .../designer/editor-app/images/delete.png | Bin 0 -> 304 bytes .../designer/editor-app/images/loading.gif | Bin 0 -> 17550 bytes .../editor-app/images/nw-handle-dark.gif | Bin 0 -> 839 bytes .../designer/editor-app/images/pencil.png | Bin 0 -> 450 bytes .../editor-app/images/report_edit.png | Bin 0 -> 762 bytes .../editor-app/images/se-handle-dark.gif | Bin 0 -> 838 bytes .../editor-app/images/shapemenu_highlight.png | Bin 0 -> 462 bytes .../designer/editor-app/images/wrench.png | Bin 0 -> 374 bytes .../img-kis/add-bendpoint-hover.png | Bin 0 -> 637 bytes .../editor-app/img-kis/add-bendpoint.png | Bin 0 -> 490 bytes .../designer/editor-app/img-kis/grid.gif | Bin 0 -> 1138 bytes .../img-kis/icon-add-bendpoint-selected.png | Bin 0 -> 1826 bytes .../editor-app/img-kis/icon-add-bendpoint.png | Bin 0 -> 1291 bytes .../icon-align-horizontal-selected.png | Bin 0 -> 831 bytes .../img-kis/icon-align-horizontal.png | Bin 0 -> 684 bytes .../img-kis/icon-align-vertical-selected.png | Bin 0 -> 802 bytes .../img-kis/icon-align-vertical.png | Bin 0 -> 648 bytes .../icon-remove-bendpoint-selected.png | Bin 0 -> 1745 bytes .../img-kis/icon-remove-bendpoint.png | Bin 0 -> 1247 bytes .../img-kis/icon-same-size-selected.png | Bin 0 -> 1024 bytes .../editor-app/img-kis/icon-same-size.png | Bin 0 -> 778 bytes .../img-kis/icon-zoom-actual-selected.png | Bin 0 -> 1352 bytes .../editor-app/img-kis/icon-zoom-actual.png | Bin 0 -> 970 bytes .../img-kis/icon-zoom-fit-selected.png | Bin 0 -> 1165 bytes .../editor-app/img-kis/icon-zoom-fit.png | Bin 0 -> 838 bytes .../designer/editor-app/img-kis/kis_logo.png | Bin 0 -> 2498 bytes .../img-kis/remove-bendpoint-hover.png | Bin 0 -> 625 bytes .../editor-app/img-kis/remove-bendpoint.png | Bin 0 -> 478 bytes .../libs/jquery.autogrow-textarea.js | 61 + .../libs/mousetrap/1.6.0/mousetrap-record.js | 205 + .../libs/mousetrap/1.6.0/mousetrap.js | 1038 + .../libs/mousetrap/1.6.0/mousetrap.min.js | 11 + .../designer/editor-app/libs/path_parser.js | 30 + .../editor-app/libs/prototype-1.6.1.js | 4874 +++ .../editor-app/libs/prototype-1.7.3.js | 7588 ++++ .../editor-app/libs/ui-utils.min-0.2.1.js | 7 + .../designer/editor-app/libs/update-helper.js | 494 + .../partials/process-tree-list.html | 7 + .../partials/root-stencil-item-template.html | 12 + .../partials/stencil-item-template.html | 28 + .../static/designer/editor-app/plugins.xml | 73 + .../editor-app/popups/define-data.html | 45 + .../editor-app/popups/icon-template.html | 4 + .../editor-app/popups/save-model.html | 114 + .../editor-app/popups/select-shape.html | 18 + .../editor-app/popups/unsaved-changes.html | 23 + .../editor-app/popups/validate-model.html | 18 + .../process-navigator-controller.js | 81 + .../editor-app/select-shape-controller.js | 318 + .../designer/editor-app/stencil-controller.js | 1487 + .../designer/editor-app/stencilset.json | 2116 ++ .../icons/activity/adhoc.subprocess.png | Bin 0 -> 293 bytes .../activity/event.subprocess.collapsed.png | Bin 0 -> 309 bytes .../icons/activity/event.subprocess.png | Bin 0 -> 274 bytes .../icons/activity/expanded.subprocess.png | Bin 0 -> 273 bytes .../activity/list/type.business.rule.png | Bin 0 -> 209 bytes .../icons/activity/list/type.camel.png | Bin 0 -> 608 bytes .../icons/activity/list/type.decision.png | Bin 0 -> 299 bytes .../bpmn2.0/icons/activity/list/type.http.png | Bin 0 -> 1267 bytes .../icons/activity/list/type.manual.png | Bin 0 -> 405 bytes .../bpmn2.0/icons/activity/list/type.mule.png | Bin 0 -> 705 bytes .../icons/activity/list/type.receive.png | Bin 0 -> 297 bytes .../icons/activity/list/type.script.png | Bin 0 -> 300 bytes .../bpmn2.0/icons/activity/list/type.send.png | Bin 0 -> 440 bytes .../icons/activity/list/type.service.png | Bin 0 -> 530 bytes .../icons/activity/list/type.shell.png | Bin 0 -> 325 bytes .../bpmn2.0/icons/activity/list/type.user.png | Bin 0 -> 405 bytes .../bpmn2.0/icons/activity/subprocess.png | Bin 0 -> 282 bytes .../bpmn2.0/icons/activity/task.png | Bin 0 -> 255 bytes .../icons/artifact/text.annotation.png | Bin 0 -> 367 bytes .../bpmn2.0/icons/catching/cancel.png | Bin 0 -> 3241 bytes .../bpmn2.0/icons/catching/compensation.png | Bin 0 -> 3256 bytes .../bpmn2.0/icons/catching/conditional.png | Bin 0 -> 3154 bytes .../bpmn2.0/icons/catching/error.png | Bin 0 -> 698 bytes .../bpmn2.0/icons/catching/escalation.png | Bin 0 -> 3336 bytes .../bpmn2.0/icons/catching/message.png | Bin 0 -> 549 bytes .../bpmn2.0/icons/catching/signal.png | Bin 0 -> 627 bytes .../bpmn2.0/icons/catching/timer.png | Bin 0 -> 573 bytes .../connector/association.undirected.png | Bin 0 -> 413 bytes .../connector/association.unidirectional.png | Bin 0 -> 3032 bytes .../bpmn2.0/icons/connector/messageflow.png | Bin 0 -> 3121 bytes .../bpmn2.0/icons/connector/sequenceflow.png | Bin 0 -> 346 bytes .../bpmn2.0/icons/dataobject/data.store.png | Bin 0 -> 3184 bytes .../stencilsets/bpmn2.0/icons/diagram.png | Bin 0 -> 206 bytes .../bpmn2.0/icons/endevent/cancel.png | Bin 0 -> 910 bytes .../bpmn2.0/icons/endevent/error.png | Bin 0 -> 757 bytes .../bpmn2.0/icons/endevent/escalation.png | Bin 0 -> 3185 bytes .../bpmn2.0/icons/endevent/none.png | Bin 0 -> 467 bytes .../bpmn2.0/icons/endevent/terminate.png | Bin 0 -> 3166 bytes .../bpmn2.0/icons/gateway/eventbased.png | Bin 0 -> 492 bytes .../icons/gateway/exclusive.databased.png | Bin 0 -> 462 bytes .../bpmn2.0/icons/gateway/inclusive.png | Bin 0 -> 432 bytes .../bpmn2.0/icons/gateway/parallel.png | Bin 0 -> 329 bytes .../bpmn2.0/icons/startevent/conditional.png | Bin 0 -> 3134 bytes .../bpmn2.0/icons/startevent/error.png | Bin 0 -> 698 bytes .../bpmn2.0/icons/startevent/escalation.png | Bin 0 -> 3212 bytes .../bpmn2.0/icons/startevent/message.png | Bin 0 -> 549 bytes .../bpmn2.0/icons/startevent/none.png | Bin 0 -> 450 bytes .../bpmn2.0/icons/startevent/signal.png | Bin 0 -> 3201 bytes .../bpmn2.0/icons/startevent/timer.png | Bin 0 -> 573 bytes .../bpmn2.0/icons/swimlane/lane.png | Bin 0 -> 187 bytes .../bpmn2.0/icons/swimlane/pool.png | Bin 0 -> 189 bytes .../bpmn2.0/icons/throwing/escalation.png | Bin 0 -> 3195 bytes .../bpmn2.0/icons/throwing/none.png | Bin 0 -> 582 bytes .../bpmn2.0/icons/throwing/signal.png | Bin 0 -> 747 bytes .../cmmn1.1/icons/activity/casefileitem.png | Bin 0 -> 2937 bytes .../cmmn1.1/icons/activity/casetask.png | Bin 0 -> 230 bytes .../icons/activity/collapsed.planfragment.png | Bin 0 -> 629 bytes .../cmmn1.1/icons/activity/decisiontask.png | Bin 0 -> 299 bytes .../icons/activity/expanded.planfragment.png | Bin 0 -> 386 bytes .../cmmn1.1/icons/activity/httptask.png | Bin 0 -> 1267 bytes .../cmmn1.1/icons/activity/humantask.png | Bin 0 -> 3015 bytes .../cmmn1.1/icons/activity/milestone.png | Bin 0 -> 285 bytes .../cmmn1.1/icons/activity/processtask.png | Bin 0 -> 102 bytes .../cmmn1.1/icons/activity/scripttask.png | Bin 0 -> 300 bytes .../cmmn1.1/icons/activity/servicetask.png | Bin 0 -> 530 bytes .../cmmn1.1/icons/activity/task.png | Bin 0 -> 2990 bytes .../icons/activity/timereventlistener.png | Bin 0 -> 573 bytes .../cmmn1.1/icons/connection/connector.png | Bin 0 -> 2988 bytes .../icons/containers/caseplanmodel.png | Bin 0 -> 241 bytes .../icons/containers/collapsed.stage.png | Bin 0 -> 625 bytes .../icons/containers/expanded.stage.png | Bin 0 -> 252 bytes .../cmmn1.1/icons/event/eventlistener.png | Bin 0 -> 3189 bytes .../cmmn1.1/icons/event/timerlistener.png | Bin 0 -> 3420 bytes .../cmmn1.1/icons/event/userlistener.png | Bin 0 -> 673 bytes .../cmmn1.1/icons/sentry/entry.png | Bin 0 -> 375 bytes .../stencilsets/cmmn1.1/icons/sentry/exit.png | Bin 0 -> 282 bytes .../cmmn1.1/icons/tables/planningtable.png | Bin 0 -> 476 bytes .../stencilsets/xforms/icons/new_action.png | Bin 0 -> 218 bytes .../xforms/icons/new_action_container.png | Bin 0 -> 151 bytes .../stencilsets/xforms/icons/new_alert.png | Bin 0 -> 365 bytes .../stencilsets/xforms/icons/new_case.png | Bin 0 -> 3696 bytes .../stencilsets/xforms/icons/new_checkbox.png | Bin 0 -> 308 bytes .../stencilsets/xforms/icons/new_choices.png | Bin 0 -> 206 bytes .../stencilsets/xforms/icons/new_combo.png | Bin 0 -> 278 bytes .../stencilsets/xforms/icons/new_date.png | Bin 0 -> 473 bytes .../stencilsets/xforms/icons/new_form.png | Bin 0 -> 258 bytes .../stencilsets/xforms/icons/new_group.png | Bin 0 -> 402 bytes .../stencilsets/xforms/icons/new_header.png | Bin 0 -> 277 bytes .../stencilsets/xforms/icons/new_help.png | Bin 0 -> 393 bytes .../stencilsets/xforms/icons/new_hint.png | Bin 0 -> 352 bytes .../stencilsets/xforms/icons/new_input.png | Bin 0 -> 328 bytes .../stencilsets/xforms/icons/new_item.png | Bin 0 -> 169 bytes .../stencilsets/xforms/icons/new_itemset.png | Bin 0 -> 169 bytes .../stencilsets/xforms/icons/new_label.png | Bin 0 -> 223 bytes .../stencilsets/xforms/icons/new_number.png | Bin 0 -> 315 bytes .../stencilsets/xforms/icons/new_output.png | Bin 0 -> 250 bytes .../xforms/icons/new_paragraph.png | Bin 0 -> 314 bytes .../xforms/icons/new_radiobutton.png | Bin 0 -> 586 bytes .../stencilsets/xforms/icons/new_range.png | Bin 0 -> 199 bytes .../stencilsets/xforms/icons/new_repeat.png | Bin 0 -> 574 bytes .../xforms/icons/new_repeating_group.png | Bin 0 -> 539 bytes .../stencilsets/xforms/icons/new_secret.png | Bin 0 -> 324 bytes .../stencilsets/xforms/icons/new_select.png | Bin 0 -> 163 bytes .../stencilsets/xforms/icons/new_select1.png | Bin 0 -> 165 bytes .../xforms/icons/new_separator.png | Bin 0 -> 240 bytes .../stencilsets/xforms/icons/new_submit.png | Bin 0 -> 271 bytes .../stencilsets/xforms/icons/new_switch.png | Bin 0 -> 524 bytes .../stencilsets/xforms/icons/new_textarea.png | Bin 0 -> 419 bytes .../stencilsets/xforms/icons/new_trigger.png | Bin 0 -> 174 bytes .../stencilsets/xforms/icons/new_upload.png | Bin 0 -> 185 bytes .../editor-app/stencilsets/xforms/xforms.png | Bin 0 -> 830 bytes .../designer/editor-app/toolbar-controller.js | 186 + .../static/designer/editor-app/tour.js | 201 + .../resources/static/designer/favicon.ico | Bin 0 -> 102134 bytes .../designer/fonts/TitilliumWeb-Bold.ttf | Bin 0 -> 59908 bytes .../designer/fonts/TitilliumWeb-Regular.ttf | Bin 0 -> 63752 bytes .../designer/fonts/cherokee-webfont.eot | Bin 0 -> 4160 bytes .../designer/fonts/cherokee-webfont.svg | 49 + .../designer/fonts/cherokee-webfont.ttf | Bin 0 -> 6896 bytes .../designer/fonts/cherokee-webfont.woff | Bin 0 -> 4816 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20290 bytes .../fonts/glyphicons-halflings-regular.svg | 229 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 41236 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23292 bytes .../designer/fonts/lato-bold-webfont.eot | Bin 0 -> 28830 bytes .../designer/fonts/lato-bold-webfont.svg | 4551 +++ .../designer/fonts/lato-bold-webfont.ttf | Bin 0 -> 58344 bytes .../designer/fonts/lato-bold-webfont.woff | Bin 0 -> 32400 bytes .../designer/fonts/lato-regular-webfont.eot | Bin 0 -> 28222 bytes .../designer/fonts/lato-regular-webfont.svg | 4241 +++ .../designer/fonts/lato-regular-webfont.ttf | Bin 0 -> 57528 bytes .../designer/fonts/lato-regular-webfont.woff | Bin 0 -> 31816 bytes .../resources/static/designer/i18n/en-US.json | 2616 ++ .../resources/static/designer/i18n/en.json | 2616 ++ .../resources/static/designer/i18n/es.json | 872 + .../resources/static/designer/i18n/fr.json | 1008 + .../resources/static/designer/i18n/pt-BR.json | 818 + .../resources/static/designer/i18n/zh-CN.json | 2736 ++ .../resources/static/designer/i18n/zh-TW.json | 1006 + .../images/android-chrome-192x192.png | Bin 0 -> 4310 bytes .../images/android-chrome-384x384.png | Bin 0 -> 10466 bytes .../designer/images/apple-touch-icon.png | Bin 0 -> 2788 bytes .../static/designer/images/favicon-16x16.png | Bin 0 -> 693 bytes .../static/designer/images/favicon-32x32.png | Bin 0 -> 996 bytes .../static/designer/images/flowable-logo.png | Bin 0 -> 11874 bytes .../designer/images/flowable-logo@2x.png | Bin 0 -> 25782 bytes .../images/form-builder/amountfield-icon.png | Bin 0 -> 3174 bytes .../images/form-builder/booleanfield-icon.png | Bin 0 -> 694 bytes .../images/form-builder/choicefield-icon.png | Bin 0 -> 764 bytes .../images/form-builder/datefield-icon.png | Bin 0 -> 520 bytes .../images/form-builder/decimalfield-icon.png | Bin 0 -> 3174 bytes .../form-builder/dropdownfield-icon.png | Bin 0 -> 492 bytes .../form-builder/dynamic-table-icon.png | Bin 0 -> 1744 bytes .../images/form-builder/group-icon.png | Bin 0 -> 305 bytes .../images/form-builder/headline-icon.png | Bin 0 -> 219 bytes .../form-builder/headline-with-line-icon.png | Bin 0 -> 229 bytes .../form-builder/horizontal-line-icon.png | Bin 0 -> 161 bytes .../images/form-builder/hyperlink-icon.png | Bin 0 -> 2326 bytes .../multi-line-textfield-icon.png | Bin 0 -> 489 bytes .../images/form-builder/numberfield-icon.png | Bin 0 -> 521 bytes .../images/form-builder/password-icon.png | Bin 0 -> 1021 bytes .../images/form-builder/peoplefield-icon.png | Bin 0 -> 789 bytes .../images/form-builder/readonly-icon.png | Bin 0 -> 497 bytes .../form-builder/readonly-text-icon.png | Bin 0 -> 301 bytes .../images/form-builder/spacer-icon.png | Bin 0 -> 466 bytes .../images/form-builder/textfield-icon.png | Bin 0 -> 434 bytes .../images/form-builder/uploadfield-icon.png | Bin 0 -> 638 bytes .../static/designer/images/glasspane.png | Bin 0 -> 46744 bytes .../static/designer/images/line-1px.png | Bin 0 -> 3199 bytes .../resources/static/designer/images/line.png | Bin 0 -> 147 bytes .../static/designer/images/mstile-150x150.png | Bin 0 -> 3250 bytes .../designer/images/safari-pinned-tab.svg | 26 + .../designer/images/tour/open-group.gif | Bin 0 -> 44216 bytes .../images/tour/sequenceflow-bendpoint.gif | Bin 0 -> 74199 bytes .../static/designer/images/tour/tour-dnd.gif | Bin 0 -> 81854 bytes .../main/resources/static/designer/index.html | 277 + .../angular-animate_1.3.13/angular-animate.js | 2137 ++ .../angular-animate.min.js | 33 + .../angular-animate.min.js.map | 8 + .../angular-cookies_1.3.13/angular-cookies.js | 206 + .../angular-cookies.min.js | 8 + .../angular-cookies.min.js.map | 8 + .../angular-drag-and-drop-lists.js | 501 + .../angular-drag-and-drop-lists.min.js | 1 + .../angular-dragdrop.js | 360 + .../angular-dragdrop.min.js | 29 + .../angular-gridster.js | 2109 ++ .../angular-gridster.min.css | 1 + .../angular-gridster.min.js | 8 + .../hotkeys--activiti-patch.js | 1533 + .../libs/angular-hotkeys_1.4.5/hotkeys.css | 110 + .../libs/angular-hotkeys_1.4.5/hotkeys.js | 1523 + .../angular-hotkeys_1.4.5/hotkeys.min.css | 8 + .../libs/angular-hotkeys_1.4.5/hotkeys.min.js | 7 + .../loading-bar.min.css | 8 + .../loading-bar.min.js | 7 + .../angular-mocks_1.2.13/angular-mocks.js | 2136 ++ .../angular-resource.js | 667 + .../angular-resource.min.js | 13 + .../angular-resource.min.js.map | 8 + .../angular-route_1.3.13/angular-route.js | 989 + .../angular-route_1.3.13/angular-route.min.js | 15 + .../angular-route.min.js.map | 8 + .../angular-sanitize.js | 681 + .../angular-sanitize.min.js | 16 + .../angular-sanitize.min.js.map | 8 + .../angular-scroll.min.js | 1 + .../angular-spectrum-colorpicker.min.js | 2 + .../spectrum.css | 519 + .../spectrum.js | 2080 ++ .../libs/angular-strap_2.1.6/angular-strap.js | 5014 +++ .../angular-strap_2.1.6/angular-strap.min.js | 11 + .../angular-strap.min.js.map | 1 + .../angular-strap_2.1.6/angular-strap.tpl.js | 89 + .../angular-strap.tpl.min.js | 8 + .../.bower.json | 19 + .../angular-translate-loader-static-files.js | 112 + ...gular-translate-loader-static-files.min.js | 6 + .../.bower.json | 20 + .../angular-translate-storage-cookie.js | 121 + .../angular-translate-storage-cookie.min.js | 6 + .../angular-translate.js | 3709 ++ .../angular-translate.min.js | 6 + .../designer/libs/angular_1.3.13/angular.js | 26130 ++++++++++++++ .../libs/angular_1.3.13/angular.min.js | 250 + .../libs/angular_1.3.13/angular.min.js.map | 8 + .../angular-nvd3-directives.min.js | 3 + .../autofill-events_1.0.0/autofill-event.js | 133 + .../daterangepicker-bs3.css | 267 + .../daterangepicker.js | 1026 + .../bootstrap-tour_0.9.1/bootstrap-tour.js | 716 + .../bootstrap-tour.min.css | 19 + .../bootstrap-tour.min.js | 19 + .../bootstrap_3.1.1/css/bootstrap-theme.css | 347 + .../css/bootstrap-theme.css.map | 1 + .../css/bootstrap-theme.min.css | 7 + .../libs/bootstrap_3.1.1/css/bootstrap.css | 5785 ++++ .../bootstrap_3.1.1/css/bootstrap.css.map | 1 + .../bootstrap_3.1.1/css/bootstrap.min.css | 7 + .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20335 bytes .../fonts/glyphicons-halflings-regular.svg | 229 + .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 41280 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23320 bytes .../libs/bootstrap_3.1.1/js/bootstrap.js | 1951 ++ .../libs/bootstrap_3.1.1/js/bootstrap.min.js | 6 + .../libs/es5-shim-15.3.4.5/.bower.json | 14 + .../libs/es5-shim-15.3.4.5/.gitignore | 2 + .../designer/libs/es5-shim-15.3.4.5/CHANGES | 93 + .../libs/es5-shim-15.3.4.5/CONTRIBUTORS.md | 25 + .../designer/libs/es5-shim-15.3.4.5/LICENSE | 19 + .../designer/libs/es5-shim-15.3.4.5/README.md | 161 + .../libs/es5-shim-15.3.4.5/es5-sham.js | 444 + .../libs/es5-shim-15.3.4.5/es5-sham.map | 1 + .../libs/es5-shim-15.3.4.5/es5-sham.min.js | 4 + .../libs/es5-shim-15.3.4.5/es5-shim.js | 1314 + .../libs/es5-shim-15.3.4.5/es5-shim.map | 1 + .../libs/es5-shim-15.3.4.5/es5-shim.min.js | 4 + .../libs/es5-shim-15.3.4.5/package.json | 34 + .../es5-shim-15.3.4.5/tests/helpers/h-kill.js | 64 + .../tests/helpers/h-matchers.js | 34 + .../libs/es5-shim-15.3.4.5/tests/helpers/h.js | 3 + .../libs/es5-shim-15.3.4.5/tests/index.html | 64 + .../es5-shim-15.3.4.5/tests/index.min.html | 63 + .../tests/lib/jasmine-html.js | 190 + .../es5-shim-15.3.4.5/tests/lib/jasmine.css | 166 + .../es5-shim-15.3.4.5/tests/lib/jasmine.js | 2477 ++ .../tests/lib/jasmine_favicon.png | Bin 0 -> 905 bytes .../libs/es5-shim-15.3.4.5/tests/lib/json2.js | 478 + .../es5-shim-15.3.4.5/tests/spec/s-array.js | 1223 + .../es5-shim-15.3.4.5/tests/spec/s-date.js | 152 + .../tests/spec/s-function.js | 147 + .../es5-shim-15.3.4.5/tests/spec/s-number.js | 14 + .../es5-shim-15.3.4.5/tests/spec/s-object.js | 181 + .../es5-shim-15.3.4.5/tests/spec/s-string.js | 204 + .../handsontable.full.min.css | 31 + .../handsontable.full.min.js | 97 + .../libs/html2canvas_0.4.1/html2canvas.js | 2871 ++ .../libs/jquery-ui-1.10.3.custom.min.js | 6 + .../designer/libs/jquery_1.11.0/jquery.js | 9789 ++++++ .../designer/libs/jquery_1.11.0/jquery.min.js | 4 + .../libs/jquery_1.11.0/jquery.min.map | 1 + .../static/designer/libs/json3_3.2.6/LICENSE | 20 + .../designer/libs/json3_3.2.6/lib/json3.js | 861 + .../libs/json3_3.2.6/lib/json3.min.js | 18 + .../libs/momentjs_2.18.1/momentjs.min.js | 505 + .../libs/ng-file-upload/FileAPI.flash.swf | Bin 0 -> 36947 bytes .../designer/libs/ng-file-upload/FileAPI.js | 4249 +++ .../libs/ng-file-upload/FileAPI.min.js | 3 + .../libs/ng-file-upload/ng-file-upload-all.js | 982 + .../ng-file-upload/ng-file-upload-all.min.js | 2 + .../ng-file-upload/ng-file-upload-shim.js | 376 + .../ng-file-upload/ng-file-upload-shim.min.js | 2 + .../libs/ng-file-upload/ng-file-upload.js | 605 + .../libs/ng-file-upload/ng-file-upload.min.js | 2 + .../ng-handsontable_0.13/ngHandsontable.js | 607 + .../ngHandsontable.min.js | 11 + .../libs/nvd3_1.1.15-beta/nvd3.min.css | 1 + .../libs/nvd3_1.1.15-beta/nvd3.min.js | 6 + .../designer/libs/sizzle_1.10.16/.bower.json | 33 + .../libs/sizzle_1.10.16/tasks/commit.js | 10 + .../libs/sizzle_1.10.16/tasks/compile.js | 34 + .../libs/sizzle_1.10.16/tasks/dist.js | 35 + .../libs/sizzle_1.10.16/tasks/release.js | 43 + .../designer/libs/sizzle_1.10.16/tasks/tag.js | 9 + .../libs/sizzle_1.10.16/tasks/version.js | 35 + .../libs/sizzle_1.10.16/test/data/empty.js | 0 .../sizzle_1.10.16/test/data/mixed_sort.html | 22 + .../libs/sizzle_1.10.16/test/data/testinit.js | 136 + .../libs/sizzle_1.10.16/test/index.html | 242 + .../libs/sizzle_1.10.16/test/jquery.js | 9597 ++++++ .../sizzle_1.10.16/test/libs/qunit/qunit.css | 244 + .../sizzle_1.10.16/test/libs/qunit/qunit.js | 2212 ++ .../sizzle_1.10.16/test/unit/extending.js | 95 + .../libs/sizzle_1.10.16/test/unit/selector.js | 1138 + .../sizzle_1.10.16/test/unit/utilities.js | 169 + .../designer/libs/ui-grid_3.0.0/ui-grid.css | 1996 ++ .../designer/libs/ui-grid_3.0.0/ui-grid.eot | Bin 0 -> 10320 bytes .../designer/libs/ui-grid_3.0.0/ui-grid.js | 28540 ++++++++++++++++ .../libs/ui-grid_3.0.0/ui-grid.min.css | 4 + .../libs/ui-grid_3.0.0/ui-grid.min.js | 15 + .../designer/libs/ui-grid_3.0.0/ui-grid.svg | 56 + .../designer/libs/ui-grid_3.0.0/ui-grid.ttf | Bin 0 -> 10156 bytes .../designer/libs/ui-grid_3.0.0/ui-grid.woff | Bin 0 -> 5728 bytes .../resources/static/designer/manifest.json | 17 + .../static/designer/scripts/app-cfg.js | 27 + .../resources/static/designer/scripts/app.js | 381 + .../scripts/common/controllers/about.js | 43 + .../designer/scripts/common/directives.js | 1279 + .../scripts/common/providers-config.js | 46 + .../common/services/recursion-helper.js | 56 + .../common/services/resource-service.js | 146 + .../app-definition-toolbar-default-actions.js | 150 + .../configuration/app-definition-toolbar.js | 33 + .../decision-table-toolbar-default-actions.js | 221 + .../configuration/decision-table-toolbar.js | 36 + .../form-builder-toolbar-default-actions.js | 217 + .../configuration/form-builder-toolbar.js | 33 + .../scripts/configuration/url-config.js | 247 + .../controllers/app-definition-builder.js | 325 + .../app-definition-toolbar-controller.js | 52 + .../scripts/controllers/app-definition.js | 328 + .../scripts/controllers/app-definitions.js | 289 + .../designer/scripts/controllers/casemodel.js | 171 + .../scripts/controllers/casemodels.js | 284 + .../controllers/decision-table-editor.js | 1206 + .../decision-table-toolbar-controller.js | 55 + .../scripts/controllers/decision-table.js | 737 + .../scripts/controllers/decision-tables.js | 306 + .../scripts/controllers/form-builder.js | 321 + .../scripts/controllers/form-readonly-view.js | 75 + .../controllers/form-toolbar-controller.js | 52 + .../designer/scripts/controllers/form.js | 149 + .../designer/scripts/controllers/forms.js | 247 + .../controllers/model-common-actions.js | 273 + .../designer/scripts/controllers/process.js | 173 + .../designer/scripts/controllers/processes.js | 296 + .../designer/scripts/editor-directives.js | 333 + .../designer/scripts/resource-loader.js | 94 + .../services/decision-table-service.js | 169 + .../scripts/services/form-services.js | 256 + .../scripts/services/identity-services.js | 81 + .../scripts/services/util-services.js | 29 + .../designer/styles/common/bootstrap.min.css | 2 + .../designer/styles/common/style-retina.css | 26 + .../static/designer/styles/common/style.css | 3282 ++ .../static/designer/styles/style-editor.css | 1884 + .../views/app-definition-builder.html | 146 + .../static/designer/views/app-definition.html | 144 + .../designer/views/app-definitions.html | 103 + .../static/designer/views/casemodel.html | 65 + .../static/designer/views/casemodels.html | 98 + .../designer/views/decision-table-editor.html | 100 + .../static/designer/views/decision-table.html | 103 + .../designer/views/decision-tables.html | 86 + .../static/designer/views/form-builder.html | 134 + .../resources/static/designer/views/form.html | 64 + .../static/designer/views/forms.html | 86 + .../views/popover/formfield-edit-popover.html | 222 + .../designer/views/popover/history.html | 20 + .../views/popover/select-app-icon.html | 18 + .../views/popover/select-app-theme.html | 25 + .../views/popover/select-group-popover.html | 61 + .../views/popup/app-definition-create.html | 45 + .../views/popup/app-definition-delete.html | 38 + .../views/popup/app-definition-duplicate.html | 45 + .../views/popup/app-definition-import.html | 86 + .../popup/app-definition-models-included.html | 72 + .../views/popup/app-definition-publish.html | 66 + .../popup/app-definition-save-model.html | 102 + .../views/popup/app-definitions-import.html | 90 + .../views/popup/casemodel-create.html | 45 + .../views/popup/casemodel-duplicate.html | 44 + .../views/popup/casemodel-import.html | 80 + .../views/popup/decision-table-create.html | 45 + .../views/popup/decision-table-duplicate.html | 45 + .../popup/decision-table-edit-hit-policy.html | 63 + .../decision-table-edit-input-expression.html | 100 + ...decision-table-edit-output-expression.html | 100 + .../views/popup/decision-table-import.html | 80 + .../popup/decision-table-save-model.html | 60 + .../designer/views/popup/form-create.html | 45 + .../designer/views/popup/form-duplicate.html | 44 + .../designer/views/popup/form-save-model.html | 52 + .../designer/views/popup/model-delete.html | 58 + .../designer/views/popup/model-edit.html | 46 + .../views/popup/model-use-as-new-version.html | 45 + .../designer/views/popup/process-create.html | 45 + .../views/popup/process-duplicate.html | 45 + .../designer/views/popup/process-import.html | 80 + .../views/popup/subprocess-create.html | 34 + .../static/designer/views/process.html | 65 + .../static/designer/views/processes.html | 98 + .../decision-table-header-template.html | 19 + .../decision-table-headercell-template.html | 1 + .../form-builder-element-template.html | 132 + zbf-common/pom.xml | 196 + .../com/zbf/common/annotation/Anonymous.java | 19 + .../com/zbf/common/annotation/DataScope.java | 33 + .../com/zbf/common/annotation/DataSource.java | 28 + .../java/com/zbf/common/annotation/Excel.java | 199 + .../com/zbf/common/annotation/Excels.java | 18 + .../java/com/zbf/common/annotation/Log.java | 51 + .../com/zbf/common/annotation/NoAutoFill.java | 12 + .../zbf/common/annotation/RateLimiter.java | 40 + .../zbf/common/annotation/RepeatSubmit.java | 31 + .../com/zbf/common/config/RuoYiConfig.java | 122 + .../zbf/common/config/TaskExecutorConfig.java | 25 + .../zbf/common/constant/CacheConstants.java | 44 + .../com/zbf/common/constant/Constants.java | 174 + .../com/zbf/common/constant/GenConstants.java | 117 + .../com/zbf/common/constant/HttpStatus.java | 94 + .../common/constant/ScheduleConstants.java | 50 + .../zbf/common/constant/UserConstants.java | 78 + .../core/controller/BaseController.java | 203 + .../core/controller/ManualPagination.java | 26 + .../zbf/common/core/domain/AjaxResult.java | 216 + .../zbf/common/core/domain/BaseEntity.java | 129 + .../java/com/zbf/common/core/domain/R.java | 115 + .../zbf/common/core/domain/TreeEntity.java | 79 + .../zbf/common/core/domain/TreeSelect.java | 77 + .../common/core/domain/entity/SysDept.java | 213 + .../core/domain/entity/SysDictData.java | 176 + .../core/domain/entity/SysDictType.java | 96 + .../common/core/domain/entity/SysMenu.java | 259 + .../common/core/domain/entity/SysRole.java | 240 + .../common/core/domain/entity/SysUser.java | 379 + .../common/core/domain/model/LoginBody.java | 69 + .../common/core/domain/model/LoginUser.java | 266 + .../core/domain/model/RegisterBody.java | 11 + .../com/zbf/common/core/page/PageDomain.java | 101 + .../zbf/common/core/page/TableDataInfo.java | 98 + .../zbf/common/core/page/TableSupport.java | 56 + .../com/zbf/common/core/redis/RedisCache.java | 268 + .../com/zbf/common/core/text/CharsetKit.java | 86 + .../com/zbf/common/core/text/Convert.java | 1006 + .../zbf/common/core/text/StrFormatter.java | 92 + .../com/zbf/common/enums/BusinessStatus.java | 20 + .../com/zbf/common/enums/BusinessType.java | 61 + .../com/zbf/common/enums/DataSourceType.java | 19 + .../java/com/zbf/common/enums/HttpMethod.java | 36 + .../java/com/zbf/common/enums/LimitType.java | 20 + .../com/zbf/common/enums/OperatorType.java | 24 + .../java/com/zbf/common/enums/UserStatus.java | 30 + .../zbf/common/exception/CustomException.java | 43 + .../common/exception/DemoModeException.java | 15 + .../zbf/common/exception/GlobalException.java | 58 + .../common/exception/NonCaptureException.java | 13 + .../common/exception/ServiceException.java | 74 + .../zbf/common/exception/UtilException.java | 26 + .../common/exception/base/BaseException.java | 97 + .../common/exception/file/FileException.java | 19 + .../FileNameLengthLimitExceededException.java | 16 + .../file/FileSizeLimitExceededException.java | 16 + .../exception/file/FileUploadException.java | 61 + .../file/InvalidExtensionException.java | 80 + .../common/exception/job/TaskException.java | 34 + .../exception/user/BlackListException.java | 16 + .../exception/user/CaptchaException.java | 16 + .../user/CaptchaExpireException.java | 16 + .../common/exception/user/UserException.java | 18 + .../user/UserNotExistsException.java | 16 + .../user/UserPasswordNotMatchException.java | 16 + ...UserPasswordRetryLimitExceedException.java | 16 + .../filter/PropertyPreExcludeFilter.java | 24 + .../zbf/common/filter/RepeatableFilter.java | 52 + .../filter/RepeatedlyRequestWrapper.java | 76 + .../java/com/zbf/common/filter/XssFilter.java | 75 + .../filter/XssHttpServletRequestWrapper.java | 111 + .../main/java/com/zbf/common/utils/Arith.java | 114 + .../com/zbf/common/utils/CommonUtils.java | 107 + .../java/com/zbf/common/utils/DateUtil.java | 301 + .../java/com/zbf/common/utils/DateUtils.java | 191 + .../java/com/zbf/common/utils/DictUtils.java | 252 + .../com/zbf/common/utils/ExceptionUtil.java | 39 + .../java/com/zbf/common/utils/LogUtils.java | 18 + .../com/zbf/common/utils/MessageUtils.java | 26 + .../zbf/common/utils/OrderCodeFactory.java | 115 + .../java/com/zbf/common/utils/PageUtils.java | 35 + .../java/com/zbf/common/utils/RsaUtils.java | 169 + .../com/zbf/common/utils/SecurityUtils.java | 204 + .../com/zbf/common/utils/ServletUtils.java | 218 + .../com/zbf/common/utils/StringUtils.java | 638 + .../java/com/zbf/common/utils/Threads.java | 99 + .../com/zbf/common/utils/bean/BeanUtils.java | 110 + .../zbf/common/utils/bean/BeanValidators.java | 24 + .../zbf/common/utils/file/FileTypeUtils.java | 76 + .../common/utils/file/FileUploadUtils.java | 232 + .../com/zbf/common/utils/file/FileUtils.java | 291 + .../com/zbf/common/utils/file/ImageUtils.java | 98 + .../zbf/common/utils/file/MimeTypeUtils.java | 59 + .../com/zbf/common/utils/html/EscapeUtil.java | 167 + .../com/zbf/common/utils/html/HTMLFilter.java | 570 + .../com/zbf/common/utils/http/HttpHelper.java | 55 + .../com/zbf/common/utils/http/HttpUtils.java | 274 + .../com/zbf/common/utils/ip/AddressUtils.java | 56 + .../java/com/zbf/common/utils/ip/IpUtils.java | 382 + .../com/zbf/common/utils/oConvertUtils.java | 649 + .../common/utils/poi/ExcelHandlerAdapter.java | 24 + .../com/zbf/common/utils/poi/ExcelUtil.java | 1910 ++ .../common/utils/reflect/ReflectUtils.java | 410 + .../com/zbf/common/utils/sign/Base64.java | 291 + .../com/zbf/common/utils/sign/Md5Utils.java | 67 + .../zbf/common/utils/spring/SpringUtils.java | 158 + .../com/zbf/common/utils/sql/SqlUtil.java | 70 + .../com/zbf/common/utils/uuid/IdUtils.java | 49 + .../java/com/zbf/common/utils/uuid/Seq.java | 86 + .../java/com/zbf/common/utils/uuid/UUID.java | 484 + .../src/main/java/com/zbf/common/xss/Xss.java | 27 + .../java/com/zbf/common/xss/XssValidator.java | 39 + zbf-framework/pom.xml | 64 + .../framework/aspectj/DataScopeAspect.java | 192 + .../framework/aspectj/DataSourceAspect.java | 72 + .../com/zbf/framework/aspectj/LogAspect.java | 263 + .../framework/aspectj/RateLimiterAspect.java | 89 + .../framework/config/ApplicationConfig.java | 30 + .../zbf/framework/config/CaptchaConfig.java | 83 + .../com/zbf/framework/config/DruidConfig.java | 127 + .../config/FastJson2JsonRedisSerializer.java | 52 + .../zbf/framework/config/FilterConfig.java | 58 + .../framework/config/KaptchaTextCreator.java | 68 + .../zbf/framework/config/MyBatisConfig.java | 132 + .../framework/config/MyMetaObjectHandler.java | 76 + .../framework/config/MybatisPlusConfig.java | 66 + .../config/P6spySqlFormatConfig.java | 23 + .../com/zbf/framework/config/RedisConfig.java | 69 + .../zbf/framework/config/ResourcesConfig.java | 73 + .../zbf/framework/config/SecurityConfig.java | 149 + .../zbf/framework/config/ServerConfig.java | 32 + .../framework/config/ThreadPoolConfig.java | 63 + .../config/properties/DruidProperties.java | 89 + .../properties/PermitAllUrlProperties.java | 73 + .../datasource/DynamicDataSource.java | 26 + .../DynamicDataSourceContextHolder.java | 45 + .../interceptor/RepeatSubmitInterceptor.java | 56 + .../impl/SameUrlDataInterceptor.java | 110 + .../zbf/framework/manager/AsyncManager.java | 55 + .../framework/manager/ShutdownManager.java | 39 + .../manager/factory/AsyncFactory.java | 102 + .../context/AuthenticationContextHolder.java | 28 + .../context/PermissionContextHolder.java | 27 + .../filter/JwtAuthenticationTokenFilter.java | 44 + .../handle/AuthenticationEntryPointImpl.java | 34 + .../handle/LogoutSuccessHandlerImpl.java | 54 + .../com/zbf/framework/web/domain/Server.java | 240 + .../zbf/framework/web/domain/server/Cpu.java | 101 + .../zbf/framework/web/domain/server/Jvm.java | 130 + .../zbf/framework/web/domain/server/Mem.java | 61 + .../zbf/framework/web/domain/server/Sys.java | 84 + .../framework/web/domain/server/SysFile.java | 114 + .../web/exception/GlobalExceptionHandler.java | 149 + .../web/service/PermissionService.java | 159 + .../web/service/SysLoginService.java | 198 + .../web/service/SysPasswordService.java | 86 + .../web/service/SysPermissionService.java | 83 + .../web/service/SysRegisterService.java | 115 + .../framework/web/service/TokenService.java | 256 + .../web/service/UserDetailsServiceImpl.java | 66 + zbf-generator/pom.xml | 51 + .../com/zbf/generator/config/GenConfig.java | 73 + .../generator/controller/GenController.java | 258 + .../com/zbf/generator/domain/GenTable.java | 385 + .../zbf/generator/domain/GenTableColumn.java | 373 + .../mapper/GenTableColumnMapper.java | 60 + .../zbf/generator/mapper/GenTableMapper.java | 91 + .../service/GenTableColumnServiceImpl.java | 68 + .../service/GenTableServiceImpl.java | 531 + .../service/IGenTableColumnService.java | 44 + .../generator/service/IGenTableService.java | 130 + .../com/zbf/generator/util/ColumnUtils.java | 47 + .../java/com/zbf/generator/util/GenUtils.java | 257 + .../generator/util/VelocityInitializer.java | 34 + .../com/zbf/generator/util/VelocityUtils.java | 404 + .../src/main/resources/generator.yml | 10 + .../mapper/generator/GenTableColumnMapper.xml | 127 + .../mapper/generator/GenTableMapper.xml | 206 + .../main/resources/vm/java/controller.java.vm | 149 + .../src/main/resources/vm/java/domain.java.vm | 187 + .../src/main/resources/vm/java/mapper.java.vm | 109 + .../main/resources/vm/java/service.java.vm | 86 + .../resources/vm/java/serviceImpl.java.vm | 211 + .../main/resources/vm/java/sub-domain.java.vm | 162 + .../src/main/resources/vm/js/api.js.vm | 72 + .../src/main/resources/vm/sql/sql.vm | 22 + .../main/resources/vm/vue/index-tree.vue.vm | 602 + .../src/main/resources/vm/vue/index.vue.vm | 757 + .../resources/vm/vue/v3/index-tree.vue.vm | 474 + .../src/main/resources/vm/vue/v3/index.vue.vm | 590 + .../src/main/resources/vm/xml/mapper.xml.vm | 148 + zbf-quartz/pom.xml | 44 + .../com/zbf/quartz/config/ScheduleConfig.java | 57 + .../quartz/controller/SysJobController.java | 185 + .../controller/SysJobLogController.java | 92 + .../java/com/zbf/quartz/domain/SysJob.java | 171 + .../java/com/zbf/quartz/domain/SysJobLog.java | 155 + .../zbf/quartz/mapper/SysJobLogMapper.java | 64 + .../com/zbf/quartz/mapper/SysJobMapper.java | 67 + .../zbf/quartz/service/ISysJobLogService.java | 56 + .../zbf/quartz/service/ISysJobService.java | 102 + .../service/impl/SysJobLogServiceImpl.java | 88 + .../service/impl/SysJobServiceImpl.java | 261 + .../java/com/zbf/quartz/task/DataPushing.java | 160 + .../zbf/quartz/task/GeneratePlcIdTask.java | 123 + .../com/zbf/quartz/task/InventoryTask.java | 124 + .../main/java/com/zbf/quartz/task/RyTask.java | 28 + .../com/zbf/quartz/task/UpdatePallet.java | 23 + .../zbf/quartz/util/AbstractQuartzJob.java | 107 + .../java/com/zbf/quartz/util/CronUtils.java | 63 + .../com/zbf/quartz/util/JobInvokeUtil.java | 182 + .../QuartzDisallowConcurrentExecution.java | 21 + .../zbf/quartz/util/QuartzJobExecution.java | 19 + .../com/zbf/quartz/util/ScheduleUtils.java | 141 + .../mapper/quartz/SysJobLogMapper.xml | 94 + .../resources/mapper/quartz/SysJobMapper.xml | 111 + zbf-system/pom.xml | 52 + .../com/zbf/system/config/CommonConfig.java | 11 + .../java/com/zbf/system/config/D_Service.java | 782 + .../com/zbf/system/domain/ActRuExecution.java | 447 + .../com/zbf/system/domain/AppVersions.java | 60 + .../java/com/zbf/system/domain/DataItem.java | 15 + .../com/zbf/system/domain/DeadLetterJob.java | 86 + .../java/com/zbf/system/domain/DeviceLog.java | 111 + .../java/com/zbf/system/domain/FlowInfo.java | 142 + .../com/zbf/system/domain/InventoryCheck.java | 103 + .../com/zbf/system/domain/Leaveapply.java | 170 + .../java/com/zbf/system/domain/Meeting.java | 140 + .../com/zbf/system/domain/ModelParam.java | 54 + .../java/com/zbf/system/domain/OutBound.java | 222 + .../com/zbf/system/domain/OutStockVo.java | 18 + .../main/java/com/zbf/system/domain/Plc.java | 68 + .../java/com/zbf/system/domain/Process.java | 83 + .../java/com/zbf/system/domain/Purchase.java | 143 + .../domain/RfidQuantityUpdateRequest.java | 49 + .../zbf/system/domain/RfidQueryRequest.java | 14 + .../com/zbf/system/domain/SafetyStockVO.java | 76 + .../java/com/zbf/system/domain/SysCache.java | 81 + .../java/com/zbf/system/domain/SysConfig.java | 111 + .../com/zbf/system/domain/SysDeployForm.java | 64 + .../com/zbf/system/domain/SysExpression.java | 83 + .../java/com/zbf/system/domain/SysForm.java | 70 + .../com/zbf/system/domain/SysListener.java | 126 + .../com/zbf/system/domain/SysLogininfor.java | 144 + .../java/com/zbf/system/domain/SysNotice.java | 102 + .../com/zbf/system/domain/SysOperLog.java | 269 + .../java/com/zbf/system/domain/SysPost.java | 124 + .../com/zbf/system/domain/SysRoleDept.java | 46 + .../com/zbf/system/domain/SysRoleMenu.java | 46 + .../com/zbf/system/domain/SysTaskForm.java | 65 + .../system/domain/SysUserBusinessColumn.java | 183 + .../com/zbf/system/domain/SysUserOnline.java | 113 + .../com/zbf/system/domain/SysUserPost.java | 46 + .../com/zbf/system/domain/SysUserRole.java | 46 + .../main/java/com/zbf/system/domain/TAgv.java | 397 + .../system/domain/TBaseFinancialClass.java | 103 + .../com/zbf/system/domain/TBaseGoods.java | 839 + .../com/zbf/system/domain/TBaseGoodsBom.java | 170 + .../com/zbf/system/domain/TBasePallet.java | 347 + .../com/zbf/system/domain/TBaseProvider.java | 540 + .../com/zbf/system/domain/TBaseStorage.java | 274 + .../zbf/system/domain/TBaseStorageArea.java | 206 + .../domain/TBaseStorageAreaLocation.java | 529 + .../domain/TBaseStorageLocationRecord.java | 135 + .../com/zbf/system/domain/TCallNotice.java | 291 + .../zbf/system/domain/TCallNoticeOrder.java | 173 + .../com/zbf/system/domain/TCkOrderdetail.java | 521 + .../java/com/zbf/system/domain/TCkOrders.java | 506 + .../system/domain/TCkPickingwavegoods.java | 1164 + .../system/domain/TCkPickingwavegoodsBak.java | 1131 + .../java/com/zbf/system/domain/TErrorLog.java | 161 + .../java/com/zbf/system/domain/TMiStock.java | 606 + .../com/zbf/system/domain/TMiStockBak.java | 564 + .../com/zbf/system/domain/TMiStockDto.java | 4 + .../java/com/zbf/system/domain/TMiStockF.java | 588 + .../zbf/system/domain/TMiStockFUpdate.java | 89 + .../com/zbf/system/domain/TMiStockUpdate.java | 110 + .../com/zbf/system/domain/TMiXnStock.java | 604 + .../com/zbf/system/domain/TOngoodsshelf.java | 1140 + .../zbf/system/domain/TOngoodsshelfBak.java | 1268 + .../com/zbf/system/domain/TPanDetail.java | 168 + .../java/com/zbf/system/domain/TPanOrder.java | 120 + .../zbf/system/domain/TRkReceivingGoods.java | 451 + .../system/domain/TRkReceivingGoodsTab.java | 694 + .../com/zbf/system/domain/TRkWareNotice.java | 507 + .../zbf/system/domain/TRkWareNoticeBak.java | 491 + .../zbf/system/domain/TRkWareNoticeTab.java | 1256 + .../system/domain/TRkWareNoticeTabBak.java | 409 + .../system/domain/TRkWareNoticeTabExcel.java | 1199 + .../system/domain/TRkWareNoticeTabUpdate.java | 320 + .../system/domain/TRkXnWareNoticeTabBak.java | 409 + .../main/java/com/zbf/system/domain/TSeq.java | 89 + .../com/zbf/system/domain/TStockCheck.java | 1383 + .../com/zbf/system/domain/TUserConfig.java | 37 + .../com/zbf/system/domain/TUserFavorites.java | 106 + .../main/java/com/zbf/system/domain/Task.java | 13 + .../java/com/zbf/system/domain/TaskInfo.java | 164 + .../zbf/system/domain/TckOrderdetailBak.java | 572 + .../com/zbf/system/domain/TckOrdersBak.java | 452 + .../system/domain/TckXnOrderdetailBak.java | 572 + .../com/zbf/system/domain/TransferOrder.java | 130 + .../com/zbf/system/domain/VariableInfo.java | 58 + .../com/zbf/system/domain/vo/D_Instance.java | 15 + .../com/zbf/system/domain/vo/DataPayload.java | 13 + .../com/zbf/system/domain/vo/GoodsToD.java | 15 + .../com/zbf/system/domain/vo/GoodsVo.java | 31 + .../java/com/zbf/system/domain/vo/MetaVo.java | 106 + .../java/com/zbf/system/domain/vo/Quest.java | 21 + .../com/zbf/system/domain/vo/RouterVo.java | 157 + .../com/zbf/system/domain/vo/TCkOrdersVo.java | 13 + .../com/zbf/system/domain/vo/TMiStockVo.java | 529 + .../java/com/zbf/system/domain/vo/TPanVo.java | 18 + .../system/domain/vo/TRkWareNoticeTabVo.java | 460 + .../java/com/zbf/system/domain/vo/Types.java | 14 + .../zbf/system/listener/MyTaskListener.java | 108 + .../system/mapper/ActRuExecutionMapper.java | 68 + .../zbf/system/mapper/AppVersionsMapper.java | 74 + .../zbf/system/mapper/DeviceLogMapper.java | 79 + .../system/mapper/InventoryCheckMapper.java | 80 + .../zbf/system/mapper/LeaveapplyMapper.java | 63 + .../com/zbf/system/mapper/MeetingMapper.java | 63 + .../com/zbf/system/mapper/OutBoundMapper.java | 80 + .../java/com/zbf/system/mapper/PlcMapper.java | 33 + .../com/zbf/system/mapper/PurchaseMapper.java | 63 + .../system/mapper/RkWareNoticeTabMapper.java | 10 + .../zbf/system/mapper/SafetyStockMapper.java | 20 + .../zbf/system/mapper/SysConfigMapper.java | 76 + .../com/zbf/system/mapper/SysDeptMapper.java | 127 + .../zbf/system/mapper/SysDictDataMapper.java | 95 + .../zbf/system/mapper/SysDictTypeMapper.java | 83 + .../system/mapper/SysExpressionMapper.java | 61 + .../com/zbf/system/mapper/SysFormMapper.java | 62 + .../zbf/system/mapper/SysListenerMapper.java | 61 + .../system/mapper/SysLogininforMapper.java | 42 + .../com/zbf/system/mapper/SysMenuMapper.java | 125 + .../zbf/system/mapper/SysNoticeMapper.java | 60 + .../zbf/system/mapper/SysOperLogMapper.java | 48 + .../com/zbf/system/mapper/SysPostMapper.java | 99 + .../zbf/system/mapper/SysRoleDeptMapper.java | 47 + .../com/zbf/system/mapper/SysRoleMapper.java | 113 + .../zbf/system/mapper/SysRoleMenuMapper.java | 44 + .../zbf/system/mapper/SysTaskFormMapper.java | 62 + .../mapper/SysUserBusinessColumnMapper.java | 79 + .../com/zbf/system/mapper/SysUserMapper.java | 137 + .../zbf/system/mapper/SysUserPostMapper.java | 46 + .../zbf/system/mapper/SysUserRoleMapper.java | 62 + .../com/zbf/system/mapper/TAgvMapper.java | 79 + .../mapper/TBaseFinancialClassMapper.java | 79 + .../system/mapper/TBaseGoodsBomMapper.java | 79 + .../zbf/system/mapper/TBaseGoodsMapper.java | 98 + .../zbf/system/mapper/TBasePalletMapper.java | 86 + .../system/mapper/TBaseProviderMapper.java | 79 + .../TBaseStorageAreaLocationMapper.java | 91 + .../system/mapper/TBaseStorageAreaMapper.java | 79 + .../zbf/system/mapper/TBaseStorageMapper.java | 108 + .../zbf/system/mapper/TCallNoticeMapper.java | 87 + .../system/mapper/TCallNoticeOrderMapper.java | 87 + .../system/mapper/TCkOrderdetailMapper.java | 80 + .../zbf/system/mapper/TCkOrdersMapper.java | 133 + .../mapper/TCkPickingwavegoodsBakMapper.java | 79 + .../mapper/TCkPickingwavegoodsMapper.java | 99 + .../zbf/system/mapper/TErrorLogMapper.java | 79 + .../zbf/system/mapper/TMiStockBakMapper.java | 79 + .../zbf/system/mapper/TMiStockFMapper.java | 103 + .../com/zbf/system/mapper/TMiStockMapper.java | 152 + .../zbf/system/mapper/TMiXnStockMapper.java | 151 + .../system/mapper/TOngoodsshelfBakMapper.java | 79 + .../system/mapper/TOngoodsshelfMapper.java | 90 + .../zbf/system/mapper/TPanDetailMapper.java | 84 + .../zbf/system/mapper/TPanOrderMapper.java | 79 + .../mapper/TRkReceivingGoodsMapper.java | 121 + .../system/mapper/TRkWareNoticeBakMapper.java | 108 + .../system/mapper/TRkWareNoticeMapper.java | 175 + .../mapper/TRkWareNoticeTabBakMapper.java | 99 + .../system/mapper/TRkWareNoticeTabMapper.java | 80 + .../mapper/TRkXnWareNoticeTabBakMapper.java | 99 + .../com/zbf/system/mapper/TSeqMapper.java | 79 + .../zbf/system/mapper/TStockCheckMapper.java | 80 + .../zbf/system/mapper/TUserConfigMapper.java | 14 + .../system/mapper/TUserFavoritesMapper.java | 79 + .../mapper/TckOrderdetailBakMapper.java | 104 + .../zbf/system/mapper/TckOrdersBakMapper.java | 114 + .../mapper/TckXnOrderdetailBakMapper.java | 106 + .../system/mapper/TransferOrderMapper.java | 96 + .../com/zbf/system/print/BoxCodeEntity.java | 25 + .../main/java/com/zbf/system/print/Print.java | 29 + .../main/java/com/zbf/system/print/Req.java | 83 + .../com/zbf/system/print/RotateImage.java | 104 + .../com/zbf/system/print/SalesTicket.java | 262 + .../com/zbf/system/print/TWmsDataEntity.java | 105 + .../java/com/zbf/system/print/YcPrinter.java | 76 + .../system/service/IAppVersionsService.java | 79 + .../zbf/system/service/IDeviceLogService.java | 88 + .../service/IInventoryCheckService.java | 86 + .../system/service/ILeaveapplyService.java | 63 + .../zbf/system/service/IMeetingService.java | 63 + .../zbf/system/service/IOutBoundService.java | 87 + .../com/zbf/system/service/IPlcService.java | 32 + .../zbf/system/service/IPurchaseService.java | 62 + .../zbf/system/service/ISysConfigService.java | 89 + .../zbf/system/service/ISysDeptService.java | 124 + .../system/service/ISysDictDataService.java | 60 + .../system/service/ISysDictTypeService.java | 98 + .../system/service/ISysExpressionService.java | 61 + .../system/service/ISysListenerService.java | 61 + .../system/service/ISysLogininforService.java | 40 + .../zbf/system/service/ISysMenuService.java | 148 + .../zbf/system/service/ISysNoticeService.java | 60 + .../system/service/ISysOperLogService.java | 48 + .../zbf/system/service/ISysPostService.java | 99 + .../zbf/system/service/ISysRoleService.java | 175 + .../ISysUserBusinessColumnService.java | 86 + .../system/service/ISysUserOnlineService.java | 48 + .../zbf/system/service/ISysUserService.java | 212 + .../com/zbf/system/service/ITAgvService.java | 86 + .../service/ITBaseFinancialClassService.java | 86 + .../system/service/ITBaseGoodsBomService.java | 86 + .../system/service/ITBaseGoodsService.java | 92 + .../system/service/ITBasePalletService.java | 83 + .../system/service/ITBaseProviderService.java | 88 + .../ITBaseStorageAreaLocationService.java | 97 + .../service/ITBaseStorageAreaService.java | 89 + .../system/service/ITBaseStorageService.java | 100 + .../service/ITCallNoticeOrderService.java | 99 + .../system/service/ITCallNoticeService.java | 99 + .../service/ITCkOrderdetailService.java | 95 + .../zbf/system/service/ITCkOrdersService.java | 138 + .../ITCkPickingwavegoodsBakService.java | 95 + .../service/ITCkPickingwavegoodsService.java | 114 + .../zbf/system/service/ITErrorLogService.java | 86 + .../system/service/ITMiStockBakService.java | 86 + .../zbf/system/service/ITMiStockFService.java | 91 + .../zbf/system/service/ITMiStockService.java | 69 + .../system/service/ITMiXnStockService.java | 61 + .../service/ITOngoodsshelfBakService.java | 91 + .../system/service/ITOngoodsshelfService.java | 94 + .../zbf/system/service/ITOverdueService.java | 20 + .../system/service/ITPanDetailService.java | 87 + .../zbf/system/service/ITPanOrderService.java | 23 + .../service/ITRkReceivingGoodsService.java | 87 + .../service/ITRkWareNoticeBakService.java | 87 + .../system/service/ITRkWareNoticeService.java | 153 + .../service/ITRkWareNoticeTabBakService.java | 94 + .../service/ITRkWareNoticeTabService.java | 86 + .../ITRkXnWareNoticeTabBakService.java | 96 + .../system/service/ITSafetyStockService.java | 19 + .../com/zbf/system/service/ITSeqService.java | 92 + .../system/service/ITStockCheckService.java | 89 + .../system/service/ITUserConfigService.java | 12 + .../service/ITUserFavoritesService.java | 86 + .../service/ITckOrderdetailBakService.java | 90 + .../system/service/ITckOrdersBakService.java | 95 + .../service/ITckXnOrderdetailBakService.java | 92 + .../system/service/ITransferOrderService.java | 106 + .../system/service/LargeScreenService.java | 28 + .../service/impl/AppVersionsServiceImpl.java | 121 + .../service/impl/DeviceLogServiceImpl.java | 158 + .../impl/InventoryCheckServiceImpl.java | 130 + .../service/impl/LargeScreenServiceImpl.java | 317 + .../service/impl/LeaveapplyServiceImpl.java | 140 + .../service/impl/MeetingServiceImpl.java | 143 + .../service/impl/OutBoundServiceImpl.java | 218 + .../system/service/impl/PlcServiceImpl.java | 51 + .../service/impl/PurchaseServiceImpl.java | 141 + .../service/impl/SysConfigServiceImpl.java | 232 + .../service/impl/SysDeptServiceImpl.java | 338 + .../service/impl/SysDictDataServiceImpl.java | 111 + .../service/impl/SysDictTypeServiceImpl.java | 223 + .../impl/SysExpressionServiceImpl.java | 96 + .../service/impl/SysListenerServiceImpl.java | 96 + .../impl/SysLogininforServiceImpl.java | 65 + .../service/impl/SysMenuServiceImpl.java | 512 + .../service/impl/SysNoticeServiceImpl.java | 92 + .../service/impl/SysOperLogServiceImpl.java | 76 + .../service/impl/SysPostServiceImpl.java | 178 + .../service/impl/SysRoleServiceImpl.java | 429 + .../SysUserBusinessColumnServiceImpl.java | 132 + .../impl/SysUserOnlineServiceImpl.java | 96 + .../service/impl/SysUserServiceImpl.java | 577 + .../system/service/impl/TAgvServiceImpl.java | 129 + .../impl/TBaseFinancialClassServiceImpl.java | 132 + .../impl/TBaseGoodsBomServiceImpl.java | 132 + .../service/impl/TBaseGoodsServiceImpl.java | 575 + .../service/impl/TBasePalletServiceImpl.java | 203 + .../impl/TBaseProviderServiceImpl.java | 185 + .../TBaseStorageAreaLocationServiceImpl.java | 278 + .../impl/TBaseStorageAreaServiceImpl.java | 141 + .../service/impl/TBaseStorageServiceImpl.java | 208 + .../impl/TCallNoticeOrderServiceImpl.java | 155 + .../service/impl/TCallNoticeServiceImpl.java | 156 + .../impl/TCkOrderdetailServiceImpl.java | 197 + .../service/impl/TCkOrdersServiceImpl.java | 1669 + .../TCkPickingwavegoodsBakServiceImpl.java | 160 + .../impl/TCkPickingwavegoodsServiceImpl.java | 1095 + .../service/impl/TErrorLogServiceImpl.java | 129 + .../service/impl/TMiStockBakServiceImpl.java | 149 + .../service/impl/TMiStockFServiceImpl.java | 399 + .../service/impl/TMiStockServiceImpl.java | 354 + .../service/impl/TMiXnStockServiceImpl.java | 360 + .../impl/TOngoodsshelfBakServiceImpl.java | 154 + .../impl/TOngoodsshelfServiceImpl.java | 185 + .../service/impl/TOverdueServiceImpl.java | 53 + .../service/impl/TPanDetailServiceImpl.java | 149 + .../service/impl/TPanOrderServiceImpl.java | 144 + .../impl/TRkReceivingGoodsServiceImpl.java | 174 + .../impl/TRkWareNoticeBakServiceImpl.java | 177 + .../impl/TRkWareNoticeServiceImpl.java | 2960 ++ .../impl/TRkWareNoticeTabBakServiceImpl.java | 147 + .../impl/TRkWareNoticeTabServiceImpl.java | 132 + .../TRkXnWareNoticeTabBakServiceImpl.java | 190 + .../service/impl/TSafetyStockServiceImpl.java | 56 + .../system/service/impl/TSeqServiceImpl.java | 178 + .../service/impl/TStockCheckServiceImpl.java | 138 + .../service/impl/TUserConfigServiceImpl.java | 18 + .../impl/TUserFavoritesServiceImpl.java | 141 + .../impl/TckOrderdetailBakServiceImpl.java | 139 + .../service/impl/TckOrdersBakServiceImpl.java | 184 + .../impl/TckXnOrderdetailBakServiceImpl.java | 187 + .../impl/TransferOrderServiceImpl.java | 147 + .../com/zbf/system/test/GenericsExample.java | 19 + .../java/com/zbf/system/utils/DeviceInfo.java | 25 + .../java/com/zbf/system/utils/HttpUtils.java | 45 + .../java/com/zbf/system/utils/SignTool.java | 91 + .../main/java/com/zbf/system/utils/test.java | 18 + .../zbf/system/websocket/SemaphoreUtils.java | 59 + .../zbf/system/websocket/WebSocketConfig.java | 20 + .../zbf/system/websocket/WebSocketServer.java | 107 + .../zbf/system/websocket/WebSocketUsers.java | 172 + .../websocket/WsAuthHandlerInterceptor.java | 76 + .../mapper/system/ActRuExecutionMapper.xml | 213 + .../mapper/system/AppVersionsMapper.xml | 89 + .../mapper/system/DeviceLogMapper.xml | 84 + .../mapper/system/InventoryCheckMapper.xml | 79 + .../mapper/system/LeaveapplyMapper.xml | 87 + .../resources/mapper/system/MeetingMapper.xml | 85 + .../mapper/system/OutBoundMapper.xml | 126 + .../resources/mapper/system/PlcMapper.xml | 28 + .../mapper/system/PurchaseMapper.xml | 72 + .../mapper/system/SafetyStockMapper.xml | 49 + .../mapper/system/SysConfigMapper.xml | 117 + .../mapper/system/SysDeployFormMapper.xml | 66 + .../resources/mapper/system/SysDeptMapper.xml | 179 + .../mapper/system/SysDictDataMapper.xml | 124 + .../mapper/system/SysDictTypeMapper.xml | 105 + .../mapper/system/SysExpressionMapper.xml | 86 + .../resources/mapper/system/SysFormMapper.xml | 82 + .../mapper/system/SysListenerMapper.xml | 115 + .../mapper/system/SysLogininforMapper.xml | 57 + .../resources/mapper/system/SysMenuMapper.xml | 202 + .../mapper/system/SysNoticeMapper.xml | 89 + .../mapper/system/SysOperLogMapper.xml | 87 + .../resources/mapper/system/SysPostMapper.xml | 122 + .../mapper/system/SysRoleDeptMapper.xml | 41 + .../resources/mapper/system/SysRoleMapper.xml | 156 + .../mapper/system/SysRoleMenuMapper.xml | 34 + .../system/SysUserBusinessColumnMapper.xml | 131 + .../resources/mapper/system/SysUserMapper.xml | 288 + .../mapper/system/SysUserPostMapper.xml | 39 + .../mapper/system/SysUserRoleMapper.xml | 44 + .../resources/mapper/system/TAgvMapper.xml | 186 + .../system/TBaseFinancialClassMapper.xml | 100 + .../mapper/system/TBaseGoodsBomMapper.xml | 106 + .../mapper/system/TBaseGoodsMapper.xml | 370 + .../mapper/system/TBasePalletMapper.xml | 187 + .../mapper/system/TBaseProviderMapper.xml | 246 + .../system/TBaseStorageAreaLocationMapper.xml | 268 + .../mapper/system/TBaseStorageAreaMapper.xml | 128 + .../mapper/system/TBaseStorageMapper.xml | 179 + .../mapper/system/TCallNoticeMapper.xml | 161 + .../mapper/system/TCallNoticeOrderMapper.xml | 131 + .../mapper/system/TCkOrderdetailMapper.xml | 290 + .../mapper/system/TCkOrdersMapper.xml | 372 + .../system/TCkPickingwavegoodsBakMapper.xml | 417 + .../system/TCkPickingwavegoodsMapper.xml | 542 + .../mapper/system/TErrorLogMapper.xml | 101 + .../mapper/system/TMiStockBakMapper.xml | 541 + .../mapper/system/TMiStockFMapper.xml | 770 + .../mapper/system/TMiStockMapper.xml | 819 + .../mapper/system/TMiXnStockMapper.xml | 819 + .../mapper/system/TOngoodsshelfBakMapper.xml | 452 + .../mapper/system/TOngoodsshelfMapper.xml | 483 + .../mapper/system/TPanDetailMapper.xml | 249 + .../mapper/system/TPanOrderMapper.xml | 163 + .../mapper/system/TRkReceivingGoodsMapper.xml | 324 + .../mapper/system/TRkWareNoticeBakMapper.xml | 438 + .../mapper/system/TRkWareNoticeMapper.xml | 661 + .../system/TRkWareNoticeTabBakMapper.xml | 573 + .../mapper/system/TRkWareNoticeTabMapper.xml | 543 + .../system/TRkXnWareNoticeTabBakMapper.xml | 573 + .../resources/mapper/system/TSeqMapper.xml | 74 + .../mapper/system/TStockCheckMapper.xml | 525 + .../mapper/system/TUserConfigMapper.xml | 102 + .../mapper/system/TUserFavoritesMapper.xml | 155 + .../mapper/system/TckOrderdetailBakMapper.xml | 333 + .../mapper/system/TckOrdersBakMapper.xml | 297 + .../system/TckXnOrderdetailBakMapper.xml | 333 + .../mapper/system/TransferOrderMapper.xml | 84 + zbf-system/src/main/resources/print_logo.png | Bin 0 -> 11782 bytes zbf-ui/.editorconfig | 22 + zbf-ui/.env.development | 14 + zbf-ui/.env.production | 13 + zbf-ui/.env.staging | 10 + zbf-ui/.eslintignore | 10 + zbf-ui/.eslintrc.js | 199 + zbf-ui/.gitignore | 23 + zbf-ui/README.md | 40 + zbf-ui/babel.config.js | 13 + zbf-ui/bin/build.bat | 12 + zbf-ui/bin/package.bat | 12 + zbf-ui/bin/run-web.bat | 12 + zbf-ui/build/index.js | 35 + zbf-ui/package.json | 107 + zbf-ui/public/1.png | Bin 0 -> 1386 bytes zbf-ui/public/2.png | Bin 0 -> 1605 bytes zbf-ui/public/3.png | Bin 0 -> 2063 bytes zbf-ui/public/favicon.ico | Bin 0 -> 4286 bytes zbf-ui/public/html/ie.html | 46 + zbf-ui/public/img.png | Bin 0 -> 18122 bytes zbf-ui/public/index.html | 216 + zbf-ui/public/preview.html | 37 + zbf-ui/public/robots.txt | 2 + zbf-ui/src/App.vue | 28 + zbf-ui/src/api/common.js | 25 + zbf-ui/src/api/login.js | 68 + zbf-ui/src/api/menu.js | 9 + zbf-ui/src/api/monitor/cache.js | 57 + zbf-ui/src/api/monitor/job.js | 71 + zbf-ui/src/api/monitor/jobLog.js | 26 + zbf-ui/src/api/monitor/logininfor.js | 34 + zbf-ui/src/api/monitor/online.js | 18 + zbf-ui/src/api/monitor/operlog.js | 26 + zbf-ui/src/api/monitor/server.js | 9 + zbf-ui/src/api/system/batchAdjustment.js | 47 + zbf-ui/src/api/system/bom.js | 72 + zbf-ui/src/api/system/bound.js | 72 + zbf-ui/src/api/system/check.js | 89 + zbf-ui/src/api/system/ckOrders.js | 151 + .../src/api/system/ckPickingWavegoodsbak.js | 72 + zbf-ui/src/api/system/column.js | 72 + zbf-ui/src/api/system/config.js | 60 + zbf-ui/src/api/system/dept.js | 68 + zbf-ui/src/api/system/dict/data.js | 52 + zbf-ui/src/api/system/dict/type.js | 60 + zbf-ui/src/api/system/expression.js | 44 + zbf-ui/src/api/system/favorites.js | 72 + zbf-ui/src/api/system/financialClass.js | 72 + zbf-ui/src/api/system/freeze.js | 77 + zbf-ui/src/api/system/goods.js | 72 + zbf-ui/src/api/system/listener.js | 44 + zbf-ui/src/api/system/location.js | 71 + zbf-ui/src/api/system/log.js | 66 + zbf-ui/src/api/system/menu.js | 60 + zbf-ui/src/api/system/notice.js | 44 + zbf-ui/src/api/system/ongoodsShelfBak.js | 72 + zbf-ui/src/api/system/ongoodsshelf.js | 72 + zbf-ui/src/api/system/orderdetail.js | 72 + zbf-ui/src/api/system/orderdetailBak.js | 72 + zbf-ui/src/api/system/overInsured.js | 12 + zbf-ui/src/api/system/overdueStock.js | 12 + zbf-ui/src/api/system/pallet.js | 71 + zbf-ui/src/api/system/panDetail.js | 72 + zbf-ui/src/api/system/panOrder.js | 94 + zbf-ui/src/api/system/pickingwavegoods.js | 72 + zbf-ui/src/api/system/post.js | 44 + zbf-ui/src/api/system/provider.js | 72 + zbf-ui/src/api/system/rkRecevinggoods.js | 72 + zbf-ui/src/api/system/rkWareNoticeBak.js | 72 + zbf-ui/src/api/system/rkWareNoticeTabBak.js | 91 + zbf-ui/src/api/system/rkXnWareNoticeTabBak.js | 91 + zbf-ui/src/api/system/role.js | 126 + zbf-ui/src/api/system/safetyStock.js | 12 + zbf-ui/src/api/system/storage.js | 90 + zbf-ui/src/api/system/storageArea.js | 72 + zbf-ui/src/api/system/tMiStock.js | 124 + zbf-ui/src/api/system/tMiStockbak.js | 72 + zbf-ui/src/api/system/tMiXnStock.js | 124 + zbf-ui/src/api/system/tckOrderDetailbak.js | 80 + zbf-ui/src/api/system/tckOrdersbak.js | 81 + zbf-ui/src/api/system/tckXnOrderDetailbak.js | 80 + zbf-ui/src/api/system/trkNotice.js | 138 + zbf-ui/src/api/system/trkWareNoticeTab.js | 72 + zbf-ui/src/api/system/user.js | 151 + zbf-ui/src/api/system/user_config.js | 72 + zbf-ui/src/api/tableMixin.js | 24 + zbf-ui/src/api/tool/gen.js | 109 + zbf-ui/src/assets/401_images/401.gif | Bin 0 -> 164227 bytes zbf-ui/src/assets/404_images/404.png | Bin 0 -> 98071 bytes zbf-ui/src/assets/404_images/404_cloud.png | Bin 0 -> 4766 bytes zbf-ui/src/assets/icons/index.js | 9 + zbf-ui/src/assets/icons/svg/404.svg | 1 + zbf-ui/src/assets/icons/svg/bug.svg | 1 + zbf-ui/src/assets/icons/svg/build.svg | 1 + zbf-ui/src/assets/icons/svg/button.svg | 1 + zbf-ui/src/assets/icons/svg/cascader.svg | 1 + zbf-ui/src/assets/icons/svg/chart.svg | 1 + zbf-ui/src/assets/icons/svg/checkbox.svg | 1 + zbf-ui/src/assets/icons/svg/clipboard.svg | 1 + zbf-ui/src/assets/icons/svg/code.svg | 1 + zbf-ui/src/assets/icons/svg/color.svg | 1 + zbf-ui/src/assets/icons/svg/component.svg | 1 + zbf-ui/src/assets/icons/svg/dashboard.svg | 1 + zbf-ui/src/assets/icons/svg/date-range.svg | 1 + zbf-ui/src/assets/icons/svg/date.svg | 1 + zbf-ui/src/assets/icons/svg/dict.svg | 1 + zbf-ui/src/assets/icons/svg/documentation.svg | 1 + zbf-ui/src/assets/icons/svg/download.svg | 1 + zbf-ui/src/assets/icons/svg/drag.svg | 1 + zbf-ui/src/assets/icons/svg/druid.svg | 1 + zbf-ui/src/assets/icons/svg/edit.svg | 1 + zbf-ui/src/assets/icons/svg/education.svg | 1 + zbf-ui/src/assets/icons/svg/email.svg | 1 + zbf-ui/src/assets/icons/svg/example.svg | 1 + zbf-ui/src/assets/icons/svg/excel.svg | 1 + .../src/assets/icons/svg/exit-fullscreen.svg | 1 + zbf-ui/src/assets/icons/svg/eye-open.svg | 1 + zbf-ui/src/assets/icons/svg/eye.svg | 1 + zbf-ui/src/assets/icons/svg/favicon.svg | 18 + zbf-ui/src/assets/icons/svg/form.svg | 1 + zbf-ui/src/assets/icons/svg/fullscreen.svg | 1 + zbf-ui/src/assets/icons/svg/github.svg | 1 + zbf-ui/src/assets/icons/svg/guide.svg | 1 + zbf-ui/src/assets/icons/svg/icon.svg | 1 + zbf-ui/src/assets/icons/svg/input.svg | 1 + zbf-ui/src/assets/icons/svg/international.svg | 1 + zbf-ui/src/assets/icons/svg/job.svg | 1 + zbf-ui/src/assets/icons/svg/language.svg | 1 + zbf-ui/src/assets/icons/svg/link.svg | 1 + zbf-ui/src/assets/icons/svg/list.svg | 1 + zbf-ui/src/assets/icons/svg/lock.svg | 1 + zbf-ui/src/assets/icons/svg/log.svg | 1 + zbf-ui/src/assets/icons/svg/logininfor.svg | 1 + zbf-ui/src/assets/icons/svg/message.svg | 1 + zbf-ui/src/assets/icons/svg/money.svg | 1 + zbf-ui/src/assets/icons/svg/monitor.svg | 2 + zbf-ui/src/assets/icons/svg/nested.svg | 1 + zbf-ui/src/assets/icons/svg/number.svg | 1 + zbf-ui/src/assets/icons/svg/online.svg | 1 + zbf-ui/src/assets/icons/svg/password.svg | 1 + zbf-ui/src/assets/icons/svg/pdf.svg | 1 + zbf-ui/src/assets/icons/svg/people.svg | 1 + zbf-ui/src/assets/icons/svg/peoples.svg | 1 + zbf-ui/src/assets/icons/svg/phone.svg | 1 + zbf-ui/src/assets/icons/svg/post.svg | 1 + zbf-ui/src/assets/icons/svg/qq.svg | 1 + zbf-ui/src/assets/icons/svg/question.svg | 1 + zbf-ui/src/assets/icons/svg/radio.svg | 1 + zbf-ui/src/assets/icons/svg/rate.svg | 1 + zbf-ui/src/assets/icons/svg/redis-list.svg | 2 + zbf-ui/src/assets/icons/svg/redis.svg | 1 + zbf-ui/src/assets/icons/svg/row.svg | 1 + zbf-ui/src/assets/icons/svg/search.svg | 1 + zbf-ui/src/assets/icons/svg/select.svg | 1 + zbf-ui/src/assets/icons/svg/server.svg | 1 + zbf-ui/src/assets/icons/svg/shopping.svg | 1 + zbf-ui/src/assets/icons/svg/size.svg | 1 + zbf-ui/src/assets/icons/svg/skill.svg | 1 + zbf-ui/src/assets/icons/svg/slider.svg | 1 + zbf-ui/src/assets/icons/svg/star.svg | 1 + zbf-ui/src/assets/icons/svg/swagger.svg | 1 + zbf-ui/src/assets/icons/svg/switch.svg | 1 + zbf-ui/src/assets/icons/svg/system.svg | 2 + zbf-ui/src/assets/icons/svg/tab.svg | 1 + zbf-ui/src/assets/icons/svg/table.svg | 1 + zbf-ui/src/assets/icons/svg/textarea.svg | 1 + zbf-ui/src/assets/icons/svg/theme.svg | 1 + zbf-ui/src/assets/icons/svg/time-range.svg | 1 + zbf-ui/src/assets/icons/svg/time.svg | 1 + zbf-ui/src/assets/icons/svg/tool.svg | 1 + zbf-ui/src/assets/icons/svg/tree-table.svg | 1 + zbf-ui/src/assets/icons/svg/tree.svg | 1 + zbf-ui/src/assets/icons/svg/upload.svg | 1 + zbf-ui/src/assets/icons/svg/user.svg | 1 + zbf-ui/src/assets/icons/svg/validCode.svg | 1 + zbf-ui/src/assets/icons/svg/wechat.svg | 1 + zbf-ui/src/assets/icons/svg/zip.svg | 1 + zbf-ui/src/assets/icons/svg/山东港口.svg | 6 + zbf-ui/src/assets/icons/svgo.yml | 22 + zbf-ui/src/assets/images/bg.jpg | Bin 0 -> 268679 bytes zbf-ui/src/assets/images/dark.svg | 39 + zbf-ui/src/assets/images/index_1.jpg | Bin 0 -> 2063 bytes zbf-ui/src/assets/images/index_2.jpg | Bin 0 -> 1605 bytes zbf-ui/src/assets/images/index_3.jpg | Bin 0 -> 1386 bytes zbf-ui/src/assets/images/index_logo_new.png | Bin 0 -> 11782 bytes zbf-ui/src/assets/images/index_logo_short.png | Bin 0 -> 2575 bytes zbf-ui/src/assets/images/index_logo_white.png | Bin 0 -> 10157 bytes zbf-ui/src/assets/images/light.svg | 39 + zbf-ui/src/assets/images/login-background.jpg | Bin 0 -> 521275 bytes zbf-ui/src/assets/images/pay.png | Bin 0 -> 140720 bytes zbf-ui/src/assets/images/profile.jpg | Bin 0 -> 81131 bytes zbf-ui/src/assets/logo/logo.png | Bin 0 -> 2575 bytes zbf-ui/src/assets/styles/btn.scss | 99 + zbf-ui/src/assets/styles/element-ui.scss | 92 + .../src/assets/styles/element-variables.scss | 31 + zbf-ui/src/assets/styles/index.scss | 321 + zbf-ui/src/assets/styles/mixin.scss | 66 + zbf-ui/src/assets/styles/ruoyi.scss | 291 + zbf-ui/src/assets/styles/sidebar.scss | 239 + zbf-ui/src/assets/styles/transition.scss | 49 + zbf-ui/src/assets/styles/variables.scss | 54 + zbf-ui/src/components/Breadcrumb/index.vue | 87 + zbf-ui/src/components/ChartPanel.vue | 67 + zbf-ui/src/components/Crontab/day.vue | 161 + zbf-ui/src/components/Crontab/hour.vue | 114 + zbf-ui/src/components/Crontab/index.vue | 430 + zbf-ui/src/components/Crontab/min.vue | 116 + zbf-ui/src/components/Crontab/month.vue | 114 + zbf-ui/src/components/Crontab/result.vue | 559 + zbf-ui/src/components/Crontab/second.vue | 117 + zbf-ui/src/components/Crontab/week.vue | 202 + zbf-ui/src/components/Crontab/year.vue | 131 + zbf-ui/src/components/DictData/index.js | 49 + zbf-ui/src/components/DictTag/index.vue | 89 + zbf-ui/src/components/Editor/index.vue | 274 + zbf-ui/src/components/FileUpload/index.vue | 216 + zbf-ui/src/components/Hamburger/index.vue | 44 + zbf-ui/src/components/HeaderSearch/index.vue | 198 + zbf-ui/src/components/IconSelect/index.vue | 104 + .../src/components/IconSelect/requireIcons.js | 11 + zbf-ui/src/components/ImagePreview/index.vue | 90 + zbf-ui/src/components/ImageUpload/index.vue | 226 + zbf-ui/src/components/Pagination/index.vue | 114 + zbf-ui/src/components/PanThumb/index.vue | 142 + zbf-ui/src/components/ParentView/index.vue | 3 + zbf-ui/src/components/Print/index.vue | 55 + zbf-ui/src/components/RightPanel/index.vue | 106 + zbf-ui/src/components/RightToolbar/index.vue | 284 + zbf-ui/src/components/RuoYi/Doc/index.vue | 21 + zbf-ui/src/components/RuoYi/Git/index.vue | 22 + zbf-ui/src/components/Screenfull/index.vue | 57 + zbf-ui/src/components/SizeSelect/index.vue | 56 + zbf-ui/src/components/StatCardContent.vue | 117 + zbf-ui/src/components/SvgIcon/index.vue | 61 + zbf-ui/src/components/TableTemplate/index.vue | 104 + zbf-ui/src/components/ThemePicker/index.vue | 173 + zbf-ui/src/components/TopNav/index.vue | 195 + zbf-ui/src/components/customBpmn/index.js | 12 + .../src/components/flow/Expression/index.vue | 139 + zbf-ui/src/components/flow/Listener/index.vue | 125 + zbf-ui/src/components/flow/Role/index.vue | 189 + zbf-ui/src/components/flow/User/index.vue | 266 + zbf-ui/src/components/iFrame/index.vue | 36 + zbf-ui/src/components/parser/Parser.vue | 257 + zbf-ui/src/components/parser/README.md | 17 + .../src/components/parser/example/Index.vue | 324 + zbf-ui/src/components/parser/index.js | 3 + zbf-ui/src/components/parser/package.json | 25 + zbf-ui/src/components/render/package.json | 19 + zbf-ui/src/components/render/render.js | 147 + .../src/components/render/slots/el-button.js | 5 + .../render/slots/el-checkbox-group.js | 13 + .../src/components/render/slots/el-input.js | 8 + .../components/render/slots/el-radio-group.js | 13 + .../src/components/render/slots/el-select.js | 9 + .../src/components/render/slots/el-upload.js | 17 + zbf-ui/src/components/tinymce/README.md | 3 + zbf-ui/src/components/tinymce/config.js | 8 + zbf-ui/src/components/tinymce/index.js | 3 + zbf-ui/src/components/tinymce/index.vue | 88 + zbf-ui/src/components/tinymce/package.json | 28 + zbf-ui/src/components/tinymce/zh_CN.js | 420 + zbf-ui/src/directive/dialog/drag.js | 64 + zbf-ui/src/directive/dialog/dragHeight.js | 34 + zbf-ui/src/directive/dialog/dragWidth.js | 30 + zbf-ui/src/directive/index.js | 23 + zbf-ui/src/directive/module/clipboard.js | 54 + zbf-ui/src/directive/permission/hasPermi.js | 28 + zbf-ui/src/directive/permission/hasRole.js | 28 + zbf-ui/src/icons/index.js | 9 + zbf-ui/src/icons/svg/button.svg | 1 + zbf-ui/src/icons/svg/cascader.svg | 1 + zbf-ui/src/icons/svg/checkbox.svg | 1 + zbf-ui/src/icons/svg/color.svg | 1 + zbf-ui/src/icons/svg/component.svg | 1 + zbf-ui/src/icons/svg/date-range.svg | 1 + zbf-ui/src/icons/svg/date.svg | 1 + zbf-ui/src/icons/svg/input.svg | 1 + zbf-ui/src/icons/svg/number.svg | 1 + zbf-ui/src/icons/svg/password.svg | 1 + zbf-ui/src/icons/svg/radio.svg | 1 + zbf-ui/src/icons/svg/rate.svg | 1 + zbf-ui/src/icons/svg/rich-text.svg | 1 + zbf-ui/src/icons/svg/row.svg | 1 + zbf-ui/src/icons/svg/select.svg | 1 + zbf-ui/src/icons/svg/slider.svg | 1 + zbf-ui/src/icons/svg/switch.svg | 1 + zbf-ui/src/icons/svg/table.svg | 1 + zbf-ui/src/icons/svg/textarea.svg | 1 + zbf-ui/src/icons/svg/time-range.svg | 1 + zbf-ui/src/icons/svg/time.svg | 1 + zbf-ui/src/icons/svg/upload.svg | 1 + zbf-ui/src/layout/components/AppMain.vue | 75 + .../layout/components/IframeToggle/index.vue | 33 + .../src/layout/components/InnerLink/index.vue | 47 + zbf-ui/src/layout/components/Navbar.vue | 266 + .../src/layout/components/Settings/index.vue | 260 + .../layout/components/Sidebar/FixiOSBug.js | 25 + zbf-ui/src/layout/components/Sidebar/Item.vue | 33 + zbf-ui/src/layout/components/Sidebar/Link.vue | 43 + zbf-ui/src/layout/components/Sidebar/Logo.vue | 93 + .../layout/components/Sidebar/SidebarItem.vue | 100 + .../src/layout/components/Sidebar/index.vue | 62 + .../layout/components/TagsView/ScrollPane.vue | 95 + .../src/layout/components/TagsView/index.vue | 426 + zbf-ui/src/layout/components/index.js | 5 + zbf-ui/src/layout/index.vue | 115 + zbf-ui/src/layout/mixin/ResizeHandler.js | 45 + zbf-ui/src/main.js | 120 + zbf-ui/src/permission.js | 77 + zbf-ui/src/plugins/auth.js | 60 + zbf-ui/src/plugins/cache.js | 77 + zbf-ui/src/plugins/download.js | 79 + zbf-ui/src/plugins/index.js | 20 + zbf-ui/src/plugins/modal.js | 83 + zbf-ui/src/plugins/tab.js | 71 + zbf-ui/src/router/index.js | 223 + zbf-ui/src/router/updateIndex.js | 37 + zbf-ui/src/settings.js | 44 + zbf-ui/src/store/getters.js | 21 + zbf-ui/src/store/index.js | 25 + zbf-ui/src/store/modules/app.js | 66 + zbf-ui/src/store/modules/dict.js | 50 + zbf-ui/src/store/modules/permission.js | 141 + zbf-ui/src/store/modules/settings.js | 44 + zbf-ui/src/store/modules/tagsView.js | 228 + zbf-ui/src/store/modules/user.js | 175 + zbf-ui/src/styles/home.scss | 271 + zbf-ui/src/styles/index.scss | 141 + zbf-ui/src/styles/mixin.scss | 33 + zbf-ui/src/utils/StrUtil.js | 553 + zbf-ui/src/utils/auth.js | 15 + zbf-ui/src/utils/common.js | 88 + zbf-ui/src/utils/db.js | 58 + zbf-ui/src/utils/dict/Dict.js | 82 + zbf-ui/src/utils/dict/DictConverter.js | 17 + zbf-ui/src/utils/dict/DictData.js | 13 + zbf-ui/src/utils/dict/DictMeta.js | 38 + zbf-ui/src/utils/dict/DictOptions.js | 51 + zbf-ui/src/utils/dict/index.js | 33 + zbf-ui/src/utils/errorCode.js | 6 + zbf-ui/src/utils/generator/config.js | 629 + zbf-ui/src/utils/generator/css.js | 18 + zbf-ui/src/utils/generator/drawingDefalut.js | 37 + zbf-ui/src/utils/generator/html.js | 399 + zbf-ui/src/utils/generator/icon.json | 1 + zbf-ui/src/utils/generator/js.js | 271 + zbf-ui/src/utils/generator/render.js | 126 + zbf-ui/src/utils/generator/ruleTrigger.js | 16 + zbf-ui/src/utils/index.js | 435 + zbf-ui/src/utils/jsencrypt.js | 30 + zbf-ui/src/utils/loadBeautifier.js | 28 + zbf-ui/src/utils/loadMonaco.js | 40 + zbf-ui/src/utils/loadScript.js | 60 + zbf-ui/src/utils/loadTinymce.js | 29 + zbf-ui/src/utils/permission.js | 47 + zbf-ui/src/utils/pluginsConfig.js | 13 + zbf-ui/src/utils/request.js | 152 + zbf-ui/src/utils/ruoyi.js | 233 + zbf-ui/src/utils/scroll-to.js | 58 + zbf-ui/src/utils/validate.js | 80 + zbf-ui/src/views/bl.vue | 887 + zbf-ui/src/views/dashboard/BarChart.vue | 102 + zbf-ui/src/views/dashboard/LineChart.vue | 135 + zbf-ui/src/views/dashboard/PanelGroup.vue | 181 + zbf-ui/src/views/dashboard/PieChart.vue | 79 + zbf-ui/src/views/dashboard/RaddarChart.vue | 116 + zbf-ui/src/views/dashboard/mixins/resize.js | 56 + zbf-ui/src/views/error/401.vue | 88 + zbf-ui/src/views/error/404.vue | 233 + zbf-ui/src/views/function/api/leaveApply.js | 50 + zbf-ui/src/views/function/api/meeting.js | 53 + zbf-ui/src/views/function/api/outbound.js | 83 + zbf-ui/src/views/function/api/purchase.js | 50 + zbf-ui/src/views/function/lauchMeeting.vue | 263 + zbf-ui/src/views/function/leaveApply.vue | 282 + zbf-ui/src/views/function/outbound.vue | 307 + zbf-ui/src/views/function/purchaseApply.vue | 289 + zbf-ui/src/views/index.vue | 1339 + zbf-ui/src/views/index1.vue | 17 + zbf-ui/src/views/index2.vue | 98 + zbf-ui/src/views/indexbak1.vue | 819 + zbf-ui/src/views/inspection/api.js | 93 + .../views/inspection/components/workTable.vue | 0 .../src/views/inspection/processInstance.vue | 181 + zbf-ui/src/views/inspection/runHistory.vue | 249 + zbf-ui/src/views/inspection/runInstance.vue | 122 + .../src/views/inspection/workManagement.vue | 271 + zbf-ui/src/views/leader.vue | 1046 + .../batchAdjustment/index.vue | 515 + .../views/libraryManagement/freeze/index.vue | 607 + .../views/libraryManagement/posMove/index.vue | 662 + zbf-ui/src/views/login.vue | 293 + zbf-ui/src/views/monitor/cache/index.vue | 148 + zbf-ui/src/views/monitor/cache/list.vue | 241 + zbf-ui/src/views/monitor/druid/index.vue | 15 + zbf-ui/src/views/monitor/job/index.vue | 513 + zbf-ui/src/views/monitor/job/log.vue | 295 + zbf-ui/src/views/monitor/logininfor/index.vue | 246 + zbf-ui/src/views/monitor/online/index.vue | 122 + zbf-ui/src/views/monitor/operlog/index.vue | 323 + zbf-ui/src/views/monitor/server/index.vue | 207 + zbf-ui/src/views/process/api/deployService.js | 63 + zbf-ui/src/views/process/api/model.js | 41 + zbf-ui/src/views/process/deployManagement.vue | 300 + zbf-ui/src/views/process/modelManagement.vue | 237 + zbf-ui/src/views/redirect.vue | 12 + zbf-ui/src/views/register.vue | 268 + zbf-ui/src/views/system/bom/index.vue | 418 + zbf-ui/src/views/system/bound/index.vue | 478 + zbf-ui/src/views/system/check/index.vue | 524 + zbf-ui/src/views/system/ckOrders/ct.vue | 502 + zbf-ui/src/views/system/ckOrders/index.vue | 2512 ++ .../system/ckPickingWavegoodsbak/index.vue | 1099 + zbf-ui/src/views/system/column/index.vue | 534 + zbf-ui/src/views/system/config/index.vue | 343 + zbf-ui/src/views/system/dept/index.vue | 472 + .../views/system/dialog/ExistOrdersSelect.vue | 341 + .../src/views/system/dialog/GoodsSelect.vue | 403 + .../views/system/dialog/ProviderSelect.vue | 303 + .../src/views/system/dialog/StockSelect.vue | 491 + zbf-ui/src/views/system/dict/data.vue | 402 + zbf-ui/src/views/system/dict/index.vue | 347 + zbf-ui/src/views/system/expression/index.vue | 282 + .../src/views/system/financialClass/index.vue | 438 + zbf-ui/src/views/system/goods/index.vue | 784 + zbf-ui/src/views/system/listener/index.vue | 335 + zbf-ui/src/views/system/location/index.vue | 920 + zbf-ui/src/views/system/log/index.vue | 306 + zbf-ui/src/views/system/menu/index.vue | 452 + zbf-ui/src/views/system/notice/index.vue | 312 + .../views/system/ongoodsShelfBak/index.vue | 1108 + .../src/views/system/ongoodsshelf/index.vue | 1112 + zbf-ui/src/views/system/orderdetail/index.vue | 842 + .../src/views/system/orderdetailBak/index.vue | 862 + zbf-ui/src/views/system/overInsured/index.vue | 353 + zbf-ui/src/views/system/overdue/index.vue | 582 + zbf-ui/src/views/system/pallet/index.vue | 712 + zbf-ui/src/views/system/panDetail/index.vue | 671 + zbf-ui/src/views/system/panOrder/detail.vue | 468 + zbf-ui/src/views/system/panOrder/index.vue | 449 + .../views/system/pickingwavegoods/index.vue | 533 + zbf-ui/src/views/system/post/index.vue | 309 + zbf-ui/src/views/system/print/PrintPage.vue | 290 + zbf-ui/src/views/system/provider/index.vue | 530 + zbf-ui/src/views/system/requisition/index.vue | 648 + .../views/system/rkRecevinggoods/index.vue | 1049 + .../views/system/rkWareNoticeBak/index.vue | 856 + .../views/system/rkXnWareNoticeBak/index.vue | 942 + zbf-ui/src/views/system/role/authUser.vue | 199 + zbf-ui/src/views/system/role/index.vue | 721 + zbf-ui/src/views/system/role/selectUser.vue | 138 + zbf-ui/src/views/system/safetyStock/index.vue | 246 + zbf-ui/src/views/system/storage/index.vue | 639 + zbf-ui/src/views/system/storageArea/index.vue | 546 + zbf-ui/src/views/system/tMiStock/index.vue | 784 + zbf-ui/src/views/system/tMiStockbak/index.vue | 877 + zbf-ui/src/views/system/tMiXnStock/index.vue | 879 + .../src/views/system/tckOrdersbak/index.vue | 789 + .../src/views/system/tckXnOrdersbak/index.vue | 880 + zbf-ui/src/views/system/trkNotice/index.vue | 2413 ++ zbf-ui/src/views/system/user/authRole.vue | 117 + zbf-ui/src/views/system/user/index.vue | 885 + .../src/views/system/user/profile/index.vue | 91 + .../views/system/user/profile/resetPwd.vue | 134 + .../views/system/user/profile/userAvatar.vue | 184 + .../views/system/user/profile/userInfo.vue | 88 + zbf-ui/src/views/todo/allTodoList.vue | 168 + zbf-ui/src/views/todo/api/allTodoList.js | 17 + zbf-ui/src/views/todo/api/myTodoList.js | 112 + zbf-ui/src/views/todo/api/processTaks.js | 10 + zbf-ui/src/views/todo/components/TimeLine.vue | 75 + .../views/todo/components/leaveApplyForm.vue | 180 + .../src/views/todo/components/meetingForm.vue | 75 + .../views/todo/components/outboundForm.vue | 386 + .../src/views/todo/components/processForm.vue | 0 .../views/todo/components/purchaseForm.vue | 103 + zbf-ui/src/views/todo/myTodoList.vue | 162 + zbf-ui/src/views/todo/processTask.vue | 250 + zbf-ui/src/views/tool/build/App.vue | 22 + .../src/views/tool/build/CodeTypeDialog.vue | 110 + zbf-ui/src/views/tool/build/DraggableItem.vue | 120 + zbf-ui/src/views/tool/build/FormDrawer.vue | 335 + zbf-ui/src/views/tool/build/IconsDialog.vue | 123 + zbf-ui/src/views/tool/build/JsonDrawer.vue | 144 + .../src/views/tool/build/ResourceDialog.vue | 116 + zbf-ui/src/views/tool/build/RightPanel.vue | 1052 + .../src/views/tool/build/TreeNodeDialog.vue | 158 + zbf-ui/src/views/tool/build/index.vue | 558 + zbf-ui/src/views/tool/build/main.js | 17 + zbf-ui/src/views/tool/gen/basicInfoForm.vue | 60 + zbf-ui/src/views/tool/gen/createTable.vue | 45 + zbf-ui/src/views/tool/gen/editTable.vue | 234 + zbf-ui/src/views/tool/gen/genInfoForm.vue | 312 + zbf-ui/src/views/tool/gen/importTable.vue | 120 + zbf-ui/src/views/tool/gen/index.vue | 354 + zbf-ui/src/views/tool/preview/main.js | 61 + zbf-ui/src/views/tool/swagger/index.vue | 15 + zbf-ui/src/views/tool/test.vue | 784 + zbf-ui/src/views/wx.vue | 978 + zbf-ui/vue.config.js | 144 + 1857 files changed, 439993 insertions(+) create mode 100644 .DS_Store create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.en.md create mode 100644 README.md create mode 100644 bin/clean.bat create mode 100644 bin/package.bat create mode 100644 bin/run.bat create mode 100644 doc/若依环境使用手册.docx create mode 100644 package-lock.json create mode 100644 pom.xml create mode 100644 ry.bat create mode 100644 ry.sh create mode 100644 sql/Menu.sql create mode 100644 sql/README.md create mode 100644 sql/quartz.sql create mode 100644 sql/ry_20231130.sql create mode 100644 sql/tony-flowable.sql create mode 100644 zbf-admin/pom.xml create mode 100644 zbf-admin/src/main/java/com/zbf/ZbfApplication.java create mode 100644 zbf-admin/src/main/java/com/zbf/ZbfServletInitializer.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/common/CaptchaController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/common/CommonController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/common/FileUploadController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/DynamicFlowController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowDesignerController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowMonitorController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/LeaveapplyController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/MeetingController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/ModelManageController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/OutBoundController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/PurchaseController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/flowable/TaskController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/monitor/CacheController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/monitor/ServerController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysLogininforController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysOperlogController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysUserOnlineController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/section/DataListAspect.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/section/EnhanceDataList.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/section/ListColumns.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/AppVerController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/DeviceLogController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/InventoryCheckController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/LargeScreenController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/RestClientConfig.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysConfigController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysDeptController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictDataController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictTypeController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysExpressionController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysIndexController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysListenerController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysLoginController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysMenuController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysNoticeController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysPostController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysProfileController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysRegisterController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysRoleController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserBusinessColumnController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TAgvController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseFinancialClassController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsBomController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBasePalletController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseProviderController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaLocationController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeOrderController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrderdetailController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrdersController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TErrorLogController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TMiBatchAdjustmentController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockFController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TMiXnStockController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TPanDetailController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TPanOrderController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TRkReceivingGoodsController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TRkXnWareNoticeTabBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TSafetyStockController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TStockCheckController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TUserConfigController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TUserFavoritesController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrderdetailBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrdersBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TckXnOrderdetailBakController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/system/TransferOrderController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/controller/tool/TestController.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/core/config/SwaggerConfig.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/mqtt/MqttConfig.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageHandler.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageSender.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/mqtt/MqttProperties.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/util/ActivitiTracingChart.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/util/Check.java create mode 100644 zbf-admin/src/main/java/com/zbf/web/util/RID.java create mode 100644 zbf-admin/src/main/resources/META-INF/spring-devtools.properties create mode 100644 zbf-admin/src/main/resources/application-druid.yml create mode 100644 zbf-admin/src/main/resources/application.yml create mode 100644 zbf-admin/src/main/resources/banner.txt create mode 100644 zbf-admin/src/main/resources/i18n/messages.properties create mode 100644 zbf-admin/src/main/resources/logback.xml create mode 100644 zbf-admin/src/main/resources/mybatis/mybatis-config.xml create mode 100644 zbf-admin/src/main/resources/processes/Flowable_Pickingout.bpmn20.xml create mode 100644 zbf-admin/src/main/resources/processes/Pickingout_Audit.bpmn20.xml create mode 100644 zbf-admin/src/main/resources/processes/leave.bpmn create mode 100644 zbf-admin/src/main/resources/processes/meeting.bpmn create mode 100644 zbf-admin/src/main/resources/processes/purchase.bpmn20.xml create mode 100644 zbf-admin/src/main/resources/static/designer/404.html create mode 100644 zbf-admin/src/main/resources/static/designer/browserconfig.xml create mode 100644 zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-draw.js create mode 100644 zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-icons.js create mode 100644 zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.css create mode 100644 zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.html create mode 100644 zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/.gitignore create mode 100644 zbf-admin/src/main/resources/static/designer/display/Gruntfile.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/Polyline.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/bpmn-draw.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/bpmn-icons.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/displaymodel.css create mode 100644 zbf-admin/src/main/resources/static/designer/display/displaymodel.html create mode 100644 zbf-admin/src/main/resources/static/designer/display/displaymodel.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/display/package.json create mode 100644 zbf-admin/src/main/resources/static/designer/display/raphael.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/flowable-header-custom.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/flowable-toolbar-custom-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-assignment-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-calledelementtype-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-case-reference-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-condition-expression-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-custom-controllers.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-data-properties-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-decisiontable-reference-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-default-controllers.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-duedate-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-event-listeners-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-execution-listeners-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-fields-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-properties-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-reference-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-httprequest-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-in-parameters-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-definitions-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-scope-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-multiinstance-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-ordering-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-out-parameters-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-planitem-dropdown-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-historylevel-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-reference-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-sequenceflow-order-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-definitions-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-scope-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-task-listeners-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-transition-event-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-trigger-mode-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/boolean-property-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/calledelementtype-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/case-reference-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/case-reference-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/case-reference-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/condition-expression-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/condition-expression-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/condition-expression-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/data-properties-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/data-properties-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/data-properties-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/decisiontable-reference-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/decisiontable-reference-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/decisiontable-reference-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/default-value-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/duedate-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/duedate-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/duedate-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/errorgrid-critical.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/event-listeners-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/event-listeners-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/event-listeners-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/execution-listeners-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/execution-listeners-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/execution-listeners-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/feedback-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/fields-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/fields-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/fields-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/multiinstance-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/ordering-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-read-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-historylevel-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/string-property-write-mode-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-display-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/text-popup.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/text-property-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/transition-event-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/trigger-mode-read-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/trigger-mode-write-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/toolbar-custom-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/toolbar-default-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/toolbar.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/configuration/url-config.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/css/style.css create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/define-data-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor-config.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor-utils.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/css/editor.css create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/i18n/translation_de.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/i18n/translation_en_us.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/i18n/translation_signavio_de.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/i18n/translation_signavio_en_us.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/oryx.debug.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editor/oryx.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/editormanager.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/eventbus.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/FontAwesome.otf create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/activiti-admin-webfont.eot create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/activiti-admin-webfont.svg create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/activiti-admin-webfont.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/activiti-admin-webfont.woff create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/fontawesome-webfont.eot create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/fontawesome-webfont.svg create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/fontawesome-webfont.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/fontawesome-webfont.woff create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/fontawesome-webfont.woff2 create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/glyphicons-halflings-regular.eot create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/glyphicons-halflings-regular.svg create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/glyphicons-halflings-regular.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/fonts/glyphicons-halflings-regular.woff create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/header-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/bpmn-error.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/bpmn-warning.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/datadefinition.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/delete.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/loading.gif create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/nw-handle-dark.gif create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/pencil.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/report_edit.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/se-handle-dark.gif create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/shapemenu_highlight.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/images/wrench.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/add-bendpoint-hover.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/add-bendpoint.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/grid.gif create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-add-bendpoint-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-add-bendpoint.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-align-horizontal-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-align-horizontal.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-align-vertical-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-align-vertical.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-remove-bendpoint-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-remove-bendpoint.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-same-size-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-same-size.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-zoom-actual-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-zoom-actual.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-zoom-fit-selected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/icon-zoom-fit.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/kis_logo.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/remove-bendpoint-hover.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/img-kis/remove-bendpoint.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/jquery.autogrow-textarea.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/mousetrap/1.6.0/mousetrap-record.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/mousetrap/1.6.0/mousetrap.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/mousetrap/1.6.0/mousetrap.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/path_parser.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/prototype-1.6.1.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/prototype-1.7.3.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/ui-utils.min-0.2.1.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/libs/update-helper.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/partials/process-tree-list.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/partials/root-stencil-item-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/partials/stencil-item-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/plugins.xml create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/popups/define-data.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/popups/icon-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/popups/save-model.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/popups/select-shape.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/popups/unsaved-changes.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/popups/validate-model.html create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/process-navigator-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/select-shape-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencil-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilset.json create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/adhoc.subprocess.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/event.subprocess.collapsed.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/event.subprocess.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/expanded.subprocess.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.business.rule.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.camel.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.http.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.manual.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.mule.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.receive.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.script.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.send.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.service.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.shell.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.user.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/subprocess.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/task.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/artifact/text.annotation.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/cancel.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/compensation.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/conditional.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/error.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/escalation.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/message.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/signal.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/timer.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/association.undirected.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/association.unidirectional.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/messageflow.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/sequenceflow.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/dataobject/data.store.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/diagram.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/error.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/escalation.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/none.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/terminate.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/eventbased.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/exclusive.databased.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/inclusive.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/parallel.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/conditional.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/error.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/escalation.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/message.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/none.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/signal.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/timer.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/swimlane/lane.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/swimlane/pool.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/escalation.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/none.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/signal.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/casefileitem.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/casetask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/collapsed.planfragment.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/decisiontask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/expanded.planfragment.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/httptask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/humantask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/milestone.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/processtask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/scripttask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/servicetask.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/task.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/timereventlistener.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/connection/connector.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/caseplanmodel.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/collapsed.stage.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/expanded.stage.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/event/eventlistener.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/event/timerlistener.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/event/userlistener.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/sentry/entry.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/sentry/exit.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/tables/planningtable.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_action.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_action_container.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_alert.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_case.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_checkbox.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_choices.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_combo.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_date.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_form.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_group.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_header.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_help.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_hint.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_input.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_item.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_itemset.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_label.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_number.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_output.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_paragraph.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_radiobutton.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_range.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_repeat.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_repeating_group.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_secret.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_select.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_select1.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_separator.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_submit.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_switch.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_textarea.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_trigger.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_upload.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/xforms.png create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/toolbar-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/editor-app/tour.js create mode 100644 zbf-admin/src/main/resources/static/designer/favicon.ico create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/TitilliumWeb-Bold.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/TitilliumWeb-Regular.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.eot create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.svg create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.woff create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/glyphicons-halflings-regular.eot create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/glyphicons-halflings-regular.svg create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/glyphicons-halflings-regular.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/glyphicons-halflings-regular.woff create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-bold-webfont.eot create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-bold-webfont.svg create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-bold-webfont.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-bold-webfont.woff create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.eot create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.svg create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.woff create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/en-US.json create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/en.json create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/es.json create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/fr.json create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/pt-BR.json create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/zh-CN.json create mode 100644 zbf-admin/src/main/resources/static/designer/i18n/zh-TW.json create mode 100644 zbf-admin/src/main/resources/static/designer/images/android-chrome-192x192.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/android-chrome-384x384.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/apple-touch-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/favicon-16x16.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/favicon-32x32.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/flowable-logo.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/flowable-logo@2x.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/amountfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/booleanfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/choicefield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/datefield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/decimalfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/dropdownfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/dynamic-table-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/group-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/headline-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/headline-with-line-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/horizontal-line-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/hyperlink-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/multi-line-textfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/numberfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/password-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/peoplefield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/readonly-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/readonly-text-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/spacer-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/textfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/form-builder/uploadfield-icon.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/glasspane.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/line-1px.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/line.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/mstile-150x150.png create mode 100644 zbf-admin/src/main/resources/static/designer/images/safari-pinned-tab.svg create mode 100644 zbf-admin/src/main/resources/static/designer/images/tour/open-group.gif create mode 100644 zbf-admin/src/main/resources/static/designer/images/tour/sequenceflow-bendpoint.gif create mode 100644 zbf-admin/src/main/resources/static/designer/images/tour/tour-dnd.gif create mode 100644 zbf-admin/src/main/resources/static/designer/index.html create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-loading-bar-0.7.0/loading-bar.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-loading-bar-0.7.0/loading-bar.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-mocks_1.2.13/angular-mocks.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-resource_1.3.13/angular-resource.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-resource_1.3.13/angular-resource.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-resource_1.3.13/angular-resource.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-route_1.3.13/angular-route.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-route_1.3.13/angular-route.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-route_1.3.13/angular-route.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-scroll_0.5.7/angular-scroll.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/angular-spectrum-colorpicker.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/.bower.json create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate-storage-cookie/.bower.json create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular_1.3.13/angular.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular_1.3.13/angular.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angular_1.3.13/angular.min.js.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/angularjs-nvd3-directives_0.0.7/angular-nvd3-directives.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/autofill-events_1.0.0/autofill-event.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap-daterangepicker_1.3.7/daterangepicker-bs3.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap-daterangepicker_1.3.7/daterangepicker.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap-tour_0.9.1/bootstrap-tour.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap-tour_0.9.1/bootstrap-tour.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap-tour_0.9.1/bootstrap-tour.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/css/bootstrap-theme.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/css/bootstrap-theme.css.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/css/bootstrap-theme.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/css/bootstrap.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/css/bootstrap.css.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/css/bootstrap.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/fonts/glyphicons-halflings-regular.eot create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/fonts/glyphicons-halflings-regular.svg create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/fonts/glyphicons-halflings-regular.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/fonts/glyphicons-halflings-regular.woff create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/js/bootstrap.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/bootstrap_3.1.1/js/bootstrap.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/.bower.json create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/.gitignore create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/CHANGES create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/CONTRIBUTORS.md create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/LICENSE create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/README.md create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/es5-sham.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/es5-sham.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/es5-sham.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/es5-shim.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/es5-shim.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/es5-shim.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/package.json create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/helpers/h-kill.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/helpers/h-matchers.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/helpers/h.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/index.html create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/index.min.html create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/lib/jasmine-html.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/lib/jasmine.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/lib/jasmine.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/lib/jasmine_favicon.png create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/lib/json2.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/spec/s-array.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/spec/s-date.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/spec/s-function.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/spec/s-number.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/spec/s-object.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/es5-shim-15.3.4.5/tests/spec/s-string.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/handsontable_0.31.2/handsontable.full.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/handsontable_0.31.2/handsontable.full.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/html2canvas_0.4.1/html2canvas.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/jquery-ui-1.10.3.custom.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/jquery_1.11.0/jquery.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/jquery_1.11.0/jquery.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/jquery_1.11.0/jquery.min.map create mode 100644 zbf-admin/src/main/resources/static/designer/libs/json3_3.2.6/LICENSE create mode 100644 zbf-admin/src/main/resources/static/designer/libs/json3_3.2.6/lib/json3.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/json3_3.2.6/lib/json3.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/momentjs_2.18.1/momentjs.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/FileAPI.flash.swf create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/FileAPI.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/FileAPI.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/ng-file-upload-all.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/ng-file-upload-all.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/ng-file-upload-shim.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/ng-file-upload-shim.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/ng-file-upload.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-file-upload/ng-file-upload.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-handsontable_0.13/ngHandsontable.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ng-handsontable_0.13/ngHandsontable.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/nvd3_1.1.15-beta/nvd3.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/nvd3_1.1.15-beta/nvd3.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/.bower.json create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/tasks/commit.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/tasks/compile.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/tasks/dist.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/tasks/release.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/tasks/tag.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/tasks/version.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/data/empty.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/data/mixed_sort.html create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/data/testinit.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/index.html create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/jquery.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/libs/qunit/qunit.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/libs/qunit/qunit.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/unit/extending.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/unit/selector.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/sizzle_1.10.16/test/unit/utilities.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.eot create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.min.js create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.svg create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.ttf create mode 100644 zbf-admin/src/main/resources/static/designer/libs/ui-grid_3.0.0/ui-grid.woff create mode 100644 zbf-admin/src/main/resources/static/designer/manifest.json create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/app-cfg.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/app.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/common/controllers/about.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/common/directives.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/common/providers-config.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/common/services/recursion-helper.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/common/services/resource-service.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/app-definition-toolbar-default-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/app-definition-toolbar.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/decision-table-toolbar-default-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/decision-table-toolbar.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/form-builder-toolbar-default-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/form-builder-toolbar.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/configuration/url-config.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/app-definition-builder.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/app-definition-toolbar-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/app-definition.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/app-definitions.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/casemodel.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/casemodels.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/decision-table-editor.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/decision-table-toolbar-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/decision-table.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/decision-tables.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/form-builder.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/form-readonly-view.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/form-toolbar-controller.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/form.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/forms.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/model-common-actions.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/process.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/controllers/processes.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/editor-directives.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/resource-loader.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/services/decision-table-service.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/services/form-services.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/services/identity-services.js create mode 100644 zbf-admin/src/main/resources/static/designer/scripts/services/util-services.js create mode 100644 zbf-admin/src/main/resources/static/designer/styles/common/bootstrap.min.css create mode 100644 zbf-admin/src/main/resources/static/designer/styles/common/style-retina.css create mode 100644 zbf-admin/src/main/resources/static/designer/styles/common/style.css create mode 100644 zbf-admin/src/main/resources/static/designer/styles/style-editor.css create mode 100644 zbf-admin/src/main/resources/static/designer/views/app-definition-builder.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/app-definition.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/app-definitions.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/casemodel.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/casemodels.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/decision-table-editor.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/decision-table.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/decision-tables.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/form-builder.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/form.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/forms.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popover/formfield-edit-popover.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popover/history.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popover/select-app-icon.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popover/select-app-theme.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popover/select-group-popover.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-create.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-delete.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-duplicate.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-import.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-models-included.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-publish.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definition-save-model.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/app-definitions-import.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/casemodel-create.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/casemodel-duplicate.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/casemodel-import.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-create.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-duplicate.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-edit-hit-policy.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-edit-input-expression.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-edit-output-expression.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-import.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/decision-table-save-model.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/form-create.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/form-duplicate.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/form-save-model.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/model-delete.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/model-edit.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/model-use-as-new-version.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/process-create.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/process-duplicate.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/process-import.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/popup/subprocess-create.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/process.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/processes.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/templates/decision-table-header-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/templates/decision-table-headercell-template.html create mode 100644 zbf-admin/src/main/resources/static/designer/views/templates/form-builder-element-template.html create mode 100644 zbf-common/pom.xml create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/Anonymous.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/DataScope.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/DataSource.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/Excel.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/Excels.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/Log.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/NoAutoFill.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/RateLimiter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/annotation/RepeatSubmit.java create mode 100644 zbf-common/src/main/java/com/zbf/common/config/RuoYiConfig.java create mode 100644 zbf-common/src/main/java/com/zbf/common/config/TaskExecutorConfig.java create mode 100644 zbf-common/src/main/java/com/zbf/common/constant/CacheConstants.java create mode 100644 zbf-common/src/main/java/com/zbf/common/constant/Constants.java create mode 100644 zbf-common/src/main/java/com/zbf/common/constant/GenConstants.java create mode 100644 zbf-common/src/main/java/com/zbf/common/constant/HttpStatus.java create mode 100644 zbf-common/src/main/java/com/zbf/common/constant/ScheduleConstants.java create mode 100644 zbf-common/src/main/java/com/zbf/common/constant/UserConstants.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/controller/BaseController.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/controller/ManualPagination.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/AjaxResult.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/BaseEntity.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/R.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/TreeEntity.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/TreeSelect.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/entity/SysDept.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/entity/SysDictData.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/entity/SysDictType.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/entity/SysMenu.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/entity/SysRole.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/entity/SysUser.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/model/LoginBody.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/model/LoginUser.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/domain/model/RegisterBody.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/page/PageDomain.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/page/TableDataInfo.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/page/TableSupport.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/redis/RedisCache.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/text/CharsetKit.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/text/Convert.java create mode 100644 zbf-common/src/main/java/com/zbf/common/core/text/StrFormatter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/BusinessStatus.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/BusinessType.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/DataSourceType.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/HttpMethod.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/LimitType.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/OperatorType.java create mode 100644 zbf-common/src/main/java/com/zbf/common/enums/UserStatus.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/CustomException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/DemoModeException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/GlobalException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/NonCaptureException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/ServiceException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/UtilException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/base/BaseException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/file/FileException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/file/FileNameLengthLimitExceededException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/file/FileSizeLimitExceededException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/file/FileUploadException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/file/InvalidExtensionException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/job/TaskException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/BlackListException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/CaptchaException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/CaptchaExpireException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/UserException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/UserNotExistsException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/UserPasswordNotMatchException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/exception/user/UserPasswordRetryLimitExceedException.java create mode 100644 zbf-common/src/main/java/com/zbf/common/filter/PropertyPreExcludeFilter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/filter/RepeatableFilter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/filter/RepeatedlyRequestWrapper.java create mode 100644 zbf-common/src/main/java/com/zbf/common/filter/XssFilter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/filter/XssHttpServletRequestWrapper.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/Arith.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/CommonUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/DateUtil.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/DateUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/DictUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/ExceptionUtil.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/LogUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/MessageUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/OrderCodeFactory.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/PageUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/RsaUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/SecurityUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/ServletUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/StringUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/Threads.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/bean/BeanUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/bean/BeanValidators.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/file/FileTypeUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/file/FileUploadUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/file/FileUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/file/ImageUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/file/MimeTypeUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/html/EscapeUtil.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/html/HTMLFilter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/http/HttpHelper.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/http/HttpUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/ip/AddressUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/ip/IpUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/oConvertUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/poi/ExcelHandlerAdapter.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/poi/ExcelUtil.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/reflect/ReflectUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/sign/Base64.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/sign/Md5Utils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/spring/SpringUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/sql/SqlUtil.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/uuid/IdUtils.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/uuid/Seq.java create mode 100644 zbf-common/src/main/java/com/zbf/common/utils/uuid/UUID.java create mode 100644 zbf-common/src/main/java/com/zbf/common/xss/Xss.java create mode 100644 zbf-common/src/main/java/com/zbf/common/xss/XssValidator.java create mode 100644 zbf-framework/pom.xml create mode 100644 zbf-framework/src/main/java/com/zbf/framework/aspectj/DataScopeAspect.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/aspectj/DataSourceAspect.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/aspectj/LogAspect.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/aspectj/RateLimiterAspect.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/ApplicationConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/CaptchaConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/DruidConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/FastJson2JsonRedisSerializer.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/FilterConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/KaptchaTextCreator.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/MyBatisConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/MyMetaObjectHandler.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/MybatisPlusConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/P6spySqlFormatConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/RedisConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/ResourcesConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/SecurityConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/ServerConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/ThreadPoolConfig.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/properties/DruidProperties.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/config/properties/PermitAllUrlProperties.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/datasource/DynamicDataSource.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/datasource/DynamicDataSourceContextHolder.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/interceptor/RepeatSubmitInterceptor.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/interceptor/impl/SameUrlDataInterceptor.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/manager/AsyncManager.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/manager/ShutdownManager.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/manager/factory/AsyncFactory.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/security/context/AuthenticationContextHolder.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/security/context/PermissionContextHolder.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/security/filter/JwtAuthenticationTokenFilter.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/security/handle/AuthenticationEntryPointImpl.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/security/handle/LogoutSuccessHandlerImpl.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/domain/Server.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/domain/server/Cpu.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/domain/server/Jvm.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/domain/server/Mem.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/domain/server/Sys.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/domain/server/SysFile.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/exception/GlobalExceptionHandler.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/PermissionService.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/SysLoginService.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/SysPasswordService.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/SysPermissionService.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/SysRegisterService.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/TokenService.java create mode 100644 zbf-framework/src/main/java/com/zbf/framework/web/service/UserDetailsServiceImpl.java create mode 100644 zbf-generator/pom.xml create mode 100644 zbf-generator/src/main/java/com/zbf/generator/config/GenConfig.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/controller/GenController.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/domain/GenTable.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/domain/GenTableColumn.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/mapper/GenTableColumnMapper.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/mapper/GenTableMapper.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/service/GenTableColumnServiceImpl.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/service/GenTableServiceImpl.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/service/IGenTableColumnService.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/service/IGenTableService.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/util/ColumnUtils.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/util/GenUtils.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/util/VelocityInitializer.java create mode 100644 zbf-generator/src/main/java/com/zbf/generator/util/VelocityUtils.java create mode 100644 zbf-generator/src/main/resources/generator.yml create mode 100644 zbf-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml create mode 100644 zbf-generator/src/main/resources/mapper/generator/GenTableMapper.xml create mode 100644 zbf-generator/src/main/resources/vm/java/controller.java.vm create mode 100644 zbf-generator/src/main/resources/vm/java/domain.java.vm create mode 100644 zbf-generator/src/main/resources/vm/java/mapper.java.vm create mode 100644 zbf-generator/src/main/resources/vm/java/service.java.vm create mode 100644 zbf-generator/src/main/resources/vm/java/serviceImpl.java.vm create mode 100644 zbf-generator/src/main/resources/vm/java/sub-domain.java.vm create mode 100644 zbf-generator/src/main/resources/vm/js/api.js.vm create mode 100644 zbf-generator/src/main/resources/vm/sql/sql.vm create mode 100644 zbf-generator/src/main/resources/vm/vue/index-tree.vue.vm create mode 100644 zbf-generator/src/main/resources/vm/vue/index.vue.vm create mode 100644 zbf-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm create mode 100644 zbf-generator/src/main/resources/vm/vue/v3/index.vue.vm create mode 100644 zbf-generator/src/main/resources/vm/xml/mapper.xml.vm create mode 100644 zbf-quartz/pom.xml create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/config/ScheduleConfig.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/controller/SysJobController.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/controller/SysJobLogController.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/domain/SysJob.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/domain/SysJobLog.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/mapper/SysJobLogMapper.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/mapper/SysJobMapper.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/service/ISysJobLogService.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/service/ISysJobService.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/service/impl/SysJobLogServiceImpl.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/service/impl/SysJobServiceImpl.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/task/DataPushing.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/task/GeneratePlcIdTask.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/task/InventoryTask.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/task/RyTask.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/task/UpdatePallet.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/util/AbstractQuartzJob.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/util/CronUtils.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/util/JobInvokeUtil.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/util/QuartzDisallowConcurrentExecution.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/util/QuartzJobExecution.java create mode 100644 zbf-quartz/src/main/java/com/zbf/quartz/util/ScheduleUtils.java create mode 100644 zbf-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml create mode 100644 zbf-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml create mode 100644 zbf-system/pom.xml create mode 100644 zbf-system/src/main/java/com/zbf/system/config/CommonConfig.java create mode 100644 zbf-system/src/main/java/com/zbf/system/config/D_Service.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/ActRuExecution.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/AppVersions.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/DataItem.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/DeadLetterJob.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/DeviceLog.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/FlowInfo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/InventoryCheck.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/Leaveapply.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/Meeting.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/ModelParam.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/OutBound.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/OutStockVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/Plc.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/Process.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/Purchase.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/RfidQuantityUpdateRequest.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/RfidQueryRequest.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SafetyStockVO.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysCache.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysConfig.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysDeployForm.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysExpression.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysForm.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysListener.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysLogininfor.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysNotice.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysOperLog.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysPost.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysRoleDept.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysRoleMenu.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysTaskForm.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysUserBusinessColumn.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysUserOnline.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysUserPost.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/SysUserRole.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TAgv.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseFinancialClass.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseGoods.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseGoodsBom.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBasePallet.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseProvider.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseStorage.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseStorageArea.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseStorageAreaLocation.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TBaseStorageLocationRecord.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TCallNotice.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TCallNoticeOrder.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TCkOrderdetail.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TCkOrders.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TCkPickingwavegoods.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TCkPickingwavegoodsBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TErrorLog.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiStock.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiStockBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiStockDto.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiStockF.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiStockFUpdate.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiStockUpdate.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TMiXnStock.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TOngoodsshelf.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TOngoodsshelfBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TPanDetail.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TPanOrder.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkReceivingGoods.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkReceivingGoodsTab.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkWareNotice.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkWareNoticeBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkWareNoticeTab.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkWareNoticeTabBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkWareNoticeTabExcel.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkWareNoticeTabUpdate.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TRkXnWareNoticeTabBak.java create mode 100755 zbf-system/src/main/java/com/zbf/system/domain/TSeq.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TStockCheck.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TUserConfig.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TUserFavorites.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/Task.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TaskInfo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TckOrderdetailBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TckOrdersBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TckXnOrderdetailBak.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/TransferOrder.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/VariableInfo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/D_Instance.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/DataPayload.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/GoodsToD.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/GoodsVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/MetaVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/Quest.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/RouterVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/TCkOrdersVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/TMiStockVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/TPanVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/TRkWareNoticeTabVo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/domain/vo/Types.java create mode 100644 zbf-system/src/main/java/com/zbf/system/listener/MyTaskListener.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/ActRuExecutionMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/AppVersionsMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/DeviceLogMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/InventoryCheckMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/LeaveapplyMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/MeetingMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/OutBoundMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/PlcMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/PurchaseMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/RkWareNoticeTabMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SafetyStockMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysConfigMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysDeptMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysDictDataMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysDictTypeMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysExpressionMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysFormMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysListenerMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysLogininforMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysMenuMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysNoticeMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysOperLogMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysPostMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysRoleDeptMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysRoleMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysRoleMenuMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysTaskFormMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysUserBusinessColumnMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysUserMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysUserPostMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/SysUserRoleMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TAgvMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseFinancialClassMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseGoodsBomMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseGoodsMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBasePalletMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseProviderMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseStorageAreaLocationMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseStorageAreaMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TBaseStorageMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TCallNoticeMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TCallNoticeOrderMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TCkOrderdetailMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TCkOrdersMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TCkPickingwavegoodsBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TCkPickingwavegoodsMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TErrorLogMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TMiStockBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TMiStockFMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TMiStockMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TMiXnStockMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TOngoodsshelfBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TOngoodsshelfMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TPanDetailMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TPanOrderMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TRkReceivingGoodsMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TRkWareNoticeBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TRkWareNoticeMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TRkWareNoticeTabBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TRkWareNoticeTabMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TRkXnWareNoticeTabBakMapper.java create mode 100755 zbf-system/src/main/java/com/zbf/system/mapper/TSeqMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TStockCheckMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TUserConfigMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TUserFavoritesMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TckOrderdetailBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TckOrdersBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TckXnOrderdetailBakMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/mapper/TransferOrderMapper.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/BoxCodeEntity.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/Print.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/Req.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/RotateImage.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/SalesTicket.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/TWmsDataEntity.java create mode 100644 zbf-system/src/main/java/com/zbf/system/print/YcPrinter.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IAppVersionsService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IDeviceLogService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IInventoryCheckService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ILeaveapplyService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IMeetingService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IOutBoundService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IPlcService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/IPurchaseService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysConfigService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysDeptService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysDictDataService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysDictTypeService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysExpressionService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysListenerService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysLogininforService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysMenuService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysNoticeService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysOperLogService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysPostService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysRoleService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysUserBusinessColumnService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysUserOnlineService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ISysUserService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITAgvService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseFinancialClassService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseGoodsBomService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseGoodsService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBasePalletService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseProviderService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseStorageAreaLocationService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseStorageAreaService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITBaseStorageService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITCallNoticeOrderService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITCallNoticeService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITCkOrderdetailService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITCkOrdersService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITCkPickingwavegoodsBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITCkPickingwavegoodsService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITErrorLogService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITMiStockBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITMiStockFService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITMiStockService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITMiXnStockService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITOngoodsshelfBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITOngoodsshelfService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITOverdueService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITPanDetailService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITPanOrderService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITRkReceivingGoodsService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITRkWareNoticeBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITRkWareNoticeService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITRkWareNoticeTabBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITRkWareNoticeTabService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITRkXnWareNoticeTabBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITSafetyStockService.java create mode 100755 zbf-system/src/main/java/com/zbf/system/service/ITSeqService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITStockCheckService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITUserConfigService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITUserFavoritesService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITckOrderdetailBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITckOrdersBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITckXnOrderdetailBakService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/ITransferOrderService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/LargeScreenService.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/AppVersionsServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/DeviceLogServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/InventoryCheckServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/LargeScreenServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/LeaveapplyServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/MeetingServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/OutBoundServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/PlcServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/PurchaseServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysConfigServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysDeptServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysDictDataServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysDictTypeServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysExpressionServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysListenerServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysLogininforServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysMenuServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysNoticeServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysOperLogServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysPostServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysRoleServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysUserBusinessColumnServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysUserOnlineServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/SysUserServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TAgvServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseFinancialClassServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseGoodsBomServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseGoodsServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBasePalletServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseProviderServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseStorageAreaLocationServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseStorageAreaServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TBaseStorageServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TCallNoticeOrderServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TCallNoticeServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TCkOrderdetailServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TCkOrdersServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TCkPickingwavegoodsBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TCkPickingwavegoodsServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TErrorLogServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TMiStockBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TMiStockFServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TMiStockServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TMiXnStockServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TOngoodsshelfBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TOngoodsshelfServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TOverdueServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TPanDetailServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TPanOrderServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TRkReceivingGoodsServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TRkWareNoticeBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TRkWareNoticeServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TRkWareNoticeTabBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TRkWareNoticeTabServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TRkXnWareNoticeTabBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TSafetyStockServiceImpl.java create mode 100755 zbf-system/src/main/java/com/zbf/system/service/impl/TSeqServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TStockCheckServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TUserConfigServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TUserFavoritesServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TckOrderdetailBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TckOrdersBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TckXnOrderdetailBakServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/service/impl/TransferOrderServiceImpl.java create mode 100644 zbf-system/src/main/java/com/zbf/system/test/GenericsExample.java create mode 100644 zbf-system/src/main/java/com/zbf/system/utils/DeviceInfo.java create mode 100644 zbf-system/src/main/java/com/zbf/system/utils/HttpUtils.java create mode 100644 zbf-system/src/main/java/com/zbf/system/utils/SignTool.java create mode 100644 zbf-system/src/main/java/com/zbf/system/utils/test.java create mode 100644 zbf-system/src/main/java/com/zbf/system/websocket/SemaphoreUtils.java create mode 100644 zbf-system/src/main/java/com/zbf/system/websocket/WebSocketConfig.java create mode 100644 zbf-system/src/main/java/com/zbf/system/websocket/WebSocketServer.java create mode 100644 zbf-system/src/main/java/com/zbf/system/websocket/WebSocketUsers.java create mode 100644 zbf-system/src/main/java/com/zbf/system/websocket/WsAuthHandlerInterceptor.java create mode 100644 zbf-system/src/main/resources/mapper/system/ActRuExecutionMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/AppVersionsMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/DeviceLogMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/InventoryCheckMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/LeaveapplyMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/MeetingMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/OutBoundMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/PlcMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/PurchaseMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SafetyStockMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysConfigMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysDeployFormMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysDeptMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysDictDataMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysDictTypeMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysExpressionMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysFormMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysListenerMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysLogininforMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysMenuMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysNoticeMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysOperLogMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysPostMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysRoleMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysUserBusinessColumnMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysUserMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysUserPostMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/SysUserRoleMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TAgvMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseFinancialClassMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseGoodsBomMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseGoodsMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBasePalletMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseProviderMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseStorageAreaLocationMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseStorageAreaMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TBaseStorageMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TCallNoticeMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TCallNoticeOrderMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TCkOrderdetailMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TCkOrdersMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TCkPickingwavegoodsBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TCkPickingwavegoodsMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TErrorLogMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TMiStockBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TMiStockFMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TMiStockMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TMiXnStockMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TOngoodsshelfBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TOngoodsshelfMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TPanDetailMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TPanOrderMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TRkReceivingGoodsMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TRkWareNoticeBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TRkWareNoticeMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TRkWareNoticeTabBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TRkWareNoticeTabMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TRkXnWareNoticeTabBakMapper.xml create mode 100755 zbf-system/src/main/resources/mapper/system/TSeqMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TStockCheckMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TUserConfigMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TUserFavoritesMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TckOrderdetailBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TckOrdersBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TckXnOrderdetailBakMapper.xml create mode 100644 zbf-system/src/main/resources/mapper/system/TransferOrderMapper.xml create mode 100644 zbf-system/src/main/resources/print_logo.png create mode 100644 zbf-ui/.editorconfig create mode 100644 zbf-ui/.env.development create mode 100644 zbf-ui/.env.production create mode 100644 zbf-ui/.env.staging create mode 100644 zbf-ui/.eslintignore create mode 100644 zbf-ui/.eslintrc.js create mode 100644 zbf-ui/.gitignore create mode 100644 zbf-ui/README.md create mode 100644 zbf-ui/babel.config.js create mode 100644 zbf-ui/bin/build.bat create mode 100644 zbf-ui/bin/package.bat create mode 100644 zbf-ui/bin/run-web.bat create mode 100644 zbf-ui/build/index.js create mode 100644 zbf-ui/package.json create mode 100644 zbf-ui/public/1.png create mode 100644 zbf-ui/public/2.png create mode 100644 zbf-ui/public/3.png create mode 100644 zbf-ui/public/favicon.ico create mode 100644 zbf-ui/public/html/ie.html create mode 100644 zbf-ui/public/img.png create mode 100644 zbf-ui/public/index.html create mode 100644 zbf-ui/public/preview.html create mode 100644 zbf-ui/public/robots.txt create mode 100644 zbf-ui/src/App.vue create mode 100644 zbf-ui/src/api/common.js create mode 100644 zbf-ui/src/api/login.js create mode 100644 zbf-ui/src/api/menu.js create mode 100644 zbf-ui/src/api/monitor/cache.js create mode 100644 zbf-ui/src/api/monitor/job.js create mode 100644 zbf-ui/src/api/monitor/jobLog.js create mode 100644 zbf-ui/src/api/monitor/logininfor.js create mode 100644 zbf-ui/src/api/monitor/online.js create mode 100644 zbf-ui/src/api/monitor/operlog.js create mode 100644 zbf-ui/src/api/monitor/server.js create mode 100644 zbf-ui/src/api/system/batchAdjustment.js create mode 100644 zbf-ui/src/api/system/bom.js create mode 100644 zbf-ui/src/api/system/bound.js create mode 100644 zbf-ui/src/api/system/check.js create mode 100644 zbf-ui/src/api/system/ckOrders.js create mode 100644 zbf-ui/src/api/system/ckPickingWavegoodsbak.js create mode 100644 zbf-ui/src/api/system/column.js create mode 100644 zbf-ui/src/api/system/config.js create mode 100644 zbf-ui/src/api/system/dept.js create mode 100644 zbf-ui/src/api/system/dict/data.js create mode 100644 zbf-ui/src/api/system/dict/type.js create mode 100644 zbf-ui/src/api/system/expression.js create mode 100644 zbf-ui/src/api/system/favorites.js create mode 100644 zbf-ui/src/api/system/financialClass.js create mode 100644 zbf-ui/src/api/system/freeze.js create mode 100644 zbf-ui/src/api/system/goods.js create mode 100644 zbf-ui/src/api/system/listener.js create mode 100644 zbf-ui/src/api/system/location.js create mode 100644 zbf-ui/src/api/system/log.js create mode 100644 zbf-ui/src/api/system/menu.js create mode 100644 zbf-ui/src/api/system/notice.js create mode 100644 zbf-ui/src/api/system/ongoodsShelfBak.js create mode 100644 zbf-ui/src/api/system/ongoodsshelf.js create mode 100644 zbf-ui/src/api/system/orderdetail.js create mode 100644 zbf-ui/src/api/system/orderdetailBak.js create mode 100644 zbf-ui/src/api/system/overInsured.js create mode 100644 zbf-ui/src/api/system/overdueStock.js create mode 100644 zbf-ui/src/api/system/pallet.js create mode 100644 zbf-ui/src/api/system/panDetail.js create mode 100644 zbf-ui/src/api/system/panOrder.js create mode 100644 zbf-ui/src/api/system/pickingwavegoods.js create mode 100644 zbf-ui/src/api/system/post.js create mode 100644 zbf-ui/src/api/system/provider.js create mode 100644 zbf-ui/src/api/system/rkRecevinggoods.js create mode 100644 zbf-ui/src/api/system/rkWareNoticeBak.js create mode 100644 zbf-ui/src/api/system/rkWareNoticeTabBak.js create mode 100644 zbf-ui/src/api/system/rkXnWareNoticeTabBak.js create mode 100644 zbf-ui/src/api/system/role.js create mode 100644 zbf-ui/src/api/system/safetyStock.js create mode 100644 zbf-ui/src/api/system/storage.js create mode 100644 zbf-ui/src/api/system/storageArea.js create mode 100644 zbf-ui/src/api/system/tMiStock.js create mode 100644 zbf-ui/src/api/system/tMiStockbak.js create mode 100644 zbf-ui/src/api/system/tMiXnStock.js create mode 100644 zbf-ui/src/api/system/tckOrderDetailbak.js create mode 100644 zbf-ui/src/api/system/tckOrdersbak.js create mode 100644 zbf-ui/src/api/system/tckXnOrderDetailbak.js create mode 100644 zbf-ui/src/api/system/trkNotice.js create mode 100644 zbf-ui/src/api/system/trkWareNoticeTab.js create mode 100644 zbf-ui/src/api/system/user.js create mode 100644 zbf-ui/src/api/system/user_config.js create mode 100644 zbf-ui/src/api/tableMixin.js create mode 100644 zbf-ui/src/api/tool/gen.js create mode 100644 zbf-ui/src/assets/401_images/401.gif create mode 100644 zbf-ui/src/assets/404_images/404.png create mode 100644 zbf-ui/src/assets/404_images/404_cloud.png create mode 100644 zbf-ui/src/assets/icons/index.js create mode 100644 zbf-ui/src/assets/icons/svg/404.svg create mode 100644 zbf-ui/src/assets/icons/svg/bug.svg create mode 100644 zbf-ui/src/assets/icons/svg/build.svg create mode 100644 zbf-ui/src/assets/icons/svg/button.svg create mode 100644 zbf-ui/src/assets/icons/svg/cascader.svg create mode 100644 zbf-ui/src/assets/icons/svg/chart.svg create mode 100644 zbf-ui/src/assets/icons/svg/checkbox.svg create mode 100644 zbf-ui/src/assets/icons/svg/clipboard.svg create mode 100644 zbf-ui/src/assets/icons/svg/code.svg create mode 100644 zbf-ui/src/assets/icons/svg/color.svg create mode 100644 zbf-ui/src/assets/icons/svg/component.svg create mode 100644 zbf-ui/src/assets/icons/svg/dashboard.svg create mode 100644 zbf-ui/src/assets/icons/svg/date-range.svg create mode 100644 zbf-ui/src/assets/icons/svg/date.svg create mode 100644 zbf-ui/src/assets/icons/svg/dict.svg create mode 100644 zbf-ui/src/assets/icons/svg/documentation.svg create mode 100644 zbf-ui/src/assets/icons/svg/download.svg create mode 100644 zbf-ui/src/assets/icons/svg/drag.svg create mode 100644 zbf-ui/src/assets/icons/svg/druid.svg create mode 100644 zbf-ui/src/assets/icons/svg/edit.svg create mode 100644 zbf-ui/src/assets/icons/svg/education.svg create mode 100644 zbf-ui/src/assets/icons/svg/email.svg create mode 100644 zbf-ui/src/assets/icons/svg/example.svg create mode 100644 zbf-ui/src/assets/icons/svg/excel.svg create mode 100644 zbf-ui/src/assets/icons/svg/exit-fullscreen.svg create mode 100644 zbf-ui/src/assets/icons/svg/eye-open.svg create mode 100644 zbf-ui/src/assets/icons/svg/eye.svg create mode 100644 zbf-ui/src/assets/icons/svg/favicon.svg create mode 100644 zbf-ui/src/assets/icons/svg/form.svg create mode 100644 zbf-ui/src/assets/icons/svg/fullscreen.svg create mode 100644 zbf-ui/src/assets/icons/svg/github.svg create mode 100644 zbf-ui/src/assets/icons/svg/guide.svg create mode 100644 zbf-ui/src/assets/icons/svg/icon.svg create mode 100644 zbf-ui/src/assets/icons/svg/input.svg create mode 100644 zbf-ui/src/assets/icons/svg/international.svg create mode 100644 zbf-ui/src/assets/icons/svg/job.svg create mode 100644 zbf-ui/src/assets/icons/svg/language.svg create mode 100644 zbf-ui/src/assets/icons/svg/link.svg create mode 100644 zbf-ui/src/assets/icons/svg/list.svg create mode 100644 zbf-ui/src/assets/icons/svg/lock.svg create mode 100644 zbf-ui/src/assets/icons/svg/log.svg create mode 100644 zbf-ui/src/assets/icons/svg/logininfor.svg create mode 100644 zbf-ui/src/assets/icons/svg/message.svg create mode 100644 zbf-ui/src/assets/icons/svg/money.svg create mode 100644 zbf-ui/src/assets/icons/svg/monitor.svg create mode 100644 zbf-ui/src/assets/icons/svg/nested.svg create mode 100644 zbf-ui/src/assets/icons/svg/number.svg create mode 100644 zbf-ui/src/assets/icons/svg/online.svg create mode 100644 zbf-ui/src/assets/icons/svg/password.svg create mode 100644 zbf-ui/src/assets/icons/svg/pdf.svg create mode 100644 zbf-ui/src/assets/icons/svg/people.svg create mode 100644 zbf-ui/src/assets/icons/svg/peoples.svg create mode 100644 zbf-ui/src/assets/icons/svg/phone.svg create mode 100644 zbf-ui/src/assets/icons/svg/post.svg create mode 100644 zbf-ui/src/assets/icons/svg/qq.svg create mode 100644 zbf-ui/src/assets/icons/svg/question.svg create mode 100644 zbf-ui/src/assets/icons/svg/radio.svg create mode 100644 zbf-ui/src/assets/icons/svg/rate.svg create mode 100644 zbf-ui/src/assets/icons/svg/redis-list.svg create mode 100644 zbf-ui/src/assets/icons/svg/redis.svg create mode 100644 zbf-ui/src/assets/icons/svg/row.svg create mode 100644 zbf-ui/src/assets/icons/svg/search.svg create mode 100644 zbf-ui/src/assets/icons/svg/select.svg create mode 100644 zbf-ui/src/assets/icons/svg/server.svg create mode 100644 zbf-ui/src/assets/icons/svg/shopping.svg create mode 100644 zbf-ui/src/assets/icons/svg/size.svg create mode 100644 zbf-ui/src/assets/icons/svg/skill.svg create mode 100644 zbf-ui/src/assets/icons/svg/slider.svg create mode 100644 zbf-ui/src/assets/icons/svg/star.svg create mode 100644 zbf-ui/src/assets/icons/svg/swagger.svg create mode 100644 zbf-ui/src/assets/icons/svg/switch.svg create mode 100644 zbf-ui/src/assets/icons/svg/system.svg create mode 100644 zbf-ui/src/assets/icons/svg/tab.svg create mode 100644 zbf-ui/src/assets/icons/svg/table.svg create mode 100644 zbf-ui/src/assets/icons/svg/textarea.svg create mode 100644 zbf-ui/src/assets/icons/svg/theme.svg create mode 100644 zbf-ui/src/assets/icons/svg/time-range.svg create mode 100644 zbf-ui/src/assets/icons/svg/time.svg create mode 100644 zbf-ui/src/assets/icons/svg/tool.svg create mode 100644 zbf-ui/src/assets/icons/svg/tree-table.svg create mode 100644 zbf-ui/src/assets/icons/svg/tree.svg create mode 100644 zbf-ui/src/assets/icons/svg/upload.svg create mode 100644 zbf-ui/src/assets/icons/svg/user.svg create mode 100644 zbf-ui/src/assets/icons/svg/validCode.svg create mode 100644 zbf-ui/src/assets/icons/svg/wechat.svg create mode 100644 zbf-ui/src/assets/icons/svg/zip.svg create mode 100644 zbf-ui/src/assets/icons/svg/山东港口.svg create mode 100644 zbf-ui/src/assets/icons/svgo.yml create mode 100644 zbf-ui/src/assets/images/bg.jpg create mode 100644 zbf-ui/src/assets/images/dark.svg create mode 100644 zbf-ui/src/assets/images/index_1.jpg create mode 100644 zbf-ui/src/assets/images/index_2.jpg create mode 100644 zbf-ui/src/assets/images/index_3.jpg create mode 100644 zbf-ui/src/assets/images/index_logo_new.png create mode 100644 zbf-ui/src/assets/images/index_logo_short.png create mode 100644 zbf-ui/src/assets/images/index_logo_white.png create mode 100644 zbf-ui/src/assets/images/light.svg create mode 100644 zbf-ui/src/assets/images/login-background.jpg create mode 100644 zbf-ui/src/assets/images/pay.png create mode 100644 zbf-ui/src/assets/images/profile.jpg create mode 100644 zbf-ui/src/assets/logo/logo.png create mode 100644 zbf-ui/src/assets/styles/btn.scss create mode 100644 zbf-ui/src/assets/styles/element-ui.scss create mode 100644 zbf-ui/src/assets/styles/element-variables.scss create mode 100644 zbf-ui/src/assets/styles/index.scss create mode 100644 zbf-ui/src/assets/styles/mixin.scss create mode 100644 zbf-ui/src/assets/styles/ruoyi.scss create mode 100644 zbf-ui/src/assets/styles/sidebar.scss create mode 100644 zbf-ui/src/assets/styles/transition.scss create mode 100644 zbf-ui/src/assets/styles/variables.scss create mode 100644 zbf-ui/src/components/Breadcrumb/index.vue create mode 100644 zbf-ui/src/components/ChartPanel.vue create mode 100644 zbf-ui/src/components/Crontab/day.vue create mode 100644 zbf-ui/src/components/Crontab/hour.vue create mode 100644 zbf-ui/src/components/Crontab/index.vue create mode 100644 zbf-ui/src/components/Crontab/min.vue create mode 100644 zbf-ui/src/components/Crontab/month.vue create mode 100644 zbf-ui/src/components/Crontab/result.vue create mode 100644 zbf-ui/src/components/Crontab/second.vue create mode 100644 zbf-ui/src/components/Crontab/week.vue create mode 100644 zbf-ui/src/components/Crontab/year.vue create mode 100644 zbf-ui/src/components/DictData/index.js create mode 100644 zbf-ui/src/components/DictTag/index.vue create mode 100644 zbf-ui/src/components/Editor/index.vue create mode 100644 zbf-ui/src/components/FileUpload/index.vue create mode 100644 zbf-ui/src/components/Hamburger/index.vue create mode 100644 zbf-ui/src/components/HeaderSearch/index.vue create mode 100644 zbf-ui/src/components/IconSelect/index.vue create mode 100644 zbf-ui/src/components/IconSelect/requireIcons.js create mode 100644 zbf-ui/src/components/ImagePreview/index.vue create mode 100644 zbf-ui/src/components/ImageUpload/index.vue create mode 100644 zbf-ui/src/components/Pagination/index.vue create mode 100644 zbf-ui/src/components/PanThumb/index.vue create mode 100644 zbf-ui/src/components/ParentView/index.vue create mode 100644 zbf-ui/src/components/Print/index.vue create mode 100644 zbf-ui/src/components/RightPanel/index.vue create mode 100644 zbf-ui/src/components/RightToolbar/index.vue create mode 100644 zbf-ui/src/components/RuoYi/Doc/index.vue create mode 100644 zbf-ui/src/components/RuoYi/Git/index.vue create mode 100644 zbf-ui/src/components/Screenfull/index.vue create mode 100644 zbf-ui/src/components/SizeSelect/index.vue create mode 100644 zbf-ui/src/components/StatCardContent.vue create mode 100644 zbf-ui/src/components/SvgIcon/index.vue create mode 100644 zbf-ui/src/components/TableTemplate/index.vue create mode 100644 zbf-ui/src/components/ThemePicker/index.vue create mode 100644 zbf-ui/src/components/TopNav/index.vue create mode 100644 zbf-ui/src/components/customBpmn/index.js create mode 100644 zbf-ui/src/components/flow/Expression/index.vue create mode 100644 zbf-ui/src/components/flow/Listener/index.vue create mode 100644 zbf-ui/src/components/flow/Role/index.vue create mode 100644 zbf-ui/src/components/flow/User/index.vue create mode 100644 zbf-ui/src/components/iFrame/index.vue create mode 100644 zbf-ui/src/components/parser/Parser.vue create mode 100644 zbf-ui/src/components/parser/README.md create mode 100644 zbf-ui/src/components/parser/example/Index.vue create mode 100644 zbf-ui/src/components/parser/index.js create mode 100644 zbf-ui/src/components/parser/package.json create mode 100644 zbf-ui/src/components/render/package.json create mode 100644 zbf-ui/src/components/render/render.js create mode 100644 zbf-ui/src/components/render/slots/el-button.js create mode 100644 zbf-ui/src/components/render/slots/el-checkbox-group.js create mode 100644 zbf-ui/src/components/render/slots/el-input.js create mode 100644 zbf-ui/src/components/render/slots/el-radio-group.js create mode 100644 zbf-ui/src/components/render/slots/el-select.js create mode 100644 zbf-ui/src/components/render/slots/el-upload.js create mode 100644 zbf-ui/src/components/tinymce/README.md create mode 100644 zbf-ui/src/components/tinymce/config.js create mode 100644 zbf-ui/src/components/tinymce/index.js create mode 100644 zbf-ui/src/components/tinymce/index.vue create mode 100644 zbf-ui/src/components/tinymce/package.json create mode 100644 zbf-ui/src/components/tinymce/zh_CN.js create mode 100644 zbf-ui/src/directive/dialog/drag.js create mode 100644 zbf-ui/src/directive/dialog/dragHeight.js create mode 100644 zbf-ui/src/directive/dialog/dragWidth.js create mode 100644 zbf-ui/src/directive/index.js create mode 100644 zbf-ui/src/directive/module/clipboard.js create mode 100644 zbf-ui/src/directive/permission/hasPermi.js create mode 100644 zbf-ui/src/directive/permission/hasRole.js create mode 100644 zbf-ui/src/icons/index.js create mode 100644 zbf-ui/src/icons/svg/button.svg create mode 100644 zbf-ui/src/icons/svg/cascader.svg create mode 100644 zbf-ui/src/icons/svg/checkbox.svg create mode 100644 zbf-ui/src/icons/svg/color.svg create mode 100644 zbf-ui/src/icons/svg/component.svg create mode 100644 zbf-ui/src/icons/svg/date-range.svg create mode 100644 zbf-ui/src/icons/svg/date.svg create mode 100644 zbf-ui/src/icons/svg/input.svg create mode 100644 zbf-ui/src/icons/svg/number.svg create mode 100644 zbf-ui/src/icons/svg/password.svg create mode 100644 zbf-ui/src/icons/svg/radio.svg create mode 100644 zbf-ui/src/icons/svg/rate.svg create mode 100644 zbf-ui/src/icons/svg/rich-text.svg create mode 100644 zbf-ui/src/icons/svg/row.svg create mode 100644 zbf-ui/src/icons/svg/select.svg create mode 100644 zbf-ui/src/icons/svg/slider.svg create mode 100644 zbf-ui/src/icons/svg/switch.svg create mode 100644 zbf-ui/src/icons/svg/table.svg create mode 100644 zbf-ui/src/icons/svg/textarea.svg create mode 100644 zbf-ui/src/icons/svg/time-range.svg create mode 100644 zbf-ui/src/icons/svg/time.svg create mode 100644 zbf-ui/src/icons/svg/upload.svg create mode 100644 zbf-ui/src/layout/components/AppMain.vue create mode 100644 zbf-ui/src/layout/components/IframeToggle/index.vue create mode 100644 zbf-ui/src/layout/components/InnerLink/index.vue create mode 100644 zbf-ui/src/layout/components/Navbar.vue create mode 100644 zbf-ui/src/layout/components/Settings/index.vue create mode 100644 zbf-ui/src/layout/components/Sidebar/FixiOSBug.js create mode 100644 zbf-ui/src/layout/components/Sidebar/Item.vue create mode 100644 zbf-ui/src/layout/components/Sidebar/Link.vue create mode 100644 zbf-ui/src/layout/components/Sidebar/Logo.vue create mode 100644 zbf-ui/src/layout/components/Sidebar/SidebarItem.vue create mode 100644 zbf-ui/src/layout/components/Sidebar/index.vue create mode 100644 zbf-ui/src/layout/components/TagsView/ScrollPane.vue create mode 100644 zbf-ui/src/layout/components/TagsView/index.vue create mode 100644 zbf-ui/src/layout/components/index.js create mode 100644 zbf-ui/src/layout/index.vue create mode 100644 zbf-ui/src/layout/mixin/ResizeHandler.js create mode 100644 zbf-ui/src/main.js create mode 100644 zbf-ui/src/permission.js create mode 100644 zbf-ui/src/plugins/auth.js create mode 100644 zbf-ui/src/plugins/cache.js create mode 100644 zbf-ui/src/plugins/download.js create mode 100644 zbf-ui/src/plugins/index.js create mode 100644 zbf-ui/src/plugins/modal.js create mode 100644 zbf-ui/src/plugins/tab.js create mode 100644 zbf-ui/src/router/index.js create mode 100644 zbf-ui/src/router/updateIndex.js create mode 100644 zbf-ui/src/settings.js create mode 100644 zbf-ui/src/store/getters.js create mode 100644 zbf-ui/src/store/index.js create mode 100644 zbf-ui/src/store/modules/app.js create mode 100644 zbf-ui/src/store/modules/dict.js create mode 100644 zbf-ui/src/store/modules/permission.js create mode 100644 zbf-ui/src/store/modules/settings.js create mode 100644 zbf-ui/src/store/modules/tagsView.js create mode 100644 zbf-ui/src/store/modules/user.js create mode 100644 zbf-ui/src/styles/home.scss create mode 100644 zbf-ui/src/styles/index.scss create mode 100644 zbf-ui/src/styles/mixin.scss create mode 100644 zbf-ui/src/utils/StrUtil.js create mode 100644 zbf-ui/src/utils/auth.js create mode 100644 zbf-ui/src/utils/common.js create mode 100644 zbf-ui/src/utils/db.js create mode 100644 zbf-ui/src/utils/dict/Dict.js create mode 100644 zbf-ui/src/utils/dict/DictConverter.js create mode 100644 zbf-ui/src/utils/dict/DictData.js create mode 100644 zbf-ui/src/utils/dict/DictMeta.js create mode 100644 zbf-ui/src/utils/dict/DictOptions.js create mode 100644 zbf-ui/src/utils/dict/index.js create mode 100644 zbf-ui/src/utils/errorCode.js create mode 100644 zbf-ui/src/utils/generator/config.js create mode 100644 zbf-ui/src/utils/generator/css.js create mode 100644 zbf-ui/src/utils/generator/drawingDefalut.js create mode 100644 zbf-ui/src/utils/generator/html.js create mode 100644 zbf-ui/src/utils/generator/icon.json create mode 100644 zbf-ui/src/utils/generator/js.js create mode 100644 zbf-ui/src/utils/generator/render.js create mode 100644 zbf-ui/src/utils/generator/ruleTrigger.js create mode 100644 zbf-ui/src/utils/index.js create mode 100644 zbf-ui/src/utils/jsencrypt.js create mode 100644 zbf-ui/src/utils/loadBeautifier.js create mode 100644 zbf-ui/src/utils/loadMonaco.js create mode 100644 zbf-ui/src/utils/loadScript.js create mode 100644 zbf-ui/src/utils/loadTinymce.js create mode 100644 zbf-ui/src/utils/permission.js create mode 100644 zbf-ui/src/utils/pluginsConfig.js create mode 100644 zbf-ui/src/utils/request.js create mode 100644 zbf-ui/src/utils/ruoyi.js create mode 100644 zbf-ui/src/utils/scroll-to.js create mode 100644 zbf-ui/src/utils/validate.js create mode 100644 zbf-ui/src/views/bl.vue create mode 100644 zbf-ui/src/views/dashboard/BarChart.vue create mode 100644 zbf-ui/src/views/dashboard/LineChart.vue create mode 100644 zbf-ui/src/views/dashboard/PanelGroup.vue create mode 100644 zbf-ui/src/views/dashboard/PieChart.vue create mode 100644 zbf-ui/src/views/dashboard/RaddarChart.vue create mode 100644 zbf-ui/src/views/dashboard/mixins/resize.js create mode 100644 zbf-ui/src/views/error/401.vue create mode 100644 zbf-ui/src/views/error/404.vue create mode 100644 zbf-ui/src/views/function/api/leaveApply.js create mode 100644 zbf-ui/src/views/function/api/meeting.js create mode 100644 zbf-ui/src/views/function/api/outbound.js create mode 100644 zbf-ui/src/views/function/api/purchase.js create mode 100644 zbf-ui/src/views/function/lauchMeeting.vue create mode 100644 zbf-ui/src/views/function/leaveApply.vue create mode 100644 zbf-ui/src/views/function/outbound.vue create mode 100644 zbf-ui/src/views/function/purchaseApply.vue create mode 100644 zbf-ui/src/views/index.vue create mode 100644 zbf-ui/src/views/index1.vue create mode 100644 zbf-ui/src/views/index2.vue create mode 100644 zbf-ui/src/views/indexbak1.vue create mode 100644 zbf-ui/src/views/inspection/api.js create mode 100644 zbf-ui/src/views/inspection/components/workTable.vue create mode 100644 zbf-ui/src/views/inspection/processInstance.vue create mode 100644 zbf-ui/src/views/inspection/runHistory.vue create mode 100644 zbf-ui/src/views/inspection/runInstance.vue create mode 100644 zbf-ui/src/views/inspection/workManagement.vue create mode 100644 zbf-ui/src/views/leader.vue create mode 100644 zbf-ui/src/views/libraryManagement/batchAdjustment/index.vue create mode 100644 zbf-ui/src/views/libraryManagement/freeze/index.vue create mode 100644 zbf-ui/src/views/libraryManagement/posMove/index.vue create mode 100644 zbf-ui/src/views/login.vue create mode 100644 zbf-ui/src/views/monitor/cache/index.vue create mode 100644 zbf-ui/src/views/monitor/cache/list.vue create mode 100644 zbf-ui/src/views/monitor/druid/index.vue create mode 100644 zbf-ui/src/views/monitor/job/index.vue create mode 100644 zbf-ui/src/views/monitor/job/log.vue create mode 100644 zbf-ui/src/views/monitor/logininfor/index.vue create mode 100644 zbf-ui/src/views/monitor/online/index.vue create mode 100644 zbf-ui/src/views/monitor/operlog/index.vue create mode 100644 zbf-ui/src/views/monitor/server/index.vue create mode 100644 zbf-ui/src/views/process/api/deployService.js create mode 100644 zbf-ui/src/views/process/api/model.js create mode 100644 zbf-ui/src/views/process/deployManagement.vue create mode 100644 zbf-ui/src/views/process/modelManagement.vue create mode 100644 zbf-ui/src/views/redirect.vue create mode 100644 zbf-ui/src/views/register.vue create mode 100644 zbf-ui/src/views/system/bom/index.vue create mode 100644 zbf-ui/src/views/system/bound/index.vue create mode 100644 zbf-ui/src/views/system/check/index.vue create mode 100644 zbf-ui/src/views/system/ckOrders/ct.vue create mode 100644 zbf-ui/src/views/system/ckOrders/index.vue create mode 100644 zbf-ui/src/views/system/ckPickingWavegoodsbak/index.vue create mode 100644 zbf-ui/src/views/system/column/index.vue create mode 100644 zbf-ui/src/views/system/config/index.vue create mode 100644 zbf-ui/src/views/system/dept/index.vue create mode 100644 zbf-ui/src/views/system/dialog/ExistOrdersSelect.vue create mode 100644 zbf-ui/src/views/system/dialog/GoodsSelect.vue create mode 100644 zbf-ui/src/views/system/dialog/ProviderSelect.vue create mode 100644 zbf-ui/src/views/system/dialog/StockSelect.vue create mode 100644 zbf-ui/src/views/system/dict/data.vue create mode 100644 zbf-ui/src/views/system/dict/index.vue create mode 100644 zbf-ui/src/views/system/expression/index.vue create mode 100644 zbf-ui/src/views/system/financialClass/index.vue create mode 100644 zbf-ui/src/views/system/goods/index.vue create mode 100644 zbf-ui/src/views/system/listener/index.vue create mode 100644 zbf-ui/src/views/system/location/index.vue create mode 100644 zbf-ui/src/views/system/log/index.vue create mode 100644 zbf-ui/src/views/system/menu/index.vue create mode 100644 zbf-ui/src/views/system/notice/index.vue create mode 100644 zbf-ui/src/views/system/ongoodsShelfBak/index.vue create mode 100644 zbf-ui/src/views/system/ongoodsshelf/index.vue create mode 100644 zbf-ui/src/views/system/orderdetail/index.vue create mode 100644 zbf-ui/src/views/system/orderdetailBak/index.vue create mode 100644 zbf-ui/src/views/system/overInsured/index.vue create mode 100644 zbf-ui/src/views/system/overdue/index.vue create mode 100644 zbf-ui/src/views/system/pallet/index.vue create mode 100644 zbf-ui/src/views/system/panDetail/index.vue create mode 100644 zbf-ui/src/views/system/panOrder/detail.vue create mode 100644 zbf-ui/src/views/system/panOrder/index.vue create mode 100644 zbf-ui/src/views/system/pickingwavegoods/index.vue create mode 100644 zbf-ui/src/views/system/post/index.vue create mode 100644 zbf-ui/src/views/system/print/PrintPage.vue create mode 100644 zbf-ui/src/views/system/provider/index.vue create mode 100644 zbf-ui/src/views/system/requisition/index.vue create mode 100644 zbf-ui/src/views/system/rkRecevinggoods/index.vue create mode 100644 zbf-ui/src/views/system/rkWareNoticeBak/index.vue create mode 100644 zbf-ui/src/views/system/rkXnWareNoticeBak/index.vue create mode 100644 zbf-ui/src/views/system/role/authUser.vue create mode 100644 zbf-ui/src/views/system/role/index.vue create mode 100644 zbf-ui/src/views/system/role/selectUser.vue create mode 100644 zbf-ui/src/views/system/safetyStock/index.vue create mode 100644 zbf-ui/src/views/system/storage/index.vue create mode 100644 zbf-ui/src/views/system/storageArea/index.vue create mode 100644 zbf-ui/src/views/system/tMiStock/index.vue create mode 100644 zbf-ui/src/views/system/tMiStockbak/index.vue create mode 100644 zbf-ui/src/views/system/tMiXnStock/index.vue create mode 100644 zbf-ui/src/views/system/tckOrdersbak/index.vue create mode 100644 zbf-ui/src/views/system/tckXnOrdersbak/index.vue create mode 100644 zbf-ui/src/views/system/trkNotice/index.vue create mode 100644 zbf-ui/src/views/system/user/authRole.vue create mode 100644 zbf-ui/src/views/system/user/index.vue create mode 100644 zbf-ui/src/views/system/user/profile/index.vue create mode 100644 zbf-ui/src/views/system/user/profile/resetPwd.vue create mode 100644 zbf-ui/src/views/system/user/profile/userAvatar.vue create mode 100644 zbf-ui/src/views/system/user/profile/userInfo.vue create mode 100644 zbf-ui/src/views/todo/allTodoList.vue create mode 100644 zbf-ui/src/views/todo/api/allTodoList.js create mode 100644 zbf-ui/src/views/todo/api/myTodoList.js create mode 100644 zbf-ui/src/views/todo/api/processTaks.js create mode 100644 zbf-ui/src/views/todo/components/TimeLine.vue create mode 100644 zbf-ui/src/views/todo/components/leaveApplyForm.vue create mode 100644 zbf-ui/src/views/todo/components/meetingForm.vue create mode 100644 zbf-ui/src/views/todo/components/outboundForm.vue create mode 100644 zbf-ui/src/views/todo/components/processForm.vue create mode 100644 zbf-ui/src/views/todo/components/purchaseForm.vue create mode 100644 zbf-ui/src/views/todo/myTodoList.vue create mode 100644 zbf-ui/src/views/todo/processTask.vue create mode 100644 zbf-ui/src/views/tool/build/App.vue create mode 100644 zbf-ui/src/views/tool/build/CodeTypeDialog.vue create mode 100644 zbf-ui/src/views/tool/build/DraggableItem.vue create mode 100644 zbf-ui/src/views/tool/build/FormDrawer.vue create mode 100644 zbf-ui/src/views/tool/build/IconsDialog.vue create mode 100644 zbf-ui/src/views/tool/build/JsonDrawer.vue create mode 100644 zbf-ui/src/views/tool/build/ResourceDialog.vue create mode 100644 zbf-ui/src/views/tool/build/RightPanel.vue create mode 100644 zbf-ui/src/views/tool/build/TreeNodeDialog.vue create mode 100644 zbf-ui/src/views/tool/build/index.vue create mode 100644 zbf-ui/src/views/tool/build/main.js create mode 100644 zbf-ui/src/views/tool/gen/basicInfoForm.vue create mode 100644 zbf-ui/src/views/tool/gen/createTable.vue create mode 100644 zbf-ui/src/views/tool/gen/editTable.vue create mode 100644 zbf-ui/src/views/tool/gen/genInfoForm.vue create mode 100644 zbf-ui/src/views/tool/gen/importTable.vue create mode 100644 zbf-ui/src/views/tool/gen/index.vue create mode 100644 zbf-ui/src/views/tool/preview/main.js create mode 100644 zbf-ui/src/views/tool/swagger/index.vue create mode 100644 zbf-ui/src/views/tool/test.vue create mode 100644 zbf-ui/src/views/wx.vue create mode 100644 zbf-ui/vue.config.js diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..55a68bc492f459e5b20c63d64de4f65ad8e12ff8 GIT binary patch literal 8196 zcmeI1&2G~`5XWbmws9y$K>{fkBuiXNNk6EBxTI-%s02vVs2rdwc9N!{{z&7bfmW4r zhIil1_<#coZvsZOJX}MQZER^jh1> z`1xR?u&-!8R9-$hP{}O-{4|=S;aGn8hqt)_zM}n5d9=WUlEN#g&|3_l_YOkI(O=Q= zL*>+Q6ggT3O7 zjVSE7?XcOEf_9^ckQdL|VIvw;qkh3Ol6-%e5%d4vk_R8A5vjzL~{&IQ2 zUR_x`J1bZ>Z{K~ey?5vbVf0p|DfFX)=GFPAeupESjo(^w>QT_qim&6IAga}Lp4RTS zC#6rvpP7i(1ySQSy`6*PsAV2p>yDjn=tp4-ExfuMH7KHbhWrQgB+2LLA#KqHZPH_M zXfquxZe^mcQ-@rt(;?~>HR%rdJO|Df=@rE|&Rl81Jks-Z5EUT)HEKUI-}g-PRoceN z)~QC1;1@Ath&rG~S~tZxCub>SbQ21UN%TH(2hLKL-e7DGnf2166EjQ3&gj^f4$_g5 zS28jOCPx!lGLvLfo_4^*r#>=kQk))>a}(DRD=p9oR=E%MF0ODe`RNi&F**K~k)kfy z2b0%H5=?65N1A

&lf4pzG3MdVNeXwZ5^E?~o9M^*z>Rl;E0Dj@Nkv7A|x>I!SAo z@CBL}*Dr>mNkK*f-YL!OD7QYfGqGSdjy3Op+)2g^fy)!fDM@J#e)Hnr|1UqVQ5XV- zz&}GkOxK)R70czXq~{s$wQZD_C~O=zR9;F@$?Z72d>zA&{xHO`jZoH9v>z&u7MS@V NKw>bJA@D~D`~;w7PtE`U literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed8368a --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e245dc3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2022 tony Authors. All Rights Reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..bb85590 --- /dev/null +++ b/README.en.md @@ -0,0 +1,36 @@ +# rz_wms + +#### Description +日照港仓储管理系统 + +#### Software Architecture +Software architecture description + +#### Installation + +1. xxxx +2. xxxx +3. xxxx + +#### Instructions + +1. xxxx +2. xxxx +3. xxxx + +#### Contribution + +1. Fork the repository +2. Create Feat_xxx branch +3. Commit your code +4. Create Pull Request + + +#### Gitee Feature + +1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md +2. Gitee blog [blog.gitee.com](https://blog.gitee.com) +3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) +4. The most valuable open source project [GVP](https://gitee.com/gvp) +5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) +6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md new file mode 100644 index 0000000..8995eba --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# rz_wms + +#### 介绍 +日照港仓储管理系统 + +#### 软件架构 +软件架构说明 + + +#### 安装教程 + +1. xxxx +2. xxxx +3. xxxx + +#### 使用说明 + +1. xxxx +2. xxxx +3. xxxx + +#### 参与贡献 + +1. Fork 本仓库 +2. 新建 Feat_xxx 分支 +3. 提交代码 +4. 新建 Pull Request + + +#### 特技 + +1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md +2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) +3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 +4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 +5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) +6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) + + +# nohup java -jar rzg.jar > /dev/null 2 > out.log & + +# nginx 启动配置文件需全路径 \ No newline at end of file diff --git a/bin/clean.bat b/bin/clean.bat new file mode 100644 index 0000000..24c0974 --- /dev/null +++ b/bin/clean.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] target· +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean + +pause \ No newline at end of file diff --git a/bin/package.bat b/bin/package.bat new file mode 100644 index 0000000..c693ec0 --- /dev/null +++ b/bin/package.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] Weḅwar/jarļ +echo. + +%~d0 +cd %~dp0 + +cd .. +call mvn clean package -Dmaven.test.skip=true + +pause \ No newline at end of file diff --git a/bin/run.bat b/bin/run.bat new file mode 100644 index 0000000..41efbd0 --- /dev/null +++ b/bin/run.bat @@ -0,0 +1,14 @@ +@echo off +echo. +echo [Ϣ] ʹJarWeb̡ +echo. + +cd %~dp0 +cd ../ruoyi-admin/target + +set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m + +java -jar %JAVA_OPTS% ruoyi-admin.jar + +cd bin +pause \ No newline at end of file diff --git a/doc/若依环境使用手册.docx b/doc/若依环境使用手册.docx new file mode 100644 index 0000000000000000000000000000000000000000..9e4daef4d9be2e445419109a02eaf321cd4d537e GIT binary patch literal 428430 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 +HtCx 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 Rli)_iWGz7fMupr%QDEgRC> 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%0DfC-!Au^tv1-R|XemvERC8O1`5!u;Z5%iD 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

K#u)l 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

)q;tSdIrAwYxlSM|Hl};Y` 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..36b8560 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "rz_wms", + "lockfileVersion": 2, + "requires": true, + "packages": {} +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..33ba487 --- /dev/null +++ b/pom.xml @@ -0,0 +1,248 @@ + + + 4.0.0 + + com.zbf + zbf + 3.8.7 + + zbf + http://www.rzport.com/ + 日照港仓储管理系统 + + + 3.8.7 + UTF-8 + UTF-8 + 1.8 + 3.1.1 + 1.2.20 + 1.21 + 3.0.0 + 2.3.3 + 1.4.7 + 2.0.43 + 6.4.13 + 2.13.0 + 4.1.2 + 2.3 + 0.9.1 + 6.7.2 + 3.4.2 + 1.18.12 + + + + + + + + + org.springframework.boot + spring-boot-dependencies + 2.5.15 + pom + import + + + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + + + eu.bitwalker + UserAgentUtils + ${bitwalker.version} + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.boot.version} + + + + + com.github.oshi + oshi-core + ${oshi.version} + + + + + io.springfox + springfox-boot-starter + ${swagger.version} + + + io.swagger + swagger-models + + + + + + + commons-io + commons-io + ${commons.io.version} + + + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + com.alibaba.fastjson2 + fastjson2 + ${fastjson.version} + + + + + io.jsonwebtoken + jjwt + ${jwt.version} + + + + + pro.fessional + kaptcha + ${kaptcha.version} + + + + + com.zbf + zbf-quartz + ${zbf.version} + + + + + com.zbf + zbf-generator + ${zbf.version} + + + + + com.zbf + zbf-framework + ${zbf.version} + + + + + com.zbf + zbf-system + ${zbf.version} + + + + + com.zbf + zbf-common + ${zbf.version} + + + + org.flowable + flowable-spring-boot-starter + ${flowable.version} + + + io.swagger + swagger-annotations + 1.5.21 + compile + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus-version} + + + org.projectlombok + lombok + ${lombok.version} + + + + com.google.guava + guava + 31.1-jre + + + + + + zbf-admin + zbf-framework + zbf-system + zbf-quartz + zbf-generator + zbf-common + + pom + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public + + true + + + + + + + public + aliyun nexus + https://maven.aliyun.com/repository/public + + true + + + false + + + + + diff --git a/ry.bat b/ry.bat new file mode 100644 index 0000000..ac1e437 --- /dev/null +++ b/ry.bat @@ -0,0 +1,67 @@ +@echo off + +rem jarƽĿ¼ +set AppName=ruoyi-admin.jar + +rem JVM +set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" + + +ECHO. + ECHO. [1] %AppName% + ECHO. [2] ر%AppName% + ECHO. [3] %AppName% + ECHO. [4] ״̬ %AppName% + ECHO. [5] +ECHO. + +ECHO.ѡĿ: +set /p ID= + IF "%id%"=="1" GOTO start + IF "%id%"=="2" GOTO stop + IF "%id%"=="3" GOTO restart + IF "%id%"=="4" GOTO status + IF "%id%"=="5" EXIT +PAUSE +:start + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if defined pid ( + echo %%is running + PAUSE + ) + +start javaw %JVM_OPTS% -jar %AppName% + +echo starting +echo Start %AppName% success... +goto:eof + +rem stopͨjpspid +:stop + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% does not exists) else ( + echo prepare to kill %image_name% + echo start kill %pid% ... + rem ݽIDkill + taskkill /f /pid %pid% + ) +goto:eof +:restart + call :stop + call :start +goto:eof +:status + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% is dead ) else ( + echo %image_name% is running + ) +goto:eof diff --git a/ry.sh b/ry.sh new file mode 100644 index 0000000..d6a9cf3 --- /dev/null +++ b/ry.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# ./ry.sh start 启动 stop 停止 restart 重启 status 状态 +AppName=ruoyi-admin.jar + +# JVM参数 +JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" +APP_HOME=`pwd` +LOG_PATH=$APP_HOME/logs/$AppName.log + +if [ "$1" = "" ]; +then + echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" + exit 1 +fi + +if [ "$AppName" = "" ]; +then + echo -e "\033[0;31m 未输入应用名 \033[0m" + exit 1 +fi + +function start() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + + if [ x"$PID" != x"" ]; then + echo "$AppName is running..." + else + nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 & + echo "Start $AppName success..." + fi +} + +function stop() +{ + echo "Stop $AppName" + + PID="" + query(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + } + + query + if [ x"$PID" != x"" ]; then + kill -TERM $PID + echo "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ] + do + sleep 1 + query + done + echo "$AppName exited." + else + echo "$AppName already stopped." + fi +} + +function restart() +{ + stop + sleep 2 + start +} + +function status() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` + if [ $PID != 0 ];then + echo "$AppName is running..." + else + echo "$AppName is not running..." + fi +} + +case $1 in + start) + start;; + stop) + stop;; + restart) + restart;; + status) + status;; + *) + +esac diff --git a/sql/Menu.sql b/sql/Menu.sql new file mode 100644 index 0000000..57db212 --- /dev/null +++ b/sql/Menu.sql @@ -0,0 +1,3 @@ +INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2288, '托盘导入', 2158, 6, '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:pallet:import', '#', 'admin', '2024-08-28 18:10:11', '', NULL, ''); +INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2290, '供应商管理导入', 2080, 6, '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:provider:import', '#', 'admin', '2024-08-28 18:41:56', '', NULL, ''); +INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (2291, '物料管理导入', 2086, 6, '', NULL, NULL, 1, 0, 'F', '0', '0', 'system:goods:import', '#', 'admin', '2024-08-28 18:42:47', '', NULL, ''); diff --git a/sql/README.md b/sql/README.md new file mode 100644 index 0000000..c4db233 --- /dev/null +++ b/sql/README.md @@ -0,0 +1,2 @@ +## 数据库导入说明 +只需要导入tony-flowable.sql, 其它两个若依默认的SQL文件不要执行 diff --git a/sql/quartz.sql b/sql/quartz.sql new file mode 100644 index 0000000..cee613b --- /dev/null +++ b/sql/quartz.sql @@ -0,0 +1,174 @@ +DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; +DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; +DROP TABLE IF EXISTS QRTZ_LOCKS; +DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; +DROP TABLE IF EXISTS QRTZ_CALENDARS; + +-- ---------------------------- +-- 1、存储每一个已配置的 jobDetail 的详细信息 +-- ---------------------------- +create table QRTZ_JOB_DETAILS ( + sched_name varchar(120) not null comment '调度名称', + job_name varchar(200) not null comment '任务名称', + job_group varchar(200) not null comment '任务组名', + description varchar(250) null comment '相关介绍', + job_class_name varchar(250) not null comment '执行任务类名称', + is_durable varchar(1) not null comment '是否持久化', + is_nonconcurrent varchar(1) not null comment '是否并发', + is_update_data varchar(1) not null comment '是否更新数据', + requests_recovery varchar(1) not null comment '是否接受恢复执行', + job_data blob null comment '存放持久化job对象', + primary key (sched_name, job_name, job_group) +) engine=innodb comment = '任务详细信息表'; + +-- ---------------------------- +-- 2、 存储已配置的 Trigger 的信息 +-- ---------------------------- +create table QRTZ_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment '触发器的名字', + trigger_group varchar(200) not null comment '触发器所属组的名字', + job_name varchar(200) not null comment 'qrtz_job_details表job_name的外键', + job_group varchar(200) not null comment 'qrtz_job_details表job_group的外键', + description varchar(250) null comment '相关介绍', + next_fire_time bigint(13) null comment '上一次触发时间(毫秒)', + prev_fire_time bigint(13) null comment '下一次触发时间(默认为-1表示不触发)', + priority integer null comment '优先级', + trigger_state varchar(16) not null comment '触发器状态', + trigger_type varchar(8) not null comment '触发器的类型', + start_time bigint(13) not null comment '开始时间', + end_time bigint(13) null comment '结束时间', + calendar_name varchar(200) null comment '日程表名称', + misfire_instr smallint(2) null comment '补偿执行的策略', + job_data blob null comment '存放持久化job对象', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, job_name, job_group) references QRTZ_JOB_DETAILS(sched_name, job_name, job_group) +) engine=innodb comment = '触发器详细信息表'; + +-- ---------------------------- +-- 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数 +-- ---------------------------- +create table QRTZ_SIMPLE_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + repeat_count bigint(7) not null comment '重复的次数统计', + repeat_interval bigint(12) not null comment '重复的间隔时间', + times_triggered bigint(10) not null comment '已经触发的次数', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = '简单触发器的信息表'; + +-- ---------------------------- +-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息 +-- ---------------------------- +create table QRTZ_CRON_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + cron_expression varchar(200) not null comment 'cron表达式', + time_zone_id varchar(80) comment '时区', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = 'Cron类型的触发器表'; + +-- ---------------------------- +-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候) +-- ---------------------------- +create table QRTZ_BLOB_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + blob_data blob null comment '存放持久化Trigger对象', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = 'Blob类型的触发器表'; + +-- ---------------------------- +-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围 +-- ---------------------------- +create table QRTZ_CALENDARS ( + sched_name varchar(120) not null comment '调度名称', + calendar_name varchar(200) not null comment '日历名称', + calendar blob not null comment '存放持久化calendar对象', + primary key (sched_name, calendar_name) +) engine=innodb comment = '日历信息表'; + +-- ---------------------------- +-- 7、 存储已暂停的 Trigger 组的信息 +-- ---------------------------- +create table QRTZ_PAUSED_TRIGGER_GRPS ( + sched_name varchar(120) not null comment '调度名称', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + primary key (sched_name, trigger_group) +) engine=innodb comment = '暂停的触发器表'; + +-- ---------------------------- +-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息 +-- ---------------------------- +create table QRTZ_FIRED_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + entry_id varchar(95) not null comment '调度器实例id', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + instance_name varchar(200) not null comment '调度器实例名', + fired_time bigint(13) not null comment '触发的时间', + sched_time bigint(13) not null comment '定时器制定的时间', + priority integer not null comment '优先级', + state varchar(16) not null comment '状态', + job_name varchar(200) null comment '任务名称', + job_group varchar(200) null comment '任务组名', + is_nonconcurrent varchar(1) null comment '是否并发', + requests_recovery varchar(1) null comment '是否接受恢复执行', + primary key (sched_name, entry_id) +) engine=innodb comment = '已触发的触发器表'; + +-- ---------------------------- +-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例 +-- ---------------------------- +create table QRTZ_SCHEDULER_STATE ( + sched_name varchar(120) not null comment '调度名称', + instance_name varchar(200) not null comment '实例名称', + last_checkin_time bigint(13) not null comment '上次检查时间', + checkin_interval bigint(13) not null comment '检查间隔时间', + primary key (sched_name, instance_name) +) engine=innodb comment = '调度器状态表'; + +-- ---------------------------- +-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁) +-- ---------------------------- +create table QRTZ_LOCKS ( + sched_name varchar(120) not null comment '调度名称', + lock_name varchar(40) not null comment '悲观锁名称', + primary key (sched_name, lock_name) +) engine=innodb comment = '存储的悲观锁信息表'; + +-- ---------------------------- +-- 11、 Quartz集群实现同步机制的行锁表 +-- ---------------------------- +create table QRTZ_SIMPROP_TRIGGERS ( + sched_name varchar(120) not null comment '调度名称', + trigger_name varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + trigger_group varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + str_prop_1 varchar(512) null comment 'String类型的trigger的第一个参数', + str_prop_2 varchar(512) null comment 'String类型的trigger的第二个参数', + str_prop_3 varchar(512) null comment 'String类型的trigger的第三个参数', + int_prop_1 int null comment 'int类型的trigger的第一个参数', + int_prop_2 int null comment 'int类型的trigger的第二个参数', + long_prop_1 bigint null comment 'long类型的trigger的第一个参数', + long_prop_2 bigint null comment 'long类型的trigger的第二个参数', + dec_prop_1 numeric(13,4) null comment 'decimal类型的trigger的第一个参数', + dec_prop_2 numeric(13,4) null comment 'decimal类型的trigger的第二个参数', + bool_prop_1 varchar(1) null comment 'Boolean类型的trigger的第一个参数', + bool_prop_2 varchar(1) null comment 'Boolean类型的trigger的第二个参数', + primary key (sched_name, trigger_name, trigger_group), + foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group) +) engine=innodb comment = '同步机制的行锁表'; + +commit; \ No newline at end of file diff --git a/sql/ry_20231130.sql b/sql/ry_20231130.sql new file mode 100644 index 0000000..b90fca2 --- /dev/null +++ b/sql/ry_20231130.sql @@ -0,0 +1,700 @@ +-- ---------------------------- +-- 1、部门表 +-- ---------------------------- +drop table if exists sys_dept; +create table sys_dept ( + dept_id bigint(20) not null auto_increment comment '部门id', + parent_id bigint(20) default 0 comment '父部门id', + ancestors varchar(50) default '' comment '祖级列表', + dept_name varchar(30) default '' comment '部门名称', + order_num int(4) default 0 comment '显示顺序', + leader varchar(20) default null comment '负责人', + phone varchar(11) default null comment '联系电话', + email varchar(50) default null comment '邮箱', + status char(1) default '0' comment '部门状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + primary key (dept_id) +) engine=innodb auto_increment=200 comment = '部门表'; + +-- ---------------------------- +-- 初始化-部门表数据 +-- ---------------------------- +insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); +insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null); + + +-- ---------------------------- +-- 2、用户信息表 +-- ---------------------------- +drop table if exists sys_user; +create table sys_user ( + user_id bigint(20) not null auto_increment comment '用户ID', + dept_id bigint(20) default null comment '部门ID', + user_name varchar(30) not null comment '用户账号', + nick_name varchar(30) not null comment '用户名称', + user_type varchar(2) default '00' comment '用户类型(00系统用户)', + email varchar(50) default '' comment '用户邮箱', + phonenumber varchar(11) default '' comment '手机号码', + sex char(1) default '0' comment '用户性别(0男 1女 2未知)', + avatar varchar(100) default '' comment '头像地址', + password varchar(100) default '' comment '密码', + status char(1) default '0' comment '帐号状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + login_ip varchar(128) default '' comment '最后登录IP', + login_date datetime comment '最后登录时间', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (user_id) +) engine=innodb auto_increment=100 comment = '用户信息表'; + +-- ---------------------------- +-- 初始化-用户信息表数据 +-- ---------------------------- +insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '管理员'); +insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员'); + + +-- ---------------------------- +-- 3、岗位信息表 +-- ---------------------------- +drop table if exists sys_post; +create table sys_post +( + post_id bigint(20) not null auto_increment comment '岗位ID', + post_code varchar(64) not null comment '岗位编码', + post_name varchar(50) not null comment '岗位名称', + post_sort int(4) not null comment '显示顺序', + status char(1) not null comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (post_id) +) engine=innodb comment = '岗位信息表'; + +-- ---------------------------- +-- 初始化-岗位信息表数据 +-- ---------------------------- +insert into sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', sysdate(), '', null, ''); +insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 4、角色信息表 +-- ---------------------------- +drop table if exists sys_role; +create table sys_role ( + role_id bigint(20) not null auto_increment comment '角色ID', + role_name varchar(30) not null comment '角色名称', + role_key varchar(100) not null comment '角色权限字符串', + role_sort int(4) not null comment '显示顺序', + data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示', + dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示', + status char(1) not null comment '角色状态(0正常 1停用)', + del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (role_id) +) engine=innodb auto_increment=100 comment = '角色信息表'; + +-- ---------------------------- +-- 初始化-角色信息表数据 +-- ---------------------------- +insert into sys_role values('1', '超级管理员', 'admin', 1, 1, 1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员'); +insert into sys_role values('2', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 'admin', sysdate(), '', null, '普通角色'); + + +-- ---------------------------- +-- 5、菜单权限表 +-- ---------------------------- +drop table if exists sys_menu; +create table sys_menu ( + menu_id bigint(20) not null auto_increment comment '菜单ID', + menu_name varchar(50) not null comment '菜单名称', + parent_id bigint(20) default 0 comment '父菜单ID', + order_num int(4) default 0 comment '显示顺序', + path varchar(200) default '' comment '路由地址', + component varchar(255) default null comment '组件路径', + query varchar(255) default null comment '路由参数', + is_frame int(1) default 1 comment '是否为外链(0是 1否)', + is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)', + menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)', + visible char(1) default 0 comment '菜单状态(0显示 1隐藏)', + status char(1) default 0 comment '菜单状态(0正常 1停用)', + perms varchar(100) default null comment '权限标识', + icon varchar(100) default '#' comment '菜单图标', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注', + primary key (menu_id) +) engine=innodb auto_increment=2000 comment = '菜单权限表'; + +-- ---------------------------- +-- 初始化-菜单信息表数据 +-- ---------------------------- +-- 一级菜单 +insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录'); +insert into sys_menu values('2', '系统监控', '0', '2', 'monitor', null, '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '3', 'tool', null, '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录'); +insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', null, '', 0, 0, 'M', '0', '0', '', 'guide', 'admin', sysdate(), '', null, '若依官网地址'); +-- 二级菜单 +insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', sysdate(), '', null, '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', sysdate(), '', null, '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', sysdate(), '', null, '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', sysdate(), '', null, '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', sysdate(), '', null, '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', sysdate(), '', null, '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', sysdate(), '', null, '在线用户菜单'); +insert into sys_menu values('110', '定时任务', '2', '2', 'job', 'monitor/job/index', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', sysdate(), '', null, '定时任务菜单'); +insert into sys_menu values('111', '数据监控', '2', '3', 'druid', 'monitor/druid/index', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', sysdate(), '', null, '数据监控菜单'); +insert into sys_menu values('112', '服务监控', '2', '4', 'server', 'monitor/server/index', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', sysdate(), '', null, '服务监控菜单'); +insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', sysdate(), '', null, '缓存监控菜单'); +insert into sys_menu values('114', '缓存列表', '2', '6', 'cacheList', 'monitor/cache/list', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', sysdate(), '', null, '缓存列表菜单'); +insert into sys_menu values('115', '表单构建', '3', '1', 'build', 'tool/build/index', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单'); +insert into sys_menu values('116', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单'); +insert into sys_menu values('117', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', sysdate(), '', null, '系统接口菜单'); +-- 三级菜单 +insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', sysdate(), '', null, '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', sysdate(), '', null, '登录日志菜单'); +-- 用户管理按钮 +insert into sys_menu values('1000', '用户查询', '100', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1001', '用户新增', '100', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1002', '用户修改', '100', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1003', '用户删除', '100', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1004', '用户导出', '100', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1005', '用户导入', '100', '6', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1006', '重置密码', '100', '7', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', sysdate(), '', null, ''); +-- 角色管理按钮 +insert into sys_menu values('1007', '角色查询', '101', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1008', '角色新增', '101', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1009', '角色修改', '101', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1010', '角色删除', '101', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1011', '角色导出', '101', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', sysdate(), '', null, ''); +-- 菜单管理按钮 +insert into sys_menu values('1012', '菜单查询', '102', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1013', '菜单新增', '102', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1014', '菜单修改', '102', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1015', '菜单删除', '102', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', sysdate(), '', null, ''); +-- 部门管理按钮 +insert into sys_menu values('1016', '部门查询', '103', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1017', '部门新增', '103', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1018', '部门修改', '103', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1019', '部门删除', '103', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', sysdate(), '', null, ''); +-- 岗位管理按钮 +insert into sys_menu values('1020', '岗位查询', '104', '1', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1021', '岗位新增', '104', '2', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1022', '岗位修改', '104', '3', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1023', '岗位删除', '104', '4', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1024', '岗位导出', '104', '5', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', sysdate(), '', null, ''); +-- 字典管理按钮 +insert into sys_menu values('1025', '字典查询', '105', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1026', '字典新增', '105', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1027', '字典修改', '105', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1028', '字典删除', '105', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1029', '字典导出', '105', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', sysdate(), '', null, ''); +-- 参数设置按钮 +insert into sys_menu values('1030', '参数查询', '106', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1031', '参数新增', '106', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1032', '参数修改', '106', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1033', '参数删除', '106', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1034', '参数导出', '106', '5', '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', sysdate(), '', null, ''); +-- 通知公告按钮 +insert into sys_menu values('1035', '公告查询', '107', '1', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1036', '公告新增', '107', '2', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1037', '公告修改', '107', '3', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1038', '公告删除', '107', '4', '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', sysdate(), '', null, ''); +-- 操作日志按钮 +insert into sys_menu values('1039', '操作查询', '500', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1040', '操作删除', '500', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1041', '日志导出', '500', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', sysdate(), '', null, ''); +-- 登录日志按钮 +insert into sys_menu values('1042', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1043', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1044', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1045', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', sysdate(), '', null, ''); +-- 在线用户按钮 +insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, ''); +-- 定时任务按钮 +insert into sys_menu values('1049', '任务查询', '110', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1050', '任务新增', '110', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1051', '任务修改', '110', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1052', '任务删除', '110', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1053', '状态修改', '110', '5', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1054', '任务导出', '110', '6', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', sysdate(), '', null, ''); +-- 代码生成按钮 +insert into sys_menu values('1055', '生成查询', '116', '1', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1056', '生成修改', '116', '2', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1057', '生成删除', '116', '3', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1058', '导入代码', '116', '4', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1059', '预览代码', '116', '5', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, ''); +insert into sys_menu values('1060', '生成代码', '116', '6', '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 6、用户和角色关联表 用户N-1角色 +-- ---------------------------- +drop table if exists sys_user_role; +create table sys_user_role ( + user_id bigint(20) not null comment '用户ID', + role_id bigint(20) not null comment '角色ID', + primary key(user_id, role_id) +) engine=innodb comment = '用户和角色关联表'; + +-- ---------------------------- +-- 初始化-用户和角色关联表数据 +-- ---------------------------- +insert into sys_user_role values ('1', '1'); +insert into sys_user_role values ('2', '2'); + + +-- ---------------------------- +-- 7、角色和菜单关联表 角色1-N菜单 +-- ---------------------------- +drop table if exists sys_role_menu; +create table sys_role_menu ( + role_id bigint(20) not null comment '角色ID', + menu_id bigint(20) not null comment '菜单ID', + primary key(role_id, menu_id) +) engine=innodb comment = '角色和菜单关联表'; + +-- ---------------------------- +-- 初始化-角色和菜单关联表数据 +-- ---------------------------- +insert into sys_role_menu values ('2', '1'); +insert into sys_role_menu values ('2', '2'); +insert into sys_role_menu values ('2', '3'); +insert into sys_role_menu values ('2', '4'); +insert into sys_role_menu values ('2', '100'); +insert into sys_role_menu values ('2', '101'); +insert into sys_role_menu values ('2', '102'); +insert into sys_role_menu values ('2', '103'); +insert into sys_role_menu values ('2', '104'); +insert into sys_role_menu values ('2', '105'); +insert into sys_role_menu values ('2', '106'); +insert into sys_role_menu values ('2', '107'); +insert into sys_role_menu values ('2', '108'); +insert into sys_role_menu values ('2', '109'); +insert into sys_role_menu values ('2', '110'); +insert into sys_role_menu values ('2', '111'); +insert into sys_role_menu values ('2', '112'); +insert into sys_role_menu values ('2', '113'); +insert into sys_role_menu values ('2', '114'); +insert into sys_role_menu values ('2', '115'); +insert into sys_role_menu values ('2', '116'); +insert into sys_role_menu values ('2', '117'); +insert into sys_role_menu values ('2', '500'); +insert into sys_role_menu values ('2', '501'); +insert into sys_role_menu values ('2', '1000'); +insert into sys_role_menu values ('2', '1001'); +insert into sys_role_menu values ('2', '1002'); +insert into sys_role_menu values ('2', '1003'); +insert into sys_role_menu values ('2', '1004'); +insert into sys_role_menu values ('2', '1005'); +insert into sys_role_menu values ('2', '1006'); +insert into sys_role_menu values ('2', '1007'); +insert into sys_role_menu values ('2', '1008'); +insert into sys_role_menu values ('2', '1009'); +insert into sys_role_menu values ('2', '1010'); +insert into sys_role_menu values ('2', '1011'); +insert into sys_role_menu values ('2', '1012'); +insert into sys_role_menu values ('2', '1013'); +insert into sys_role_menu values ('2', '1014'); +insert into sys_role_menu values ('2', '1015'); +insert into sys_role_menu values ('2', '1016'); +insert into sys_role_menu values ('2', '1017'); +insert into sys_role_menu values ('2', '1018'); +insert into sys_role_menu values ('2', '1019'); +insert into sys_role_menu values ('2', '1020'); +insert into sys_role_menu values ('2', '1021'); +insert into sys_role_menu values ('2', '1022'); +insert into sys_role_menu values ('2', '1023'); +insert into sys_role_menu values ('2', '1024'); +insert into sys_role_menu values ('2', '1025'); +insert into sys_role_menu values ('2', '1026'); +insert into sys_role_menu values ('2', '1027'); +insert into sys_role_menu values ('2', '1028'); +insert into sys_role_menu values ('2', '1029'); +insert into sys_role_menu values ('2', '1030'); +insert into sys_role_menu values ('2', '1031'); +insert into sys_role_menu values ('2', '1032'); +insert into sys_role_menu values ('2', '1033'); +insert into sys_role_menu values ('2', '1034'); +insert into sys_role_menu values ('2', '1035'); +insert into sys_role_menu values ('2', '1036'); +insert into sys_role_menu values ('2', '1037'); +insert into sys_role_menu values ('2', '1038'); +insert into sys_role_menu values ('2', '1039'); +insert into sys_role_menu values ('2', '1040'); +insert into sys_role_menu values ('2', '1041'); +insert into sys_role_menu values ('2', '1042'); +insert into sys_role_menu values ('2', '1043'); +insert into sys_role_menu values ('2', '1044'); +insert into sys_role_menu values ('2', '1045'); +insert into sys_role_menu values ('2', '1046'); +insert into sys_role_menu values ('2', '1047'); +insert into sys_role_menu values ('2', '1048'); +insert into sys_role_menu values ('2', '1049'); +insert into sys_role_menu values ('2', '1050'); +insert into sys_role_menu values ('2', '1051'); +insert into sys_role_menu values ('2', '1052'); +insert into sys_role_menu values ('2', '1053'); +insert into sys_role_menu values ('2', '1054'); +insert into sys_role_menu values ('2', '1055'); +insert into sys_role_menu values ('2', '1056'); +insert into sys_role_menu values ('2', '1057'); +insert into sys_role_menu values ('2', '1058'); +insert into sys_role_menu values ('2', '1059'); +insert into sys_role_menu values ('2', '1060'); + +-- ---------------------------- +-- 8、角色和部门关联表 角色1-N部门 +-- ---------------------------- +drop table if exists sys_role_dept; +create table sys_role_dept ( + role_id bigint(20) not null comment '角色ID', + dept_id bigint(20) not null comment '部门ID', + primary key(role_id, dept_id) +) engine=innodb comment = '角色和部门关联表'; + +-- ---------------------------- +-- 初始化-角色和部门关联表数据 +-- ---------------------------- +insert into sys_role_dept values ('2', '100'); +insert into sys_role_dept values ('2', '101'); +insert into sys_role_dept values ('2', '105'); + + +-- ---------------------------- +-- 9、用户与岗位关联表 用户1-N岗位 +-- ---------------------------- +drop table if exists sys_user_post; +create table sys_user_post +( + user_id bigint(20) not null comment '用户ID', + post_id bigint(20) not null comment '岗位ID', + primary key (user_id, post_id) +) engine=innodb comment = '用户与岗位关联表'; + +-- ---------------------------- +-- 初始化-用户与岗位关联表数据 +-- ---------------------------- +insert into sys_user_post values ('1', '1'); +insert into sys_user_post values ('2', '2'); + + +-- ---------------------------- +-- 10、操作日志记录 +-- ---------------------------- +drop table if exists sys_oper_log; +create table sys_oper_log ( + oper_id bigint(20) not null auto_increment comment '日志主键', + title varchar(50) default '' comment '模块标题', + business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)', + method varchar(100) default '' comment '方法名称', + request_method varchar(10) default '' comment '请求方式', + operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)', + oper_name varchar(50) default '' comment '操作人员', + dept_name varchar(50) default '' comment '部门名称', + oper_url varchar(255) default '' comment '请求URL', + oper_ip varchar(128) default '' comment '主机地址', + oper_location varchar(255) default '' comment '操作地点', + oper_param varchar(2000) default '' comment '请求参数', + json_result varchar(2000) default '' comment '返回参数', + status int(1) default 0 comment '操作状态(0正常 1异常)', + error_msg varchar(2000) default '' comment '错误消息', + oper_time datetime comment '操作时间', + cost_time bigint(20) default 0 comment '消耗时间', + primary key (oper_id), + key idx_sys_oper_log_bt (business_type), + key idx_sys_oper_log_s (status), + key idx_sys_oper_log_ot (oper_time) +) engine=innodb auto_increment=100 comment = '操作日志记录'; + + +-- ---------------------------- +-- 11、字典类型表 +-- ---------------------------- +drop table if exists sys_dict_type; +create table sys_dict_type +( + dict_id bigint(20) not null auto_increment comment '字典主键', + dict_name varchar(100) default '' comment '字典名称', + dict_type varchar(100) default '' comment '字典类型', + status char(1) default '0' comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_id), + unique (dict_type) +) engine=innodb auto_increment=100 comment = '字典类型表'; + +insert into sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', sysdate(), '', null, '用户性别列表'); +insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', sysdate(), '', null, '菜单状态列表'); +insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', sysdate(), '', null, '系统开关列表'); +insert into sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', sysdate(), '', null, '任务状态列表'); +insert into sys_dict_type values(5, '任务分组', 'sys_job_group', '0', 'admin', sysdate(), '', null, '任务分组列表'); +insert into sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', sysdate(), '', null, '系统是否列表'); +insert into sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', sysdate(), '', null, '通知类型列表'); +insert into sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', sysdate(), '', null, '通知状态列表'); +insert into sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', sysdate(), '', null, '操作类型列表'); +insert into sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', sysdate(), '', null, '登录状态列表'); + + +-- ---------------------------- +-- 12、字典数据表 +-- ---------------------------- +drop table if exists sys_dict_data; +create table sys_dict_data +( + dict_code bigint(20) not null auto_increment comment '字典编码', + dict_sort int(4) default 0 comment '字典排序', + dict_label varchar(100) default '' comment '字典标签', + dict_value varchar(100) default '' comment '字典键值', + dict_type varchar(100) default '' comment '字典类型', + css_class varchar(100) default null comment '样式属性(其他样式扩展)', + list_class varchar(100) default null comment '表格回显样式', + is_default char(1) default 'N' comment '是否默认(Y是 N否)', + status char(1) default '0' comment '状态(0正常 1停用)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (dict_code) +) engine=innodb auto_increment=100 comment = '字典数据表'; + +insert into sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', sysdate(), '', null, '性别男'); +insert into sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别女'); +insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别未知'); +insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单'); +insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '隐藏菜单'); +insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); +insert into sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); +insert into sys_dict_data values(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', sysdate(), '', null, '默认分组'); +insert into sys_dict_data values(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', sysdate(), '', null, '系统分组'); +insert into sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是'); +insert into sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '系统默认否'); +insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知'); +insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '公告'); +insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '关闭状态'); +insert into sys_dict_data values(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '其他操作'); +insert into sys_dict_data values(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '新增操作'); +insert into sys_dict_data values(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '修改操作'); +insert into sys_dict_data values(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '删除操作'); +insert into sys_dict_data values(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作'); +insert into sys_dict_data values(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作'); +insert into sys_dict_data values(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作'); +insert into sys_dict_data values(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '强退操作'); +insert into sys_dict_data values(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作'); +insert into sys_dict_data values(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '清空操作'); +insert into sys_dict_data values(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态'); +insert into sys_dict_data values(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态'); + + +-- ---------------------------- +-- 13、参数配置表 +-- ---------------------------- +drop table if exists sys_config; +create table sys_config ( + config_id int(5) not null auto_increment comment '参数主键', + config_name varchar(100) default '' comment '参数名称', + config_key varchar(100) default '' comment '参数键名', + config_value varchar(500) default '' comment '参数键值', + config_type char(1) default 'N' comment '系统内置(Y是 N否)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (config_id) +) engine=innodb auto_increment=100 comment = '参数配置表'; + +insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); +insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456' ); +insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)'); +insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)'); + + +-- ---------------------------- +-- 14、系统访问记录 +-- ---------------------------- +drop table if exists sys_logininfor; +create table sys_logininfor ( + info_id bigint(20) not null auto_increment comment '访问ID', + user_name varchar(50) default '' comment '用户账号', + ipaddr varchar(128) default '' comment '登录IP地址', + login_location varchar(255) default '' comment '登录地点', + browser varchar(50) default '' comment '浏览器类型', + os varchar(50) default '' comment '操作系统', + status char(1) default '0' comment '登录状态(0成功 1失败)', + msg varchar(255) default '' comment '提示消息', + login_time datetime comment '访问时间', + primary key (info_id), + key idx_sys_logininfor_s (status), + key idx_sys_logininfor_lt (login_time) +) engine=innodb auto_increment=100 comment = '系统访问记录'; + + +-- ---------------------------- +-- 15、定时任务调度表 +-- ---------------------------- +drop table if exists sys_job; +create table sys_job ( + job_id bigint(20) not null auto_increment comment '任务ID', + job_name varchar(64) default '' comment '任务名称', + job_group varchar(64) default 'DEFAULT' comment '任务组名', + invoke_target varchar(500) not null comment '调用目标字符串', + cron_expression varchar(255) default '' comment 'cron执行表达式', + misfire_policy varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + concurrent char(1) default '1' comment '是否并发执行(0允许 1禁止)', + status char(1) default '0' comment '状态(0正常 1暂停)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default '' comment '备注信息', + primary key (job_id, job_name, job_group) +) engine=innodb auto_increment=100 comment = '定时任务调度表'; + +insert into sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, ''); +insert into sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, ''); +insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, ''); + + +-- ---------------------------- +-- 16、定时任务调度日志表 +-- ---------------------------- +drop table if exists sys_job_log; +create table sys_job_log ( + job_log_id bigint(20) not null auto_increment comment '任务日志ID', + job_name varchar(64) not null comment '任务名称', + job_group varchar(64) not null comment '任务组名', + invoke_target varchar(500) not null comment '调用目标字符串', + job_message varchar(500) comment '日志信息', + status char(1) default '0' comment '执行状态(0正常 1失败)', + exception_info varchar(2000) default '' comment '异常信息', + create_time datetime comment '创建时间', + primary key (job_log_id) +) engine=innodb comment = '定时任务调度日志表'; + + +-- ---------------------------- +-- 17、通知公告表 +-- ---------------------------- +drop table if exists sys_notice; +create table sys_notice ( + notice_id int(4) not null auto_increment comment '公告ID', + notice_title varchar(50) not null comment '公告标题', + notice_type char(1) not null comment '公告类型(1通知 2公告)', + notice_content longblob default null comment '公告内容', + status char(1) default '0' comment '公告状态(0正常 1关闭)', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(255) default null comment '备注', + primary key (notice_id) +) engine=innodb auto_increment=10 comment = '通知公告表'; + +-- ---------------------------- +-- 初始化-公告信息表数据 +-- ---------------------------- +insert into sys_notice values('1', '温馨提醒:2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员'); +insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', sysdate(), '', null, '管理员'); + + +-- ---------------------------- +-- 18、代码生成业务表 +-- ---------------------------- +drop table if exists gen_table; +create table gen_table ( + table_id bigint(20) not null auto_increment comment '编号', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + tpl_web_type varchar(30) default '' comment '前端模板类型(element-ui模版 element-plus模版)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', + primary key (table_id) +) engine=innodb auto_increment=1 comment = '代码生成业务表'; + + +-- ---------------------------- +-- 19、代码生成业务表字段 +-- ---------------------------- +drop table if exists gen_table_column; +create table gen_table_column ( + column_id bigint(20) not null auto_increment comment '编号', + table_id bigint(20) comment '归属表编号', + column_name varchar(200) comment '列名称', + column_comment varchar(500) comment '列描述', + column_type varchar(100) comment '列类型', + java_type varchar(500) comment 'JAVA类型', + java_field varchar(200) comment 'JAVA字段名', + is_pk char(1) comment '是否主键(1是)', + is_increment char(1) comment '是否自增(1是)', + is_required char(1) comment '是否必填(1是)', + is_insert char(1) comment '是否为插入字段(1是)', + is_edit char(1) comment '是否编辑字段(1是)', + is_list char(1) comment '是否列表字段(1是)', + is_query char(1) comment '是否查询字段(1是)', + query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)', + html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + dict_type varchar(200) default '' comment '字典类型', + sort int comment '排序', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + primary key (column_id) +) engine=innodb auto_increment=1 comment = '代码生成业务表字段'; diff --git a/sql/tony-flowable.sql b/sql/tony-flowable.sql new file mode 100644 index 0000000..52ec11a --- /dev/null +++ b/sql/tony-flowable.sql @@ -0,0 +1,3637 @@ +/* + navicat premium data transfer + + source server : localhost + source server type : mysql + source server version : 50731 (5.7.31) + source host : localhost:3306 + source schema : tony-flowable + + target server type : mysql + target server version : 50731 (5.7.31) + file encoding : 65001 + + date: 28/12/2022 16:39:00 +*/ + +set names utf8mb4; +set foreign_key_checks = 0; + +-- ---------------------------- +-- table structure for act_app_appdef +-- ---------------------------- +drop table if exists `act_app_appdef`; +create table `act_app_appdef` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `name_` varchar(255) default null, + `key_` varchar(255) not null, + `version_` int(11) not null, + `category_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_name_` varchar(4000) default null, + `description_` varchar(4000) default null, + `tenant_id_` varchar(255) default '', + primary key (`id_`), + unique key `act_idx_app_def_uniq` (`key_`,`version_`,`tenant_id_`), + key `act_idx_app_def_dply` (`deployment_id_`), + constraint `act_fk_app_def_dply` foreign key (`deployment_id_`) references `act_app_deployment` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_app_appdef +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_app_databasechangelog +-- ---------------------------- +drop table if exists `act_app_databasechangelog`; +create table `act_app_databasechangelog` ( + `id` varchar(255) not null, + `author` varchar(255) not null, + `filename` varchar(255) not null, + `dateexecuted` datetime not null, + `orderexecuted` int(11) not null, + `exectype` varchar(10) not null, + `md5sum` varchar(35) default null, + `description` varchar(255) default null, + `comments` varchar(255) default null, + `tag` varchar(255) default null, + `liquibase` varchar(20) default null, + `contexts` varchar(255) default null, + `labels` varchar(255) default null, + `deployment_id` varchar(10) default null +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_app_databasechangelog +-- ---------------------------- +begin; +insert into `act_app_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('1', 'flowable', 'org/flowable/app/db/liquibase/flowable-app-db-changelog.xml', '2023-09-14 11:05:29', 1, 'executed', '8:496fc778bdf2ab13f2e1926d0e63e0a2', 'createtable tablename=act_app_deployment; createtable tablename=act_app_deployment_resource; addforeignkeyconstraint basetablename=act_app_deployment_resource, constraintname=act_fk_app_rsrc_dpl, referencedtablename=act_app_deployment; createindex...', '', null, '4.3.5', null, null, '4660729443'); +insert into `act_app_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('2', 'flowable', 'org/flowable/app/db/liquibase/flowable-app-db-changelog.xml', '2023-09-14 11:05:29', 2, 'executed', '8:ccea9ebfb6c1f8367ca4dd473fcbb7db', 'modifydatatype columnname=deploy_time_, tablename=act_app_deployment', '', null, '4.3.5', null, null, '4660729443'); +insert into `act_app_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('3', 'flowable', 'org/flowable/app/db/liquibase/flowable-app-db-changelog.xml', '2023-09-14 11:05:29', 3, 'executed', '8:f1f8aff320aade831944ebad24355f3d', 'createindex indexname=act_idx_app_def_uniq, tablename=act_app_appdef', '', null, '4.3.5', null, null, '4660729443'); +commit; + +-- ---------------------------- +-- table structure for act_app_databasechangeloglock +-- ---------------------------- +drop table if exists `act_app_databasechangeloglock`; +create table `act_app_databasechangeloglock` ( + `id` int(11) not null, + `locked` bit(1) not null, + `lockgranted` datetime default null, + `lockedby` varchar(255) default null, + primary key (`id`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_app_databasechangeloglock +-- ---------------------------- +begin; +insert into `act_app_databasechangeloglock` (`id`, `locked`, `lockgranted`, `lockedby`) values (1, b'0', null, null); +commit; + +-- ---------------------------- +-- table structure for act_app_deployment +-- ---------------------------- +drop table if exists `act_app_deployment`; +create table `act_app_deployment` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `category_` varchar(255) default null, + `key_` varchar(255) default null, + `deploy_time_` datetime(3) default null, + `tenant_id_` varchar(255) default '', + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_app_deployment +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_app_deployment_resource +-- ---------------------------- +drop table if exists `act_app_deployment_resource`; +create table `act_app_deployment_resource` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_bytes_` longblob, + primary key (`id_`), + key `act_idx_app_rsrc_dpl` (`deployment_id_`), + constraint `act_fk_app_rsrc_dpl` foreign key (`deployment_id_`) references `act_app_deployment` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_app_deployment_resource +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_casedef +-- ---------------------------- +drop table if exists `act_cmmn_casedef`; +create table `act_cmmn_casedef` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `name_` varchar(255) default null, + `key_` varchar(255) not null, + `version_` int(11) not null, + `category_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_name_` varchar(4000) default null, + `description_` varchar(4000) default null, + `has_graphical_notation_` bit(1) default null, + `tenant_id_` varchar(255) default '', + `dgrm_resource_name_` varchar(4000) default null, + `has_start_form_key_` bit(1) default null, + primary key (`id_`), + unique key `act_idx_case_def_uniq` (`key_`,`version_`,`tenant_id_`), + key `act_idx_case_def_dply` (`deployment_id_`), + constraint `act_fk_case_def_dply` foreign key (`deployment_id_`) references `act_cmmn_deployment` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_casedef +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_databasechangelog +-- ---------------------------- +drop table if exists `act_cmmn_databasechangelog`; +create table `act_cmmn_databasechangelog` ( + `id` varchar(255) not null, + `author` varchar(255) not null, + `filename` varchar(255) not null, + `dateexecuted` datetime not null, + `orderexecuted` int(11) not null, + `exectype` varchar(10) not null, + `md5sum` varchar(35) default null, + `description` varchar(255) default null, + `comments` varchar(255) default null, + `tag` varchar(255) default null, + `liquibase` varchar(20) default null, + `contexts` varchar(255) default null, + `labels` varchar(255) default null, + `deployment_id` varchar(10) default null +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_databasechangelog +-- ---------------------------- +begin; +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('1', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:27', 1, 'executed', '8:8b4b922d90b05ff27483abefc9597aa6', 'createtable tablename=act_cmmn_deployment; createtable tablename=act_cmmn_deployment_resource; addforeignkeyconstraint basetablename=act_cmmn_deployment_resource, constraintname=act_fk_cmmn_rsrc_dpl, referencedtablename=act_cmmn_deployment; create...', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('2', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 2, 'executed', '8:65e39b3d385706bb261cbeffe7533cbe', 'addcolumn tablename=act_cmmn_casedef; addcolumn tablename=act_cmmn_deployment_resource; addcolumn tablename=act_cmmn_ru_case_inst; addcolumn tablename=act_cmmn_ru_plan_item_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('3', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 3, 'executed', '8:c01f6e802b49436b4489040da3012359', 'addcolumn tablename=act_cmmn_ru_plan_item_inst; addcolumn tablename=act_cmmn_ru_case_inst; createindex indexname=act_idx_plan_item_stage_inst, tablename=act_cmmn_ru_plan_item_inst; addcolumn tablename=act_cmmn_ru_plan_item_inst; addcolumn tablenam...', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('4', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 4, 'executed', '8:e40d29cb79345b7fb5afd38a7f0ba8fc', 'createtable tablename=act_cmmn_hi_plan_item_inst; addcolumn tablename=act_cmmn_ru_mil_inst; addcolumn tablename=act_cmmn_hi_mil_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('5', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 5, 'executed', '8:70349de472f87368dcdec971a10311a0', 'modifydatatype columnname=deploy_time_, tablename=act_cmmn_deployment; modifydatatype columnname=start_time_, tablename=act_cmmn_ru_case_inst; modifydatatype columnname=start_time_, tablename=act_cmmn_ru_plan_item_inst; modifydatatype columnname=t...', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('6', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 6, 'executed', '8:10e82e26a7fee94c32a92099c059c18c', 'createindex indexname=act_idx_case_def_uniq, tablename=act_cmmn_casedef', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('7', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 7, 'executed', '8:530bc81a1e30618ccf4a2da1f7c6c043', 'renamecolumn newcolumnname=create_time_, oldcolumnname=start_time_, tablename=act_cmmn_ru_plan_item_inst; renamecolumn newcolumnname=create_time_, oldcolumnname=created_time_, tablename=act_cmmn_hi_plan_item_inst; addcolumn tablename=act_cmmn_ru_p...', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('8', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 8, 'executed', '8:e8c2eb1ce28bc301efe07e0e29757781', 'addcolumn tablename=act_cmmn_hi_plan_item_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('9', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 9, 'executed', '8:4cb4782b9bdec5ced2a64c525aa7b3a0', 'addcolumn tablename=act_cmmn_ru_plan_item_inst; addcolumn tablename=act_cmmn_hi_plan_item_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('10', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 10, 'executed', '8:341c16be247f5d17badc9809da8691f9', 'addcolumn tablename=act_cmmn_ru_case_inst; addcolumn tablename=act_cmmn_ru_case_inst; createindex indexname=act_idx_case_inst_ref_id_, tablename=act_cmmn_ru_case_inst; addcolumn tablename=act_cmmn_hi_case_inst; addcolumn tablename=act_cmmn_hi_case...', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('11', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 11, 'executed', '8:d7c4da9276bcfffbfb0ebfb25e3f7b05', 'addcolumn tablename=act_cmmn_ru_plan_item_inst; addcolumn tablename=act_cmmn_hi_plan_item_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('12', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 12, 'executed', '8:adf4ecc45f2aa9a44a5626b02e1d6f98', 'addcolumn tablename=act_cmmn_ru_case_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('13', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 13, 'executed', '8:7550626f964ab5518464709408333ec1', 'addcolumn tablename=act_cmmn_ru_plan_item_inst; addcolumn tablename=act_cmmn_hi_plan_item_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('14', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 14, 'executed', '8:086b40b3a05596dcc8a8d7479922d494', 'addcolumn tablename=act_cmmn_ru_case_inst; addcolumn tablename=act_cmmn_hi_case_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('16', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 15, 'executed', '8:a697a222ddd99dd15b36516a252f1c63', 'addcolumn tablename=act_cmmn_ru_case_inst; addcolumn tablename=act_cmmn_hi_case_inst', '', null, '4.3.5', null, null, '4660727511'); +insert into `act_cmmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('17', 'flowable', 'org/flowable/cmmn/db/liquibase/flowable-cmmn-db-changelog.xml', '2023-09-14 11:05:28', 16, 'executed', '8:d3706c5813a9b97fd2a59d12a9523946', 'createindex indexname=act_idx_hi_case_inst_end, tablename=act_cmmn_hi_case_inst', '', null, '4.3.5', null, null, '4660727511'); +commit; + +-- ---------------------------- +-- table structure for act_cmmn_databasechangeloglock +-- ---------------------------- +drop table if exists `act_cmmn_databasechangeloglock`; +create table `act_cmmn_databasechangeloglock` ( + `id` int(11) not null, + `locked` bit(1) not null, + `lockgranted` datetime default null, + `lockedby` varchar(255) default null, + primary key (`id`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_databasechangeloglock +-- ---------------------------- +begin; +insert into `act_cmmn_databasechangeloglock` (`id`, `locked`, `lockgranted`, `lockedby`) values (1, b'0', null, null); +commit; + +-- ---------------------------- +-- table structure for act_cmmn_deployment +-- ---------------------------- +drop table if exists `act_cmmn_deployment`; +create table `act_cmmn_deployment` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `category_` varchar(255) default null, + `key_` varchar(255) default null, + `deploy_time_` datetime(3) default null, + `parent_deployment_id_` varchar(255) default null, + `tenant_id_` varchar(255) default '', + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_deployment +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_deployment_resource +-- ---------------------------- +drop table if exists `act_cmmn_deployment_resource`; +create table `act_cmmn_deployment_resource` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_bytes_` longblob, + `generated_` bit(1) default null, + primary key (`id_`), + key `act_idx_cmmn_rsrc_dpl` (`deployment_id_`), + constraint `act_fk_cmmn_rsrc_dpl` foreign key (`deployment_id_`) references `act_cmmn_deployment` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_deployment_resource +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_hi_case_inst +-- ---------------------------- +drop table if exists `act_cmmn_hi_case_inst`; +create table `act_cmmn_hi_case_inst` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `business_key_` varchar(255) default null, + `name_` varchar(255) default null, + `parent_id_` varchar(255) default null, + `case_def_id_` varchar(255) default null, + `state_` varchar(255) default null, + `start_time_` datetime(3) default null, + `end_time_` datetime(3) default null, + `start_user_id_` varchar(255) default null, + `callback_id_` varchar(255) default null, + `callback_type_` varchar(255) default null, + `tenant_id_` varchar(255) default '', + `reference_id_` varchar(255) default null, + `reference_type_` varchar(255) default null, + `last_reactivation_time_` datetime(3) default null, + `last_reactivation_user_id_` varchar(255) default null, + `business_status_` varchar(255) default null, + primary key (`id_`), + key `act_idx_hi_case_inst_end` (`end_time_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_hi_case_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_hi_mil_inst +-- ---------------------------- +drop table if exists `act_cmmn_hi_mil_inst`; +create table `act_cmmn_hi_mil_inst` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `name_` varchar(255) not null, + `time_stamp_` datetime(3) default null, + `case_inst_id_` varchar(255) not null, + `case_def_id_` varchar(255) not null, + `element_id_` varchar(255) not null, + `tenant_id_` varchar(255) default '', + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_hi_mil_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_hi_plan_item_inst +-- ---------------------------- +drop table if exists `act_cmmn_hi_plan_item_inst`; +create table `act_cmmn_hi_plan_item_inst` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `name_` varchar(255) default null, + `state_` varchar(255) default null, + `case_def_id_` varchar(255) default null, + `case_inst_id_` varchar(255) default null, + `stage_inst_id_` varchar(255) default null, + `is_stage_` bit(1) default null, + `element_id_` varchar(255) default null, + `item_definition_id_` varchar(255) default null, + `item_definition_type_` varchar(255) default null, + `create_time_` datetime(3) default null, + `last_available_time_` datetime(3) default null, + `last_enabled_time_` datetime(3) default null, + `last_disabled_time_` datetime(3) default null, + `last_started_time_` datetime(3) default null, + `last_suspended_time_` datetime(3) default null, + `completed_time_` datetime(3) default null, + `occurred_time_` datetime(3) default null, + `terminated_time_` datetime(3) default null, + `exit_time_` datetime(3) default null, + `ended_time_` datetime(3) default null, + `last_updated_time_` datetime(3) default null, + `start_user_id_` varchar(255) default null, + `reference_id_` varchar(255) default null, + `reference_type_` varchar(255) default null, + `tenant_id_` varchar(255) default '', + `entry_criterion_id_` varchar(255) default null, + `exit_criterion_id_` varchar(255) default null, + `show_in_overview_` bit(1) default null, + `extra_value_` varchar(255) default null, + `derived_case_def_id_` varchar(255) default null, + `last_unavailable_time_` datetime(3) default null, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_hi_plan_item_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_ru_case_inst +-- ---------------------------- +drop table if exists `act_cmmn_ru_case_inst`; +create table `act_cmmn_ru_case_inst` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `business_key_` varchar(255) default null, + `name_` varchar(255) default null, + `parent_id_` varchar(255) default null, + `case_def_id_` varchar(255) default null, + `state_` varchar(255) default null, + `start_time_` datetime(3) default null, + `start_user_id_` varchar(255) default null, + `callback_id_` varchar(255) default null, + `callback_type_` varchar(255) default null, + `tenant_id_` varchar(255) default '', + `lock_time_` datetime(3) default null, + `is_completeable_` bit(1) default null, + `reference_id_` varchar(255) default null, + `reference_type_` varchar(255) default null, + `lock_owner_` varchar(255) default null, + `last_reactivation_time_` datetime(3) default null, + `last_reactivation_user_id_` varchar(255) default null, + `business_status_` varchar(255) default null, + primary key (`id_`), + key `act_idx_case_inst_case_def` (`case_def_id_`), + key `act_idx_case_inst_parent` (`parent_id_`), + key `act_idx_case_inst_ref_id_` (`reference_id_`), + constraint `act_fk_case_inst_case_def` foreign key (`case_def_id_`) references `act_cmmn_casedef` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_ru_case_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_ru_mil_inst +-- ---------------------------- +drop table if exists `act_cmmn_ru_mil_inst`; +create table `act_cmmn_ru_mil_inst` ( + `id_` varchar(255) not null, + `name_` varchar(255) not null, + `time_stamp_` datetime(3) default null, + `case_inst_id_` varchar(255) not null, + `case_def_id_` varchar(255) not null, + `element_id_` varchar(255) not null, + `tenant_id_` varchar(255) default '', + primary key (`id_`), + key `act_idx_mil_case_def` (`case_def_id_`), + key `act_idx_mil_case_inst` (`case_inst_id_`), + constraint `act_fk_mil_case_def` foreign key (`case_def_id_`) references `act_cmmn_casedef` (`id_`), + constraint `act_fk_mil_case_inst` foreign key (`case_inst_id_`) references `act_cmmn_ru_case_inst` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_ru_mil_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_ru_plan_item_inst +-- ---------------------------- +drop table if exists `act_cmmn_ru_plan_item_inst`; +create table `act_cmmn_ru_plan_item_inst` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `case_def_id_` varchar(255) default null, + `case_inst_id_` varchar(255) default null, + `stage_inst_id_` varchar(255) default null, + `is_stage_` bit(1) default null, + `element_id_` varchar(255) default null, + `name_` varchar(255) default null, + `state_` varchar(255) default null, + `create_time_` datetime(3) default null, + `start_user_id_` varchar(255) default null, + `reference_id_` varchar(255) default null, + `reference_type_` varchar(255) default null, + `tenant_id_` varchar(255) default '', + `item_definition_id_` varchar(255) default null, + `item_definition_type_` varchar(255) default null, + `is_completeable_` bit(1) default null, + `is_count_enabled_` bit(1) default null, + `var_count_` int(11) default null, + `sentry_part_inst_count_` int(11) default null, + `last_available_time_` datetime(3) default null, + `last_enabled_time_` datetime(3) default null, + `last_disabled_time_` datetime(3) default null, + `last_started_time_` datetime(3) default null, + `last_suspended_time_` datetime(3) default null, + `completed_time_` datetime(3) default null, + `occurred_time_` datetime(3) default null, + `terminated_time_` datetime(3) default null, + `exit_time_` datetime(3) default null, + `ended_time_` datetime(3) default null, + `entry_criterion_id_` varchar(255) default null, + `exit_criterion_id_` varchar(255) default null, + `extra_value_` varchar(255) default null, + `derived_case_def_id_` varchar(255) default null, + `last_unavailable_time_` datetime(3) default null, + primary key (`id_`), + key `act_idx_plan_item_case_def` (`case_def_id_`), + key `act_idx_plan_item_case_inst` (`case_inst_id_`), + key `act_idx_plan_item_stage_inst` (`stage_inst_id_`), + constraint `act_fk_plan_item_case_def` foreign key (`case_def_id_`) references `act_cmmn_casedef` (`id_`), + constraint `act_fk_plan_item_case_inst` foreign key (`case_inst_id_`) references `act_cmmn_ru_case_inst` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_ru_plan_item_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_cmmn_ru_sentry_part_inst +-- ---------------------------- +drop table if exists `act_cmmn_ru_sentry_part_inst`; +create table `act_cmmn_ru_sentry_part_inst` ( + `id_` varchar(255) not null, + `rev_` int(11) not null, + `case_def_id_` varchar(255) default null, + `case_inst_id_` varchar(255) default null, + `plan_item_inst_id_` varchar(255) default null, + `on_part_id_` varchar(255) default null, + `if_part_id_` varchar(255) default null, + `time_stamp_` datetime(3) default null, + primary key (`id_`), + key `act_idx_sentry_case_def` (`case_def_id_`), + key `act_idx_sentry_case_inst` (`case_inst_id_`), + key `act_idx_sentry_plan_item` (`plan_item_inst_id_`), + constraint `act_fk_sentry_case_def` foreign key (`case_def_id_`) references `act_cmmn_casedef` (`id_`), + constraint `act_fk_sentry_case_inst` foreign key (`case_inst_id_`) references `act_cmmn_ru_case_inst` (`id_`), + constraint `act_fk_sentry_plan_item` foreign key (`plan_item_inst_id_`) references `act_cmmn_ru_plan_item_inst` (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_cmmn_ru_sentry_part_inst +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_co_content_item +-- ---------------------------- +drop table if exists `act_co_content_item`; +create table `act_co_content_item` ( + `id_` varchar(255) not null, + `name_` varchar(255) not null, + `mime_type_` varchar(255) default null, + `task_id_` varchar(255) default null, + `proc_inst_id_` varchar(255) default null, + `content_store_id_` varchar(255) default null, + `content_store_name_` varchar(255) default null, + `field_` varchar(400) default null, + `content_available_` bit(1) default b'0', + `created_` timestamp(6) null default null, + `created_by_` varchar(255) default null, + `last_modified_` timestamp(6) null default null, + `last_modified_by_` varchar(255) default null, + `content_size_` bigint(20) default '0', + `tenant_id_` varchar(255) default null, + `scope_id_` varchar(255) default null, + `scope_type_` varchar(255) default null, + primary key (`id_`), + key `idx_contitem_taskid` (`task_id_`), + key `idx_contitem_procid` (`proc_inst_id_`), + key `idx_contitem_scope` (`scope_id_`,`scope_type_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_co_content_item +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_co_databasechangelog +-- ---------------------------- +drop table if exists `act_co_databasechangelog`; +create table `act_co_databasechangelog` ( + `id` varchar(255) not null, + `author` varchar(255) not null, + `filename` varchar(255) not null, + `dateexecuted` datetime not null, + `orderexecuted` int(11) not null, + `exectype` varchar(10) not null, + `md5sum` varchar(35) default null, + `description` varchar(255) default null, + `comments` varchar(255) default null, + `tag` varchar(255) default null, + `liquibase` varchar(20) default null, + `contexts` varchar(255) default null, + `labels` varchar(255) default null, + `deployment_id` varchar(10) default null +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_co_databasechangelog +-- ---------------------------- +begin; +insert into `act_co_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('1', 'activiti', 'org/flowable/content/db/liquibase/flowable-content-db-changelog.xml', '2023-09-14 11:05:26', 1, 'executed', '8:7644d7165cfe799200a2abdd3419e8b6', 'createtable tablename=act_co_content_item; createindex indexname=idx_contitem_taskid, tablename=act_co_content_item; createindex indexname=idx_contitem_procid, tablename=act_co_content_item', '', null, '4.3.5', null, null, '4660726300'); +insert into `act_co_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('2', 'flowable', 'org/flowable/content/db/liquibase/flowable-content-db-changelog.xml', '2023-09-14 11:05:26', 2, 'executed', '8:fe7b11ac7dbbf9c43006b23bbab60bab', 'addcolumn tablename=act_co_content_item; createindex indexname=idx_contitem_scope, tablename=act_co_content_item', '', null, '4.3.5', null, null, '4660726300'); +commit; + +-- ---------------------------- +-- table structure for act_co_databasechangeloglock +-- ---------------------------- +drop table if exists `act_co_databasechangeloglock`; +create table `act_co_databasechangeloglock` ( + `id` int(11) not null, + `locked` bit(1) not null, + `lockgranted` datetime default null, + `lockedby` varchar(255) default null, + primary key (`id`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_co_databasechangeloglock +-- ---------------------------- +begin; +insert into `act_co_databasechangeloglock` (`id`, `locked`, `lockgranted`, `lockedby`) values (1, b'0', null, null); +commit; + +-- ---------------------------- +-- table structure for act_dmn_databasechangelog +-- ---------------------------- +drop table if exists `act_dmn_databasechangelog`; +create table `act_dmn_databasechangelog` ( + `id` varchar(255) not null, + `author` varchar(255) not null, + `filename` varchar(255) not null, + `dateexecuted` datetime not null, + `orderexecuted` int(11) not null, + `exectype` varchar(10) not null, + `md5sum` varchar(35) default null, + `description` varchar(255) default null, + `comments` varchar(255) default null, + `tag` varchar(255) default null, + `liquibase` varchar(20) default null, + `contexts` varchar(255) default null, + `labels` varchar(255) default null, + `deployment_id` varchar(10) default null +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_dmn_databasechangelog +-- ---------------------------- +begin; +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('1', 'activiti', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 1, 'executed', '8:c8701f1c71018b55029f450b2e9a10a1', 'createtable tablename=act_dmn_deployment; createtable tablename=act_dmn_deployment_resource; createtable tablename=act_dmn_decision_table', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('2', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 2, 'executed', '8:47f94b27feb7df8a30d4e338c7bd5fb8', 'createtable tablename=act_dmn_hi_decision_execution', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('3', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 3, 'executed', '8:ac17eae89fbdccb6e08daf3c7797b579', 'addcolumn tablename=act_dmn_hi_decision_execution', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('4', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 4, 'executed', '8:f73aabc4529e7292c2942073d1cff6f9', 'dropcolumn columnname=parent_deployment_id_, tablename=act_dmn_decision_table', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('5', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 5, 'executed', '8:3e03528582dd4eeb4eb41f9b9539140d', 'modifydatatype columnname=deploy_time_, tablename=act_dmn_deployment; modifydatatype columnname=start_time_, tablename=act_dmn_hi_decision_execution; modifydatatype columnname=end_time_, tablename=act_dmn_hi_decision_execution', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('6', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 6, 'executed', '8:646c6a061e0b6e8a62e69844ff96abb0', 'createindex indexname=act_idx_dec_tbl_uniq, tablename=act_dmn_decision_table', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('7', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 7, 'executed', '8:215a499ff7ae77685b55355245b8b708', 'dropindex indexname=act_idx_dec_tbl_uniq, tablename=act_dmn_decision_table; renametable newtablename=act_dmn_decision, oldtablename=act_dmn_decision_table; createindex indexname=act_idx_dmn_dec_uniq, tablename=act_dmn_decision', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('8', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 8, 'executed', '8:5355bee389318afed91a11702f2df032', 'addcolumn tablename=act_dmn_decision', '', null, '4.3.5', null, null, '4660725322'); +insert into `act_dmn_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('9', 'flowable', 'org/flowable/dmn/db/liquibase/flowable-dmn-db-changelog.xml', '2023-09-14 11:05:25', 9, 'executed', '8:0fe82086431b1953d293f0199f805876', 'createindex indexname=act_idx_dmn_instance_id, tablename=act_dmn_hi_decision_execution', '', null, '4.3.5', null, null, '4660725322'); +commit; + +-- ---------------------------- +-- table structure for act_dmn_databasechangeloglock +-- ---------------------------- +drop table if exists `act_dmn_databasechangeloglock`; +create table `act_dmn_databasechangeloglock` ( + `id` int(11) not null, + `locked` bit(1) not null, + `lockgranted` datetime default null, + `lockedby` varchar(255) default null, + primary key (`id`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_dmn_databasechangeloglock +-- ---------------------------- +begin; +insert into `act_dmn_databasechangeloglock` (`id`, `locked`, `lockgranted`, `lockedby`) values (1, b'0', null, null); +commit; + +-- ---------------------------- +-- table structure for act_dmn_decision +-- ---------------------------- +drop table if exists `act_dmn_decision`; +create table `act_dmn_decision` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `version_` int(11) default null, + `key_` varchar(255) default null, + `category_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `tenant_id_` varchar(255) default null, + `resource_name_` varchar(255) default null, + `description_` varchar(255) default null, + `decision_type_` varchar(255) default null, + primary key (`id_`), + unique key `act_idx_dmn_dec_uniq` (`key_`,`version_`,`tenant_id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_dmn_decision +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_dmn_deployment +-- ---------------------------- +drop table if exists `act_dmn_deployment`; +create table `act_dmn_deployment` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `category_` varchar(255) default null, + `deploy_time_` datetime(3) default null, + `tenant_id_` varchar(255) default null, + `parent_deployment_id_` varchar(255) default null, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_dmn_deployment +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_dmn_deployment_resource +-- ---------------------------- +drop table if exists `act_dmn_deployment_resource`; +create table `act_dmn_deployment_resource` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_bytes_` longblob, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_dmn_deployment_resource +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_dmn_hi_decision_execution +-- ---------------------------- +drop table if exists `act_dmn_hi_decision_execution`; +create table `act_dmn_hi_decision_execution` ( + `id_` varchar(255) not null, + `decision_definition_id_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `start_time_` datetime(3) default null, + `end_time_` datetime(3) default null, + `instance_id_` varchar(255) default null, + `execution_id_` varchar(255) default null, + `activity_id_` varchar(255) default null, + `failed_` bit(1) default b'0', + `tenant_id_` varchar(255) default null, + `execution_json_` longtext, + `scope_type_` varchar(255) default null, + primary key (`id_`), + key `act_idx_dmn_instance_id` (`instance_id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_dmn_hi_decision_execution +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_evt_log +-- ---------------------------- +drop table if exists `act_evt_log`; +create table `act_evt_log` ( + `log_nr_` bigint(20) not null auto_increment, + `type_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `time_stamp_` timestamp(3) not null default current_timestamp(3), + `user_id_` varchar(255) collate utf8_bin default null, + `data_` longblob, + `lock_owner_` varchar(255) collate utf8_bin default null, + `lock_time_` timestamp(3) null default null, + `is_processed_` tinyint(4) default '0', + primary key (`log_nr_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_evt_log +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_fo_databasechangelog +-- ---------------------------- +drop table if exists `act_fo_databasechangelog`; +create table `act_fo_databasechangelog` ( + `id` varchar(255) not null, + `author` varchar(255) not null, + `filename` varchar(255) not null, + `dateexecuted` datetime not null, + `orderexecuted` int(11) not null, + `exectype` varchar(10) not null, + `md5sum` varchar(35) default null, + `description` varchar(255) default null, + `comments` varchar(255) default null, + `tag` varchar(255) default null, + `liquibase` varchar(20) default null, + `contexts` varchar(255) default null, + `labels` varchar(255) default null, + `deployment_id` varchar(10) default null +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_fo_databasechangelog +-- ---------------------------- +begin; +insert into `act_fo_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('1', 'activiti', 'org/flowable/form/db/liquibase/flowable-form-db-changelog.xml', '2023-09-14 11:05:25', 1, 'executed', '8:033ebf9380889aed7c453927ecc3250d', 'createtable tablename=act_fo_form_deployment; createtable tablename=act_fo_form_resource; createtable tablename=act_fo_form_definition; createtable tablename=act_fo_form_instance', '', null, '4.3.5', null, null, '4660725875'); +insert into `act_fo_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('2', 'flowable', 'org/flowable/form/db/liquibase/flowable-form-db-changelog.xml', '2023-09-14 11:05:25', 2, 'executed', '8:986365ceb40445ce3b27a8e6b40f159b', 'addcolumn tablename=act_fo_form_instance', '', null, '4.3.5', null, null, '4660725875'); +insert into `act_fo_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('3', 'flowable', 'org/flowable/form/db/liquibase/flowable-form-db-changelog.xml', '2023-09-14 11:05:25', 3, 'executed', '8:abf482518ceb09830ef674e52c06bf15', 'dropcolumn columnname=parent_deployment_id_, tablename=act_fo_form_definition', '', null, '4.3.5', null, null, '4660725875'); +insert into `act_fo_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('4', 'flowable', 'org/flowable/form/db/liquibase/flowable-form-db-changelog.xml', '2023-09-14 11:05:26', 4, 'executed', '8:2087829f22a4b2298dbf530681c74854', 'modifydatatype columnname=deploy_time_, tablename=act_fo_form_deployment; modifydatatype columnname=submitted_date_, tablename=act_fo_form_instance', '', null, '4.3.5', null, null, '4660725875'); +insert into `act_fo_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('5', 'flowable', 'org/flowable/form/db/liquibase/flowable-form-db-changelog.xml', '2023-09-14 11:05:26', 5, 'executed', '8:b4be732b89e5ca028bdd520c6ad4d446', 'createindex indexname=act_idx_form_def_uniq, tablename=act_fo_form_definition', '', null, '4.3.5', null, null, '4660725875'); +insert into `act_fo_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('6', 'flowable', 'org/flowable/form/db/liquibase/flowable-form-db-changelog.xml', '2023-09-14 11:05:26', 6, 'executed', '8:384bbd364a649b67c3ca1bcb72fe537f', 'createindex indexname=act_idx_form_task, tablename=act_fo_form_instance; createindex indexname=act_idx_form_proc, tablename=act_fo_form_instance; createindex indexname=act_idx_form_scope, tablename=act_fo_form_instance', '', null, '4.3.5', null, null, '4660725875'); +commit; + +-- ---------------------------- +-- table structure for act_fo_databasechangeloglock +-- ---------------------------- +drop table if exists `act_fo_databasechangeloglock`; +create table `act_fo_databasechangeloglock` ( + `id` int(11) not null, + `locked` bit(1) not null, + `lockgranted` datetime default null, + `lockedby` varchar(255) default null, + primary key (`id`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_fo_databasechangeloglock +-- ---------------------------- +begin; +insert into `act_fo_databasechangeloglock` (`id`, `locked`, `lockgranted`, `lockedby`) values (1, b'0', null, null); +commit; + +-- ---------------------------- +-- table structure for act_fo_form_definition +-- ---------------------------- +drop table if exists `act_fo_form_definition`; +create table `act_fo_form_definition` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `version_` int(11) default null, + `key_` varchar(255) default null, + `category_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `tenant_id_` varchar(255) default null, + `resource_name_` varchar(255) default null, + `description_` varchar(255) default null, + primary key (`id_`), + unique key `act_idx_form_def_uniq` (`key_`,`version_`,`tenant_id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_fo_form_definition +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_fo_form_deployment +-- ---------------------------- +drop table if exists `act_fo_form_deployment`; +create table `act_fo_form_deployment` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `category_` varchar(255) default null, + `deploy_time_` datetime(3) default null, + `tenant_id_` varchar(255) default null, + `parent_deployment_id_` varchar(255) default null, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_fo_form_deployment +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_fo_form_instance +-- ---------------------------- +drop table if exists `act_fo_form_instance`; +create table `act_fo_form_instance` ( + `id_` varchar(255) not null, + `form_definition_id_` varchar(255) not null, + `task_id_` varchar(255) default null, + `proc_inst_id_` varchar(255) default null, + `proc_def_id_` varchar(255) default null, + `submitted_date_` datetime(3) default null, + `submitted_by_` varchar(255) default null, + `form_values_id_` varchar(255) default null, + `tenant_id_` varchar(255) default null, + `scope_id_` varchar(255) default null, + `scope_type_` varchar(255) default null, + `scope_definition_id_` varchar(255) default null, + primary key (`id_`), + key `act_idx_form_task` (`task_id_`), + key `act_idx_form_proc` (`proc_inst_id_`), + key `act_idx_form_scope` (`scope_id_`,`scope_type_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_fo_form_instance +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_fo_form_resource +-- ---------------------------- +drop table if exists `act_fo_form_resource`; +create table `act_fo_form_resource` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_bytes_` longblob, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of act_fo_form_resource +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ge_bytearray +-- ---------------------------- +drop table if exists `act_ge_bytearray`; +create table `act_ge_bytearray` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `name_` varchar(255) collate utf8_bin default null, + `deployment_id_` varchar(64) collate utf8_bin default null, + `bytes_` longblob, + `generated_` tinyint(4) default null, + primary key (`id_`), + key `act_fk_bytearr_depl` (`deployment_id_`), + constraint `act_fk_bytearr_depl` foreign key (`deployment_id_`) references `act_re_deployment` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ge_bytearray +-- ---------------------------- +begin; +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2520', 1, 'flow_a9z4w99d.bpmn', '2519', 0x3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d38223f3e0a3c646566696e6974696f6e7320786d6c6e733d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f4d4f44454c2220786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a62706d6e64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f42504d4e2f32303130303532342f44492220786d6c6e733a6f6d6764633d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44432220786d6c6e733a62696f633d22687474703a2f2f62706d6e2e696f2f736368656d612f62706d6e2f62696f636f6c6f722f312e302220786d6c6e733a666c6f7761626c653d22687474703a2f2f666c6f7761626c652e6f72672f62706d6e2220786d6c6e733a64693d22687474703a2f2f7777772e6f6d672e6f72672f737065632f44442f32303130303532342f44492220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d6122207461726765744e616d6573706163653d22687474703a2f2f7777772e666c6f7761626c652e6f72672f70726f63657373646566223e0a20203c70726f636573732069643d22666c6f775f6b73326c797a346322206e616d653d22666c6f775f61397a34773939642220666c6f7761626c653a70726f6365737343617465676f72793d226f61223e0a202020203c73746172744576656e742069643d2273746172745f6576656e7422206e616d653d22e5bc80e5a78b223e0a2020202020203c6f7574676f696e673e466c6f775f3174756d6e74363c2f6f7574676f696e673e0a202020203c2f73746172744576656e743e0a202020203c757365725461736b2069643d2241637469766974795f317167396f676122206e616d653d22e8a18ce694bf2220666c6f7761626c653a75736572547970653d2263616e64696461746555736572732220666c6f7761626c653a64617461547970653d2266697865642220666c6f7761626c653a63616e64696461746555736572733d22312c32223e0a2020202020203c696e636f6d696e673e466c6f775f3174756d6e74363c2f696e636f6d696e673e0a2020202020203c6f7574676f696e673e466c6f775f31787a736963673c2f6f7574676f696e673e0a202020203c2f757365725461736b3e0a202020203c73657175656e6365466c6f772069643d22466c6f775f3174756d6e74362220736f757263655265663d2273746172745f6576656e7422207461726765745265663d2241637469766974795f317167396f676122202f3e0a202020203c757365725461736b2069643d2241637469766974795f316d3962386d7522206e616d653d22e88081e69dbf2220666c6f7761626c653a63616e64696461746547726f7570733d22237b617070726f76616c7d2220666c6f7761626c653a75736572547970653d2263616e64696461746547726f7570732220666c6f7761626c653a64617461547970653d2264796e616d6963223e0a2020202020203c696e636f6d696e673e466c6f775f31787a736963673c2f696e636f6d696e673e0a2020202020203c6f7574676f696e673e466c6f775f313668696430713c2f6f7574676f696e673e0a202020203c2f757365725461736b3e0a202020203c73657175656e6365466c6f772069643d22466c6f775f31787a736963672220736f757263655265663d2241637469766974795f317167396f676122207461726765745265663d2241637469766974795f316d3962386d7522202f3e0a202020203c656e644576656e742069643d224576656e745f3070756375313722206e616d653d22223e0a2020202020203c696e636f6d696e673e466c6f775f313668696430713c2f696e636f6d696e673e0a202020203c2f656e644576656e743e0a202020203c73657175656e6365466c6f772069643d22466c6f775f313668696430712220736f757263655265663d2241637469766974795f316d3962386d7522207461726765745265663d224576656e745f3070756375313722202f3e0a20203c2f70726f636573733e0a20203c62706d6e64693a42504d4e4469616772616d2069643d2242504d4e4469616772616d5f666c6f77223e0a202020203c62706d6e64693a42504d4e506c616e652069643d2242504d4e506c616e655f666c6f77222062706d6e456c656d656e743d22666c6f775f6b73326c797a3463223e0a2020202020203c62706d6e64693a42504d4e53686170652069643d2242504d4e53686170655f73746172745f6576656e74222062706d6e456c656d656e743d2273746172745f6576656e74222062696f633a7374726f6b653d22223e0a20202020202020203c6f6d6764633a426f756e647320783d222d32352220793d22313235222077696474683d22333022206865696768743d22333022202f3e0a20202020202020203c62706d6e64693a42504d4e4c6162656c3e0a202020202020202020203c6f6d6764633a426f756e647320783d222d32322220793d22313632222077696474683d22323222206865696768743d22313422202f3e0a20202020202020203c2f62706d6e64693a42504d4e4c6162656c3e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652069643d2241637469766974795f317167396f67615f6469222062706d6e456c656d656e743d2241637469766974795f317167396f6761223e0a20202020202020203c6f6d6764633a426f756e647320783d2236302220793d22313030222077696474683d2231303022206865696768743d22383022202f3e0a20202020202020203c62706d6e64693a42504d4e4c6162656c202f3e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652069643d2241637469766974795f316d3962386d755f6469222062706d6e456c656d656e743d2241637469766974795f316d3962386d75223e0a20202020202020203c6f6d6764633a426f756e647320783d223232302220793d22313030222077696474683d2231303022206865696768743d22383022202f3e0a20202020202020203c62706d6e64693a42504d4e4c6162656c202f3e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e53686170652069643d224576656e745f307075637531375f6469222062706d6e456c656d656e743d224576656e745f30707563753137223e0a20202020202020203c6f6d6764633a426f756e647320783d223338322220793d22313232222077696474683d22333622206865696768743d22333622202f3e0a2020202020203c2f62706d6e64693a42504d4e53686170653e0a2020202020203c62706d6e64693a42504d4e456467652069643d22466c6f775f3174756d6e74365f6469222062706d6e456c656d656e743d22466c6f775f3174756d6e7436223e0a20202020202020203c64693a776179706f696e7420783d22352220793d2231343022202f3e0a20202020202020203c64693a776179706f696e7420783d2236302220793d2231343022202f3e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652069643d22466c6f775f31787a736963675f6469222062706d6e456c656d656e743d22466c6f775f31787a73696367223e0a20202020202020203c64693a776179706f696e7420783d223136302220793d2231343022202f3e0a20202020202020203c64693a776179706f696e7420783d223232302220793d2231343022202f3e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a2020202020203c62706d6e64693a42504d4e456467652069643d22466c6f775f313668696430715f6469222062706d6e456c656d656e743d22466c6f775f31366869643071223e0a20202020202020203c64693a776179706f696e7420783d223332302220793d2231343022202f3e0a20202020202020203c64693a776179706f696e7420783d223338322220793d2231343022202f3e0a2020202020203c2f62706d6e64693a42504d4e456467653e0a202020203c2f62706d6e64693a42504d4e506c616e653e0a20203c2f62706d6e64693a42504d4e4469616772616d3e0a3c2f646566696e6974696f6e733e0a, 0); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2521', 1, 'flow_a9z4w99d.flow_ks2lyz4c.png', '2519', 0x89504e470d0a1a0a0000000d49484452000001c5000000be0806000000445314320000103b4944415478daeddd098c14e5ba06e0e34edca2718dc6dde85163dce3aed7b81d4563ae0147441474505071df85086e5173347adcaf7123a2b8218b17411d442e0272f4b8e2753902823022202ae88008ffadaf323db71d416660a6677b9ee4cbd8dd35ddd5e3cbf7d75f5d55fd97bf0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000544b29ad3d79f2e4e7c78f1fff6b4545457afdf5d755892bfbbb2f1d3366cccc51a3469d227ff2207fd084b286f442f60f22cd9a352b555555a5458b16a91257fcdde3ef3f7af4e81fb326d55efe94fc4113892df4f807a139347d555656cec99ad244f953f2074d247659d9426f3e5bec59535a287f4afea089c4670a1a42f3a9f8ff217f4afea09937a5053f54a6c9ff7c224d7ae3a6bce2bfe33e8d4453923ff98336d594e6cf9b913e19d9277df8df57fdaee2be784c33d194e44ffea0cd34a5e99386fea12115ea9b49c334134d49fee40fda4e53fadf37ef586e538ac734134d49fee40fda4c53fae4f5becb6d4af19866a229c99ffc81a6a429694af2277fd0d69a521cedb7bca6148f69269a92fcc91fb499a6f4e5dbf72fb729c5639a89a6247ff2076da629cd9df151fae4b51bffb8eb2abb2f1ed34c3425f9933f68334d296acabbfdffd094e23e8d4453923ff983b6d594162e4c5f8e7be88fbbaeb2fbe231cd4453923ff98336d194e28a215fbc7ddf723fd389c75c554453923ff983d6dd94b22df0ca2f47a58f475cbfdc8654a8582696b5d5ae29c99ffc41ab6b4a2bda3ab7d5ae29c99ffc419b694a75d93affb3ad76cd4553923ff98356d39456b621154a73d194e44ffea0757da6a33425f9933f96a96bd7ae1b9d7efae91dcacacafe91fdacc86a4a56bf6495aa7fc6ed8aeac73bc4f2fe6a9a92d294e44ffe5a954e9d3a1d9b0d7283b25a543d00d6b562f941f1fbfe8a9a92d294e44ffe5afa60787036a84da8e740b8bc9a10cfe7afaa29294d49fee4afa5ed266d575656f64036902dad3db85d7ae9a569c08001e9bdf7de4b5f7df5559a3b776e0af1336ec7fdf1782cb78c8171693c6f3c7fa3bf896c9d561f3f7efca9fdfbf77fad5fbf7e73aeb9e69aaa9e3d7be66fa8478f1e8bafbcf2ca9fb2fbfe7df3cd37ffbd5bb76edb181435254d49fe9441b1b66cccd8269bd17d583c989d71c619e991471e49df7cf34daa8f583e7e2f7ebfd6e0f841bc4e630d86ed468c18f15f7dfaf4f9b5bcbc3c3df8e08369c28409cb1cc1e3fe78fcdc73cf5dd2ab57afc9ddbb773fdea0a83425f9933f8362f5eed2bf6635a37800bbe38e3bd2f4e9d3d3aa88df8fe7a935304e8fd76bd037900d72176633bfaa98a666b3c4b464c9923aad602c17cb5f7cf1c58b2fb8e0827f65d3d99d0c8a4a53923ff96bf333c419c5b3c3a14387a68614cf576bd638bd41668cd973af3672e4c801e79f7f7e1a3e7c78faedb7df566a05e3f7e2f7bb76edbaa0ad1d1da429694af2a70c8affff1962f12ed36eddbaa5f7df7f3f358678de78fee25da9abf419630c8883060d7aa767cf9ee9b3cf3e6b90958ce7292f2fff251bc1cfd59494a6247ff2d7b6541f545333436cac01b178602c9e31c6ebaff4cac70cb1478f1e69d6ac590dba92f17cd9e83dffb4d34e3b4653529a92fcc95f9bf91c314ebb585218a0860d1b964a215ea768b6b864a54ed718376edc85312036d40c711933c6a5679d75d6bc8e1d3beeac29294d49fee4af4d7c9638a1f8a09a52aa75f0cd84faee366d77cb2db754c567808d69c89021f3b269ed084d49694af2277fad5bec192cde6dbaaa4799aecc51a9c5bb51ebb5a7f2d5575f7d248e325dd9836aea73f04d7979f9ec6ce58ed29494a6247ff2d7aa6789830a03529c4fd814e2758b668b83ea3a4b5cbd77efdebfc66914a53076ecd81fb295fb1f4d49694af2277fad533643dbb8f85aa6a59e2516cf168baf951aeb5597cf12ffb37bf7ee753e0f7155c5eb74eedcf9878e1d3b6edd02b77cdeccea3f34254d49fe545b1d14eb92c3f8168be24bb735a55a9784ebb0c237f8d4534fbd1e57a229a57efdfa7d525656d6b30586a1f087fdd350684a9a92fca9563c28ae3087d9fdf715967bfae9a79b74508cd72f5ae7fb56f8066fbef9e6d9a5da755af0c61b6f4caaf3fedde619863f0d85a6a429c99f6a0383e27273d8a953a75185c7df7df7dd261d14e3f50beb12ebb5c23778f5d557574d9e3cb9a42bf9f9e79f4fcd56f09fad200ccb0c85a6a429c99f6a4383e21f7298fd9c56b8bfd4e34b6df1fa45eb386d856fb0478f1e4bbffffefb92aee4dcb973e7672b37a31585e177a1d0943425f9536d70502ccee1cf85dba51e5f6a8bd72f9a29feb4c237d8a54b97b478f1e292ae64f67a3f35d0174b36cbd2949a57b5e6acc99ffc35f72af5f8b28cf1a6787d7e5be1a078fef9e72f2ef5483e7bf6ec7fb7b299628bdb7d15bb143efae8a395fadd418306a5679e79c696bafcad728d1c3932afe53d1e5f4df7f0c30fa71933669829b6a01cc68cacc5ce14afb8e28a9f4abdcff7d34f3f7db7957ca6d8220f74f8eebbefd241071d9476de79e774cf3df7a45d77dd35edb9e79e3515f77ffcf1c7e995575e898be9a633cf3c33afb83ac4dd77df9dfef6b7bfa50e1d3a684af2b7523573e6ccfc0b62bffdf6db74c20927a4638e3926bfefebafbfce07c0ebafbf3ecd9f3f3f5f3696cbde52fe7dad8f3ffe78da6aabadd276db6d57535b6fbd75baf6da6be5af99e5b0457fa69805f08b521f7dfaf2cb2f0f6de1479fb6d843e2df7cf3cdb4c30e3ba4fdf7df3f8d1b372ebdfdf6dbe9de7bef4d0f3cf0404ddd75d75da9b2b232ffc77cc10517a4f6eddba735d658235d78e185f9b2ebaebb6eda7df7dd63ab2b1f34e31a839a92fcd5b5aebefaea3c833beeb8635a6fbdf5f28affde64934dd23aebac93e21acc0b172e4cefbcf34ebe111683629f3e7df2c16ffdf5d74f8f3efa684d3df4d04369f4e8d1f2d7cc72d8a28f3eedd7afdfdf4b7d9ee245175d34bc859ea7d8e24f9e8e5d094f3ef964baf5d65bf3c12d1a50349cbe7dfbd6d40d37dc909e78e289d8cd9d4e3df5d4bc3145b38adf8fffde60830df22dfb5ebd7aa5238e3822cd9933475392bf3ad5871f7e989e7ffef9f4d24b2fe575c82187a4030e38205d79e59569f5d5574fc71d775c7af6d967f3463671e2c43c9f31284643bbfcf2cbd39a6bae99f6d9679fbcf6de7bef74f8e187a779f3e6c95f33cb618b3e4fb15bb76edb9497972f29e1156dbecd566c764bbca24d5d35f72df518f062e6976d10a53df6d823df6adf69a79df22df5683ab15b2aae7214836234a4db6ebb2dffb9d1461ba576eddaa5b5d65a2b1f148f3ffef814dfbd69f7a9fcd5b56eb9e5963c4b2baa1b6fbc315fbe3028eeb6db6ee9ce3befac79fcbcf3ce4b871e7a683ecb2cec6a95bf663570369b2bda5c72c9254beb75459b906df14f29d52ed48103073eeddaa74d57b1cba9d0585e7bedb5df3d16bb41b7dd76db9adb31038ce56ebffdf67cb0ecddbb77da6cb3cdd2c61b6f9c0f94317b8cddad0645f9ab6bc58133f1fdaa31bb8b8b354796b6dc72cb3c8b71304d454545cde3b1eca69b6e9a673006bf7df7dd37edb7df7e79ee5e7cf1c57cb7fe29a79c227fcd508bbef669c86605c75f7cf1c58b4bf02d19d3b315fbd2b764345d159a497d07c5c2eed308596cf9adbdf6daf9ac313e7bd494e4afae555555951fbd1cbb3d235b31db8bf58dcf0b37df7cf33c53b18b35968d8db0d86b11cbdd74d34d355f4174f2c927a7bdf6da2bdfdbd1bf7f7ff96bbeb3c596f92d1905175d74d1bf860f1fbeb411d76fe99d77def944b662c335a5a6ab38802106b6959929bef0c20b69cc9831857fe4e9c4134f74f4a9fcd5abe2b3c3c84ee42c36aca2e2f6861b6e98ce3efbecf4d8638fa51f7ffc315ff6b2cb2ecb77a3c6e3efbdf75e7e70d875d75d179789ccefdb7efbedd3cf3fff2c7fcd5473f83ec54e9d3a2d5da9ef530c1d3b76dcb95bb76ef33ffbecb34659c1b7de7aeba96cc52ae37534a5a6adc261eecb1a1463cbbc703b8efe8be562b75561976b1c9413cd2806c9d5565b2ddd7ffffd9a92fcd52b7bb1f51e9f03c6aef8d8b08af314172c58903f1e076f1d76d861f97f4f9b36ad66036ee8d0a179de060f1e9c1f115dd8a5fa67e738ca5fb3982d4e280c4ad15f4a295eaf68963861a5de4036aa1e7bce39e7fc12fbf41bd2d4a95387652b35b3de23b5a6d42815cd269aca881123f2dba3468dca4fb7885d5abbecb24bcd72716e621c5473f4d147e7a76274eedc39bf1de7314e9a3429df8d1acf1307e5684af257dfda628b2df2537b624678d55557e5835d0c94599fa85926ce652c6c98c56cf2e0830faed9383bf0c003f32356e3486af96b9eb231e5e0acf72f290c4ec3860d2bc98018af5334202e89f558950f48cfcd668c3f35d48cb17a863823ab7334a5e6515f7cf1457e12f4f0e1c3f3db71659b238f3c323f913a8e4c2d2c17198813fd0bb763d75634afe243e0e3409b214386684af257ef8a53c14e3ae9a474d45147e5f98b93f8bb76edfabb2b2d4d9932259f11c639b171a1898e1d3ba6e79e7b2e7f2c72181b6471eeadfc355f6565650f14ef467dfffdf71b75408ce72fde6d1aafdf20fb82bb74e9322f6b76f356f6e09b38a8a6fa33c46fdbca0cb1a535251764963f257f8d2ddbd069978d031f1406a96cd2d56803633c6ff67a4b8a66891fc4eb37d4e8be5336aa8f2c2f2f9f3d76ecd81fea7a1e63b6dcac8103070e88a34cb37a359ea7ad854053d294e44f19147ff7d9e236594d2f9e31c6e7c40d299eaf788658fd7adb34c6114447654f3ca673e7ce3ff6eddbf7e38a8a8a4f3efffcf36973e6cc5990adc7fcefbefb6ef2a44993de1d3c78f0905ebd7abd9a2d3b27966feda75d684a9a92fc29f9abd7e78b7f2d1e180b07dfacea51a9f1fbb50eaac907c478bd467d4371059aec857a6433bfb86ee9c4a237173f2756dfdfa3355fa94653d294e44fc9df2acf183f281ec062d6184724c791c9f5513892b9d6ec30553fff36feda9a92d294e44ffe5ac4678cd507dfd41eccf223da070c18909f97fad5575fe55735aafe62fafc76dc1f8fd7ba745ba196c6f336d86788684a9a92fc29f92be1eed4838bcf635cc59ab04aa75da029694af2a7e4af990c8ec7565f126e513d07c2587e50fcbebfa2a6a43425f993bfd6b65b75a3f8168bb2b2b27f643f2bb29a92d52fd503e02fd5b72baa1fef10cbfbab694a4a53923ff9034d49694af2277fa029294d49fee40f3425a529c99ffc81a6a43425f9933fd09494a6247ff2079a92d294e44ffe4053529a92fcc91f684a4a53923ff9034d49694af2277f6050549a92fcc91f181495a6247ff2070645a529c99f322882a6a429c99f322882a6a429c99f322882a6a429c99f923fd0943425f953f2077fa6a2a2626955559586d00c2afbff30336b4a0be54fc91f34913163c6cc9c356b96a6d00ceaebafbf1e9835a589f2a7e40f9ac8a851a34e193d7af48f959595736cb137d9167ae5d4a9539fc91ad2b4acdacb9f923f68dacf75dac71662568be2330555f25a54fdf76f2f7ff2207f0000000000000000000000000000000025f27f960d66048be0fa430000000049454e44ae426082, 1); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2530', 1, 'hist.var-variables', null, 0xaced0005737200176a6176612e7574696c2e4c696e6b6564486173684d617034c04e5c106cc0fb0200015a000b6163636573734f72646572787200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000b7400066669656c6473737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000037704000000037371007e00003f4000000000000c7708000000100000000c74000a5f5f636f6e6669675f5f7371007e00003f400000000000187708000000200000000e7400056c6162656c74000ce8afb7e58187e6a087e9a29874000a6c6162656c57696474687074000973686f774c6162656c737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017400096368616e676554616771007e000e740003746167740008656c2d696e70757474000774616749636f6e740005696e707574740008726571756972656471007e000e7400066c61796f757474000b636f6c466f726d4974656d7400047370616e737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000018740008646f63756d656e7474003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e7075747400077265674c6973747371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e7400076d657373616765740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a29874000774726967676572740004626c7572780078740006666f726d49647371007e00180000006574000972656e6465724b65797400103130313136353035393234363637303374000c64656661756c7456616c7565740006e6b58be8af9578007400085f5f736c6f745f5f7371007e00003f400000000000037708000000040000000274000770726570656e64740000740006617070656e6471007e002d780074000b706c616365686f6c646572740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a2987400057374796c657371007e00003f40000000000001770800000002000000017400057769647468740004313030257800740009636c65617261626c6571007e000e74000b7072656669782d69636f6e71007e002d74000b7375666669782d69636f6e71007e002d7400096d61786c656e6774687074000f73686f772d776f72642d6c696d69747371007e000d00740008726561646f6e6c7971007e003a74000864697361626c656471007e003a74000a5f5f764d6f64656c5f5f7400086669656c6431303178007371007e00003f4000000000000c7708000000100000000c71007e00077371007e00003f400000000000187708000000200000000e71007e000974000ce8afb7e58187e5a4a9e695b071007e000b7071007e000c71007e000e71007e000f71007e000e71007e0010740008656c2d696e70757471007e0012740005696e70757471007e001471007e000e71007e001574000b636f6c466f726d4974656d71007e001771007e001a71007e001b74003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e001d7371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e71007e0020740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e0022740004626c757278007871007e002471007e002571007e00267400103130313136343633363237353238353271007e002874000133780071007e002a7371007e00003f400000000000037708000000040000000271007e002c71007e002d71007e002e71007e002d780071007e002f740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e00317371007e00003f400000000000017708000000020000000171007e003374000431303025780071007e003571007e000e71007e003671007e002d71007e003771007e002d71007e00387071007e003971007e003a71007e003b71007e003a71007e003c71007e003a71007e003d74000364617978007371007e00003f4000000000000c7708000000100000000a71007e00077371007e00003f400000000000187708000000200000000e71007e000974000ce8afb7e58187e5a487e6b3a871007e000b7071007e000c71007e000e71007e0010740008656c2d696e70757471007e0012740008746578746172656171007e001471007e000e71007e001574000b636f6c466f726d4974656d71007e001771007e001a71007e001d7371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e71007e0020740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a871007e0022740004626c757278007871007e000f71007e000e71007e001b74003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e00247371007e00180000006671007e00267400103130323136353035393234363936393271007e002874000474657374780074000474797065740008746578746172656171007e002f740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a87400086175746f73697a657371007e00003f40000000000003770800000004000000027400076d696e526f77737371007e0018000000047400076d6178526f777371007e0065780071007e00317371007e00003f400000000000017708000000020000000171007e003374000431303025780071007e00387071007e003971007e003a71007e003b71007e003a71007e003c71007e003a71007e003d7400086669656c64313032780078740007666f726d526566740006656c466f726d740009666f726d4d6f64656c740008666f726d4461746174000473697a657400066d656469756d74000d6c6162656c506f736974696f6e740005726967687471007e000b7371007e001800000064740009666f726d52756c657374000572756c65737400066775747465727371007e00180000000f71007e003c71007e000e71007e001771007e001a740008666f726d42746e7371007e003a7800, null); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2546', 1, 'hist.var-fields', null, 0xaced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a65787000000003770400000003737200176a6176612e7574696c2e4c696e6b6564486173684d617034c04e5c106cc0fb0200015a000b6163636573734f72646572787200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000c74000a5f5f636f6e6669675f5f7371007e00023f400000000000187708000000200000000e7400056c6162656c74000ce8afb7e58187e6a087e9a29874000a6c6162656c57696474687074000973686f774c6162656c737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017400096368616e676554616771007e000c740003746167740008656c2d696e70757474000774616749636f6e740005696e707574740008726571756972656471007e000c7400066c61796f757474000b636f6c466f726d4974656d7400047370616e737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000018740008646f63756d656e7474003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e7075747400077265674c6973747371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c7400076d657373616765740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a29874000774726967676572740004626c7572780078740006666f726d49647371007e00160000006574000972656e6465724b65797400103130313136353035393234363637303374000c64656661756c7456616c7565740006e6b58be8af9578007400085f5f736c6f745f5f7371007e00023f400000000000037708000000040000000274000770726570656e64740000740006617070656e6471007e002b780074000b706c616365686f6c646572740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a2987400057374796c657371007e00023f40000000000001770800000002000000017400057769647468740004313030257800740009636c65617261626c6571007e000c74000b7072656669782d69636f6e71007e002b74000b7375666669782d69636f6e71007e002b7400096d61786c656e6774687074000f73686f772d776f72642d6c696d69747371007e000b00740008726561646f6e6c7971007e003874000864697361626c656471007e003874000a5f5f764d6f64656c5f5f7400086669656c6431303178007371007e00023f4000000000000c7708000000100000000c71007e00057371007e00023f400000000000187708000000200000000e71007e000774000ce8afb7e58187e5a4a9e695b071007e00097071007e000a71007e000c71007e000d71007e000c71007e000e740008656c2d696e70757471007e0010740005696e70757471007e001271007e000c71007e001374000b636f6c466f726d4974656d71007e001571007e001871007e001974003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e001b7371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c71007e001e740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e0020740004626c757278007871007e002271007e002371007e00247400103130313136343633363237353238353271007e002674000133780071007e00287371007e00023f400000000000037708000000040000000271007e002a71007e002b71007e002c71007e002b780071007e002d740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e002f7371007e00023f400000000000017708000000020000000171007e003174000431303025780071007e003371007e000c71007e003471007e002b71007e003571007e002b71007e00367071007e003771007e003871007e003971007e003871007e003a71007e003871007e003b74000364617978007371007e00023f4000000000000c7708000000100000000a71007e00057371007e00023f400000000000187708000000200000000e71007e000774000ce8afb7e58187e5a487e6b3a871007e00097071007e000a71007e000c71007e000e740008656c2d696e70757471007e0010740008746578746172656171007e001271007e000c71007e001374000b636f6c466f726d4974656d71007e001571007e001871007e001b7371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c71007e001e740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a871007e0020740004626c757278007871007e000d71007e000c71007e001974003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e00227371007e00160000006671007e00247400103130323136353035393234363936393271007e002674000474657374780074000474797065740008746578746172656171007e002d740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a87400086175746f73697a657371007e00023f40000000000003770800000004000000027400076d696e526f77737371007e0016000000047400076d6178526f777371007e0063780071007e002f7371007e00023f400000000000017708000000020000000171007e003174000431303025780071007e00367071007e003771007e003871007e003971007e003871007e003a71007e003871007e003b7400086669656c64313032780078, null); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2568', 1, 'var-variables', null, 0xaced0005737200176a6176612e7574696c2e4c696e6b6564486173684d617034c04e5c106cc0fb0200015a000b6163636573734f72646572787200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000b7400066669656c6473737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000037704000000037371007e00003f4000000000000c7708000000100000000c74000a5f5f636f6e6669675f5f7371007e00003f400000000000187708000000200000000e7400056c6162656c74000ce8afb7e58187e6a087e9a29874000a6c6162656c57696474687074000973686f774c6162656c737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017400096368616e676554616771007e000e740003746167740008656c2d696e70757474000774616749636f6e740005696e707574740008726571756972656471007e000e7400066c61796f757474000b636f6c466f726d4974656d7400047370616e737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000018740008646f63756d656e7474003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e7075747400077265674c6973747371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e7400076d657373616765740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a29874000774726967676572740004626c7572780078740006666f726d49647371007e00180000006574000972656e6465724b65797400103130313136353035393234363637303374000c64656661756c7456616c75657400066a696e74747478007400085f5f736c6f745f5f7371007e00003f400000000000037708000000040000000274000770726570656e64740000740006617070656e6471007e002d780074000b706c616365686f6c646572740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a2987400057374796c657371007e00003f40000000000001770800000002000000017400057769647468740004313030257800740009636c65617261626c6571007e000e74000b7072656669782d69636f6e71007e002d74000b7375666669782d69636f6e71007e002d7400096d61786c656e6774687074000f73686f772d776f72642d6c696d69747371007e000d00740008726561646f6e6c7971007e003a74000864697361626c656471007e003a74000a5f5f764d6f64656c5f5f7400086669656c6431303178007371007e00003f4000000000000c7708000000100000000c71007e00077371007e00003f400000000000187708000000200000000e71007e000974000ce8afb7e58187e5a4a9e695b071007e000b7071007e000c71007e000e71007e000f71007e000e71007e0010740008656c2d696e70757471007e0012740005696e70757471007e001471007e000e71007e001574000b636f6c466f726d4974656d71007e001771007e001a71007e001b74003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e001d7371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e71007e0020740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e0022740004626c757278007871007e002471007e002571007e00267400103130313136343633363237353238353271007e002874000134780071007e002a7371007e00003f400000000000037708000000040000000271007e002c71007e002d71007e002e71007e002d780071007e002f740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e00317371007e00003f400000000000017708000000020000000171007e003374000431303025780071007e003571007e000e71007e003671007e002d71007e003771007e002d71007e00387071007e003971007e003a71007e003b71007e003a71007e003c71007e003a71007e003d74000364617978007371007e00003f4000000000000c7708000000100000000a71007e00077371007e00003f400000000000187708000000200000000e71007e000974000ce8afb7e58187e5a487e6b3a871007e000b7071007e000c71007e000e71007e0010740008656c2d696e70757471007e0012740008746578746172656171007e001471007e000e71007e001574000b636f6c466f726d4974656d71007e001771007e001a71007e001d7371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e71007e0020740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a871007e0022740004626c757278007871007e000f71007e000e71007e001b74003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e00247371007e00180000006671007e00267400103130323136353035393234363936393271007e0028740003747474780074000474797065740008746578746172656171007e002f740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a87400086175746f73697a657371007e00003f40000000000003770800000004000000027400076d696e526f77737371007e0018000000047400076d6178526f777371007e0065780071007e00317371007e00003f400000000000017708000000020000000171007e003374000431303025780071007e00387071007e003971007e003a71007e003b71007e003a71007e003c71007e003a71007e003d7400086669656c64313032780078740007666f726d526566740006656c466f726d740009666f726d4d6f64656c740008666f726d4461746174000473697a657400066d656469756d74000d6c6162656c506f736974696f6e740005726967687471007e000b7371007e001800000064740009666f726d52756c657374000572756c65737400066775747465727371007e00180000000f71007e003c71007e000e71007e001771007e001a740008666f726d42746e7371007e003a7800, null); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2570', 1, 'hist.var-variables', null, 0xaced0005737200176a6176612e7574696c2e4c696e6b6564486173684d617034c04e5c106cc0fb0200015a000b6163636573734f72646572787200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000b7400066669656c6473737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000037704000000037371007e00003f4000000000000c7708000000100000000c74000a5f5f636f6e6669675f5f7371007e00003f400000000000187708000000200000000e7400056c6162656c74000ce8afb7e58187e6a087e9a29874000a6c6162656c57696474687074000973686f774c6162656c737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017400096368616e676554616771007e000e740003746167740008656c2d696e70757474000774616749636f6e740005696e707574740008726571756972656471007e000e7400066c61796f757474000b636f6c466f726d4974656d7400047370616e737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000018740008646f63756d656e7474003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e7075747400077265674c6973747371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e7400076d657373616765740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a29874000774726967676572740004626c7572780078740006666f726d49647371007e00180000006574000972656e6465724b65797400103130313136353035393234363637303374000c64656661756c7456616c75657400066a696e74747478007400085f5f736c6f745f5f7371007e00003f400000000000037708000000040000000274000770726570656e64740000740006617070656e6471007e002d780074000b706c616365686f6c646572740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a2987400057374796c657371007e00003f40000000000001770800000002000000017400057769647468740004313030257800740009636c65617261626c6571007e000e74000b7072656669782d69636f6e71007e002d74000b7375666669782d69636f6e71007e002d7400096d61786c656e6774687074000f73686f772d776f72642d6c696d69747371007e000d00740008726561646f6e6c7971007e003a74000864697361626c656471007e003a74000a5f5f764d6f64656c5f5f7400086669656c6431303178007371007e00003f4000000000000c7708000000100000000c71007e00077371007e00003f400000000000187708000000200000000e71007e000974000ce8afb7e58187e5a4a9e695b071007e000b7071007e000c71007e000e71007e000f71007e000e71007e0010740008656c2d696e70757471007e0012740005696e70757471007e001471007e000e71007e001574000b636f6c466f726d4974656d71007e001771007e001a71007e001b74003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e001d7371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e71007e0020740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e0022740004626c757278007871007e002471007e002571007e00267400103130313136343633363237353238353271007e002874000134780071007e002a7371007e00003f400000000000037708000000040000000271007e002c71007e002d71007e002e71007e002d780071007e002f740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e00317371007e00003f400000000000017708000000020000000171007e003374000431303025780071007e003571007e000e71007e003671007e002d71007e003771007e002d71007e00387071007e003971007e003a71007e003b71007e003a71007e003c71007e003a71007e003d74000364617978007371007e00003f4000000000000c7708000000100000000a71007e00077371007e00003f400000000000187708000000200000000e71007e000974000ce8afb7e58187e5a487e6b3a871007e000b7071007e000c71007e000e71007e0010740008656c2d696e70757471007e0012740008746578746172656171007e001471007e000e71007e001574000b636f6c466f726d4974656d71007e001771007e001a71007e001d7371007e0004000000017704000000017371007e00003f4000000000000c7708000000100000000371007e001471007e000e71007e0020740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a871007e0022740004626c757278007871007e000f71007e000e71007e001b74003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e00247371007e00180000006671007e00267400103130323136353035393234363936393271007e0028740003747474780074000474797065740008746578746172656171007e002f740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a87400086175746f73697a657371007e00003f40000000000003770800000004000000027400076d696e526f77737371007e0018000000047400076d6178526f777371007e0065780071007e00317371007e00003f400000000000017708000000020000000171007e003374000431303025780071007e00387071007e003971007e003a71007e003b71007e003a71007e003c71007e003a71007e003d7400086669656c64313032780078740007666f726d526566740006656c466f726d740009666f726d4d6f64656c740008666f726d4461746174000473697a657400066d656469756d74000d6c6162656c506f736974696f6e740005726967687471007e000b7371007e001800000064740009666f726d52756c657374000572756c65737400066775747465727371007e00180000000f71007e003c71007e000e71007e001771007e001a740008666f726d42746e7371007e003a7800, null); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2584', 1, 'var-fields', null, 0xaced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a65787000000003770400000003737200176a6176612e7574696c2e4c696e6b6564486173684d617034c04e5c106cc0fb0200015a000b6163636573734f72646572787200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000c74000a5f5f636f6e6669675f5f7371007e00023f400000000000187708000000200000000e7400056c6162656c74000ce8afb7e58187e6a087e9a29874000a6c6162656c57696474687074000973686f774c6162656c737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017400096368616e676554616771007e000c740003746167740008656c2d696e70757474000774616749636f6e740005696e707574740008726571756972656471007e000c7400066c61796f757474000b636f6c466f726d4974656d7400047370616e737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000018740008646f63756d656e7474003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e7075747400077265674c6973747371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c7400076d657373616765740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a29874000774726967676572740004626c7572780078740006666f726d49647371007e00160000006574000972656e6465724b65797400103130313136353035393234363637303374000c64656661756c7456616c75657400066a696e74747478007400085f5f736c6f745f5f7371007e00023f400000000000037708000000040000000274000770726570656e64740000740006617070656e6471007e002b780074000b706c616365686f6c646572740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a2987400057374796c657371007e00023f40000000000001770800000002000000017400057769647468740004313030257800740009636c65617261626c6571007e000c74000b7072656669782d69636f6e71007e002b74000b7375666669782d69636f6e71007e002b7400096d61786c656e6774687074000f73686f772d776f72642d6c696d69747371007e000b00740008726561646f6e6c7971007e003874000864697361626c656471007e003874000a5f5f764d6f64656c5f5f7400086669656c6431303178007371007e00023f4000000000000c7708000000100000000c71007e00057371007e00023f400000000000187708000000200000000e71007e000774000ce8afb7e58187e5a4a9e695b071007e00097071007e000a71007e000c71007e000d71007e000c71007e000e740008656c2d696e70757471007e0010740005696e70757471007e001271007e000c71007e001374000b636f6c466f726d4974656d71007e001571007e001871007e001974003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e001b7371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c71007e001e740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e0020740004626c757278007871007e002271007e002371007e00247400103130313136343633363237353238353271007e002674000134780071007e00287371007e00023f400000000000037708000000040000000271007e002a71007e002b71007e002c71007e002b780071007e002d740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e002f7371007e00023f400000000000017708000000020000000171007e003174000431303025780071007e003371007e000c71007e003471007e002b71007e003571007e002b71007e00367071007e003771007e003871007e003971007e003871007e003a71007e003871007e003b74000364617978007371007e00023f4000000000000c7708000000100000000a71007e00057371007e00023f400000000000187708000000200000000e71007e000774000ce8afb7e58187e5a487e6b3a871007e00097071007e000a71007e000c71007e000e740008656c2d696e70757471007e0010740008746578746172656171007e001271007e000c71007e001374000b636f6c466f726d4974656d71007e001571007e001871007e001b7371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c71007e001e740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a871007e0020740004626c757278007871007e000d71007e000c71007e001974003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e00227371007e00160000006671007e00247400103130323136353035393234363936393271007e0026740003747474780074000474797065740008746578746172656171007e002d740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a87400086175746f73697a657371007e00023f40000000000003770800000004000000027400076d696e526f77737371007e0016000000047400076d6178526f777371007e0063780071007e002f7371007e00023f400000000000017708000000020000000171007e003174000431303025780071007e00367071007e003771007e003871007e003971007e003871007e003a71007e003871007e003b7400086669656c64313032780078, null); +insert into `act_ge_bytearray` (`id_`, `rev_`, `name_`, `deployment_id_`, `bytes_`, `generated_`) values ('2586', 1, 'hist.var-fields', null, 0xaced0005737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a65787000000003770400000003737200176a6176612e7574696c2e4c696e6b6564486173684d617034c04e5c106cc0fb0200015a000b6163636573734f72646572787200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000c7708000000100000000c74000a5f5f636f6e6669675f5f7371007e00023f400000000000187708000000200000000e7400056c6162656c74000ce8afb7e58187e6a087e9a29874000a6c6162656c57696474687074000973686f774c6162656c737200116a6176612e6c616e672e426f6f6c65616ecd207280d59cfaee0200015a000576616c75657870017400096368616e676554616771007e000c740003746167740008656c2d696e70757474000774616749636f6e740005696e707574740008726571756972656471007e000c7400066c61796f757474000b636f6c466f726d4974656d7400047370616e737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000018740008646f63756d656e7474003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e7075747400077265674c6973747371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c7400076d657373616765740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a29874000774726967676572740004626c7572780078740006666f726d49647371007e00160000006574000972656e6465724b65797400103130313136353035393234363637303374000c64656661756c7456616c75657400066a696e74747478007400085f5f736c6f745f5f7371007e00023f400000000000037708000000040000000274000770726570656e64740000740006617070656e6471007e002b780074000b706c616365686f6c646572740015e8afb7e8be93e585a5e8afb7e58187e6a087e9a2987400057374796c657371007e00023f40000000000001770800000002000000017400057769647468740004313030257800740009636c65617261626c6571007e000c74000b7072656669782d69636f6e71007e002b74000b7375666669782d69636f6e71007e002b7400096d61786c656e6774687074000f73686f772d776f72642d6c696d69747371007e000b00740008726561646f6e6c7971007e003874000864697361626c656471007e003874000a5f5f764d6f64656c5f5f7400086669656c6431303178007371007e00023f4000000000000c7708000000100000000c71007e00057371007e00023f400000000000187708000000200000000e71007e000774000ce8afb7e58187e5a4a9e695b071007e00097071007e000a71007e000c71007e000d71007e000c71007e000e740008656c2d696e70757471007e0010740005696e70757471007e001271007e000c71007e001374000b636f6c466f726d4974656d71007e001571007e001871007e001974003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e001b7371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c71007e001e740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e0020740004626c757278007871007e002271007e002371007e00247400103130313136343633363237353238353271007e002674000134780071007e00287371007e00023f400000000000037708000000040000000271007e002a71007e002b71007e002c71007e002b780071007e002d740015e8afb7e8be93e585a5e8afb7e58187e5a4a9e695b071007e002f7371007e00023f400000000000017708000000020000000171007e003174000431303025780071007e003371007e000c71007e003471007e002b71007e003571007e002b71007e00367071007e003771007e003871007e003971007e003871007e003a71007e003871007e003b74000364617978007371007e00023f4000000000000c7708000000100000000a71007e00057371007e00023f400000000000187708000000200000000e71007e000774000ce8afb7e58187e5a487e6b3a871007e00097071007e000a71007e000c71007e000e740008656c2d696e70757471007e0010740008746578746172656171007e001271007e000c71007e001374000b636f6c466f726d4974656d71007e001571007e001871007e001b7371007e0000000000017704000000017371007e00023f4000000000000c7708000000100000000371007e001271007e000c71007e001e740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a871007e0020740004626c757278007871007e000d71007e000c71007e001974003068747470733a2f2f656c656d656e742e656c656d652e636e2f232f7a682d434e2f636f6d706f6e656e742f696e70757471007e00227371007e00160000006671007e00247400103130323136353035393234363936393271007e0026740003747474780074000474797065740008746578746172656171007e002d740015e8afb7e8be93e585a5e8afb7e58187e5a487e6b3a87400086175746f73697a657371007e00023f40000000000003770800000004000000027400076d696e526f77737371007e0016000000047400076d6178526f777371007e0063780071007e002f7371007e00023f400000000000017708000000020000000171007e003174000431303025780071007e00367071007e003771007e003871007e003971007e003871007e003a71007e003871007e003b7400086669656c64313032780078, null); +commit; + +-- ---------------------------- +-- table structure for act_ge_property +-- ---------------------------- +drop table if exists `act_ge_property`; +create table `act_ge_property` ( + `name_` varchar(64) collate utf8_bin not null, + `value_` varchar(300) collate utf8_bin default null, + `rev_` int(11) default null, + primary key (`name_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ge_property +-- ---------------------------- +begin; +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('batch.schema.version', '6.7.2.3', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('cfg.execution-related-entities-count', 'true', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('cfg.task-related-entities-count', 'true', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('common.schema.version', '6.8.0.0', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('entitylink.schema.version', '6.8.0.0', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('eventsubscription.schema.version', '6.8.0.0', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('identitylink.schema.version', '6.8.0.0', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('job.schema.version', '6.8.0.0', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('next.dbid', '7501', 4); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('schema.history', 'upgrade(6.7.2.0->6.8.0.0)', 2); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('schema.version', '6.8.0.0', 2); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('task.schema.version', '6.8.0.0', 1); +insert into `act_ge_property` (`name_`, `value_`, `rev_`) values ('variable.schema.version', '6.8.0.0', 1); +commit; + +-- ---------------------------- +-- table structure for act_hi_actinst +-- ---------------------------- +drop table if exists `act_hi_actinst`; +create table `act_hi_actinst` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default '1', + `proc_def_id_` varchar(64) collate utf8_bin not null, + `proc_inst_id_` varchar(64) collate utf8_bin not null, + `execution_id_` varchar(64) collate utf8_bin not null, + `act_id_` varchar(255) collate utf8_bin not null, + `task_id_` varchar(64) collate utf8_bin default null, + `call_proc_inst_id_` varchar(64) collate utf8_bin default null, + `act_name_` varchar(255) collate utf8_bin default null, + `act_type_` varchar(255) collate utf8_bin not null, + `assignee_` varchar(255) collate utf8_bin default null, + `start_time_` datetime(3) not null, + `end_time_` datetime(3) default null, + `transaction_order_` int(11) default null, + `duration_` bigint(20) default null, + `delete_reason_` varchar(4000) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_hi_act_inst_start` (`start_time_`), + key `act_idx_hi_act_inst_end` (`end_time_`), + key `act_idx_hi_act_inst_procinst` (`proc_inst_id_`,`act_id_`), + key `act_idx_hi_act_inst_exec` (`execution_id_`,`act_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_actinst +-- ---------------------------- +begin; +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2533', 1, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'start_event', null, null, '开始', 'startevent', null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659', 1, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2534', 1, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'flow_1tumnt6', null, null, null, 'sequenceflow', null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659', 2, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2535', 3, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'activity_1qg9oga', '2536', null, '行政', 'usertask', '1', '2022-12-26 11:28:09.659', '2022-12-26 11:29:12.968', 3, 63309, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2558', 1, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'flow_1xzsicg', null, null, null, 'sequenceflow', null, '2022-12-26 11:29:12.969', '2022-12-26 11:29:12.969', 1, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2559', 3, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'activity_1m9b8mu', '2560', null, '老板', 'usertask', '1', '2022-12-26 11:29:12.969', '2022-12-26 18:54:38.684', 2, 26725715, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2573', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'start_event', null, null, '开始', 'startevent', null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717', 1, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2574', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'flow_1tumnt6', null, null, null, 'sequenceflow', null, '2022-12-26 11:31:33.718', '2022-12-26 11:31:33.718', 2, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2575', 3, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'activity_1qg9oga', '2576', null, '行政', 'usertask', '2', '2022-12-26 11:31:33.718', '2022-12-26 11:32:01.166', 3, 27448, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2598', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'flow_1xzsicg', null, null, null, 'sequenceflow', null, '2022-12-26 11:32:01.166', '2022-12-26 11:32:01.166', 1, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('2599', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'activity_1m9b8mu', '2600', null, '老板', 'usertask', null, '2022-12-26 11:32:01.167', null, 2, null, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('5005', 1, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'flow_16hid0q', null, null, null, 'sequenceflow', null, '2022-12-26 18:54:38.691', '2022-12-26 18:54:38.691', 1, 0, null, ''); +insert into `act_hi_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `transaction_order_`, `duration_`, `delete_reason_`, `tenant_id_`) values ('5006', 1, 'flow_ks2lyz4c:2:2522', '2523', '2532', 'event_0pucu17', null, null, '', 'endevent', null, '2022-12-26 18:54:38.692', '2022-12-26 18:54:38.693', 2, 1, null, ''); +commit; + +-- ---------------------------- +-- table structure for act_hi_attachment +-- ---------------------------- +drop table if exists `act_hi_attachment`; +create table `act_hi_attachment` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `user_id_` varchar(255) collate utf8_bin default null, + `name_` varchar(255) collate utf8_bin default null, + `description_` varchar(4000) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `url_` varchar(4000) collate utf8_bin default null, + `content_id_` varchar(64) collate utf8_bin default null, + `time_` datetime(3) default null, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_attachment +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_hi_comment +-- ---------------------------- +drop table if exists `act_hi_comment`; +create table `act_hi_comment` ( + `id_` varchar(64) collate utf8_bin not null, + `type_` varchar(255) collate utf8_bin default null, + `time_` datetime(3) not null, + `user_id_` varchar(255) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `action_` varchar(255) collate utf8_bin default null, + `message_` varchar(4000) collate utf8_bin default null, + `full_msg_` longblob, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_comment +-- ---------------------------- +begin; +insert into `act_hi_comment` (`id_`, `type_`, `time_`, `user_id_`, `task_id_`, `proc_inst_id_`, `action_`, `message_`, `full_msg_`) values ('2541', '1', '2022-12-26 11:29:12.929', null, '2536', '2523', 'addcomment', 'ddd', 0x646464); +insert into `act_hi_comment` (`id_`, `type_`, `time_`, `user_id_`, `task_id_`, `proc_inst_id_`, `action_`, `message_`, `full_msg_`) values ('2543', 'event', '2022-12-26 11:29:12.946', null, '2536', null, 'adduserlink', '1_|_assignee', null); +insert into `act_hi_comment` (`id_`, `type_`, `time_`, `user_id_`, `task_id_`, `proc_inst_id_`, `action_`, `message_`, `full_msg_`) values ('2581', '1', '2022-12-26 11:32:01.141', null, '2576', '2563', 'addcomment', 'rrrr', 0x72727272); +insert into `act_hi_comment` (`id_`, `type_`, `time_`, `user_id_`, `task_id_`, `proc_inst_id_`, `action_`, `message_`, `full_msg_`) values ('2583', 'event', '2022-12-26 11:32:01.150', null, '2576', null, 'adduserlink', '2_|_assignee', null); +insert into `act_hi_comment` (`id_`, `type_`, `time_`, `user_id_`, `task_id_`, `proc_inst_id_`, `action_`, `message_`, `full_msg_`) values ('5001', '1', '2022-12-26 18:54:38.588', 'admin', '2560', '2523', 'addcomment', 'hhh', 0x686868); +insert into `act_hi_comment` (`id_`, `type_`, `time_`, `user_id_`, `task_id_`, `proc_inst_id_`, `action_`, `message_`, `full_msg_`) values ('5003', 'event', '2022-12-26 18:54:38.622', 'admin', '2560', null, 'adduserlink', '1_|_assignee', null); +commit; + +-- ---------------------------- +-- table structure for act_hi_detail +-- ---------------------------- +drop table if exists `act_hi_detail`; +create table `act_hi_detail` ( + `id_` varchar(64) collate utf8_bin not null, + `type_` varchar(255) collate utf8_bin not null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `act_inst_id_` varchar(64) collate utf8_bin default null, + `name_` varchar(255) collate utf8_bin not null, + `var_type_` varchar(255) collate utf8_bin default null, + `rev_` int(11) default null, + `time_` datetime(3) not null, + `bytearray_id_` varchar(64) collate utf8_bin default null, + `double_` double default null, + `long_` bigint(20) default null, + `text_` varchar(4000) collate utf8_bin default null, + `text2_` varchar(4000) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_hi_detail_proc_inst` (`proc_inst_id_`), + key `act_idx_hi_detail_act_inst` (`act_inst_id_`), + key `act_idx_hi_detail_time` (`time_`), + key `act_idx_hi_detail_name` (`name_`), + key `act_idx_hi_detail_task_id` (`task_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_detail +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_hi_entitylink +-- ---------------------------- +drop table if exists `act_hi_entitylink`; +create table `act_hi_entitylink` ( + `id_` varchar(64) collate utf8_bin not null, + `link_type_` varchar(255) collate utf8_bin default null, + `create_time_` datetime(3) default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `parent_element_id_` varchar(255) collate utf8_bin default null, + `ref_scope_id_` varchar(255) collate utf8_bin default null, + `ref_scope_type_` varchar(255) collate utf8_bin default null, + `ref_scope_definition_id_` varchar(255) collate utf8_bin default null, + `root_scope_id_` varchar(255) collate utf8_bin default null, + `root_scope_type_` varchar(255) collate utf8_bin default null, + `hierarchy_type_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_hi_ent_lnk_scope` (`scope_id_`,`scope_type_`,`link_type_`), + key `act_idx_hi_ent_lnk_ref_scope` (`ref_scope_id_`,`ref_scope_type_`,`link_type_`), + key `act_idx_hi_ent_lnk_root_scope` (`root_scope_id_`,`root_scope_type_`,`link_type_`), + key `act_idx_hi_ent_lnk_scope_def` (`scope_definition_id_`,`scope_type_`,`link_type_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_entitylink +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_hi_identitylink +-- ---------------------------- +drop table if exists `act_hi_identitylink`; +create table `act_hi_identitylink` ( + `id_` varchar(64) collate utf8_bin not null, + `group_id_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin default null, + `user_id_` varchar(255) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `create_time_` datetime(3) default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_hi_ident_lnk_user` (`user_id_`), + key `act_idx_hi_ident_lnk_scope` (`scope_id_`,`scope_type_`), + key `act_idx_hi_ident_lnk_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_hi_ident_lnk_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_idx_hi_ident_lnk_task` (`task_id_`), + key `act_idx_hi_ident_lnk_procinst` (`proc_inst_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_identitylink +-- ---------------------------- +begin; +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2524', null, 'starter', '1', null, '2022-12-26 11:28:09.658', '2523', null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2537', null, 'candidate', '1', '2536', '2022-12-26 11:28:09.660', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2538', null, 'participant', '1', null, '2022-12-26 11:28:09.660', '2523', null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2539', null, 'candidate', '2', '2536', '2022-12-26 11:28:09.660', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2540', null, 'participant', '2', null, '2022-12-26 11:28:09.660', '2523', null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2542', null, 'assignee', '1', '2536', '2022-12-26 11:29:12.943', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2561', '1', 'candidate', null, '2560', '2022-12-26 11:29:12.973', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2562', '2', 'candidate', null, '2560', '2022-12-26 11:29:12.973', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2564', null, 'starter', '1', null, '2022-12-26 11:31:33.717', '2563', null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2577', null, 'candidate', '1', '2576', '2022-12-26 11:31:33.718', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2578', null, 'participant', '1', null, '2022-12-26 11:31:33.718', '2563', null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2579', null, 'candidate', '2', '2576', '2022-12-26 11:31:33.718', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2580', null, 'participant', '2', null, '2022-12-26 11:31:33.718', '2563', null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2582', null, 'assignee', '2', '2576', '2022-12-26 11:32:01.148', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2601', '2', 'candidate', null, '2600', '2022-12-26 11:32:01.168', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('5002', null, 'assignee', '1', '2560', '2022-12-26 18:54:38.616', null, null, null, null, null); +insert into `act_hi_identitylink` (`id_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `create_time_`, `proc_inst_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('5004', null, 'participant', 'admin', null, '2022-12-26 18:54:38.671', '2523', null, null, null, null); +commit; + +-- ---------------------------- +-- table structure for act_hi_procinst +-- ---------------------------- +drop table if exists `act_hi_procinst`; +create table `act_hi_procinst` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default '1', + `proc_inst_id_` varchar(64) collate utf8_bin not null, + `business_key_` varchar(255) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin not null, + `start_time_` datetime(3) not null, + `end_time_` datetime(3) default null, + `duration_` bigint(20) default null, + `start_user_id_` varchar(255) collate utf8_bin default null, + `start_act_id_` varchar(255) collate utf8_bin default null, + `end_act_id_` varchar(255) collate utf8_bin default null, + `super_process_instance_id_` varchar(64) collate utf8_bin default null, + `delete_reason_` varchar(4000) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `name_` varchar(255) collate utf8_bin default null, + `callback_id_` varchar(255) collate utf8_bin default null, + `callback_type_` varchar(255) collate utf8_bin default null, + `reference_id_` varchar(255) collate utf8_bin default null, + `reference_type_` varchar(255) collate utf8_bin default null, + `propagated_stage_inst_id_` varchar(255) collate utf8_bin default null, + `business_status_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + unique key `proc_inst_id_` (`proc_inst_id_`), + key `act_idx_hi_pro_inst_end` (`end_time_`), + key `act_idx_hi_pro_i_buskey` (`business_key_`), + key `act_idx_hi_pro_super_procinst` (`super_process_instance_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_procinst +-- ---------------------------- +begin; +insert into `act_hi_procinst` (`id_`, `rev_`, `proc_inst_id_`, `business_key_`, `proc_def_id_`, `start_time_`, `end_time_`, `duration_`, `start_user_id_`, `start_act_id_`, `end_act_id_`, `super_process_instance_id_`, `delete_reason_`, `tenant_id_`, `name_`, `callback_id_`, `callback_type_`, `reference_id_`, `reference_type_`, `propagated_stage_inst_id_`, `business_status_`) values ('2523', 2, '2523', null, 'flow_ks2lyz4c:2:2522', '2022-12-26 11:28:09.658', '2022-12-26 18:54:38.715', 26789057, '1', 'start_event', 'event_0pucu17', null, null, '', null, null, null, null, null, null, null); +insert into `act_hi_procinst` (`id_`, `rev_`, `proc_inst_id_`, `business_key_`, `proc_def_id_`, `start_time_`, `end_time_`, `duration_`, `start_user_id_`, `start_act_id_`, `end_act_id_`, `super_process_instance_id_`, `delete_reason_`, `tenant_id_`, `name_`, `callback_id_`, `callback_type_`, `reference_id_`, `reference_type_`, `propagated_stage_inst_id_`, `business_status_`) values ('2563', 1, '2563', null, 'flow_ks2lyz4c:2:2522', '2022-12-26 11:31:33.717', null, null, '1', 'start_event', null, null, null, '', null, null, null, null, null, null, null); +commit; + +-- ---------------------------- +-- table structure for act_hi_taskinst +-- ---------------------------- +drop table if exists `act_hi_taskinst`; +create table `act_hi_taskinst` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default '1', + `proc_def_id_` varchar(64) collate utf8_bin default null, + `task_def_id_` varchar(64) collate utf8_bin default null, + `task_def_key_` varchar(255) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `propagated_stage_inst_id_` varchar(255) collate utf8_bin default null, + `name_` varchar(255) collate utf8_bin default null, + `parent_task_id_` varchar(64) collate utf8_bin default null, + `description_` varchar(4000) collate utf8_bin default null, + `owner_` varchar(255) collate utf8_bin default null, + `assignee_` varchar(255) collate utf8_bin default null, + `start_time_` datetime(3) not null, + `claim_time_` datetime(3) default null, + `end_time_` datetime(3) default null, + `duration_` bigint(20) default null, + `delete_reason_` varchar(4000) collate utf8_bin default null, + `priority_` int(11) default null, + `due_date_` datetime(3) default null, + `form_key_` varchar(255) collate utf8_bin default null, + `category_` varchar(255) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `last_updated_time_` datetime(3) default null, + primary key (`id_`), + key `act_idx_hi_task_scope` (`scope_id_`,`scope_type_`), + key `act_idx_hi_task_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_hi_task_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_idx_hi_task_inst_procinst` (`proc_inst_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_taskinst +-- ---------------------------- +begin; +insert into `act_hi_taskinst` (`id_`, `rev_`, `proc_def_id_`, `task_def_id_`, `task_def_key_`, `proc_inst_id_`, `execution_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`, `propagated_stage_inst_id_`, `name_`, `parent_task_id_`, `description_`, `owner_`, `assignee_`, `start_time_`, `claim_time_`, `end_time_`, `duration_`, `delete_reason_`, `priority_`, `due_date_`, `form_key_`, `category_`, `tenant_id_`, `last_updated_time_`) values ('2536', 3, 'flow_ks2lyz4c:2:2522', null, 'activity_1qg9oga', '2523', '2532', null, null, null, null, null, '行政', null, null, null, '1', '2022-12-26 11:28:09.659', null, '2022-12-26 11:29:12.964', 63305, null, 50, null, null, null, '', '2022-12-26 11:29:12.964'); +insert into `act_hi_taskinst` (`id_`, `rev_`, `proc_def_id_`, `task_def_id_`, `task_def_key_`, `proc_inst_id_`, `execution_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`, `propagated_stage_inst_id_`, `name_`, `parent_task_id_`, `description_`, `owner_`, `assignee_`, `start_time_`, `claim_time_`, `end_time_`, `duration_`, `delete_reason_`, `priority_`, `due_date_`, `form_key_`, `category_`, `tenant_id_`, `last_updated_time_`) values ('2560', 3, 'flow_ks2lyz4c:2:2522', null, 'activity_1m9b8mu', '2523', '2532', null, null, null, null, null, '老板', null, null, null, '1', '2022-12-26 11:29:12.969', null, '2022-12-26 18:54:38.676', 26725707, null, 50, null, null, null, '', '2022-12-26 18:54:38.676'); +insert into `act_hi_taskinst` (`id_`, `rev_`, `proc_def_id_`, `task_def_id_`, `task_def_key_`, `proc_inst_id_`, `execution_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`, `propagated_stage_inst_id_`, `name_`, `parent_task_id_`, `description_`, `owner_`, `assignee_`, `start_time_`, `claim_time_`, `end_time_`, `duration_`, `delete_reason_`, `priority_`, `due_date_`, `form_key_`, `category_`, `tenant_id_`, `last_updated_time_`) values ('2576', 3, 'flow_ks2lyz4c:2:2522', null, 'activity_1qg9oga', '2563', '2572', null, null, null, null, null, '行政', null, null, null, '2', '2022-12-26 11:31:33.718', null, '2022-12-26 11:32:01.163', 27445, null, 50, null, null, null, '', '2022-12-26 11:32:01.163'); +insert into `act_hi_taskinst` (`id_`, `rev_`, `proc_def_id_`, `task_def_id_`, `task_def_key_`, `proc_inst_id_`, `execution_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`, `propagated_stage_inst_id_`, `name_`, `parent_task_id_`, `description_`, `owner_`, `assignee_`, `start_time_`, `claim_time_`, `end_time_`, `duration_`, `delete_reason_`, `priority_`, `due_date_`, `form_key_`, `category_`, `tenant_id_`, `last_updated_time_`) values ('2600', 1, 'flow_ks2lyz4c:2:2522', null, 'activity_1m9b8mu', '2563', '2572', null, null, null, null, null, '老板', null, null, null, null, '2022-12-26 11:32:01.167', null, null, null, null, 50, null, null, null, '', '2022-12-26 11:32:01.167'); +commit; + +-- ---------------------------- +-- table structure for act_hi_tsk_log +-- ---------------------------- +drop table if exists `act_hi_tsk_log`; +create table `act_hi_tsk_log` ( + `id_` bigint(20) not null auto_increment, + `type_` varchar(64) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin not null, + `time_stamp_` timestamp(3) not null default current_timestamp(3) on update current_timestamp(3), + `user_id_` varchar(255) collate utf8_bin default null, + `data_` varchar(4000) collate utf8_bin default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_tsk_log +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_hi_varinst +-- ---------------------------- +drop table if exists `act_hi_varinst`; +create table `act_hi_varinst` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default '1', + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `name_` varchar(255) collate utf8_bin not null, + `var_type_` varchar(100) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `bytearray_id_` varchar(64) collate utf8_bin default null, + `double_` double default null, + `long_` bigint(20) default null, + `text_` varchar(4000) collate utf8_bin default null, + `text2_` varchar(4000) collate utf8_bin default null, + `create_time_` datetime(3) default null, + `last_updated_time_` datetime(3) default null, + primary key (`id_`), + key `act_idx_hi_procvar_name_type` (`name_`,`var_type_`), + key `act_idx_hi_var_scope_id_type` (`scope_id_`,`scope_type_`), + key `act_idx_hi_var_sub_id_type` (`sub_scope_id_`,`scope_type_`), + key `act_idx_hi_procvar_proc_inst` (`proc_inst_id_`), + key `act_idx_hi_procvar_task_id` (`task_id_`), + key `act_idx_hi_procvar_exe` (`execution_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_hi_varinst +-- ---------------------------- +begin; +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2525', 0, '2523', '2523', null, 'field101', 'string', null, null, null, null, null, null, '测试', null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2526', 0, '2523', '2523', null, 'day', 'string', null, null, null, null, null, null, '3', null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2527', 0, '2523', '2523', null, 'field102', 'string', null, null, null, null, null, null, 'test', null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2529', 0, '2523', '2523', null, 'variables', 'serializable', null, null, null, '2530', null, null, null, null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2531', 0, '2523', '2523', null, 'initiator', 'long', null, null, null, null, null, 1, '1', null, '2022-12-26 11:28:09.659', '2022-12-26 11:28:09.659'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2545', 1, '2523', '2523', null, 'fields', 'serializable', null, null, null, '2546', null, null, null, null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.656'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2547', 1, '2523', '2523', null, 'formref', 'string', null, null, null, null, null, null, 'elform', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.659'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2548', 1, '2523', '2523', null, 'formmodel', 'string', null, null, null, null, null, null, 'formdata', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.661'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2549', 1, '2523', '2523', null, 'size', 'string', null, null, null, null, null, null, 'medium', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.662'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2550', 1, '2523', '2523', null, 'labelposition', 'string', null, null, null, null, null, null, 'right', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.663'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2551', 1, '2523', '2523', null, 'labelwidth', 'integer', null, null, null, null, null, 100, '100', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.665'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2552', 1, '2523', '2523', null, 'formrules', 'string', null, null, null, null, null, null, 'rules', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.665'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2553', 1, '2523', '2523', null, 'gutter', 'integer', null, null, null, null, null, 15, '15', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.666'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2554', 1, '2523', '2523', null, 'disabled', 'boolean', null, null, null, null, null, 1, null, null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.667'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2555', 1, '2523', '2523', null, 'span', 'integer', null, null, null, null, null, 24, '24', null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.668'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2556', 1, '2523', '2523', null, 'formbtns', 'boolean', null, null, null, null, null, 0, null, null, '2022-12-26 11:29:12.962', '2022-12-26 18:54:38.669'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2557', 0, '2523', '2523', null, 'approval', 'string', null, null, null, null, null, null, '1,2', null, '2022-12-26 11:29:12.963', '2022-12-26 11:29:12.963'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2565', 0, '2563', '2563', null, 'field101', 'string', null, null, null, null, null, null, 'jinttt', null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2566', 0, '2563', '2563', null, 'day', 'string', null, null, null, null, null, null, '4', null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2567', 0, '2563', '2563', null, 'field102', 'string', null, null, null, null, null, null, 'ttt', null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2569', 0, '2563', '2563', null, 'variables', 'serializable', null, null, null, '2570', null, null, null, null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2571', 0, '2563', '2563', null, 'initiator', 'long', null, null, null, null, null, 1, '1', null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2585', 0, '2563', '2563', null, 'fields', 'serializable', null, null, null, '2586', null, null, null, null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2587', 0, '2563', '2563', null, 'formref', 'string', null, null, null, null, null, null, 'elform', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2588', 0, '2563', '2563', null, 'formmodel', 'string', null, null, null, null, null, null, 'formdata', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2589', 0, '2563', '2563', null, 'size', 'string', null, null, null, null, null, null, 'medium', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2590', 0, '2563', '2563', null, 'labelposition', 'string', null, null, null, null, null, null, 'right', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2591', 0, '2563', '2563', null, 'labelwidth', 'integer', null, null, null, null, null, 100, '100', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2592', 0, '2563', '2563', null, 'formrules', 'string', null, null, null, null, null, null, 'rules', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2593', 0, '2563', '2563', null, 'gutter', 'integer', null, null, null, null, null, 15, '15', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2594', 0, '2563', '2563', null, 'disabled', 'boolean', null, null, null, null, null, 1, null, null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2595', 0, '2563', '2563', null, 'span', 'integer', null, null, null, null, null, 24, '24', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2596', 0, '2563', '2563', null, 'formbtns', 'boolean', null, null, null, null, null, 0, null, null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +insert into `act_hi_varinst` (`id_`, `rev_`, `proc_inst_id_`, `execution_id_`, `task_id_`, `name_`, `var_type_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`, `create_time_`, `last_updated_time_`) values ('2597', 0, '2563', '2563', null, 'approval', 'string', null, null, null, null, null, null, '2', null, '2022-12-26 11:32:01.162', '2022-12-26 11:32:01.162'); +commit; + +-- ---------------------------- +-- table structure for act_id_bytearray +-- ---------------------------- +drop table if exists `act_id_bytearray`; +create table `act_id_bytearray` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `name_` varchar(255) collate utf8_bin default null, + `bytes_` longblob, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_bytearray +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_group +-- ---------------------------- +drop table if exists `act_id_group`; +create table `act_id_group` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `name_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin default null, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_group +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_info +-- ---------------------------- +drop table if exists `act_id_info`; +create table `act_id_info` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `user_id_` varchar(64) collate utf8_bin default null, + `type_` varchar(64) collate utf8_bin default null, + `key_` varchar(255) collate utf8_bin default null, + `value_` varchar(255) collate utf8_bin default null, + `password_` longblob, + `parent_id_` varchar(255) collate utf8_bin default null, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_info +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_membership +-- ---------------------------- +drop table if exists `act_id_membership`; +create table `act_id_membership` ( + `user_id_` varchar(64) collate utf8_bin not null, + `group_id_` varchar(64) collate utf8_bin not null, + primary key (`user_id_`,`group_id_`), + key `act_fk_memb_group` (`group_id_`), + constraint `act_fk_memb_group` foreign key (`group_id_`) references `act_id_group` (`id_`), + constraint `act_fk_memb_user` foreign key (`user_id_`) references `act_id_user` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_membership +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_priv +-- ---------------------------- +drop table if exists `act_id_priv`; +create table `act_id_priv` ( + `id_` varchar(64) collate utf8_bin not null, + `name_` varchar(255) collate utf8_bin not null, + primary key (`id_`), + unique key `act_uniq_priv_name` (`name_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_priv +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_priv_mapping +-- ---------------------------- +drop table if exists `act_id_priv_mapping`; +create table `act_id_priv_mapping` ( + `id_` varchar(64) collate utf8_bin not null, + `priv_id_` varchar(64) collate utf8_bin not null, + `user_id_` varchar(255) collate utf8_bin default null, + `group_id_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_fk_priv_mapping` (`priv_id_`), + key `act_idx_priv_user` (`user_id_`), + key `act_idx_priv_group` (`group_id_`), + constraint `act_fk_priv_mapping` foreign key (`priv_id_`) references `act_id_priv` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_priv_mapping +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_property +-- ---------------------------- +drop table if exists `act_id_property`; +create table `act_id_property` ( + `name_` varchar(64) collate utf8_bin not null, + `value_` varchar(300) collate utf8_bin default null, + `rev_` int(11) default null, + primary key (`name_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_property +-- ---------------------------- +begin; +insert into `act_id_property` (`name_`, `value_`, `rev_`) values ('schema.version', '6.8.0.0', 1); +commit; + +-- ---------------------------- +-- table structure for act_id_token +-- ---------------------------- +drop table if exists `act_id_token`; +create table `act_id_token` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `token_value_` varchar(255) collate utf8_bin default null, + `token_date_` timestamp(3) not null default current_timestamp(3) on update current_timestamp(3), + `ip_address_` varchar(255) collate utf8_bin default null, + `user_agent_` varchar(255) collate utf8_bin default null, + `user_id_` varchar(255) collate utf8_bin default null, + `token_data_` varchar(2000) collate utf8_bin default null, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_token +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_id_user +-- ---------------------------- +drop table if exists `act_id_user`; +create table `act_id_user` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `first_` varchar(255) collate utf8_bin default null, + `last_` varchar(255) collate utf8_bin default null, + `display_name_` varchar(255) collate utf8_bin default null, + `email_` varchar(255) collate utf8_bin default null, + `pwd_` varchar(255) collate utf8_bin default null, + `picture_id_` varchar(64) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_id_user +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_procdef_info +-- ---------------------------- +drop table if exists `act_procdef_info`; +create table `act_procdef_info` ( + `id_` varchar(64) collate utf8_bin not null, + `proc_def_id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `info_json_id_` varchar(64) collate utf8_bin default null, + primary key (`id_`), + unique key `act_uniq_info_procdef` (`proc_def_id_`), + key `act_idx_info_procdef` (`proc_def_id_`), + key `act_fk_info_json_ba` (`info_json_id_`), + constraint `act_fk_info_json_ba` foreign key (`info_json_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_info_procdef` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_procdef_info +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_re_deployment +-- ---------------------------- +drop table if exists `act_re_deployment`; +create table `act_re_deployment` ( + `id_` varchar(64) collate utf8_bin not null, + `name_` varchar(255) collate utf8_bin default null, + `category_` varchar(255) collate utf8_bin default null, + `key_` varchar(255) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `deploy_time_` timestamp(3) null default null, + `derived_from_` varchar(64) collate utf8_bin default null, + `derived_from_root_` varchar(64) collate utf8_bin default null, + `parent_deployment_id_` varchar(255) collate utf8_bin default null, + `engine_version_` varchar(255) collate utf8_bin default null, + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_re_deployment +-- ---------------------------- +begin; +insert into `act_re_deployment` (`id_`, `name_`, `category_`, `key_`, `tenant_id_`, `deploy_time_`, `derived_from_`, `derived_from_root_`, `parent_deployment_id_`, `engine_version_`) values ('2519', 'flow_a9z4w99d', 'oa', null, '', '2022-12-26 11:27:34.708', null, null, '2519', null); +commit; + +-- ---------------------------- +-- table structure for act_re_model +-- ---------------------------- +drop table if exists `act_re_model`; +create table `act_re_model` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `name_` varchar(255) collate utf8_bin default null, + `key_` varchar(255) collate utf8_bin default null, + `category_` varchar(255) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `last_update_time_` timestamp(3) null default null, + `version_` int(11) default null, + `meta_info_` varchar(4000) collate utf8_bin default null, + `deployment_id_` varchar(64) collate utf8_bin default null, + `editor_source_value_id_` varchar(64) collate utf8_bin default null, + `editor_source_extra_value_id_` varchar(64) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_fk_model_source` (`editor_source_value_id_`), + key `act_fk_model_source_extra` (`editor_source_extra_value_id_`), + key `act_fk_model_deployment` (`deployment_id_`), + constraint `act_fk_model_deployment` foreign key (`deployment_id_`) references `act_re_deployment` (`id_`), + constraint `act_fk_model_source` foreign key (`editor_source_value_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_model_source_extra` foreign key (`editor_source_extra_value_id_`) references `act_ge_bytearray` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_re_model +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_re_procdef +-- ---------------------------- +drop table if exists `act_re_procdef`; +create table `act_re_procdef` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `category_` varchar(255) collate utf8_bin default null, + `name_` varchar(255) collate utf8_bin default null, + `key_` varchar(255) collate utf8_bin not null, + `version_` int(11) not null, + `deployment_id_` varchar(64) collate utf8_bin default null, + `resource_name_` varchar(4000) collate utf8_bin default null, + `dgrm_resource_name_` varchar(4000) collate utf8_bin default null, + `description_` varchar(4000) collate utf8_bin default null, + `has_start_form_key_` tinyint(4) default null, + `has_graphical_notation_` tinyint(4) default null, + `suspension_state_` int(11) default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `engine_version_` varchar(255) collate utf8_bin default null, + `derived_from_` varchar(64) collate utf8_bin default null, + `derived_from_root_` varchar(64) collate utf8_bin default null, + `derived_version_` int(11) not null default '0', + primary key (`id_`), + unique key `act_uniq_procdef` (`key_`,`version_`,`derived_version_`,`tenant_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_re_procdef +-- ---------------------------- +begin; +insert into `act_re_procdef` (`id_`, `rev_`, `category_`, `name_`, `key_`, `version_`, `deployment_id_`, `resource_name_`, `dgrm_resource_name_`, `description_`, `has_start_form_key_`, `has_graphical_notation_`, `suspension_state_`, `tenant_id_`, `engine_version_`, `derived_from_`, `derived_from_root_`, `derived_version_`) values ('flow_ks2lyz4c:2:2522', 2, 'oa', 'flow_a9z4w99d', 'flow_ks2lyz4c', 2, '2519', 'flow_a9z4w99d.bpmn', 'flow_a9z4w99d.flow_ks2lyz4c.png', null, 0, 1, 1, '', null, null, null, 0); +commit; + +-- ---------------------------- +-- table structure for act_ru_actinst +-- ---------------------------- +drop table if exists `act_ru_actinst`; +create table `act_ru_actinst` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default '1', + `proc_def_id_` varchar(64) collate utf8_bin not null, + `proc_inst_id_` varchar(64) collate utf8_bin not null, + `execution_id_` varchar(64) collate utf8_bin not null, + `act_id_` varchar(255) collate utf8_bin not null, + `task_id_` varchar(64) collate utf8_bin default null, + `call_proc_inst_id_` varchar(64) collate utf8_bin default null, + `act_name_` varchar(255) collate utf8_bin default null, + `act_type_` varchar(255) collate utf8_bin not null, + `assignee_` varchar(255) collate utf8_bin default null, + `start_time_` datetime(3) not null, + `end_time_` datetime(3) default null, + `duration_` bigint(20) default null, + `transaction_order_` int(11) default null, + `delete_reason_` varchar(4000) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_ru_acti_start` (`start_time_`), + key `act_idx_ru_acti_end` (`end_time_`), + key `act_idx_ru_acti_proc` (`proc_inst_id_`), + key `act_idx_ru_acti_proc_act` (`proc_inst_id_`,`act_id_`), + key `act_idx_ru_acti_exec` (`execution_id_`), + key `act_idx_ru_acti_exec_act` (`execution_id_`,`act_id_`), + key `act_idx_ru_acti_task` (`task_id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_actinst +-- ---------------------------- +begin; +insert into `act_ru_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `duration_`, `transaction_order_`, `delete_reason_`, `tenant_id_`) values ('2573', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'start_event', null, null, '开始', 'startevent', null, '2022-12-26 11:31:33.717', '2022-12-26 11:31:33.717', 0, 1, null, ''); +insert into `act_ru_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `duration_`, `transaction_order_`, `delete_reason_`, `tenant_id_`) values ('2574', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'flow_1tumnt6', null, null, null, 'sequenceflow', null, '2022-12-26 11:31:33.718', '2022-12-26 11:31:33.718', 0, 2, null, ''); +insert into `act_ru_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `duration_`, `transaction_order_`, `delete_reason_`, `tenant_id_`) values ('2575', 3, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'activity_1qg9oga', '2576', null, '行政', 'usertask', '2', '2022-12-26 11:31:33.718', '2022-12-26 11:32:01.166', 27448, 3, null, ''); +insert into `act_ru_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `duration_`, `transaction_order_`, `delete_reason_`, `tenant_id_`) values ('2598', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'flow_1xzsicg', null, null, null, 'sequenceflow', null, '2022-12-26 11:32:01.166', '2022-12-26 11:32:01.166', 0, 1, null, ''); +insert into `act_ru_actinst` (`id_`, `rev_`, `proc_def_id_`, `proc_inst_id_`, `execution_id_`, `act_id_`, `task_id_`, `call_proc_inst_id_`, `act_name_`, `act_type_`, `assignee_`, `start_time_`, `end_time_`, `duration_`, `transaction_order_`, `delete_reason_`, `tenant_id_`) values ('2599', 1, 'flow_ks2lyz4c:2:2522', '2563', '2572', 'activity_1m9b8mu', '2600', null, '老板', 'usertask', null, '2022-12-26 11:32:01.167', null, null, 2, null, ''); +commit; + +-- ---------------------------- +-- table structure for act_ru_deadletter_job +-- ---------------------------- +drop table if exists `act_ru_deadletter_job`; +create table `act_ru_deadletter_job` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `category_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin not null, + `exclusive_` tinyint(1) default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `process_instance_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `element_id_` varchar(255) collate utf8_bin default null, + `element_name_` varchar(255) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `correlation_id_` varchar(255) collate utf8_bin default null, + `exception_stack_id_` varchar(64) collate utf8_bin default null, + `exception_msg_` varchar(4000) collate utf8_bin default null, + `duedate_` timestamp(3) null default null, + `repeat_` varchar(255) collate utf8_bin default null, + `handler_type_` varchar(255) collate utf8_bin default null, + `handler_cfg_` varchar(4000) collate utf8_bin default null, + `custom_values_id_` varchar(64) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_deadletter_job_exception_stack_id` (`exception_stack_id_`), + key `act_idx_deadletter_job_custom_values_id` (`custom_values_id_`), + key `act_idx_deadletter_job_correlation_id` (`correlation_id_`), + key `act_idx_djob_scope` (`scope_id_`,`scope_type_`), + key `act_idx_djob_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_djob_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_fk_deadletter_job_execution` (`execution_id_`), + key `act_fk_deadletter_job_process_instance` (`process_instance_id_`), + key `act_fk_deadletter_job_proc_def` (`proc_def_id_`), + constraint `act_fk_deadletter_job_custom_values` foreign key (`custom_values_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_deadletter_job_exception` foreign key (`exception_stack_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_deadletter_job_execution` foreign key (`execution_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_deadletter_job_process_instance` foreign key (`process_instance_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_deadletter_job_proc_def` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_deadletter_job +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_entitylink +-- ---------------------------- +drop table if exists `act_ru_entitylink`; +create table `act_ru_entitylink` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `create_time_` datetime(3) default null, + `link_type_` varchar(255) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `parent_element_id_` varchar(255) collate utf8_bin default null, + `ref_scope_id_` varchar(255) collate utf8_bin default null, + `ref_scope_type_` varchar(255) collate utf8_bin default null, + `ref_scope_definition_id_` varchar(255) collate utf8_bin default null, + `root_scope_id_` varchar(255) collate utf8_bin default null, + `root_scope_type_` varchar(255) collate utf8_bin default null, + `hierarchy_type_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_ent_lnk_scope` (`scope_id_`,`scope_type_`,`link_type_`), + key `act_idx_ent_lnk_ref_scope` (`ref_scope_id_`,`ref_scope_type_`,`link_type_`), + key `act_idx_ent_lnk_root_scope` (`root_scope_id_`,`root_scope_type_`,`link_type_`), + key `act_idx_ent_lnk_scope_def` (`scope_definition_id_`,`scope_type_`,`link_type_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_entitylink +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_event_subscr +-- ---------------------------- +drop table if exists `act_ru_event_subscr`; +create table `act_ru_event_subscr` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `event_type_` varchar(255) collate utf8_bin not null, + `event_name_` varchar(255) collate utf8_bin default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `activity_id_` varchar(64) collate utf8_bin default null, + `configuration_` varchar(255) collate utf8_bin default null, + `created_` timestamp(3) not null default current_timestamp(3), + `proc_def_id_` varchar(64) collate utf8_bin default null, + `sub_scope_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(64) collate utf8_bin default null, + `scope_definition_id_` varchar(64) collate utf8_bin default null, + `scope_type_` varchar(64) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `lock_time_` timestamp(3) null default null, + `lock_owner_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_event_subscr_config_` (`configuration_`), + key `act_fk_event_exec` (`execution_id_`), + key `act_idx_event_subscr_scoperef_` (`scope_id_`,`scope_type_`), + constraint `act_fk_event_exec` foreign key (`execution_id_`) references `act_ru_execution` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_event_subscr +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_execution +-- ---------------------------- +drop table if exists `act_ru_execution`; +create table `act_ru_execution` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `business_key_` varchar(255) collate utf8_bin default null, + `parent_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `super_exec_` varchar(64) collate utf8_bin default null, + `root_proc_inst_id_` varchar(64) collate utf8_bin default null, + `act_id_` varchar(255) collate utf8_bin default null, + `is_active_` tinyint(4) default null, + `is_concurrent_` tinyint(4) default null, + `is_scope_` tinyint(4) default null, + `is_event_scope_` tinyint(4) default null, + `is_mi_root_` tinyint(4) default null, + `suspension_state_` int(11) default null, + `cached_ent_state_` int(11) default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `name_` varchar(255) collate utf8_bin default null, + `start_act_id_` varchar(255) collate utf8_bin default null, + `start_time_` datetime(3) default null, + `start_user_id_` varchar(255) collate utf8_bin default null, + `lock_time_` timestamp(3) null default null, + `lock_owner_` varchar(255) collate utf8_bin default null, + `is_count_enabled_` tinyint(4) default null, + `evt_subscr_count_` int(11) default null, + `task_count_` int(11) default null, + `job_count_` int(11) default null, + `timer_job_count_` int(11) default null, + `susp_job_count_` int(11) default null, + `deadletter_job_count_` int(11) default null, + `external_worker_job_count_` int(11) default null, + `var_count_` int(11) default null, + `id_link_count_` int(11) default null, + `callback_id_` varchar(255) collate utf8_bin default null, + `callback_type_` varchar(255) collate utf8_bin default null, + `reference_id_` varchar(255) collate utf8_bin default null, + `reference_type_` varchar(255) collate utf8_bin default null, + `propagated_stage_inst_id_` varchar(255) collate utf8_bin default null, + `business_status_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_exec_buskey` (`business_key_`), + key `act_idc_exec_root` (`root_proc_inst_id_`), + key `act_idx_exec_ref_id_` (`reference_id_`), + key `act_fk_exe_procinst` (`proc_inst_id_`), + key `act_fk_exe_parent` (`parent_id_`), + key `act_fk_exe_super` (`super_exec_`), + key `act_fk_exe_procdef` (`proc_def_id_`), + constraint `act_fk_exe_parent` foreign key (`parent_id_`) references `act_ru_execution` (`id_`) on delete cascade, + constraint `act_fk_exe_procdef` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`), + constraint `act_fk_exe_procinst` foreign key (`proc_inst_id_`) references `act_ru_execution` (`id_`) on delete cascade on update cascade, + constraint `act_fk_exe_super` foreign key (`super_exec_`) references `act_ru_execution` (`id_`) on delete cascade +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_execution +-- ---------------------------- +begin; +insert into `act_ru_execution` (`id_`, `rev_`, `proc_inst_id_`, `business_key_`, `parent_id_`, `proc_def_id_`, `super_exec_`, `root_proc_inst_id_`, `act_id_`, `is_active_`, `is_concurrent_`, `is_scope_`, `is_event_scope_`, `is_mi_root_`, `suspension_state_`, `cached_ent_state_`, `tenant_id_`, `name_`, `start_act_id_`, `start_time_`, `start_user_id_`, `lock_time_`, `lock_owner_`, `is_count_enabled_`, `evt_subscr_count_`, `task_count_`, `job_count_`, `timer_job_count_`, `susp_job_count_`, `deadletter_job_count_`, `external_worker_job_count_`, `var_count_`, `id_link_count_`, `callback_id_`, `callback_type_`, `reference_id_`, `reference_type_`, `propagated_stage_inst_id_`, `business_status_`) values ('2563', 1, '2563', null, null, 'flow_ks2lyz4c:2:2522', null, '2563', null, 1, 0, 1, 0, 0, 1, null, '', null, 'start_event', '2022-12-26 11:31:33.717', '1', null, null, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null); +insert into `act_ru_execution` (`id_`, `rev_`, `proc_inst_id_`, `business_key_`, `parent_id_`, `proc_def_id_`, `super_exec_`, `root_proc_inst_id_`, `act_id_`, `is_active_`, `is_concurrent_`, `is_scope_`, `is_event_scope_`, `is_mi_root_`, `suspension_state_`, `cached_ent_state_`, `tenant_id_`, `name_`, `start_act_id_`, `start_time_`, `start_user_id_`, `lock_time_`, `lock_owner_`, `is_count_enabled_`, `evt_subscr_count_`, `task_count_`, `job_count_`, `timer_job_count_`, `susp_job_count_`, `deadletter_job_count_`, `external_worker_job_count_`, `var_count_`, `id_link_count_`, `callback_id_`, `callback_type_`, `reference_id_`, `reference_type_`, `propagated_stage_inst_id_`, `business_status_`) values ('2572', 2, '2563', null, '2563', 'flow_ks2lyz4c:2:2522', null, '2563', 'activity_1m9b8mu', 1, 0, 0, 0, 0, 1, null, '', null, null, '2022-12-26 11:31:33.717', null, null, null, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null); +commit; + +-- ---------------------------- +-- table structure for act_ru_external_job +-- ---------------------------- +drop table if exists `act_ru_external_job`; +create table `act_ru_external_job` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `category_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin not null, + `lock_exp_time_` timestamp(3) null default null, + `lock_owner_` varchar(255) collate utf8_bin default null, + `exclusive_` tinyint(1) default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `process_instance_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `element_id_` varchar(255) collate utf8_bin default null, + `element_name_` varchar(255) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `correlation_id_` varchar(255) collate utf8_bin default null, + `retries_` int(11) default null, + `exception_stack_id_` varchar(64) collate utf8_bin default null, + `exception_msg_` varchar(4000) collate utf8_bin default null, + `duedate_` timestamp(3) null default null, + `repeat_` varchar(255) collate utf8_bin default null, + `handler_type_` varchar(255) collate utf8_bin default null, + `handler_cfg_` varchar(4000) collate utf8_bin default null, + `custom_values_id_` varchar(64) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_external_job_exception_stack_id` (`exception_stack_id_`), + key `act_idx_external_job_custom_values_id` (`custom_values_id_`), + key `act_idx_external_job_correlation_id` (`correlation_id_`), + key `act_idx_ejob_scope` (`scope_id_`,`scope_type_`), + key `act_idx_ejob_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_ejob_scope_def` (`scope_definition_id_`,`scope_type_`), + constraint `act_fk_external_job_custom_values` foreign key (`custom_values_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_external_job_exception` foreign key (`exception_stack_id_`) references `act_ge_bytearray` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_external_job +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_history_job +-- ---------------------------- +drop table if exists `act_ru_history_job`; +create table `act_ru_history_job` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `lock_exp_time_` timestamp(3) null default null, + `lock_owner_` varchar(255) collate utf8_bin default null, + `retries_` int(11) default null, + `exception_stack_id_` varchar(64) collate utf8_bin default null, + `exception_msg_` varchar(4000) collate utf8_bin default null, + `handler_type_` varchar(255) collate utf8_bin default null, + `handler_cfg_` varchar(4000) collate utf8_bin default null, + `custom_values_id_` varchar(64) collate utf8_bin default null, + `adv_handler_cfg_id_` varchar(64) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_history_job +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_identitylink +-- ---------------------------- +drop table if exists `act_ru_identitylink`; +create table `act_ru_identitylink` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `group_id_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin default null, + `user_id_` varchar(255) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_ident_lnk_user` (`user_id_`), + key `act_idx_ident_lnk_group` (`group_id_`), + key `act_idx_ident_lnk_scope` (`scope_id_`,`scope_type_`), + key `act_idx_ident_lnk_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_ident_lnk_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_idx_athrz_procedef` (`proc_def_id_`), + key `act_fk_tskass_task` (`task_id_`), + key `act_fk_idl_procinst` (`proc_inst_id_`), + constraint `act_fk_athrz_procedef` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`), + constraint `act_fk_idl_procinst` foreign key (`proc_inst_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_tskass_task` foreign key (`task_id_`) references `act_ru_task` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_identitylink +-- ---------------------------- +begin; +insert into `act_ru_identitylink` (`id_`, `rev_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `proc_inst_id_`, `proc_def_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2564', 1, null, 'starter', '1', null, '2563', null, null, null, null, null); +insert into `act_ru_identitylink` (`id_`, `rev_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `proc_inst_id_`, `proc_def_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2578', 1, null, 'participant', '1', null, '2563', null, null, null, null, null); +insert into `act_ru_identitylink` (`id_`, `rev_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `proc_inst_id_`, `proc_def_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2580', 1, null, 'participant', '2', null, '2563', null, null, null, null, null); +insert into `act_ru_identitylink` (`id_`, `rev_`, `group_id_`, `type_`, `user_id_`, `task_id_`, `proc_inst_id_`, `proc_def_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`) values ('2601', 1, '2', 'candidate', null, '2600', null, null, null, null, null, null); +commit; + +-- ---------------------------- +-- table structure for act_ru_job +-- ---------------------------- +drop table if exists `act_ru_job`; +create table `act_ru_job` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `category_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin not null, + `lock_exp_time_` timestamp(3) null default null, + `lock_owner_` varchar(255) collate utf8_bin default null, + `exclusive_` tinyint(1) default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `process_instance_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `element_id_` varchar(255) collate utf8_bin default null, + `element_name_` varchar(255) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `correlation_id_` varchar(255) collate utf8_bin default null, + `retries_` int(11) default null, + `exception_stack_id_` varchar(64) collate utf8_bin default null, + `exception_msg_` varchar(4000) collate utf8_bin default null, + `duedate_` timestamp(3) null default null, + `repeat_` varchar(255) collate utf8_bin default null, + `handler_type_` varchar(255) collate utf8_bin default null, + `handler_cfg_` varchar(4000) collate utf8_bin default null, + `custom_values_id_` varchar(64) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_job_exception_stack_id` (`exception_stack_id_`), + key `act_idx_job_custom_values_id` (`custom_values_id_`), + key `act_idx_job_correlation_id` (`correlation_id_`), + key `act_idx_job_scope` (`scope_id_`,`scope_type_`), + key `act_idx_job_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_job_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_fk_job_execution` (`execution_id_`), + key `act_fk_job_process_instance` (`process_instance_id_`), + key `act_fk_job_proc_def` (`proc_def_id_`), + constraint `act_fk_job_custom_values` foreign key (`custom_values_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_job_exception` foreign key (`exception_stack_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_job_execution` foreign key (`execution_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_job_process_instance` foreign key (`process_instance_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_job_proc_def` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_job +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_suspended_job +-- ---------------------------- +drop table if exists `act_ru_suspended_job`; +create table `act_ru_suspended_job` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `category_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin not null, + `exclusive_` tinyint(1) default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `process_instance_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `element_id_` varchar(255) collate utf8_bin default null, + `element_name_` varchar(255) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `correlation_id_` varchar(255) collate utf8_bin default null, + `retries_` int(11) default null, + `exception_stack_id_` varchar(64) collate utf8_bin default null, + `exception_msg_` varchar(4000) collate utf8_bin default null, + `duedate_` timestamp(3) null default null, + `repeat_` varchar(255) collate utf8_bin default null, + `handler_type_` varchar(255) collate utf8_bin default null, + `handler_cfg_` varchar(4000) collate utf8_bin default null, + `custom_values_id_` varchar(64) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_suspended_job_exception_stack_id` (`exception_stack_id_`), + key `act_idx_suspended_job_custom_values_id` (`custom_values_id_`), + key `act_idx_suspended_job_correlation_id` (`correlation_id_`), + key `act_idx_sjob_scope` (`scope_id_`,`scope_type_`), + key `act_idx_sjob_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_sjob_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_fk_suspended_job_execution` (`execution_id_`), + key `act_fk_suspended_job_process_instance` (`process_instance_id_`), + key `act_fk_suspended_job_proc_def` (`proc_def_id_`), + constraint `act_fk_suspended_job_custom_values` foreign key (`custom_values_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_suspended_job_exception` foreign key (`exception_stack_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_suspended_job_execution` foreign key (`execution_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_suspended_job_process_instance` foreign key (`process_instance_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_suspended_job_proc_def` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_suspended_job +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_task +-- ---------------------------- +drop table if exists `act_ru_task`; +create table `act_ru_task` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `task_def_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `propagated_stage_inst_id_` varchar(255) collate utf8_bin default null, + `name_` varchar(255) collate utf8_bin default null, + `parent_task_id_` varchar(64) collate utf8_bin default null, + `description_` varchar(4000) collate utf8_bin default null, + `task_def_key_` varchar(255) collate utf8_bin default null, + `owner_` varchar(255) collate utf8_bin default null, + `assignee_` varchar(255) collate utf8_bin default null, + `delegation_` varchar(64) collate utf8_bin default null, + `priority_` int(11) default null, + `create_time_` timestamp(3) null default null, + `due_date_` datetime(3) default null, + `category_` varchar(255) collate utf8_bin default null, + `suspension_state_` int(11) default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + `form_key_` varchar(255) collate utf8_bin default null, + `claim_time_` datetime(3) default null, + `is_count_enabled_` tinyint(4) default null, + `var_count_` int(11) default null, + `id_link_count_` int(11) default null, + `sub_task_count_` int(11) default null, + primary key (`id_`), + key `act_idx_task_create` (`create_time_`), + key `act_idx_task_scope` (`scope_id_`,`scope_type_`), + key `act_idx_task_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_task_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_fk_task_exe` (`execution_id_`), + key `act_fk_task_procinst` (`proc_inst_id_`), + key `act_fk_task_procdef` (`proc_def_id_`), + constraint `act_fk_task_exe` foreign key (`execution_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_task_procdef` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`), + constraint `act_fk_task_procinst` foreign key (`proc_inst_id_`) references `act_ru_execution` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_task +-- ---------------------------- +begin; +insert into `act_ru_task` (`id_`, `rev_`, `execution_id_`, `proc_inst_id_`, `proc_def_id_`, `task_def_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `scope_definition_id_`, `propagated_stage_inst_id_`, `name_`, `parent_task_id_`, `description_`, `task_def_key_`, `owner_`, `assignee_`, `delegation_`, `priority_`, `create_time_`, `due_date_`, `category_`, `suspension_state_`, `tenant_id_`, `form_key_`, `claim_time_`, `is_count_enabled_`, `var_count_`, `id_link_count_`, `sub_task_count_`) values ('2600', 1, '2572', '2563', 'flow_ks2lyz4c:2:2522', null, null, null, null, null, null, '老板', null, null, 'activity_1m9b8mu', null, null, null, 50, '2022-12-26 11:32:01.167', null, null, 1, '', null, null, 1, 0, 1, 0); +commit; + +-- ---------------------------- +-- table structure for act_ru_timer_job +-- ---------------------------- +drop table if exists `act_ru_timer_job`; +create table `act_ru_timer_job` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `category_` varchar(255) collate utf8_bin default null, + `type_` varchar(255) collate utf8_bin not null, + `lock_exp_time_` timestamp(3) null default null, + `lock_owner_` varchar(255) collate utf8_bin default null, + `exclusive_` tinyint(1) default null, + `execution_id_` varchar(64) collate utf8_bin default null, + `process_instance_id_` varchar(64) collate utf8_bin default null, + `proc_def_id_` varchar(64) collate utf8_bin default null, + `element_id_` varchar(255) collate utf8_bin default null, + `element_name_` varchar(255) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `scope_definition_id_` varchar(255) collate utf8_bin default null, + `correlation_id_` varchar(255) collate utf8_bin default null, + `retries_` int(11) default null, + `exception_stack_id_` varchar(64) collate utf8_bin default null, + `exception_msg_` varchar(4000) collate utf8_bin default null, + `duedate_` timestamp(3) null default null, + `repeat_` varchar(255) collate utf8_bin default null, + `handler_type_` varchar(255) collate utf8_bin default null, + `handler_cfg_` varchar(4000) collate utf8_bin default null, + `custom_values_id_` varchar(64) collate utf8_bin default null, + `create_time_` timestamp(3) null default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `act_idx_timer_job_exception_stack_id` (`exception_stack_id_`), + key `act_idx_timer_job_custom_values_id` (`custom_values_id_`), + key `act_idx_timer_job_correlation_id` (`correlation_id_`), + key `act_idx_timer_job_duedate` (`duedate_`), + key `act_idx_tjob_scope` (`scope_id_`,`scope_type_`), + key `act_idx_tjob_sub_scope` (`sub_scope_id_`,`scope_type_`), + key `act_idx_tjob_scope_def` (`scope_definition_id_`,`scope_type_`), + key `act_fk_timer_job_execution` (`execution_id_`), + key `act_fk_timer_job_process_instance` (`process_instance_id_`), + key `act_fk_timer_job_proc_def` (`proc_def_id_`), + constraint `act_fk_timer_job_custom_values` foreign key (`custom_values_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_timer_job_exception` foreign key (`exception_stack_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_timer_job_execution` foreign key (`execution_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_timer_job_process_instance` foreign key (`process_instance_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_timer_job_proc_def` foreign key (`proc_def_id_`) references `act_re_procdef` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_timer_job +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for act_ru_variable +-- ---------------------------- +drop table if exists `act_ru_variable`; +create table `act_ru_variable` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `type_` varchar(255) collate utf8_bin not null, + `name_` varchar(255) collate utf8_bin not null, + `execution_id_` varchar(64) collate utf8_bin default null, + `proc_inst_id_` varchar(64) collate utf8_bin default null, + `task_id_` varchar(64) collate utf8_bin default null, + `scope_id_` varchar(255) collate utf8_bin default null, + `sub_scope_id_` varchar(255) collate utf8_bin default null, + `scope_type_` varchar(255) collate utf8_bin default null, + `bytearray_id_` varchar(64) collate utf8_bin default null, + `double_` double default null, + `long_` bigint(20) default null, + `text_` varchar(4000) collate utf8_bin default null, + `text2_` varchar(4000) collate utf8_bin default null, + primary key (`id_`), + key `act_idx_ru_var_scope_id_type` (`scope_id_`,`scope_type_`), + key `act_idx_ru_var_sub_id_type` (`sub_scope_id_`,`scope_type_`), + key `act_fk_var_bytearray` (`bytearray_id_`), + key `act_idx_variable_task_id` (`task_id_`), + key `act_fk_var_exe` (`execution_id_`), + key `act_fk_var_procinst` (`proc_inst_id_`), + constraint `act_fk_var_bytearray` foreign key (`bytearray_id_`) references `act_ge_bytearray` (`id_`), + constraint `act_fk_var_exe` foreign key (`execution_id_`) references `act_ru_execution` (`id_`), + constraint `act_fk_var_procinst` foreign key (`proc_inst_id_`) references `act_ru_execution` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of act_ru_variable +-- ---------------------------- +begin; +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2565', 1, 'string', 'field101', '2563', '2563', null, null, null, null, null, null, null, 'jinttt', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2566', 1, 'string', 'day', '2563', '2563', null, null, null, null, null, null, null, '4', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2567', 1, 'string', 'field102', '2563', '2563', null, null, null, null, null, null, null, 'ttt', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2569', 1, 'serializable', 'variables', '2563', '2563', null, null, null, null, '2568', null, null, null, null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2571', 1, 'long', 'initiator', '2563', '2563', null, null, null, null, null, null, 1, '1', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2585', 1, 'serializable', 'fields', '2563', '2563', null, null, null, null, '2584', null, null, null, null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2587', 1, 'string', 'formref', '2563', '2563', null, null, null, null, null, null, null, 'elform', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2588', 1, 'string', 'formmodel', '2563', '2563', null, null, null, null, null, null, null, 'formdata', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2589', 1, 'string', 'size', '2563', '2563', null, null, null, null, null, null, null, 'medium', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2590', 1, 'string', 'labelposition', '2563', '2563', null, null, null, null, null, null, null, 'right', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2591', 1, 'integer', 'labelwidth', '2563', '2563', null, null, null, null, null, null, 100, '100', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2592', 1, 'string', 'formrules', '2563', '2563', null, null, null, null, null, null, null, 'rules', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2593', 1, 'integer', 'gutter', '2563', '2563', null, null, null, null, null, null, 15, '15', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2594', 1, 'boolean', 'disabled', '2563', '2563', null, null, null, null, null, null, 1, null, null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2595', 1, 'integer', 'span', '2563', '2563', null, null, null, null, null, null, 24, '24', null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2596', 1, 'boolean', 'formbtns', '2563', '2563', null, null, null, null, null, null, 0, null, null); +insert into `act_ru_variable` (`id_`, `rev_`, `type_`, `name_`, `execution_id_`, `proc_inst_id_`, `task_id_`, `scope_id_`, `sub_scope_id_`, `scope_type_`, `bytearray_id_`, `double_`, `long_`, `text_`, `text2_`) values ('2597', 1, 'string', 'approval', '2563', '2563', null, null, null, null, null, null, null, '2', null); +commit; + +-- ---------------------------- +-- table structure for flw_channel_definition +-- ---------------------------- +drop table if exists `flw_channel_definition`; +create table `flw_channel_definition` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `version_` int(11) default null, + `key_` varchar(255) default null, + `category_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `create_time_` datetime(3) default null, + `tenant_id_` varchar(255) default null, + `resource_name_` varchar(255) default null, + `description_` varchar(255) default null, + `type_` varchar(255) default null, + `implementation_` varchar(255) default null, + primary key (`id_`), + unique key `act_idx_channel_def_uniq` (`key_`,`version_`,`tenant_id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of flw_channel_definition +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for flw_event_definition +-- ---------------------------- +drop table if exists `flw_event_definition`; +create table `flw_event_definition` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `version_` int(11) default null, + `key_` varchar(255) default null, + `category_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `tenant_id_` varchar(255) default null, + `resource_name_` varchar(255) default null, + `description_` varchar(255) default null, + primary key (`id_`), + unique key `act_idx_event_def_uniq` (`key_`,`version_`,`tenant_id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of flw_event_definition +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for flw_event_deployment +-- ---------------------------- +drop table if exists `flw_event_deployment`; +create table `flw_event_deployment` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `category_` varchar(255) default null, + `deploy_time_` datetime(3) default null, + `tenant_id_` varchar(255) default null, + `parent_deployment_id_` varchar(255) default null, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of flw_event_deployment +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for flw_event_resource +-- ---------------------------- +drop table if exists `flw_event_resource`; +create table `flw_event_resource` ( + `id_` varchar(255) not null, + `name_` varchar(255) default null, + `deployment_id_` varchar(255) default null, + `resource_bytes_` longblob, + primary key (`id_`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of flw_event_resource +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for flw_ev_databasechangelog +-- ---------------------------- +drop table if exists `flw_ev_databasechangelog`; +create table `flw_ev_databasechangelog` ( + `id` varchar(255) not null, + `author` varchar(255) not null, + `filename` varchar(255) not null, + `dateexecuted` datetime not null, + `orderexecuted` int(11) not null, + `exectype` varchar(10) not null, + `md5sum` varchar(35) default null, + `description` varchar(255) default null, + `comments` varchar(255) default null, + `tag` varchar(255) default null, + `liquibase` varchar(20) default null, + `contexts` varchar(255) default null, + `labels` varchar(255) default null, + `deployment_id` varchar(10) default null +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of flw_ev_databasechangelog +-- ---------------------------- +begin; +insert into `flw_ev_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('1', 'flowable', 'org/flowable/eventregistry/db/liquibase/flowable-eventregistry-db-changelog.xml', '2022-12-11 17:28:49', 1, 'executed', '8:1b0c48c9cf7945be799d868a2626d687', 'createtable tablename=flw_event_deployment; createtable tablename=flw_event_resource; createtable tablename=flw_event_definition; createindex indexname=act_idx_event_def_uniq, tablename=flw_event_definition; createtable tablename=flw_channel_defin...', '', null, '4.3.5', null, null, '0750929197'); +insert into `flw_ev_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('2', 'flowable', 'org/flowable/eventregistry/db/liquibase/flowable-eventregistry-db-changelog.xml', '2022-12-11 17:28:49', 2, 'executed', '8:0ea825feb8e470558f0b5754352b9cda', 'addcolumn tablename=flw_channel_definition; addcolumn tablename=flw_channel_definition', '', null, '4.3.5', null, null, '0750929197'); +insert into `flw_ev_databasechangelog` (`id`, `author`, `filename`, `dateexecuted`, `orderexecuted`, `exectype`, `md5sum`, `description`, `comments`, `tag`, `liquibase`, `contexts`, `labels`, `deployment_id`) values ('3', 'flowable', 'org/flowable/eventregistry/db/liquibase/flowable-eventregistry-db-changelog.xml', '2022-12-11 17:28:49', 3, 'executed', '8:3c2bb293350b5cbe6504331980c9dcee', 'customchange', '', null, '4.3.5', null, null, '0750929197'); +commit; + +-- ---------------------------- +-- table structure for flw_ev_databasechangeloglock +-- ---------------------------- +drop table if exists `flw_ev_databasechangeloglock`; +create table `flw_ev_databasechangeloglock` ( + `id` int(11) not null, + `locked` bit(1) not null, + `lockgranted` datetime default null, + `lockedby` varchar(255) default null, + primary key (`id`) +) engine=innodb default charset=utf8mb4; + +-- ---------------------------- +-- records of flw_ev_databasechangeloglock +-- ---------------------------- +begin; +insert into `flw_ev_databasechangeloglock` (`id`, `locked`, `lockgranted`, `lockedby`) values (1, b'0', null, null); +commit; + +-- ---------------------------- +-- table structure for flw_ru_batch +-- ---------------------------- +drop table if exists `flw_ru_batch`; +create table `flw_ru_batch` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `type_` varchar(64) collate utf8_bin not null, + `search_key_` varchar(255) collate utf8_bin default null, + `search_key2_` varchar(255) collate utf8_bin default null, + `create_time_` datetime(3) not null, + `complete_time_` datetime(3) default null, + `status_` varchar(255) collate utf8_bin default null, + `batch_doc_id_` varchar(64) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of flw_ru_batch +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for flw_ru_batch_part +-- ---------------------------- +drop table if exists `flw_ru_batch_part`; +create table `flw_ru_batch_part` ( + `id_` varchar(64) collate utf8_bin not null, + `rev_` int(11) default null, + `batch_id_` varchar(64) collate utf8_bin default null, + `type_` varchar(64) collate utf8_bin not null, + `scope_id_` varchar(64) collate utf8_bin default null, + `sub_scope_id_` varchar(64) collate utf8_bin default null, + `scope_type_` varchar(64) collate utf8_bin default null, + `search_key_` varchar(255) collate utf8_bin default null, + `search_key2_` varchar(255) collate utf8_bin default null, + `create_time_` datetime(3) not null, + `complete_time_` datetime(3) default null, + `status_` varchar(255) collate utf8_bin default null, + `result_doc_id_` varchar(64) collate utf8_bin default null, + `tenant_id_` varchar(255) collate utf8_bin default '', + primary key (`id_`), + key `flw_idx_batch_part` (`batch_id_`), + constraint `flw_fk_batch_part_parent` foreign key (`batch_id_`) references `flw_ru_batch` (`id_`) +) engine=innodb default charset=utf8 collate=utf8_bin; + +-- ---------------------------- +-- records of flw_ru_batch_part +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_blob_triggers +-- ---------------------------- +drop table if exists `qrtz_blob_triggers`; +create table `qrtz_blob_triggers` ( + `sched_name` varchar(120) not null comment '调度名称', + `trigger_name` varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + `blob_data` blob comment '存放持久化trigger对象', + primary key (`sched_name`,`trigger_name`,`trigger_group`), + constraint `qrtz_blob_triggers_ibfk_1` foreign key (`sched_name`, `trigger_name`, `trigger_group`) references `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) +) engine=innodb default charset=utf8mb4 comment='blob类型的触发器表'; + +-- ---------------------------- +-- records of qrtz_blob_triggers +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_calendars +-- ---------------------------- +drop table if exists `qrtz_calendars`; +create table `qrtz_calendars` ( + `sched_name` varchar(120) not null comment '调度名称', + `calendar_name` varchar(200) not null comment '日历名称', + `calendar` blob not null comment '存放持久化calendar对象', + primary key (`sched_name`,`calendar_name`) +) engine=innodb default charset=utf8mb4 comment='日历信息表'; + +-- ---------------------------- +-- records of qrtz_calendars +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_cron_triggers +-- ---------------------------- +drop table if exists `qrtz_cron_triggers`; +create table `qrtz_cron_triggers` ( + `sched_name` varchar(120) not null comment '调度名称', + `trigger_name` varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + `cron_expression` varchar(200) not null comment 'cron表达式', + `time_zone_id` varchar(80) default null comment '时区', + primary key (`sched_name`,`trigger_name`,`trigger_group`), + constraint `qrtz_cron_triggers_ibfk_1` foreign key (`sched_name`, `trigger_name`, `trigger_group`) references `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) +) engine=innodb default charset=utf8mb4 comment='cron类型的触发器表'; + +-- ---------------------------- +-- records of qrtz_cron_triggers +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_fired_triggers +-- ---------------------------- +drop table if exists `qrtz_fired_triggers`; +create table `qrtz_fired_triggers` ( + `sched_name` varchar(120) not null comment '调度名称', + `entry_id` varchar(95) not null comment '调度器实例id', + `trigger_name` varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + `instance_name` varchar(200) not null comment '调度器实例名', + `fired_time` bigint(13) not null comment '触发的时间', + `sched_time` bigint(13) not null comment '定时器制定的时间', + `priority` int(11) not null comment '优先级', + `state` varchar(16) not null comment '状态', + `job_name` varchar(200) default null comment '任务名称', + `job_group` varchar(200) default null comment '任务组名', + `is_nonconcurrent` varchar(1) default null comment '是否并发', + `requests_recovery` varchar(1) default null comment '是否接受恢复执行', + primary key (`sched_name`,`entry_id`) +) engine=innodb default charset=utf8mb4 comment='已触发的触发器表'; + +-- ---------------------------- +-- records of qrtz_fired_triggers +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_job_details +-- ---------------------------- +drop table if exists `qrtz_job_details`; +create table `qrtz_job_details` ( + `sched_name` varchar(120) not null comment '调度名称', + `job_name` varchar(200) not null comment '任务名称', + `job_group` varchar(200) not null comment '任务组名', + `description` varchar(250) default null comment '相关介绍', + `job_class_name` varchar(250) not null comment '执行任务类名称', + `is_durable` varchar(1) not null comment '是否持久化', + `is_nonconcurrent` varchar(1) not null comment '是否并发', + `is_update_data` varchar(1) not null comment '是否更新数据', + `requests_recovery` varchar(1) not null comment '是否接受恢复执行', + `job_data` blob comment '存放持久化job对象', + primary key (`sched_name`,`job_name`,`job_group`) +) engine=innodb default charset=utf8mb4 comment='任务详细信息表'; + +-- ---------------------------- +-- records of qrtz_job_details +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_locks +-- ---------------------------- +drop table if exists `qrtz_locks`; +create table `qrtz_locks` ( + `sched_name` varchar(120) not null comment '调度名称', + `lock_name` varchar(40) not null comment '悲观锁名称', + primary key (`sched_name`,`lock_name`) +) engine=innodb default charset=utf8mb4 comment='存储的悲观锁信息表'; + +-- ---------------------------- +-- records of qrtz_locks +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_paused_trigger_grps +-- ---------------------------- +drop table if exists `qrtz_paused_trigger_grps`; +create table `qrtz_paused_trigger_grps` ( + `sched_name` varchar(120) not null comment '调度名称', + `trigger_group` varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + primary key (`sched_name`,`trigger_group`) +) engine=innodb default charset=utf8mb4 comment='暂停的触发器表'; + +-- ---------------------------- +-- records of qrtz_paused_trigger_grps +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_scheduler_state +-- ---------------------------- +drop table if exists `qrtz_scheduler_state`; +create table `qrtz_scheduler_state` ( + `sched_name` varchar(120) not null comment '调度名称', + `instance_name` varchar(200) not null comment '实例名称', + `last_checkin_time` bigint(13) not null comment '上次检查时间', + `checkin_interval` bigint(13) not null comment '检查间隔时间', + primary key (`sched_name`,`instance_name`) +) engine=innodb default charset=utf8mb4 comment='调度器状态表'; + +-- ---------------------------- +-- records of qrtz_scheduler_state +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_simple_triggers +-- ---------------------------- +drop table if exists `qrtz_simple_triggers`; +create table `qrtz_simple_triggers` ( + `sched_name` varchar(120) not null comment '调度名称', + `trigger_name` varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + `repeat_count` bigint(7) not null comment '重复的次数统计', + `repeat_interval` bigint(12) not null comment '重复的间隔时间', + `times_triggered` bigint(10) not null comment '已经触发的次数', + primary key (`sched_name`,`trigger_name`,`trigger_group`), + constraint `qrtz_simple_triggers_ibfk_1` foreign key (`sched_name`, `trigger_name`, `trigger_group`) references `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) +) engine=innodb default charset=utf8mb4 comment='简单触发器的信息表'; + +-- ---------------------------- +-- records of qrtz_simple_triggers +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_simprop_triggers +-- ---------------------------- +drop table if exists `qrtz_simprop_triggers`; +create table `qrtz_simprop_triggers` ( + `sched_name` varchar(120) not null comment '调度名称', + `trigger_name` varchar(200) not null comment 'qrtz_triggers表trigger_name的外键', + `trigger_group` varchar(200) not null comment 'qrtz_triggers表trigger_group的外键', + `str_prop_1` varchar(512) default null comment 'string类型的trigger的第一个参数', + `str_prop_2` varchar(512) default null comment 'string类型的trigger的第二个参数', + `str_prop_3` varchar(512) default null comment 'string类型的trigger的第三个参数', + `int_prop_1` int(11) default null comment 'int类型的trigger的第一个参数', + `int_prop_2` int(11) default null comment 'int类型的trigger的第二个参数', + `long_prop_1` bigint(20) default null comment 'long类型的trigger的第一个参数', + `long_prop_2` bigint(20) default null comment 'long类型的trigger的第二个参数', + `dec_prop_1` decimal(13,4) default null comment 'decimal类型的trigger的第一个参数', + `dec_prop_2` decimal(13,4) default null comment 'decimal类型的trigger的第二个参数', + `bool_prop_1` varchar(1) default null comment 'boolean类型的trigger的第一个参数', + `bool_prop_2` varchar(1) default null comment 'boolean类型的trigger的第二个参数', + primary key (`sched_name`,`trigger_name`,`trigger_group`), + constraint `qrtz_simprop_triggers_ibfk_1` foreign key (`sched_name`, `trigger_name`, `trigger_group`) references `qrtz_triggers` (`sched_name`, `trigger_name`, `trigger_group`) +) engine=innodb default charset=utf8mb4 comment='同步机制的行锁表'; + +-- ---------------------------- +-- records of qrtz_simprop_triggers +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for qrtz_triggers +-- ---------------------------- +drop table if exists `qrtz_triggers`; +create table `qrtz_triggers` ( + `sched_name` varchar(120) not null comment '调度名称', + `trigger_name` varchar(200) not null comment '触发器的名字', + `trigger_group` varchar(200) not null comment '触发器所属组的名字', + `job_name` varchar(200) not null comment 'qrtz_job_details表job_name的外键', + `job_group` varchar(200) not null comment 'qrtz_job_details表job_group的外键', + `description` varchar(250) default null comment '相关介绍', + `next_fire_time` bigint(13) default null comment '上一次触发时间(毫秒)', + `prev_fire_time` bigint(13) default null comment '下一次触发时间(默认为-1表示不触发)', + `priority` int(11) default null comment '优先级', + `trigger_state` varchar(16) not null comment '触发器状态', + `trigger_type` varchar(8) not null comment '触发器的类型', + `start_time` bigint(13) not null comment '开始时间', + `end_time` bigint(13) default null comment '结束时间', + `calendar_name` varchar(200) default null comment '日程表名称', + `misfire_instr` smallint(2) default null comment '补偿执行的策略', + `job_data` blob comment '存放持久化job对象', + primary key (`sched_name`,`trigger_name`,`trigger_group`), + key `sched_name` (`sched_name`,`job_name`,`job_group`), + constraint `qrtz_triggers_ibfk_1` foreign key (`sched_name`, `job_name`, `job_group`) references `qrtz_job_details` (`sched_name`, `job_name`, `job_group`) +) engine=innodb default charset=utf8mb4 comment='触发器详细信息表'; + +-- ---------------------------- +-- records of qrtz_triggers +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for gen_table +-- ---------------------------- +drop table if exists `gen_table`; +create table `gen_table` ( + `table_id` bigint(20) not null auto_increment comment '编号', + `table_name` varchar(200) default '' comment '表名称', + `table_comment` varchar(500) default '' comment '表描述', + `sub_table_name` varchar(64) default null comment '关联子表的表名', + `sub_table_fk_name` varchar(64) default null comment '子表关联的外键名', + `class_name` varchar(100) default '' comment '实体类名称', + `tpl_category` varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', + `package_name` varchar(100) default null comment '生成包路径', + `module_name` varchar(30) default null comment '生成模块名', + `business_name` varchar(30) default null comment '生成业务名', + `function_name` varchar(50) default null comment '生成功能名', + `function_author` varchar(50) default null comment '生成功能作者', + `gen_type` char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + `gen_path` varchar(200) default '/' comment '生成路径(不填默认项目路径)', + `options` varchar(1000) default null comment '其它生成选项', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`table_id`) +) engine=innodb auto_increment=3 default charset=utf8mb4 comment='代码生成业务表'; + +-- ---------------------------- +-- records of gen_table +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for gen_table_column +-- ---------------------------- +drop table if exists `gen_table_column`; +create table `gen_table_column` ( + `column_id` bigint(20) not null auto_increment comment '编号', + `table_id` varchar(64) default null comment '归属表编号', + `column_name` varchar(200) default null comment '列名称', + `column_comment` varchar(500) default null comment '列描述', + `column_type` varchar(100) default null comment '列类型', + `java_type` varchar(500) default null comment 'java类型', + `java_field` varchar(200) default null comment 'java字段名', + `is_pk` char(1) default null comment '是否主键(1是)', + `is_increment` char(1) default null comment '是否自增(1是)', + `is_required` char(1) default null comment '是否必填(1是)', + `is_insert` char(1) default null comment '是否为插入字段(1是)', + `is_edit` char(1) default null comment '是否编辑字段(1是)', + `is_list` char(1) default null comment '是否列表字段(1是)', + `is_query` char(1) default null comment '是否查询字段(1是)', + `query_type` varchar(200) default 'eq' comment '查询方式(等于、不等于、大于、小于、范围)', + `html_type` varchar(200) default null comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + `dict_type` varchar(200) default '' comment '字典类型', + `sort` int(11) default null comment '排序', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + primary key (`column_id`) +) engine=innodb auto_increment=23 default charset=utf8mb4 comment='代码生成业务表字段'; + +-- ---------------------------- +-- records of gen_table_column +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for sys_config +-- ---------------------------- +drop table if exists `sys_config`; +create table `sys_config` ( + `config_id` int(5) not null auto_increment comment '参数主键', + `config_name` varchar(100) default '' comment '参数名称', + `config_key` varchar(100) default '' comment '参数键名', + `config_value` varchar(500) default '' comment '参数键值', + `config_type` char(1) default 'n' comment '系统内置(y是 n否)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`config_id`) +) engine=innodb auto_increment=6 default charset=utf8mb4 comment='参数配置表'; + +-- ---------------------------- +-- records of sys_config +-- ---------------------------- +begin; +insert into `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, '主框架页-默认皮肤样式名称', 'sys.index.skinname', 'skin-blue', 'y', 'admin', '2022-12-11 16:51:52', '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +insert into `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, '用户管理-账号初始密码', 'sys.user.initpassword', '123456', 'y', 'admin', '2022-12-11 16:51:52', '', null, '初始化密码 123456'); +insert into `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (3, '主框架页-侧边栏主题', 'sys.index.sidetheme', 'theme-dark', 'y', 'admin', '2022-12-11 16:51:52', '', null, '深色主题theme-dark,浅色主题theme-light'); +insert into `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (4, '账号自助-验证码开关', 'sys.account.captchaenabled', 'true', 'y', 'admin', '2022-12-11 16:51:52', '', null, '是否开启验证码功能(true开启,false关闭)'); +insert into `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (5, '账号自助-是否开启用户注册功能', 'sys.account.registeruser', 'false', 'y', 'admin', '2022-12-11 16:51:52', '', null, '是否开启注册用户功能(true开启,false关闭)'); +commit; + +-- ---------------------------- +-- table structure for sys_deploy_form +-- ---------------------------- +drop table if exists `sys_deploy_form`; +create table `sys_deploy_form` ( + `id` bigint(20) not null auto_increment comment '主键', + `form_id` bigint(20) default null comment '表单主键', + `deploy_id` varchar(50) default null comment '流程实例主键', + primary key (`id`) using btree +) engine=innodb auto_increment=6201 default charset=utf8mb4 comment='流程实例关联表单'; + +-- ---------------------------- +-- records of sys_deploy_form +-- ---------------------------- +begin; +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6180, 3170, '599f76eb-7954-11ed-b4f6-a6d273354027'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6181, 3170, '7626e55d-7af5-11ed-9d2c-aef9a5fa0bfa'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6182, 3170, '9fc55848-7b94-11ed-8d55-5ae1c970b0cc'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6183, 3170, '86d012f0-7b95-11ed-8d55-5ae1c970b0cc'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6184, 3170, '9324a1b5-7c2c-11ed-8695-924c6d734391'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6185, 3170, '18667e8e-7c88-11ed-a7de-e253d0217ba3'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6186, 3170, 'c2f37152-7cf1-11ed-948d-7226aba284c4'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6187, 3170, '3408e017-7cf2-11ed-948d-7226aba284c4'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6188, 3170, 'b69aadce-7cf7-11ed-bd4e-7226aba284c4'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6189, 3170, '9c3e92ed-7cfd-11ed-813e-621e497bd95c'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6190, 3170, '275bfcb5-7e95-11ed-b044-cacdb63dfd63'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6191, 3170, '42caede2-7eb1-11ed-8a7b-563e6b3c7d31'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6192, 3170, '4ff26436-7eb1-11ed-8a7b-563e6b3c7d31'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6193, 3170, '70c7041b-7eb3-11ed-b231-1a65000c45b2'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6194, 3170, 'ce79c9a0-7ebd-11ed-acae-6ec23aad2db1'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6195, 3170, '9233b1a6-7ecd-11ed-a1a8-767ed87bdd9a'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6196, 3170, '1b5733f0-7f59-11ed-9cbf-4a21df182334'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6197, 3170, '39b6f89f-7f5a-11ed-9cbf-4a21df182334'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6198, 3170, '0fad32e8-8437-11ed-8d46-7270fbe7c88b'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6199, 3170, 'c4b3b55c-8438-11ed-8d46-7270fbe7c88b'); +insert into `sys_deploy_form` (`id`, `form_id`, `deploy_id`) values (6200, 3170, '2519'); +commit; + +-- ---------------------------- +-- table structure for sys_dept +-- ---------------------------- +drop table if exists `sys_dept`; +create table `sys_dept` ( + `dept_id` bigint(20) not null auto_increment comment '部门id', + `parent_id` bigint(20) default '0' comment '父部门id', + `ancestors` varchar(50) default '' comment '祖级列表', + `dept_name` varchar(30) default '' comment '部门名称', + `order_num` int(4) default '0' comment '显示顺序', + `leader` varchar(20) default null comment '负责人', + `phone` varchar(11) default null comment '联系电话', + `email` varchar(50) default null comment '邮箱', + `status` char(1) default '0' comment '部门状态(0正常 1停用)', + `del_flag` char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + primary key (`dept_id`) +) engine=innodb auto_increment=110 default charset=utf8mb4 comment='部门表'; + +-- ---------------------------- +-- records of sys_dept +-- ---------------------------- +begin; +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +insert into `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) values (109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2022-12-11 16:51:52', '', null); +commit; + +-- ---------------------------- +-- table structure for sys_dict_data +-- ---------------------------- +drop table if exists `sys_dict_data`; +create table `sys_dict_data` ( + `dict_code` bigint(20) not null auto_increment comment '字典编码', + `dict_sort` int(4) default '0' comment '字典排序', + `dict_label` varchar(100) default '' comment '字典标签', + `dict_value` varchar(100) default '' comment '字典键值', + `dict_type` varchar(100) default '' comment '字典类型', + `css_class` varchar(100) default null comment '样式属性(其他样式扩展)', + `list_class` varchar(100) default null comment '表格回显样式', + `is_default` char(1) default 'n' comment '是否默认(y是 n否)', + `status` char(1) default '0' comment '状态(0正常 1停用)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`dict_code`) +) engine=innodb auto_increment=109 default charset=utf8mb4 comment='字典数据表'; + +-- ---------------------------- +-- records of sys_dict_data +-- ---------------------------- +begin; +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, 1, '男', '0', 'sys_user_sex', '', '', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '性别男'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, 2, '女', '1', 'sys_user_sex', '', '', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '性别女'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (3, 3, '未知', '2', 'sys_user_sex', '', '', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '性别未知'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '显示菜单'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '隐藏菜单'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '正常状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '停用状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '正常状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '停用状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (10, 1, '默认', 'default', 'sys_job_group', '', '', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '默认分组'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (11, 2, '系统', 'system', 'sys_job_group', '', '', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '系统分组'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (12, 1, '是', 'y', 'sys_yes_no', '', 'primary', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '系统默认是'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (13, 2, '否', 'n', 'sys_yes_no', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '系统默认否'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '通知'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '公告'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'y', '0', 'admin', '2022-12-11 16:51:52', '', null, '正常状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '关闭状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '其他操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '新增操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '修改操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '删除操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '授权操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '导出操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '导入操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '强退操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '生成操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '清空操作'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '正常状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'n', '0', 'admin', '2022-12-11 16:51:52', '', null, '停用状态'); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (100, 0, '请假流程', 'leave', 'sys_process_category', null, 'default', 'n', '0', 'admin', '2022-12-12 11:17:56', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (101, 0, 'oa流程', 'oa', 'sys_process_category', null, 'default', 'n', '0', 'admin', '2022-12-12 11:18:08', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (102, 0, '正常', '0', 'common_status', null, 'success', 'n', '0', 'admin', '2022-12-18 22:01:08', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (103, 1, '禁用', '1', 'common_status', null, 'danger', 'n', '0', 'admin', '2022-12-18 22:01:21', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (104, 0, '任务监听', '1', 'sys_listener_type', null, 'default', 'n', '0', 'admin', '2022-12-25 11:47:26', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (105, 2, '执行监听', '2', 'sys_listener_type', null, 'default', 'n', '0', 'admin', '2022-12-25 11:47:37', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (106, 0, 'java类', '1', 'sys_listener_value_type', null, 'default', 'n', '0', 'admin', '2022-12-25 11:48:55', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (107, 0, '表达式', '2', 'sys_listener_value_type', null, 'default', 'n', '0', 'admin', '2022-12-25 11:49:05', '', null, null); +insert into `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (108, 0, '代理表达式', '3', 'sys_listener_value_type', null, 'default', 'n', '0', 'admin', '2022-12-25 11:49:16', '', null, null); +commit; + +-- ---------------------------- +-- table structure for sys_dict_type +-- ---------------------------- +drop table if exists `sys_dict_type`; +create table `sys_dict_type` ( + `dict_id` bigint(20) not null auto_increment comment '字典主键', + `dict_name` varchar(100) default '' comment '字典名称', + `dict_type` varchar(100) default '' comment '字典类型', + `status` char(1) default '0' comment '状态(0正常 1停用)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`dict_id`), + unique key `dict_type` (`dict_type`) +) engine=innodb auto_increment=105 default charset=utf8mb4 comment='字典类型表'; + +-- ---------------------------- +-- records of sys_dict_type +-- ---------------------------- +begin; +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, '用户性别', 'sys_user_sex', '0', 'admin', '2022-12-11 16:51:52', '', null, '用户性别列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, '菜单状态', 'sys_show_hide', '0', 'admin', '2022-12-11 16:51:52', '', null, '菜单状态列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (3, '系统开关', 'sys_normal_disable', '0', 'admin', '2022-12-11 16:51:52', '', null, '系统开关列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (4, '任务状态', 'sys_job_status', '0', 'admin', '2022-12-11 16:51:52', '', null, '任务状态列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (5, '任务分组', 'sys_job_group', '0', 'admin', '2022-12-11 16:51:52', '', null, '任务分组列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (6, '系统是否', 'sys_yes_no', '0', 'admin', '2022-12-11 16:51:52', '', null, '系统是否列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (7, '通知类型', 'sys_notice_type', '0', 'admin', '2022-12-11 16:51:52', '', null, '通知类型列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (8, '通知状态', 'sys_notice_status', '0', 'admin', '2022-12-11 16:51:52', '', null, '通知状态列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (9, '操作类型', 'sys_oper_type', '0', 'admin', '2022-12-11 16:51:52', '', null, '操作类型列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (10, '系统状态', 'sys_common_status', '0', 'admin', '2022-12-11 16:51:52', '', null, '登录状态列表'); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (100, '流程分类', 'sys_process_category', '0', 'admin', '2022-12-12 11:17:38', '', null, null); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (101, '通用状态', 'common_status', '0', 'admin', '2022-12-18 22:00:02', '', null, null); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (102, '监听类型', 'sys_listener_type', '0', 'admin', '2022-12-18 22:03:07', '', null, null); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (103, '监听值类型', 'sys_listener_value_type', '0', 'admin', '2022-12-18 22:03:39', '', null, null); +insert into `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (104, '监听属性', 'sys_listener_event_type', '0', 'admin', '2022-12-18 22:04:29', '', null, null); +commit; + +-- ---------------------------- +-- table structure for sys_expression +-- ---------------------------- +drop table if exists `sys_expression`; +create table `sys_expression` ( + `id` bigint(20) not null auto_increment comment '表单主键', + `name` varchar(50) default null comment '表达式名称', + `expression` varchar(255) default null comment '表达式内容', + `create_time` datetime default null comment '创建时间', + `update_time` datetime default null comment '更新时间', + `create_by` bigint(20) default null comment '创建人员', + `update_by` bigint(20) default null comment '更新人员', + `status` tinyint(2) default '0' comment '状态', + `remark` varchar(255) default null comment '备注', + primary key (`id`) using btree +) engine=innodb auto_increment=3 default charset=utf8mb4 comment='流程表达式'; + +-- ---------------------------- +-- records of sys_expression +-- ---------------------------- +begin; +insert into `sys_expression` (`id`, `name`, `expression`, `create_time`, `update_time`, `create_by`, `update_by`, `status`, `remark`) values (1, '流程发起人', '${initiator}', '2022-12-12 17:29:10', null, null, null, 0, null); +insert into `sys_expression` (`id`, `name`, `expression`, `create_time`, `update_time`, `create_by`, `update_by`, `status`, `remark`) values (2, '审批流程指定接收人', '#{approval}', '2022-12-12 17:43:10', null, null, null, 0, null); +commit; + +-- ---------------------------- +-- table structure for sys_form +-- ---------------------------- +drop table if exists `sys_form`; +create table `sys_form` ( + `form_id` bigint(20) not null auto_increment comment '表单主键', + `form_name` varchar(50) default null comment '表单名称', + `form_content` longtext comment '表单内容', + `create_time` datetime default null comment '创建时间', + `update_time` datetime default null comment '更新时间', + `create_by` bigint(20) default null comment '创建人员', + `update_by` bigint(20) default null comment '更新人员', + `remark` varchar(255) default null comment '备注', + primary key (`form_id`) using btree +) engine=innodb auto_increment=3171 default charset=utf8mb4 comment='流程表单'; + +-- ---------------------------- +-- records of sys_form +-- ---------------------------- +begin; +insert into `sys_form` (`form_id`, `form_name`, `form_content`, `create_time`, `update_time`, `create_by`, `update_by`, `remark`) values (3170, '请假表单', '{\"fields\":[{\"__config__\":{\"label\":\"请假标题\",\"labelwidth\":null,\"showlabel\":true,\"changetag\":true,\"tag\":\"el-input\",\"tagicon\":\"input\",\"required\":true,\"layout\":\"colformitem\",\"span\":24,\"document\":\"https://element.eleme.cn/#/zh-cn/component/input\",\"reglist\":[],\"formid\":101,\"renderkey\":\"1011650592466703\"},\"__slot__\":{\"prepend\":\"\",\"append\":\"\"},\"placeholder\":\"请输入请假标题\",\"style\":{\"width\":\"100%\"},\"clearable\":true,\"prefix-icon\":\"\",\"suffix-icon\":\"\",\"maxlength\":null,\"show-word-limit\":false,\"readonly\":false,\"disabled\":false,\"__vmodel__\":\"field101\"},{\"__config__\":{\"label\":\"请假天数\",\"labelwidth\":null,\"showlabel\":true,\"changetag\":true,\"tag\":\"el-input\",\"tagicon\":\"input\",\"required\":true,\"layout\":\"colformitem\",\"span\":24,\"document\":\"https://element.eleme.cn/#/zh-cn/component/input\",\"reglist\":[],\"formid\":101,\"renderkey\":\"1011646362752852\"},\"__slot__\":{\"prepend\":\"\",\"append\":\"\"},\"placeholder\":\"请输入请假天数\",\"style\":{\"width\":\"100%\"},\"clearable\":true,\"prefix-icon\":\"\",\"suffix-icon\":\"\",\"maxlength\":null,\"show-word-limit\":false,\"readonly\":false,\"disabled\":false,\"__vmodel__\":\"day\"},{\"__config__\":{\"label\":\"请假备注\",\"labelwidth\":null,\"showlabel\":true,\"tag\":\"el-input\",\"tagicon\":\"textarea\",\"required\":true,\"layout\":\"colformitem\",\"span\":24,\"reglist\":[],\"changetag\":true,\"document\":\"https://element.eleme.cn/#/zh-cn/component/input\",\"formid\":102,\"renderkey\":\"1021650592469692\"},\"type\":\"textarea\",\"placeholder\":\"请输入请假备注\",\"autosize\":{\"minrows\":4,\"maxrows\":4},\"style\":{\"width\":\"100%\"},\"maxlength\":null,\"show-word-limit\":false,\"readonly\":false,\"disabled\":false,\"__vmodel__\":\"field102\"}],\"formref\":\"elform\",\"formmodel\":\"formdata\",\"size\":\"medium\",\"labelposition\":\"right\",\"labelwidth\":100,\"formrules\":\"rules\",\"gutter\":15,\"disabled\":false,\"span\":24,\"formbtns\":true}', '2022-12-11 21:02:39', null, null, null, '请假表单'); +commit; + +-- ---------------------------- +-- table structure for sys_job +-- ---------------------------- +drop table if exists `sys_job`; +create table `sys_job` ( + `job_id` bigint(20) not null auto_increment comment '任务id', + `job_name` varchar(64) not null default '' comment '任务名称', + `job_group` varchar(64) not null default 'default' comment '任务组名', + `invoke_target` varchar(500) not null comment '调用目标字符串', + `cron_expression` varchar(255) default '' comment 'cron执行表达式', + `misfire_policy` varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + `concurrent` char(1) default '1' comment '是否并发执行(0允许 1禁止)', + `status` char(1) default '0' comment '状态(0正常 1暂停)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default '' comment '备注信息', + primary key (`job_id`,`job_name`,`job_group`) +) engine=innodb auto_increment=4 default charset=utf8mb4 comment='定时任务调度表'; + +-- ---------------------------- +-- records of sys_job +-- ---------------------------- +begin; +insert into `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, '系统默认(无参)', 'default', 'rytask.rynoparams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, '系统默认(有参)', 'default', 'rytask.ryparams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (3, '系统默认(多参)', 'default', 'rytask.rymultipleparams(\'ry\', true, 2000l, 316.50d, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2022-12-11 16:51:52', '', null, ''); +commit; + +-- ---------------------------- +-- table structure for sys_job_log +-- ---------------------------- +drop table if exists `sys_job_log`; +create table `sys_job_log` ( + `job_log_id` bigint(20) not null auto_increment comment '任务日志id', + `job_name` varchar(64) not null comment '任务名称', + `job_group` varchar(64) not null comment '任务组名', + `invoke_target` varchar(500) not null comment '调用目标字符串', + `job_message` varchar(500) default null comment '日志信息', + `status` char(1) default '0' comment '执行状态(0正常 1失败)', + `exception_info` varchar(2000) default '' comment '异常信息', + `create_time` datetime default null comment '创建时间', + primary key (`job_log_id`) +) engine=innodb default charset=utf8mb4 comment='定时任务调度日志表'; + +-- ---------------------------- +-- records of sys_job_log +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for sys_listener +-- ---------------------------- +drop table if exists `sys_listener`; +create table `sys_listener` ( + `id` bigint(20) not null auto_increment comment '表单主键', + `name` varchar(128) default null comment '名称', + `type` char(2) default null comment '监听类型', + `event_type` varchar(32) default null comment '事件类型', + `value_type` char(2) default null comment '值类型', + `value` varchar(255) default null comment '执行内容', + `create_time` datetime default null comment '创建时间', + `update_time` datetime default null comment '更新时间', + `create_by` bigint(20) default null comment '创建人员', + `update_by` bigint(20) default null comment '更新人员', + `status` tinyint(2) default '0' comment '状态', + `remark` varchar(255) default null comment '备注', + primary key (`id`) using btree +) engine=innodb auto_increment=3 default charset=utf8mb4 comment='流程监听'; + +-- ---------------------------- +-- records of sys_listener +-- ---------------------------- +begin; +insert into `sys_listener` (`id`, `name`, `type`, `event_type`, `value_type`, `value`, `create_time`, `update_time`, `create_by`, `update_by`, `status`, `remark`) values (1, '任务监听', '1', 'assignment', '1', 'com.zbf.flowable.listener.flowtasklistener', '2022-12-25 12:31:50', null, null, null, 0, null); +insert into `sys_listener` (`id`, `name`, `type`, `event_type`, `value_type`, `value`, `create_time`, `update_time`, `create_by`, `update_by`, `status`, `remark`) values (2, '执行监听', '2', 'start', '1', 'com.zbf.flowable.listener.flowexecutionlistener', '2022-12-25 12:41:10', null, null, null, 0, null); +commit; + +-- ---------------------------- +-- table structure for sys_logininfor +-- ---------------------------- +drop table if exists `sys_logininfor`; +create table `sys_logininfor` ( + `info_id` bigint(20) not null auto_increment comment '访问id', + `user_name` varchar(50) default '' comment '用户账号', + `ipaddr` varchar(128) default '' comment '登录ip地址', + `login_location` varchar(255) default '' comment '登录地点', + `browser` varchar(50) default '' comment '浏览器类型', + `os` varchar(50) default '' comment '操作系统', + `status` char(1) default '0' comment '登录状态(0成功 1失败)', + `msg` varchar(255) default '' comment '提示消息', + `login_time` datetime default null comment '访问时间', + primary key (`info_id`) +) engine=innodb auto_increment=178 default charset=utf8mb4 comment='系统访问记录'; + +-- ---------------------------- +-- records of sys_logininfor +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for sys_menu +-- ---------------------------- +drop table if exists `sys_menu`; +create table `sys_menu` ( + `menu_id` bigint(20) not null auto_increment comment '菜单id', + `menu_name` varchar(50) not null comment '菜单名称', + `parent_id` bigint(20) default '0' comment '父菜单id', + `order_num` int(4) default '0' comment '显示顺序', + `path` varchar(200) default '' comment '路由地址', + `component` varchar(255) default null comment '组件路径', + `query` varchar(255) default null comment '路由参数', + `is_frame` int(1) default '1' comment '是否为外链(0是 1否)', + `is_cache` int(1) default '0' comment '是否缓存(0缓存 1不缓存)', + `menu_type` char(1) default '' comment '菜单类型(m目录 c菜单 f按钮)', + `visible` char(1) default '0' comment '菜单状态(0显示 1隐藏)', + `status` char(1) default '0' comment '菜单状态(0正常 1停用)', + `perms` varchar(100) default null comment '权限标识', + `icon` varchar(100) default '#' comment '菜单图标', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default '' comment '备注', + primary key (`menu_id`) +) engine=innodb auto_increment=2048 default charset=utf8mb4 comment='菜单权限表'; + +-- ---------------------------- +-- records of sys_menu +-- ---------------------------- +begin; +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, '系统管理', 0, 1, 'system', null, '', 1, 0, 'm', '0', '0', '', 'system', 'admin', '2022-12-11 16:51:52', '', null, '系统管理目录'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, '系统监控', 0, 2, 'monitor', null, '', 1, 0, 'm', '0', '0', '', 'monitor', 'admin', '2022-12-11 16:51:52', '', null, '系统监控目录'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (3, '系统工具', 0, 3, 'tool', null, '', 1, 0, 'm', '0', '0', '', 'tool', 'admin', '2022-12-11 16:51:52', '', null, '系统工具目录'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (4, '若依官网', 0, 4, 'http://ruoyi.vip', null, '', 0, 0, 'm', '0', '0', '', 'guide', 'admin', '2022-12-11 16:51:52', '', null, '若依官网地址'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (100, '用户管理', 1, 1, 'user', 'system/user/index', '', 1, 0, 'c', '0', '0', 'system:user:list', 'user', 'admin', '2022-12-11 16:51:52', '', null, '用户管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (101, '角色管理', 1, 2, 'role', 'system/role/index', '', 1, 0, 'c', '0', '0', 'system:role:list', 'peoples', 'admin', '2022-12-11 16:51:52', '', null, '角色管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', 1, 0, 'c', '0', '0', 'system:menu:list', 'tree-table', 'admin', '2022-12-11 16:51:52', '', null, '菜单管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', 1, 0, 'c', '0', '0', 'system:dept:list', 'tree', 'admin', '2022-12-11 16:51:52', '', null, '部门管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (104, '岗位管理', 1, 5, 'post', 'system/post/index', '', 1, 0, 'c', '0', '0', 'system:post:list', 'post', 'admin', '2022-12-11 16:51:52', '', null, '岗位管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', 1, 0, 'c', '0', '0', 'system:dict:list', 'dict', 'admin', '2022-12-11 16:51:52', '', null, '字典管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (106, '参数设置', 1, 7, 'config', 'system/config/index', '', 1, 0, 'c', '0', '0', 'system:config:list', 'edit', 'admin', '2022-12-11 16:51:52', '', null, '参数设置菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', 1, 0, 'c', '0', '0', 'system:notice:list', 'message', 'admin', '2022-12-11 16:51:52', '', null, '通知公告菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (108, '日志管理', 1, 9, 'log', '', '', 1, 0, 'm', '0', '0', '', 'log', 'admin', '2022-12-11 16:51:52', '', null, '日志管理菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', 1, 0, 'c', '0', '0', 'monitor:online:list', 'online', 'admin', '2022-12-11 16:51:52', '', null, '在线用户菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (110, '定时任务', 2, 2, 'job', 'monitor/job/index', '', 1, 0, 'c', '0', '0', 'monitor:job:list', 'job', 'admin', '2022-12-11 16:51:52', '', null, '定时任务菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (111, '数据监控', 2, 3, 'druid', 'monitor/druid/index', '', 1, 0, 'c', '0', '0', 'monitor:druid:list', 'druid', 'admin', '2022-12-11 16:51:52', '', null, '数据监控菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (112, '服务监控', 2, 4, 'server', 'monitor/server/index', '', 1, 0, 'c', '0', '0', 'monitor:server:list', 'server', 'admin', '2022-12-11 16:51:52', '', null, '服务监控菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', 1, 0, 'c', '0', '0', 'monitor:cache:list', 'redis', 'admin', '2022-12-11 16:51:52', '', null, '缓存监控菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (114, '缓存列表', 2, 6, 'cachelist', 'monitor/cache/list', '', 1, 0, 'c', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', '2022-12-11 16:51:52', '', null, '缓存列表菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (115, '表单构建', 3, 1, 'build', 'tool/build/index', '', 1, 0, 'c', '0', '0', 'tool:build:list', 'build', 'admin', '2022-12-11 16:51:52', '', null, '表单构建菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (116, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', 1, 0, 'c', '0', '0', 'tool:gen:list', 'code', 'admin', '2022-12-11 16:51:52', '', null, '代码生成菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (117, '系统接口', 3, 3, 'swagger', 'tool/swagger/index', '', 1, 0, 'c', '0', '0', 'tool:swagger:list', 'swagger', 'admin', '2022-12-11 16:51:52', '', null, '系统接口菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', 1, 0, 'c', '0', '0', 'monitor:operlog:list', 'form', 'admin', '2022-12-11 16:51:52', '', null, '操作日志菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'c', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2022-12-11 16:51:52', '', null, '登录日志菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1000, '用户查询', 100, 1, '', '', '', 1, 0, 'f', '0', '0', 'system:user:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1001, '用户新增', 100, 2, '', '', '', 1, 0, 'f', '0', '0', 'system:user:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1002, '用户修改', 100, 3, '', '', '', 1, 0, 'f', '0', '0', 'system:user:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1003, '用户删除', 100, 4, '', '', '', 1, 0, 'f', '0', '0', 'system:user:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1004, '用户导出', 100, 5, '', '', '', 1, 0, 'f', '0', '0', 'system:user:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1005, '用户导入', 100, 6, '', '', '', 1, 0, 'f', '0', '0', 'system:user:import', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1006, '重置密码', 100, 7, '', '', '', 1, 0, 'f', '0', '0', 'system:user:resetpwd', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1007, '角色查询', 101, 1, '', '', '', 1, 0, 'f', '0', '0', 'system:role:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1008, '角色新增', 101, 2, '', '', '', 1, 0, 'f', '0', '0', 'system:role:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1009, '角色修改', 101, 3, '', '', '', 1, 0, 'f', '0', '0', 'system:role:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1010, '角色删除', 101, 4, '', '', '', 1, 0, 'f', '0', '0', 'system:role:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1011, '角色导出', 101, 5, '', '', '', 1, 0, 'f', '0', '0', 'system:role:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1012, '菜单查询', 102, 1, '', '', '', 1, 0, 'f', '0', '0', 'system:menu:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1013, '菜单新增', 102, 2, '', '', '', 1, 0, 'f', '0', '0', 'system:menu:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1014, '菜单修改', 102, 3, '', '', '', 1, 0, 'f', '0', '0', 'system:menu:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1015, '菜单删除', 102, 4, '', '', '', 1, 0, 'f', '0', '0', 'system:menu:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1016, '部门查询', 103, 1, '', '', '', 1, 0, 'f', '0', '0', 'system:dept:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1017, '部门新增', 103, 2, '', '', '', 1, 0, 'f', '0', '0', 'system:dept:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1018, '部门修改', 103, 3, '', '', '', 1, 0, 'f', '0', '0', 'system:dept:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1019, '部门删除', 103, 4, '', '', '', 1, 0, 'f', '0', '0', 'system:dept:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1020, '岗位查询', 104, 1, '', '', '', 1, 0, 'f', '0', '0', 'system:post:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1021, '岗位新增', 104, 2, '', '', '', 1, 0, 'f', '0', '0', 'system:post:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1022, '岗位修改', 104, 3, '', '', '', 1, 0, 'f', '0', '0', 'system:post:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1023, '岗位删除', 104, 4, '', '', '', 1, 0, 'f', '0', '0', 'system:post:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1024, '岗位导出', 104, 5, '', '', '', 1, 0, 'f', '0', '0', 'system:post:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1025, '字典查询', 105, 1, '#', '', '', 1, 0, 'f', '0', '0', 'system:dict:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1026, '字典新增', 105, 2, '#', '', '', 1, 0, 'f', '0', '0', 'system:dict:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1027, '字典修改', 105, 3, '#', '', '', 1, 0, 'f', '0', '0', 'system:dict:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1028, '字典删除', 105, 4, '#', '', '', 1, 0, 'f', '0', '0', 'system:dict:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1029, '字典导出', 105, 5, '#', '', '', 1, 0, 'f', '0', '0', 'system:dict:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1030, '参数查询', 106, 1, '#', '', '', 1, 0, 'f', '0', '0', 'system:config:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1031, '参数新增', 106, 2, '#', '', '', 1, 0, 'f', '0', '0', 'system:config:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1032, '参数修改', 106, 3, '#', '', '', 1, 0, 'f', '0', '0', 'system:config:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1033, '参数删除', 106, 4, '#', '', '', 1, 0, 'f', '0', '0', 'system:config:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1034, '参数导出', 106, 5, '#', '', '', 1, 0, 'f', '0', '0', 'system:config:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1035, '公告查询', 107, 1, '#', '', '', 1, 0, 'f', '0', '0', 'system:notice:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1036, '公告新增', 107, 2, '#', '', '', 1, 0, 'f', '0', '0', 'system:notice:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1037, '公告修改', 107, 3, '#', '', '', 1, 0, 'f', '0', '0', 'system:notice:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1038, '公告删除', 107, 4, '#', '', '', 1, 0, 'f', '0', '0', 'system:notice:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1039, '操作查询', 500, 1, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:operlog:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1040, '操作删除', 500, 2, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:operlog:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1041, '日志导出', 500, 3, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:operlog:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1042, '登录查询', 501, 1, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:logininfor:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1043, '登录删除', 501, 2, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:logininfor:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1044, '日志导出', 501, 3, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:logininfor:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1045, '账户解锁', 501, 4, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1046, '在线查询', 109, 1, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:online:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1047, '批量强退', 109, 2, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:online:batchlogout', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1048, '单条强退', 109, 3, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:online:forcelogout', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1049, '任务查询', 110, 1, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:job:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1050, '任务新增', 110, 2, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:job:add', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1051, '任务修改', 110, 3, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:job:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1052, '任务删除', 110, 4, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:job:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1053, '状态修改', 110, 5, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:job:changestatus', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1054, '任务导出', 110, 6, '#', '', '', 1, 0, 'f', '0', '0', 'monitor:job:export', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1055, '生成查询', 116, 1, '#', '', '', 1, 0, 'f', '0', '0', 'tool:gen:query', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1056, '生成修改', 116, 2, '#', '', '', 1, 0, 'f', '0', '0', 'tool:gen:edit', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1057, '生成删除', 116, 3, '#', '', '', 1, 0, 'f', '0', '0', 'tool:gen:remove', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1058, '导入代码', 116, 4, '#', '', '', 1, 0, 'f', '0', '0', 'tool:gen:import', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1059, '预览代码', 116, 5, '#', '', '', 1, 0, 'f', '0', '0', 'tool:gen:preview', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1060, '生成代码', 116, 6, '#', '', '', 1, 0, 'f', '0', '0', 'tool:gen:code', '#', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2020, '流程管理', 0, 6, 'flowable', null, null, 1, 0, 'm', '0', '0', null, 'cascader', 'tony', '2021-03-25 11:35:09', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2022, '流程定义', 2020, 2, 'definition', 'flowable/definition/index', null, 1, 0, 'c', '0', '0', '', 'job', 'tony', '2021-03-25 13:53:55', 'admin', '2021-03-29 09:39:07', ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2023, '任务管理', 0, 7, 'task', null, null, 1, 0, 'm', '0', '0', '', 'dict', 'tony', '2021-03-26 10:53:10', 'admin', '2021-03-29 09:37:40', ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2024, '待办任务', 2023, 2, 'todo', 'flowable/task/todo/index', null, 1, 1, 'c', '0', '0', '', 'cascader', 'admin', '2021-03-26 10:55:52', 'admin', '2021-03-30 09:26:36', ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2025, '已办任务', 2023, 3, 'finished', 'flowable/task/finished/index', null, 1, 1, 'c', '0', '0', '', 'time-range', 'admin', '2021-03-26 10:57:54', 'admin', '2021-03-30 09:26:50', ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2026, '我的流程', 2023, 1, 'process', 'flowable/task/myprocess/index', null, 1, 1, 'c', '0', '0', '', 'guide', 'admin', '2021-03-30 09:26:23', 'admin', '2022-12-12 09:58:07', ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2027, '表单配置', 2020, 2, 'form', 'flowable/task/form/index', null, 1, 0, 'c', '0', '0', 'flowable:form:list', 'form', 'admin', '2021-03-30 22:55:12', 'admin', '2021-04-03 18:50:54', ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2028, '新增', 2027, 1, '', null, null, 1, 0, 'f', '0', '0', 'flowable:form:add', '#', 'admin', '2021-07-07 14:23:37', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2029, '删除', 2027, 3, '', null, null, 1, 0, 'f', '0', '0', 'flowable:form:remove', '#', 'admin', '2021-07-07 14:24:10', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2030, '编辑', 2027, 2, '', null, null, 1, 0, 'f', '0', '0', 'flowable:form:edit', '#', 'admin', '2021-07-07 14:24:31', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2031, '新增', 2026, 1, '', null, null, 1, 0, 'f', '0', '0', 'system:deployment:add', '#', 'admin', '2021-07-07 14:25:22', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2032, '编辑', 2026, 2, '', null, null, 1, 0, 'f', '0', '0', 'system:deployment:edit', '#', 'admin', '2021-07-07 14:25:47', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2033, '删除', 2026, 3, '', null, null, 1, 0, 'f', '0', '0', 'system:deployment:remove', '#', 'admin', '2021-07-07 14:26:02', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2034, '查询', 2027, 4, '', null, null, 1, 0, 'f', '0', '0', 'flowable:form:query', '#', 'admin', '2021-07-08 14:05:22', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2035, '修改密码', 100, 8, '', null, null, 1, 0, 'f', '0', '0', 'system:user:updatepwd', '#', 'admin', '2022-04-29 11:27:13', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2036, '流程表达式', 2020, 3, 'expression', 'system/expression/index', null, 1, 1, 'c', '0', '0', 'system:expression:list', 'list', 'admin', '2022-12-12 17:12:19', 'admin', '2022-12-12 17:13:44', '流程达式菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2037, '流程达式查询', 2036, 1, '#', '', null, 1, 0, 'f', '0', '0', 'system:expression:query', '#', 'admin', '2022-12-12 17:12:19', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2038, '流程达式新增', 2036, 2, '#', '', null, 1, 0, 'f', '0', '0', 'system:expression:add', '#', 'admin', '2022-12-12 17:12:19', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2039, '流程达式修改', 2036, 3, '#', '', null, 1, 0, 'f', '0', '0', 'system:expression:edit', '#', 'admin', '2022-12-12 17:12:19', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2040, '流程达式删除', 2036, 4, '#', '', null, 1, 0, 'f', '0', '0', 'system:expression:remove', '#', 'admin', '2022-12-12 17:12:19', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2041, '流程达式导出', 2036, 5, '#', '', null, 1, 0, 'f', '0', '0', 'system:expression:export', '#', 'admin', '2022-12-12 17:12:19', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2042, '流程监听', 2020, 1, 'listener', 'system/listener/index', null, 1, 0, 'c', '0', '0', 'system:listener:list', '#', 'admin', '2022-12-25 11:44:16', '', null, '流程监听菜单'); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2043, '流程监听查询', 2042, 1, '#', '', null, 1, 0, 'f', '0', '0', 'system:listener:query', '#', 'admin', '2022-12-25 11:44:16', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2044, '流程监听新增', 2042, 2, '#', '', null, 1, 0, 'f', '0', '0', 'system:listener:add', '#', 'admin', '2022-12-25 11:44:16', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2045, '流程监听修改', 2042, 3, '#', '', null, 1, 0, 'f', '0', '0', 'system:listener:edit', '#', 'admin', '2022-12-25 11:44:16', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2046, '流程监听删除', 2042, 4, '#', '', null, 1, 0, 'f', '0', '0', 'system:listener:remove', '#', 'admin', '2022-12-25 11:44:16', '', null, ''); +insert into `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2047, '流程监听导出', 2042, 5, '#', '', null, 1, 0, 'f', '0', '0', 'system:listener:export', '#', 'admin', '2022-12-25 11:44:16', '', null, ''); +commit; + +-- ---------------------------- +-- table structure for sys_notice +-- ---------------------------- +drop table if exists `sys_notice`; +create table `sys_notice` ( + `notice_id` int(4) not null auto_increment comment '公告id', + `notice_title` varchar(50) not null comment '公告标题', + `notice_type` char(1) not null comment '公告类型(1通知 2公告)', + `notice_content` longblob comment '公告内容', + `status` char(1) default '0' comment '公告状态(0正常 1关闭)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(255) default null comment '备注', + primary key (`notice_id`) +) engine=innodb auto_increment=3 default charset=utf8mb4 comment='通知公告表'; + +-- ---------------------------- +-- records of sys_notice +-- ---------------------------- +begin; +insert into `sys_notice` (`notice_id`, `notice_title`, `notice_type`, `notice_content`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, '温馨提醒:2018-07-01 若依新版本发布啦', '2', 0xe696b0e78988e69cace58685e5aeb9, '0', 'admin', '2022-12-11 16:51:52', '', null, '管理员'); +insert into `sys_notice` (`notice_id`, `notice_title`, `notice_type`, `notice_content`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, '维护通知:2018-07-01 若依系统凌晨维护', '1', 0xe7bbb4e68aa4e58685e5aeb9, '0', 'admin', '2022-12-11 16:51:52', '', null, '管理员'); +commit; + +-- ---------------------------- +-- table structure for sys_oper_log +-- ---------------------------- +drop table if exists `sys_oper_log`; +create table `sys_oper_log` ( + `oper_id` bigint(20) not null auto_increment comment '日志主键', + `title` varchar(50) default '' comment '模块标题', + `business_type` int(2) default '0' comment '业务类型(0其它 1新增 2修改 3删除)', + `method` varchar(100) default '' comment '方法名称', + `request_method` varchar(10) default '' comment '请求方式', + `operator_type` int(1) default '0' comment '操作类别(0其它 1后台用户 2手机端用户)', + `oper_name` varchar(50) default '' comment '操作人员', + `dept_name` varchar(50) default '' comment '部门名称', + `oper_url` varchar(255) default '' comment '请求url', + `oper_ip` varchar(128) default '' comment '主机地址', + `oper_location` varchar(255) default '' comment '操作地点', + `oper_param` varchar(2000) default '' comment '请求参数', + `json_result` varchar(2000) default '' comment '返回参数', + `status` int(1) default '0' comment '操作状态(0正常 1异常)', + `error_msg` varchar(2000) default '' comment '错误消息', + `oper_time` datetime default null comment '操作时间', + `cost_time` bigint(20) default '0' comment '消耗时间', + primary key (`oper_id`) +) engine=innodb auto_increment=166 default charset=utf8mb4 comment='操作日志记录'; + +-- ---------------------------- +-- records of sys_oper_log +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for sys_post +-- ---------------------------- +drop table if exists `sys_post`; +create table `sys_post` ( + `post_id` bigint(20) not null auto_increment comment '岗位id', + `post_code` varchar(64) not null comment '岗位编码', + `post_name` varchar(50) not null comment '岗位名称', + `post_sort` int(4) not null comment '显示顺序', + `status` char(1) not null comment '状态(0正常 1停用)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`post_id`) +) engine=innodb auto_increment=5 default charset=utf8mb4 comment='岗位信息表'; + +-- ---------------------------- +-- records of sys_post +-- ---------------------------- +begin; +insert into `sys_post` (`post_id`, `post_code`, `post_name`, `post_sort`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, 'ceo', '董事长', 1, '0', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_post` (`post_id`, `post_code`, `post_name`, `post_sort`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, 'se', '项目经理', 2, '0', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_post` (`post_id`, `post_code`, `post_name`, `post_sort`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (3, 'hr', '人力资源', 3, '0', 'admin', '2022-12-11 16:51:52', '', null, ''); +insert into `sys_post` (`post_id`, `post_code`, `post_name`, `post_sort`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (4, 'user', '普通员工', 4, '0', 'admin', '2022-12-11 16:51:52', '', null, ''); +commit; + +-- ---------------------------- +-- table structure for sys_role +-- ---------------------------- +drop table if exists `sys_role`; +create table `sys_role` ( + `role_id` bigint(20) not null auto_increment comment '角色id', + `role_name` varchar(30) not null comment '角色名称', + `role_key` varchar(100) not null comment '角色权限字符串', + `role_sort` int(4) not null comment '显示顺序', + `data_scope` char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + `menu_check_strictly` tinyint(1) default '1' comment '菜单树选择项是否关联显示', + `dept_check_strictly` tinyint(1) default '1' comment '部门树选择项是否关联显示', + `status` char(1) not null comment '角色状态(0正常 1停用)', + `del_flag` char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`role_id`) +) engine=innodb auto_increment=3 default charset=utf8mb4 comment='角色信息表'; + +-- ---------------------------- +-- records of sys_role +-- ---------------------------- +begin; +insert into `sys_role` (`role_id`, `role_name`, `role_key`, `role_sort`, `data_scope`, `menu_check_strictly`, `dept_check_strictly`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, '超级管理员', 'admin', 1, '1', 1, 1, '0', '0', 'admin', '2022-12-11 16:51:52', '', null, '超级管理员'); +insert into `sys_role` (`role_id`, `role_name`, `role_key`, `role_sort`, `data_scope`, `menu_check_strictly`, `dept_check_strictly`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, '普通角色', 'common', 2, '2', 1, 1, '0', '0', 'admin', '2022-12-11 16:51:52', 'admin', '2022-12-26 11:30:33', '普通角色'); +commit; + +-- ---------------------------- +-- table structure for sys_role_dept +-- ---------------------------- +drop table if exists `sys_role_dept`; +create table `sys_role_dept` ( + `role_id` bigint(20) not null comment '角色id', + `dept_id` bigint(20) not null comment '部门id', + primary key (`role_id`,`dept_id`) +) engine=innodb default charset=utf8mb4 comment='角色和部门关联表'; + +-- ---------------------------- +-- records of sys_role_dept +-- ---------------------------- +begin; +insert into `sys_role_dept` (`role_id`, `dept_id`) values (2, 100); +insert into `sys_role_dept` (`role_id`, `dept_id`) values (2, 101); +insert into `sys_role_dept` (`role_id`, `dept_id`) values (2, 105); +commit; + +-- ---------------------------- +-- table structure for sys_role_menu +-- ---------------------------- +drop table if exists `sys_role_menu`; +create table `sys_role_menu` ( + `role_id` bigint(20) not null comment '角色id', + `menu_id` bigint(20) not null comment '菜单id', + primary key (`role_id`,`menu_id`) +) engine=innodb default charset=utf8mb4 comment='角色和菜单关联表'; + +-- ---------------------------- +-- records of sys_role_menu +-- ---------------------------- +begin; +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 3); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 4); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 100); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 101); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 102); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 103); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 104); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 105); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 106); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 107); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 108); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 109); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 110); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 111); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 112); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 113); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 114); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 115); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 116); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 117); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 500); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 501); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1000); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1001); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1002); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1003); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1004); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1005); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1006); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1007); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1008); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1009); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1010); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1011); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1012); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1013); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1014); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1015); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1016); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1017); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1018); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1019); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1020); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1021); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1022); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1023); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1024); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1025); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1026); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1027); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1028); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1029); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1030); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1031); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1032); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1033); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1034); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1035); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1036); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1037); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1038); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1039); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1040); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1041); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1042); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1043); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1044); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1045); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1046); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1047); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1048); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1049); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1050); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1051); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1052); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1053); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1054); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1055); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1056); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1057); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1058); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1059); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 1060); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2020); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2022); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2023); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2024); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2025); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2026); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2027); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2028); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2029); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2030); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2031); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2032); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2033); +insert into `sys_role_menu` (`role_id`, `menu_id`) values (2, 2034); +commit; + +-- ---------------------------- +-- table structure for sys_task_form +-- ---------------------------- +drop table if exists `sys_task_form`; +create table `sys_task_form` ( + `id` bigint(20) not null auto_increment comment '主键', + `form_id` bigint(20) default null comment '表单主键', + `task_id` varchar(50) default null comment '所属任务', + primary key (`id`) using btree +) engine=innodb default charset=utf8mb4 comment='流程任务关联表单'; + +-- ---------------------------- +-- records of sys_task_form +-- ---------------------------- +begin; +commit; + +-- ---------------------------- +-- table structure for sys_user +-- ---------------------------- +drop table if exists `sys_user`; +create table `sys_user` ( + `user_id` bigint(20) not null auto_increment comment '用户id', + `dept_id` bigint(20) default null comment '部门id', + `user_name` varchar(30) not null comment '用户账号', + `nick_name` varchar(30) not null comment '用户名称', + `user_type` varchar(2) default '00' comment '用户类型(00系统用户)', + `email` varchar(50) default '' comment '用户邮箱', + `phonenumber` varchar(11) default '' comment '手机号码', + `sex` char(1) default '0' comment '用户性别(0男 1女 2未知)', + `avatar` varchar(100) default '' comment '头像地址', + `password` varchar(100) default '' comment '密码', + `status` char(1) default '0' comment '帐号状态(0正常 1停用)', + `del_flag` char(1) default '0' comment '删除标志(0代表存在 2代表删除)', + `login_ip` varchar(128) default '' comment '最后登录ip', + `login_date` datetime default null comment '最后登录时间', + `create_by` varchar(64) default '' comment '创建者', + `create_time` datetime default null comment '创建时间', + `update_by` varchar(64) default '' comment '更新者', + `update_time` datetime default null comment '更新时间', + `remark` varchar(500) default null comment '备注', + primary key (`user_id`) +) engine=innodb auto_increment=3 default charset=utf8mb4 comment='用户信息表'; + +-- ---------------------------- +-- records of sys_user +-- ---------------------------- +begin; +insert into `sys_user` (`user_id`, `dept_id`, `user_name`, `nick_name`, `user_type`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `del_flag`, `login_ip`, `login_date`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7jb720yubvszvui0reqk/.vqgozth.ulu33dhoibe8byohjirdau2', '0', '0', '127.0.0.1', '2022-12-28 15:47:23', 'admin', '2022-12-11 16:51:52', '', '2022-12-28 15:47:22', '管理员'); +insert into `sys_user` (`user_id`, `dept_id`, `user_name`, `nick_name`, `user_type`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `del_flag`, `login_ip`, `login_date`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) values (2, 105, 'ry', '李四', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7jb720yubvszvui0reqk/.vqgozth.ulu33dhoibe8byohjirdau2', '0', '0', '127.0.0.1', '2022-12-26 11:30:01', 'admin', '2022-12-11 16:51:52', 'admin', '2022-12-26 11:30:01', '测试员'); +commit; + +-- ---------------------------- +-- table structure for sys_user_post +-- ---------------------------- +drop table if exists `sys_user_post`; +create table `sys_user_post` ( + `user_id` bigint(20) not null comment '用户id', + `post_id` bigint(20) not null comment '岗位id', + primary key (`user_id`,`post_id`) +) engine=innodb default charset=utf8mb4 comment='用户与岗位关联表'; + +-- ---------------------------- +-- records of sys_user_post +-- ---------------------------- +begin; +insert into `sys_user_post` (`user_id`, `post_id`) values (1, 1); +insert into `sys_user_post` (`user_id`, `post_id`) values (2, 2); +commit; + +-- ---------------------------- +-- table structure for sys_user_role +-- ---------------------------- +drop table if exists `sys_user_role`; +create table `sys_user_role` ( + `user_id` bigint(20) not null comment '用户id', + `role_id` bigint(20) not null comment '角色id', + primary key (`user_id`,`role_id`) +) engine=innodb default charset=utf8mb4 comment='用户和角色关联表'; + +-- ---------------------------- +-- records of sys_user_role +-- ---------------------------- +begin; +insert into `sys_user_role` (`user_id`, `role_id`) values (1, 1); +insert into `sys_user_role` (`user_id`, `role_id`) values (2, 2); +commit; + +set foreign_key_checks = 1; diff --git a/zbf-admin/pom.xml b/zbf-admin/pom.xml new file mode 100644 index 0000000..04502fe --- /dev/null +++ b/zbf-admin/pom.xml @@ -0,0 +1,149 @@ + + + + zbf + com.zbf + 3.8.7 + + 4.0.0 + jar + zbf-admin + + + web服务入口 + + + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + io.springfox + springfox-boot-starter + + + + + io.swagger + swagger-models + 1.6.2 + + + + + mysql + mysql-connector-java + + + + + com.zbf + zbf-framework + + + + + com.zbf + zbf-quartz + + + + + com.zbf + zbf-generator + + + + org.apache.httpcomponents + httpclient + 4.5.13 + + + + + org.apache.httpcomponents + httpcore + 4.4.14 + + + org.flowable + flowable-spring-boot-starter-process + 6.7.2 + + + org.flowable + flowable-json-converter + 6.7.2 + + + + org.flowable + flowable-bpmn-layout + 6.7.2 + + + + org.redisson + redisson + 3.16.6 + + + + com.alibaba + easyexcel + 3.2.1 + + + + com.google.guava + guava + 31.1-jre + + + + + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.5.15 + + true + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.1.0 + + false + ${project.artifactId} + + + + + rzg + + + diff --git a/zbf-admin/src/main/java/com/zbf/ZbfApplication.java b/zbf-admin/src/main/java/com/zbf/ZbfApplication.java new file mode 100644 index 0000000..0f65370 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/ZbfApplication.java @@ -0,0 +1,34 @@ +package com.zbf; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.integration.config.EnableIntegration; + +/** + * 启动程序 + * + * @author ruoyi + */ +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) +@EnableIntegration +@EnableConfigurationProperties +public class ZbfApplication +{ + public static void main(String[] args) + { + // System.setProperty("spring.devtools.restart.enabled", "false"); + SpringApplication.run(ZbfApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ 日照港仓储系统运行成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/ZbfServletInitializer.java b/zbf-admin/src/main/java/com/zbf/ZbfServletInitializer.java new file mode 100644 index 0000000..829e931 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/ZbfServletInitializer.java @@ -0,0 +1,18 @@ +package com.zbf; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author ruoyi + */ +public class ZbfServletInitializer extends SpringBootServletInitializer +{ + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) + { + return application.sources(ZbfApplication.class); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/common/CaptchaController.java b/zbf-admin/src/main/java/com/zbf/web/controller/common/CaptchaController.java new file mode 100644 index 0000000..461df1a --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/common/CaptchaController.java @@ -0,0 +1,94 @@ +package com.zbf.web.controller.common; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import javax.annotation.Resource; +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.FastByteArrayOutputStream; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import com.google.code.kaptcha.Producer; +import com.zbf.common.config.RuoYiConfig; +import com.zbf.common.constant.CacheConstants; +import com.zbf.common.constant.Constants; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.redis.RedisCache; +import com.zbf.common.utils.sign.Base64; +import com.zbf.common.utils.uuid.IdUtils; +import com.zbf.system.service.ISysConfigService; + +/** + * 验证码操作处理 + * + * @author ruoyi + */ +@RestController +public class CaptchaController +{ + @Resource(name = "captchaProducer") + private Producer captchaProducer; + + @Resource(name = "captchaProducerMath") + private Producer captchaProducerMath; + + @Autowired + private RedisCache redisCache; + + @Autowired + private ISysConfigService configService; + /** + * 生成验证码 + */ + @GetMapping("/captchaImage") + public AjaxResult getCode(HttpServletResponse response) throws IOException + { + AjaxResult ajax = AjaxResult.success(); + boolean captchaEnabled = configService.selectCaptchaEnabled(); + ajax.put("captchaEnabled", captchaEnabled); + if (!captchaEnabled) + { + return ajax; + } + + // 保存验证码信息 + String uuid = IdUtils.simpleUUID(); + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + + String capStr = null, code = null; + BufferedImage image = null; + + // 生成验证码 + String captchaType = RuoYiConfig.getCaptchaType(); + if ("math".equals(captchaType)) + { + String capText = captchaProducerMath.createText(); + capStr = capText.substring(0, capText.lastIndexOf("@")); + code = capText.substring(capText.lastIndexOf("@") + 1); + image = captchaProducerMath.createImage(capStr); + } + else if ("char".equals(captchaType)) + { + capStr = code = captchaProducer.createText(); + image = captchaProducer.createImage(capStr); + } + + redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); + // 转换流信息写出 + FastByteArrayOutputStream os = new FastByteArrayOutputStream(); + try + { + ImageIO.write(image, "jpg", os); + } + catch (IOException e) + { + return AjaxResult.error(e.getMessage()); + } + + ajax.put("uuid", uuid); + ajax.put("img", Base64.encode(os.toByteArray())); + return ajax; + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/common/CommonController.java b/zbf-admin/src/main/java/com/zbf/web/controller/common/CommonController.java new file mode 100644 index 0000000..4432add --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/common/CommonController.java @@ -0,0 +1,168 @@ +package com.zbf.web.controller.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import com.zbf.system.service.ITSeqService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import com.zbf.common.config.RuoYiConfig; +import com.zbf.common.constant.Constants; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.file.FileUploadUtils; +import com.zbf.common.utils.file.FileUtils; +import com.zbf.framework.config.ServerConfig; + +/** + * 通用请求处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/common") +public class CommonController { + private static final Logger log = LoggerFactory.getLogger(CommonController.class); + + private final ServerConfig serverConfig; + private ITSeqService seqService; + private static final String FILE_DELIMETER = ","; + + public CommonController(ServerConfig serverConfig, ITSeqService seqService) { + this.serverConfig = serverConfig; + this.seqService = seqService; + } + + /** + * 通用下载请求 + * + * @param fileName 文件名称 + * @param delete 是否删除 + */ + @GetMapping("/download") + public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) { + try { + if (!FileUtils.checkAllowDownload(fileName)) { + throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); + } + String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); + String filePath = RuoYiConfig.getDownloadPath() + fileName; + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, realFileName); + FileUtils.writeBytes(filePath, response.getOutputStream()); + if (delete) { + FileUtils.deleteFile(filePath); + } + } catch (Exception e) { + log.error("下载文件失败", e); + } + } + + /** + * 通用上传请求(单个) + */ + @PostMapping("/upload") + public AjaxResult uploadFile(MultipartFile file) throws Exception { + try { + // 上传文件路径 + String filePath = RuoYiConfig.getUploadPath(); + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = serverConfig.getUrl() + fileName; + AjaxResult ajax = AjaxResult.success(); + ajax.put("url", url); + ajax.put("fileName", fileName); + ajax.put("newFileName", FileUtils.getName(fileName)); + ajax.put("originalFilename", file.getOriginalFilename()); + return ajax; + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 通用上传请求(多个) + */ + @PostMapping("/uploads") + public AjaxResult uploadFiles(List files) throws Exception { + try { + // 上传文件路径 + String filePath = RuoYiConfig.getUploadPath(); + List urls = new ArrayList(); + List fileNames = new ArrayList(); + List newFileNames = new ArrayList(); + List originalFilenames = new ArrayList(); + for (MultipartFile file : files) { + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = serverConfig.getUrl() + fileName; + urls.add(url); + fileNames.add(fileName); + newFileNames.add(FileUtils.getName(fileName)); + originalFilenames.add(file.getOriginalFilename()); + } + AjaxResult ajax = AjaxResult.success(); + ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER)); + ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER)); + ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER)); + ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER)); + return ajax; + } catch (Exception e) { + return AjaxResult.error(e.getMessage()); + } + } + + /** + * 本地资源通用下载 + */ + @GetMapping("/download/resource") + public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) + throws Exception { + try { + if (!FileUtils.checkAllowDownload(resource)) { + throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); + } + // 本地资源路径 + String localPath = RuoYiConfig.getProfile(); + // 数据库资源地址 + String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX); + // 下载名称 + String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, downloadName); + FileUtils.writeBytes(downloadPath, response.getOutputStream()); + } catch (Exception e) { + log.error("下载文件失败", e); + } + } + + /** + * 生成流水号,key为前缀,len为长度  + */ + @GetMapping("/generateSeq") + public AjaxResult generateSeq(@RequestParam Map params) + throws Exception { + AjaxResult ajax = AjaxResult.success(); + ajax.put("seq", seqService.generateSeq(params.get("key").toString(), Integer.parseInt(params.get("len").toString()))); + return ajax; + } + + /** + * 生成流水号,key为前缀,len为长度  + */ + @GetMapping("/generateTempSeq") + public AjaxResult generateTempSeq(@RequestParam Map params) + throws Exception { + AjaxResult ajax = AjaxResult.success(); + ajax.put("seq", seqService.generateTempSeq(params.get("key").toString(), Integer.parseInt(params.get("len").toString()))); + return ajax; + } + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/common/FileUploadController.java b/zbf-admin/src/main/java/com/zbf/web/controller/common/FileUploadController.java new file mode 100644 index 0000000..0913be5 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/common/FileUploadController.java @@ -0,0 +1,50 @@ +package com.zbf.web.controller.common; + +import com.zbf.common.annotation.Anonymous; +import com.zbf.common.config.RuoYiConfig; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.exception.NonCaptureException; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.file.FileUploadUtils; +import com.zbf.common.utils.file.FileUtils; +import com.zbf.framework.config.ServerConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +@RestController +@RequestMapping("/file") +public class FileUploadController { + + private final Logger log = LoggerFactory.getLogger(FileUploadController.class); + + @Autowired + private ServerConfig serverConfig; + + @Anonymous + @PostMapping("/upload") + @SuppressWarnings("DuplicatedCode") + public AjaxResult uploadFile(MultipartFile file) { + try { + log.info("文件 {} 上传中...", file.getOriginalFilename()); + // 上传文件路径 + String filePath = RuoYiConfig.getUploadPath(); + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = serverConfig.getUrl() + fileName; + AjaxResult ajax = AjaxResult.success(); + ajax.put("url", url); + ajax.put("fileName", fileName); + ajax.put("newFileName", FileUtils.getName(fileName)); + ajax.put("originalFilename", file.getOriginalFilename()); + log.info("文件 {} 上传成功!", file.getOriginalFilename()); + return ajax; + } catch (Exception e) { + throw new NonCaptureException(StringUtils.format("文件 {} 上传失败!", file.getOriginalFilename()), e); + } + } +} \ No newline at end of file diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/DynamicFlowController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/DynamicFlowController.java new file mode 100644 index 0000000..3c804f1 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/DynamicFlowController.java @@ -0,0 +1,233 @@ +package com.zbf.web.controller.flowable; + + +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.domain.TCkOrders; +import com.zbf.system.service.ITCkOrdersService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.flowable.bpmn.BpmnAutoLayout; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.*; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.runtime.Execution; +import org.flowable.task.api.Task; +import org.flowable.validation.ValidationError; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import java.util.*; + +@Api(value = "动态流程接口") +@Controller +@RequestMapping("/dynamic/flow") +public class DynamicFlowController { + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @Resource + RepositoryService repositoryService; + + @Resource + private HistoryService historyService; + @Autowired + private ITCkOrdersService tCkOrdersService; + + + + @ApiOperation("遍历流程信息") + @GetMapping(value = "/info/{processInstanceId}") + @ResponseBody + public AjaxResult remove(@PathVariable String processInstanceId) { + String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult().getProcessDefinitionId(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); + for (FlowElement flowElement : flowElements) { + if (flowElement instanceof UserTask) { + UserTask userTask = (UserTask) flowElement; + System.out.println(flowElement.getName()); + System.out.println(flowElement.getId()); + System.out.println(userTask.getAssignee()); + String assigneeEl = userTask.getAssignee(); + if (StringUtils.isBlank(assigneeEl)) { + continue; + } + if (assigneeEl.startsWith("${") && assigneeEl.endsWith("}") && assigneeEl.length() > 3) { + String assignee = assigneeEl.substring(2, assigneeEl.length() - 2); + System.out.println("assignee:" + assignee); + } + } + } + return AjaxResult.success(flowElements); + } + + @ApiOperation("撤销:强制结束一个流程") + @GetMapping(value = "/forceEnd/{taskId}") + @ResponseBody + public AjaxResult forceEnd(@PathVariable String taskId) { + Task t = taskService.createTaskQuery().taskId(taskId).singleResult(); + String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + // 寻找流程实例当前任务的activeId + Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult(); + String activityId = execution.getActivityId(); + FlowNode currentNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityId); + // 创建结束节点和连接线 + EndEvent end = new EndEvent(); + end.setName("强制结束"); + end.setId("forceEnd"); + List newSequenceFlowList = new ArrayList(); + SequenceFlow newSequenceFlow = new SequenceFlow(); + newSequenceFlow.setId("newFlow"); + newSequenceFlow.setSourceFlowElement(currentNode); + newSequenceFlow.setTargetFlowElement(end); + newSequenceFlowList.add(newSequenceFlow); + // 备份原有方向 + List dataflows = currentNode.getOutgoingFlows(); + List oriSequenceFlows = new ArrayList(); + oriSequenceFlows.addAll(dataflows); + // 清空原有方向 + currentNode.getOutgoingFlows().clear(); + // 设置新方向 + currentNode.setOutgoingFlows(newSequenceFlowList); + // 完成当前任务 + taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "撤销流程"); + taskService.complete(taskId); + // 恢复原有方向 + currentNode.setOutgoingFlows(oriSequenceFlows); + return AjaxResult.success(); + } + + @ApiOperation("驳回或跳转到指定节点") + @GetMapping(value = "/jump/{taskId}/{sid}/{rejectReason}") + @ResponseBody + public AjaxResult jump(@PathVariable String taskId, @PathVariable String sid,@PathVariable String rejectReason) { + Task t = taskService.createTaskQuery().taskId(taskId).singleResult(); + String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + // 寻找流程实例当前任务的activeId + Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult(); + String activityId = execution.getActivityId(); + FlowNode currentNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityId); + FlowNode targetNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(sid); + // 创建连接线 + if(!"startOutbound".equals(sid)) { + List newSequenceFlowList = new ArrayList(); + SequenceFlow newSequenceFlow = new SequenceFlow(); + newSequenceFlow.setId("newFlow"); + newSequenceFlow.setSourceFlowElement(currentNode); + newSequenceFlow.setTargetFlowElement(targetNode); + newSequenceFlowList.add(newSequenceFlow); + // 备份原有方向 + List dataflows = currentNode.getOutgoingFlows(); + List oriSequenceFlows = new ArrayList(); + oriSequenceFlows.addAll(dataflows); + // 清空原有方向 + currentNode.getOutgoingFlows().clear(); + // 设置新方向 + currentNode.setOutgoingFlows(newSequenceFlowList); + // 完成当前任务 + taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "跳转节点"); + taskService.complete(taskId); + // 恢复原有方向 + currentNode.setOutgoingFlows(oriSequenceFlows); + }else{ + //删除实例任务 + System.out.println(rejectReason); + //更新出库通知单表 + Map variables = runtimeService.getVariables(execution.getId()); + System.out.println(variables); + String deliveryId =(String) variables.get("deliveryId"); + TCkOrders tCkOrders1 = tCkOrdersService.selectTCkOrdersByDeliveryId(deliveryId); + TCkOrders tCkOrders = new TCkOrders(); + tCkOrders.setId(tCkOrders1.getId()); + tCkOrders.setAuditMan(t.getAssignee()); + tCkOrders.setAuditDate(new Date()); + tCkOrders.setIsAudit("3"); + tCkOrders.setRejectReason(rejectReason); + tCkOrdersService.updateTCkOrders(tCkOrders); + + runtimeService.deleteProcessInstance(t.getProcessInstanceId(),"流程结束删除"); + } + return AjaxResult.success(); + } + + @ApiOperation("动态创建流程") + @GetMapping(value = "/createProcess") + @ResponseBody + public AjaxResult createProcess() { + // 开始节点的属性 + StartEvent startEvent=new StartEvent(); + startEvent.setId("start"); + startEvent.setName("start"); + // 普通UserTask节点 + UserTask userTask=new UserTask(); + userTask.setId("userTask"); + userTask.setName("审批任务"); + // 结束节点属性 + EndEvent endEvent=new EndEvent(); + endEvent.setId("end"); + endEvent.setName("end"); + // 连线信息 + List flows=new ArrayList(); + List toEnd=new ArrayList(); + SequenceFlow s1=new SequenceFlow(); + s1.setId("flow1"); + s1.setName("flow1"); + s1.setSourceRef(startEvent.getId()); + s1.setTargetRef(userTask.getId()); + flows.add(s1); + + SequenceFlow s2=new SequenceFlow(); + s2.setId("flow2"); + s2.setName("flow2"); + s2.setSourceRef(userTask.getId()); + s2.setTargetRef(endEvent.getId()); + toEnd.add(s2); + startEvent.setOutgoingFlows(flows); + userTask.setOutgoingFlows(toEnd); + + // 给流程对象添加元素 + Process process=new Process(); + process.setId("dynamicProcess"); + process.setName("动态流程"); + process.addFlowElement(startEvent); + process.addFlowElement(s1); + process.addFlowElement(userTask); + process.addFlowElement(s2); + process.addFlowElement(endEvent); + // 创建模型对象 + BpmnModel bpmnModel=new BpmnModel(); + bpmnModel.addProcess(process); + // 流程图自动布局 + new BpmnAutoLayout(bpmnModel).execute(); + + // 模型合法性校验 + List validationErrorList = repositoryService.validateProcess(bpmnModel); + if (validationErrorList.size() == 0) { + // 模型合法就部署流程 + Deployment deploy = repositoryService.createDeployment().category("dynamic") + .key("dynamicProcess") + .addBpmnModel("dynamicProcess.bpmn20.xml", bpmnModel) + .deploy(); + return AjaxResult.success("success"); + } else { + return AjaxResult.error("fail"); + } + } + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowController.java new file mode 100644 index 0000000..1a8a1bd --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowController.java @@ -0,0 +1,224 @@ +package com.zbf.web.controller.flowable; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.utils.StringUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.io.IOUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.editor.constants.ModelDataJsonConstants; +import org.flowable.editor.language.json.converter.BpmnJsonConverter; +import org.flowable.engine.ProcessEngineConfiguration; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.repository.ProcessDefinitionQuery; +import org.flowable.image.ProcessDiagramGenerator; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipInputStream; +import com.zbf.system.domain.Process; + +/** + * 流程管理 + */ +@Api(value = "部署管理接口") +@Controller +@RequestMapping("/flow/manage") +public class FlowController extends BaseController { + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @Resource + RepositoryService repositoryService; + + @Resource + ProcessEngineConfiguration configuration; + + private String prefix = "flowable/manage"; + + @GetMapping("") + public String processList() + { + return prefix + "/processList"; + } + + @GetMapping("deploy") + public String deploy() + { + return prefix + "/deployProcess"; + } + + @ApiOperation("上传一个工作流文件") + @RequestMapping(value = "/uploadworkflow", method = RequestMethod.POST) + @ResponseBody + public AjaxResult fileupload(@RequestParam MultipartFile uploadfile) { + try { + String filename = uploadfile.getOriginalFilename(); + InputStream is = uploadfile.getInputStream(); + if (filename.endsWith("zip")) { + repositoryService.createDeployment().name(filename).addZipInputStream(new ZipInputStream(is)).deploy(); + } else if (filename.endsWith("bpmn") || filename.endsWith("xml")) { + repositoryService.createDeployment().name(filename).addInputStream(filename, is).deploy(); + } else { + return AjaxResult.error("文件格式错误"); + } + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("部署失败"); + } + return AjaxResult.success("部署成功"); + } + + @ApiOperation("查询已部署工作流列表") + @RequestMapping(value = "/getprocesslists", method = RequestMethod.POST) + @ResponseBody + public TableDataInfo getlist(@RequestParam(required = false) String key, @RequestParam(required = false) String name, + @RequestParam(required = false) Boolean latest, Integer pageSize, Integer pageNum) { + ProcessDefinitionQuery queryCondition = repositoryService.createProcessDefinitionQuery(); + if (StringUtils.isNotEmpty(key)) { + queryCondition.processDefinitionKey(key); + } + if (StringUtils.isNotEmpty(name)) { + queryCondition.processDefinitionName(name); + } + if (latest) { + queryCondition.latestVersion(); + } + int total = queryCondition.list().size(); + int start = (pageNum - 1) * pageSize; + List pageList = queryCondition.orderByDeploymentId().desc().listPage(start, pageSize); + List mylist = new ArrayList(); + for (int i = 0; i < pageList.size(); i++) { + Process p = new Process(); + p.setDeploymentId(pageList.get(i).getDeploymentId()); + p.setId(pageList.get(i).getId()); + p.setKey(pageList.get(i).getKey()); + p.setName(pageList.get(i).getName()); + p.setResourceName(pageList.get(i).getResourceName()); + p.setDiagramresourceName(pageList.get(i).getDiagramResourceName()); + p.setSuspended(pageList.get(i).isSuspended()); + p.setVersion(pageList.get(i).getVersion()); + mylist.add(p); + } + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(mylist); + rspData.setTotal(total); + return rspData; + } + + @ApiOperation("删除一次部署的工作流") + @RequestMapping(value = "/remove/{deploymentId}", method = RequestMethod.POST) + @ResponseBody + public AjaxResult remove(@PathVariable String deploymentId) { + repositoryService.deleteDeployment(deploymentId, true); + return AjaxResult.success(); + } + + + @ApiOperation("查看工作流图片") + @RequestMapping(value = "/showresource", method = RequestMethod.GET) + public void showresource(@RequestParam("pdid") String pdid, + HttpServletResponse response) throws Exception { + response.setContentType("image/jpeg;charset=UTF-8"); + response.setHeader("Content-Disposition","inline;filename=process.jpg"); + BpmnModel bpmnModel = repositoryService.getBpmnModel(pdid); + ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator(); + InputStream is = diagramGenerator.generateDiagram(bpmnModel, "png", "宋体", "宋体", "宋体", configuration.getClassLoader(), true); + ServletOutputStream output = response.getOutputStream(); + IOUtils.copy(is, output); + } + + @ApiOperation("查看工作流定义") + @RequestMapping(value = "/showProcessDefinition/{pdid}/{resource}", method = RequestMethod.GET) + public void showProcessDefinition(@PathVariable("pdid") String pdid, @PathVariable(value="resource") String resource, + HttpServletResponse response) throws Exception { + response.setContentType("application/xml"); + response.setHeader("Content-Disposition","inline;filename=process.bpmn20.xml"); + InputStream is = repositoryService.getResourceAsStream(pdid, resource); + ServletOutputStream output = response.getOutputStream(); + IOUtils.copy(is, output); + } + + @ApiOperation("将流程定义转为模型") + @RequestMapping(value = "/exchangeProcessToModel/{pdid}", method = RequestMethod.GET) + @ResponseBody + public String exchangeProcessToModel(@PathVariable("pdid") String pdid, HttpServletResponse response) throws Exception { + ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(pdid).singleResult(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId()); + ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel); + Model modelData = repositoryService.newModel(); + modelData.setKey(definition.getKey()); + modelData.setName(definition.getName()); + modelData.setCategory(definition.getCategory()); + ObjectNode modelJson = new ObjectMapper().createObjectNode(); + modelJson.put(ModelDataJsonConstants.MODEL_NAME, definition.getName()); + modelJson.put(ModelDataJsonConstants.MODEL_DESCRIPTION, definition.getDescription()); + List models = repositoryService.createModelQuery().modelKey(definition.getKey()).list(); + if (models.size() > 0) { + Integer version = models.get(0).getVersion(); + version++; + modelJson.put(ModelDataJsonConstants.MODEL_REVISION, version); + // 删除旧模型 + repositoryService.deleteModel(models.get(0).getId()); + modelData.setVersion(version); + } else { + modelJson.put(ModelDataJsonConstants.MODEL_REVISION, 1); + } + modelData.setMetaInfo(modelJson.toString()); + modelData.setDeploymentId(definition.getDeploymentId()); + // 保存新模型 + repositoryService.saveModel(modelData); + // 保存模型json + repositoryService.addModelEditorSource(modelData.getId(), objectNode.toString().getBytes(StandardCharsets.UTF_8)); + return objectNode.toString(); + } + + @ApiOperation("挂起一个流程定义") + @RequestMapping(value = "/suspendProcessDefinition", method = RequestMethod.GET) + @ResponseBody + public AjaxResult suspendProcessDefinition(@RequestParam("pdid") String pdid, @RequestParam("flag") Boolean flag, + @RequestParam(value="date", required = false) String date) throws Exception { + if (StringUtils.isNotEmpty(date)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + repositoryService.suspendProcessDefinitionById(pdid, flag, sdf.parse(date)); + } else { + repositoryService.suspendProcessDefinitionById(pdid, flag, null); + } + return AjaxResult.success(); + } + + @ApiOperation("激活一个流程定义") + @RequestMapping(value = "/activateProcessDefinition", method = RequestMethod.GET) + @ResponseBody + public AjaxResult activateProcessDefinition(@RequestParam("pdid") String pdid, @RequestParam("flag") Boolean flag, @RequestParam(value="date", required = false) String date) throws Exception { + if (StringUtils.isNotEmpty(date)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + repositoryService.activateProcessDefinitionById(pdid, flag, sdf.parse(date)); + } else { + repositoryService.activateProcessDefinitionById(pdid, flag, null); + } + return AjaxResult.success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowDesignerController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowDesignerController.java new file mode 100644 index 0000000..e84bae1 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowDesignerController.java @@ -0,0 +1,143 @@ +package com.zbf.web.controller.flowable; + +import com.alibaba.fastjson2.JSONObject; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.commons.lang3.StringUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.editor.constants.ModelDataJsonConstants; +import org.flowable.editor.language.json.converter.BpmnJsonConverter; +import org.flowable.engine.IdentityService; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.repository.Model; +import org.flowable.validation.ProcessValidator; +import org.flowable.validation.ProcessValidatorFactory; +import org.flowable.validation.ValidationError; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Collections; +import java.util.List; + +@RestController +@RequestMapping("/app/rest/") +public class FlowDesignerController { + + + @Autowired + RepositoryService repositoryService; + + @Autowired + IdentityService identityService; + + @Autowired + RuntimeService runtimeService; + + @Autowired + TaskService taskService; + + @Autowired + protected ObjectMapper objectMapper; + + /** + * 获得 + * @param modelId + * @return + */ + @RequestMapping(value = "/models/{modelId}/editor/json", method = RequestMethod.GET, produces = "application/json") + public ObjectNode getModelJSON(@PathVariable String modelId) { + Model model = repositoryService.getModel(modelId); + ObjectNode modelNode = objectMapper.createObjectNode(); + modelNode.put("modelId", model.getId()); + modelNode.put("name", model.getName()); + modelNode.put("key", model.getKey()); + modelNode.put("description", JSONObject.parseObject(model.getMetaInfo()).getString("description")); + modelNode.putPOJO("lastUpdated", model.getLastUpdateTime()); + byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId); + if (null != modelEditorSource && modelEditorSource.length > 0) { + try { + ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(modelEditorSource); + editorJsonNode.put("modelType", "model"); + modelNode.put("model", editorJsonNode); + } catch (Exception e) { + e.printStackTrace(); + } + + } else { + ObjectNode editorJsonNode = objectMapper.createObjectNode(); + editorJsonNode.put("id", "canvas"); + editorJsonNode.put("resourceId", "canvas"); + ObjectNode stencilSetNode = objectMapper.createObjectNode(); + stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); + editorJsonNode.put("modelType", "model"); + modelNode.put("model", editorJsonNode); + } + return modelNode; + } + + /** + * 保存 + * @param modelId + * @param values + */ + @RequestMapping(value = "models/{modelId}/editor/json", method = RequestMethod.POST) + public void saveModel(@PathVariable String modelId, @RequestBody MultiValueMap values) { + + String json = values.getFirst("json_xml"); + String name = values.getFirst("name"); + String description = values.getFirst("description"); + String key = values.getFirst("key"); + + Model modelData = repositoryService.getModel(modelId); + if (null == modelData) { + modelData = repositoryService.newModel(); + } + + ObjectNode modelNode = null; + try { + modelNode = (ObjectNode) new ObjectMapper().readTree(json); + } catch (IOException e) { + e.printStackTrace(); + } + + ObjectNode modelObjectNode = objectMapper.createObjectNode(); + modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name); + modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1); + description = StringUtils.defaultString(description); + modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description); + modelData.setMetaInfo(modelObjectNode.toString()); + modelData.setName(name); + modelData.setKey(StringUtils.defaultString(key)); + // 显示发布按钮 + modelData.setDeploymentId(null); + repositoryService.saveModel(modelData); + try { + repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8")); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + /** + * 校验流程图 + */ + @PostMapping(value = "/model/validate", consumes = MediaType.APPLICATION_JSON_VALUE) + public List validate(@RequestBody JsonNode body) { + if (body != null && body.has("stencilset")) { + BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(body); + ProcessValidator validator = new ProcessValidatorFactory().createDefaultProcessValidator(); + List errors = validator.validate(bpmnModel); + return errors; + } + return Collections.emptyList(); + } + + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowMonitorController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowMonitorController.java new file mode 100644 index 0000000..0f3ffea --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/FlowMonitorController.java @@ -0,0 +1,456 @@ +package com.zbf.web.controller.flowable; + + +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.bean.BeanUtils; +import com.zbf.system.domain.*; +import com.zbf.system.mapper.ActRuExecutionMapper; +import com.zbf.system.service.ISysUserService; +import com.zbf.web.util.ActivitiTracingChart; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.cmmn.engine.impl.behavior.impl.ChildTaskActivityBehavior; +import org.flowable.engine.*; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricDetail; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.history.HistoricProcessInstanceQuery; +import org.flowable.engine.impl.persistence.entity.HistoricDetailVariableInstanceUpdateEntity; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.runtime.ProcessInstanceQuery; +import org.flowable.engine.task.Comment; +import org.flowable.job.api.*; +import org.flowable.task.api.Task; +import org.flowable.variable.api.history.HistoricVariableInstance; +import org.flowable.variable.api.history.HistoricVariableInstanceQuery; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 流程监控 + */ +@Api(value = "流程监控接口") +@Controller +@RequestMapping("/flow/monitor") +public class FlowMonitorController extends BaseController { + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @Resource + private HistoryService historyService; + + @Resource + ManagementService managementService; + + @Resource + RepositoryService repositoryService; + + @Resource + ProcessEngineConfiguration configuration; + + @Resource + private ActivitiTracingChart activitiTracingChart; + + @Resource + ActRuExecutionMapper actRuExecutionMapper; + @Resource + private ISysUserService userService; + + + private String prefix = "flowable/monitor"; + + @GetMapping("/instance") + public String processList() { + return prefix + "/processInstance"; + } + + @GetMapping("/history") + public String processHistory() { + return prefix + "/processHistory"; + } + + @GetMapping("/execution") + public String execution() { + return prefix + "/execution"; + } + + @GetMapping("/historyDetail") + public String historyDetail(String processInstanceId, ModelMap mmap) { + mmap.put("processInstanceId", processInstanceId); + return prefix + "/processHistoryDetail"; + } + + @GetMapping("/processVariablesDetail") + public String processVariablesDetail(String processInstanceId, ModelMap mmap) { + mmap.put("processInstanceId", processInstanceId); + return prefix + "/processVariablesDetail"; + } + + @ApiOperation("查询所有正在运行的流程实例列表") + @RequestMapping(value = "/listProcess", method = RequestMethod.POST) + @ResponseBody + public TableDataInfo getlist(@RequestParam(required = false) String bussinesskey, @RequestParam(required = false) String name, + Integer pageSize, Integer pageNum) { + int start = (pageNum - 1) * pageSize; + ProcessInstanceQuery condition = runtimeService.createProcessInstanceQuery(); + if (StringUtils.isNotEmpty(bussinesskey)) { + condition.processInstanceBusinessKey(bussinesskey); + } + if (StringUtils.isNotEmpty(name)) { + condition.processDefinitionName(name); + } + int total = condition.orderByProcessDefinitionId().desc().list().size(); + List processList = condition.orderByProcessDefinitionId().desc().listPage(start, pageSize); + List flows = new ArrayList<>(); + processList.stream().forEach(p -> { + FlowInfo info = new FlowInfo(); + info.setProcessInstanceId(p.getProcessInstanceId()); + info.setBusinessKey(p.getBusinessKey()); + info.setName(p.getProcessDefinitionName()); + info.setStartTime(p.getStartTime()); + info.setStartUserId(p.getStartUserId()); + info.setSuspended(p.isSuspended()); + info.setEnded(p.isEnded()); + // 查看当前活动任务 + List tasks = taskService.createTaskQuery().processInstanceId(p.getProcessInstanceId()).list(); + String taskName = ""; + String assignee = ""; + for (Task t : tasks) { + taskName += t.getName() + ","; + assignee += t.getAssignee() + ","; + } + taskName = taskName.substring(0, taskName.length() -1); + assignee = assignee.substring(0, assignee.length() -1); + info.setCurrentTask(taskName); + info.setAssignee(assignee); + flows.add(info); + }); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(flows); + rspData.setTotal(total); + return rspData; + } + + @ApiOperation("查询所有流程实例列表-包含在运行和已结束") + @RequestMapping(value = "/listHistoryProcess", method = RequestMethod.POST) + @ResponseBody + public TableDataInfo listHistoryProcess(@RequestParam(required = false) String bussinesskey, @RequestParam(required = false) String name, + Integer pageSize, Integer pageNum) { + int start = (pageNum - 1) * pageSize; + HistoricProcessInstanceQuery condition = historyService.createHistoricProcessInstanceQuery().finished(); //finished 只查询历史 + if (StringUtils.isNotEmpty(bussinesskey)) { + condition.processInstanceBusinessKey(bussinesskey); + } + if (StringUtils.isNotEmpty(name)) { + condition.processDefinitionName(name); + } + //根据发起人查询 + condition.startedBy(SecurityUtils.getUsername()); + int total = condition.orderByProcessInstanceStartTime().desc().list().size(); + List processList = condition.orderByProcessInstanceStartTime().desc().listPage(start, pageSize); + List flows = new ArrayList<>(); + processList.stream().forEach(p -> { + FlowInfo info = new FlowInfo(); + info.setProcessInstanceId(p.getId()); + info.setBusinessKey(p.getBusinessKey()); + if("Flowable_Pickingout".equalsIgnoreCase(p.getProcessDefinitionName()) || + "Pickingout_Audit".equalsIgnoreCase(p.getProcessDefinitionName())){ + info.setName("出库通知单审批申请"); + }else{ + info.setName(p.getProcessDefinitionName()); + } + + info.setStartTime(p.getStartTime()); + info.setEndTime(p.getEndTime()); +// info.setStartUserId(p.getStartUserId()); + //根据用户id查询用户名称 + SysUser user = userService.selectUserByUserName(p.getStartUserId()); + info.setStartUserId(user.getNickName()); + if (p.getEndTime() == null) { + info.setEnded(false); + // 查看当前活动任务 + List tasks = taskService.createTaskQuery().processInstanceId(p.getId()).list(); + String taskName = ""; + String assignee = ""; + for (Task t : tasks) { + taskName += t.getName() + ","; + assignee += t.getAssignee() + ","; + } + taskName = taskName.substring(0, taskName.length() -1); + assignee = assignee.substring(0, assignee.length() -1); + info.setCurrentTask(taskName); + info.setAssignee(assignee); + } else { + info.setEnded(true); + } + flows.add(info); + }); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(flows); + rspData.setTotal(total); + return rspData; + } + + @ApiOperation("查询一个流程的活动历史") + @RequestMapping(value = "/history/{processInstanceId}", method = RequestMethod.POST) + @ResponseBody + public TableDataInfo history(@PathVariable String processInstanceId, Integer pageSize, Integer pageNum) { + int start = (pageNum - 1) * pageSize; + List history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().listPage(start, pageSize); + int total = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list().size(); + //查看历史变量 + List list = historyService.createHistoricVariableInstanceQuery() + .processInstanceId(processInstanceId) + .list(); + + List infos = new ArrayList<>(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + history.stream().forEach(h->{ + TaskInfo info = new TaskInfo(); + info.setProcessInstanceId(h.getProcessInstanceId()); + info.setStartTime(sdf.format(h.getStartTime())); + if (h.getEndTime() != null) { + info.setEndTime(sdf.format(h.getEndTime())); + } + + SysUser user = userService.selectUserByUserName(h.getAssignee()); + if(user != null){ + info.setAssignee(user.getNickName()); + }else{ + info.setAssignee(h.getAssignee()); + } + + List variableInstances = list.stream() + .filter(s -> s.getVariableName().equals(h.getAssignee())) // 根据用户编号属性过滤 + .collect(Collectors.toList()); + if(variableInstances.size() > 0){ + String r = (String)variableInstances.get(0).getValue(); + info.setResult("true".equals(r) ? "同意" : ("false".equals(r) ? "拒绝" : "")); + } + + + info.setTaskName(h.getActivityName()); + List comments = taskService.getTaskComments(h.getTaskId()); + if (comments.size() > 0) { + info.setComment(comments.get(0).getFullMessage()); + } + infos.add(info); + }); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(infos); + rspData.setTotal(total); + return rspData; + } + + @ApiOperation("查询所有正在运行的执行实例列表") + @RequestMapping(value = "/listExecutions", method = RequestMethod.POST) + @ResponseBody + public List listExecutions(@RequestParam(required = false) String name) { + List executionList = actRuExecutionMapper.selectActRuExecutionListByProcessName(name); + List flows = new ArrayList<>(); + executionList.stream().forEach(p -> { + FlowInfo info = new FlowInfo(); + info.setProcessInstanceId(p.getProcInstId()); + if (p.getSuspensionState() == 1L) { + info.setSuspended(false); + } else { + info.setSuspended(true); + } + if (p.getIsActive() == 0) { + info.setActive(false); + } else { + info.setActive(true); + } + if (p.getActId() != null) { + ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(p.getProcInstId()).singleResult(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(process.getProcessDefinitionId()); + Map nodes = bpmnModel.getMainProcess().getFlowElementMap(); + info.setCurrentTask(nodes.get(p.getActId()).getName()); + info.setName(process.getProcessDefinitionName()); + } else { + ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(p.getProcInstId()).singleResult(); + info.setStartTime(process.getStartTime()); + info.setStartUserId(process.getStartUserId()); + info.setName(process.getProcessDefinitionName()); + List tasks = taskService.createTaskQuery().processInstanceId(p.getProcInstId()).list(); + String taskName = ""; + for (Task t : tasks) { + taskName += t.getName() + ","; + } + taskName = taskName.substring(0, taskName.length() -1); + info.setCurrentTask(taskName); + } + info.setStartTime(p.getStartTime()); + info.setExecutionId(p.getId()); + if (p.getParentId() == null) { + info.setParentExecutionId("0"); + } else { + info.setParentExecutionId(p.getParentId()); + } + flows.add(info); + }); + return flows; + } + + @ApiOperation("流程图进度追踪") + @RequestMapping(value = {"/traceProcess/{processInstanceId}"}, method = RequestMethod.GET) + public void traceprocess(@PathVariable String processInstanceId, HttpServletResponse response) throws IOException { + response.setContentType("image/jpeg;charset=UTF-8"); + response.setHeader("Content-Disposition", "inline; filename= trace.png"); + activitiTracingChart.generateFlowChart(processInstanceId, response.getOutputStream()); + } + + @ApiOperation("挂起一个流程实例") + @RequestMapping(value = "/suspend/{processInstanceId}", method = RequestMethod.GET) + @ResponseBody + public AjaxResult suspend(@PathVariable String processInstanceId) { + runtimeService.suspendProcessInstanceById(processInstanceId); + return AjaxResult.success(); + } + + @ApiOperation("唤醒一个挂起的流程实例") + @RequestMapping(value = "/run/{processInstanceId}", method = RequestMethod.GET) + @ResponseBody + public AjaxResult rerun(@PathVariable String processInstanceId) { + runtimeService.activateProcessInstanceById(processInstanceId); + return AjaxResult.success(); + } + + @ApiOperation("查询一个流程的变量") + @RequestMapping(value = "/variables/{processInstanceId}", method = RequestMethod.POST) + @ResponseBody + public TableDataInfo variables(@PathVariable String processInstanceId, Integer pageSize, Integer pageNum) { + int start = (pageNum - 1) * pageSize; + List variables = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByVariableName().asc().listPage(start, pageSize); + int total = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).orderByVariableName().asc().list().size(); + List infos = new ArrayList<>(); + variables.forEach(v->{ + VariableInfo info = new VariableInfo(); + BeanUtils.copyBeanProp(info, v); + if (v.getValue() != null) { + info.setValue(v.getValue().toString()); + } + infos.add(info); + }); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(infos); + rspData.setTotal(total); + return rspData; + } + + @ApiOperation("按类型查询所有的作业列表:定时作业、异步作业、挂起作业、死亡作业") + @PostMapping(value = "/listJobs") + @ResponseBody + public TableDataInfo listJobs(@RequestParam(required = false) String processDefinitionId, @RequestParam(required = false) String startDate, + @RequestParam(required = false) String endDate,@RequestParam Integer type, Integer pageSize, Integer pageNum) throws Exception { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + int start = (pageNum - 1) * pageSize; + int total = 0; + List jobList = null; + ArrayList jobs = new ArrayList<>(); + TableDataInfo rspData = new TableDataInfo(); + if (type == 1) { + // 定时作业 + TimerJobQuery condition = managementService.createTimerJobQuery(); + if (StringUtils.isNotEmpty(processDefinitionId)) { + condition.processDefinitionId(processDefinitionId); + } + if (StringUtils.isNotEmpty(startDate)) { + condition.duedateHigherThan(sdf.parse(startDate)); + } + if (StringUtils.isNotEmpty(endDate)) { + condition.duedateLowerThan(sdf.parse(endDate)); + } + total = condition.orderByJobDuedate().desc().list().size(); + jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize); + rspData.setRows(jobList); + } else if (type == 2) { + // 异步作业 + JobQuery condition = managementService.createJobQuery(); + if (StringUtils.isNotEmpty(processDefinitionId)) { + condition.processDefinitionId(processDefinitionId); + } + if (StringUtils.isNotEmpty(startDate)) { + condition.duedateHigherThan(sdf.parse(startDate)); + } + if (StringUtils.isNotEmpty(endDate)) { + condition.duedateLowerThan(sdf.parse(endDate)); + } + total = condition.orderByJobDuedate().desc().list().size(); + jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize); + rspData.setRows(jobList); + } else if (type == 3) { + // 挂起作业 + SuspendedJobQuery condition = managementService.createSuspendedJobQuery(); + if (StringUtils.isNotEmpty(processDefinitionId)) { + condition.processDefinitionId(processDefinitionId); + } + if (StringUtils.isNotEmpty(startDate)) { + condition.duedateHigherThan(sdf.parse(startDate)); + } + if (StringUtils.isNotEmpty(endDate)) { + condition.duedateLowerThan(sdf.parse(endDate)); + } + total = condition.orderByJobDuedate().desc().list().size(); + jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize); + rspData.setRows(jobList); + } else if (type == 4) { + // 死亡作业 + DeadLetterJobQuery condition = managementService.createDeadLetterJobQuery(); + if (StringUtils.isNotEmpty(processDefinitionId)) { + condition.processDefinitionId(processDefinitionId); + } + if (StringUtils.isNotEmpty(startDate)) { + condition.duedateHigherThan(sdf.parse(startDate)); + } + if (StringUtils.isNotEmpty(endDate)) { + condition.duedateLowerThan(sdf.parse(endDate)); + } + total = condition.orderByJobDuedate().desc().list().size(); + jobList = condition.orderByJobDuedate().desc().listPage(start, pageSize); + + jobList.forEach(j->{ + DeadLetterJob job = new DeadLetterJob(); + job.setId(j.getId()); + job.setDueDate(j.getDuedate()); + job.setJobType(j.getJobType()); + job.setExceptionMessage(j.getExceptionMessage()); + job.setJobHandlerType(j.getJobHandlerType()); + job.setProcessDefId(j.getProcessDefinitionId()); + job.setProcessInstanceId(j.getProcessInstanceId()); + job.setExecutionId(j.getExecutionId()); + jobs.add(job); + }); + rspData.setRows(jobs); + } + rspData.setCode(0); + rspData.setTotal(total); + return rspData; + } + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/LeaveapplyController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/LeaveapplyController.java new file mode 100644 index 0000000..b83fdfb --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/LeaveapplyController.java @@ -0,0 +1,231 @@ +package com.zbf.web.controller.flowable; + + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.Leaveapply; +import com.zbf.system.service.ILeaveapplyService; +import com.zbf.system.service.ISysUserService; +import io.swagger.annotations.ApiOperation; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; + +/** + * 请假Controller + * + * @author shenzhanwang + * @date 2022-04-02 + */ +@Controller +@RequestMapping("/leaveapply") +public class LeaveapplyController extends BaseController +{ + private String prefix = "flowable/leaveapply"; + + @Autowired + private ILeaveapplyService leaveapplyService; + + @Autowired + private ISysUserService userService; + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @GetMapping() + public String leaveapply() + { + return prefix + "/leaveapply"; + } + + /** + * 部门领导审批 + * @return + */ + @ApiOperation("部门领导审批") + @GetMapping("/deptleadercheck") + @ResponseBody + public AjaxResult deptleadercheck(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 人事审批 + * @return + */ + @ApiOperation("人事审批") + @GetMapping("/hrcheck") + @ResponseBody + public AjaxResult hrcheck(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 销假 + * @return + */ + @ApiOperation("销假") + @GetMapping("/destroyapply") + @ResponseBody + public AjaxResult destroyapply(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + + /** + * 调整申请 + * @return + */ + @ApiOperation("调整申请") + @GetMapping("/modifyapply") + @ResponseBody + public AjaxResult modifyapply(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 发起请假申请 + * 驳回后使用 + * @return + */ + @ApiOperation("发起请假申请-驳回后使用") + @GetMapping("/addleave") + @ResponseBody + public AjaxResult addLeave(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Leaveapply apply = leaveapplyService.selectLeaveapplyById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 查询请假列表 + */ + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(Leaveapply leaveapply) + { + String username = getUsername(); + leaveapply.setUserId(username); + startPage(); + List list = leaveapplyService.selectLeaveapplyList(leaveapply); + return getDataTable(list); + } + + /** + * 导出请假列表 + */ + @Log(title = "请假", businessType = BusinessType.EXPORT) + @PostMapping("/export") + @ResponseBody + public AjaxResult export(Leaveapply leaveapply) + { + SysUser user = SecurityUtils.getLoginUser().getUser(); + String username = getUsername(); + leaveapply.setUserId(username); + List list = leaveapplyService.selectLeaveapplyList(leaveapply); + ExcelUtil util = new ExcelUtil(Leaveapply.class); + return util.exportExcel(list, "请假数据"); + } + + /** + * 当前登录用户 + */ + @ApiOperation("当前登录用户") + @GetMapping("/cuurentUser") + @ResponseBody + public AjaxResult cuurentUser() + { + SysUser user = SecurityUtils.getLoginUser().getUser(); + return AjaxResult.success(user); + } + + + /** + * 发起请假流程 + */ + @Log(title = "请假", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(Leaveapply leaveapply) + { + leaveapply.setApplyTime(new Date()); + return toAjax(leaveapplyService.insertLeaveapply(leaveapply)); + } + + @PostMapping("/update") + @ResponseBody + public AjaxResult update(Leaveapply leaveapply) + { + return toAjax(leaveapplyService.updateLeaveapply(leaveapply)); + } + + /** + * 删除请假 + */ + @Log(title = "请假", businessType = BusinessType.DELETE) + @PostMapping( "/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(leaveapplyService.deleteLeaveapplyByIds(ids)); + } + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/MeetingController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/MeetingController.java new file mode 100644 index 0000000..d290c01 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/MeetingController.java @@ -0,0 +1,133 @@ +package com.zbf.web.controller.flowable; + + +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.Meeting; +import com.zbf.system.service.IMeetingService; +import com.zbf.system.service.ISysUserService; +import io.swagger.annotations.ApiOperation; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import java.util.List; + +@Controller +@RequestMapping("/meeting") +public class MeetingController extends BaseController { + + private String prefix = "flowable/meeting"; + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @Autowired + private ISysUserService userService; + + @Autowired + private IMeetingService meetingService; + + + /** + * 查询会议列表 + */ + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(Meeting meeting) + { + startPage(); + List list = meetingService.selectMeetingList(meeting); + return getDataTable(list); + } + + /** + * 导出会议列表 + */ + @PostMapping("/export") + @ResponseBody + public AjaxResult export(Meeting meeting) + { + List list = meetingService.selectMeetingList(meeting); + ExcelUtil util = new ExcelUtil(Meeting.class); + return util.exportExcel(list, "会议数据"); + } + + + /** + * 新增保存会议 + */ + @ApiOperation("新增保存会议") + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(Meeting meeting) + { + return toAjax(meetingService.insertMeeting(meeting)); + } + + @PostMapping("/edit") + @ResponseBody + public AjaxResult edit(Meeting meeting) + { + return toAjax(meetingService.updateMeeting(meeting)); + } + + /** + * 删除会议 + */ + @PostMapping( "/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(meetingService.deleteMeetingByIds(ids)); + } + + /** + * 会议签到 + */ + @ApiOperation("会议签到") + @GetMapping("/signate") + @ResponseBody + public AjaxResult signate(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Meeting apply = meetingService.selectMeetingById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 填写会议纪要 + */ + @ApiOperation("填写会议纪要") + @GetMapping("/input") + @ResponseBody + public AjaxResult input(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Meeting apply = meetingService.selectMeetingById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/ModelManageController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/ModelManageController.java new file mode 100644 index 0000000..d7a7b62 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/ModelManageController.java @@ -0,0 +1,161 @@ +package com.zbf.web.controller.flowable; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.domain.ModelParam; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.poi.util.IOUtils; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.editor.constants.ModelDataJsonConstants; +import org.flowable.editor.language.json.converter.BpmnJsonConverter; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.Model; +import org.flowable.engine.repository.ModelQuery; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; + +@Api(value = "模型管理接口") +@Controller +@RequestMapping("/model/manage") +public class ModelManageController extends BaseController { + + @Resource + RepositoryService repositoryService; + + @Resource + private ObjectMapper objectMapper; + + private String prefix = "flowable/manage"; + + + @ApiOperation("查询所有模型") + @RequestMapping(value = "/modelLists", method = RequestMethod.POST) + @ResponseBody + public TableDataInfo modelLists(@RequestParam(required = false) String key, @RequestParam(required = false) String name, + Integer pageSize, Integer pageNum) { + ModelQuery query = repositoryService.createModelQuery(); + if (StringUtils.isNotEmpty(key)) { + query.modelKey(key); + } + if (StringUtils.isNotEmpty(name)) { + query.modelName(name); + } + int start = (pageNum - 1) * pageSize; + List page = query.orderByCreateTime().desc().listPage(start, pageSize); + int total = repositoryService.createModelQuery().list().size(); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(page); + rspData.setTotal(total); + return rspData; + } + + /** + * 新增模型页面 + * @return + */ + @GetMapping("/add") + public String add() + { + return prefix + "/add"; + } + + /** + * 新增模型 + */ + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(ModelParam modelRequest) throws JsonProcessingException { + Model model = repositoryService.newModel(); + model.setCategory(modelRequest.getCategory()); + model.setKey(modelRequest.getKey()); + ObjectNode modelNode = objectMapper.createObjectNode(); + modelNode.put(ModelDataJsonConstants.MODEL_NAME, modelRequest.getName()); + modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, modelRequest.getDescription()); + modelNode.put(ModelDataJsonConstants.MODEL_REVISION, modelRequest.getVersion()); + model.setMetaInfo(modelNode.toString()); + model.setName(modelRequest.getName()); + model.setVersion(modelRequest.getVersion()); + ModelQuery modelQuery = repositoryService.createModelQuery(); + List list = modelQuery.modelKey(modelRequest.getKey()).list(); + if (list.size() > 0) { + return AjaxResult.error("模型标识不能重复"); + } else { + // 保存模型到act_re_model表 + repositoryService.saveModel(model); + HashMap content = new HashMap(); + content.put("resourceId", model.getId()); + HashMap properties = new HashMap(); + properties.put("process_id", modelRequest.getKey()); + properties.put("name", modelRequest.getName()); + properties.put("category", modelRequest.getCategory()); + content.put("properties", properties); + HashMap stencilset = new HashMap(); + stencilset.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); + content.put("stencilset", stencilset); + // 保存模型文件到act_ge_bytearray表 + repositoryService.addModelEditorSource(model.getId(), objectMapper.writeValueAsBytes(content)); + return AjaxResult.success(model); + } + } + + @RequestMapping("/deploy/{modelId}") + @ResponseBody + public AjaxResult modelDeployment(@PathVariable String modelId) { + try { + Model model = repositoryService.getModel(modelId); + byte[] modelData = repositoryService.getModelEditorSource(modelId); + JsonNode jsonNode = objectMapper.readTree(modelData); + BpmnModel bpmnModel = (new BpmnJsonConverter()).convertToBpmnModel(jsonNode); + Deployment deploy = repositoryService.createDeployment().category(model.getCategory()) + .name(model.getName()).key(model.getKey()) + .addBpmnModel(model.getKey() + ".bpmn20.xml", bpmnModel) + .deploy(); + model.setDeploymentId(deploy.getId()); + repositoryService.saveModel(model); + return AjaxResult.success(); + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("流程图不合规范,请重新设计"); + } + } + + @PostMapping("/remove/{modelId}") + @ResponseBody + public AjaxResult removeModel(@PathVariable String modelId) { + repositoryService.deleteModel(modelId); + return AjaxResult.success("删除成功"); + } + + @GetMapping("/export/{modelId}") + public void modelExport(@PathVariable String modelId, HttpServletResponse response) throws IOException { + byte[] modelData = repositoryService.getModelEditorSource(modelId); + JsonNode jsonNode = objectMapper.readTree(modelData); + BpmnModel bpmnModel = (new BpmnJsonConverter()).convertToBpmnModel(jsonNode); + byte[] xmlBytes = (new BpmnXMLConverter()).convertToXML(bpmnModel, "UTF-8"); + ByteArrayInputStream in = new ByteArrayInputStream(xmlBytes); + String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml"; + response.setHeader("Content-Disposition","attachment;filename=" + filename); + response.setHeader("content-Type", "application/xml"); + response.flushBuffer(); + IOUtils.copy(in, response.getOutputStream()); + } + + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/OutBoundController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/OutBoundController.java new file mode 100644 index 0000000..8c20ea0 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/OutBoundController.java @@ -0,0 +1,286 @@ +package com.zbf.web.controller.flowable; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.Leaveapply; +import com.zbf.system.domain.OutBound; +import com.zbf.system.service.IOutBoundService; +import com.zbf.system.service.ISysUserService; +import io.swagger.annotations.ApiOperation; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 出库申请单Controller + * + * @author tony + * @date 2024-08-07 + */ +@RestController +@RequestMapping("/outbound") +public class OutBoundController extends BaseController +{ + private String prefix = "flowable/outbound"; + + @Autowired + private IOutBoundService outBoundService; + + @Autowired + private ISysUserService userService; + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @GetMapping() + public String outbound() + { + return prefix + "/outbound"; + } + +/** + * 查询出库申请单列表 + */ +@GetMapping("/list") + public TableDataInfo list(OutBound outBound) + { + startPage(); + List list = outBoundService.selectOutBoundList(outBound); + return getDataTable(list); + } + + /** + * 导出出库申请单列表 + */ + @Log(title = "出库申请单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, OutBound outBound) + { + List list = outBoundService.selectOutBoundList(outBound); + ExcelUtil util = new ExcelUtil(OutBound.class); + util.exportExcel(response, list, "出库申请单数据"); + } + + /** + * 获取出库申请单详细信息 + */ + + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(outBoundService.selectOutBoundById(id)); + } + + /** + * 新增出库申请单 + */ + + @Log(title = "出库申请单", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody OutBound outBound) + { + return toAjax(outBoundService.insertOutBound(outBound)); + } + + /** + * 修改出库申请单 + */ + + @Log(title = "出库申请单", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody OutBound outBound) + { + return toAjax(outBoundService.updateOutBound(outBound)); + } + + /** + * 删除出库申请单 + */ + @Log(title = "出库申请单", businessType = BusinessType.DELETE) + @PostMapping("/remove") + public AjaxResult remove(String ids) + { + return toAjax(outBoundService.deleteOutBoundByIds(ids)); + } + + /** + * 启用 + */ + @Log(title = "出库申请单", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(outBoundService.disabledOutBoundByIds(ids)); + } + + /** + * 禁用 + */ + @Log(title = "出库申请单", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(outBoundService.enableOutBoundByIds(ids)); + } + + /** + * 修改状态 + */ + @Log(title = "出库申请单", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody OutBound outBound) { + return toAjax(outBoundService.updateStatus(outBound)); + } + + /** + * 第一审批人 + */ + @ApiOperation("第一审批人") + @GetMapping("/deptmanager") + @ResponseBody + public AjaxResult deptmanager(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + OutBound apply = outBoundService.selectOutBoundById(Long.parseLong(p.getBusinessKey())); + SysUser sysUser = userService.selectUserByUserName(apply.getApplyer()); + if(sysUser != null){ + apply.setApplyer(sysUser.getNickName()); + } + + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + + /** + * 第二审批人 + */ + @ApiOperation("第二审批人") + @GetMapping("/managerName") + @ResponseBody + public AjaxResult manager(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + OutBound apply = outBoundService.selectOutBoundById(Long.parseLong(p.getBusinessKey())); + SysUser sysUser = userService.selectUserByUserName(apply.getApplyer()); + if(sysUser != null){ + apply.setApplyer(sysUser.getNickName()); + } + + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + /** + * 第三审批人 + */ + @ApiOperation("第三审批人") + @GetMapping("/crossDeptManager") + @ResponseBody + public AjaxResult crossDeptManager(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + OutBound apply = outBoundService.selectOutBoundById(Long.parseLong(p.getBusinessKey())); + SysUser sysUser = userService.selectUserByUserName(apply.getApplyer()); + if(sysUser != null){ + apply.setApplyer(sysUser.getNickName()); + } + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + /** + * + * 驳回后使用 + * @return + */ + @ApiOperation("驳回") + @GetMapping("/reject") + @ResponseBody + public AjaxResult reject(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + OutBound apply = outBoundService.selectOutBoundById(Long.parseLong(p.getBusinessKey())); + SysUser sysUser = userService.selectUserByUserName(apply.getApplyer()); + if(sysUser != null){ + apply.setApplyer(sysUser.getNickName()); + } + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + /** + * 发起出库申请 + * @return + */ + @ApiOperation("驳回到发起人") + @GetMapping("/addOutbound") + @ResponseBody + public AjaxResult addLeave(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + OutBound apply = outBoundService.selectOutBoundById(Long.parseLong(p.getBusinessKey())); + SysUser sysUser = userService.selectUserByUserName(apply.getApplyer()); + if(sysUser != null){ + apply.setApplyer(sysUser.getNickName()); + } + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + /** + * 调整申请 + * @return + */ + @ApiOperation("调整申请") + @GetMapping("/modifyapply") + @ResponseBody + public AjaxResult modifyapply(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + OutBound apply = outBoundService.selectOutBoundById(Long.parseLong(p.getBusinessKey())); + SysUser sysUser = userService.selectUserByUserName(apply.getApplyer()); + if(sysUser != null){ + apply.setApplyer(sysUser.getNickName()); + }; + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/PurchaseController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/PurchaseController.java new file mode 100644 index 0000000..6284fac --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/PurchaseController.java @@ -0,0 +1,221 @@ +package com.zbf.web.controller.flowable; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.Purchase; +import com.zbf.system.service.IPurchaseService; +import com.zbf.system.service.ISysUserService; +import io.swagger.annotations.ApiOperation; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; + +/** + * 采购Controller + * + * @author shenzhanwang + * @date 2022-05-28 + */ +@Controller +@RequestMapping("/purchase") +public class PurchaseController extends BaseController +{ + private String prefix = "flowable/purchase"; + + @Autowired + private IPurchaseService purchaseService; + + @Autowired + private ISysUserService userService; + + @Resource + private RuntimeService runtimeService; + + @Resource + private TaskService taskService; + + @GetMapping() + public String purchase() + { + return prefix + "/purchase"; + } + + /** + * 查询采购列表 + */ + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(Purchase purchase) + { + startPage(); + List list = purchaseService.selectPurchaseList(purchase); + return getDataTable(list); + } + + /** + * 导出采购列表 + */ + @PostMapping("/export") + @ResponseBody + public AjaxResult export(Purchase purchase) + { + List list = purchaseService.selectPurchaseList(purchase); + ExcelUtil util = new ExcelUtil(Purchase.class); + return util.exportExcel(list, "采购数据"); + } + + + /** + * 新增保存采购 + */ + @ApiOperation("新增保存采购") + @Log(title = "采购", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(Purchase purchase) + { + purchase.setApplytime(new Date()); + return toAjax(purchaseService.insertPurchase(purchase)); + } + + @PostMapping("/edit") + @ResponseBody + public AjaxResult edit(Purchase purchase) + { + return toAjax(purchaseService.updatePurchase(purchase)); + } + + /** + * 删除采购 + */ + @Log(title = "采购", businessType = BusinessType.DELETE) + @PostMapping( "/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(purchaseService.deletePurchaseByIds(ids)); + } + + /** + * 采购经理审批 + */ + @ApiOperation("采购经理审批") + @GetMapping("/purchasemanager") + @ResponseBody + public AjaxResult purchasemanager(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 财务审批 + */ + @ApiOperation("财务审批") + @GetMapping("/finance") + @ResponseBody + public AjaxResult finance(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 总经理审批 + */ + @ApiOperation("总经理审批") + @GetMapping("/manager") + @ResponseBody + public AjaxResult manager(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 出纳付款 + */ + @ApiOperation("出纳付款") + @GetMapping("/pay") + @ResponseBody + public AjaxResult pay(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 收货确认 + */ + @ApiOperation("收货确认") + @GetMapping("/receiveitem") + @ResponseBody + public AjaxResult receiveitem(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } + + /** + * 调整申请 + */ + @ApiOperation("调整申请") + @GetMapping("/updateapply") + @ResponseBody + public AjaxResult updateapply(String taskid) + { + Task t = taskService.createTaskQuery().taskId(taskid).singleResult(); + String processId = t.getProcessInstanceId(); + ProcessInstance p = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); + if (p != null) { + Purchase apply = purchaseService.selectPurchaseById(Long.parseLong(p.getBusinessKey())); + return AjaxResult.success(apply); + } + return AjaxResult.error("流程不存在"); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/flowable/TaskController.java b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/TaskController.java new file mode 100644 index 0000000..a9bc815 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/flowable/TaskController.java @@ -0,0 +1,370 @@ +package com.zbf.web.controller.flowable; + + +import cn.hutool.system.UserInfo; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.config.D_Service; +import com.zbf.system.domain.OutBound; +import com.zbf.system.domain.SysPost; +import com.zbf.system.domain.TCkOrders; +import com.zbf.system.domain.TaskInfo; +import com.zbf.system.mapper.OutBoundMapper; +import com.zbf.system.mapper.SysPostMapper; +import com.zbf.system.service.ISysPostService; +import com.zbf.system.service.ISysUserService; +import com.zbf.system.service.ITCkOrdersService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import liquibase.pro.packaged.O; +import org.flowable.engine.FormService; +import org.flowable.engine.HistoryService; +import org.flowable.engine.RuntimeService; +import org.flowable.engine.TaskService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.task.Comment; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskQuery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.simp.user.UserRegistryMessageHandler; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.swing.text.StyledEditorKit; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +@Api(value = "待办任务接口") +@Controller +@RequestMapping("/task/manage") +public class TaskController extends BaseController { + + @Autowired + private RuntimeService runtimeService; + + @Autowired + private TaskService taskService; + + @Autowired + FormService formService; + + @Resource + private HistoryService historyService; + @Autowired + private ISysUserService userService; + @Autowired + private SysPostMapper sysPostMapper; + @Autowired + private ITCkOrdersService tCkOrdersService; + + @Autowired + private D_Service d_service; + @Autowired + private OutBoundMapper outBoundMapper; + private String prefix = "flowable/task"; + + @GetMapping("/mytask") + public String mytasks() { + return prefix + "/mytasks"; + } + + @GetMapping("/alltasks") + public String alltasks() { + return prefix + "/alltasks"; + } + + /** + * 查询我的待办任务列表 + */ + @ApiOperation("查询我的待办任务列表") + @PostMapping("/mylist") + @ResponseBody + public TableDataInfo mylist(TaskInfo param) { + SysUser user = SecurityUtils.getLoginUser().getUser(); + String username = getUsername(); + TaskQuery condition = taskService.createTaskQuery().taskAssignee(username); + if (StringUtils.isNotEmpty(param.getTaskName())) { + condition.taskName(param.getTaskName()); + } + if (StringUtils.isNotEmpty(param.getProcessName())) { + condition.processDefinitionName(param.getProcessName()); + } + // 过滤掉流程挂起的待办任务 + int total = condition.active().orderByTaskCreateTime().desc().list().size(); + int start = (param.getPageNum() - 1) * param.getPageSize(); + List taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize()); + List tasks = new ArrayList<>(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + taskList.stream().forEach(a -> { + ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult(); + TaskInfo info = new TaskInfo(); + SysUser user1 = userService.selectUserByUserName(a.getAssignee()); + if (user1 == null) { + info.setAssignee(a.getAssignee()); + } else { + info.setAssignee(user1.getNickName()); + } +// info.setAssignee(a.getAssignee()); + info.setBusinessKey(process.getBusinessKey()); + info.setCreateTime(sdf.format(a.getCreateTime())); + + info.setExecutionId(a.getExecutionId()); + info.setProcessInstanceId(a.getProcessInstanceId()); + info.setProcessName(process.getProcessDefinitionName()); + info.setStarter(process.getStartUserId()); + info.setStartTime(sdf.format(process.getStartTime())); + info.setTaskId(a.getId()); + String formKey = formService.getTaskFormData(a.getId()).getFormKey(); + info.setFormKey(formKey); + if (formKey.contains("outbound")) { + info.setTaskName("出库通知单审批申请"); + } else { + info.setTaskName(a.getName()); + } + tasks.add(info); + }); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(tasks); + rspData.setTotal(total); + return rspData; + } + + /** + * 查询所有待办任务列表 + */ + @ApiOperation("查询所有待办任务列表") + @PostMapping("/alllist") + @ResponseBody + public TableDataInfo alllist(TaskInfo param) { + TaskQuery condition = taskService.createTaskQuery(); + if (StringUtils.isNotEmpty(param.getTaskName())) { + condition.taskName(param.getTaskName()); + } + if (StringUtils.isNotEmpty(param.getProcessName())) { + condition.processDefinitionName(param.getProcessName()); + } + int total = condition.active().orderByTaskCreateTime().desc().list().size(); + int start = (param.getPageNum() - 1) * param.getPageSize(); + List taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize()); + List tasks = new ArrayList<>(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + taskList.stream().forEach(a -> { + ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult(); + TaskInfo info = new TaskInfo(); + SysUser user1 = userService.selectUserByUserName(a.getAssignee()); + if (user1 == null) { + info.setAssignee(a.getAssignee()); + } else { + info.setAssignee(user1.getNickName()); + } +// info.setAssignee(a.getAssignee()); + info.setBusinessKey(process.getBusinessKey()); + info.setCreateTime(sdf.format(a.getCreateTime())); +// info.setTaskName(a.getName()); + info.setExecutionId(a.getExecutionId()); + info.setProcessInstanceId(a.getProcessInstanceId()); + info.setProcessName(process.getProcessDefinitionName()); + info.setStarter(process.getStartUserId()); + info.setStartTime(sdf.format(process.getStartTime())); + info.setTaskId(a.getId()); + String formKey = formService.getTaskFormData(a.getId()).getFormKey(); + info.setFormKey(formKey); + if (formKey.contains("outbound")) { + info.setTaskName("出库通知单审批申请"); + } else { + info.setTaskName(a.getName()); + } + tasks.add(info); + }); + TableDataInfo rspData = new TableDataInfo(); + rspData.setCode(0); + rspData.setRows(tasks); + rspData.setTotal(total); + return rspData; + } + + + /** + * 用taskid查询formkey + **/ + @ApiOperation("用taskid查询formkey") + @PostMapping("/forminfo/{taskId}") + @ResponseBody + public AjaxResult alllist(@PathVariable String taskId) { + String formKey = formService.getTaskFormData(taskId).getFormKey(); + return AjaxResult.success(formKey); + } + + @ApiOperation("办理一个用户任务") + @RequestMapping(value = "/completeTask/{taskId}", method = RequestMethod.POST) + @ResponseBody + public AjaxResult completeTask(@PathVariable("taskId") String taskId, @RequestBody(required = false) Map variables) { + logger.info("办理一个代办:{}",taskId); + String username = getUsername(); + taskService.setAssignee(taskId, username); + //存储审核结果 + variables.put(username, variables.get("result")); + SysUser user = userService.selectUserByUserName(username); + // 查出流程实例id + String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId(); + if (variables == null) { + taskService.complete(taskId); + } else { + // 添加审批意见 + String comment = StringUtils.EMPTY; + if (variables.get("comment") != null) { + taskService.addComment(taskId, processInstanceId, (String) variables.get("comment")); + comment = (String) variables.get("comment"); + variables.remove("comment"); + } + String deliveryId = (String)runtimeService.getVariable(processInstanceId, "deliveryId"); + TCkOrders tCkOrders1 = tCkOrdersService.selectTCkOrdersByDeliveryId(deliveryId); + TCkOrders tCkOrders = new TCkOrders(); + tCkOrders.setId(tCkOrders1.getId()); + String auditMan = tCkOrders1.getAuditMan(); + if (StringUtils.isNotBlank(auditMan)) { + tCkOrders.setAuditMan(auditMan + "->" + user.getNickName()); + } else { + tCkOrders.setAuditMan(user.getNickName()); + } + tCkOrders.setAuditDate(new Date()); + //更新出库明细 + String dResult = StringUtils.EMPTY; + if ("false".equals(variables.get("result"))) { + dResult = "refuse"; + if (StringUtils.isNotBlank(comment)) { + if (StringUtils.isNotBlank(tCkOrders1.getRejectReason())) { + tCkOrders.setRejectReason(tCkOrders1.getRejectReason() + "|" + user.getNickName() + ":拒绝,原因:" + comment); + } else { + tCkOrders.setRejectReason(user.getNickName() + ":拒绝,原因:" + comment); + } + } else { + if (StringUtils.isNotBlank(tCkOrders1.getRejectReason())) { + tCkOrders.setRejectReason(tCkOrders1.getRejectReason() + "|" + user.getNickName() + ":拒绝"); + } else + tCkOrders.setRejectReason(user.getNickName() + ":拒绝"); + } + } else { + dResult = "agree"; + if (StringUtils.isNotBlank(comment)) { + if (StringUtils.isNotBlank(tCkOrders1.getRejectReason())) { + tCkOrders.setRejectReason(tCkOrders1.getRejectReason() + "|" + user.getNickName() + ":同意,意见:" + comment); + } else { + tCkOrders.setRejectReason(user.getNickName() + ":同意,意见:" + comment); + } + } else { + if (StringUtils.isNotBlank(tCkOrders1.getRejectReason())) { + tCkOrders.setRejectReason(tCkOrders1.getRejectReason() + "|" + user.getNickName() + ":同意"); + } else + tCkOrders.setRejectReason(user.getNickName() + ":同意"); + + } + } + tCkOrders.setRemark(dResult); + if("refuse".equalsIgnoreCase(dResult)){ + tCkOrders.setIsAudit("3"); + } + tCkOrdersService.updateTCkOrders(tCkOrders); + String instanceId = (String)runtimeService.getVariable(processInstanceId, "instanceId"); + taskService.complete(taskId, variables); + //更新下一个任务id + List nextTasks = taskService.createTaskQuery() + .processInstanceId(processInstanceId) // 根据流程实例 ID 查询 + .orderByTaskCreateTime().desc() // 按任务创建时间排序 + .list(); + + if (!nextTasks.isEmpty()) { + Task nextTask = nextTasks.get(0); // 获取下一个任务 + String nextTaskId = nextTask.getId(); + System.out.println("下一个任务的 ID: " + nextTaskId); + OutBound outBound = new OutBound(); + outBound.setfInstanceId(processInstanceId); + List outBounds = outBoundMapper.selectOutBoundList(outBound); + if(!outBounds.isEmpty()){ + OutBound outBound1 = outBounds.get(0); + OutBound outBound44 = new OutBound(); + outBound44.setId(outBound1.getId()); + outBound44.setTaskId(nextTaskId); + outBound44.setUpdateTime(new Date()); + outBound44.setFinishName(username); + outBoundMapper.updateOutBound(outBound44); + } + } + //同步钉钉 + //根据taskId查询钉钉实例ID +// Map variables1 = taskService.getVariables(taskId); +// String instanceId = (String)runtimeService.getVariable(processInstanceId, "instanceId"); +// String instanceId =(String) variables1.get("instanceId"); + logger.info("发起同步钉钉,钉钉实例ID=====》》》》{} ",instanceId); +// logger.info("发起同步钉钉,获取所有变量:==》》》》{} ",variables1); +// variables1.forEach((key, value) -> logger.info(key + ": " + value)); + if(StringUtils.isNotBlank(instanceId)) { + d_service.auditStatusToDd(instanceId, username, dResult); + } + } + return AjaxResult.success(); + } + + @ApiOperation("任务办理时间轴") + @RequestMapping(value = "/history/{taskId}", method = RequestMethod.GET) + @ResponseBody + public List history(@PathVariable String taskId) { + String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId(); + List history = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).activityType("userTask").orderByHistoricActivityInstanceStartTime().asc().list(); + List infos = new ArrayList<>(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + history.stream().forEach(h -> { + TaskInfo info = new TaskInfo(); + info.setProcessInstanceId(h.getProcessInstanceId()); + info.setStartTime(sdf.format(h.getStartTime())); + if (h.getEndTime() != null) { + info.setEndTime(sdf.format(h.getEndTime())); + } + //根据用户名或者昵称 + Map variables = taskService.getVariables(taskId); + + SysUser user = userService.selectUserByUserName(h.getAssignee()); +// info.setAssignee(h.getAssignee()); + StringBuilder userInfo = new StringBuilder(); + if (user != null) { + List sysPosts = sysPostMapper.selectPostsByUserName(user.getUserName()); + userInfo.append("【 " + user.getDept().getDeptName() + " 】"); + userInfo.append("【 "); + for (SysPost post : sysPosts) { + userInfo.append(post.getPostName()).append(" "); + } + ; + userInfo.append("】"); + userInfo.append(user.getNickName()); + } else { + userInfo.append(h.getAssignee()); + } + String result = (String) variables.get(h.getAssignee()); + info.setAssignee(userInfo.toString()); + if ("true".equals(result)) { + info.setResult("同意"); + } else if ("false".equals(result)) { + info.setResult("拒绝"); + } + +// info.setTaskName(h.getActivityName()); +// info.setTaskName("出库通知单申请"); + List comments = taskService.getTaskComments(h.getTaskId()); + if (comments.size() > 0) { + info.setComment(comments.get(0).getFullMessage()); + } + infos.add(info); + }); + return infos; + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/monitor/CacheController.java b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/CacheController.java new file mode 100644 index 0000000..a540ecf --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/CacheController.java @@ -0,0 +1,120 @@ +package com.zbf.web.controller.monitor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.constant.CacheConstants; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.domain.SysCache; + +/** + * 缓存监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/cache") +public class CacheController +{ + @Autowired + private RedisTemplate redisTemplate; + + private final static List caches = new ArrayList(); + { + caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); + caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息")); + caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典")); + caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); + caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); + caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); + caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception + { + Properties info = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info()); + Properties commandStats = (Properties) redisTemplate.execute((RedisCallback) connection -> connection.info("commandstats")); + Object dbSize = redisTemplate.execute((RedisCallback) connection -> connection.dbSize()); + + Map result = new HashMap<>(3); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + result.put("commandStats", pieList); + return AjaxResult.success(result); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getNames") + public AjaxResult cache() + { + return AjaxResult.success(caches); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getKeys/{cacheName}") + public AjaxResult getCacheKeys(@PathVariable String cacheName) + { + Set cacheKeys = redisTemplate.keys(cacheName + "*"); + return AjaxResult.success(cacheKeys); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @GetMapping("/getValue/{cacheName}/{cacheKey}") + public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) + { + String cacheValue = redisTemplate.opsForValue().get(cacheKey); + SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue); + return AjaxResult.success(sysCache); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheName/{cacheName}") + public AjaxResult clearCacheName(@PathVariable String cacheName) + { + Collection cacheKeys = redisTemplate.keys(cacheName + "*"); + redisTemplate.delete(cacheKeys); + return AjaxResult.success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheKey/{cacheKey}") + public AjaxResult clearCacheKey(@PathVariable String cacheKey) + { + redisTemplate.delete(cacheKey); + return AjaxResult.success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:cache:list')") + @DeleteMapping("/clearCacheAll") + public AjaxResult clearCacheAll() + { + Collection cacheKeys = redisTemplate.keys("*"); + redisTemplate.delete(cacheKeys); + return AjaxResult.success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/monitor/ServerController.java b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/ServerController.java new file mode 100644 index 0000000..c814bb9 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/ServerController.java @@ -0,0 +1,27 @@ +package com.zbf.web.controller.monitor; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.framework.web.domain.Server; + +/** + * 服务器监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/server") +public class ServerController +{ + @PreAuthorize("@ss.hasPermi('monitor:server:list')") + @GetMapping() + public AjaxResult getInfo() throws Exception + { + Server server = new Server(); + server.copyTo(); + return AjaxResult.success(server); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysLogininforController.java b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000..8efd4df --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysLogininforController.java @@ -0,0 +1,82 @@ +package com.zbf.web.controller.monitor; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.framework.web.service.SysPasswordService; +import com.zbf.system.domain.SysLogininfor; +import com.zbf.system.service.ISysLogininforService; + +/** + * 系统访问记录 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController +{ + @Autowired + private ISysLogininforService logininforService; + + @Autowired + private SysPasswordService passwordService; + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')") + @GetMapping("/list") + public TableDataInfo list(SysLogininfor logininfor) + { + startPage(); + List list = logininforService.selectLogininforList(logininfor); + return getDataTable(list); + } + + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysLogininfor logininfor) + { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil util = new ExcelUtil(SysLogininfor.class); + util.exportExcel(response, list, "登录日志"); + } + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public AjaxResult remove(@PathVariable Long[] infoIds) + { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public AjaxResult clean() + { + logininforService.cleanLogininfor(); + return success(); + } + + @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public AjaxResult unlock(@PathVariable("userName") String userName) + { + passwordService.clearLoginRecordCache(userName); + return success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysOperlogController.java b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000..776004c --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysOperlogController.java @@ -0,0 +1,69 @@ +package com.zbf.web.controller.monitor; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.SysOperLog; +import com.zbf.system.service.ISysOperLogService; + +/** + * 操作日志记录 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController +{ + @Autowired + private ISysOperLogService operLogService; + + @PreAuthorize("@ss.hasPermi('monitor:operlog:list')") + @GetMapping("/list") + public TableDataInfo list(SysOperLog operLog) + { + startPage(); + List list = operLogService.selectOperLogList(operLog); + return getDataTable(list); + } + + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monitor:operlog:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysOperLog operLog) + { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil util = new ExcelUtil(SysOperLog.class); + util.exportExcel(response, list, "操作日志"); + } + + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @DeleteMapping("/{operIds}") + public AjaxResult remove(@PathVariable Long[] operIds) + { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") + @DeleteMapping("/clean") + public AjaxResult clean() + { + operLogService.cleanOperLog(); + return success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysUserOnlineController.java b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..4f1c518 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,83 @@ +package com.zbf.web.controller.monitor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.constant.CacheConstants; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.core.redis.RedisCache; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.domain.SysUserOnline; +import com.zbf.system.service.ISysUserOnlineService; + +/** + * 在线用户监控 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController +{ + @Autowired + private ISysUserOnlineService userOnlineService; + + @Autowired + private RedisCache redisCache; + + @PreAuthorize("@ss.hasPermi('monitor:online:list')") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) + { + Collection keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*"); + List userOnlineList = new ArrayList(); + for (String key : keys) + { + LoginUser user = redisCache.getCacheObject(key); + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) + { + userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user)); + } + else if (StringUtils.isNotEmpty(ipaddr)) + { + userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user)); + } + else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) + { + userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user)); + } + else + { + userOnlineList.add(userOnlineService.loginUserToUserOnline(user)); + } + } + Collections.reverse(userOnlineList); + userOnlineList.removeAll(Collections.singleton(null)); + return getDataTable(userOnlineList); + } + + /** + * 强退用户 + */ + @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public AjaxResult forceLogout(@PathVariable String tokenId) + { + redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId); + return success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/section/DataListAspect.java b/zbf-admin/src/main/java/com/zbf/web/controller/section/DataListAspect.java new file mode 100644 index 0000000..b015ca9 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/section/DataListAspect.java @@ -0,0 +1,73 @@ +package com.zbf.web.controller.section; + +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.generator.util.ColumnUtils; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.After; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static com.zbf.common.utils.PageUtils.startPage; + +@Aspect +@Component +public class DataListAspect { + + @Pointcut("@annotation(EnhanceDataList)") + public void dataListPointcut() {} + + //分页不处理 + @Around(value = "dataListPointcut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + // 先执行目标方法 + Object result = joinPoint.proceed(); + + // 检查结果是否为 TableDataInfo 实例 + if (result instanceof TableDataInfo) { + TableDataInfo dataTable = (TableDataInfo) result; + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + EnhanceDataList enhanceDataList = signature.getMethod().getAnnotation(EnhanceDataList.class); + + // 设置列信息 + dataTable.setColumns(ColumnUtils.getColumnsJson(enhanceDataList.entityType())); + + // 在这里添加其他逻辑来修改 dataTable + // 例如重新计算 total 或修改 rows + // dataTable.setTotal(newTotal); + // dataTable.setRows(newRows); + + return dataTable; // 返回修改后的 dataTable + } + + return result; // 如果结果不是 TableDataInfo 实例,直接返回原结果 + } + + + + //集合类 + @Pointcut("@annotation(ListColumns)") + public void list() {} + + @Around("list()") + public Object lists(ProceedingJoinPoint joinPoint) throws Throwable { + Object result = joinPoint.proceed(); + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + ListColumns columns = signature.getMethod().getAnnotation(ListColumns.class); + if (result instanceof Map) { + Map map = (Map) result; + // 确保list也被放入map中 + if (joinPoint.getArgs().length > 0 && joinPoint.getArgs()[0] instanceof List) { + map.put("list", joinPoint.getArgs()[0]); + } + map.put("columns", ColumnUtils.getColumnsJson(columns.value())); + } + return result; + } + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/section/EnhanceDataList.java b/zbf-admin/src/main/java/com/zbf/web/controller/section/EnhanceDataList.java new file mode 100644 index 0000000..82ac6d7 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/section/EnhanceDataList.java @@ -0,0 +1,12 @@ +package com.zbf.web.controller.section; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface EnhanceDataList { + Class entityType(); +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/section/ListColumns.java b/zbf-admin/src/main/java/com/zbf/web/controller/section/ListColumns.java new file mode 100644 index 0000000..6dfb1e7 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/section/ListColumns.java @@ -0,0 +1,15 @@ +package com.zbf.web.controller.section; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ListColumns { + Class value(); +} + + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/AppVerController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/AppVerController.java new file mode 100644 index 0000000..89962cd --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/AppVerController.java @@ -0,0 +1,42 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.system.domain.AppVersions; +import com.zbf.system.mapper.AppVersionsMapper; +import com.zbf.system.service.IAppVersionsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequestMapping("/system/app") +public class AppVerController extends BaseController { + + + @Autowired + private AppVersionsMapper appVersionsMapper; + + + @GetMapping("/ver") + public AjaxResult list(AppVersions appVersions) { + AppVersions ver = appVersionsMapper.selectOne(null); + + if (ver != null) { + if (ver.getHversion().equals(ver.getVersion())) { + return AjaxResult.warn("暂无更新"); + } + } + return AjaxResult.success(ver); + + } + +} + + + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/DeviceLogController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/DeviceLogController.java new file mode 100644 index 0000000..4f00b48 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/DeviceLogController.java @@ -0,0 +1,129 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.system.domain.DeviceLog; +import com.zbf.system.service.IDeviceLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 【请填写功能名称】Controller + * + * @author tony + * @date 2024-10-22 + */ +@RestController +@RequestMapping("/system/log") +public class DeviceLogController extends BaseController +{ + @Autowired + private IDeviceLogService deviceLogService; + + /** + * 查询【请填写功能名称】列表 + */ + @GetMapping("/list") + public TableDataInfo list(DeviceLog deviceLog) + { + startPage(); + List list = deviceLogService.selectDeviceLogList(deviceLog); + return getDataTable(list); + } + + /** + * 导出【请填写功能名称】列表 + *//* + @PreAuthorize("@ss.hasPermi('system:log:export')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, DeviceLog deviceLog) + { + List list = deviceLogService.selectDeviceLogList(deviceLog); + ExcelUtil util = new ExcelUtil(DeviceLog.class); + util.exportExcel(response, list, "【请填写功能名称】数据"); + }*/ + + /** + * 推送 + */ + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return deviceLogService.selectDeviceLogById(id); + } + + /* *//** + * 新增【请填写功能名称】 + *//* + @PreAuthorize("@ss.hasPermi('system:log:add')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody DeviceLog deviceLog) + { + return toAjax(deviceLogService.insertDeviceLog(deviceLog)); + } + + *//** + * 修改【请填写功能名称】 + *//* + @PreAuthorize("@ss.hasPermi('system:log:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody DeviceLog deviceLog) + { + return toAjax(deviceLogService.updateDeviceLog(deviceLog)); + } + + *//** + * 删除【请填写功能名称】 + *//* + @PreAuthorize("@ss.hasPermi('system:log:remove')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(deviceLogService.deleteDeviceLogByIds(ids)); + } + + *//** + * 启用 + *//* + @PreAuthorize("@ss.hasPermi('system:log:remove')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(deviceLogService.disabledDeviceLogByIds(ids)); + } + + *//** + * 禁用 + *//* + @PreAuthorize("@ss.hasPermi('system:log:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PostMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(deviceLogService.enableDeviceLogByIds(ids)); + } + + *//** + * 修改状态 + *//* + @PreAuthorize("@ss.hasPermi('system:log:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody DeviceLog deviceLog) { + return toAjax(deviceLogService.updateStatus(deviceLog)); + }*/ + +} + + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/InventoryCheckController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/InventoryCheckController.java new file mode 100644 index 0000000..ca92925 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/InventoryCheckController.java @@ -0,0 +1,132 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.InventoryCheck; +import com.zbf.system.service.IInventoryCheckService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 盘点主Controller + * + * @author tony + * @date 2024-10-31 + */ +@RestController +@RequestMapping("/system/check") +public class InventoryCheckController extends BaseController +{ + @Autowired + private IInventoryCheckService inventoryCheckService; + + /** + * 查询盘点主列表 + */ + @PreAuthorize("@ss.hasPermi('system:check:list')") + @GetMapping("/list") + public TableDataInfo list(InventoryCheck inventoryCheck) + { + startPage(); + List list = inventoryCheckService.selectInventoryCheckList(inventoryCheck); + return getDataTable(list); + } + + /** + * 导出盘点主列表 + */ + @PreAuthorize("@ss.hasPermi('system:check:export')") + @Log(title = "盘点主", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, InventoryCheck inventoryCheck) + { + List list = inventoryCheckService.selectInventoryCheckList(inventoryCheck); + ExcelUtil util = new ExcelUtil(InventoryCheck.class); + util.exportExcel(response, list, "盘点主数据"); + } + + /** + * 获取盘点主详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:check:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(inventoryCheckService.selectInventoryCheckById(id)); + } + + /** + * 新增盘点主 + */ + @PreAuthorize("@ss.hasPermi('system:check:add')") + @Log(title = "盘点主", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody InventoryCheck inventoryCheck) + { + return toAjax(inventoryCheckService.insertInventoryCheck(inventoryCheck)); + } + + /** + * 修改盘点主 + */ + @PreAuthorize("@ss.hasPermi('system:check:edit')") + @Log(title = "盘点主", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody InventoryCheck inventoryCheck) + { + return toAjax(inventoryCheckService.updateInventoryCheck(inventoryCheck)); + } + + /** + * 删除盘点主 + */ + @PreAuthorize("@ss.hasPermi('system:check:remove')") + @Log(title = "盘点主", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(inventoryCheckService.deleteInventoryCheckByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:check:remove')") + @Log(title = "盘点主", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(inventoryCheckService.disabledInventoryCheckByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:check:edit')") + @Log(title = "盘点主", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(inventoryCheckService.enableInventoryCheckByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:check:edit')") + @Log(title = "盘点主", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody InventoryCheck inventoryCheck) { + return toAjax(inventoryCheckService.updateStatus(inventoryCheck)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/LargeScreenController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/LargeScreenController.java new file mode 100644 index 0000000..56eac61 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/LargeScreenController.java @@ -0,0 +1,4469 @@ +package com.zbf.web.controller.system; + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDept; +import com.zbf.common.core.domain.entity.SysDictData; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.DateUtils; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.bean.BeanUtils; +import com.zbf.system.domain.*; +import com.zbf.system.domain.vo.Quest; +import com.zbf.system.domain.vo.Types; +import com.zbf.system.mapper.*; +import com.zbf.system.service.*; +import com.zbf.system.service.impl.TCkOrdersServiceImpl; +import com.zbf.system.service.impl.TCkPickingwavegoodsBakServiceImpl; +import com.zbf.system.service.impl.TCkPickingwavegoodsServiceImpl; +import com.zbf.system.service.impl.TckOrdersBakServiceImpl; +import com.zbf.system.utils.HttpUtils; +import com.zbf.web.mqtt.MqttMessageSender; +import liquibase.pro.packaged.O; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import javax.validation.Validator; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.text.SimpleDateFormat; +import java.time.*; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + + +/** + * 大屏数据 + */ +@CrossOrigin +@RestController +@RequestMapping("/system/LargeScreen") +public class LargeScreenController extends BaseController { + private static final Logger logger = LoggerFactory.getLogger(TCkOrdersServiceImpl.class); + + @Autowired + private LargeScreenService largeScreenService; + + + @Autowired + private ITRkWareNoticeService tRkWareNoticeService; + + + @Autowired + private TRkWareNoticeMapper tRkWareNoticeMapper; + + @Autowired + private TRkWareNoticeBakMapper tRkWareNoticeBakMapper; + + @Autowired + private TOngoodsshelfMapper tOngoodsshelfMapper; + + @Autowired + private TOngoodsshelfBakMapper tOngoodsshelfBakMapper; + + @Autowired + private TRkReceivingGoodsMapper tRkReceivingGoodsMapper; + + @Autowired + private TBaseStorageMapper tBaseStorageMapper; + + @Autowired + private TMiStockMapper tMiStockMapper; + + @Autowired + private TMiStockFMapper tMiStockFMapper; + + @Autowired + private SysConfigMapper sysConfigMapper; + + @Autowired + private IPlcService plcService; + + @Autowired + private ITCallNoticeService tNoticeService; + + @Autowired + private TBaseStorageAreaLocationMapper tBaseStorageAreaLocationMapper; + + @Autowired + private ISysConfigService configService; + @Autowired + protected Validator validator; + @Autowired + private TRkWareNoticeTabMapper tRkWareNoticeTabMapper; + + @Autowired + private PlcMapper plcMapper; + + @Autowired + private TBasePalletMapper palletMapper; + + @Autowired + private TBaseStorageAreaLocationMapper service; + + @Autowired + private TRkWareNoticeTabMapper mapper; + + @Autowired + private ITCallNoticeOrderService tNoticeOrderService; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private SysDictDataMapper sysDictDataMapper; + + + @Autowired + @Qualifier("defaultRestTemplate") + private RestTemplate restClientConfig; + + @Autowired + private TCkOrdersMapper tCkOrdersMapper; + @Autowired + private TCkOrderdetailMapper tCkOrderdetailMapper; + + @Autowired + private TCkPickingwavegoodsMapper tCkPickingwavegoodsMapper; + + @Autowired + private TRkWareNoticeMapper rkWareNoticeMapper; + + @Autowired + private TRkWareNoticeTabBakMapper tRkWareNoticeTabBakMapper; + + @Autowired + private ITBaseStorageService baseStorageService; + + @Autowired + private TCkOrderdetailMapper orderdetailMapper; + + @Autowired + private TckOrderdetailBakMapper tckOrderdetailBakMapper; + + @Autowired + private TCallNoticeMapper tCallNoticeMapper; + @Resource + private IOutBoundService outBoundService; + + @Autowired + private TckOrdersBakServiceImpl tckOrdersBakService; + + + @Autowired + private ITCkOrdersService tCkOrdersService; + + @Autowired + private TBaseGoodsMapper goodsMapper; + + @Autowired + private TCkPickingwavegoodsServiceImpl tCkPickingwavegoodsService; + + @Autowired + private TCkPickingwavegoodsBakServiceImpl tCkPickingwavegoodsBakService; + + + @Autowired + private TBaseGoodsMapper tBaseGoodsMapper; + + + @Autowired + private MqttMessageSender mqttMessageSender; + + @Autowired + private SysUserMapper sysUserMapper; + + @Autowired + private TBasePalletMapper basePalletMapper; + + @Autowired + private SysDeptMapper sysDeptMapper; + + @Autowired + private TBasePalletMapper tBasePalletMapper; + + + /* @Autowired + private RedissonClient redissonClient; // 直接注入RedissonClient*/ + + + private final ReentrantLock lock = new ReentrantLock(); + + @GetMapping("/chart") + @Log(title = "利用率") + public List> chart() { + List> resultList = new ArrayList<>(); + + // 获取所有托盘信息并筛选有效数据 + List allPallets = tBasePalletMapper.selectTBasePalletList(new TBasePallet()); + List validPallets = allPallets.stream() + .filter(pallet -> ObjectUtils.isNotEmpty(pallet.getType()) && ObjectUtils.isNotEmpty(pallet.getStatus())) + .collect(Collectors.toList()); + + // 获取“占用”的状态值 + List locationType = sysDictDataMapper.selectDictDataByType("location_type"); + String occupiedStatus = locationType.stream() + .filter(data -> "占用".equals(data.getDictLabel())) + .map(SysDictData::getDictValue) + .findFirst() + .orElse(null); + + if (occupiedStatus == null) { + throw new IllegalStateException("无法获取占用状态值"); + } + + // 托盘数据处理 + List containerType = sysDictDataMapper.selectDictDataByType("container_type"); + + // 处理重型料箱 + resultList.add(processContainerData(validPallets, containerType, "重型料箱", occupiedStatus)); + + // 处理轻型料箱 + resultList.add(processContainerData(validPallets, containerType, "轻型料箱", occupiedStatus)); + + // 库位数据处理 + List storageLocationData = processStorageLocationData(occupiedStatus); + resultList.add(storageLocationData); + + return resultList; + } + + private List processContainerData(List pallets, List containerType, String containerLabel, String occupiedStatus) { + List dataList = new ArrayList<>(); + + // 获取指定类型的字典值 + String typeValue = containerType.stream() + .filter(data -> containerLabel.equals(data.getDictLabel())) + .map(SysDictData::getDictValue) + .findFirst() + .orElse(null); + + if (typeValue == null) { + // 如果字典值未找到,默认返回 0 + dataList.add(0); + dataList.add(0); + return dataList; + } + + // 获取指定类型的托盘 + List filteredPallets = pallets.stream() + .filter(pallet -> typeValue.equals(pallet.getType())) + .collect(Collectors.toList()); + + if (filteredPallets.isEmpty()) { + // 如果没有该类型的托盘,默认返回 0 + dataList.add(0); + dataList.add(0); + } else { + // 获取占用状态的托盘 + long occupiedCount = filteredPallets.stream() + .filter(pallet -> occupiedStatus.equals(pallet.getStatus())) + .count(); + dataList.add((int) occupiedCount); + dataList.add(filteredPallets.size()); + } + + return dataList; + } + + private List processStorageLocationData(String occupiedStatus) { + List dataList = new ArrayList<>(); + + // 获取所有库位信息 + List allLocations = tBaseStorageAreaLocationMapper.selectTBaseStorageAreaLocationList(new TBaseStorageAreaLocation()); + + // 获取占用状态的库位 + long occupiedCount = allLocations.stream() + .filter(location -> occupiedStatus.equals(location.getStatus())) + .count(); + + dataList.add((int) occupiedCount); + dataList.add(allLocations.size()); + + return dataList; + } + @GetMapping("/ckRkData") + @Log(title = "出入库通知单") + public List ckRkData() { + List list = new ArrayList<>(); + int size = tOngoodsshelfMapper.selectTOngoodsshelfList(new TOngoodsshelf()).size(); + //入库 + list.add(size); + + int size1 = tCkPickingwavegoodsMapper.selectTCkPickingwavegoodsList(new TCkPickingwavegoods()).size(); + //出库 + list.add(size1); + + int size2 = tRkWareNoticeTabMapper.selectTRkWareNoticeTabList(new TRkWareNoticeTab()).size(); + //入库通知单 + list.add(size2); + + int size3 = tCkOrdersMapper.selectTCkOrdersList(new TCkOrders()).size(); + //出库通知单 + list.add(size3); + + int size4 = tCkOrdersMapper.selectTCkOrdersList(new TCkOrders()).stream().filter(f -> f.getIsAudit().equals("2")).collect(Collectors.toList()).size(); + //出库通知单待审核 + list.add(size4); + return list; + } + @GetMapping("/dayAMonthCk") + @Log(title = "今日本月出库") + public List dayAMonthCk() { + List list = new ArrayList<>(); + + try { + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + Date startOfDay = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endOfDay = Date.from(today.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); + + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tCkOrderdetails = tCkOrderdetailMapper.selectTCkOrderdetailList(new TCkOrderdetail()); + + // 1. 过滤创建时间为空的元素 (Stream 操作) + List filteredByCreateTime = tckOrderdetailBaks != null ? tckOrderdetailBaks.stream() + .filter(f -> f != null && f.getCreateTime() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + List filteredByCreateTime1 = tCkOrderdetails != null ? tCkOrderdetails.stream() + .filter(f -> f != null && f.getCreateTime() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + // 2. 判断是否有数据,避免空指针 + if (filteredByCreateTime.isEmpty() && filteredByCreateTime1.isEmpty()) { + list.add(0); + list.add(BigDecimal.ZERO); + list.add(BigDecimal.ZERO); + return list; + } + + // 3. 筛选当天数据 (Stream 操作) + List todayOrders = filteredByCreateTime.stream() + .filter(f -> f.getCreateTime().compareTo(startOfDay) >= 0 && f.getCreateTime().compareTo(endOfDay) < 0) + .collect(Collectors.toList()); + + List todayOrders1 = filteredByCreateTime1.stream() + .filter(f -> f.getCreateTime().compareTo(startOfDay) >= 0 && f.getCreateTime().compareTo(endOfDay) < 0) + .collect(Collectors.toList()); + + // 4. 计算每日条数 + int dailyCount = (todayOrders != null ? todayOrders.size() : 0) + (todayOrders1 != null ? todayOrders1.size() : 0); + list.add(dailyCount); + + // 5. 筛选当天有金额数据的订单 (Stream 操作) + List todayOrdersWithMoney = todayOrders != null ? todayOrders.stream() + .filter(f -> f != null && f.getToMoney() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + List todayOrdersWithMoney1 = todayOrders1 != null ? todayOrders1.stream() + .filter(f -> f != null && f.getToMoney() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + // 6. 计算每日金额 + BigDecimal totalTomoney = todayOrdersWithMoney.stream() + .map(TckOrderdetailBak::getToMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + BigDecimal totalTomoney1 = todayOrdersWithMoney1.stream() + .map(TCkOrderdetail::getToMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + list.add(totalTomoney); + + // 7. 筛选本月数据 (Stream 操作) + YearMonth currentYearMonth = YearMonth.now(); + List thisMonthOrders = filteredByCreateTime.stream() + .filter(f -> { + if (f != null && f.getCreateTime() != null) { + LocalDate createTimeLocalDate = f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + YearMonth yearMonth = YearMonth.of(createTimeLocalDate.getYear(), createTimeLocalDate.getMonth()); + return yearMonth.equals(currentYearMonth); + } + return false; + }) + .collect(Collectors.toList()); + + List thisMonthOrders1 = filteredByCreateTime1.stream() + .filter(f -> { + if (f != null && f.getCreateTime() != null) { + LocalDate createTimeLocalDate = f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + YearMonth yearMonth = YearMonth.of(createTimeLocalDate.getYear(), createTimeLocalDate.getMonth()); + return yearMonth.equals(currentYearMonth); + } + return false; + }) + .collect(Collectors.toList()); + + // 8. 计算月总金额 + BigDecimal monthlyTotalTomoney = thisMonthOrders.stream() + .filter(f -> f != null && f.getToMoney() != null) + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + BigDecimal monthlyTotalTomoney1 = thisMonthOrders1.stream() + .filter(f -> f != null && f.getToMoney() != null) + .map(TCkOrderdetail::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + list.add(monthlyTotalTomoney); + + } catch (Exception e) { + // 异常处理 + e.printStackTrace(); + // 如果发生异常,添加默认值 + list.clear(); + list.add(0); + list.add(BigDecimal.ZERO); + list.add(BigDecimal.ZERO); + } + + return list; + } + + @GetMapping("/dayAMonthRk") + @Log(title = "今日本月入库") + public List dayAMonthRk() { + List list = new ArrayList<>(); + + try { + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + Date startOfDay = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endOfDay = Date.from(today.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); + + List tckOrderdetailBaks = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + List tCkOrderdetails = tRkWareNoticeTabMapper.selectTRkWareNoticeTabList(new TRkWareNoticeTab()); + + // 1. 过滤创建时间为空的元素 (Stream 操作) + List filteredByCreateTime = tckOrderdetailBaks != null ? tckOrderdetailBaks.stream() + .filter(f -> f != null && f.getCreateTime() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + List filteredByCreateTime1 = tCkOrderdetails != null ? tCkOrderdetails.stream() + .filter(f -> f != null && f.getCreateTime() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + // 2. 判断是否有数据,避免空指针 + if (filteredByCreateTime.isEmpty() && filteredByCreateTime1.isEmpty()) { + list.add(0); + list.add(BigDecimal.ZERO); + list.add(BigDecimal.ZERO); + return list; + } + + // 3. 筛选当天数据 (Stream 操作) + List todayOrders = filteredByCreateTime.stream() + .filter(f -> f.getCreateTime().compareTo(startOfDay) >= 0 && f.getCreateTime().compareTo(endOfDay) < 0) + .collect(Collectors.toList()); + + List todayOrders1 = filteredByCreateTime1.stream() + .filter(f -> f.getCreateTime().compareTo(startOfDay) >= 0 && f.getCreateTime().compareTo(endOfDay) < 0) + .collect(Collectors.toList()); + + // 4. 计算每日条数 + int dailyCount = (todayOrders != null ? todayOrders.size() : 0) + (todayOrders1 != null ? todayOrders1.size() : 0); + list.add(dailyCount); + + // 5. 筛选当天有金额数据的订单 (Stream 操作) + List todayOrdersWithMoney = todayOrders != null ? todayOrders.stream() + .filter(f -> f != null && f.getTotalMoney() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + List todayOrdersWithMoney1 = todayOrders1 != null ? todayOrders1.stream() + .filter(f -> f != null && f.getTotalMoney() != null) + .collect(Collectors.toList()) : new ArrayList<>(); + + // 6. 计算每日金额 + BigDecimal totalTomoney = todayOrdersWithMoney.stream() + .map(TRkWareNoticeTabBak::getTotalMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + BigDecimal totalTomoney1 = todayOrdersWithMoney1.stream() + .map(TRkWareNoticeTab::getTotalMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + list.add(totalTomoney); + + // 7. 筛选本月数据 (Stream 操作) + YearMonth currentYearMonth = YearMonth.now(); + List thisMonthOrders = filteredByCreateTime.stream() + .filter(f -> { + if (f != null && f.getCreateTime() != null) { + LocalDate createTimeLocalDate = f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + YearMonth yearMonth = YearMonth.of(createTimeLocalDate.getYear(), createTimeLocalDate.getMonth()); + return yearMonth.equals(currentYearMonth); + } + return false; + }) + .collect(Collectors.toList()); + + List thisMonthOrders1 = filteredByCreateTime1.stream() + .filter(f -> { + if (f != null && f.getCreateTime() != null) { + LocalDate createTimeLocalDate = f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + YearMonth yearMonth = YearMonth.of(createTimeLocalDate.getYear(), createTimeLocalDate.getMonth()); + return yearMonth.equals(currentYearMonth); + } + return false; + }) + .collect(Collectors.toList()); + + // 8. 计算月总金额 + BigDecimal monthlyTotalTomoney = thisMonthOrders.stream() + .filter(f -> f != null && f.getTotalMoney() != null) + .map(TRkWareNoticeTabBak::getTotalMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + BigDecimal monthlyTotalTomoney1 = thisMonthOrders1.stream() + .filter(f -> f != null && f.getTotalMoney() != null) + .map(TRkWareNoticeTab::getTotalMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + + list.add(monthlyTotalTomoney); + + } catch (Exception e) { + // 异常处理 + e.printStackTrace(); + // 如果发生异常,添加默认值 + list.clear(); + list.add(0); + list.add(BigDecimal.ZERO); + list.add(BigDecimal.ZERO); + } + + return list; + } + + @GetMapping("/sixMonthCk") + @Log(title = "近六个月出库数量金额") + public Map> sixMonthCk() { + Map> map = new LinkedHashMap<>(); + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + // 获取当前时间 + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + // 遍历当前月及前五个月 + for (int i = 5; i >= 0; i--) { + List list = new ArrayList<>(); + // 获取当前月向前推 i 个月的 YearMonth + YearMonth yearMonth = currentMonth.minusMonths(1); + YearMonth targetMonth = yearMonth.minusMonths(i); + LocalDate monthStart = targetMonth.atDay(1); // 月初 + LocalDate monthEnd = targetMonth.atEndOfMonth(); // 月末 + String date = targetMonth.format(formatter); + + // 将 LocalDate 转换为 Date + Date startDate = Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(monthEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 筛选出 createtime 在当前月份范围内的数据 + List filteredList = tckOrderdetailBak.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + + if(filteredList.isEmpty()){ + list.add(0); + list.add(0); + }else{ + BigDecimal goodNums = filteredList.stream() + .map(TckOrderdetailBak::getGoodsNum) + .reduce(BigDecimal.ZERO, BigDecimal::add); + list.add(goodNums); + List collect = filteredList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else { + BigDecimal toMoney = collect.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + list.add(toMoney); + } + } + map.put(date,list); + } + return map; + } + + @GetMapping("/sixMonthOutAndIn") + @Log(title = "近六个月出库入库金额") + public Map> sixMonthOutAndIn() { + Map> map = new LinkedHashMap<>(); + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + + List tckOrderdetailBaks1 = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + List tckOrderdetailBak1 = tckOrderdetailBaks1.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + + + // 获取当前时间 + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + // 遍历前6个月 + for (int i = 6; i >= 1; i--) { + List list = new ArrayList<>(); + // 获取当前月向前推 i 个月的 YearMonth + YearMonth targetMonth = currentMonth.minusMonths(i); + LocalDate monthStart = targetMonth.atDay(1); // 月初 + LocalDate monthEnd = targetMonth.atEndOfMonth(); // 月末 + String date = targetMonth.format(formatter); + + // 将 LocalDate 转换为 Date + Date startDate = Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(monthEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 筛选出 createtime 在当前月份范围内的数据 + List filteredList = tckOrderdetailBak.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + + if(filteredList.isEmpty()){ + list.add(0); + + }else{ + List collect = filteredList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else { + BigDecimal toMoney = collect.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + if(toMoney == BigDecimal.ZERO){ + list.add(toMoney); + }else{ + BigDecimal divide = toMoney.divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP); + list.add(divide); + } + } + } + + List filteredList1 = tckOrderdetailBak1.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + + if(filteredList1.isEmpty()){ + list.add(0); + + }else{ + List collect = filteredList1.stream().filter(f -> ObjectUtils.isNotEmpty(f.getTotalMoney())).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else { + BigDecimal toMoney = collect.stream() + .map(TRkWareNoticeTabBak::getTotalMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + if(toMoney == BigDecimal.ZERO){ + list.add(toMoney); + }else{ + BigDecimal divide = toMoney.divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP); + list.add(divide); + } + + } + } + map.put(date,list); + } + return map; + } + + @GetMapping("/sixMonthRk") + @Log(title = "近六个月入库数量金额") + public Map> sixMonthRk() { + Map> map = new LinkedHashMap<>(); + List tckOrderdetailBaks = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + // 获取当前时间 + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + // 遍历当前月及前五个月 + for (int i = 5; i >= 0; i--) { + List list = new ArrayList<>(); + // 获取当前月向前推 i 个月的 YearMonth + YearMonth yearMonth = currentMonth.minusMonths(1); + YearMonth targetMonth = yearMonth.minusMonths(i); + LocalDate monthStart = targetMonth.atDay(1); // 月初 + LocalDate monthEnd = targetMonth.atEndOfMonth(); // 月末 + String date = targetMonth.format(formatter); + + // 将 LocalDate 转换为 Date + Date startDate = Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(monthEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 筛选出 createtime 在当前月份范围内的数据 + List filteredList = tckOrderdetailBak.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + + if(filteredList.isEmpty()){ + list.add(0); + list.add(0); + }else{ + List collect1 = filteredList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getAcceNum())).collect(Collectors.toList()); + if(collect1.isEmpty()){ + list.add(0); + }else{ + BigDecimal goodNums = collect1.stream() + .map(TRkWareNoticeTabBak::getAcceNum) + .reduce(BigDecimal.ZERO, BigDecimal::add); + list.add(goodNums); + } + List collect = filteredList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getTotalMoney())).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else { + BigDecimal toMoney = collect.stream() + .map(TRkWareNoticeTabBak::getTotalMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + list.add(toMoney); + } + } + map.put(date,list); + } + return map; + } + + @GetMapping("/ckMoneyVS") + @Log(title = "出库金额同比") + public Map> ckMoneyVS() { + Map> map = new LinkedHashMap<>(); + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .collect(Collectors.toList()); + + // 获取当前时间 + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + + for (int i = 6; i >= 1; i--) { + List list = new ArrayList<>(); + + // 获取当前月向前推 i 个月的 YearMonth + YearMonth targetMonth = currentMonth.minusMonths(i); + LocalDate monthStart = targetMonth.atDay(1); // 月初 + LocalDate monthEnd = targetMonth.atEndOfMonth(); // 月末 + String date = targetMonth.format(formatter); + + // 定义时间范围 + Date startDate = Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(monthEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 筛选出 createtime 在当前月份范围内的数据 + list.add(getSumForMonth(tckOrderdetailBak, startDate, endDate)); + + // 添加去年同月数据 + YearMonth lastYearMonth = targetMonth.minusYears(1); + LocalDate lastYearStart = lastYearMonth.atDay(1); + LocalDate lastYearEnd = lastYearMonth.atEndOfMonth(); + Date lastYearStartDate = Date.from(lastYearStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date lastYearEndDate = Date.from(lastYearEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + list.add(getSumForMonth(tckOrderdetailBak, lastYearStartDate, lastYearEndDate)); + + // 添加前年同月数据 + YearMonth twoYearsAgoMonth = targetMonth.minusYears(2); + LocalDate twoYearsAgoStart = twoYearsAgoMonth.atDay(1); + LocalDate twoYearsAgoEnd = twoYearsAgoMonth.atEndOfMonth(); + Date twoYearsAgoStartDate = Date.from(twoYearsAgoStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date twoYearsAgoEndDate = Date.from(twoYearsAgoEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + list.add(getSumForMonth(tckOrderdetailBak, twoYearsAgoStartDate, twoYearsAgoEndDate)); + + // 将结果存入 map + map.put(date, list); + } + return map; + } + + @GetMapping("/monthOutTo") + @Log(title = "本月物资流向") + public Map monthOutTo() { + Map map = new LinkedHashMap<>(); + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + //筛选日期不为空 + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime()) && ObjectUtils.isNotEmpty(f.getApplicant())) + .collect(Collectors.toList()); + //筛选本月 + List thisMonthOrders = tckOrderdetailBak.stream() + .filter(f -> { + LocalDate createTimeLocalDate = f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + YearMonth yearMonth = YearMonth.of(createTimeLocalDate.getYear(), createTimeLocalDate.getMonth()); + YearMonth currentYearMonth = YearMonth.now(); + return yearMonth.equals(currentYearMonth); + }) + .collect(Collectors.toList()); + //根据申请人分组 + Map> groupedByApplicant = thisMonthOrders.stream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getApplicant)); + + Map> filteredMap = new HashMap<>(); + groupedByApplicant.forEach((applicant, group) -> { + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + + if(deptId == null){ + return; + } + + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + String[] split = ancestors.split(","); + if (split.length > 3 ||split.length==3) { + filteredMap.put(applicant, group); + } + }); + groupedByApplicant = filteredMap; + groupedByApplicant.forEach((applicant, group) -> { + + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + if(deptId == null){ + return; + } + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + String[] split = ancestors.split(","); + String deptName; + if(split.length==3){ + deptName= sysDeptMapper.selectDeptById(deptId).getDeptName(); + }else { + deptName= sysDeptMapper.selectDeptById(Long.valueOf(split[3])).getDeptName(); + } + System.out.println("Applicant: " + applicant); + //筛选空值 + List collect = group.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); + BigDecimal toMoney; + if(collect.isEmpty()){ + toMoney= BigDecimal.ZERO; + }else{ + toMoney = collect.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + if(toMoney.compareTo(BigDecimal.ZERO) != 0){ + toMoney = toMoney.divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP); + } + BigDecimal bigDecimal = map.get(deptName); + if(ObjectUtils.isEmpty(bigDecimal)){ + map.put(deptName,toMoney); + }else{ + BigDecimal add = bigDecimal.add(toMoney); + map.put(deptName,add); + } + + }); + + return map; + } + + @GetMapping("/sixMonthOutTo") + @Log(title = "近6个月物资流向") + public List> sixMonthOutTo() { + List> list = new LinkedList<>(); +// Map> maps = new LinkedHashMap<>(); + LocalDate today = LocalDate.now(ZoneId.systemDefault()); + //筛选日期不为空 + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime()) && ObjectUtils.isNotEmpty(f.getApplicant())) + .collect(Collectors.toList()); + // 获取当前时间 + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + // 遍历当前月及前五个月 + for (int i = 6; i >= 1; i--) { + Map map = new LinkedHashMap<>(); + + // 获取当前月向前推 i 个月的 YearMonth + YearMonth targetMonth = currentMonth.minusMonths(i); + LocalDate monthStart = targetMonth.atDay(1); // 月初 + LocalDate monthEnd = targetMonth.atEndOfMonth(); // 月末 + String date = targetMonth.format(formatter); + + // 将 LocalDate 转换为 Date + Date startDate = Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(monthEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 筛选出 createtime 在当前月份范围内的数据 + List thisMonthOrders = tckOrderdetailBak.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + + + //筛选本月 + if(thisMonthOrders.isEmpty()){ + map.put("其他",BigDecimal.ZERO); + list.add(map); + continue; + } + List collect1 = thisMonthOrders.stream().filter(f -> ObjectUtils.isNotEmpty(f.getApplicant())).collect(Collectors.toList()); + if(collect1.isEmpty()){ + map.put("其他",BigDecimal.ZERO); + list.add(map); + continue; + } + //根据申请人分组 + Map> groupedByApplicant = collect1.stream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getApplicant)); + Map> filteredMap = new HashMap<>(); + groupedByApplicant.forEach((applicant, group) -> { + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + if(deptId == null){ + return; + } + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + String[] split = ancestors.split(","); + if (split.length > 3 ||split.length==3) { + filteredMap.put(applicant, group); + } + }); + groupedByApplicant = filteredMap; + groupedByApplicant.forEach((applicant, group) -> { + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + if(deptId == null){ + return; + } + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + String[] split = ancestors.split(","); + String deptName; + if(split.length==3){ + deptName= sysDeptMapper.selectDeptById(deptId).getDeptName(); + }else { + deptName= sysDeptMapper.selectDeptById(Long.valueOf(split[3])).getDeptName(); + } + System.out.println("Applicant: " + applicant); + //筛选空值 + List collect = group.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); + BigDecimal toMoney; + if (collect.isEmpty()) { + toMoney = BigDecimal.ZERO; + } else { + toMoney = collect.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + BigDecimal bigDecimal = map.get(deptName); + if (ObjectUtils.isEmpty(bigDecimal)) { + map.put(deptName, toMoney); + } else { + BigDecimal add = bigDecimal.add(toMoney); + map.put(deptName, add); + } + + }); + list.add(map); + } + + return list; + } + + + @GetMapping("/groupCk") + @Log(title = "小组出库金额") + public Map groupCk() { + Map map = new LinkedHashMap<>(); + LocalDate today = LocalDate.now(ZoneId.systemDefault()); +// 筛选日期不为空和申请人不为空 + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime()) && ObjectUtils.isNotEmpty(f.getApplicant())) + .collect(Collectors.toList()); +// 筛选本年 + List thisYearOrders = tckOrderdetailBak.stream() + .filter(f -> { + LocalDate createTimeLocalDate = f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + int createTimeYear = createTimeLocalDate.getYear(); + int currentYear = Year.now().getValue(); + return createTimeYear == currentYear; // 判断年份是否为当前年份 + }) + .collect(Collectors.toList()); + //根据申请人分组 + Map> groupedByApplicant = thisYearOrders.stream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getApplicant)); + + Map> filteredMap = new HashMap<>(); + groupedByApplicant.forEach((applicant, group) -> { + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + if(deptId == null){ + return; + } + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + String[] split = ancestors.split(","); + if (split.length > 3 ||split.length==3) { + filteredMap.put(applicant, group); + } + }); + groupedByApplicant = filteredMap; + groupedByApplicant.forEach((applicant, group) -> { + + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + if(deptId == null){ + return; + } + + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + String[] split = ancestors.split(","); + String deptName; + if(split.length==3){ + deptName= sysDeptMapper.selectDeptById(deptId).getDeptName(); + }else { + deptName= sysDeptMapper.selectDeptById(Long.valueOf(split[3])).getDeptName(); + } + System.out.println("Applicant: " + applicant); + //筛选空值 + List collect = group.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); + BigDecimal toMoney; + if(collect.isEmpty()){ + toMoney= BigDecimal.ZERO; + }else{ + toMoney = collect.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + BigDecimal bigDecimal = map.get(deptName); + if(ObjectUtils.isEmpty(bigDecimal)){ + map.put(deptName,toMoney); + }else{ + BigDecimal add = bigDecimal.add(toMoney); + map.put(deptName,add); + } + + }); + + return map; + } + + + @GetMapping("/monthYsOut/{deptId}") + @Log(title = "近6月预算支出") + public Map monthYsOut(@PathVariable String deptId) { + System.out.println(deptId); + Map map = new LinkedHashMap<>(); + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + // 获取当前时间 + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + // 遍历当前月及前五个月 + for (int i = 6; i >= 1; i--) { + List list = new ArrayList<>(); + // 获取当前月向前推 i 个月的 YearMonth + YearMonth targetMonth = currentMonth.minusMonths(i); + LocalDate monthStart = targetMonth.atDay(1); // 月初 + LocalDate monthEnd = targetMonth.atEndOfMonth(); // 月末 + String date = targetMonth.format(formatter); + + // 将 LocalDate 转换为 Date + Date startDate = Date.from(monthStart.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Date endDate = Date.from(monthEnd.atStartOfDay(ZoneId.systemDefault()).toInstant()); + + // 筛选出 createtime 在当前月份范围内的数据 + List filteredList = tckOrderdetailBak.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + BigDecimal toMoney; + if(filteredList.isEmpty()){ + toMoney=BigDecimal.ZERO; + + }else{ +// List collect = filteredList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); +// if(collect.isEmpty()){ +// toMoney=BigDecimal.ZERO; +// }else { +// toMoney = collect.stream() +// .map(TckOrderdetailBak::getToMoney) +// .reduce(BigDecimal.ZERO, BigDecimal::add); +// list.add(toMoney); +// } + List ck = ck(filteredList, deptId); + + Object o = ck.get(0); + BigDecimal bigDecimalValue = new BigDecimal(String.valueOf(o)); + toMoney = bigDecimalValue; + } + map.put(date,toMoney); + } + return map; + } + + + @GetMapping("/totalUse") + @Log(title = "累计使用率") + public BigDecimal totalUse() { + BigDecimal total; + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + if(tckOrderdetailBak.isEmpty()){ + total = BigDecimal.ZERO; + }else{ + int currentYear = LocalDate.now(ZoneId.systemDefault()).getYear(); + + // 筛选 createTime 字段为本年的数据 + List collect = tckOrderdetailBak.stream() + .filter(item -> { + LocalDate createTimeLocalDate = item.getCreateTime() + .toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); // 将 Date 转换为 LocalDate + return createTimeLocalDate.getYear() == currentYear; // 比较年份 + }) + .collect(Collectors.toList()); + if(collect.isEmpty()){ + total = BigDecimal.ZERO; + }else{ + List collect1 = collect.stream().filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())).collect(Collectors.toList()); + if(collect1.isEmpty()){ + total = BigDecimal.ZERO; + }else{ + total = collect1.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + } + } + return total; + } + + + @GetMapping("/yearCkRk") + @Log(title = "出入库单数趋势") + public Map yearCkRk() { + Map map =new LinkedHashMap<>(); + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + List tckOrderdetailBak = tckOrderdetailBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + + List tRkWareNoticeTabBaks = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + List tRkWareNoticeTabBak = tRkWareNoticeTabBaks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())).collect(Collectors.toList()); + + int currentYear = LocalDate.now().getYear(); + + List dong1 = new LinkedList(); + List xi1 = new LinkedList(); + List nan1 = new LinkedList(); + List ccd1 = new LinkedList(); + + // 遍历本年每个月 + for (int month = 1; month <= 12; month++) { + YearMonth yearMonth = YearMonth.of(currentYear, month); + + LocalDate startDate = yearMonth.atDay(1); // Start of the month + LocalDate endDate = yearMonth.atEndOfMonth(); // End of the month (inclusive) + + List monthlyData = tckOrderdetailBak.stream() + .filter(order -> { + LocalDate orderDate = order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + return orderDate.isAfter(startDate.minusDays(1)) && orderDate.isBefore(endDate.plusDays(1)); + }) + .collect(Collectors.toList()); + + List monthlyDatas = tRkWareNoticeTabBak.stream() + .filter(order -> { + LocalDate orderDate = order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + return orderDate.isAfter(startDate.minusDays(1)) && orderDate.isBefore(endDate.plusDays(1)); + }) + .collect(Collectors.toList()); + int dong = location(monthlyData, monthlyDatas, 101, "东区维修中心"); + int xi = location(monthlyData, monthlyDatas, 128, "西区维修中心"); + int nan = location(monthlyData, monthlyDatas, 129, "南区维修中心"); + int ccd = location(monthlyData, monthlyDatas, 120, "仓储队"); + dong1.add(dong); + xi1.add(xi); + nan1.add(nan); + ccd1.add(ccd); + + } + map.put("东区维修中心",dong1); + map.put("西区维修中心",xi1); + map.put("南区维修中心",nan1); + map.put("仓储队",ccd1); + return map; + } + public int location(List monthlyData,List monthlyDatas,int i,String location){ + int totalsize; + int ck; + int rk; + if(monthlyData.isEmpty()){ + ck = 0; + } + else { + List ckList = monthlyData.stream().filter(f -> ObjectUtils.isNotEmpty(f.getApplicant())).collect(Collectors.toList()); + if(ckList.isEmpty()){ + ck=0; + } + else{ + Map> groupedByApplicant = ckList.stream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getApplicant)); + Map> filteredMap = new HashMap<>(); + groupedByApplicant.forEach((applicant, group) -> { + SysUser sysUser = sysUserMapper.selectUserByNickName(applicant); + Long deptId = null; + if(sysUser != null){ + deptId = sysUser.getDeptId(); + } + if(deptId == null){ + return; + } + String ancestors = sysDeptMapper.selectDeptById(deptId).getAncestors(); + if(deptId == i || ancestors.contains(String.valueOf(i))){ + filteredMap.put(applicant, group); + } + + + }); + if(filteredMap.isEmpty()){ + ck = 0; + }else{ + groupedByApplicant = filteredMap; + ck = groupedByApplicant.size(); + } + + } + } + + if(monthlyDatas.isEmpty()){ + rk = 0; + }else{ + List rks = monthlyDatas.stream().filter(f -> ObjectUtils.isNotEmpty(f.getNeedDept()) && f.getNeedDept().equals(location)).collect(Collectors.toList()); + if(rks.isEmpty()){ + rk = 0; + }else{ + rk = rks.size(); + } + } + totalsize = ck + rk; + return totalsize; + } + + + /** + * 获取指定时间段内的金额总和 + */ + private Object getSumForMonth(List tckOrderdetailBak, Date startDate, Date endDate) { + // 筛选出 createtime 在指定范围内的数据 + List filteredList = tckOrderdetailBak.stream() + .filter(item -> item.getCreateTime() != null) + .filter(item -> item.getCreateTime().compareTo(startDate) >= 0 && + item.getCreateTime().compareTo(endDate) <= 0) + .collect(Collectors.toList()); + + // 如果没有符合条件的数据,返回 0 + if (filteredList.isEmpty()) { + return 0; + } + + // 筛选出 toMoney 非空的数据并计算总和 + List collect = filteredList.stream() + .filter(f -> ObjectUtils.isNotEmpty(f.getToMoney())) + .collect(Collectors.toList()); + if (collect.isEmpty()) { + return 0; + } else { + return collect.stream() + .map(TckOrderdetailBak::getToMoney) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + } + + + + + /** + * 出入库任务数量统计 + * + * @return + */ + @GetMapping("/task") + public List> task() { + return largeScreenService.task(); + } + + @GetMapping("/tmistockFB") + @Log(title = "库存分布") + public List> tmistockFB() { + List> list = new ArrayList<>(); + List tMiStocks = tMiStockMapper.selectTMiStockList(new TMiStock()); + List tMiStock = tMiStocks.stream().filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime()) && ObjectUtils.isNotEmpty(f.getTotalMoney())).collect(Collectors.toList()); + LocalDateTime now = LocalDateTime.now(); + LocalDateTime oneMonthAgo = now.minusMonths(1); + Map map = new LinkedHashMap<>(); + BigDecimal total = total(tMiStock, oneMonthAgo); + map.put("1个月",total); + + List collect = tMiStock.stream() + .filter(f -> LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()) + .isBefore(oneMonthAgo)) + .collect(Collectors.toList()); + LocalDateTime oneMonthAgo3 = now.minusMonths(3); + BigDecimal total3 = total(collect, oneMonthAgo3); + map.put("3个月",total3); + + + List collect1 = tMiStock.stream() + .filter(f -> LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()) + .isBefore(oneMonthAgo3)) + .collect(Collectors.toList()); + LocalDateTime oneMonthAgo6 = now.minusMonths(6); + BigDecimal total6 = total(collect1, oneMonthAgo6); + map.put("6个月",total6); + + + List collect2 = tMiStock.stream() + .filter(f -> LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()) + .isBefore(oneMonthAgo6)) + .collect(Collectors.toList()); + LocalDateTime oneMonthAgo12 = now.minusMonths(12); + BigDecimal total12 = total(collect2, oneMonthAgo12); + map.put("12个月",total12); + + + List collect3 = tMiStock.stream() + .filter(f -> LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()) + .isBefore(oneMonthAgo12)) + .collect(Collectors.toList()); + LocalDateTime oneMonthAgo24 = now.minusMonths(24); + BigDecimal total24 = total(collect3, oneMonthAgo24); + map.put("24个月",total24); + + List collect4 = tMiStock.stream() + .filter(f -> LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()) + .isBefore(oneMonthAgo24)) + .collect(Collectors.toList()); + LocalDateTime oneMonthAgo36 = now.minusMonths(36); + BigDecimal total36 = total(collect4, oneMonthAgo36); + map.put("36个月",total36); + + + LocalDateTime thirtySixMonthsAgo = now.minusMonths(36); + + List collect5 = tMiStocks.stream() + .filter(f -> { + LocalDateTime createTime = LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()); + return createTime.isBefore(thirtySixMonthsAgo); + }) + .collect(Collectors.toList()); + BigDecimal totalMoney; + if(collect5.isEmpty()){ + totalMoney = BigDecimal.ZERO; + }else{ + totalMoney = collect.stream() + .map(TMiStock::getTotalMoney) // 提取 getMoney 字段 + .filter(java.util.Objects::nonNull) // 排除 null 值 + .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加 + BigDecimal num2 = new BigDecimal("10000"); + totalMoney = totalMoney.divide(num2, 2, RoundingMode.HALF_UP); + + } + map.put("36个月以上",totalMoney); + list.add(map); + + + return list; + } + + public BigDecimal total( List tMiStock , LocalDateTime oneMonthAgo) { + + List collect = tMiStock.stream() + .filter(f -> LocalDateTime.ofInstant(f.getCreateTime().toInstant(), ZoneId.systemDefault()) + .isBefore(oneMonthAgo)) + .collect(Collectors.toList()); + BigDecimal totalMoney; + if(collect.isEmpty()){ + totalMoney = BigDecimal.ZERO; + }else{ + totalMoney = collect.stream() + .map(TMiStock::getTotalMoney) // 提取 getMoney 字段 + .filter(java.util.Objects::nonNull) // 排除 null 值 + .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加 + BigDecimal num2 = new BigDecimal("10000"); + totalMoney = totalMoney.divide(num2, 2, RoundingMode.HALF_UP); + + } + return totalMoney; + } + + + @GetMapping("/ys") + @Log(title = "五大维修中心预算使用率") + public List ys() { + int currentYear = Year.now().getValue(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + +// CompletableFuture> tMiStocksFuture = CompletableFuture.supplyAsync(() -> +// tMiStockMapper.selectTMiStockList(new TMiStock())); + + CompletableFuture> tckOrderdetailBaksFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak())); + + try { +// List tMiStocks = tMiStocksFuture.get(); + List tckOrderdetailBaks = tckOrderdetailBaksFuture.get(); + +// List filteredList = tMiStocks.parallelStream() +// .filter(t -> { +// try { +// LocalDate wareDate = LocalDate.parse(t.getWareDate(), formatter); +// return wareDate.getYear() == currentYear; +// } catch (DateTimeParseException e) { +// return false; +// } +// }) +// .collect(Collectors.toList()); + +// BigDecimal totalMoney = filteredList.parallelStream() +// .map(TMiStock::getTotalMoney) +// .filter(Objects::nonNull) +// .reduce(BigDecimal.ZERO, BigDecimal::add) +// .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + + List filteredList1 = tckOrderdetailBaks.parallelStream() + .filter(order -> order.getCreateTime() != null && + order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().getYear() == currentYear) + .collect(Collectors.toList()); + + List centers = new ArrayList<>(); + SysDictData sysDictDatas =new SysDictData(); + sysDictDatas.setDictType("sys_ys"); + List sysDictData4 = sysDictDataMapper.selectDictDataList(sysDictDatas); + for(SysDictData t : sysDictData4){ + centers.add(t.getDictLabel()); + } + centers.remove("总预算"); + //全年出库金额 + List lists = centers.parallelStream().map(center -> { + List centerData = ck(filteredList1, center); + BigDecimal centerValue = new BigDecimal(centerData.get(0).toString()); + BigDecimal result; + SysDictData sysDictData =new SysDictData(); + sysDictData.setDictType("sys_ys"); + sysDictData.setDictLabel(center); + List sysDictData1 = sysDictDataMapper.selectDictDataList(sysDictData); + String dictValue = sysDictData1.get(0).getDictValue(); + BigDecimal bigDecimal = new BigDecimal(dictValue); + + if (centerValue.compareTo(BigDecimal.ZERO) != 0 && bigDecimal.compareTo(BigDecimal.ZERO) != 0) { + result = centerValue.divide(bigDecimal, new MathContext(2, RoundingMode.HALF_UP)) + .multiply(new BigDecimal("100")); + } else { + result = BigDecimal.ZERO; + } + YearMonth yearMonth = YearMonth.now(); + // 每个月出库金额 + List value =new ArrayList<>(); + for (int month = 0; month < yearMonth.getMonthValue(); month++) { + int m = yearMonth.getMonthValue() - month - 1; + YearMonth previousMonth = yearMonth.minusMonths(m); + LocalDate startOfMonth = previousMonth.atDay(1); + LocalDate endOfMonth = previousMonth.atEndOfMonth(); + + List filteredLists = tckOrderdetailBaks.stream() + .filter(order -> ObjectUtils.isNotEmpty(order.getCreateTime())) + .filter(order -> { + LocalDate orderDate = order.getCreateTime().toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + return orderDate.getYear() == currentYear && + orderDate.isAfter(startOfMonth.minusDays(1)) && + orderDate.isBefore(endOfMonth.plusDays(1)); + }) + .collect(Collectors.toList()); + + List centerData1 = ck(filteredLists, center); + BigDecimal centerValue1 = new BigDecimal(centerData1.get(0).toString()); + BigDecimal result1; + SysDictData sysDictData2 =new SysDictData(); + sysDictData2.setDictType("sys_ys"); + sysDictData2.setDictLabel(center); + List sysDictData3 = sysDictDataMapper.selectDictDataList(sysDictData2); + String dictValue1 = sysDictData3.get(0).getDictValue(); + BigDecimal bigDecimal1 = new BigDecimal(dictValue1); + + if (centerValue1.compareTo(BigDecimal.ZERO) != 0 && bigDecimal1.compareTo(BigDecimal.ZERO) != 0) { + result1 = centerValue1.divide(bigDecimal1, new MathContext(2, RoundingMode.HALF_UP)) + .multiply(new BigDecimal("100")); + } else { + result1 = BigDecimal.ZERO; + } + value.add(result1); + } + + Task task = new Task(); + task.setName(center); + task.setRate(result); + task.setValues(value); + return task; + }).collect(Collectors.toList()); + + return lists; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + + @GetMapping("/ys/other") + @Log(title = "五大维修中心预算使用率") + public List ys1() { + int currentYear = Year.now().getValue(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + +// CompletableFuture> tMiStocksFuture = CompletableFuture.supplyAsync(() -> +// tMiStockMapper.selectTMiStockList(new TMiStock())); + + CompletableFuture> tckOrderdetailBaksFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak())); + + try { +// List tMiStocks = tMiStocksFuture.get(); + List collect = tckOrderdetailBaksFuture.get(); + List tckOrderdetailBaks = (collect != null && !collect.isEmpty()) ? + collect.stream() + .filter(f -> f != null && f.getLevelType() != null && !f.getLevelType().equals("1")) + .collect(Collectors.toList()) : + Collections.emptyList(); + +// List filteredList = tMiStocks.parallelStream() +// .filter(t -> { +// try { +// LocalDate wareDate = LocalDate.parse(t.getWareDate(), formatter); +// return wareDate.getYear() == currentYear; +// } catch (DateTimeParseException e) { +// return false; +// } +// }) +// .collect(Collectors.toList()); + +// BigDecimal totalMoney = filteredList.parallelStream() +// .map(TMiStock::getTotalMoney) +// .filter(Objects::nonNull) +// .reduce(BigDecimal.ZERO, BigDecimal::add) +// .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + + List filteredList1 = tckOrderdetailBaks.parallelStream() + .filter(order -> order.getCreateTime() != null && + order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().getYear() == currentYear) + .collect(Collectors.toList()); + + List centers = new ArrayList<>(); + SysDictData sysDictDatas =new SysDictData(); + sysDictDatas.setDictType("sys_ys"); + List sysDictData4 = sysDictDataMapper.selectDictDataList(sysDictDatas); + for(SysDictData t : sysDictData4){ + centers.add(t.getDictLabel()); + } + centers.remove("总预算"); + //全年出库金额 + List lists = centers.parallelStream().map(center -> { + List centerData = ck(filteredList1, center); + BigDecimal centerValue = new BigDecimal(centerData.get(0).toString()); + BigDecimal result; + SysDictData sysDictData =new SysDictData(); + sysDictData.setDictType("sys_ys"); + sysDictData.setDictLabel(center); + List sysDictData1 = sysDictDataMapper.selectDictDataList(sysDictData); + String dictValue = sysDictData1.get(0).getDictValue(); + BigDecimal bigDecimal = new BigDecimal(dictValue); + + if (centerValue.compareTo(BigDecimal.ZERO) != 0 && bigDecimal.compareTo(BigDecimal.ZERO) != 0) { + result = centerValue.divide(bigDecimal, new MathContext(2, RoundingMode.HALF_UP)) + .multiply(new BigDecimal("100")); + } else { + result = BigDecimal.ZERO; + } + YearMonth yearMonth = YearMonth.now(); + // 每个月出库金额 + List value =new ArrayList<>(); + for (int month = 0; month < yearMonth.getMonthValue(); month++) { + int m = yearMonth.getMonthValue() - month - 1; + YearMonth previousMonth = yearMonth.minusMonths(m); + LocalDate startOfMonth = previousMonth.atDay(1); + LocalDate endOfMonth = previousMonth.atEndOfMonth(); + + List filteredLists = tckOrderdetailBaks.stream() + .filter(order -> ObjectUtils.isNotEmpty(order.getCreateTime())) + .filter(order -> { + LocalDate orderDate = order.getCreateTime().toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + return orderDate.getYear() == currentYear && + orderDate.isAfter(startOfMonth.minusDays(1)) && + orderDate.isBefore(endOfMonth.plusDays(1)); + }) + .collect(Collectors.toList()); + + List centerData1 = ck(filteredLists, center); + BigDecimal centerValue1 = new BigDecimal(centerData1.get(0).toString()); + BigDecimal result1; + SysDictData sysDictData2 =new SysDictData(); + sysDictData2.setDictType("sys_ys"); + sysDictData2.setDictLabel(center); + List sysDictData3 = sysDictDataMapper.selectDictDataList(sysDictData2); + String dictValue1 = sysDictData3.get(0).getDictValue(); + BigDecimal bigDecimal1 = new BigDecimal(dictValue1); + + if (centerValue1.compareTo(BigDecimal.ZERO) != 0 && bigDecimal1.compareTo(BigDecimal.ZERO) != 0) { + result1 = centerValue1.divide(bigDecimal1, new MathContext(2, RoundingMode.HALF_UP)) + .multiply(new BigDecimal("100")); + } else { + result1 = BigDecimal.ZERO; + } + value.add(result1); + } + + Task task = new Task(); + task.setName(center); + task.setRate(result); + task.setValues(value); + return task; + }).collect(Collectors.toList()); + + return lists; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + + @GetMapping("/ys/global") + @Log(title = "五大维修中心预算使用率") + public List ys2() { + int currentYear = Year.now().getValue(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + +// CompletableFuture> tMiStocksFuture = CompletableFuture.supplyAsync(() -> +// tMiStockMapper.selectTMiStockList(new TMiStock())); + + CompletableFuture> tckOrderdetailBaksFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak())); + + try { +// List tMiStocks = tMiStocksFuture.get(); + List collect = tckOrderdetailBaksFuture.get(); + List tckOrderdetailBaks = (collect != null && !collect.isEmpty()) ? + collect.stream() + .filter(f -> f != null && f.getLevelType() != null && f.getLevelType().equals("1")) + .collect(Collectors.toList()) : + Collections.emptyList(); + // List filteredList = tMiStocks.parallelStream() +// .filter(t -> { +// try { +// LocalDate wareDate = LocalDate.parse(t.getWareDate(), formatter); +// return wareDate.getYear() == currentYear; +// } catch (DateTimeParseException e) { +// return false; +// } +// }) +// .collect(Collectors.toList()); + +// BigDecimal totalMoney = filteredList.parallelStream() +// .map(TMiStock::getTotalMoney) +// .filter(Objects::nonNull) +// .reduce(BigDecimal.ZERO, BigDecimal::add) +// .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + + List filteredList1 = tckOrderdetailBaks.parallelStream() + .filter(order -> order.getCreateTime() != null && + order.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().getYear() == currentYear) + .collect(Collectors.toList()); + + List centers = new ArrayList<>(); + SysDictData sysDictDatas =new SysDictData(); + sysDictDatas.setDictType("sys_ys"); + List sysDictData4 = sysDictDataMapper.selectDictDataList(sysDictDatas); + for(SysDictData t : sysDictData4){ + centers.add(t.getDictLabel()); + } + centers.remove("总预算"); + //全年出库金额 + List lists = centers.parallelStream().map(center -> { + List centerData = ck(filteredList1, center); + BigDecimal centerValue = new BigDecimal(centerData.get(0).toString()); + BigDecimal result; + SysDictData sysDictData =new SysDictData(); + sysDictData.setDictType("sys_ys"); + sysDictData.setDictLabel(center); + List sysDictData1 = sysDictDataMapper.selectDictDataList(sysDictData); + String dictValue = sysDictData1.get(0).getDictValue(); + BigDecimal bigDecimal = new BigDecimal(dictValue); + + if (centerValue.compareTo(BigDecimal.ZERO) != 0 && bigDecimal.compareTo(BigDecimal.ZERO) != 0) { + result = centerValue.divide(bigDecimal, new MathContext(2, RoundingMode.HALF_UP)) + .multiply(new BigDecimal("100")); + } else { + result = BigDecimal.ZERO; + } + YearMonth yearMonth = YearMonth.now(); + // 每个月出库金额 + List value =new ArrayList<>(); + for (int month = 0; month < yearMonth.getMonthValue(); month++) { + int m = yearMonth.getMonthValue() - month - 1; + YearMonth previousMonth = yearMonth.minusMonths(m); + LocalDate startOfMonth = previousMonth.atDay(1); + LocalDate endOfMonth = previousMonth.atEndOfMonth(); + + List filteredLists = tckOrderdetailBaks.stream() + .filter(order -> ObjectUtils.isNotEmpty(order.getCreateTime())) + .filter(order -> { + LocalDate orderDate = order.getCreateTime().toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDate(); + return orderDate.getYear() == currentYear && + orderDate.isAfter(startOfMonth.minusDays(1)) && + orderDate.isBefore(endOfMonth.plusDays(1)); + }) + .collect(Collectors.toList()); + + List centerData1 = ck(filteredLists, center); + BigDecimal centerValue1 = new BigDecimal(centerData1.get(0).toString()); + BigDecimal result1; + SysDictData sysDictData2 =new SysDictData(); + sysDictData2.setDictType("sys_ys"); + sysDictData2.setDictLabel(center); + List sysDictData3 = sysDictDataMapper.selectDictDataList(sysDictData2); + String dictValue1 = sysDictData3.get(0).getDictValue(); + BigDecimal bigDecimal1 = new BigDecimal(dictValue1); + + if (centerValue1.compareTo(BigDecimal.ZERO) != 0 && bigDecimal1.compareTo(BigDecimal.ZERO) != 0) { + result1 = centerValue1.divide(bigDecimal1, new MathContext(2, RoundingMode.HALF_UP)) + .multiply(new BigDecimal("100")); + } else { + result1 = BigDecimal.ZERO; + } + value.add(result1); + } + + Task task = new Task(); + task.setName(center); + task.setRate(result); + task.setValues(value); + return task; + }).collect(Collectors.toList()); + + return lists; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyList(); + } + } + + public List month(List collect, String location) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); + + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + List list = new ArrayList<>(6); + + Map> groupedData = collect.parallelStream() + .collect(Collectors.groupingBy(item -> { + try { + return YearMonth.from(LocalDateTime.parse(item.getCreateTime().toString(), formatter)); + } catch (Exception e) { + return YearMonth.of(1900, 1); + } + })); + + for (int i = 1; i <= 6; i++) { + YearMonth startMonth = currentMonth.minusMonths(i); + YearMonth endMonth = startMonth.plusMonths(1); + + List monthData = new ArrayList<>(); + for (YearMonth month = startMonth; month.isBefore(endMonth); month = month.plusMonths(1)) { + monthData.addAll(groupedData.getOrDefault(month, Collections.emptyList())); + } + + if (monthData.isEmpty()) { + list.add(BigDecimal.ZERO); + } else { + List ck = ck(monthData, location); + Object o = ck.get(0); + list.add(convertToBigDecimal(o)); + } + } + + return list; + } + + private BigDecimal convertToBigDecimal(Object o) { + if (o instanceof BigDecimal) { + return (BigDecimal) o; + } else if (o instanceof Number) { + return new BigDecimal(o.toString()); + } else if (o instanceof String) { + try { + return new BigDecimal((String) o); + } catch (NumberFormatException e) { + System.err.println("Invalid number format: " + o); + return BigDecimal.ZERO; + } + } else { + System.err.println("Unsupported object type: " + (o != null ? o.getClass() : "null")); + return BigDecimal.ZERO; + } + } + + @GetMapping("/Outbound") + @Log(title = "各仓本月出库分布(万元)") + public Map Outbound() { + YearMonth currentMonth = YearMonth.from(LocalDateTime.now()); + List filteredList = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()).parallelStream() + .filter(f -> { + Date createTimeDate = f.getCreateTime(); + return createTimeDate != null && YearMonth.from(createTimeDate.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime()).equals(currentMonth); + }) + .collect(Collectors.toList()); + + Map> groupedByStorage = filteredList.parallelStream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getStorageId)); + if(ObjectUtils.isEmpty(groupedByStorage)){ + Map map = new LinkedHashMap<>(); + map.put("东区维修中心",0); + map.put("西区维修中心",0); + map.put("南区维修中心",0); + map.put("仓储队",0); + return map; + }else{ + return groupedByStorage.entrySet().parallelStream() + .collect(Collectors.toMap( + entry -> { + TckOrderdetailBak bak = new TckOrderdetailBak(); + bak.setStorageId(entry.getKey()); + List list = tckOrderdetailBakMapper.selectTckOrderdetailBakList(bak); + return list.isEmpty() ? "Unknown" : list.get(0).getStorageShortName(); + }, + entry -> calculateTotalMoneys(entry.getValue()), + (v1, v2) -> v1, + HashMap::new + )); + } + + + } + + @GetMapping("/Outbound/other") + @Log(title = "各仓本月出库分布(万元)") + public Map Outbound1() { + YearMonth currentMonth = YearMonth.from(LocalDateTime.now()); + List filteredList = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()).parallelStream() + .filter(f -> { + // 添加判空处理 + String levelType = f != null ? f.getLevelType() : null; + if (levelType != null && !levelType.equals("1")) { + return false; // 如果 levelType 为 "1",则过滤掉 + } + + Date createTimeDate = f != null ? f.getCreateTime() : null; + return createTimeDate != null && YearMonth.from(createTimeDate.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime()).equals(currentMonth); + }) + .collect(Collectors.toList()); + + Map> groupedByStorage = filteredList.parallelStream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getStorageId)); + if(ObjectUtils.isEmpty(groupedByStorage)){ + Map map = new LinkedHashMap<>(); + map.put("东区维修中心",0); + map.put("西区维修中心",0); + map.put("南区维修中心",0); + map.put("仓储队",0); + return map; + }else{ + return groupedByStorage.entrySet().parallelStream() + .collect(Collectors.toMap( + entry -> { + TckOrderdetailBak bak = new TckOrderdetailBak(); + bak.setStorageId(entry.getKey()); + List list = tckOrderdetailBakMapper.selectTckOrderdetailBakList(bak); + return list.isEmpty() ? "Unknown" : list.get(0).getStorageShortName(); + }, + entry -> calculateTotalMoneys(entry.getValue()), + (v1, v2) -> v1, + HashMap::new + )); + } + + + } + + @GetMapping("/Outbound/global") + @Log(title = "各仓本月出库分布(万元)") + public Map Outbound2() { + YearMonth currentMonth = YearMonth.from(LocalDateTime.now()); + List filteredList = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()).parallelStream() + .filter(f -> { + // 添加判空处理 + String levelType = f != null ? f.getLevelType() : null; + if (levelType != null && levelType.equals("1")) { + return false; // 如果 levelType 为 "1",则过滤掉 + } + + Date createTimeDate = f != null ? f.getCreateTime() : null; + return createTimeDate != null && YearMonth.from(createTimeDate.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime()).equals(currentMonth); + }) + .collect(Collectors.toList()); + + Map> groupedByStorage = filteredList.parallelStream() + .collect(Collectors.groupingBy(TckOrderdetailBak::getStorageId)); + if(ObjectUtils.isEmpty(groupedByStorage)){ + Map map = new LinkedHashMap<>(); + map.put("东区维修中心",0); + map.put("西区维修中心",0); + map.put("南区维修中心",0); + map.put("仓储队",0); + return map; + }else{ + return groupedByStorage.entrySet().parallelStream() + .collect(Collectors.toMap( + entry -> { + TckOrderdetailBak bak = new TckOrderdetailBak(); + bak.setStorageId(entry.getKey()); + List list = tckOrderdetailBakMapper.selectTckOrderdetailBakList(bak); + return list.isEmpty() ? "Unknown" : list.get(0).getStorageShortName(); + }, + entry -> calculateTotalMoneys(entry.getValue()), + (v1, v2) -> v1, + HashMap::new + )); + } + + + } + + @GetMapping("/CLMoney") + @Log(title = "五大维修中心本月采领金额(万元)") + public Map CLMoney() { + YearMonth currentMonth = YearMonth.from(LocalDateTime.now()); + + CompletableFuture> filteredListFuture = CompletableFuture.supplyAsync(() -> + tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()).parallelStream() + .filter(f -> isCurrentMonth(f.getCreateTime(), currentMonth)) + .collect(Collectors.toList()) + ); + + CompletableFuture> filteredList1Future = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()).parallelStream() + .filter(f -> isCurrentMonth(f.getCreateTime(), currentMonth)) + .collect(Collectors.toList()) + ); + + + try { + List filteredList = filteredListFuture.get(); + List filteredList1 = filteredList1Future.get(); + + Map map = new HashMap<>(); + List centers = Arrays.asList("东区维修中心", "西区维修中心", "南区维修中心", "仓储队"); + + centers.parallelStream().filter(Objects::nonNull).forEach(center -> { + if(ObjectUtils.isNotEmpty(center)) { + List list = new ArrayList<>(); + list.add(filteredList.isEmpty() ? 0 : rk(filteredList, center)); + list.add(filteredList1.isEmpty() ? 0 : ck(filteredList1, center)); + map.put(center, list); + }}); + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/CLMoney/other") + @Log(title = "五大维修中心本月采领金额(万元)") + public Map CLMoney1() { + YearMonth currentMonth = YearMonth.from(LocalDateTime.now()); + + CompletableFuture> filteredListFuture = CompletableFuture.supplyAsync(() -> + tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()).parallelStream() + .filter(f -> { + // leveltype 判空和条件判断 + if (f.getLevelType() == null || f.getLevelType().equals("1")) { + return false; // leveltype 为 null 或不为 "1" 时,过滤掉 + } + + // createTime 条件判断 + return isCurrentMonth(f.getCreateTime(), currentMonth); + }) + .collect(Collectors.toList()) + ); + + CompletableFuture> filteredList1Future = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()).parallelStream() + .filter(f -> { + // leveltype 判空和条件判断 + if (f.getLevelType() == null || f.getLevelType().equals("1")) { + return false; // leveltype 为 null 或不为 "1" 时,过滤掉 + } + + // createTime 条件判断 + return isCurrentMonth(f.getCreateTime(), currentMonth); + }) + .collect(Collectors.toList()) + ); + + + try { + List filteredList = filteredListFuture.get(); + List filteredList1 = filteredList1Future.get(); + + Map map = new HashMap<>(); + List centers = Arrays.asList("东区维修中心", "西区维修中心", "南区维修中心", "仓储队"); + + centers.parallelStream().filter(Objects::nonNull).forEach(center -> { + if(ObjectUtils.isNotEmpty(center)) { + List list = new ArrayList<>(); + list.add(filteredList.isEmpty() ? 0 : rk(filteredList, center)); + list.add(filteredList1.isEmpty() ? 0 : ck(filteredList1, center)); + map.put(center, list); + }}); + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/CLMoney/global") + @Log(title = "五大维修中心本月采领金额(万元)") + public Map CLMoney2() { + YearMonth currentMonth = YearMonth.from(LocalDateTime.now()); + + CompletableFuture> filteredListFuture = CompletableFuture.supplyAsync(() -> + tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()).parallelStream() + .filter(f -> { + // leveltype 判空和条件判断 + if (f.getLevelType() == null || !f.getLevelType().equals("1")) { + return false; // leveltype 为 null 或不为 "1" 时,过滤掉 + } + + // createTime 条件判断 + return isCurrentMonth(f.getCreateTime(), currentMonth); + }) + .collect(Collectors.toList()) + ); + + CompletableFuture> filteredList1Future = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()).parallelStream() + .filter(f -> { + // leveltype 判空和条件判断 + if (f.getLevelType() == null || !f.getLevelType().equals("1")) { + return false; // leveltype 为 null 或不为 "1" 时,过滤掉 + } + + // createTime 条件判断 + return isCurrentMonth(f.getCreateTime(), currentMonth); + }) + .collect(Collectors.toList()) + ); + + try { + List filteredList = filteredListFuture.get(); + List filteredList1 = filteredList1Future.get(); + + Map map = new HashMap<>(); + List centers = Arrays.asList("东区维修中心", "西区维修中心", "南区维修中心", "仓储队"); + + centers.parallelStream().filter(Objects::nonNull).forEach(center -> { + if(ObjectUtils.isNotEmpty(center)) { + List list = new ArrayList<>(); + list.add(filteredList.isEmpty() ? 0 : rk(filteredList, center)); + list.add(filteredList1.isEmpty() ? 0 : ck(filteredList1, center)); + map.put(center, list); + }}); + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + + private BigDecimal calculateTotalMoneys(List list) { + return list.parallelStream() + .map(TckOrderdetailBak::getToMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + } + public List ck(ListfilteredList1,String location){ + List list =new ArrayList<>(); + List dong1 = name(location); + if(dong1.isEmpty()){ + list.add(0); + }else { + List dong2 = filteredList1.stream() + .filter(f -> f.getApplicant() != null) // 筛选 applicant 不为空 + .filter(f -> dong1.contains(f.getApplicant())) // 筛选 applicant 在 dong1 中 + .collect(Collectors.toList()); + if (dong2.isEmpty()) { + list.add(0); + } else { + BigDecimal totalMoney = dong2.stream() + .map(TckOrderdetailBak::getToMoney) // 提取 getMoney 字段 + .filter(java.util.Objects::nonNull) // 排除 null 值 + .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加 + BigDecimal num2 = new BigDecimal("10000"); + totalMoney = totalMoney.divide(num2, 2, RoundingMode.HALF_UP); + list.add(totalMoney); + } + } + return list; + } + private boolean isCurrentMonth(Date date, YearMonth currentMonth) { + return date != null && YearMonth.from(date.toInstant() + .atZone(ZoneId.systemDefault()) + .toLocalDateTime()).equals(currentMonth); + } + public List rk(ListfilteredList,String location){ + List list =new ArrayList<>(); + if(ObjectUtils.isNotEmpty(filteredList)){ + List collect = filteredList.stream().filter(f -> ObjectUtils.isNotEmpty(f.getNeedDept())).collect(Collectors.toList()); + if(ObjectUtils.isNotEmpty(collect)){ + List dong = collect.stream().filter(f -> f.getNeedDept().equals(location)).collect(Collectors.toList()); + if(dong.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney = dong.stream() + .map(TRkWareNoticeTabBak::getTotalMoney) // 提取 getMoney 字段 + .filter(java.util.Objects::nonNull) // 排除 null 值 + .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加 + BigDecimal num2 =new BigDecimal("10000"); + totalMoney = totalMoney.divide(num2, 2, RoundingMode.HALF_UP); + list.add(totalMoney); + } + }else { + list.add(0); + } + }else { + list.add(0); + } + return list; + } + + public List name (String dept){ + SysDept sysDept = sysDeptMapper.selectDeptByName(dept); + List longs = sysDeptMapper.selectDeptId(sysDept.getDeptId()); + System.out.println(longs); + List list = sysUserMapper.selectByDepeId(longs); + return list; + } + + @GetMapping("/tmistockTotal") + @Log(title = "仓库总览") + public CompletableFuture> tmistockTotal() { + LocalDate now = LocalDate.now(); + int currentYear = now.getYear(); + Month currentMonth = now.getMonth(); + + CompletableFuture totalMoneyFuture = CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoney().divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture totalMoneyThisMonthFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.getTotalMoneyForYearMonth(currentYear, currentMonth.getValue()) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture totalMoneyThisMonth1Future = CompletableFuture.supplyAsync(() -> + tRkWareNoticeTabBakMapper.getTotalMoneyForYearMonth(currentYear, currentMonth.getValue()) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture tBaseStoragesSizeFuture = CompletableFuture.supplyAsync(() -> + tBaseStorageMapper.getCount()); + + CompletableFuture totalMoneyThisYearFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.getTotalMoneyForYear(currentYear) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + SysDictData sysDictData = new SysDictData(); + sysDictData.setDictLabel("总预算"); + sysDictData.setDictType("sys_ys"); + String dictValue = sysDictDataMapper.selectDictDataList(sysDictData).get(0).getDictValue(); + + return CompletableFuture.allOf( + totalMoneyFuture, + totalMoneyThisMonthFuture, + totalMoneyThisMonth1Future, + tBaseStoragesSizeFuture, + totalMoneyThisYearFuture + ).thenApply(v -> { + List list = new ArrayList<>(); + try { + list.add(totalMoneyFuture.get()); + list.add(totalMoneyThisMonthFuture.get()); + list.add(totalMoneyThisMonth1Future.get()); + list.add(tBaseStoragesSizeFuture.get()); + list.add(totalMoneyThisYearFuture.get()); + list.add(dictValue); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + return list; + }); + } + + @GetMapping("/tmistockTotal/other") + @Log(title = "仓库总览") + public CompletableFuture> tmistockTotal1() { + LocalDate now = LocalDate.now(); + int currentYear = now.getYear(); + Month currentMonth = now.getMonth(); + + CompletableFuture totalMoneyFuture = CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoney1().divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture totalMoneyThisMonthFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.getTotalMoneyForYearMonth1(currentYear, currentMonth.getValue()) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture totalMoneyThisMonth1Future = CompletableFuture.supplyAsync(() -> + tRkWareNoticeTabBakMapper.getTotalMoneyForYearMonth1(currentYear, currentMonth.getValue()) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture tBaseStoragesSizeFuture = CompletableFuture.supplyAsync(() -> + tBaseStorageMapper.getCount()); + + CompletableFuture totalMoneyThisYearFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.getTotalMoneyForYear1(currentYear) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + SysDictData sysDictData = new SysDictData(); + sysDictData.setDictLabel("总预算"); + sysDictData.setDictType("sys_ys"); + String dictValue = sysDictDataMapper.selectDictDataList(sysDictData).get(0).getDictValue(); + + return CompletableFuture.allOf( + totalMoneyFuture, + totalMoneyThisMonthFuture, + totalMoneyThisMonth1Future, + tBaseStoragesSizeFuture, + totalMoneyThisYearFuture + ).thenApply(v -> { + List list = new ArrayList<>(); + try { + list.add(totalMoneyFuture.get()); + list.add(totalMoneyThisMonthFuture.get()); + list.add(totalMoneyThisMonth1Future.get()); + list.add(tBaseStoragesSizeFuture.get()); + list.add(totalMoneyThisYearFuture.get()); + list.add(dictValue); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + return list; + }); + } + + @GetMapping("/tmistockTotal/global") + @Log(title = "仓库总览") + public CompletableFuture> tmistockTotal2() { + LocalDate now = LocalDate.now(); + int currentYear = now.getYear(); + Month currentMonth = now.getMonth(); + + CompletableFuture totalMoneyFuture = CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoney2().divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture totalMoneyThisMonthFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.getTotalMoneyForYearMonth2(currentYear, currentMonth.getValue()) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture totalMoneyThisMonth1Future = CompletableFuture.supplyAsync(() -> + tRkWareNoticeTabBakMapper.getTotalMoneyForYearMonth2(currentYear, currentMonth.getValue()) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + + CompletableFuture tBaseStoragesSizeFuture = CompletableFuture.supplyAsync(() -> + tBaseStorageMapper.getCount()); + + CompletableFuture totalMoneyThisYearFuture = CompletableFuture.supplyAsync(() -> + tckOrderdetailBakMapper.getTotalMoneyForYear2(currentYear) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP)); + SysDictData sysDictData = new SysDictData(); + sysDictData.setDictLabel("总预算"); + sysDictData.setDictType("sys_ys"); + String dictValue = sysDictDataMapper.selectDictDataList(sysDictData).get(0).getDictValue(); + + return CompletableFuture.allOf( + totalMoneyFuture, + totalMoneyThisMonthFuture, + totalMoneyThisMonth1Future, + tBaseStoragesSizeFuture, + totalMoneyThisYearFuture + ).thenApply(v -> { + List list = new ArrayList<>(); + try { + list.add(totalMoneyFuture.get()); + list.add(totalMoneyThisMonthFuture.get()); + list.add(totalMoneyThisMonth1Future.get()); + list.add(tBaseStoragesSizeFuture.get()); + list.add(totalMoneyThisYearFuture.get()); + list.add(dictValue); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + return list; + }); + } + + @GetMapping("/sendTotal") + @Log(title = "本月各仓出入库金额(万元)") + public Map> sendTotal() { + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + + CompletableFuture> ckFuture = CompletableFuture.supplyAsync(() -> { + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + return tckOrderdetailBaks.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) + .collect(Collectors.toList()); + }); + + CompletableFuture> rkFuture = CompletableFuture.supplyAsync(() -> { + List tRkWareNoticeTabBaks = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + return tRkWareNoticeTabBaks.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) + .collect(Collectors.toList()); + }); + + try { + List ck = ckFuture.get(); + List rk = rkFuture.get(); + + Set storageIds = new HashSet<>(); + ck.forEach(t -> { + String storageId = t.getStorageId(); + if (!StringUtils.isEmpty(storageId)) { // 使用 StringUtils.isEmpty 判断空字符串 + storageIds.add(storageId); + } + }); + rk.forEach(t ->{ + String storageId = t.getStorageId(); + if (!StringUtils.isEmpty(storageId)) { // 使用 StringUtils.isEmpty 判断空字符串 + storageIds.add(storageId); + } + }); + + Map> map = new ConcurrentHashMap<>(); + if(ObjectUtils.isEmpty(storageIds)){ + List list =new ArrayList(); + list.add(0); + list.add(0); + map.put("东区维修中心", list); + map.put("西区维修中心", list); + map.put("南区维修中心", list); + map.put("仓储队", list); + }else{ + for(String t:storageIds){ + if (ObjectUtils.isNotEmpty(t)){ + List list = new ArrayList<>(); + String storageShortName; + List collect1 = ck.stream().filter(f -> ObjectUtils.isNotEmpty(f.getStorageId()) && f.getStorageId().equals(t)).collect(Collectors.toList()); + if(collect1.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney = collect1.parallelStream() + .map(f -> f.getToMoney() == null ? BigDecimal.ZERO : f.getToMoney()) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + if(ObjectUtils.isEmpty(totalMoney)){ + System.out.println(totalMoney); + System.out.println("2222222"); + } + list.add(totalMoney); + } + List collect = rk.stream().filter(f -> ObjectUtils.isNotEmpty(f.getStorageId()) && f.getStorageId().equals(t)).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney1 = collect.parallelStream() + .map(f -> ObjectUtils.isEmpty(f.getTotalMoney()) ? BigDecimal.ZERO : f.getTotalMoney()) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + if(!ObjectUtils.isEmpty(totalMoney1)){ + System.out.println(totalMoney1); + } + list.add(totalMoney1); + } + + +// storageShortName = ck.stream() +// .filter(f -> f.getStorageId().equals(t)) +// .findFirst() +// .map(TckOrderdetailBak::getStorageShortName) +// .orElseGet(() -> rk.stream() +// .filter(f -> f.getStorageId().equals(t)) +// .findFirst() +// .map(TRkWareNoticeTabBak::getStorageShortName) +// .orElse("Unknown")); + TBaseStorage tBaseStorage = new TBaseStorage(); + tBaseStorage.setStorageId(t); + storageShortName = tBaseStorageMapper.selectTBaseStorageList(tBaseStorage).get(0).getStorageShortName(); + map.put(storageShortName, list); + }else{ + + + } + }; + } + + + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/sendTotal/other") + @Log(title = "本月各仓出入库金额(万元)") + public Map> sendTotal1() { + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + +// CompletableFuture> ckFuture = CompletableFuture.supplyAsync(() -> { +// List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); +// return tckOrderdetailBaks.parallelStream() +// .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) +// .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) +// .collect(Collectors.toList()); +// }); + CompletableFuture> ckFuture = CompletableFuture.supplyAsync(() -> { + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + return tckOrderdetailBaks.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getLevelType()) && !f.getLevelType().equals("1"))//leveltype判空和条件 + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) + .collect(Collectors.toList()); + }); + + CompletableFuture> rkFuture = CompletableFuture.supplyAsync(() -> { + List tRkWareNoticeTabBaks = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + return tRkWareNoticeTabBaks.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getLevelType()) && !f.getLevelType().equals("1"))//leveltype判空和条件 + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) + .collect(Collectors.toList()); + }); + + try { + List ck = ckFuture.get(); + List rk = rkFuture.get(); + + Set storageIds = new HashSet<>(); + ck.forEach(t -> { + String storageId = t.getStorageId(); + if (!StringUtils.isEmpty(storageId)) { // 使用 StringUtils.isEmpty 判断空字符串 + storageIds.add(storageId); + } + }); + rk.forEach(t ->{ + String storageId = t.getStorageId(); + if (!StringUtils.isEmpty(storageId)) { // 使用 StringUtils.isEmpty 判断空字符串 + storageIds.add(storageId); + } + }); + + Map> map = new ConcurrentHashMap<>(); + if(ObjectUtils.isEmpty(storageIds)){ + List list =new ArrayList(); + list.add(0); + list.add(0); + map.put("东区维修中心", list); + map.put("西区维修中心", list); + map.put("南区维修中心", list); + map.put("仓储队", list); + }else{ + for(String t:storageIds){ + if (ObjectUtils.isNotEmpty(t)){ + List list = new ArrayList<>(); + String storageShortName; + List collect1 = ck.stream().filter(f -> ObjectUtils.isNotEmpty(f.getStorageId()) && f.getStorageId().equals(t)).collect(Collectors.toList()); + if(collect1.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney = collect1.parallelStream() + .map(f -> f.getToMoney() == null ? BigDecimal.ZERO : f.getToMoney()) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + if(ObjectUtils.isEmpty(totalMoney)){ + System.out.println(totalMoney); + System.out.println("2222222"); + } + list.add(totalMoney); + } + List collect = rk.stream().filter(f -> ObjectUtils.isNotEmpty(f.getStorageId()) && f.getStorageId().equals(t)).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney1 = collect.parallelStream() + .map(f -> ObjectUtils.isEmpty(f.getTotalMoney()) ? BigDecimal.ZERO : f.getTotalMoney()) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + if(!ObjectUtils.isEmpty(totalMoney1)){ + System.out.println(totalMoney1); + } + list.add(totalMoney1); + } + + +// storageShortName = ck.stream() +// .filter(f -> f.getStorageId().equals(t)) +// .findFirst() +// .map(TckOrderdetailBak::getStorageShortName) +// .orElseGet(() -> rk.stream() +// .filter(f -> f.getStorageId().equals(t)) +// .findFirst() +// .map(TRkWareNoticeTabBak::getStorageShortName) +// .orElse("Unknown")); + TBaseStorage tBaseStorage = new TBaseStorage(); + tBaseStorage.setStorageId(t); + storageShortName = tBaseStorageMapper.selectTBaseStorageList(tBaseStorage).get(0).getStorageShortName(); + map.put(storageShortName, list); + }else{ + + + } + }; + } + + + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/sendTotal/global") + @Log(title = "本月各仓出入库金额(万元)") + public Map> sendTotal2() { + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + +// CompletableFuture> ckFuture = CompletableFuture.supplyAsync(() -> { +// List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); +// return tckOrderdetailBaks.parallelStream() +// .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) +// .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) +// .collect(Collectors.toList()); +// }); + CompletableFuture> ckFuture = CompletableFuture.supplyAsync(() -> { + List tckOrderdetailBaks = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + return tckOrderdetailBaks.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getLevelType()) && f.getLevelType().equals("1"))//leveltype判空和条件 + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) + .collect(Collectors.toList()); + }); + + CompletableFuture> rkFuture = CompletableFuture.supplyAsync(() -> { + List tRkWareNoticeTabBaks = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakList(new TRkWareNoticeTabBak()); + return tRkWareNoticeTabBaks.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getLevelType()) && f.getLevelType().equals("1"))//leveltype判空和条件 + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .filter(f -> YearMonth.from(f.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()).equals(currentMonth)) + .collect(Collectors.toList()); + }); + + try { + List ck = ckFuture.get(); + List rk = rkFuture.get(); + + Set storageIds = new HashSet<>(); + ck.forEach(t -> { + String storageId = t.getStorageId(); + if (!StringUtils.isEmpty(storageId)) { // 使用 StringUtils.isEmpty 判断空字符串 + storageIds.add(storageId); + } + }); + rk.forEach(t ->{ + String storageId = t.getStorageId(); + if (!StringUtils.isEmpty(storageId)) { // 使用 StringUtils.isEmpty 判断空字符串 + storageIds.add(storageId); + } + }); + + Map> map = new ConcurrentHashMap<>(); + if(ObjectUtils.isEmpty(storageIds)){ + List list =new ArrayList(); + list.add(0); + list.add(0); + map.put("东区维修中心", list); + map.put("西区维修中心", list); + map.put("南区维修中心", list); + map.put("仓储队", list); + }else{ + for(String t:storageIds){ + if (ObjectUtils.isNotEmpty(t)){ + List list = new ArrayList<>(); + String storageShortName; + List collect1 = ck.stream().filter(f -> ObjectUtils.isNotEmpty(f.getStorageId()) && f.getStorageId().equals(t)).collect(Collectors.toList()); + if(collect1.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney = collect1.parallelStream() + .map(f -> f.getToMoney() == null ? BigDecimal.ZERO : f.getToMoney()) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + if(ObjectUtils.isEmpty(totalMoney)){ + System.out.println(totalMoney); + System.out.println("2222222"); + } + list.add(totalMoney); + } + List collect = rk.stream().filter(f -> ObjectUtils.isNotEmpty(f.getStorageId()) && f.getStorageId().equals(t)).collect(Collectors.toList()); + if(collect.isEmpty()){ + list.add(0); + }else{ + BigDecimal totalMoney1 = collect.parallelStream() + .map(f -> ObjectUtils.isEmpty(f.getTotalMoney()) ? BigDecimal.ZERO : f.getTotalMoney()) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + if(!ObjectUtils.isEmpty(totalMoney1)){ + System.out.println(totalMoney1); + } + list.add(totalMoney1); + } + + +// storageShortName = ck.stream() +// .filter(f -> f.getStorageId().equals(t)) +// .findFirst() +// .map(TckOrderdetailBak::getStorageShortName) +// .orElseGet(() -> rk.stream() +// .filter(f -> f.getStorageId().equals(t)) +// .findFirst() +// .map(TRkWareNoticeTabBak::getStorageShortName) +// .orElse("Unknown")); + TBaseStorage tBaseStorage = new TBaseStorage(); + tBaseStorage.setStorageId(t); + storageShortName = tBaseStorageMapper.selectTBaseStorageList(tBaseStorage).get(0).getStorageShortName(); + map.put(storageShortName, list); + }else{ + + + } + }; + } + + + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/tCk") + @Log(title = "近6个月出库金额(万元)") + public List tck() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + + List tCkOrderdetails = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + + List collect = tCkOrderdetails.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime())) + .collect(Collectors.toList()); + + return IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth endMonth = currentMonth; + YearMonth startMonth = endMonth.minusMonths(i); + YearMonth yearMonth = startMonth.plusMonths(1); + + BigDecimal totalMoney = collect.parallelStream() + .filter(f -> { + try { + LocalDateTime createTime = LocalDateTime.parse(f.getCreateTime().toString(), formatter); + YearMonth wareMonth = YearMonth.from(createTime); + return !wareMonth.isBefore(startMonth) && wareMonth.isBefore(yearMonth); + } catch (Exception e) { + System.err.println("Error parsing date: " + e.getMessage()); + return false; + } + }) + .map(TckOrderdetailBak::getToMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + + return totalMoney; + }) + .collect(Collectors.toList()); + } + + @GetMapping("/tCk/other") + @Log(title = "近6个月出库金额(万元)") + public List tck1() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + + List tCkOrderdetails = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + + List collect1 = tCkOrderdetails.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime()) ) + .collect(Collectors.toList()); + + + List collect = (collect1 != null && !collect1.isEmpty()) ? + collect1.stream() + .filter(f -> f != null && f.getLevelType() != null && !f.getLevelType().equals("1")) + .collect(Collectors.toList()) : + Collections.emptyList(); + return IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth endMonth = currentMonth; + YearMonth startMonth = endMonth.minusMonths(i); + YearMonth yearMonth = startMonth.plusMonths(1); + + BigDecimal totalMoney = collect.parallelStream() + .filter(f -> { + try { + LocalDateTime createTime = LocalDateTime.parse(f.getCreateTime().toString(), formatter); + YearMonth wareMonth = YearMonth.from(createTime); + return !wareMonth.isBefore(startMonth) && wareMonth.isBefore(yearMonth); + } catch (Exception e) { + System.err.println("Error parsing date: " + e.getMessage()); + return false; + } + }) + .map(TckOrderdetailBak::getToMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + + return totalMoney; + }) + .collect(Collectors.toList()); + } + + @GetMapping("/tCk/global") + @Log(title = "近6个月出库金额(万元)") + public List tck2() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH); + LocalDate now = LocalDate.now(); + YearMonth currentMonth = YearMonth.from(now); + + List tCkOrderdetails = tckOrderdetailBakMapper.selectTckOrderdetailBakList(new TckOrderdetailBak()); + + List collect1 = tCkOrderdetails.parallelStream() + .filter(f -> ObjectUtils.isNotEmpty(f.getCreateTime()) ) + .collect(Collectors.toList()); + List collect = (collect1 != null && !collect1.isEmpty()) ? + collect1.stream() + .filter(f -> f != null && f.getLevelType() != null && f.getLevelType().equals("1")) + .collect(Collectors.toList()) : + Collections.emptyList(); + return IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth endMonth = currentMonth; + YearMonth startMonth = endMonth.minusMonths(i); + YearMonth yearMonth = startMonth.plusMonths(1); + + BigDecimal totalMoney = collect.parallelStream() + .filter(f -> { + try { + LocalDateTime createTime = LocalDateTime.parse(f.getCreateTime().toString(), formatter); + YearMonth wareMonth = YearMonth.from(createTime); + return !wareMonth.isBefore(startMonth) && wareMonth.isBefore(yearMonth); + } catch (Exception e) { + System.err.println("Error parsing date: " + e.getMessage()); + return false; + } + }) + .map(TckOrderdetailBak::getToMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add) + .divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + + return totalMoney; + }) + .collect(Collectors.toList()); + } + + + + //库存列表 + @GetMapping("/tmistock") + @Log(title = "库存趋势(万元)") + public CompletableFuture> tmistock() { + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + return CompletableFuture.supplyAsync(() -> + IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth startMonth = currentMonth.minusMonths(i); + YearMonth endMonth = startMonth.plusMonths(1); + String startDate = startMonth.atDay(1).format(formatter); + String endDate = endMonth.atDay(1).format(formatter); + return CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoneyForMonth(startDate, endDate) + ); + }) + .collect(Collectors.toList()) + ).thenCompose(futures -> + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .map(total -> total.divide(BigDecimal.valueOf(10000),2, RoundingMode.HALF_UP)) // 转换为万元 + .collect(Collectors.toList()) + ) + ); + } + + @GetMapping("/tmistock/other") + @Log(title = "库存趋势(万元)") + public CompletableFuture> tmistock1() { + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + return CompletableFuture.supplyAsync(() -> + IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth startMonth = currentMonth.minusMonths(i); + YearMonth endMonth = startMonth.plusMonths(1); + String startDate = startMonth.atDay(1).format(formatter); + String endDate = endMonth.atDay(1).format(formatter); + return CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoneyForMonth3(startDate, endDate) + ); + }) + .collect(Collectors.toList()) + ).thenCompose(futures -> + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .map(total -> total.divide(BigDecimal.valueOf(10000),2, RoundingMode.HALF_UP)) // 转换为万元 + .collect(Collectors.toList()) + ) + ); + } + + @GetMapping("/tmistock/global") + @Log(title = "库存趋势(万元)") + public CompletableFuture> tmistock2() { + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + return CompletableFuture.supplyAsync(() -> + IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth startMonth = currentMonth.minusMonths(i); + YearMonth endMonth = startMonth.plusMonths(1); + String startDate = startMonth.atDay(1).format(formatter); + String endDate = endMonth.atDay(1).format(formatter); + return CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoneyForMonth1(startDate, endDate) + ); + }) + .collect(Collectors.toList()) + ).thenCompose(futures -> + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .map(total -> total.divide(BigDecimal.valueOf(10000),2, RoundingMode.HALF_UP)) // 转换为万元 + .collect(Collectors.toList()) + ) + ); + } + + + @GetMapping("/tmistockSix") + @Log(title = "近6个月各级库存趋势(万元)") + public CompletableFuture> tmistockSix() { + YearMonth currentMonth = YearMonth.now(); + + return CompletableFuture.supplyAsync(() -> + IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth targetMonth = currentMonth.minusMonths(i); + return CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoneyForSpecificMonth(targetMonth.getYear(), targetMonth.getMonthValue()) + ); + }) + .collect(Collectors.toList()) + ).thenCompose(futures -> + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .map(total -> total.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP)) // 转换为万元 + .collect(Collectors.toList()) + ) + ); + } + + @GetMapping("/tmistockSix1") + @Log(title = "近6个月1级库存趋势(万元)") + public CompletableFuture> tmistockSix1() { + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + List>> list = new ArrayList<>(); + return CompletableFuture.supplyAsync(() -> + IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth startMonth = currentMonth.minusMonths(i); + YearMonth endMonth = startMonth.plusMonths(1); + String startDate = startMonth.atDay(1).format(formatter); + String endDate = endMonth.atDay(1).format(formatter); + return CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoneyForMonth1(startDate, endDate) + ); + }) + .collect(Collectors.toList()) + ).thenCompose(futures -> + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .map(total -> total.divide(BigDecimal.valueOf(10000),2, RoundingMode.HALF_UP)) // 转换为万元 + .collect(Collectors.toList()) + ) + ); + + } + + @GetMapping("/tmistockSix2") + @Log(title = "近6个月2级库存趋势(万元)") + public CompletableFuture> tmistockSix2() { + YearMonth currentMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + List>> list = new ArrayList<>(); + return CompletableFuture.supplyAsync(() -> + IntStream.rangeClosed(1, 6) + .mapToObj(i -> { + YearMonth startMonth = currentMonth.minusMonths(i); + YearMonth endMonth = startMonth.plusMonths(1); + String startDate = startMonth.atDay(1).format(formatter); + String endDate = endMonth.atDay(1).format(formatter); + return CompletableFuture.supplyAsync(() -> + tMiStockMapper.getTotalMoneyForMonth2(startDate, endDate) + ); + }) + .collect(Collectors.toList()) + ).thenCompose(futures -> + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .map(total -> total.divide(BigDecimal.valueOf(10000),2, RoundingMode.HALF_UP)) // 转换为万元 + .collect(Collectors.toList()) + ) + ); + + } + + private BigDecimal calculateTotalMoney(List stocks) { + if (stocks == null || stocks.isEmpty()) { + return BigDecimal.ZERO; + } + + BigDecimal totalMoneys = stocks.parallelStream() + .filter(Objects::nonNull) + .map(tmiStock -> Optional.ofNullable(tmiStock.getTotalMoney()).orElse(BigDecimal.ZERO)) + .reduce(BigDecimal::add) + .orElse(BigDecimal.ZERO); + + return totalMoneys.divide(new BigDecimal("10000"), 2, RoundingMode.HALF_UP); + } + + @GetMapping("/tmistockPie") + @Log(title = "全年存货总值") + public Map tmistockPie() { + int currentYear = Year.now().getValue(); + + CompletableFuture> groupFuture = CompletableFuture.supplyAsync(() -> + tMiStockMapper.selectGroupForYear()); + + try { + List list = groupFuture.get(); + Map map = new HashMap<>(); + + if (!list.isEmpty()) { + list.parallelStream().forEach(tMiStock -> { + TMiStock tMiStock1 = new TMiStock(); + tMiStock1.setStorageId(tMiStock.getStorageId()); + List tMiStocks = tMiStockMapper.selectTMiStockListForYear(tMiStock1); + + BigDecimal totalMoney = calculateTotalMoneyss(tMiStocks); + if(totalMoney.compareTo(BigDecimal.ZERO) == 0 ){ + map.put(tMiStock.getStorageShortName(), totalMoney); + }else{ + BigDecimal divide = totalMoney.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP); + map.put(tMiStock.getStorageShortName(), divide); + } + + }); + } + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/tmistockPie/other") + @Log(title = "全年存货总值") + public Map tmistockPieOther() { + int currentYear = Year.now().getValue(); + + CompletableFuture> groupFuture = CompletableFuture.supplyAsync(() -> + tMiStockMapper.selectGroupForYear()); + + try { + List list = groupFuture.get(); + Map map = new HashMap<>(); + + if (!list.isEmpty()) { + list.parallelStream().forEach(tMiStock -> { + TMiStock tMiStock1 = new TMiStock(); + tMiStock1.setStorageId(tMiStock.getStorageId()); + List tMiStocks = tMiStockMapper.selectTMiStockListForYear(tMiStock1); + List collect = tMiStocks.stream().filter(t -> !t.getLevelType().equals("1")).collect(Collectors.toList()); + BigDecimal totalMoney = calculateTotalMoneyss(collect); + if(totalMoney.compareTo(BigDecimal.ZERO) == 0 ){ + map.put(tMiStock.getStorageShortName(), totalMoney); + }else{ + BigDecimal divide = totalMoney.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP); + map.put(tMiStock.getStorageShortName(), divide); + } + + }); + } + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + @GetMapping("/tmistockPie/global") + @Log(title = "全年存货总值") + public Map tmistockPieOtherGlobal() { + int currentYear = Year.now().getValue(); + + CompletableFuture> groupFuture = CompletableFuture.supplyAsync(() -> + tMiStockMapper.selectGroupForYear()); + + try { + List list = groupFuture.get(); + Map map = new HashMap<>(); + + if (!list.isEmpty()) { + list.parallelStream().forEach(tMiStock -> { + TMiStock tMiStock1 = new TMiStock(); + tMiStock1.setStorageId(tMiStock.getStorageId()); + List tMiStocks = tMiStockMapper.selectTMiStockListForYear(tMiStock1); + List collect = tMiStocks.stream().filter(t -> t.getLevelType().equals("1")).collect(Collectors.toList()); + BigDecimal totalMoney = calculateTotalMoneyss(collect); + if(totalMoney.compareTo(BigDecimal.ZERO) == 0 ){ + map.put(tMiStock.getStorageShortName(), totalMoney); + }else{ + BigDecimal divide = totalMoney.divide(BigDecimal.valueOf(10000), 2, RoundingMode.HALF_UP); + map.put(tMiStock.getStorageShortName(), divide); + } + + }); + } + + return map; + } catch (Exception e) { + e.printStackTrace(); + return Collections.emptyMap(); + } + } + + private BigDecimal calculateTotalMoneyss(List tMiStocks) { + return tMiStocks.stream() + .map(TMiStock::getTotalMoney) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } + + + /** + * 出库入库任务表格 + * + * @return + */ + @GetMapping("/quest") + public List quest() { + return largeScreenService.quest(); + } + + + //折线图 + @GetMapping("/line") + public List> line() { + return largeScreenService.line(); + + } + + + /** + * 仓位统计 + * + * @return + */ + @GetMapping("/pieChart") + public Map pieChart() { + return largeScreenService.pieChart(); + } + + /** + * 设备状态 + */ + @GetMapping("/equipmentStatu") + public List equipmentStatu() { + return largeScreenService.equipmentStatu(); + } + + + @GetMapping("/police") + public List> police() { + return largeScreenService.police(); + } + + /** + * 货值分布 + * + * @return + */ + @GetMapping("/distribution") + public List> distribution() { + return largeScreenService.distribution(); + } + + @GetMapping("/child") + public List> child() { + return largeScreenService.child(); + } + + /** + * 首页报警数据 + * + * @return + */ + @GetMapping("/alarmData") + public Map alarmData() { + return largeScreenService.alarmData(); + } + + + @GetMapping("/tasks/{location}") + public AjaxResult tasks(@PathVariable("location") String location) { + final String url = "https://172.18.29.101/rcs/rtas/api/robot/controller/task/submit"; + ObjectMapper objectMapper = new ObjectMapper(); + + // 构建请求体 + Map taskData = new HashMap<>(); + List> targetRoute = new ArrayList<>(); + Map site1 = new HashMap<>(); + site1.put("type", "SITE"); + site1.put("code", location); + targetRoute.add(site1); + + Map site2 = new HashMap<>(); + site2.put("type", "SITE"); + + if (location.equals("111")) { + site2.put("code", "222"); + targetRoute.add(site2); + } else if (location.equals("222")) { + site2.put("code", "111"); + targetRoute.add(site2); + } + + taskData.put("targetRoute", targetRoute); + taskData.put("taskType", "PF-LMR-COMMON"); + taskData.put("deadline", ""); + taskData.put("initPriority", 1); + taskData.put("extra", new HashMap<>()); + taskData.put("interrupt", ""); + taskData.put("groupCode", ""); + taskData.put("robotType", ""); + taskData.put("robotTaskCode", ""); + + String requestBody = ""; + try { + requestBody = objectMapper.writeValueAsString(taskData); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return AjaxResult.error("JSON processing failed"); + } + + try (CloseableHttpClient httpClient = createHttpClient()) { + HttpPost httpPost = new HttpPost(url); + httpPost.setHeader("Accept", "application/json"); + httpPost.setHeader("Content-type", "application/json"); + + + // 生成一个类似于给定字符串的随机字符串 + String hexChars = "0123456789abcdef"; // 十六进制字符集 + int len = 32; // 与给定字符串相同的长度 + StringBuilder sb = new StringBuilder(len); + SecureRandom random = new SecureRandom(); + + for (int i = 0; i < len; i++) { + int index = random.nextInt(hexChars.length()); + sb.append(hexChars.charAt(index)); + } + + String randomHexString = sb.toString(); + + + //生成id + httpPost.setHeader("X-Lr-Request-Id", randomHexString); + + + /*httpPost.setHeader("Authorization", "Bearer 7a9623b5ad554ab49fbc42a270e620cb");*/ + + httpPost.setEntity(new StringEntity(requestBody)); + + HttpResponse response = httpClient.execute(httpPost); + String responseString = EntityUtils.toString(response.getEntity(), "UTF-8"); + + return AjaxResult.success(responseString); + } catch (Exception e) { + e.printStackTrace(); + return AjaxResult.error("Failed to send POST request"); + } + } + + + private SSLContext createTrustAllSslContext() throws Exception { + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } + }; + + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new SecureRandom()); + return sslContext; + } + + + private CloseableHttpClient createHttpClient() throws Exception { + return HttpClients.custom() + .setSslcontext(createTrustAllSslContext()) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + } + + private final ObjectMapper objectMapper = new ObjectMapper(); + + + @Log(title = "入库过账", businessType = BusinessType.OTHER) + @PostMapping(value = "/accountIntoOrder") + @Transactional(rollbackFor = Exception.class) + public AjaxResult sendIwms(@RequestBody JSONObject jsonObject) { + /* RLock lock = redissonClient.getLock("sendIwmsLock"); // 创建锁对象*/ + /*try { + // 尝试获取锁,等待最多10秒,锁自动释放时间30秒 + if (!lock.tryLock(10, 30, TimeUnit.SECONDS)) { + return new AjaxResult(99, "系统繁忙,请稍后再试", null); + }*/ + + + logger.info("接收到callback:{}",jsonObject.getJSONArray("data").toString()); + + JSONArray dataArray = jsonObject.getJSONArray("data"); + + for (int i = 0; i < dataArray.size(); i++) { + JSONObject item = dataArray.getJSONObject(i); + //仓位号 + String binCode = item.getStr("binCode"); + //物料编码 + String matCode = item.getStr("matCode"); + //数量 + double matQty = item.getDouble("matQty"); + //单位 + String matUnit = item.getStr("matUnit"); + //明细单号 + String orderItem = item.getStr("orderItem"); + //明细子需求编号 + String orderKeyThird = item.getStr("orderKeyThird"); + //通知单号 + String orderNum = item.getStr("orderNum"); + //入库类型 + String orderType = item.getStr("orderType"); + // 申请人 +// String username = item.getStr("username"); + //仓库 + String whCode = item.getStr("whCode"); +// //需求人 +// String needPerson = item.getStr("needPerson"); +// //需求人联系方式 +// String needTel = item.getStr("needTel"); +// //操作人 +// String createBy = item.getStr("createBy"); + if ("RZ01".equalsIgnoreCase(whCode)) { + whCode = "FJQR01"; + } + + //容器号 + String traceCode = item.getStr("traceCode"); + // 处理这些数据,例如保存到数据库或进行其他业务逻辑 + + //入库通知单和明细 + TRkWareNotice wareNotice = tRkWareNoticeService.selectTRkWareNoticeById(orderNum); + if (wareNotice == null) { + return new AjaxResult(99, "未查询出数据", null); + } + List tabList = wareNotice.getTRkWareNoticeTabList(); + + + //确认上架数据组装 + TRkWareNoticeTabUpdate update = new TRkWareNoticeTabUpdate(); + update.setCtlNo(traceCode); + update.setId(wareNotice.getId()); + update.setNoticeId(wareNotice.getNoticeId()); + update.setDeliveryId(wareNotice.getDeliveryId()); + update.setStorageId(whCode); + update.setStorageLocation(binCode); + update.setStorageMode("3"); + update.setReceiveNum((int) matQty); + update.setRkMxId(orderItem); + update.setTrkWareNoticeTabList(tabList); + //库位 + update.setFictitious("0"); + //确认收货 + Map map = shelvesConfirm(update); + String success = map.get("success"); + if (StringUtils.isNotBlank(success) && "上架成功".equals(success)) { + return new AjaxResult(0, "过账成功", null); + } + } + return new AjaxResult(99, "失败", null); +// } +// catch (InterruptedException e) { +// Thread.currentThread().interrupt(); +// return new AjaxResult(99, "请求中断", null); +// } finally { +// lock.unlock(); // 释放锁 +// } + } + + @Transactional + public Map shelvesConfirm(TRkWareNoticeTabUpdate params) { + // 返回结果 + Map resultMap = new HashMap<>(); + /*LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(TBaseStorageAreaLocation::getLocationId, params.getStorageLocation()); + List areaLocations = service.selectList(wrapper); + if (areaLocations.isEmpty()) { + throw new RuntimeException("库位号错误"); + }*/ + + //校验托盘容器是否正确 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(TBasePallet::getPalletId, params.getCtlNo()); + List plcs = palletMapper.selectList(wrapper); + if (!plcs.isEmpty()) { + TBasePallet palletChk = plcs.get(0); + if("0".equals(palletChk.getStatus()) || StringUtils.isBlank(palletChk.getStatus())){ + TBasePallet tBasePallet = new TBasePallet(); + tBasePallet.setStatus("1"); + tBasePallet.setId(palletChk.getId()); + tBasePallet.setUpdateTime(new Date()); + palletMapper.updateTBasePallet(tBasePallet); + } + } + + + // 超期呆滞时间获取 + SysConfig sysConfig = new SysConfig(); + sysConfig.setConfigKey("overdue.stagnation"); + List sList = sysConfigMapper.selectConfigList(sysConfig); + + if (sList.size() > 0) { + params.getExtras().put("extraTime", sList.get(0).getConfigValue()); + } else { + params.getExtras().put("extraTime", ""); + } + +// if (StringUtils.isBlank(params.getUserName())) { +// params.setUserName(getUsername()); +// } + + List updateNoticeTabs = new ArrayList(); + List insertTMiStocks = new ArrayList(); + List insertTMiStockFs = new ArrayList(); + + // 判断通知单明细是否存在为完成的 + Boolean allReceive = true; + + String noticeId = ""; + TRkWareNotice tRkWareNotice = null; + List tabList = params.getTrkWareNoticeTabList(); + if (tabList == null || tabList.size() == 0) { + resultMap.put("error", "物料的通知单明细不存在"); + return resultMap; + } + for (TRkWareNoticeTab tRkWareNoticeTab : tabList) { + if (params.getRkMxId().equals(tRkWareNoticeTab.getId())) { + tRkWareNotice = tRkWareNoticeMapper.selectTRkWareNoticeById(tRkWareNoticeTab.getNoticeId()); + + if ("2".equals(tRkWareNotice.getReceivingStatus())) { + resultMap.put("error", "入库通知单已全部收货,请刷新"); + return resultMap; + } + + + // 库位 + String storageLocation = params.getStorageLocation(); + if (ObjectUtils.isEmpty(storageLocation)) { + resultMap.put("error", "库位不能为空"); + return resultMap; + } + + + if ("2".equals(tRkWareNoticeTab.getReceivingStatus())) { + continue; + } + + + // 累计收货数量 + BigDecimal recNum = tRkWareNoticeTab.getRecNum() == null ? BigDecimal.ZERO : tRkWareNoticeTab.getRecNum(); + //累计入库数量 + BigDecimal acceNum = tRkWareNoticeTab.getAcceNum() == null ? BigDecimal.ZERO : tRkWareNoticeTab.getAcceNum(); + // 本次上架数量 + BigDecimal acceNumNew = BigDecimal.valueOf(params.getReceiveNum()); + + if (acceNumNew.compareTo(BigDecimal.ZERO) == 0) { + resultMap.put("error", "物料【" + tRkWareNoticeTab.getGoodsName() + "】的上架数量不能为0"); + return resultMap; + } + + + // 收货状态:全部收货 + String receiveStatus = "2"; + + BigDecimal acceTotalNum = acceNum.add(acceNumNew); + + if (acceTotalNum.compareTo(recNum) < 0) { + /** 部分收货 */ + receiveStatus = "1"; + } + // 设置更新信息 + tRkWareNoticeTab.setReceivingStatus(receiveStatus); + // 本次上架数量 + tRkWareNoticeTab.setAmount(acceNumNew); + // 累计上架数量 + tRkWareNoticeTab.setAcceNum(acceTotalNum); + // 库位 + tRkWareNoticeTab.setStorageLocation(storageLocation); + // 托盘 + tRkWareNoticeTab.setStorageId(params.getStorageId()); + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TBaseStorage::getStorageId, params.getStorageId()); + TBaseStorage storage = tBaseStorageMapper.selectOne(queryWrapper); + tRkWareNoticeTab.setStorageShortName(storage.getStorageShortName()); + tRkWareNoticeTab.setCtl(params.getCtlNo()); + tRkWareNoticeTab.setUpdateTime(new Date()); + updateNoticeTabs.add(tRkWareNoticeTab); + tRkWareNoticeTabMapper.updateTRkWareNoticeTab(tRkWareNoticeTab); + // 入库时间 +// DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss"); + + // 生成库存信息 + if ("0".equals(params.getFictitious())) { + insertTMiStocks.add(makeTMiStock(tRkWareNotice, tRkWareNoticeTab, params)); + } else { + insertTMiStockFs.add(makeTMiStockF(tRkWareNotice, tRkWareNoticeTab, params)); + } + } + } + + + if ("0".equals(params.getFictitious())) { + // 更新库存信息 + if (insertTMiStocks.size() > 0) { + for (TMiStock tMiStock1 : insertTMiStocks) { + String goodsId = tMiStock1.getGoodsId(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TBaseGoods::getGoodsId, goodsId); + TBaseGoods tBaseGoods = goodsMapper.selectOne(queryWrapper); + //原来仓库 + //总价 + /*BigDecimal shelvesNum = tMiStock1.getShelvesNum(); + BigDecimal price = tBaseGoods.getPrice(); + // 设置默认值 + if (price == null || price.compareTo(BigDecimal.ZERO) == 0) { + price = BigDecimal.ZERO; // 默认值为 1 + } + + BigDecimal totalPrice = price.multiply(shelvesNum); + tMiStock1.setPrice(String.valueOf(price)); + tMiStock1.setTotalMoney(totalPrice);*/ + tMiStock1.setOriginal(tBaseGoods.getStorageId()); + tMiStockMapper.insertTMiStock(tMiStock1); + } + } + } else { + // 更新虚拟库存信息 + if (insertTMiStockFs.size() > 0) { + for (TMiStockF tMiStock1 : insertTMiStockFs) { + tMiStockFMapper.insertTMiStock(tMiStock1); + } + } + } + + // 更新库位信息 已占用 + String storageLocation = params.getStorageLocation(); + if (StringUtils.isNotBlank(storageLocation)) { + TBaseStorageAreaLocation tBaseStorageAreaLocation = new TBaseStorageAreaLocation(); + tBaseStorageAreaLocation.setLocationId(storageLocation); + tBaseStorageAreaLocation.setStatus("1"); + tBaseStorageAreaLocationMapper.updateLocationSts(tBaseStorageAreaLocation); + } + + // 查询是否存在收货表数据 +// if (updateNoticeTabs.size() > 0) { +// // 更新入库通知单明细 +// tRkWareNoticeMapper.updateForeach(updateNoticeTabs); +// } + + // 获取最新的通知单信息,判断是否全部完成 + tRkWareNotice = tRkWareNoticeMapper.selectTRkWareNoticeByNoticeId(params.getNoticeId()); + + + + // 查询存货表数据 + TRkReceivingGoods tRkReceivingGoods = tRkReceivingGoodsMapper + .selectTRkReceivingGoodsByNoticeId(tRkWareNotice.getNoticeId()); + + String trkReceivingGoodsId = OrderCodeFactory.getOrderCode("R", ""); + if (tRkReceivingGoods != null) { + tRkReceivingGoods.setReceivingStatus(tRkWareNotice.getReceivingStatus()); + tRkReceivingGoods.setUpdateTime(new Date()); + tRkReceivingGoodsMapper.updateTRkReceivingGoods(tRkReceivingGoods); + + trkReceivingGoodsId = tRkReceivingGoods.getId(); + } else { + TRkReceivingGoods tGoods = new TRkReceivingGoods(); + BeanUtils.copyProperties(tRkWareNotice, tGoods); + tGoods.setId(trkReceivingGoodsId); + tGoods.setUpdateTime(new Date()); + tGoods.setCreateTime(new Date()); + tRkReceivingGoodsMapper.insertTRkReceivingGoods(tGoods); + } + + // 查询是否存在收货表数据 + if (updateNoticeTabs.size() > 0) { + + Map trkReceiveGoodsTabMap = new HashMap(); + + if (tRkReceivingGoods != null) { + for (TRkReceivingGoodsTab goodsTab : tRkReceivingGoods.getTRkReceivingGoodsTabList()) { + trkReceiveGoodsTabMap.put(goodsTab.getSalesOrderNumber() + goodsTab.getGoodsId(), goodsTab); + } + } + + List insertGoodsTabs = new ArrayList<>(); + // 存货表更新集合 + List tReceivingGoodsTabs = new ArrayList(); + + for (TRkWareNoticeTab noticeTab : updateNoticeTabs) { + TRkReceivingGoodsTab goodsTab = trkReceiveGoodsTabMap + .get(noticeTab.getSalesOrderNumber() + noticeTab.getGoodsId()); + if (goodsTab != null) { + goodsTab.setRecNum(noticeTab.getRecNum()); + goodsTab.setReceivingStatus(noticeTab.getReceivingStatus()); + goodsTab.setUpdateBy(params.getUserName()); + goodsTab.setUpdateTime(new Date()); + tReceivingGoodsTabs.add(goodsTab); + } else { + goodsTab = new TRkReceivingGoodsTab(); + BeanUtils.copyProperties(noticeTab, goodsTab); + goodsTab.setNoticeId(trkReceivingGoodsId); +// goodsTab.setId(OrderCodeFactory.getOrderCode("RTAB", "")); + insertGoodsTabs.add(goodsTab); + } + } + + if (tReceivingGoodsTabs.size() > 0) { + // 批量更新存货明细表 + tRkReceivingGoodsMapper.updateForeach(tReceivingGoodsTabs); + } + + if (insertGoodsTabs.size() > 0) { + tRkReceivingGoodsMapper.batchTRkReceivingGoodsTab(insertGoodsTabs); + } + } + + for (TRkWareNoticeTab trkNoticeTab : tRkWareNotice.getTRkWareNoticeTabList()) { + if (!"2".equals(trkNoticeTab.getReceivingStatus())) { + allReceive = false; + break; + } + } + // 入库通知单及明细数据 移到 bak表 + if (allReceive) { + try { + // 查询入库通知单明细 +// tRkWareNotice = tRkWareNoticeMapper.selectTRkWareNoticeByNoticeId(tRkWareNotice.getNoticeId()); + TRkWareNoticeBak tRkWareNoticeBak = new TRkWareNoticeBak(); + BeanUtils.copyProperties(tRkWareNotice, tRkWareNoticeBak); +// String tRkWareNoticeBakId = OrderCodeFactory.getOrderCode("TRKBAK", ""); +// tRkWareNoticeBak.setId(tRkWareNoticeBakId); + + // 插入 t_rk_ware_notice_bak 表的数据 + tRkWareNoticeBak.setReceivingStatus("2"); + tRkWareNoticeBakMapper.insertTRkWareNoticeBak(tRkWareNoticeBak); + + List tRkWareNoticeTabBaks = new ArrayList<>(); + for (TRkWareNoticeTab trWareNoticeTab : tRkWareNotice.getTRkWareNoticeTabList()) { + TRkWareNoticeTabBak tRkWareNoticeTabBak = new TRkWareNoticeTabBak(); +// tRkWareNoticeTabBak.setId(OrderCodeFactory.getOrderCode("TRKTABBAK", "")); +// tRkWareNoticeTabBak.setNoticeId(tRkWareNoticeBakId); + BeanUtils.copyProperties(trWareNoticeTab, tRkWareNoticeTabBak); + tRkWareNoticeTabBak.setPurchaser(tRkWareNotice.getPurchaser()); + tRkWareNoticeTabBak.setSendeDate(tRkWareNotice.getSendeDate()); + tRkWareNoticeTabBak.setProviderName(tRkWareNotice.getProviderName()); + tRkWareNoticeTabBak.setRecPerson(tRkWareNotice.getRecPerson()); + tRkWareNoticeTabBaks.add(tRkWareNoticeTabBak); + } + + // 批量插入 t_rk_ware_notice_tab_bak 表的数据 + if (!tRkWareNoticeTabBaks.isEmpty()) { + tRkWareNoticeBakMapper.batchTRkWareNoticeTabBak(tRkWareNoticeTabBaks); + } + + // 删除入库通知单和明细 + tRkWareNoticeMapper.deleteTRkWareNoticeById(tRkWareNotice.getId()); + //单子id 就是明细的 Notice id + tRkWareNoticeMapper.deleteNoticeTabByNoticeId(tRkWareNotice.getId()); + + // 关闭入库通知单任务消息 + TCallNoticeOrder tCallNotice = new TCallNoticeOrder(); + tCallNotice.setTaskId(tRkWareNotice.getId()); + tCallNotice.setTaskType("0"); + tCallNotice.setUpdateBy(params.getUserName()); + tCallNotice.setUpdateTime(new Date()); + tNoticeOrderService.updateTaskStatus(tCallNotice); + } catch (Exception e) { + // 记录异常,并抛出运行时异常以触发事务回滚 + e.printStackTrace(); + throw new RuntimeException("处理全部接收失败", e); + } + } + + resultMap.put("success", "上架成功"); + + return resultMap; + } + + + private TMiStock makeTMiStock(TRkWareNotice notice, TRkWareNoticeTab noticeTab, TRkWareNoticeTabUpdate params) { + TMiStock tMiStock = new TMiStock(); + + // 需求数量 TODO + // tMiStock.setStoNum(); + + tMiStock.setId(OrderCodeFactory.getOrderCode("TMI", "")); + + // 上架数量 + tMiStock.setShelvesNum(noticeTab.getAmount()); + // 中标供应商 + tMiStock.setProviderId(notice.getProviderId()); + // 单位 + tMiStock.setUnit(noticeTab.getUnit()); + // 子需求编号 + tMiStock.setSalesOrderNumber(noticeTab.getSalesOrderNumber()); + // 物料名称 + tMiStock.setGoodsName(noticeTab.getGoodsName()); + // 规格型号 + tMiStock.setSpecification(noticeTab.getSpecification()); + // 物料描述 + tMiStock.setRecoil(noticeTab.getRecoil()); + // 招标员 + tMiStock.setCustomerId(notice.getTenderer()); + tMiStock.setStorageShortName(noticeTab.getStorageShortName()); + // 需求组织 + tMiStock.setOperatorId(notice.getOperatorId()); + // 申请部门 + tMiStock.setSupplier(noticeTab.getSupplier()); + // 创建时间 + tMiStock.setOperateDate(noticeTab.getOperateDate()); + // 上报时间 + // 上报时间 + if (StringUtils.isNotBlank(noticeTab.getReportTime())) { + tMiStock.setReportTime(noticeTab.getReportTime()); + } else { + tMiStock.setReportTime(DateUtils.getDate()); + } + // 申请单号 设置为来源单号 发货单号 TODO + if (StringUtils.isNotBlank(notice.getDeliveryId())) { + tMiStock.setLotId(notice.getDeliveryId()); + } else if (StringUtils.isNotBlank(notice.getPurchaseId())) { + tMiStock.setLotId(notice.getPurchaseId()); + } else if (StringUtils.isNotBlank(noticeTab.getSourceNum())) { + tMiStock.setLotId(noticeTab.getSourceNum()); + } else { + tMiStock.setLotId(noticeTab.getPurchaseId()); + } + // 申请人 + tMiStock.setApplicant(notice.getApplicant()); + // 计划日期 + tMiStock.setPlanDate(noticeTab.getPlanDate()); + // 计划期间 + tMiStock.setPlanTime(noticeTab.getPlanTime()); + // 需求周期 + tMiStock.setNeedCycle(noticeTab.getNeedCycle()); + // 需求类型 + tMiStock.setNeedType(noticeTab.getNeedType()); + // 物料编码 + tMiStock.setGoodsId(noticeTab.getGoodsId()); + // 物料分类 + tMiStock.setGoodsTypeId(noticeTab.getGoodsTypeId()); + // 品牌 + tMiStock.setBrand(noticeTab.getBrand()); + // 计划单价(含税) + tMiStock.setPrice(noticeTab.getPrice() != null ? noticeTab.getPrice().toString() : null); + // 计划金额 + tMiStock.setTotalMoney(noticeTab.getTotalMoney()); + // 需求时间 + tMiStock.setExpiryDate(noticeTab.getExpiryDate()); + // 建议供应商名称 TODO + tMiStock.setProviderName(notice.getProviderName()); + // 收货人 + tMiStock.setReceiver(notice.getReceiver()); + // 需求部门 + tMiStock.setNeedDept(noticeTab.getNeedDept()); + // 采购组织 + tMiStock.setPurchaseDept(notice.getPurchaseDept()); + // 收货组织 + tMiStock.setProduclotId(notice.getProduclotId()); + // 收货人部门 + tMiStock.setReceiverDept(notice.getReceiverDept()); + // 送货区域 + tMiStock.setReceivingArea(notice.getReceivingArea()); + // 技术需求附件 + tMiStock.setPackageId(noticeTab.getPackageId()); + // 物资计划明细备注 + tMiStock.setRemark(noticeTab.getRemark()); + // 用途 + tMiStock.setUseType(noticeTab.getUseType()); + // 中标供应商联系方式 + tMiStock.setTelephone(notice.getTelephone()); + // wms订单号 入库通知单号 + tMiStock.setNoticeId(notice.getId()); + // 生产日期 + tMiStock.setProductionDate(noticeTab.getProductionDate()); + // 入库类型 + tMiStock.setStorageMode(params.getStorageMode()); + // 仓库编号 + tMiStock.setStorageId(noticeTab.getStorageId()); + // 库位 + tMiStock.setLocationId(noticeTab.getStorageLocation()); + // 增加外部批次号 + tMiStock.setBatchNo(noticeTab.getBatchNo()); + // 条码 + tMiStock.setBarcode(noticeTab.getBarcode()); + // 入库级别 + tMiStock.setLevelType(noticeTab.getLevelType()); + // 标准超期呆滞 + tMiStock.setStandard(params.getExtras().get("extraTime")); + // 托盘 + tMiStock.setCtl(params.getCtlNo()); + + tMiStock.setCreateBy(notice.getOperatorId()); + + tMiStock.setCreateTime(new Date()); + // 入库时间 + tMiStock.setWareDate(DateUtils.getTime()); + tMiStock.setDeptId(params.getDeptId()); + tMiStock.setNeedPerson(noticeTab.getNeedPerson()); + tMiStock.setNeedTel(noticeTab.getNeedTel()); + tMiStock.setExpiryDate(noticeTab.getExpiryDate()); + tMiStock.setShelvesNum(noticeTab.getAmount()); + + tMiStock.setPurchaseId(noticeTab.getPurchaseId()); + tMiStock.setUpdateTime(new Date()); + tMiStock.setOperateDate(new Date()); + return tMiStock; + } + + /** + * 编辑库存信息 + * + * @param notice + * @param noticeTab + * @return + */ + private TMiStockF makeTMiStockF(TRkWareNotice notice, TRkWareNoticeTab noticeTab, TRkWareNoticeTabUpdate params) { + TMiStockF tMiStock = new TMiStockF(); + + // 需求数量 TODO + // tMiStock.setStoNum(); + + tMiStock.setId(OrderCodeFactory.getOrderCode("TMI", "")); + + // 上架数量 + tMiStock.setShelvesNum(noticeTab.getAmount()); + // 中标供应商 + tMiStock.setProviderId(notice.getProviderId()); + // 单位 + tMiStock.setUnit(noticeTab.getUnit()); + // 子需求编号 + tMiStock.setSalesOrderNumber(noticeTab.getSalesOrderNumber()); + // 物料名称 + tMiStock.setGoodsName(noticeTab.getGoodsName()); + // 规格型号 + tMiStock.setSpecification(noticeTab.getSpecification()); + // 物料描述 + tMiStock.setRecoil(noticeTab.getRecoil()); + // 招标员 + tMiStock.setCustomerId(notice.getTenderer()); + // 需求组织 + tMiStock.setOperatorId(notice.getOperatorId()); + // 申请部门 + tMiStock.setSupplier(noticeTab.getSupplier()); + // 创建时间 + tMiStock.setOperateDate(noticeTab.getOperateDate()); + // 上报时间 + tMiStock.setReportTime(noticeTab.getReportTime()); + // 申请单号 设置为来源单号 发货单号 TODO + tMiStock.setLotId(notice.getPurchaseId()); + // 申请人 + tMiStock.setApplicant(notice.getApplicant()); + // 计划日期 + tMiStock.setPlanDate(noticeTab.getPlanDate()); + // 计划期间 + tMiStock.setPlanTime(noticeTab.getPlanTime()); + // 需求周期 + tMiStock.setNeedCycle(noticeTab.getNeedCycle()); + // 需求类型 + tMiStock.setNeedType(noticeTab.getNeedType()); + // 物料编码 + tMiStock.setGoodsId(noticeTab.getGoodsId()); + // 物料分类 + tMiStock.setGoodsTypeId(noticeTab.getGoodsTypeId()); + // 品牌 + tMiStock.setBrand(noticeTab.getBrand()); + // 计划单价(含税) + tMiStock.setPrice(noticeTab.getPrice() != null ? noticeTab.getPrice().toString() : null); + // 计划金额 + tMiStock.setTotalMoney(noticeTab.getTotalMoney()); + // 需求时间 + tMiStock.setExpiryDate(noticeTab.getExpiryDate()); + // 建议供应商名称 TODO + tMiStock.setProviderName(notice.getProviderName()); + // 收货人 + tMiStock.setReceiver(notice.getReceiver()); + // 需求部门 + tMiStock.setNeedDept(noticeTab.getNeedDept()); + // 采购组织 + tMiStock.setPurchaseDept(notice.getPurchaseDept()); + // 收货组织 + tMiStock.setProduclotId(notice.getProduclotId()); + // 收货人部门 + tMiStock.setReceiverDept(notice.getReceiverDept()); + // 送货区域 + tMiStock.setReceivingArea(notice.getReceivingArea()); + // 技术需求附件 + tMiStock.setPackageId(noticeTab.getPackageId()); + // 物资计划明细备注 + tMiStock.setRemark(noticeTab.getRemark()); + // 用途 + tMiStock.setUseType(noticeTab.getUseType()); + // 中标供应商联系方式 + tMiStock.setTelephone(notice.getTelephone()); + // wms订单号 入库通知单号 + tMiStock.setNoticeId(notice.getNoticeId()); + // 生产日期 + tMiStock.setProductionDate(noticeTab.getProductionDate()); + // 入库类型 + tMiStock.setStorageMode(params.getStorageMode()); + // 仓库编号 + tMiStock.setStorageId(noticeTab.getStorageId()); + // 库位 + tMiStock.setLocationId(noticeTab.getStorageLocation()); + // 增加外部批次号 + tMiStock.setBatchNo(noticeTab.getBatchNo()); + // 条码 + tMiStock.setBarcode(noticeTab.getBarcode()); + // 入库级别 + tMiStock.setLevelType(noticeTab.getLevelType()); + + // 标准超期呆滞 + tMiStock.setStandard(params.getExtras().get("extraTime")); + + // 托盘 + tMiStock.setCtl(params.getCtlNo()); + + tMiStock.setCreateBy(notice.getOperatorId()); + tMiStock.setCreateTime(new Date()); + + // 入库时间 + tMiStock.setWareDate(DateUtils.getTime()); + + tMiStock.setDeptId(params.getDeptId()); + + tMiStock.setNoticeTabId(noticeTab.getId()); + + return tMiStock; + } + + + @Log(title = "出库过账", businessType = BusinessType.OTHER) + @PostMapping(value = "/accountOutOrder") + @Transactional + public AjaxResult accountOutOrder(@RequestBody JSONObject jsonObject) { + String orderNum = ""; + String orderItem = ""; + TCkOrders ckOrders = null; + JSONArray dataArray = jsonObject.getJSONArray("data"); + for (int i = 0; i < dataArray.size(); i++) { + JSONObject item = dataArray.getJSONObject(i); + //仓位号 + String binCode = item.getStr("binCode"); + //物料编码 + String matCode = item.getStr("matCode"); + //数量 + double matQty = item.getDouble("matQty"); + //单位 + String matUnit = item.getStr("matUnit"); + //明细单号 + orderItem = item.getStr("orderItem"); + //明细子需求编号 + String orderKeyThird = item.getStr("orderKeyThird"); + //通知单号 + orderNum = item.getStr("orderNum"); + //入库类型 + String orderType = item.getStr("orderType"); + // 申请人 + String username = item.getStr("username"); + //仓库 + String whCode = item.getStr("whCode"); + if (whCode.equals("RZ01")) { + whCode = "FJQR01"; + } + //容器号 + String traceCode = item.getStr("traceCode"); + // 处理这些数据,例如保存到数据库或进行其他业务逻辑 + //通知单 + ckOrders = tCkOrdersMapper.selectOnes(orderNum); + List list = ckOrders.getTckOrderdetailList(); + //通知单明细 + String finalOrderItem = orderItem; + TCkOrderdetail ck = list.stream() + .filter(c -> { + boolean isMatch = c.getId().equals(finalOrderItem); + return isMatch; + }) + .findFirst() + .orElse(null); // 如果没有找到,返回 null + + if (ck == null) { + logger.error("出库明细条数必须大于0"); + return AjaxResult.error("出库明细条数必须大于0"); + } + + //全部出matCode + TMiStock tMiStock = new TMiStock(); + tMiStock.setGoodsId(ck.getGoodsId()); + tMiStock.setGoodsName(ck.getGoodsName()); + tMiStock.setStorageId(whCode); + tMiStock.setCtl(traceCode); + tMiStock.setSalesOrderNumber(ck.getBusinessId()); + + /** + * 正序列出仓库下的该物料列表 + */ + List tMiStocks = tMiStockMapper.selectTMiStockListByGoodsId(tMiStock); + if (ck.getShelvesNum().compareTo(BigDecimal.valueOf(matQty)) == 0) { + logger.info("出库请求解析开始:{}", ck); + if (tMiStocks.size() == 0) { + logger.warn("未找到该物料库存或在冻结中:{}", ck.getGoodsId()); + return AjaxResult.error("未找到该物料库存或在冻结中: + ck.getGoodsId()"); + } + if (!"2".equals(ck.getConfirmStatus())) { + + /* lock.lock(); // 获取锁*/ + + for (TMiStock stock : tMiStocks) { + BigDecimal currentStockQty = stock.getShelvesNum(); // 假设这是库存数量字段 + BigDecimal newStockQty = currentStockQty.subtract(BigDecimal.valueOf(matQty)); // 减去本次出库数量 + stock.setShelvesNum(newStockQty); // 设置新的库存数量 + + String goodsId = stock.getGoodsId(); + + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TBaseGoods::getGoodsId, goodsId); + TBaseGoods tBaseGoods = goodsMapper.selectOne(queryWrapper); + //原来仓库 + //总价 + BigDecimal shelvesNum = stock.getShelvesNum(); + BigDecimal price = tBaseGoods.getPrice(); + if (price == null || price.compareTo(BigDecimal.ZERO) == 0) { + price = BigDecimal.ZERO; // 默认值为 1 + } + BigDecimal totalPrice = price.multiply(shelvesNum); + stock.setPrice(String.valueOf(price)); + stock.setTotalMoney(totalPrice); + + // 更新库存记录 + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(TMiStock::getId, stock.getId()) // 假设有一个ID字段 + .set(TMiStock::getShelvesNum, newStockQty) + .set(TMiStock::getPrice, price) + .set(TMiStock::getTotalMoney, totalPrice); + if (newStockQty.compareTo(BigDecimal.ZERO) == 0) { + tMiStockMapper.deleteById(stock.getId()); + } else { + tMiStockMapper.update(null, updateWrapper); // 执行更新操作 + } + + } + /*finally { + lock.unlock(); // 释放锁 + }*/ + logger.error("出库过账成功"); + tCkPickingwavegoodsService.sendDevice(ckOrders); + } else { + ckOrders.setConfirmStatus("1"); + tCkOrdersMapper.updateConfirmStatus(ckOrders); + } + } else { + // 部分出库逻辑 + logger.info("部分出库逻辑解析:{}", ck); + BigDecimal shelvesNum = ck.getShelvesNum(); // 总数量 + BigDecimal alreadyShippedQty = ck.getGoodsNum(); // 已出库数量 + BigDecimal remainingQty = shelvesNum.subtract(alreadyShippedQty); // 剩余数量 + + BigDecimal partQty = BigDecimal.valueOf(matQty); // 本次请求的出库数量 + + // 检查本次请求的出库数量是否可以满足 + if (partQty.compareTo(remainingQty) <= 0) { + // 可以满足本次出库请求 + ck.setGoodsNum(alreadyShippedQty.add(partQty)); // 更新已出库数量 + // 更新库存 + for (TMiStock stock : tMiStocks) { + BigDecimal currentStockQty = stock.getShelvesNum(); + BigDecimal newStockQty = currentStockQty.subtract(partQty); + stock.setShelvesNum(newStockQty); + + LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); + updateWrapper.eq(TMiStock::getId, stock.getId()) + .set(TMiStock::getShelvesNum, newStockQty); + tMiStockMapper.update(null, updateWrapper); + } + + // 更新订单详情 + LambdaUpdateWrapper updateOrderDetailWrapper = new LambdaUpdateWrapper<>(); + updateOrderDetailWrapper.eq(TCkOrderdetail::getOrderId, ck.getOrderId()) + .set(TCkOrderdetail::getGoodsNum, ck.getGoodsNum()); + tCkOrderdetailMapper.update(null, updateOrderDetailWrapper); + + + // 重新获取最新的订单详情 + TCkOrderdetail updatedCk = tCkOrderdetailMapper.selectById(ck.getId()); + + // 检查是否所有物品都已出库 + if (updatedCk.getShelvesNum().compareTo(updatedCk.getGoodsNum()) == 0) { + // 所有物品都已出库,处理通知单的删除和备份 + TckOrdersBak tckOrdersBak = new TckOrdersBak(); + org.springframework.beans.BeanUtils.copyProperties(ckOrders, tckOrdersBak); + LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); + queryWrapper1.eq(TCkOrderdetail::getOrderId, ck.getOrderId()); + List detailList = tCkOrderdetailMapper.selectList(queryWrapper1); + List bakList = new ArrayList<>(); + for (TCkOrderdetail tCkOrderdetail1 : detailList) { + TckOrderdetailBak tckOrderdetailBak = new TckOrderdetailBak(); + org.springframework.beans.BeanUtils.copyProperties(tCkOrderdetail1, tckOrderdetailBak); + //存储审核人和审核时间 + tckOrderdetailBak.setAuditDate(ckOrders.getAuditDate()); + tckOrderdetailBak.setAuditMan(ckOrders.getAuditMan()); + tckOrderdetailBak.setApplicant(ckOrders.getApplicant()); + tckOrderdetailBak.setRejectReason(ckOrders.getRejectReason()); + bakList.add(tckOrderdetailBak); + } + tckOrdersBak.setTckOrderdetailBakList(bakList); + tckOrdersBakService.insertTckOrdersBak(tckOrdersBak); + tCkOrdersMapper.deleteTCkOrdersById(ck.getOrderId()); + tCkOrdersMapper.deleteTCkOrderdetailByOrderId(ck.getOrderId()); + logger.info("全部出库完成,通知单已删除并备份"); + return new AjaxResult(0, "部分出库已完成最最大数量,通知单改为bak", null); + } + // 更新订单状态为部分出库 + ckOrders.setConfirmStatus("1"); + BigDecimal newShippedQty = alreadyShippedQty.add(partQty); // 更新已出库数量 + ck.setGoodsNum(newShippedQty); + tCkOrdersMapper.updateConfirmStatus(ckOrders); + logger.info("部分出库更新完成"); + return new AjaxResult(0, "部分出库成功", null); + + } else { + // 请求的出库数量大于剩余库存,不能出库 + logger.warn("请求的出库数量大于剩余库存,无法出库"); + return new AjaxResult(99, "请求的出库数量大于剩余库存", null); + } + } + + //删除通知单 + //根据库位查询是否有库存 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TMiStock::getLocationId,binCode); +// queryWrapper.eq(TMiStock::getCtl,ctl); + + List tMiStocks0 = tMiStockMapper.selectList(queryWrapper); + if(tMiStocks0.size() == 0){ + //释放库位 + TBaseStorageAreaLocation baseStorageAreaLocation = new TBaseStorageAreaLocation(); + baseStorageAreaLocation.setLocationId(binCode); + baseStorageAreaLocation.setStatus("0"); + tBaseStorageAreaLocationMapper.updateLocationSts(baseStorageAreaLocation); + } + //校验托盘容器是否正确 + LambdaQueryWrapper queryWrapper2 = new LambdaQueryWrapper<>(); + queryWrapper2.eq(TMiStock::getCtl,traceCode); + List tMiStocks2 = tMiStockMapper.selectList(queryWrapper); + if(tMiStocks2.size() == 0){ + LambdaQueryWrapper ctlWrapper = new LambdaQueryWrapper<>(); + ctlWrapper.eq(TBasePallet::getPalletId, traceCode); + List plcs = basePalletMapper.selectList(ctlWrapper); + if (!plcs.isEmpty()) { + TBasePallet palletChk = plcs.get(0); + if("1".equals(palletChk.getStatus())){ + TBasePallet tBasePallet = new TBasePallet(); + tBasePallet.setStatus("0"); + tBasePallet.setId(palletChk.getId()); + tBasePallet.setUpdateTime(new Date()); + basePalletMapper.updateTBasePallet(tBasePallet); + } + } + } + + } + + + //删除出库通知单 备份出库通知单 + TckOrdersBak tckOrdersBak = new TckOrdersBak(); + BeanUtils.copyProperties(ckOrders, tckOrdersBak); + + List list = ckOrders.getTckOrderdetailList(); + for (TCkOrderdetail ckOrderdetail : list) { + if (ckOrderdetail.getStorageId().startsWith("FJQR")) { + ckOrderdetail.setConfirmStatus("2"); + orderdetailMapper.updateTCkOrderdetail(ckOrderdetail); + } + } + + // + List bakList = new ArrayList<>(); + for (TCkOrderdetail ckOrderdetail : list) { + if (ckOrderdetail.getConfirmStatus().equals("2")) { + TckOrderdetailBak tckOrderdetailBak = new TckOrderdetailBak(); + org.springframework.beans.BeanUtils.copyProperties(ckOrderdetail, tckOrderdetailBak); + //存储审核人和审核时间 + tckOrderdetailBak.setAuditDate(ckOrders.getAuditDate()); + tckOrderdetailBak.setAuditMan(ckOrders.getAuditMan()); + tckOrderdetailBak.setApplicant(ckOrders.getApplicant()); + tckOrderdetailBak.setRejectReason(ckOrders.getRejectReason()); + bakList.add(tckOrderdetailBak); + tCkOrderdetailMapper.deleteById(orderItem); + } + } + if (bakList.size() == list.size()) { + tckOrdersBak.setTckOrderdetailBakList(bakList); + tckOrdersBakService.insertTckOrdersBak(tckOrdersBak); + tCkOrdersMapper.deleteTCkOrdersById(orderNum); + } + return new AjaxResult(0, "出库过账成功", null); + } + + + @Log(title = "库位查询", businessType = BusinessType.OTHER) + @Transactional(rollbackFor = Exception.class) + @GetMapping("/stocks") + public AjaxResult getStocks(@RequestParam String whCode, @RequestParam(required = false) String ownerCode, @RequestParam(required = false) String matCode, @RequestParam(required = false) String batchNum, @RequestParam(required = false) String podCode, @RequestParam(required = false) String binCode, @RequestParam(required = false) Integer pageNum, @RequestParam(required = false) Integer pageSize, @RequestParam String type) { + List dataItems = null; + if (type.equals("0") || type.equals("1")) { + + String ip = "http://172.18.29.101/wms/api/RestJsonService/getStocks"; + ObjectMapper objectMapper = new ObjectMapper(); + + // Build request body + Map requestMap = new HashMap<>(); + requestMap.put("reqCode", "T" + System.currentTimeMillis()); + + Map data = new HashMap<>(); + data.put("whCode", "RZ01"); + data.put("ownerCode", ownerCode != null ? ownerCode : ""); + data.put("matCode", matCode != null ? matCode : ""); + data.put("batchNum", batchNum != null ? batchNum : ""); + data.put("podCode", podCode != null ? podCode : ""); + data.put("binCode", binCode != null ? binCode : ""); + if(pageNum == null || pageSize == null) { + pageNum = 1; + pageSize = 1000; + } + data.put("pageNum", pageNum); + data.put("pageSize", pageSize); + + requestMap.put("data", data); + + // Set request headers + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json;charset=UTF-8"); + + // Create request entity + String jsonString = null; + try { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + jsonString = objectMapper.writeValueAsString(requestMap); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + JSONObject result = HttpUtils.post(ip, jsonString, headers); + List data1 = (List) result.get("data"); + dataItems = new ArrayList<>(); + + + // Convert data1 to DataItem objects + for (Object obj : data1) { + if (obj instanceof Map) { + Map map = (Map) obj; + DataItem dataItem = objectMapper.convertValue(map, DataItem.class); + dataItems.add(dataItem); + } + } + + // If type is 0, also add data from TBaseGoods + if (type.equals("0")) { + List list = tBaseGoodsMapper.selectTBaseGoodsList(new TBaseGoods()); + for (TBaseGoods tBaseGoods : list) { + for (DataItem dataItem : dataItems) { + if (tBaseGoods.getGoodsId().equals(dataItem.getMatCode())) { + dataItem.setContainerCode(tBaseGoods.getGoodsTid()); + } + } + } + } + //去重 + List distinctDataItems = dataItems.stream() + .filter(Objects::nonNull) // 过滤掉 null 值 + .filter(item -> !item.getContainerCode().startsWith("A2F")) // 过滤掉以 A2FB 开头的项 + .collect(Collectors.toMap(DataItem::getContainerCode, item -> item, (existing, replacement) -> existing)) + .values() + .stream() + .collect(Collectors.toList()); + + return AjaxResult.success(distinctDataItems); + } else if (type.equals("2")) { + List list = tBaseGoodsMapper.selectTBaseGoodsList(new TBaseGoods()); + for (TBaseGoods tBaseGoods : list) { + for (DataItem dataItem : dataItems) { + if (tBaseGoods.getGoodsId().equals(dataItem.getMatCode())) { + dataItem.setContainerCode(tBaseGoods.getGoodsEpc()); + } + } + } + //去重 + List distinctDataItems = dataItems.stream() + .filter(Objects::nonNull) // 过滤掉 null 值 + .filter(item -> !item.getContainerCode().startsWith("A2F")) // 过滤掉以 A2FB 开头的项 + .collect(Collectors.toMap(DataItem::getContainerCode, item -> item, (existing, replacement) -> existing)) + .values() + .stream() + .collect(Collectors.toList()); + return AjaxResult.success(distinctDataItems); + } else if (type.equals("3")) { + //请求海康 + String ip = "http://172.18.29.101/wms/api/RestJsonService/getStocks"; + ObjectMapper objectMapper = new ObjectMapper(); + + // Build request body + Map requestMap = new HashMap<>(); + requestMap.put("reqCode", "T" + System.currentTimeMillis()); + + Map data = new HashMap<>(); + data.put("whCode", "RZ01"); + data.put("ownerCode", ownerCode != null ? ownerCode : ""); + data.put("matCode", matCode != null ? matCode : ""); + data.put("batchNum", batchNum != null ? batchNum : ""); + data.put("podCode", podCode != null ? podCode : ""); + data.put("binCode", binCode != null ? binCode : ""); + data.put("pageNum", 1); + data.put("pageSize", 1000); + requestMap.put("data", data); + Map headers = new HashMap<>(); + headers.put("Content-Type", "application/json;charset=UTF-8"); + String jsonString = null; + try { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + jsonString = objectMapper.writeValueAsString(requestMap); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + JSONObject result = HttpUtils.post(ip, jsonString, headers); + List data1 = (List) result.get("data"); + List dataItem = new ArrayList<>(); + for (Object obj : data1) { + if (obj instanceof Map) { + Map map = (Map) obj; + DataItem item = objectMapper.convertValue(map, DataItem.class); + dataItem.add(item); + } + } + //推送盘点 + String url = "http://172.22.28.156:8090/api/v2/inventory/container"; + List list = tBaseGoodsMapper.selectTBaseGoodsList(new TBaseGoods()); + for (TBaseGoods tBaseGoods : list) { + for (DataItem item : dataItem) { + if (tBaseGoods.getGoodsId().equals(item.getMatCode())) { + item.setContainerCode(tBaseGoods.getGoodsEpc()); + } + } + + } + Map requestBody = new HashMap<>(); + requestBody.put("data", dataItem); + requestMap.put("code", 200); + requestMap.put("msg", "操作成功"); + try { + String jsonBody = objectMapper.writeValueAsString(requestBody); + logger.info("盘点推送数据:{}",jsonBody); + JSONObject results = HttpUtils.post(url, jsonBody, headers); + + // 检查返回的 JSON 对象 + if (results != null && "succ".equals(results.getStr("msg")) && results.getInt("result") == 0) { + return AjaxResult.success("数据推送成功", results); + } else { + return AjaxResult.error("推送失败,未收到有效响应或返回值不正确"); + } + } catch (Exception e) { + return AjaxResult.error("推送过程中发生错误: " + e.getMessage()); + } + } + + return AjaxResult.error("有问题"); + } + + + @PostMapping("/sendMqtt") + public Boolean sendGoMessage(@RequestBody Types types) { + String method = "go"; + Object[] params = new Object[]{types.getCheckType()}; + String id = "sdrz.go"; + return mqttMessageSender.sendMessage(method, params, id); + } + + +} + + + + + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/RestClientConfig.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/RestClientConfig.java new file mode 100644 index 0000000..eb3fc26 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/RestClientConfig.java @@ -0,0 +1,35 @@ +package com.zbf.web.controller.system; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; +import javax.net.ssl.SSLContext; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.TrustStrategy; +import java.security.cert.X509Certificate; + +@Configuration +public class RestClientConfig { + + + @Bean(name = "defaultRestTemplate") + public RestTemplate restTemplates() throws Exception { + TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true; + SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy) + .build(); + + CloseableHttpClient httpClient = HttpClients.custom() + .setSslcontext(sslContext) + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .build(); + + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory.setHttpClient(httpClient); + + return new RestTemplate(requestFactory); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysConfigController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysConfigController.java new file mode 100644 index 0000000..a5c6821 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysConfigController.java @@ -0,0 +1,133 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.SysConfig; +import com.zbf.system.service.ISysConfigService; + +/** + * 参数配置 信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController +{ + @Autowired + private ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @PreAuthorize("@ss.hasPermi('system:config:list')") + @GetMapping("/list") + public TableDataInfo list(SysConfig config) + { + startPage(); + List list = configService.selectConfigList(config); + return getDataTable(list); + } + + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:config:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysConfig config) + { + List list = configService.selectConfigList(config); + ExcelUtil util = new ExcelUtil(SysConfig.class); + util.exportExcel(response, list, "参数数据"); + } + + /** + * 根据参数编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:config:query')") + @GetMapping(value = "/{configId}") + public AjaxResult getInfo(@PathVariable Long configId) + { + return success(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + */ + @GetMapping(value = "/configKey/{configKey}") + public AjaxResult getConfigKey(@PathVariable String configKey) + { + return success(configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @PreAuthorize("@ss.hasPermi('system:config:add')") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysConfig config) + { + if (!configService.checkConfigKeyUnique(config)) + { + return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setCreateBy(getUsername()); + return toAjax(configService.insertConfig(config)); + } + + /** + * 修改参数配置 + */ + @PreAuthorize("@ss.hasPermi('system:config:edit')") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysConfig config) + { + if (!configService.checkConfigKeyUnique(config)) + { + return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + config.setUpdateBy(getUsername()); + return toAjax(configService.updateConfig(config)); + } + + /** + * 删除参数配置 + */ + @PreAuthorize("@ss.hasPermi('system:config:remove')") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public AjaxResult remove(@PathVariable Long[] configIds) + { + configService.deleteConfigByIds(configIds); + return success(); + } + + /** + * 刷新参数缓存 + */ + @PreAuthorize("@ss.hasPermi('system:config:remove')") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() + { + configService.resetConfigCache(); + return success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDeptController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDeptController.java new file mode 100644 index 0000000..7c5b6b6 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDeptController.java @@ -0,0 +1,155 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.constant.UserConstants; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDept; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.service.ISysDeptService; + +/** + * 部门信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController +{ + @Autowired + private ISysDeptService deptService; + + /** + * 获取部门列表 + */ + @PreAuthorize("@ss.hasPermi('system:dept:list')") + @GetMapping("/list") + public AjaxResult list(SysDept dept) + { + List depts = deptService.selectDeptList(dept); + return success(depts); + } + + @GetMapping("/supplier") + public AjaxResult supplier() + { + SysDept dept = new SysDept(); + dept.setStatus("0"); + dept.setDelFlag("0"); + List depts = deptService.selectDeptList(dept); + List collect = depts.stream().filter(f -> f.getAncestors().split(",").length == 3).collect(Collectors.toList()); + return success(collect); + } + + /** + * 查询部门列表(排除节点) + */ + @PreAuthorize("@ss.hasPermi('system:dept:list')") + @GetMapping("/list/exclude/{deptId}") + public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) + { + List depts = deptService.selectDeptList(new SysDept()); + depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); + return success(depts); + } + + /** + * 获取部门下拉树列表 + */ + @GetMapping("/treeselect") + public AjaxResult treeselect(SysDept dept) + { + List depts = deptService.selectDeptList(dept); + return AjaxResult.success(deptService.buildDeptTreeSelect(depts)); + } + + /** + * 根据部门编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:dept:query')") + @GetMapping(value = "/{deptId}") + public AjaxResult getInfo(@PathVariable Long deptId) + { + deptService.checkDeptDataScope(deptId); + return success(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门 + */ + @PreAuthorize("@ss.hasPermi('system:dept:add')") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDept dept) + { + if (!deptService.checkDeptNameUnique(dept)) + { + return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + dept.setCreateBy(getUsername()); + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @PreAuthorize("@ss.hasPermi('system:dept:edit')") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDept dept) + { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (!deptService.checkDeptNameUnique(dept)) + { + return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + else if (dept.getParentId().equals(deptId)) + { + return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } + else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) + { + return error("该部门包含未停用的子部门!"); + } + dept.setUpdateBy(getUsername()); + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + */ + @PreAuthorize("@ss.hasPermi('system:dept:remove')") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public AjaxResult remove(@PathVariable Long deptId) + { + if (deptService.hasChildByDeptId(deptId)) + { + return warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) + { + return warn("部门存在用户,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictDataController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictDataController.java new file mode 100644 index 0000000..de88aec --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictDataController.java @@ -0,0 +1,134 @@ +package com.zbf.web.controller.system; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDictData; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.service.ISysDictDataService; +import com.zbf.system.service.ISysDictTypeService; + +/** + * 数据字典信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController +{ + @Autowired + private ISysDictDataService dictDataService; + + @Autowired + private ISysDictTypeService dictTypeService; + + @PreAuthorize("@ss.hasPermi('system:dict:list')") + @GetMapping("/list") + public TableDataInfo list(SysDictData dictData) + { + startPage(); + List list = dictDataService.selectDictDataList(dictData); + return getDataTable(list); + } + + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:dict:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictData dictData) + { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil util = new ExcelUtil(SysDictData.class); + util.exportExcel(response, list, "字典数据"); + } + + /** + * 查询字典数据详细 + */ + @PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/{dictCode}") + public AjaxResult getInfo(@PathVariable Long dictCode) + { + return success(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 查询字典数据详细 + */ + //@PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/queryLabel") + public AjaxResult getInfo(SysDictData dictData) + { + return success(dictDataService.selectDictLabel(dictData.getDictType(),dictData.getDictValue())); + } + + /** + * 根据字典类型查询字典数据信息 + */ + @GetMapping(value = "/type/{dictType}") + public AjaxResult dictType(@PathVariable String dictType) + { + List data = dictTypeService.selectDictDataByType(dictType); + if (StringUtils.isNull(data)) + { + data = new ArrayList(); + } + return success(data); + } + + /** + * 新增字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:add')") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictData dict) + { + dict.setCreateBy(getUsername()); + return toAjax(dictDataService.insertDictData(dict)); + } + + /** + * 修改保存字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictData dict) + { + dict.setUpdateBy(getUsername()); + return toAjax(dictDataService.updateDictData(dict)); + } + + /** + * 删除字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public AjaxResult remove(@PathVariable Long[] dictCodes) + { + dictDataService.deleteDictDataByIds(dictCodes); + return success(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictTypeController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictTypeController.java new file mode 100644 index 0000000..2999c30 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysDictTypeController.java @@ -0,0 +1,131 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDictType; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.service.ISysDictTypeService; + +/** + * 数据字典信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController +{ + @Autowired + private ISysDictTypeService dictTypeService; + + @PreAuthorize("@ss.hasPermi('system:dict:list')") + @GetMapping("/list") + public TableDataInfo list(SysDictType dictType) + { + startPage(); + List list = dictTypeService.selectDictTypeList(dictType); + return getDataTable(list); + } + + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:dict:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysDictType dictType) + { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil util = new ExcelUtil(SysDictType.class); + util.exportExcel(response, list, "字典类型"); + } + + /** + * 查询字典类型详细 + */ + @PreAuthorize("@ss.hasPermi('system:dict:query')") + @GetMapping(value = "/{dictId}") + public AjaxResult getInfo(@PathVariable Long dictId) + { + return success(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:add')") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysDictType dict) + { + if (!dictTypeService.checkDictTypeUnique(dict)) + { + return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setCreateBy(getUsername()); + return toAjax(dictTypeService.insertDictType(dict)); + } + + /** + * 修改字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:edit')") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysDictType dict) + { + if (!dictTypeService.checkDictTypeUnique(dict)) + { + return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dict.setUpdateBy(getUsername()); + return toAjax(dictTypeService.updateDictType(dict)); + } + + /** + * 删除字典类型 + */ + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public AjaxResult remove(@PathVariable Long[] dictIds) + { + dictTypeService.deleteDictTypeByIds(dictIds); + return success(); + } + + /** + * 刷新字典缓存 + */ + @PreAuthorize("@ss.hasPermi('system:dict:remove')") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public AjaxResult refreshCache() + { + dictTypeService.resetDictCache(); + return success(); + } + + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + List dictTypes = dictTypeService.selectDictTypeAll(); + return success(dictTypes); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysExpressionController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysExpressionController.java new file mode 100644 index 0000000..3f12812 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysExpressionController.java @@ -0,0 +1,104 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.SysExpression; +import com.zbf.system.service.ISysExpressionService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 流程达式Controller + * + * @author ruoyi + * @date 2022-12-12 + */ +@RestController +@RequestMapping("/system/expression") +public class SysExpressionController extends BaseController +{ + @Autowired + private ISysExpressionService sysExpressionService; + + /** + * 查询流程达式列表 + */ + @PreAuthorize("@ss.hasPermi('system:expression:list')") + @GetMapping("/list") + public TableDataInfo list(SysExpression sysExpression) + { + startPage(); + List list = sysExpressionService.selectSysExpressionList(sysExpression); + return getDataTable(list); + } + + /** + * 导出流程达式列表 + */ + @PreAuthorize("@ss.hasPermi('system:expression:export')") + @Log(title = "流程达式", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysExpression sysExpression) + { + List list = sysExpressionService.selectSysExpressionList(sysExpression); + ExcelUtil util = new ExcelUtil(SysExpression.class); + util.exportExcel(response, list, "流程达式数据"); + } + + /** + * 获取流程达式详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:expression:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(sysExpressionService.selectSysExpressionById(id)); + } + + /** + * 新增流程达式 + */ + @PreAuthorize("@ss.hasPermi('system:expression:add')") + @Log(title = "流程达式", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysExpression sysExpression) + { + return toAjax(sysExpressionService.insertSysExpression(sysExpression)); + } + + /** + * 修改流程达式 + */ + @PreAuthorize("@ss.hasPermi('system:expression:edit')") + @Log(title = "流程达式", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysExpression sysExpression) + { + return toAjax(sysExpressionService.updateSysExpression(sysExpression)); + } + + /** + * 删除流程达式 + */ + @PreAuthorize("@ss.hasPermi('system:expression:remove')") + @Log(title = "流程达式", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(sysExpressionService.deleteSysExpressionByIds(ids)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysIndexController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysIndexController.java new file mode 100644 index 0000000..7be88a9 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysIndexController.java @@ -0,0 +1,29 @@ +package com.zbf.web.controller.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.config.RuoYiConfig; +import com.zbf.common.utils.StringUtils; + +/** + * 首页 + * + * @author ruoyi + */ +@RestController +public class SysIndexController +{ + /** 系统基础配置 */ + @Autowired + private RuoYiConfig ruoyiConfig; + + /** + * 访问首页,提示语 + */ + @RequestMapping("/") + public String index() + { + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysListenerController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysListenerController.java new file mode 100644 index 0000000..9ca922f --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysListenerController.java @@ -0,0 +1,104 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.SysListener; +import com.zbf.system.service.ISysListenerService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 流程监听Controller + * + * @author Tony + * @date 2022-12-25 + */ +@RestController +@RequestMapping("/system/listener") +public class SysListenerController extends BaseController +{ + @Autowired + private ISysListenerService sysListenerService; + + /** + * 查询流程监听列表 + */ + @PreAuthorize("@ss.hasPermi('system:listener:list')") + @GetMapping("/list") + public TableDataInfo list(SysListener sysListener) + { + startPage(); + List list = sysListenerService.selectSysListenerList(sysListener); + return getDataTable(list); + } + + /** + * 导出流程监听列表 + */ + @PreAuthorize("@ss.hasPermi('system:listener:export')") + @Log(title = "流程监听", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysListener sysListener) + { + List list = sysListenerService.selectSysListenerList(sysListener); + ExcelUtil util = new ExcelUtil(SysListener.class); + util.exportExcel(response, list, "流程监听数据"); + } + + /** + * 获取流程监听详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:listener:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(sysListenerService.selectSysListenerById(id)); + } + + /** + * 新增流程监听 + */ + @PreAuthorize("@ss.hasPermi('system:listener:add')") + @Log(title = "流程监听", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysListener sysListener) + { + return toAjax(sysListenerService.insertSysListener(sysListener)); + } + + /** + * 修改流程监听 + */ + @PreAuthorize("@ss.hasPermi('system:listener:edit')") + @Log(title = "流程监听", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysListener sysListener) + { + return toAjax(sysListenerService.updateSysListener(sysListener)); + } + + /** + * 删除流程监听 + */ + @PreAuthorize("@ss.hasPermi('system:listener:remove')") + @Log(title = "流程监听", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(sysListenerService.deleteSysListenerByIds(ids)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysLoginController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysLoginController.java new file mode 100644 index 0000000..7d04eee --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysLoginController.java @@ -0,0 +1,142 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.constant.Constants; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.TreeSelect; +import com.zbf.common.core.domain.entity.SysMenu; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.domain.model.LoginBody; +import com.zbf.common.utils.RsaUtils; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.framework.web.service.SysLoginService; +import com.zbf.framework.web.service.SysPermissionService; +import com.zbf.system.domain.TBaseStorage; +import com.zbf.system.domain.TUserFavorites; +import com.zbf.system.domain.vo.MetaVo; +import com.zbf.system.domain.vo.RouterVo; +import com.zbf.system.mapper.TUserFavoritesMapper; +import com.zbf.system.service.ISysDeptService; +import com.zbf.system.service.ISysMenuService; +import com.zbf.system.service.ITBaseStorageService; + +import cn.hutool.json.JSONUtil; + +/** + * 登录验证 + * + * @author ruoyi + */ +@RestController +public class SysLoginController { + private final SysLoginService loginService; + + private final ISysMenuService menuService; + + private final SysPermissionService permissionService; + + @Autowired + private ITBaseStorageService baseStorageService; + + private ISysDeptService deptService; + private TUserFavoritesMapper favoritesMapper; + + public SysLoginController(ISysDeptService deptService, SysLoginService loginService, ISysMenuService menuService, SysPermissionService permissionService, TUserFavoritesMapper favoritesMapper) { + this.deptService = deptService; + this.loginService = loginService; + this.menuService = menuService; + this.permissionService = permissionService; + this.favoritesMapper = favoritesMapper; + } + /** + * 获取公钥 前端用来密码加密 + * + * @return + */ + @GetMapping("/publicKey") + public RsaUtils.RsaKeyPair publicKey() { + return RsaUtils.rsaKeyPair(); + } + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @PostMapping("/login") + public AjaxResult login(@RequestBody LoginBody loginBody) { + AjaxResult ajax = AjaxResult.success(); + // 生成令牌 + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + loginBody.getUuid()); + ajax.put(Constants.TOKEN, token); + return ajax; + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("getInfo") + public AjaxResult getInfo() { + SysUser user = SecurityUtils.getLoginUser().getUser(); + List deptList = deptService.selectDeptTreeList(deptService.selectDeptById(user.getDeptId())); + // 根据用户ID查询出此用户所有收藏的状态为有效的路由 只查询10条 + LambdaQueryWrapper query = new LambdaQueryWrapper(); + query.eq(TUserFavorites::getUserId, user.getUserId()); + query.eq(TUserFavorites::getStatus, "0"); + query.orderByDesc(TUserFavorites::getUpdateTime); + List favorites = favoritesMapper.selectList(query); + List routers = favorites.stream().map(favorite -> { + MetaVo metaVo = JSONUtil.toBean(favorite.getMeta(), MetaVo.class); + RouterVo routerVo = new RouterVo(); + routerVo.setId(favorite.getId()); + routerVo.setMeta(metaVo); + routerVo.setPath(favorite.getFullPath()); + routerVo.setName(favorite.getTitle()); + return routerVo; + }).collect(Collectors.toList()); + // 角色集合 + Set roles = permissionService.getRolePermission(user); + // 权限集合 + Set permissions = permissionService.getMenuPermission(user); + + // 获取用户所属仓库列表 + TBaseStorage baseStorage = new TBaseStorage(); + baseStorage.setDeptId(user.getDeptId()); + List tStorages = baseStorageService.selectTBaseStorageList(baseStorage); + + AjaxResult ajax = AjaxResult.success(); + ajax.put("user", user); + ajax.put("roles", roles); + ajax.put("permissions", permissions); + ajax.put("deptList", deptList); + ajax.put("storageList", tStorages.stream().map(TBaseStorage::getStorageId).collect(Collectors.toList())); + int toIdx = routers.size() > 10 ? 10 : routers.size(); + ajax.put("favoriteRouter", routers.subList(0, toIdx)); // 当前用户收藏的路由信息 + return ajax; + } + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("getRouters") + public AjaxResult getRouters() { + Long userId = SecurityUtils.getUserId(); + List menus = menuService.selectMenuTreeByUserId(userId); + return AjaxResult.success(menuService.buildMenus(menus)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysMenuController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysMenuController.java new file mode 100644 index 0000000..fd67f11 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysMenuController.java @@ -0,0 +1,150 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zbf.system.domain.TUserConfig; +import com.zbf.system.domain.TUserFavorites; +import com.zbf.system.mapper.TUserConfigMapper; +import com.zbf.system.mapper.TUserFavoritesMapper; +import com.zbf.system.service.ITUserConfigService; +import com.zbf.system.service.ITUserFavoritesService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.constant.UserConstants; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysMenu; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.system.service.ISysMenuService; + +/** + * 菜单信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + @Autowired + private ISysMenuService menuService; + @Autowired + private TUserFavoritesMapper userFavoritesMapper; + @Autowired + private TUserConfigMapper userConfigMapper; + + /** + * 获取菜单列表 + */ + @PreAuthorize("@ss.hasPermi('system:menu:list')") + @GetMapping("/list") + public AjaxResult list(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return success(menus); + } + + /** + * 根据菜单编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:menu:query')") + @GetMapping(value = "/{menuId}") + public AjaxResult getInfo(@PathVariable Long menuId) { + return success(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @GetMapping("/treeselect") + public AjaxResult treeselect(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return success(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + */ + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(getUserId()); + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); + ajax.put("menus", menuService.buildMenuTreeSelect(menus)); + return ajax; + } + + /** + * 新增菜单 + */ + @PreAuthorize("@ss.hasPermi('system:menu:add')") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysMenu menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + menu.setCreateBy(getUsername()); + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @PreAuthorize("@ss.hasPermi('system:menu:edit')") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysMenu menu) { + if (!menuService.checkMenuNameUnique(menu)) { + return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + + String oldPath = menuService.buildAllRouterPath(menu); + String newPath = menuService.buildAllRouterPath1(menu); + + TUserFavorites tUserFavorites = new TUserFavorites(); + tUserFavorites.setFullPath(newPath); // 新的路由地址 + Wrapper wrapper = new QueryWrapper().eq("full_path", oldPath); // 旧的路由地址 + userFavoritesMapper.update(tUserFavorites, wrapper); + menu.setUpdateBy(getUsername()); + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + */ + @PreAuthorize("@ss.hasPermi('system:menu:remove')") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public AjaxResult remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return warn("菜单已分配,不允许删除"); + } + // 根据条件routerPath等于要删除的菜单的组件路径, 删除userConfig表中的数据 + SysMenu menu1 = menuService.selectMenuById(menuId); + Wrapper wrapper = new QueryWrapper().eq("router_path", menu1.getComponent()); + userConfigMapper.delete(wrapper); + + return toAjax(menuService.deleteMenuById(menuId)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysNoticeController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysNoticeController.java new file mode 100644 index 0000000..2c67681 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysNoticeController.java @@ -0,0 +1,91 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.SysNotice; +import com.zbf.system.service.ISysNoticeService; + +/** + * 公告 信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController +{ + @Autowired + private ISysNoticeService noticeService; + + /** + * 获取通知公告列表 + */ + @PreAuthorize("@ss.hasPermi('system:notice:list')") + @GetMapping("/list") + public TableDataInfo list(SysNotice notice) + { + startPage(); + List list = noticeService.selectNoticeList(notice); + return getDataTable(list); + } + + /** + * 根据通知公告编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:notice:query')") + @GetMapping(value = "/{noticeId}") + public AjaxResult getInfo(@PathVariable Long noticeId) + { + return success(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @PreAuthorize("@ss.hasPermi('system:notice:add')") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysNotice notice) + { + notice.setCreateBy(getUsername()); + return toAjax(noticeService.insertNotice(notice)); + } + + /** + * 修改通知公告 + */ + @PreAuthorize("@ss.hasPermi('system:notice:edit')") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysNotice notice) + { + notice.setUpdateBy(getUsername()); + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + */ + @PreAuthorize("@ss.hasPermi('system:notice:remove')") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public AjaxResult remove(@PathVariable Long[] noticeIds) + { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysPostController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysPostController.java new file mode 100644 index 0000000..4970e1f --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysPostController.java @@ -0,0 +1,129 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.SysPost; +import com.zbf.system.service.ISysPostService; + +/** + * 岗位信息操作处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController +{ + @Autowired + private ISysPostService postService; + + /** + * 获取岗位列表 + */ + @PreAuthorize("@ss.hasPermi('system:post:list')") + @GetMapping("/list") + public TableDataInfo list(SysPost post) + { + startPage(); + List list = postService.selectPostList(post); + return getDataTable(list); + } + + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:post:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysPost post) + { + List list = postService.selectPostList(post); + ExcelUtil util = new ExcelUtil(SysPost.class); + util.exportExcel(response, list, "岗位数据"); + } + + /** + * 根据岗位编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:post:query')") + @GetMapping(value = "/{postId}") + public AjaxResult getInfo(@PathVariable Long postId) + { + return success(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @PreAuthorize("@ss.hasPermi('system:post:add')") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysPost post) + { + if (!postService.checkPostNameUnique(post)) + { + return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } + else if (!postService.checkPostCodeUnique(post)) + { + return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setCreateBy(getUsername()); + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @PreAuthorize("@ss.hasPermi('system:post:edit')") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysPost post) + { + if (!postService.checkPostNameUnique(post)) + { + return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } + else if (!postService.checkPostCodeUnique(post)) + { + return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + post.setUpdateBy(getUsername()); + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + */ + @PreAuthorize("@ss.hasPermi('system:post:remove')") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public AjaxResult remove(@PathVariable Long[] postIds) + { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + */ + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + List posts = postService.selectPostAll(); + return success(posts); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysProfileController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysProfileController.java new file mode 100644 index 0000000..8632d5d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysProfileController.java @@ -0,0 +1,141 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.utils.RsaUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; +import com.zbf.common.annotation.Log; +import com.zbf.common.config.RuoYiConfig; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.file.FileUploadUtils; +import com.zbf.common.utils.file.MimeTypeUtils; +import com.zbf.framework.web.service.TokenService; +import com.zbf.system.service.ISysUserService; + +/** + * 个人信息 业务处理 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController +{ + @Autowired + private ISysUserService userService; + + @Autowired + private TokenService tokenService; + + /** + * 个人信息 + */ + @GetMapping + public AjaxResult profile() + { + LoginUser loginUser = getLoginUser(); + SysUser user = loginUser.getUser(); + AjaxResult ajax = AjaxResult.success(user); + ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername())); + ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername())); + return ajax; + } + + /** + * 修改用户 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult updateProfile(@RequestBody SysUser user) + { + LoginUser loginUser = getLoginUser(); + SysUser currentUser = loginUser.getUser(); + currentUser.setNickName(user.getNickName()); + currentUser.setEmail(user.getEmail()); + currentUser.setPhonenumber(user.getPhonenumber()); + currentUser.setSex(user.getSex()); + if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser)) + { + return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser)) + { + return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在"); + } + if (userService.updateUserProfile(currentUser) > 0) + { + // 更新缓存用户信息 + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public AjaxResult updatePwd(String oldPassword, String newPassword) throws Exception { + LoginUser loginUser = getLoginUser(); + String userName = loginUser.getUsername(); + String password = loginUser.getPassword(); + //解密 + oldPassword = RsaUtils.decryptByPrivateKey(oldPassword); + newPassword = RsaUtils.decryptByPrivateKey(newPassword); + + if (!SecurityUtils.matchesPassword(oldPassword, password)) + { + return error("修改密码失败,旧密码错误"); + } + if (SecurityUtils.matchesPassword(newPassword, password)) + { + return error("新密码不能与旧密码相同"); + } + newPassword = SecurityUtils.encryptPassword(newPassword); + if (userService.resetUserPwd(userName, newPassword) > 0) + { + // 更新缓存用户密码 + loginUser.getUser().setPassword(newPassword); + tokenService.setLoginUser(loginUser); + return success(); + } + return error("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + */ + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping("/avatar") + public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception + { + if (!file.isEmpty()) + { + LoginUser loginUser = getLoginUser(); + String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION); + if (userService.updateUserAvatar(loginUser.getUsername(), avatar)) + { + AjaxResult ajax = AjaxResult.success(); + ajax.put("imgUrl", avatar); + // 更新缓存用户头像 + loginUser.getUser().setAvatar(avatar); + tokenService.setLoginUser(loginUser); + return ajax; + } + } + return error("上传图片异常,请联系管理员"); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysRegisterController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysRegisterController.java new file mode 100644 index 0000000..ab5479f --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysRegisterController.java @@ -0,0 +1,38 @@ +package com.zbf.web.controller.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.model.RegisterBody; +import com.zbf.common.utils.StringUtils; +import com.zbf.framework.web.service.SysRegisterService; +import com.zbf.system.service.ISysConfigService; + +/** + * 注册验证 + * + * @author ruoyi + */ +@RestController +public class SysRegisterController extends BaseController +{ + @Autowired + private SysRegisterService registerService; + + @Autowired + private ISysConfigService configService; + + @PostMapping("/register") + public AjaxResult register(@RequestBody RegisterBody user) + { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) + { + return error("当前系统没有开启注册功能!"); + } + String msg = registerService.register(user); + return StringUtils.isEmpty(msg) ? success() : error(msg); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysRoleController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysRoleController.java new file mode 100644 index 0000000..efc5c2e --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysRoleController.java @@ -0,0 +1,275 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import java.util.UUID; +import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDept; +import com.zbf.common.core.domain.entity.SysRole; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.framework.web.service.SysPermissionService; +import com.zbf.framework.web.service.TokenService; +import com.zbf.system.domain.SysUserRole; +import com.zbf.system.service.ISysDeptService; +import com.zbf.system.service.ISysRoleService; +import com.zbf.system.service.ISysUserService; + +/** + * 角色信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController +{ + @Autowired + private ISysRoleService roleService; + + @Autowired + private TokenService tokenService; + + @Autowired + private SysPermissionService permissionService; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysDeptService deptService; + + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/list") + public TableDataInfo list(SysRole role) + { + startPage(); + List list = roleService.selectRoleList(role); + return getDataTable(list); + } + + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:role:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysRole role) + { + List list = roleService.selectRoleList(role); + ExcelUtil util = new ExcelUtil(SysRole.class); + util.exportExcel(response, list, "角色数据"); + } + + /** + * 根据角色顺序最大值 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/selectMaxRoleSort") + public AjaxResult queryMaxRoleSort() + { + return success(roleService.selectMaxRoleSort()); + } + + /** + * 根据角色编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/{roleId}") + public AjaxResult getInfo(@PathVariable Long roleId) + { + roleService.checkRoleDataScope(roleId); + return success(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @PreAuthorize("@ss.hasPermi('system:role:add')") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysRole role) + { + UUID uuid = UUID.randomUUID(); + role.setRoleKey(String.valueOf(uuid)); + roleService.checkRoleAllowed(role); + if (!roleService.checkRoleNameUnique(role)) + { + return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } + else if (!roleService.checkRoleKeyUnique(role)) + { + return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setCreateBy(getUsername()); + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改保存角色 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysRole role) + { + roleService.checkRoleDataScope(role.getRoleId()); + if (!roleService.checkRoleNameUnique(role)) + { + return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } + else if (!roleService.checkRoleKeyUnique(role)) + { + return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + role.setUpdateBy(getUsername()); + + if (roleService.updateRole(role) > 0) + { + // 更新缓存用户权限 + LoginUser loginUser = getLoginUser(); + if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) + { + loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser())); + loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName())); + tokenService.setLoginUser(loginUser); + } + return success(); + } + return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改保存数据权限 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public AjaxResult dataScope(@RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysRole role) + { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + role.setUpdateBy(getUsername()); + return toAjax(roleService.updateRoleStatus(role)); + } + + /** + * 删除角色 + */ + @PreAuthorize("@ss.hasPermi('system:role:remove')") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public AjaxResult remove(@PathVariable Long[] roleIds) + { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + /** + * 获取角色选择框列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping("/optionselect") + public AjaxResult optionselect() + { + return success(roleService.selectRoleAll()); + } + + /** + * 查询已分配用户角色列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user) + { + startPage(); + List list = userService.selectAllocatedList(user); + return getDataTable(list); + } + + /** + * 查询未分配用户角色列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:list')") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user) + { + startPage(); + List list = userService.selectUnallocatedList(user); + return getDataTable(list); + } + + /** + * 取消授权用户 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole) + { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds) + { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + */ + @PreAuthorize("@ss.hasPermi('system:role:edit')") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds) + { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + */ + @PreAuthorize("@ss.hasPermi('system:role:query')") + @GetMapping(value = "/deptTree/{roleId}") + public AjaxResult deptTree(@PathVariable("roleId") Long roleId) + { + AjaxResult ajax = AjaxResult.success(); + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); + ajax.put("depts", deptService.selectDeptTreeList(new SysDept())); + return ajax; + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserBusinessColumnController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserBusinessColumnController.java new file mode 100644 index 0000000..6acbf23 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserBusinessColumnController.java @@ -0,0 +1,144 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.SysUserBusinessColumn; +import com.zbf.system.service.ISysUserBusinessColumnService; + +/** + * 用户展示字段定义管理Controller + * + * @author tony + * @date 2024-06-16 + */ +@RestController +@RequestMapping("/system/COLUMN") +public class SysUserBusinessColumnController extends BaseController +{ + @Autowired + private ISysUserBusinessColumnService sysUserBusinessColumnService; + +/** + * 查询用户展示字段定义管理列表 + */ +@GetMapping("/list") + public TableDataInfo list(SysUserBusinessColumn sysUserBusinessColumn) + { + startPage(); + List list = sysUserBusinessColumnService.selectSysUserBusinessColumnList(sysUserBusinessColumn); + return getDataTable(list); + } + + /** + * 导出用户展示字段定义管理列表 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SysUserBusinessColumn sysUserBusinessColumn) + { + List list = sysUserBusinessColumnService.selectSysUserBusinessColumnList(sysUserBusinessColumn); + ExcelUtil util = new ExcelUtil(SysUserBusinessColumn.class); + util.exportExcel(response, list, "用户展示字段定义管理数据"); + } + + /** + * 获取用户展示字段定义管理详细信息 + */ + @GetMapping(value = "/{ID}") + public AjaxResult getInfo(@PathVariable("ID") Long ID) + { + return success(sysUserBusinessColumnService.selectSysUserBusinessColumnByID(ID)); + } + + /** + * 新增用户展示字段定义管理 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody SysUserBusinessColumn sysUserBusinessColumn) + { + return toAjax(sysUserBusinessColumnService.insertSysUserBusinessColumn(sysUserBusinessColumn)); + } + + /** + * 修改用户展示字段定义管理 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody SysUserBusinessColumn sysUserBusinessColumn) + { + String userName = getLoginUser().getUsername(); + String hideColumn = sysUserBusinessColumn.getColumnHide(); + sysUserBusinessColumn.setColumnHide(""); + sysUserBusinessColumn.setUserName(userName); + List result = sysUserBusinessColumnService.selectSysUserBusinessColumnList(sysUserBusinessColumn); + + if (result.size() == 0) { + sysUserBusinessColumn.setColumnHide(hideColumn); + return toAjax(sysUserBusinessColumnService.insertSysUserBusinessColumn(sysUserBusinessColumn)); + } + SysUserBusinessColumn updateRecord = result.get(0); + updateRecord.setColumnHide(hideColumn); + return toAjax(sysUserBusinessColumnService.updateSysUserBusinessColumn(updateRecord)); + } + + /** + * 删除用户展示字段定义管理 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{IDs}") + public AjaxResult remove(@PathVariable Long[] IDs) + { + return toAjax(sysUserBusinessColumnService.deleteSysUserBusinessColumnByIDs(IDs)); + } + + /** + * 启用 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{IDs}") + public AjaxResult disable(@PathVariable Long[] IDs) + { + return toAjax(sysUserBusinessColumnService.disabledSysUserBusinessColumnByIDs(IDs)); + } + + /** + * 禁用 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{IDs}") + public AjaxResult enable(@PathVariable Long[] IDs) + { + return toAjax(sysUserBusinessColumnService.enableSysUserBusinessColumnByIDs(IDs)); + } + + /** + * 修改状态 + */ + @Log(title = "用户展示字段定义管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysUserBusinessColumn sysUserBusinessColumn) { + return toAjax(sysUserBusinessColumnService.updateStatus(sysUserBusinessColumn)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserController.java new file mode 100644 index 0000000..b36719d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/SysUserController.java @@ -0,0 +1,302 @@ +package com.zbf.web.controller.system; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDept; +import com.zbf.common.core.domain.entity.SysRole; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.service.ISysDeptService; +import com.zbf.system.service.ISysPostService; +import com.zbf.system.service.ISysRoleService; +import com.zbf.system.service.ISysUserService; + +/** + * 用户信息 + * + * @author ruoyi + */ +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController +{ + @Autowired + private ISysUserService userService; + + @Autowired + private ISysRoleService roleService; + + @Autowired + private ISysDeptService deptService; + + @Autowired + private ISysPostService postService; + + /** + * 获取用户列表 + */ +// @PreAuthorize("@ss.hasPermi('system:user:list')") + @GetMapping("/list") + public TableDataInfo list(SysUser user) + { + startPage(); + List list = userService.selectUserList(user); + return getDataTable(list); + } + + // @PreAuthorize("@ss.hasPermi('system:user:list')") + //专门查询第三审核人的,其他需求慎用 + @GetMapping("/queryUserList") + public AjaxResult queryList(SysUser user) + { + user.setDeptId(getDeptId()); + List sysUsers = userService.queryUserList(user);for(SysUser user1:sysUsers){ + user1.setRoles(null); + user1.setFirstAuditList(null); + user1.setSecondAuditList(null); + user1.setPassword(null); + } + return success(sysUsers); + } + + @GetMapping("/queryAuditUserList") + public AjaxResult queryAuditUserList() + { + SysUser user = new SysUser(); + + // user.setDeptId(getDeptId()); + logger.info("申请获取审批人的登录人为:{}",getLoginUser().getUsername()); + String ancestors = getLoginUser().getUser().getDept().getAncestors(); + user.setDeptId(getDeptId()); + if (ancestors.split(",").length == 4){ + user.setDeptId(Long.parseLong(ancestors.split(",")[3])); + } + + logger.info("获取的部门id:{}",user.getDeptId()); + + if(user.getDeptId() == null){ + throw new RuntimeException("获取该用户部门ID为空异常"); + } + + user.setUserId(getUserId()); + user.setAuditType(1); + List sysUsers1 = userService.queryAuditUserList(user); + + user.setAuditType(2); + List sysUsers2 = userService.queryAuditUserList(user); + Map> listMap = new HashMap<>(); + listMap.put("audit1",sysUsers1); + listMap.put("audit2",sysUsers2); + return success(listMap); + } + + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('system:user:export')") + @PostMapping("/export") + public void export(HttpServletResponse response, SysUser user) + { + List list = userService.selectUserList(user); + ExcelUtil util = new ExcelUtil(SysUser.class); + util.exportExcel(response, list, "用户数据"); + } + + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:user:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { + ExcelUtil util = new ExcelUtil(SysUser.class); + List userList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = userService.importUser(userList, updateSupport, operName); + return success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(SysUser.class); + util.importTemplateExcel(response, "用户数据"); + } + + /** + * 根据用户编号获取详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping(value = { "/", "/{userId}" }) + public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) + { + userService.checkUserDataScope(userId); + AjaxResult ajax = AjaxResult.success(); + List roles = roleService.selectRoleAll(); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + ajax.put("posts", postService.selectPostAll()); + if (StringUtils.isNotNull(userId)) + { + SysUser sysUser = userService.selectUserById(userId); + ajax.put(AjaxResult.DATA_TAG, sysUser); + ajax.put("postIds", postService.selectPostListByUserId(userId)); + ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); + } + return ajax; + } + + /** + * 新增用户 + */ + @PreAuthorize("@ss.hasPermi('system:user:add')") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@Validated @RequestBody SysUser user) + { + if (!userService.checkUserNameUnique(user)) + { + return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } + else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) + { + return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) + { + return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setCreateBy(getUsername()); + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@Validated @RequestBody SysUser user) + { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + if (!userService.checkUserNameUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } + else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) + { + return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUpdateBy(getUsername()); + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + */ + @PreAuthorize("@ss.hasPermi('system:user:remove')") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public AjaxResult remove(@PathVariable Long[] userIds) + { + if (ArrayUtils.contains(userIds, getUserId())) + { + return error("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 重置密码 + */ + @PreAuthorize("@ss.hasPermi('system:user:resetPwd')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public AjaxResult resetPwd(@RequestBody SysUser user) + { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); + user.setUpdateBy(getUsername()); + return toAjax(userService.resetPwd(user)); + } + + /** + * 状态修改 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody SysUser user) + { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setUpdateBy(getUsername()); + return toAjax(userService.updateUserStatus(user)); + } + + /** + * 根据用户编号获取授权角色 + */ + @PreAuthorize("@ss.hasPermi('system:user:query')") + @GetMapping("/authRole/{userId}") + public AjaxResult authRole(@PathVariable("userId") Long userId) + { + AjaxResult ajax = AjaxResult.success(); + SysUser user = userService.selectUserById(userId); + List roles = roleService.selectRolesByUserId(userId); + ajax.put("user", user); + ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + return ajax; + } + + /** + * 用户授权角色 + */ + @PreAuthorize("@ss.hasPermi('system:user:edit')") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) + { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return success(); + } + + /** + * 获取部门树列表 + */ + @PreAuthorize("@ss.hasPermi('system:user:list')") + @GetMapping("/deptTree") + public AjaxResult deptTree() + { + return success(deptService.selectDeptTreeList(new SysDept())); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TAgvController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TAgvController.java new file mode 100644 index 0000000..bb6e18e --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TAgvController.java @@ -0,0 +1,135 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.zbf.common.annotation.Anonymous; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TAgv; +import com.zbf.system.service.ITAgvService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * agv列表Controller + * + * @author tony + * @date 2024-06-17 + */ +@CrossOrigin +@RestController +@RequestMapping("/system/agv") +public class TAgvController extends BaseController +{ + @Autowired + private ITAgvService tAgvService; + +/** + * 查询agv列表列表 + */ +@GetMapping("/list") + public TableDataInfo list(TAgv tAgv) + { + startPage(); + List list = tAgvService.selectTAgvList(tAgv); + return getDataTable(list); + } + + /** + * 导出agv列表列表 + */ +/* + @PreAuthorize("@ss.hasPermi('system:agv:export')") +*/ + @Log(title = "agv列表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TAgv tAgv) + { + List list = tAgvService.selectTAgvList(tAgv); + ExcelUtil util = new ExcelUtil(TAgv.class); + util.exportExcel(response, list, "agv列表数据"); + } + + /** + * 获取agv列表详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:agv:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(tAgvService.selectTAgvById(id)); + } + + /** + * 新增agv列表 + */ + @PreAuthorize("@ss.hasPermi('system:agv:add')") + @Log(title = "agv列表", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TAgv tAgv) + { + return toAjax(tAgvService.insertTAgv(tAgv)); + } + + /** + * 修改agv列表 + */ + @PreAuthorize("@ss.hasPermi('system:agv:edit')") + @Log(title = "agv列表", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TAgv tAgv) + { + return toAjax(tAgvService.updateTAgv(tAgv)); + } + + /** + * 删除agv列表 + */ + @PreAuthorize("@ss.hasPermi('system:agv:remove')") + @Log(title = "agv列表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(tAgvService.deleteTAgvByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:agv:remove')") + @Log(title = "agv列表", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(tAgvService.disabledTAgvByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:agv:edit')") + @Log(title = "agv列表", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(tAgvService.enableTAgvByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:agv:edit')") + @Log(title = "agv列表", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TAgv tAgv) { + return toAjax(tAgvService.updateStatus(tAgv)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseFinancialClassController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseFinancialClassController.java new file mode 100644 index 0000000..e361d61 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseFinancialClassController.java @@ -0,0 +1,131 @@ +package com.zbf.web.controller.system; + +import cn.hutool.json.JSONArray; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.generator.util.ColumnUtils; +import com.zbf.system.domain.TBaseFinancialClass; +import com.zbf.system.domain.TBasePallet; +import com.zbf.system.service.ITBaseFinancialClassService; +import liquibase.pro.packaged.S; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 财务分类Controller + * + * @author sunits + * @date 2024-06-28 + */ +@RestController +@RequestMapping("/system/financialClass") +public class TBaseFinancialClassController extends BaseController { + @Autowired + private ITBaseFinancialClassService tBaseFinancialClassService; + + /** + * 查询财务分类列表 + */ + //@PreAuthorize("@ss.hasPermi('system:financialClass:list')") + @GetMapping("/list") + public AjaxResult list(TBaseFinancialClass tBaseFinancialClass) { + Map map = new HashMap(); + JSONArray columns = ColumnUtils.getColumnsJson(TBaseFinancialClass.class); + List list = tBaseFinancialClassService.selectTBaseFinancialClassList(tBaseFinancialClass); + map.put("list",list); + map.put("columns",columns); + return success(map); + } + + /** + * 导出财务分类列表 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:export')") + @Log(title = "财务分类", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseFinancialClass tBaseFinancialClass) { + List list = tBaseFinancialClassService.selectTBaseFinancialClassList(tBaseFinancialClass); + ExcelUtil util = new ExcelUtil(TBaseFinancialClass.class); + util.exportExcel(response, list, "财务分类数据"); + } + + /** + * 获取财务分类详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBaseFinancialClassService.selectTBaseFinancialClassById(id)); + } + + /** + * 新增财务分类 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:add')") + @Log(title = "财务分类", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseFinancialClass tBaseFinancialClass) { + return toAjax(tBaseFinancialClassService.insertTBaseFinancialClass(tBaseFinancialClass)); + } + + /** + * 修改财务分类 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:edit')") + @Log(title = "财务分类", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseFinancialClass tBaseFinancialClass) { + return toAjax(tBaseFinancialClassService.updateTBaseFinancialClass(tBaseFinancialClass)); + } + + /** + * 删除财务分类 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:remove')") + @Log(title = "财务分类", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tBaseFinancialClassService.deleteTBaseFinancialClassByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:remove')") + @Log(title = "财务分类", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBaseFinancialClassService.disabledTBaseFinancialClassByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:edit')") + @Log(title = "财务分类", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBaseFinancialClassService.enableTBaseFinancialClassByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:financialClass:edit')") + @Log(title = "财务分类", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TBaseFinancialClass tBaseFinancialClass) { + return toAjax(tBaseFinancialClassService.updateStatus(tBaseFinancialClass)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsBomController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsBomController.java new file mode 100644 index 0000000..e8bb57d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsBomController.java @@ -0,0 +1,132 @@ +package com.zbf.web.controller.system; + +import java.util.HashMap; +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TBaseGoodsBom; +import com.zbf.system.service.ITBaseGoodsBomService; +import com.zbf.common.utils.poi.ExcelUtil; + +/** + * 物料bomController + * + * @author tony + * @date 2024-06-16 + */ +@RestController +@RequestMapping("/system/bom") +public class TBaseGoodsBomController extends BaseController { + @Autowired + private ITBaseGoodsBomService tBaseGoodsBomService; + + /** + * 查询物料bom列表 + */ + @PreAuthorize("@ss.hasPermi('system:bom:list')") + @GetMapping("/list") + public AjaxResult list(TBaseGoodsBom tBaseGoodsBom) { + HashMap map = new HashMap<>(); + List list = tBaseGoodsBomService.selectTBaseGoodsBomList(tBaseGoodsBom); + map.put("list", list); + map.put("column", tBaseGoodsBom.getColumnsJson()); + return success(map); + } + + /** + * 导出物料bom列表 + */ + @PreAuthorize("@ss.hasPermi('system:bom:export')") + @Log(title = "物料bom", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseGoodsBom tBaseGoodsBom) { + List list = tBaseGoodsBomService.selectTBaseGoodsBomList(tBaseGoodsBom); + ExcelUtil util = new ExcelUtil(TBaseGoodsBom.class); + util.exportExcel(response, list, "物料bom数据"); + } + + /** + * 获取物料bom详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:bom:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBaseGoodsBomService.selectTBaseGoodsBomById(id)); + } + + /** + * 新增物料bom + */ + @PreAuthorize("@ss.hasPermi('system:bom:add')") + @Log(title = "物料bom", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseGoodsBom tBaseGoodsBom) { + return toAjax(tBaseGoodsBomService.insertTBaseGoodsBom(tBaseGoodsBom)); + } + + /** + * 修改物料bom + */ + @PreAuthorize("@ss.hasPermi('system:bom:edit')") + @Log(title = "物料bom", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseGoodsBom tBaseGoodsBom) { + return toAjax(tBaseGoodsBomService.updateTBaseGoodsBom(tBaseGoodsBom)); + } + + /** + * 删除物料bom + */ + @PreAuthorize("@ss.hasPermi('system:bom:remove')") + @Log(title = "物料bom", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tBaseGoodsBomService.deleteTBaseGoodsBomByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:bom:remove')") + @Log(title = "物料bom", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBaseGoodsBomService.disabledTBaseGoodsBomByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:bom:edit')") + @Log(title = "物料bom", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBaseGoodsBomService.enableTBaseGoodsBomByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:bom:edit')") + @Log(title = "物料bom", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TBaseGoodsBom tBaseGoodsBom) { + return toAjax(tBaseGoodsBomService.updateStatus(tBaseGoodsBom)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsController.java new file mode 100644 index 0000000..3f5aa5d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseGoodsController.java @@ -0,0 +1,169 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBaseGoods; +import com.zbf.system.service.ITBaseGoodsService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 物料Controller + * + * @author sunits + * @date 2024-06-15 + */ +@RestController +@RequestMapping("/system/goods") +public class TBaseGoodsController extends BaseController { + @Autowired + private ITBaseGoodsService tBaseGoodsService; + + /** + * 查询物料列表 + */ + @PreAuthorize("@ss.hasPermi('system:goods:list')") + @GetMapping("/list") + public TableDataInfo list(TBaseGoods tBaseGoods) { + startPage(); + List list = tBaseGoodsService.selectTBaseGoodsList(tBaseGoods); + TableDataInfo dataTable = getDataTable(list); + dataTable.setColumns(tBaseGoods.getColumnsJson()); + return dataTable; + } + + /** + * 导出物料列表 + */ + @PreAuthorize("@ss.hasPermi('system:goods:export')") + @Log(title = "物料", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseGoods tBaseGoods) { + List list = tBaseGoodsService.selectTBaseGoodsList(tBaseGoods); + ExcelUtil util = new ExcelUtil(TBaseGoods.class); + util.exportExcel(response, list, "物料数据"); + } + + /** + * 获取物料详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:goods:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBaseGoodsService.selectTBaseGoodsById(id)); + } + + /** + * 新增物料 + */ + @PreAuthorize("@ss.hasPermi('system:goods:add')") + @Log(title = "物料", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseGoods tBaseGoods) { + logger.info("请求插入物料:{}", tBaseGoods); + if (StringUtils.isBlank(tBaseGoods.getGoodsId())) { + logger.error("物料编号不能为空"); + throw new RuntimeException("物料编号不能为空"); + } + if (StringUtils.isBlank(tBaseGoods.getGoodsName())) { + logger.error("物料名称不能为空"); + throw new RuntimeException("物料名称不能为空"); + } + if (StringUtils.isBlank(tBaseGoods.getUnit())) { + logger.error("单位不能为空"); + throw new RuntimeException("单位不能为空"); + } + return toAjax(tBaseGoodsService.insertTBaseGoods(tBaseGoods)); + } + + /** + * 修改物料 + */ + @PreAuthorize("@ss.hasPermi('system:goods:edit')") + @Log(title = "物料", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseGoods tBaseGoods) { + logger.info("更改物料信息:{}", tBaseGoods); + return toAjax(tBaseGoodsService.updateTBaseGoods(tBaseGoods)); + } + + /** + * 删除物料 + */ + @PreAuthorize("@ss.hasPermi('system:goods:remove')") + @Log(title = "物料", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + logger.info("删除物料信息:{}", ids); + return toAjax(tBaseGoodsService.deleteTBaseGoodsByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:goods:remove')") + @Log(title = "物料", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBaseGoodsService.disabledTBaseGoodsByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:goods:edit')") + @Log(title = "物料", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBaseGoodsService.enableTBaseGoodsByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:goods:edit')") + @Log(title = "物料", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TBaseGoods tBaseGoods) { + return toAjax(tBaseGoodsService.updateStatus(tBaseGoods)); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil(TBaseGoods.class); + util.importTemplateExcel(response, "物料数据"); + } + + @Log(title = "物料", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:goods:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + ExcelUtil util = new ExcelUtil(TBaseGoods.class); + List importList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = tBaseGoodsService.importData(importList, updateSupport, operName); + return success(message); + } + + @Log(title = "存入RFID", businessType = BusinessType.INSERT) + @PostMapping("/saveRfid") + public AjaxResult saveRfid(@RequestBody TBaseGoods goods) { + int i = tBaseGoodsService.saveRfid(goods); + if (i > 0) { + return AjaxResult.success(); + } + return AjaxResult.error(); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBasePalletController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBasePalletController.java new file mode 100644 index 0000000..257bfa4 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBasePalletController.java @@ -0,0 +1,141 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBasePallet; +import com.zbf.system.domain.TBaseStorageAreaLocation; +import com.zbf.system.service.ITBasePalletService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 托盘Controller + * + * @author sunits + * @date 2024-06-16 + */ +@RestController +@RequestMapping("/system/pallet") +public class TBasePalletController extends BaseController { + @Autowired + private ITBasePalletService tBasePalletService; + + /** + * 查询托盘列表 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:list')") + @GetMapping("/list") + public TableDataInfo list(TBasePallet tBasePallet) { + startPage(); + List list = tBasePalletService.selectTBasePalletList(tBasePallet); + TableDataInfo dataTable = getDataTable(list); + dataTable.setColumns(tBasePallet.getColumnsJson()); + return dataTable; + } + + /** + * 导出托盘列表 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:export')") + @Log(title = "托盘", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBasePallet tBasePallet) { + List list = tBasePalletService.selectTBasePalletList(tBasePallet); + ExcelUtil util = new ExcelUtil(TBasePallet.class); + util.exportExcel(response, list, "托盘数据"); + } + + /** + * 获取托盘详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBasePalletService.selectTBasePalletById(id)); + } + + /** + * 新增托盘 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:add')") + @Log(title = "托盘", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBasePallet tBasePallet) { + return toAjax(tBasePalletService.insertTBasePallet(tBasePallet)); + } + + /** + * 修改托盘 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:edit')") + @Log(title = "托盘", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBasePallet tBasePallet) { + return toAjax(tBasePalletService.updateTBasePallet(tBasePallet)); + } + + /** + * 删除托盘 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:remove')") + @Log(title = "托盘", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tBasePalletService.deleteTBasePalletByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:remove')") + @Log(title = "托盘", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBasePalletService.disabledTBasePalletByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:pallet:edit')") + @Log(title = "托盘", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBasePalletService.enableTBasePalletByIds(ids)); + } + + /** + * 更改禁用状态 + */ + @Log(title = "托盘管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus/{ids}") + public AjaxResult changeStatus(@PathVariable Long[] ids,@RequestBody TBasePallet tBasePallet) { + return toAjax(tBasePalletService.changeStatus(ids,tBasePallet)); + } + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil(TBasePallet.class); + util.importTemplateExcel(response, "托盘数据"); + } + + @Log(title = "托盘", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:pallet:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + ExcelUtil util = new ExcelUtil(TBasePallet.class); + List importList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = tBasePalletService.importData(importList, updateSupport, operName); + return success(message); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseProviderController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseProviderController.java new file mode 100644 index 0000000..a5acce9 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseProviderController.java @@ -0,0 +1,142 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBaseProvider; +import com.zbf.system.service.ITBaseProviderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 供应商管理Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/provider") +public class TBaseProviderController extends BaseController { + @Autowired + private ITBaseProviderService tBaseProviderService; + + /** + * 查询供应商管理列表 + */ + @PreAuthorize("@ss.hasPermi('system:provider:list')") + @GetMapping("/list") + public TableDataInfo list(TBaseProvider tBaseProvider) { + startPage(); + List list = tBaseProviderService.selectTBaseProviderList(tBaseProvider); + TableDataInfo dataTable = getDataTable(list); + dataTable.setColumns(tBaseProvider.getColumnsJson()); + return dataTable; + } + + /** + * 导出供应商管理列表 + */ + @PreAuthorize("@ss.hasPermi('system:provider:export')") + @Log(title = "供应商管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseProvider tBaseProvider) { + List list = tBaseProviderService.selectTBaseProviderList(tBaseProvider); + ExcelUtil util = new ExcelUtil(TBaseProvider.class); + util.exportExcel(response, list, "供应商管理数据"); + } + + /** + * 获取供应商管理详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:provider:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBaseProviderService.selectTBaseProviderById(id)); + } + + /** + * 新增供应商管理 + */ + @PreAuthorize("@ss.hasPermi('system:provider:add')") + @Log(title = "供应商管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseProvider tBaseProvider) { + return toAjax(tBaseProviderService.insertTBaseProvider(tBaseProvider)); + } + + /** + * 修改供应商管理 + */ + @PreAuthorize("@ss.hasPermi('system:provider:edit')") + @Log(title = "供应商管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseProvider tBaseProvider) { + return toAjax(tBaseProviderService.updateTBaseProvider(tBaseProvider)); + } + + /** + * 删除供应商管理 + */ + @PreAuthorize("@ss.hasPermi('system:provider:remove')") + @Log(title = "供应商管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tBaseProviderService.deleteTBaseProviderByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:provider:remove')") + @Log(title = "供应商管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBaseProviderService.disabledTBaseProviderByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:provider:edit')") + @Log(title = "供应商管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBaseProviderService.enableTBaseProviderByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:provider:edit')") + @Log(title = "供应商管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TBaseProvider tBaseProvider) { + return toAjax(tBaseProviderService.updateStatus(tBaseProvider)); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil(TBaseProvider.class); + util.importTemplateExcel(response, "供应商数据"); + } + + @Log(title = "供应商管理", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:provider:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + ExcelUtil util = new ExcelUtil(TBaseProvider.class); + List importList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = tBaseProviderService.importData(importList, updateSupport, operName); + return success(message); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaController.java new file mode 100644 index 0000000..d5d13ea --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaController.java @@ -0,0 +1,125 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBaseStorageArea; +import com.zbf.system.service.ITBaseStorageAreaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 仓库库区Controller + * + * @author tony + * @date 2024-06-16 + */ +@RestController +@RequestMapping("/system/storageArea") +public class TBaseStorageAreaController extends BaseController { + @Autowired + private ITBaseStorageAreaService tBaseStorageAreaService; + + /** + * 查询仓库库区列表 + */ + //@PreAuthorize("@ss.hasPermi('system:area:list')") + @GetMapping("/list") + public TableDataInfo list(TBaseStorageArea tBaseStorageArea) { + startPage(); + List list = tBaseStorageAreaService.selectTBaseStorageAreaList(tBaseStorageArea); + TableDataInfo dataTable = getDataTable(list); + dataTable.setColumns(tBaseStorageArea.getColumnsJson()); + return dataTable; + } + + /** + * 导出仓库库区列表 + */ + @PreAuthorize("@ss.hasPermi('system:area:export')") + @Log(title = "仓库库区", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseStorageArea tBaseStorageArea) { + List list = tBaseStorageAreaService.selectTBaseStorageAreaList(tBaseStorageArea); + ExcelUtil util = new ExcelUtil(TBaseStorageArea.class); + util.exportExcel(response, list, "仓库库区数据"); + } + + /** + * 获取仓库库区详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:area:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBaseStorageAreaService.selectTBaseStorageAreaById(id)); + } + + /** + * 新增仓库库区 + */ + @PreAuthorize("@ss.hasPermi('system:area:add')") + @Log(title = "仓库库区", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseStorageArea tBaseStorageArea) { + return toAjax(tBaseStorageAreaService.insertTBaseStorageArea(tBaseStorageArea)); + } + + /** + * 修改仓库库区 + */ + @PreAuthorize("@ss.hasPermi('system:area:edit')") + @Log(title = "仓库库区", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseStorageArea tBaseStorageArea) { + return toAjax(tBaseStorageAreaService.updateTBaseStorageArea(tBaseStorageArea)); + } + + /** + * 删除仓库库区 + */ + @PreAuthorize("@ss.hasPermi('system:area:remove')") + @Log(title = "仓库库区", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tBaseStorageAreaService.deleteTBaseStorageAreaByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:area:remove')") + @Log(title = "仓库库区", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBaseStorageAreaService.disabledTBaseStorageAreaByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:area:edit')") + @Log(title = "仓库库区", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBaseStorageAreaService.enableTBaseStorageAreaByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:area:edit')") + @Log(title = "仓库库区", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TBaseStorageArea tBaseStorageArea) { + return toAjax(tBaseStorageAreaService.updateStatus(tBaseStorageArea)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaLocationController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaLocationController.java new file mode 100644 index 0000000..7a75cdf --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageAreaLocationController.java @@ -0,0 +1,171 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.DataScope; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBasePallet; +import com.zbf.system.domain.TBaseStorage; +import com.zbf.system.domain.TBaseStorageArea; +import com.zbf.system.domain.TBaseStorageAreaLocation; +import com.zbf.system.service.ITBaseStorageAreaLocationService; +import com.zbf.system.service.ITBaseStorageAreaService; +import com.zbf.system.service.ITBaseStorageService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 库位 Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/location") +public class TBaseStorageAreaLocationController extends BaseController { + + private ITBaseStorageAreaLocationService tBaseStorageAreaLocationService; + private ITBaseStorageAreaService baseStorageAreaService; + + public TBaseStorageAreaLocationController(ITBaseStorageAreaLocationService tBaseStorageAreaLocationService, ITBaseStorageAreaService baseStorageAreaService) { + this.tBaseStorageAreaLocationService = tBaseStorageAreaLocationService; + this.baseStorageAreaService = baseStorageAreaService; + } + + /** + * 根据当前用的数据权限,查询所管理的仓库信息 + * @param tBaseStorageArea + * @return + */ + @PreAuthorize("@ss.hasPermi('system:location:list')") + @GetMapping("/getStorageAreaList") + public AjaxResult getStorageAreaList(TBaseStorageArea tBaseStorageArea) { + return success(baseStorageAreaService.getBaseStorageAreaList(tBaseStorageArea)); + } + + /** + * 查询库位 列表 + */ + @PreAuthorize("@ss.hasPermi('system:location:list')") + @GetMapping("/list") + public TableDataInfo list(TBaseStorageAreaLocation tBaseStorageAreaLocation) { + startPage(); + List list = tBaseStorageAreaLocationService.selectTBaseStorageAreaLocationList(tBaseStorageAreaLocation); + TableDataInfo dataTable = getDataTable(list); + dataTable.setColumns(tBaseStorageAreaLocation.getColumnsJson()); + return dataTable; + } + + /** + * 查询库位占用 + */ + @PreAuthorize("@ss.hasPermi('system:location:list')") + @GetMapping("/occupy") + public AjaxResult occupy() { + logger.info("调用库位占用接口"); + return success(tBaseStorageAreaLocationService.occupy()); + } + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:provider:remove')") + @Log(title = "库位管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(tBaseStorageAreaLocationService.disabledTBaseStorageAreaLocationByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:provider:edit')") + @Log(title = "库位管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(tBaseStorageAreaLocationService.enableTBaseStorageAreaLocationByIds(ids)); + } + + + /** + * 更改禁用状态 + */ + @Log(title = "库位管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus/{ids}") + public AjaxResult changeStatus(@PathVariable Long[] ids,@RequestBody TBaseStorageAreaLocation tBaseStorageAreaLocation) { + return toAjax(tBaseStorageAreaLocationService.changeStatus(ids,tBaseStorageAreaLocation)); + } + /** + * 导出库位 列表 + */ + @PreAuthorize("@ss.hasPermi('system:location:export')") + @Log(title = "库位 ", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseStorageAreaLocation tBaseStorageAreaLocation) { + List list = tBaseStorageAreaLocationService.selectTBaseStorageAreaLocationList(tBaseStorageAreaLocation); + ExcelUtil util = new ExcelUtil(TBaseStorageAreaLocation.class); + util.exportExcel(response, list, "库位 数据"); + } + + /** + * 获取库位 详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:location:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tBaseStorageAreaLocationService.selectTBaseStorageAreaLocationById(id)); + } + + /** + * 新增库位 + */ + @PreAuthorize("@ss.hasPermi('system:location:add')") + @Log(title = "库位 ", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseStorageAreaLocation tBaseStorageAreaLocation) { + return toAjax(tBaseStorageAreaLocationService.insertTBaseStorageAreaLocation(tBaseStorageAreaLocation)); + } + + /** + * 修改库位 + */ + @PreAuthorize("@ss.hasPermi('system:location:edit')") + @Log(title = "库位 ", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseStorageAreaLocation tBaseStorageAreaLocation) { + return toAjax(tBaseStorageAreaLocationService.updateTBaseStorageAreaLocation(tBaseStorageAreaLocation)); + } + + /** + * 删除库位 + */ + @PreAuthorize("@ss.hasPermi('system:location:remove')") + @Log(title = "库位 ", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tBaseStorageAreaLocationService.deleteTBaseStorageAreaLocationByIds(ids)); + } + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil(TBaseStorageAreaLocation.class); + util.importTemplateExcel(response, "库位数据"); + } + + @Log(title = "库位", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:location:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + ExcelUtil util = new ExcelUtil(TBaseStorageAreaLocation.class); + List importList = util.importExcel(file.getInputStream()); + String operName = getUsername(); + String message = tBaseStorageAreaLocationService.importData(importList, updateSupport, operName); + return success(message); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageController.java new file mode 100644 index 0000000..465b404 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TBaseStorageController.java @@ -0,0 +1,176 @@ +package com.zbf.web.controller.system; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import cn.hutool.json.JSONArray; +import com.zbf.generator.util.ColumnUtils; +import com.zbf.web.controller.section.EnhanceDataList; +import com.zbf.web.controller.section.ListColumns; +import liquibase.pro.packaged.S; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBaseStorage; +import com.zbf.system.domain.TBaseStorageLocationRecord; +import com.zbf.system.service.ITBaseStorageService; + +/** + * 仓库管理Controller + * + * @author tony + * @date 2024-06-19 + */ +@RestController +@RequestMapping("/system/storage") +public class TBaseStorageController extends BaseController +{ + @Autowired + private ITBaseStorageService tBaseStorageService; + + /** + * 查询仓库管理列表 + */ + @PreAuthorize("@ss.hasPermi('system:storage:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TBaseStorage.class) + public TableDataInfo list(TBaseStorage tBaseStorage) + { + + List list = tBaseStorageService.selectTBaseStorageList(tBaseStorage); + TableDataInfo dataTable = getDataTable(list); + return dataTable; // 直接返回处理后的TableDataInfo对象 + } + /** + * 查询仓库管理列表 + */ + @GetMapping("/selectList") + public AjaxResult selectList(TBaseStorage tBaseStorage) + { + tBaseStorage.setDeptId(getDeptId()); + List list = tBaseStorageService.selectTBaseStorageList(tBaseStorage); + return success(list); + } + + /** + * 导出仓库管理列表 + */ + @PreAuthorize("@ss.hasPermi('system:storage:export')") + @Log(title = "仓库管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TBaseStorage tBaseStorage) + { + List list = tBaseStorageService.selectTBaseStorageList(tBaseStorage); + ExcelUtil util = new ExcelUtil(TBaseStorage.class); + util.exportExcel(response, list, "仓库管理数据"); + } + + /** + * 获取仓库管理详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:storage:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(tBaseStorageService.selectTBaseStorageById(id)); + } + + /** + * 新增仓库管理 + */ + @PreAuthorize("@ss.hasPermi('system:storage:add')") + @Log(title = "仓库管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TBaseStorage tBaseStorage) + { + return toAjax(tBaseStorageService.insertTBaseStorage(tBaseStorage)); + } + + /** + * 修改仓库管理 + */ + @PreAuthorize("@ss.hasPermi('system:storage:edit')") + @Log(title = "仓库管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TBaseStorage tBaseStorage) + { + return toAjax(tBaseStorageService.updateTBaseStorage(tBaseStorage)); + } + + /** + * 删除仓库管理 + */ + @PreAuthorize("@ss.hasPermi('system:storage:remove')") + @Log(title = "仓库管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(tBaseStorageService.deleteTBaseStorageByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:storage:remove')") + @Log(title = "仓库管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(tBaseStorageService.disabledTBaseStorageByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:storage:edit')") + @Log(title = "仓库管理", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(tBaseStorageService.enableTBaseStorageByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:storage:edit')") + @Log(title = "仓库管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TBaseStorage tBaseStorage) { + return toAjax(tBaseStorageService.updateStatus(tBaseStorage)); + } + + /** + * 查询仓库列表 + */ + @PreAuthorize("@ss.hasPermi('system:storage:list')") + @GetMapping("/storageAreaLocationList") + public AjaxResult list(TBaseStorageLocationRecord tBaseStorage) + { + tBaseStorage.setDeptId(getDeptId()); + List list = tBaseStorageService.selectStorageAndAreaAndLocation(tBaseStorage); + return success(list); + } + /** + * 根据当前用的数据权限,查询所管理的仓库信息 + * @param tBaseStorage + * @return + */ + @PreAuthorize("@ss.hasPermi('system:storage:list')") + @GetMapping("/getStorageList") + public AjaxResult getStorageList(TBaseStorage tBaseStorage) { + tBaseStorage.setDeptId(getDeptId()); + return success(tBaseStorageService.selectTBaseStorageList(tBaseStorage)); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeController.java new file mode 100644 index 0000000..bf2412d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeController.java @@ -0,0 +1,184 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import com.zbf.common.utils.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TBaseStorage; +import com.zbf.system.domain.TCallNotice; +import com.zbf.system.service.ITBaseStorageService; +import com.zbf.system.service.ITCallNoticeService; +import com.zbf.web.controller.section.EnhanceDataList; + +/** + * 【请填写功能名称】Controller + * + * @author tony + * @date 2024-07-11 + */ +@RestController +@RequestMapping("/system/callNotice") +public class TCallNoticeController extends BaseController +{ + @Autowired + private ITCallNoticeService tCallNoticeService; + + @Autowired + private ITBaseStorageService baseStorageService; + + + + + /** + * 查询【请填写功能名称】列表 + */ + @GetMapping("/list") + public TableDataInfo list(TCallNotice tCallNotice) + { + startPage(); + List list = tCallNoticeService.selectTCallNoticeList(tCallNotice); + return getDataTable(list); + } + + /** + * 查询【请填写功能名称】列表 + */ + @GetMapping("/selectList") + @EnhanceDataList(entityType = TCallNotice.class) + public AjaxResult selectList(TCallNotice tCallNotice) + { + List list = tCallNoticeService.selectTCallNoticeList(tCallNotice); + list.forEach(tCallNotice1 -> { + if(StringUtils.isNotBlank(tCallNotice1.getShelfCtl())){ + tCallNotice1.setCtl(tCallNotice1.getShelfCtl()); + }else if(StringUtils.isNotBlank(tCallNotice1.getPickCtl())){ + tCallNotice1.setCtl(tCallNotice1.getPickCtl()); + } + if(StringUtils.isNotBlank(tCallNotice1.getrLocationId())){ + tCallNotice1.setLocationId(tCallNotice1.getrLocationId()); + }else if(StringUtils.isNotBlank(tCallNotice1.getcLocationId())){ + tCallNotice1.setLocationId(tCallNotice1.getcLocationId()); + } + }); + return success(list); + } + + /** + * 导出【请填写功能名称】列表 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TCallNotice tCallNotice) + { + List list = tCallNoticeService.selectTCallNoticeList(tCallNotice); + ExcelUtil util = new ExcelUtil(TCallNotice.class); + util.exportExcel(response, list, "【请填写功能名称】数据"); + } + + /** + * 获取【请填写功能名称】详细信息 + */ + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tCallNoticeService.selectTCallNoticeById(id)); + } + + /** + * 新增【请填写功能名称】 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TCallNotice tCallNotice) + { + return toAjax(tCallNoticeService.insertTCallNotice(tCallNotice)); + } + + /** + * 修改【请填写功能名称】 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TCallNotice tCallNotice) + { + return toAjax(tCallNoticeService.updateTCallNotice(tCallNotice)); + } + + /** + * 删除【请填写功能名称】 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tCallNoticeService.deleteTCallNoticeByIds(ids)); + } + + /** + * 启用 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tCallNoticeService.disabledTCallNoticeByIds(ids)); + } + + /** + * 禁用 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tCallNoticeService.enableTCallNoticeByIds(ids)); + } + + /** + * 修改状态 + */ + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TCallNotice tCallNotice) { + return toAjax(tCallNoticeService.updateStatus(tCallNotice)); + } + + /** + * 获取部门权限 + * @return + */ + @GetMapping("/getStorageList") + public AjaxResult list() + { + getDeptId(); + List storageList = getStorageList(getDeptId()); + return success(storageList); + } + + + private List getStorageList(Long deptId){ + TBaseStorage baseStorage = new TBaseStorage(); + baseStorage.setDeptId(deptId); + return baseStorageService.selectTBaseStorageList(baseStorage); + + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeOrderController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeOrderController.java new file mode 100644 index 0000000..1468ca0 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCallNoticeOrderController.java @@ -0,0 +1,155 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TCallNoticeOrder; +import com.zbf.system.service.ITCallNoticeOrderService; +import com.zbf.web.controller.section.EnhanceDataList; + +/** + * 【请填写功能名称】Controller + * + * @author tony + * @date 2024-07-30 + */ +@RestController +@RequestMapping("/system/callNoticeOrder") +public class TCallNoticeOrderController extends BaseController +{ + @Autowired + private ITCallNoticeOrderService tCallNoticeOrderService; + +/** + * 查询【请填写功能名称】列表 + */ +@PreAuthorize("@ss.hasPermi('system:order:list')") +@GetMapping("/list") + public TableDataInfo list(TCallNoticeOrder tCallNoticeOrder) + { + startPage(); + List list = tCallNoticeOrderService.selectTCallNoticeOrderList(tCallNoticeOrder); + return getDataTable(list); + } + + + /** + * 查询通知单消息列表 + */ + @GetMapping("/selectList") + @EnhanceDataList(entityType = TCallNoticeOrder.class) + public AjaxResult selectList(TCallNoticeOrder tCallNoticeOrder) + { + List list = tCallNoticeOrderService.selectTCallNoticeOrderList(tCallNoticeOrder); + List collect = list.stream().filter(c -> c.getTaskType().equals("0")).collect(Collectors.toList()); + return success(collect); + } + + /** + * 导出【请填写功能名称】列表 + */ + @PreAuthorize("@ss.hasPermi('system:order:export')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TCallNoticeOrder tCallNoticeOrder) + { + List list = tCallNoticeOrderService.selectTCallNoticeOrderList(tCallNoticeOrder); + ExcelUtil util = new ExcelUtil(TCallNoticeOrder.class); + util.exportExcel(response, list, "【请填写功能名称】数据"); + } + + /** + * 获取【请填写功能名称】详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:order:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tCallNoticeOrderService.selectTCallNoticeOrderById(id)); + } + + /** + * 新增【请填写功能名称】 + */ + @PreAuthorize("@ss.hasPermi('system:order:add')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TCallNoticeOrder tCallNoticeOrder) + { + return toAjax(tCallNoticeOrderService.insertTCallNoticeOrder(tCallNoticeOrder)); + } + + /** + * 修改【请填写功能名称】 + */ + @PreAuthorize("@ss.hasPermi('system:order:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TCallNoticeOrder tCallNoticeOrder) + { + return toAjax(tCallNoticeOrderService.updateTCallNoticeOrder(tCallNoticeOrder)); + } + + /** + * 删除【请填写功能名称】 + */ + @PreAuthorize("@ss.hasPermi('system:order:remove')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tCallNoticeOrderService.deleteTCallNoticeOrderByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:order:remove')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tCallNoticeOrderService.disabledTCallNoticeOrderByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:order:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tCallNoticeOrderService.enableTCallNoticeOrderByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:order:edit')") + @Log(title = "【请填写功能名称】", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TCallNoticeOrder tCallNoticeOrder) { + return toAjax(tCallNoticeOrderService.updateStatus(tCallNoticeOrder)); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrderdetailController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrderdetailController.java new file mode 100644 index 0000000..5b993ff --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrderdetailController.java @@ -0,0 +1,159 @@ +package com.zbf.web.controller.system; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zbf.common.annotation.DataSource; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.enums.DataSourceType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TCkOrderdetail; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.mapper.TMiStockMapper; +import com.zbf.system.service.ITCkOrderdetailService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.List; + +/** + * 出库物料明细Controller + * + * @author sunits + * @date 2024-06-21 + */ +@RestController +@RequestMapping("/system/orderdetail") +public class TCkOrderdetailController extends BaseController { + @Autowired + private ITCkOrderdetailService tCkOrderdetailService; + @Autowired + private TMiStockMapper tMiStockMapper; + + /** + * 查询出库物料明细列表 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TCkOrderdetail.class) + public TableDataInfo list(TCkOrderdetail tCkOrderdetail) { + startPage(); + List list = tCkOrderdetailService.selectTCkOrderdetailList(tCkOrderdetail); + return getDataTable(list); + } + + /** + * 导出出库物料明细列表 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:export')") + @Log(title = "出库物料明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TCkOrderdetail tCkOrderdetail) { + List list = tCkOrderdetailService.selectTCkOrderdetailList(tCkOrderdetail); + ExcelUtil util = new ExcelUtil(TCkOrderdetail.class); + util.exportExcel(response, list, "出库物料明细数据"); + } + + /** + * 获取出库物料明细详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tCkOrderdetailService.selectTCkOrderdetailById(id)); + } + + /** + * 新增出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:add')") + @Log(title = "出库物料明细", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TCkOrderdetail tCkOrderdetail) { + return toAjax(tCkOrderdetailService.insertTCkOrderdetail(tCkOrderdetail)); + } + + /** + * 修改出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TCkOrderdetail tCkOrderdetail) { + return tCkOrderdetailService.updateTCkOrderdetail(tCkOrderdetail); + } + + /** + * 删除出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:remove')") + @Log(title = "出库物料明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tCkOrderdetailService.deleteTCkOrderdetailByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:remove')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tCkOrderdetailService.disabledTCkOrderdetailByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tCkOrderdetailService.enableTCkOrderdetailByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:orderdetail:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TCkOrderdetail tCkOrderdetail) { + return toAjax(tCkOrderdetailService.updateStatus(tCkOrderdetail)); + } + + /** + * 下载模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil util = new ExcelUtil(TCkOrderdetail.class); + util.importTemplateExcel(response, "出库单物料明细数据"); + } + + /** + * 导入数据 + */ + @Log(title = "出库单物料明细", businessType = BusinessType.IMPORT) + @PreAuthorize("@ss.hasPermi('system:orderdetail:import')") + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) throws Exception { + ExcelUtil util = new ExcelUtil(TCkOrderdetail.class); + InputStream inputStream = file.getInputStream(); + List list = util.importExcel(inputStream); + inputStream.close(); + int count = tCkOrderdetailService.batchInsertTCkOrderdetail(list); + return AjaxResult.success("导入成功" + count + "条信息!"); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrdersController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrdersController.java new file mode 100644 index 0000000..e5bf097 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkOrdersController.java @@ -0,0 +1,291 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TCkOrderdetail; +import com.zbf.system.domain.TCkOrders; +import com.zbf.system.domain.TRkWareNotice; +import com.zbf.system.domain.vo.TCkOrdersVo; +import com.zbf.system.service.ITCkOrdersService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 出库Controller + * + * @author tony + * @date 2024-06-24 + */ +@RestController +@RequestMapping("/system/ckOrders") +public class TCkOrdersController extends BaseController { + @Autowired + private ITCkOrdersService tCkOrdersService; + + /** + * 查询出库列表 + */ + //@PreAuthorize("@ss.hasPermi('system:ckOrders:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TCkOrders.class) + public TableDataInfo list(TCkOrders tCkOrders) { + startPage(); + List list = tCkOrdersService.selectTCkOrdersList(tCkOrders); + return getDataTable(list); + } + + /** + * 导出出库列表 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:export')") + @Log(title = "出库", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TCkOrders tCkOrders) { + List list = tCkOrdersService.exportTCkOrdersList(tCkOrders); + ExcelUtil util = new ExcelUtil(TCkOrders.class); + util.exportExcel(response, list, "出库数据"); + } + + /** + * 获取出库详细信息 + */ + //@PreAuthorize("@ss.hasPermi('system:ckOrders:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { +// TCkOrders tCkOrders = tCkOrdersService.selectTCkOrdersById(id); + return success(tCkOrdersService.selectTCkOrdersById(id)); + } + + /** + * 获取出库详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:query')") + @GetMapping(value = "/order/{id}") + public AjaxResult getOrderInfo(@PathVariable("id") String id) { + return success(tCkOrdersService.selectTCkOrdersByDeliveryId(id)); + } + + /** + * 新增出库 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:add')") + @Log(title = "新增出库", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TCkOrders tCkOrders) { + tCkOrders.setId(OrderCodeFactory.getOrderCode("", "")); + tCkOrders.setOrderId(OrderCodeFactory.getOrderCode("CK", "")); + tCkOrders.setDeptId(getDeptId()); + + tCkOrders.setRecordDate(new Date()); + return toAjax(tCkOrdersService.insertTCkOrders(tCkOrders)); + } + + + /** + * 新增出库明细 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:add')") + @Log(title = "出库", businessType = BusinessType.INSERT) + @PostMapping("/updateTckOrderDetails") + public AjaxResult updateTckOrderDetails(@RequestBody List tCkOrderdetails) { + return toAjax(tCkOrdersService.insertTCkOrdersDetails(tCkOrderdetails)); + } + + /** + * 调拨创建 + */ + @Log(title = "调拨创建", businessType = BusinessType.INSERT) + @PostMapping("/create") + public AjaxResult create(@RequestBody TCkOrdersVo tCkOrders) { + return toAjax(tCkOrdersService.install(tCkOrders)); + } + + /** + * 修改出库 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:edit')") + @Log(title = "出库", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TCkOrders tCkOrders) { + return toAjax(tCkOrdersService.updateTCkOrders(tCkOrders)); + } + + /** + * 删除出库 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:remove')") + @Log(title = "审核", businessType = BusinessType.UPDATE) + @DeleteMapping("auditCkOrders/{ids}") + public AjaxResult auditCkOrders(@PathVariable String[] ids) { + return toAjax(tCkOrdersService.auditCkOrdersTCkOrdersByIds(ids)); + } + + /** + * 生成出库任务 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:remove')") + @Log(title = "生成出库任务", businessType = BusinessType.DELETE) + @PostMapping("/confirmOut") + public AjaxResult confirmOut(@RequestBody TCkOrders tCkOrders) { + tCkOrders.setDeptId(getDeptId()); + return toAjax(tCkOrdersService.confirmOut(tCkOrders)); + } + + + /** + * 任务分配 + */ + /*@PreAuthorize("@ss.hasPermi('system:ckOrders:remove')")*/ + @Log(title = "出库任务分配", businessType = BusinessType.OTHER) + @PostMapping("/send") + public AjaxResult send(@RequestBody TCkOrders tCkOrders) { + tCkOrders.setDeptId(getDeptId()); + return tCkOrdersService.send(tCkOrders); + } + + + + + /** + * 删除出库明细 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:remove')") + @Log(title = "出库", businessType = BusinessType.DELETE) + @DeleteMapping("/details/{ids}") + public AjaxResult removeDetails(@PathVariable String[] ids) { + return toAjax(tCkOrdersService.deleteTCkOrderDetailsByIds(ids)); + } + + + /** + * 删除出库 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:remove')") + @Log(title = "出库", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tCkOrdersService.deleteTCkOrdersByIds(ids)); + } + + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:remove')") + @Log(title = "出库", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tCkOrdersService.disabledTCkOrdersByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:edit')") + @Log(title = "出库", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tCkOrdersService.enableTCkOrdersByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:ckOrders:edit')") + @Log(title = "出库", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TCkOrders tCkOrders) { + return toAjax(tCkOrdersService.updateStatus(tCkOrders)); + } + + @GetMapping("/homeCount") + public AjaxResult homeCount() { + TCkOrders tCkOrders = new TCkOrders(); + TRkWareNotice notice = new TRkWareNotice(); + + Map map = new HashMap<>(); + map.put("out", tCkOrdersService.homeOutCount(tCkOrders)); + map.put("in", tCkOrdersService.homeInCount(notice)); + + return AjaxResult.success(map); + } + /** + * 导入 + */ + @Log(title = "出库数据", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { + ExcelUtil util = new ExcelUtil(TCkOrderdetail.class); + List trList = util.importExcel(file.getInputStream()); + LoginUser loginUser = getLoginUser(); + String operName = loginUser.getUsername(); + String message = tCkOrdersService.importData(trList, updateSupport, operName); + return AjaxResult.success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(TCkOrderdetail.class); + util.importTemplateExcel(response,"出库通知单"); + } + + // /** + // * 发送出库通知单消息 + // */ + // @Log(title = "发送出库通知单消息", businessType = BusinessType.UPDATE) + // @PostMapping("/sendOrderNotice") + // public AjaxResult sendNotice(@RequestBody TCkOrders update) { + // update.setCreateBy(getUsername()); + // update.setDeptId(getDeptId()); + // return AjaxResult.success(tCkOrdersService.sendOrderNotice(update)); + // } + + + + /** + * 发送出库通知到iwms + */ + @Log(title = "发送出库通知单消息", businessType = BusinessType.UPDATE) + @PostMapping("/sendiwms") + public AjaxResult sendIwms(@RequestBody TCkOrders update) { + update.setCreateBy(getUsername()); + update.setDeptId(getDeptId()); + return AjaxResult.success(tCkOrdersService.sendIwms(update)); + } + + /** + * 手持出库 + */ + @Log(title = "手持出库", businessType = BusinessType.UPDATE) + @PostMapping("/issue") + public AjaxResult handAddGoodsTab(@RequestBody TCkOrders update) { + return AjaxResult.success(tCkOrdersService.handAddGoodsTab(update)); + } + + + /** + * 出库申请审核后数量统计 + */ + @GetMapping("/statisticCallShelvesNum") + public AjaxResult statisticCallShelvesNum(TCkOrderdetail tCkOrderdetail) { + return AjaxResult.success(tCkOrdersService.statisticCallShelvesNum(tCkOrderdetail)); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsBakController.java new file mode 100644 index 0000000..f52783d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsBakController.java @@ -0,0 +1,147 @@ +package com.zbf.web.controller.system; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import javax.xml.crypto.Data; + +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TCkPickingwavegoodsBak; +import com.zbf.system.service.ITCkPickingwavegoodsBakService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 出库任务历史Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/ckPickingWavegoodsbak") +public class TCkPickingwavegoodsBakController extends BaseController { + @Autowired + private ITCkPickingwavegoodsBakService tCkPickingwavegoodsBakService; + + /** + * 查询出库任务历史列表 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TCkPickingwavegoodsBak.class) + public TableDataInfo list(TCkPickingwavegoodsBak tCkPickingwavegoodsBak) { + startPage(); + tCkPickingwavegoodsBak.setDeptId(getDeptId()); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date now = new Date(); + String formattedDate = formatter.format(now); + tCkPickingwavegoodsBak.setWareDate(formattedDate); + if (tCkPickingwavegoodsBak.getDate()!=null){ + String[] date = tCkPickingwavegoodsBak.getDate(); + tCkPickingwavegoodsBak.setStartTime(date[0]); + tCkPickingwavegoodsBak.setEndTime(date[1]); + } + List list = tCkPickingwavegoodsBakService.selectTCkPickingwavegoodsBakList(tCkPickingwavegoodsBak); + return getDataTable(list); + } + + /** + * 导出出库任务历史列表 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:export')") + @Log(title = "出库任务历史", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TCkPickingwavegoodsBak tCkPickingwavegoodsBak) { + tCkPickingwavegoodsBak.setDeptId(getDeptId()); + List list = tCkPickingwavegoodsBakService.selectTCkPickingwavegoodsBakList(tCkPickingwavegoodsBak); + ExcelUtil util = new ExcelUtil(TCkPickingwavegoodsBak.class); + util.exportExcel(response, list, "出库任务历史数据"); + } + + /** + * 获取出库任务历史详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tCkPickingwavegoodsBakService.selectTCkPickingwavegoodsBakById(id)); + } + + /** + * 新增出库任务历史 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:add')") + @Log(title = "出库任务历史", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TCkPickingwavegoodsBak tCkPickingwavegoodsBak) { + tCkPickingwavegoodsBak.setDeptId(getDeptId()); + return toAjax(tCkPickingwavegoodsBakService.insertTCkPickingwavegoodsBak(tCkPickingwavegoodsBak)); + } + + /** + * 修改出库任务历史 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:edit')") + @Log(title = "出库任务历史", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TCkPickingwavegoodsBak tCkPickingwavegoodsBak) { + return toAjax(tCkPickingwavegoodsBakService.updateTCkPickingwavegoodsBak(tCkPickingwavegoodsBak)); + } + + /** + * 删除出库任务历史 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:remove')") + @Log(title = "出库任务历史", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tCkPickingwavegoodsBakService.deleteTCkPickingwavegoodsBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:remove')") + @Log(title = "出库任务历史", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tCkPickingwavegoodsBakService.disabledTCkPickingwavegoodsBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:edit')") + @Log(title = "出库任务历史", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tCkPickingwavegoodsBakService.enableTCkPickingwavegoodsBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:ckPickingWavegoodsbak:edit')") + @Log(title = "出库任务历史", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TCkPickingwavegoodsBak tCkPickingwavegoodsBak) { + return toAjax(tCkPickingwavegoodsBakService.updateStatus(tCkPickingwavegoodsBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsController.java new file mode 100644 index 0000000..28604e8 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TCkPickingwavegoodsController.java @@ -0,0 +1,214 @@ +package com.zbf.web.controller.system; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TCkOrderdetail; +import com.zbf.system.domain.TCkOrders; +import com.zbf.system.domain.TCkPickingwavegoods; +import com.zbf.system.domain.TOngoodsshelf; +import com.zbf.system.service.ITCkPickingwavegoodsService; +import com.zbf.web.controller.section.EnhanceDataList; + +/** + * 出库任务Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/pickingwavegoods") +public class TCkPickingwavegoodsController extends BaseController { + @Autowired + private ITCkPickingwavegoodsService tCkPickingwavegoodsService; + + /** + * 查询出库任务列表 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:list')") + @EnhanceDataList(entityType = TCkPickingwavegoods.class) + @GetMapping("/list") + public TableDataInfo list(TCkPickingwavegoods tCkPickingwavegoods) { + startPage(); + // tCkPickingwavegoods.setDeptId(getDeptId()); + // SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + // Date now = new Date(); + // String formattedDate = formatter.format(now); + // tCkPickingwavegoods.setWareDate(formattedDate); + List list = tCkPickingwavegoodsService.selectTCkPickingwavegoodsList(tCkPickingwavegoods); + return getDataTable(list); + } + + /** + * 查询出库任务列表(不分页) + */ + //@PreAuthorize("@ss.hasPermi('system:pickingwavegoods:list')") + @GetMapping("/selectList") + public AjaxResult selectList(TCkPickingwavegoods tCkPickingwavegoods) { + // tCkPickingwavegoods.setDeptId(getDeptId()); + List list = tCkPickingwavegoodsService.selectTCkPickingwavegoodsList(tCkPickingwavegoods); + return success(list); + } + + + /** + * 导出出库任务列表 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:export')") + @Log(title = "出库任务", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TCkPickingwavegoods tCkPickingwavegoods) { + List list = tCkPickingwavegoodsService.selectTCkPickingwavegoodsList(tCkPickingwavegoods); + ExcelUtil util = new ExcelUtil(TCkPickingwavegoods.class); + util.exportExcel(response, list, "出库任务数据"); + } + + /** + * 获取出库任务详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tCkPickingwavegoodsService.selectTCkPickingwavegoodsById(id)); + } + + /** + * 新增出库任务 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:add')") + @Log(title = "出库任务", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TCkPickingwavegoods tCkPickingwavegoods) { + logger.info("新增出库请求:{}", tCkPickingwavegoods); + tCkPickingwavegoods.setDeptId(getDeptId()); + return toAjax(tCkPickingwavegoodsService.insertTCkPickingwavegoods(tCkPickingwavegoods)); + } + + /** + * 修改出库任务 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:edit')") + @Log(title = "出库任务", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TCkPickingwavegoods tCkPickingwavegoods) { + logger.info("修改出库任务开始:{}", tCkPickingwavegoods); + return toAjax(tCkPickingwavegoodsService.updateTCkPickingwavegoods(tCkPickingwavegoods)); + } + + /** + * 删除出库任务 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:remove')") + @Log(title = "出库任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + logger.info("删除出库任务列表:{}", ids); + return toAjax(tCkPickingwavegoodsService.deleteTCkPickingwavegoodsByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:remove')") + @Log(title = "出库任务", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tCkPickingwavegoodsService.disabledTCkPickingwavegoodsByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:edit')") + @Log(title = "出库任务", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tCkPickingwavegoodsService.enableTCkPickingwavegoodsByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:edit')") + @Log(title = "出库任务", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TCkPickingwavegoods tCkPickingwavegoods) { + return toAjax(tCkPickingwavegoodsService.updateStatus(tCkPickingwavegoods)); + } + + /** + * 更改物料货架信息 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:edit')") + @Log(title = "更改任务状态", businessType = BusinessType.UPDATE) + @PostMapping("/handleUpdateStatus/{ids}") + public AjaxResult handleUpdateStatus(@PathVariable List ids, @RequestBody TCkPickingwavegoods tCkPickingwavegoods) { + logger.info("更改出库任务状态开始:{}", tCkPickingwavegoods); + return toAjax(tCkPickingwavegoodsService.updateStatusByPickingids(ids, tCkPickingwavegoods)); + } + + /** + * 新增出库任务列表 + */ + @PreAuthorize("@ss.hasPermi('system:pickingwavegoods:add')") + @Log(title = "新增出库任务列表", businessType = BusinessType.INSERT) + @PostMapping("addTask") + public AjaxResult addTask(@RequestBody List tCkOrderdetailList) { + logger.info("新增出库单出库请求列表:{}", tCkOrderdetailList); + return toAjax(tCkPickingwavegoodsService.insertTCkPickingwavegoodsList(tCkOrderdetailList)); + } + + /** + * 确认出库 + */ + @PostMapping("/confirm") + public AjaxResult confirm(@RequestBody List goodsList) { + logger.info("确认出库:{}", goodsList); + return toAjax(tCkPickingwavegoodsService.confirm(goodsList)); + } + + /** + * 首页出入库未完成数据统计 + * @return + */ + @GetMapping("/home") + public AjaxResult home() { + + Map combinedResults = new HashMap<>(); + + TCkPickingwavegoods pickingwavegoods = new TCkPickingwavegoods(); + pickingwavegoods.setDeptId(getDeptId()); + + TOngoodsshelf tOngoodsshelf = new TOngoodsshelf(); + tOngoodsshelf.setDeptId(getDeptId()); + + TCkOrders tCkOrders = new TCkOrders(); + + combinedResults.put("out", tCkPickingwavegoodsService.homePickingwavegoodsCount(pickingwavegoods)); + combinedResults.put("in", tCkPickingwavegoodsService.homeOngoodsshelfCount(tOngoodsshelf)); + combinedResults.put("audit", tCkPickingwavegoodsService.homeTCkOrdersCount(tCkOrders)); + + return AjaxResult.success(combinedResults); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TErrorLogController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TErrorLogController.java new file mode 100644 index 0000000..4ed94e4 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TErrorLogController.java @@ -0,0 +1,138 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TErrorLog; +import com.zbf.system.service.ITErrorLogService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * agv报警信息Controller + * + * @author tony + * @date 2024-06-17 + */ +@RestController +@RequestMapping("/system/agvErrorlog") +public class TErrorLogController extends BaseController +{ + @Autowired + private ITErrorLogService tErrorLogService; + +/** + * 查询agv报警信息列表 + */ +@PreAuthorize("@ss.hasPermi('system:agvErrorlog:list')") +@GetMapping("/list") + public TableDataInfo list(TErrorLog tErrorLog) + { + startPage(); + List list = tErrorLogService.selectTErrorLogList(tErrorLog); + return getDataTable(list); + } + + /** + * 导出agv报警信息列表 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:export')") + @Log(title = "agv报警信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TErrorLog tErrorLog) + { + List list = tErrorLogService.selectTErrorLogList(tErrorLog); + ExcelUtil util = new ExcelUtil(TErrorLog.class); + util.exportExcel(response, list, "agv报警信息数据"); + } + + /** + * 获取agv报警信息详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(tErrorLogService.selectTErrorLogById(id)); + } + + /** + * 新增agv报警信息 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:add')") + @Log(title = "agv报警信息", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TErrorLog tErrorLog) + { + return toAjax(tErrorLogService.insertTErrorLog(tErrorLog)); + } + + /** + * 修改agv报警信息 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:edit')") + @Log(title = "agv报警信息", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TErrorLog tErrorLog) + { + return toAjax(tErrorLogService.updateTErrorLog(tErrorLog)); + } + + /** + * 删除agv报警信息 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:remove')") + @Log(title = "agv报警信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(tErrorLogService.deleteTErrorLogByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:remove')") + @Log(title = "agv报警信息", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(tErrorLogService.disabledTErrorLogByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:edit')") + @Log(title = "agv报警信息", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(tErrorLogService.enableTErrorLogByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:agvErrorlog:edit')") + @Log(title = "agv报警信息", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TErrorLog tErrorLog) { + return toAjax(tErrorLogService.updateStatus(tErrorLog)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiBatchAdjustmentController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiBatchAdjustmentController.java new file mode 100644 index 0000000..e0458be --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiBatchAdjustmentController.java @@ -0,0 +1,103 @@ +package com.zbf.web.controller.system; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.system.domain.vo.TMiStockVo; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + + +import lombok.RequiredArgsConstructor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zbf.common.core.controller.BaseController; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.service.ITMiStockService; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 库存Controller + * + * @author tony + * @date 2024-06-12 + */ +@RestController +@RequestMapping("/TMiBatchAdjustment/batch") +@Api(value = "库存批次调整", tags = {"库存管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class TMiBatchAdjustmentController extends BaseController { + + private final ITMiStockService tMiStockService; + + /** + * 查询库存列表 + */ + @ApiOperation("查询库存列表") +// @PreAuthorize("@ss.hasPermi('TMiBatchAdjustment:batch:list')") + @GetMapping("/list") + public TableDataInfo list(TMiStock tMiStock) { + startPage(); + List listed = tMiStockService.list(new LambdaQueryWrapper()); + return getDataTable(listed); + } + + /** + * 修改批次号 + * @param stockId + * @param value + * @return + */ + @GetMapping("update/{stockId}/{value}") + public AjaxResult update(@PathVariable String[] stockId, @PathVariable String value) { + // 将数组转换为列表 + List ids = Arrays.asList(stockId); + // 调用服务层方法进行处理 + boolean success = tMiStockService.updates(ids,value); + // 根据操作结果返回相应的AjaxResult + return success ? AjaxResult.success("批次号修改成功。") : AjaxResult.error("批次号修改失败。"); + } + + /** + * 生产日期 + * @param stockId + * @param value + * @return + */ + @GetMapping("updateDate/{stockId}/{value}") + public AjaxResult updateDate(@PathVariable String[] stockId, @PathVariable Date value) { + // 将数组转换为列表 + List ids = Arrays.asList(stockId); + // 调用服务层方法进行处理 + boolean success = tMiStockService.updateDate(ids,value); + // 根据操作结果返回相应的AjaxResult + return success ? AjaxResult.success("生产日期修改成功。") : AjaxResult.error("生产日期修改失败。"); + } + + + + + + /** + * 获取库存详细信息 + */ + @ApiOperation("获取库存详细信息") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping(value = "/{stockId}") + public AjaxResult getInfo(@PathVariable("stockId") String stockId) + { + return success(tMiStockService.getById(stockId)); + } + + + + +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockBakController.java new file mode 100644 index 0000000..675ca88 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockBakController.java @@ -0,0 +1,140 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TMiStockBak; +import com.zbf.system.service.ITMiStockBakService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 库存备份Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/tMiStockbak") +public class TMiStockBakController extends BaseController +{ + @Autowired + private ITMiStockBakService tMiStockBakService; + +/** + * 查询库存备份列表 + */ +@PreAuthorize("@ss.hasPermi('system:tMiStockbak:list')") +@GetMapping("/list") + public TableDataInfo list(TMiStockBak tMiStockBak) + { + startPage(); + tMiStockBak.setDeptId(getDeptId()); + List list = tMiStockBakService.selectTMiStockBakList(tMiStockBak); + return getDataTable(list); + } + + /** + * 导出库存备份列表 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:export')") + @Log(title = "库存备份", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TMiStockBak tMiStockBak) + { + tMiStockBak.setDeptId(getDeptId()); + List list = tMiStockBakService.selectTMiStockBakList(tMiStockBak); + ExcelUtil util = new ExcelUtil(TMiStockBak.class); + util.exportExcel(response, list, "库存备份数据"); + } + + /** + * 获取库存备份详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(tMiStockBakService.selectTMiStockBakById(id)); + } + + /** + * 新增库存备份 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:add')") + @Log(title = "库存备份", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TMiStockBak tMiStockBak) + { + return toAjax(tMiStockBakService.insertTMiStockBak(tMiStockBak)); + } + + /** + * 修改库存备份 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:edit')") + @Log(title = "库存备份", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TMiStockBak tMiStockBak) + { + return toAjax(tMiStockBakService.updateTMiStockBak(tMiStockBak)); + } + + /** + * 删除库存备份 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:remove')") + @Log(title = "库存备份", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(tMiStockBakService.deleteTMiStockBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:remove')") + @Log(title = "库存备份", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(tMiStockBakService.disabledTMiStockBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:edit')") + @Log(title = "库存备份", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(tMiStockBakService.enableTMiStockBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:tMiStockbak:edit')") + @Log(title = "库存备份", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TMiStockBak tMiStockBak) { + return toAjax(tMiStockBakService.updateStatus(tMiStockBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockController.java new file mode 100644 index 0000000..1c09db7 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockController.java @@ -0,0 +1,342 @@ +package com.zbf.web.controller.system; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.core.controller.ManualPagination; +import com.zbf.system.domain.RfidQuantityUpdateRequest; +import com.zbf.system.domain.RfidQueryRequest; +import com.zbf.system.service.ITBaseStorageService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.domain.TMiStockUpdate; +import com.zbf.system.service.ITMiStockService; +import com.zbf.system.service.ITOverdueService; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; + + +/** + * 库存Controller + * + * @author tony + * @date 2024-06-12 + */ +@RestController +@RequestMapping("/system/stock") +@Api(value = "库存控制器", tags = {"库存管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class TMiStockController extends BaseController { + + private final ITMiStockService tMiStockService; + + private final ITOverdueService overdueService; + + private final ITBaseStorageService storageService; + + /** + * 查询库存列表 + */ + @ApiOperation("查询库存列表") + @PreAuthorize("@ss.hasPermi('system:stock:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TMiStock.class) + public TableDataInfo list(TMiStock tMiStock) { + startPage(); + tMiStock.setDeptId(getDeptId()); + if (tMiStock.getDate()!=null){ + String[] date = tMiStock.getDate(); + tMiStock.setStartTime(date[0]); + tMiStock.setEndTime(date[1]); + } + List list = tMiStockService.selectTMiStockList(tMiStock); + return getDataTable(list); + } + + @GetMapping("/lists") + @EnhanceDataList(entityType = TMiStock.class) + public AjaxResult lists(TMiStock tMiStock) { + if (tMiStock.getDate()!=null){ + String[] date = tMiStock.getDate(); + tMiStock.setStartTime(date[0]); + tMiStock.setEndTime(date[1]); + } + List list = tMiStockService.select(tMiStock); + return AjaxResult.success(list); + } + + /** + * 导出库存列表 + */ + @ApiOperation("导出库存列表") + @PreAuthorize("@ss.hasPermi('system:stock:export')") + @Log(title = "库存", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TMiStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + if (tMiStock.getDate()!=null){ + tMiStock.setStartTime(tMiStock.getDate()[0]); + tMiStock.setEndTime(tMiStock.getDate()[1]); + } + List list = tMiStockService.selectTMiStockList(tMiStock); + ExcelUtil util = new ExcelUtil(TMiStock.class); + util.exportExcel(response, list, "库存数据"); + } + + /** + * 获取库存详细信息 + */ + @ApiOperation("获取库存详细信息") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping(value = "/{stockId}") + public AjaxResult getInfo(@PathVariable("stockId") String stockId) { + return success(tMiStockService.getById(stockId)); + } + + /** + * 根据条件查询库存总数 + */ + @ApiOperation("获取库存总数") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping(value = "/queryTotal") + public AjaxResult getTotal(TMiStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + return success(tMiStockService.getTotal(tMiStock)); + } + + @ApiOperation("统计查询库存列表") + @PreAuthorize("@ss.hasPermi('system:stock:list')") + @GetMapping("/countList") + public TableDataInfo countList(TMiStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + List list = tMiStockService.selectCountStockList(tMiStock); + return ManualPagination.pagination(list); + } + + + /** + * 新增库存 + */ + @ApiOperation("新增库存") + @PreAuthorize("@ss.hasPermi('system:stock:add')") + @Log(title = "库存", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TMiStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + return toAjax(tMiStockService.save(tMiStock)); + } + + /** + * 修改库存 + */ + @ApiOperation("修改库存") + @PreAuthorize("@ss.hasPermi('system:stock:edit')") + @Log(title = "库存", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TMiStock tMiStock) { + return toAjax(tMiStockService.updateById(tMiStock)); + } + + /** + * 删除库存 + */ + @ApiOperation("删除库存") + @PreAuthorize("@ss.hasPermi('system:stock:remove')") + @Log(title = "库存", businessType = BusinessType.DELETE) + @DeleteMapping("/{stockIds}") + public AjaxResult remove(@PathVariable String[] stockIds) { + return toAjax(tMiStockService.removeByIds(Arrays.asList(stockIds))); + } + + + /** + * 冻结库存操作 + * + * @param 库存ID数组 + * @return 返回操作结果 + */ + @GetMapping("/frozen") + public AjaxResult frozen(@RequestParam(name = "stockIds", required = true) String stockIdsStr, + @RequestParam(name = "value", required = true) String value) { + // 将逗号分隔的字符串转换为ID列表 + List ids = Arrays.asList(stockIdsStr.split(",")); + + // 调用服务层方法进行处理 + boolean success = tMiStockService.freezeStockByIds(ids, value); + + // 根据操作结果返回相应的AjaxResult + return success ? AjaxResult.success("库存已成功冻结。") : AjaxResult.error("库存冻结失败。"); + } + + /** + * 解冻 + * + * @param stockIds + * @return + */ + @GetMapping("/thaw/{stockIds}") + public AjaxResult thaw(@PathVariable String[] stockIds) { + // 将数组转换为列表 + List ids = Arrays.asList(stockIds); + // 调用服务层方法进行处理 + boolean success = tMiStockService.thawStockByIds(ids); + // 根据操作结果返回相应的AjaxResult + return success ? AjaxResult.success("库存已成功解冻。") : AjaxResult.error("库存解冻失败。"); + } + + @ApiOperation("查询超期呆滞列表") + @PreAuthorize("@ss.hasPermi('system:stock:overdue')") + @GetMapping("/overdueByParam") + public TableDataInfo overdueListByParam(TMiStock tMiStock) { + //超期呆滞天数 + String overdueDate = overdueService.getOverdueFromToday(); + if (StringUtils.isNotEmpty(overdueDate)) { + tMiStock.setOverdueDate(overdueDate); + startPage(); + List list = tMiStockService.selectTMiStockList(tMiStock); + return getDataTable(list); + } + return getDataTable(new ArrayList<>()); + } + + @ApiOperation("查询超期呆滞列表") + @PreAuthorize("@ss.hasPermi('system:stock:overdue')") + @GetMapping("/overdue") + public TableDataInfo overdueList(TMiStock tMiStock) { + //超期呆滞 + tMiStock.setFlag("1"); + startPage(); + List list = tMiStockService.selectTMiStockList(tMiStock); + return getDataTable(list); + } + + + @ApiOperation("查询超期呆滞列表") + @PreAuthorize("@ss.hasPermi('system:stock:overdue')") + @GetMapping("/overInsured") + public TableDataInfo overInsured(TMiStock tMiStock) { + startPage(); + List list = tMiStockService.overInsured(tMiStock); + return getDataTable(list); + } + + /** + * 手持库存查询 + */ + @ApiOperation("库存信息查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/goodsStatistics") + public AjaxResult goodsStatistics(TMiStock tMiStock) { + return success(tMiStockService.inventoryStatisticsGoods(tMiStock)); + } + + /** + * 手持盘点库存查询 + */ + @ApiOperation("手持盘点库存信息查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/pdaPanGoodsList") + public AjaxResult pdaPanGoodsList(TMiStock tMiStock) { + return success(tMiStockService.selectPanGoodsList(tMiStock)); + } + + /** + * 手持盘点当日变化库位查询 + */ + @ApiOperation("手持盘点当日库位信息查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/dayLocation") + public AjaxResult dayLocation() { + return success(tMiStockService.selectPanTimeLocation()); + } + + /** + * 手持移位 + */ + @ApiOperation("手持移位") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/reLocation") + public AjaxResult reLocation(@RequestBody TMiStockUpdate tMiStockUpdate) { + return success(tMiStockService.changeLocation(tMiStockUpdate)); + } + + @ApiOperation("查询物料") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/getStock") + public AjaxResult getStock(@RequestBody TMiStockUpdate tMiStockUpdate) { + TMiStock tMiStock = new TMiStock(); + tMiStock.setLocationId(tMiStockUpdate.getFromLoc()); + List list = tMiStockService.list(new LambdaQueryWrapper<>(tMiStock).eq(TMiStock::getLocationId, tMiStockUpdate.getFromLoc())); + return AjaxResult.success(list); + } + + /** + * 手持更换容器 托盘物料查询 + */ + @ApiOperation("手持更换容器 托盘物料查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/getCtlNoGoods") + public AjaxResult getCtlNoGoods(TMiStock tMiStock) { + return success(tMiStockService.selectTMiStockListByCtl(tMiStock)); + } + + /** + * 手持更换容器 + */ + @ApiOperation("手持更换容器") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/changeCtlNo") + public AjaxResult changeCtlNo(@RequestBody TMiStockUpdate tMiStockUpdate) { + return success(tMiStockService.changeCtlNo(tMiStockUpdate)); + } + + /** + * 手持拆分,合并容器 + */ + @ApiOperation("手持拆分合并容器") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/splitCtlNo") + public AjaxResult splitCtlNo(@RequestBody TMiStockUpdate tMiStockUpdate) { + return success(tMiStockService.splitCtlNo(tMiStockUpdate)); + } + + @PostMapping("/queryByRfid") + public AjaxResult queryByRfid(@RequestBody RfidQueryRequest request) { + + return AjaxResult.success(tMiStockService.rfid(request)); + } + + /** + * 更新RFID数量 + */ + @ApiOperation("更新RFID数量") + @PreAuthorize("@ss.hasPermi('system:stock:edit')") + @Log(title = "RFID数量更新", businessType = BusinessType.UPDATE) + @PostMapping("/updateRfidQuantity") + public AjaxResult updateRfidQuantity(@Validated @RequestBody RfidQuantityUpdateRequest request) { + try { + return AjaxResult.success(tMiStockService.updateRfidQuantity(request)); + } catch (Exception e) { + logger.error("RFID数量更新失败", e); + return AjaxResult.error("RFID数量更新失败: " + e.getMessage()); + } + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockFController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockFController.java new file mode 100644 index 0000000..802b886 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiStockFController.java @@ -0,0 +1,53 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.system.domain.TMiStockF; +import com.zbf.system.domain.TMiStockFUpdate; +import com.zbf.system.service.ITMiStockFService; + +import io.swagger.annotations.ApiOperation; + +/** + * 库存Controller + * + * @author tony + * @date 2024-07-27 + */ +@RestController +@RequestMapping("/system/tMiStockf") +public class TMiStockFController extends BaseController +{ + @Autowired + private ITMiStockFService tMiStockFService; + + /** + * 查询库存列表 + */ + @GetMapping("/selectList") + public AjaxResult selectlist(TMiStockF tMiStockF) + { + List list = tMiStockFService.selectTMiStockFList(tMiStockF); + return success(list); + } + + /** + * 物料组盘,生成真实入库上架任务 + */ + @ApiOperation("物料组盘") + @PostMapping("/goodsMakeCtl") + public AjaxResult goodsMakeCtl(@RequestBody TMiStockFUpdate tMiStockFUpdate) { + return success(tMiStockFService.goodsMakeCtl(tMiStockFUpdate)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiXnStockController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiXnStockController.java new file mode 100644 index 0000000..19924ed --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TMiXnStockController.java @@ -0,0 +1,338 @@ +package com.zbf.web.controller.system; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.controller.ManualPagination; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.StringUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TCkOrderdetail; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.domain.TMiStockUpdate; +import com.zbf.system.domain.TMiXnStock; +import com.zbf.system.service.ITBaseStorageService; +import com.zbf.system.service.ITMiStockService; +import com.zbf.system.service.ITMiXnStockService; +import com.zbf.system.service.ITOverdueService; +import com.zbf.web.controller.section.EnhanceDataList; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +/** + * 库存Controller + * + * @author tony + * @date 2024-06-12 + */ +@RestController +@RequestMapping("/system/xnstock") +@Api(value = "库存控制器", tags = {"库存管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class TMiXnStockController extends BaseController { + + private final ITMiXnStockService tMiStockService; + + private final ITOverdueService overdueService; + + private final ITBaseStorageService storageService; + + /** + * 查询库存列表 + */ + @ApiOperation("查询库存列表") + @PreAuthorize("@ss.hasPermi('system:stock:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TMiXnStock.class) + public TableDataInfo list(TMiXnStock tMiStock) { + startPage(); + tMiStock.setDeptId(getDeptId()); + if (tMiStock.getDate()!=null){ + String[] date = tMiStock.getDate(); + tMiStock.setStartTime(date[0]); + tMiStock.setEndTime(date[1]); + } + List list = tMiStockService.selectTMiStockList(tMiStock); + return getDataTable(list); + } + /** + * 导入 + */ + @Log(title = "出库数据", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) throws Exception + { + ExcelUtil util = new ExcelUtil(TMiXnStock.class); + List trList = util.importExcel(file.getInputStream()); + String message = tMiStockService.importData(trList, ""); + return AjaxResult.success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(TMiXnStock.class); + util.importTemplateExcel(response,"虚拟库存"); + } + + @GetMapping("/lists") + @EnhanceDataList(entityType = TMiXnStock.class) + public AjaxResult lists(TMiXnStock tMiStock) { + if (tMiStock.getDate()!=null){ + String[] date = tMiStock.getDate(); + tMiStock.setStartTime(date[0]); + tMiStock.setEndTime(date[1]); + } + List list = tMiStockService.select(tMiStock); + return AjaxResult.success(list); + } + + /** + * 导出库存列表 + */ + @ApiOperation("导出库存列表") + @PreAuthorize("@ss.hasPermi('system:stock:export')") + @Log(title = "库存", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TMiXnStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + if (tMiStock.getDate()!=null){ + tMiStock.setStartTime(tMiStock.getDate()[0]); + tMiStock.setEndTime(tMiStock.getDate()[1]); + } + List list = tMiStockService.selectTMiStockList(tMiStock); + ExcelUtil util = new ExcelUtil(TMiXnStock.class); + util.exportExcel(response, list, "库存数据"); + } + + /** + * 获取库存详细信息 + */ + @ApiOperation("获取库存详细信息") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping(value = "/{stockId}") + public AjaxResult getInfo(@PathVariable("stockId") String stockId) { + return success(tMiStockService.getById(stockId)); + } + + /** + * 根据条件查询库存总数 + */ + @ApiOperation("获取库存总数") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping(value = "/queryTotal") + public AjaxResult getTotal(TMiXnStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + return success(tMiStockService.getTotal(tMiStock)); + } + + @ApiOperation("统计查询库存列表") + @PreAuthorize("@ss.hasPermi('system:stock:list')") + @GetMapping("/countList") + public TableDataInfo countList(TMiXnStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + List list = tMiStockService.selectCountStockList(tMiStock); + return ManualPagination.pagination(list); + } + + + /** + * 新增库存 + */ + @ApiOperation("新增库存") + @PreAuthorize("@ss.hasPermi('system:stock:add')") + @Log(title = "库存", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TMiXnStock tMiStock) { + tMiStock.setDeptId(getDeptId()); + return toAjax(tMiStockService.save(tMiStock)); + } + + /** + * 修改库存 + */ + @ApiOperation("修改库存") + @PreAuthorize("@ss.hasPermi('system:stock:edit')") + @Log(title = "库存", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TMiXnStock tMiStock) { + return toAjax(tMiStockService.updateById(tMiStock)); + } + + /** + * 删除库存 + */ + @ApiOperation("删除库存") + @PreAuthorize("@ss.hasPermi('system:stock:remove')") + @Log(title = "库存", businessType = BusinessType.DELETE) + @DeleteMapping("/{stockIds}") + public AjaxResult remove(@PathVariable String[] stockIds) { + return toAjax(tMiStockService.removeByIds(Arrays.asList(stockIds))); + } + + + /** + * 冻结库存操作 + * + * @param 库存ID数组 + * @return 返回操作结果 + */ + @GetMapping("/frozen") + public AjaxResult frozen(@RequestParam(name = "stockIds", required = true) String stockIdsStr, + @RequestParam(name = "value", required = true) String value) { + // 将逗号分隔的字符串转换为ID列表 + List ids = Arrays.asList(stockIdsStr.split(",")); + + // 调用服务层方法进行处理 + boolean success = tMiStockService.freezeStockByIds(ids, value); + + // 根据操作结果返回相应的AjaxResult + return success ? AjaxResult.success("库存已成功冻结。") : AjaxResult.error("库存冻结失败。"); + } + + /** + * 解冻 + * + * @param stockIds + * @return + */ + @GetMapping("/thaw/{stockIds}") + public AjaxResult thaw(@PathVariable String[] stockIds) { + // 将数组转换为列表 + List ids = Arrays.asList(stockIds); + // 调用服务层方法进行处理 + boolean success = tMiStockService.thawStockByIds(ids); + // 根据操作结果返回相应的AjaxResult + return success ? AjaxResult.success("库存已成功解冻。") : AjaxResult.error("库存解冻失败。"); + } + + @ApiOperation("查询超期呆滞列表") + @PreAuthorize("@ss.hasPermi('system:stock:overdue')") + @GetMapping("/overdueByParam") + public TableDataInfo overdueListByParam(TMiXnStock tMiStock) { + //超期呆滞天数 + String overdueDate = overdueService.getOverdueFromToday(); + if (StringUtils.isNotEmpty(overdueDate)) { + tMiStock.setOverdueDate(overdueDate); + startPage(); + List list = tMiStockService.selectTMiStockList(tMiStock); + return getDataTable(list); + } + return getDataTable(new ArrayList<>()); + } + + @ApiOperation("查询超期呆滞列表") + @PreAuthorize("@ss.hasPermi('system:stock:overdue')") + @GetMapping("/overdue") + public TableDataInfo overdueList(TMiXnStock tMiStock) { + //超期呆滞 + tMiStock.setFlag("1"); + startPage(); + List list = tMiStockService.selectTMiStockList(tMiStock); + return getDataTable(list); + } + + + @ApiOperation("查询超期呆滞列表") + @PreAuthorize("@ss.hasPermi('system:stock:overdue')") + @GetMapping("/overInsured") + public TableDataInfo overInsured(TMiXnStock tMiStock) { + startPage(); + List list = tMiStockService.overInsured(tMiStock); + return getDataTable(list); + } + + /** + * 手持库存查询 + */ + @ApiOperation("库存信息查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/goodsStatistics") + public AjaxResult goodsStatistics(TMiXnStock tMiStock) { + return success(tMiStockService.inventoryStatisticsGoods(tMiStock)); + } + + /** + * 手持盘点库存查询 + */ + @ApiOperation("手持盘点库存信息查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/pdaPanGoodsList") + public AjaxResult pdaPanGoodsList(TMiXnStock tMiStock) { + return success(tMiStockService.selectPanGoodsList(tMiStock)); + } + + /** + * 手持盘点当日变化库位查询 + */ + @ApiOperation("手持盘点当日库位信息查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/dayLocation") + public AjaxResult dayLocation() { + return success(tMiStockService.selectPanTimeLocation()); + } + + /** + * 手持移位 + */ + @ApiOperation("手持移位") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/reLocation") + public AjaxResult reLocation(@RequestBody TMiStockUpdate tMiStockUpdate) { + return success(tMiStockService.changeLocation(tMiStockUpdate)); + } + + @ApiOperation("查询物料") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/getStock") + public AjaxResult getStock(@RequestBody TMiStockUpdate tMiStockUpdate) { + TMiXnStock tMiStock = new TMiXnStock(); + tMiStock.setLocationId(tMiStockUpdate.getFromLoc()); + List list = tMiStockService.list(new LambdaQueryWrapper<>(tMiStock).eq(TMiXnStock::getLocationId, tMiStockUpdate.getFromLoc())); + return AjaxResult.success(list); + } + + /** + * 手持更换容器 托盘物料查询 + */ + @ApiOperation("手持更换容器 托盘物料查询") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @GetMapping("/getCtlNoGoods") + public AjaxResult getCtlNoGoods(TMiXnStock tMiStock) { + return success(tMiStockService.selectTMiStockListByCtl(tMiStock)); + } + + /** + * 手持更换容器 + */ + @ApiOperation("手持更换容器") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/changeCtlNo") + public AjaxResult changeCtlNo(@RequestBody TMiStockUpdate tMiStockUpdate) { + return success(tMiStockService.changeCtlNo(tMiStockUpdate)); + } + + /** + * 手持拆分,合并容器 + */ + @ApiOperation("手持拆分合并容器") + @PreAuthorize("@ss.hasPermi('system:stock:query')") + @PostMapping("/splitCtlNo") + public AjaxResult splitCtlNo(@RequestBody TMiStockUpdate tMiStockUpdate) { + return success(tMiStockService.splitCtlNo(tMiStockUpdate)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfBakController.java new file mode 100644 index 0000000..06dc81d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfBakController.java @@ -0,0 +1,152 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TOngoodsshelfBak; +import com.zbf.system.service.ITOngoodsshelfBakService; + +/** + * 入库任务历史Controller + * + * @author tony + * @date 2024-06-18 + */ +@RestController +@RequestMapping("/system/tOnGoodsShelfbak") +public class TOngoodsshelfBakController extends BaseController +{ + @Autowired + private ITOngoodsshelfBakService tOngoodsshelfBakService; + +/** + * 查询入库任务历史列表 + */ +//@PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:list')") +@GetMapping("/list") +@EnhanceDataList(entityType = TOngoodsshelfBak.class) + public TableDataInfo list(TOngoodsshelfBak tOngoodsshelfBak) + { + startPage(); + tOngoodsshelfBak.setDeptId(getDeptId()); + if (tOngoodsshelfBak.getDate()!=null){ + String[] date = tOngoodsshelfBak.getDate(); + tOngoodsshelfBak.setStartTime(date[0]); + tOngoodsshelfBak.setEndTime(date[1]); + } + List list = tOngoodsshelfBakService.selectTOngoodsshelfBakList(tOngoodsshelfBak); + return getDataTable(list); + } + + /** + * 导出入库任务历史列表 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:export')") + @Log(title = "入库任务历史", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TOngoodsshelfBak tOngoodsshelfBak) + { + tOngoodsshelfBak.setDeptId(getDeptId()); + List list = tOngoodsshelfBakService.selectTOngoodsshelfBakList(tOngoodsshelfBak); + ExcelUtil util = new ExcelUtil(TOngoodsshelfBak.class); + util.exportExcel(response, list, "入库任务历史数据"); + } + + /** + * 获取入库任务历史详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tOngoodsshelfBakService.selectTOngoodsshelfBakById(id)); + } + + /** + * 新增入库任务历史 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:add')") + @Log(title = "入库任务历史", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TOngoodsshelfBak tOngoodsshelfBak) + { + tOngoodsshelfBak.setId(OrderCodeFactory.getOrderCode("SHELF", "")); + return toAjax(tOngoodsshelfBakService.insertTOngoodsshelfBak(tOngoodsshelfBak)); + } + + /** + * 修改入库任务历史 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:edit')") + @Log(title = "入库任务历史", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TOngoodsshelfBak tOngoodsshelfBak) + { + return toAjax(tOngoodsshelfBakService.updateTOngoodsshelfBak(tOngoodsshelfBak)); + } + + /** + * 删除入库任务历史 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:remove')") + @Log(title = "入库任务历史", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tOngoodsshelfBakService.deleteTOngoodsshelfBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:remove')") + @Log(title = "入库任务历史", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tOngoodsshelfBakService.disabledTOngoodsshelfBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:edit')") + @Log(title = "入库任务历史", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tOngoodsshelfBakService.enableTOngoodsshelfBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:tOnGoodsShelfbak:edit')") + @Log(title = "入库任务历史", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TOngoodsshelfBak tOngoodsshelfBak) { + return toAjax(tOngoodsshelfBakService.updateStatus(tOngoodsshelfBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfController.java new file mode 100644 index 0000000..d959de0 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TOngoodsshelfController.java @@ -0,0 +1,148 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TOngoodsshelf; +import com.zbf.system.service.ITOngoodsshelfService; +import com.zbf.web.controller.section.EnhanceDataList; + +/** + * 入库任务Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/ongoodsshelf") +public class TOngoodsshelfController extends BaseController { + @Autowired + private ITOngoodsshelfService tOngoodsshelfService; + + /** + * 查询入库任务列表 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:list')") + @EnhanceDataList(entityType = TOngoodsshelf.class) + @GetMapping("/list") + public TableDataInfo list(TOngoodsshelf tOngoodsshelf) { + startPage(); + // tOngoodsshelf.setDeptId(getDeptId()); + List list = tOngoodsshelfService.selectTOngoodsshelfList(tOngoodsshelf); + return getDataTable(list); + } + + /** + * 导出入库任务列表 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:export')") + @Log(title = "入库任务", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TOngoodsshelf tOngoodsshelf) { + // tOngoodsshelf.setDeptId(getDeptId()); + List list = tOngoodsshelfService.selectTOngoodsshelfList(tOngoodsshelf); + ExcelUtil util = new ExcelUtil(TOngoodsshelf.class); + util.exportExcel(response, list, "入库任务数据"); + } + + /** + * 获取入库任务详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tOngoodsshelfService.selectTOngoodsshelfById(id)); + } + + /** + * 新增入库任务 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:add')") + @Log(title = "入库任务", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TOngoodsshelf tOngoodsshelf) { + tOngoodsshelf.setDeptId(getDeptId()); + tOngoodsshelf.setId(OrderCodeFactory.getOrderCode("SHELF", "")); + return toAjax(tOngoodsshelfService.insertTOngoodsshelf(tOngoodsshelf)); + } + + /** + * 修改入库任务 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:edit')") + @Log(title = "入库任务", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TOngoodsshelf tOngoodsshelf) { + return toAjax(tOngoodsshelfService.updateTOngoodsshelf(tOngoodsshelf)); + } + + /** + * 删除入库任务 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:remove')") + @Log(title = "入库任务", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tOngoodsshelfService.deleteTOngoodsshelfByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:remove')") + @Log(title = "入库任务", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tOngoodsshelfService.disabledTOngoodsshelfByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:edit')") + @Log(title = "入库任务", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tOngoodsshelfService.enableTOngoodsshelfByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:ongoodsshelf:edit')") + @Log(title = "入库任务", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TOngoodsshelf tOngoodsshelf) { + return toAjax(tOngoodsshelfService.updateStatus(tOngoodsshelf)); + } + + /** + * 查询入库任务列表 + */ + @GetMapping("/selectList") + public AjaxResult selectList(TOngoodsshelf tOngoodsshelf) { + // tOngoodsshelf.setDeptId(getDeptId()); + List list = tOngoodsshelfService.selectTOngoodsshelfList(tOngoodsshelf); + return success(list); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TPanDetailController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TPanDetailController.java new file mode 100644 index 0000000..6cebdf4 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TPanDetailController.java @@ -0,0 +1,132 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TPanDetail; +import com.zbf.system.service.ITPanDetailService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 盘点明细Controller + * + * @author wgs + * @date 2024-11-01 + */ +@RestController +@RequestMapping("/system/pan") +public class TPanDetailController extends BaseController +{ + @Autowired + private ITPanDetailService tPanDetailService; + + /** + * 查询盘点明细列表 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @GetMapping("/list") + public TableDataInfo list(TPanDetail tPanDetail) + { + startPage(); + List list = tPanDetailService.selectTPanDetailList(tPanDetail); + return getDataTable(list); + } + + /** + * 导出盘点明细列表 + */ + @PreAuthorize("@ss.hasPermi('system:pan:export')") + @Log(title = "盘点明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TPanDetail tPanDetail) + { + List list = tPanDetailService.selectTPanDetailList(tPanDetail); + ExcelUtil util = new ExcelUtil(TPanDetail.class); + util.exportExcel(response, list, "盘点明细数据"); + } + + /** + * 获取盘点明细详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:pan:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(tPanDetailService.selectTPanDetailById(id)); + } + + /** + * 新增盘点明细 + */ + @PreAuthorize("@ss.hasPermi('system:pan:add')") + @Log(title = "盘点明细", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TPanDetail tPanDetail) + { + return toAjax(tPanDetailService.insertTPanDetail(tPanDetail)); + } + + /** + * 修改盘点明细 + */ + @PreAuthorize("@ss.hasPermi('system:pan:edit')") + @Log(title = "盘点修改库存数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TPanDetail tPanDetail) + { + return toAjax(tPanDetailService.updateTPanDetail(tPanDetail)); + } + + /** + * 删除盘点明细 + */ + @PreAuthorize("@ss.hasPermi('system:pan:remove')") + @Log(title = "盘点明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(tPanDetailService.deleteTPanDetailByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:pan:remove')") + @Log(title = "盘点明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) + { + return toAjax(tPanDetailService.disabledTPanDetailByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:pan:edit')") + @Log(title = "盘点明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) + { + return toAjax(tPanDetailService.enableTPanDetailByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:pan:edit')") + @Log(title = "盘点明细", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TPanDetail tPanDetail) { + return toAjax(tPanDetailService.updateStatus(tPanDetail)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TPanOrderController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TPanOrderController.java new file mode 100644 index 0000000..f615fa6 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TPanOrderController.java @@ -0,0 +1,178 @@ +package com.zbf.web.controller.system; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.domain.TPanOrder; +import com.zbf.system.service.ITMiStockService; +import com.zbf.system.service.ITPanDetailService; +import com.zbf.system.service.ITPanOrderService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 盘点单Controller + * + * @author wgs + * @date 2024-06-20 + */ +@RestController +@RequestMapping("/system/pan/order") +public class TPanOrderController extends BaseController { + private final ITPanOrderService tPanOrderService; + private final ITPanDetailService detailService; + private ITMiStockService stockService; + + public TPanOrderController(ITPanOrderService tPanOrderService, ITPanDetailService detailService, ITMiStockService stockService) { + this.tPanOrderService = tPanOrderService; + this.detailService = detailService; + this.stockService = stockService; + } + + + /** + * 保存单据主表跟单据从表的数据 + */ + /*@PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "保存盘点单主从表", businessType = BusinessType.EXPORT) + @PostMapping("/saveAll") + public AjaxResult saveAll(@RequestBody TPanVo panVo) { + + TPanOrder panOrder = new TPanOrder(); + BeanUtils.copyProperties(panVo, panOrder); + tPanOrderService.saveOrUpdate(panOrder); + List detailList = panVo.getDetailList(); + detailList = detailList.stream().map(obj -> { + obj.setMainId(panOrder.getId()); + return obj; + }).collect(Collectors.toList()); + detailService.saveOrUpdateBatch(detailList); + return AjaxResult.success(); + }*/ + + + /** + * 根据当前库存,生成盘点明细 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @GetMapping("/importCurrStock") + public TableDataInfo importCurrStock(@RequestParam Map params) { + startPage(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); + queryWrapper.eq(TMiStock::getStorageId, params.getOrDefault("storageId", "")); + queryWrapper.eq(TMiStock::getStorageAreaId, params.getOrDefault("storageAreaId", "")); + List list = stockService.list(queryWrapper); + return getDataTable(list); + } + + /** + * 查询盘点单列表 importCurrStock + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @GetMapping("/list") + public TableDataInfo list(TPanOrder tPanOrder) { + startPage(); + tPanOrder.setDeptId(getDeptId()); + List list = tPanOrderService.selectTPanOrderList(tPanOrder); + return getDataTable(list); + } + + /** + * 导出盘点单列表 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "盘点单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TPanOrder tPanOrder) { + tPanOrder.setDeptId(getDeptId()); + List list = tPanOrderService.selectTPanOrderList(tPanOrder); + ExcelUtil util = new ExcelUtil(TPanOrder.class); + util.exportExcel(response, list, "盘点单数据"); + } + + /** + * 获取盘点单详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tPanOrderService.getById(id)); + } + + /** + * 新增盘点单 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "盘点单", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TPanOrder tPanOrder) { + tPanOrder.setDeptId(getDeptId()); + return toAjax(tPanOrderService.save(tPanOrder)); + } + + /** + * 修改盘点单 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "盘点单", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TPanOrder tPanOrder) { + return toAjax(tPanOrderService.updateById(tPanOrder)); + } + + /** + * 删除盘点单 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "盘点单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tPanOrderService.removeById(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "盘点单", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + List list = new ArrayList<>(); + for (String id : ids) { + TPanOrder tPanOrder = new TPanOrder(); + tPanOrder.setId(id); + tPanOrder.setDelFlag(1); + } + return toAjax(tPanOrderService.updateBatchById(list)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:pan:list')") + @Log(title = "盘点单", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TPanOrder tPanOrder) { + return toAjax(tPanOrderService.updateById(tPanOrder)); + } + + /** + * 手持盘点提交 + */ + @Log(title = "手持盘点", businessType = BusinessType.UPDATE) + @PutMapping("/pdaPanConfirm") + public AjaxResult pdaPanConfirm(@RequestBody List tMiStockList) { + return tPanOrderService.pdaPanConfirm(tMiStockList); + } +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkReceivingGoodsController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkReceivingGoodsController.java new file mode 100644 index 0000000..f59bc4a --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkReceivingGoodsController.java @@ -0,0 +1,145 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TRkReceivingGoods; +import com.zbf.system.service.ITRkReceivingGoodsService; + +/** + * 收货单Controller + * + * @author tony + * @date 2024-06-18 + */ +@RestController +@RequestMapping("/system/rkRecevinggoods") +public class TRkReceivingGoodsController extends BaseController +{ + @Autowired + private ITRkReceivingGoodsService tRkReceivingGoodsService; + +/** + * 查询收货单列表 + */ +@PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:list')") +@GetMapping("/list") + public TableDataInfo list(TRkReceivingGoods tRkReceivingGoods) + { + startPage(); + tRkReceivingGoods.setDeptId(getDeptId()); + List list = tRkReceivingGoodsService.selectTRkReceivingGoodsList(tRkReceivingGoods); + return getDataTable(list); + } + + /** + * 导出收货单列表 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:export')") + @Log(title = "收货单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TRkReceivingGoods tRkReceivingGoods) + { + tRkReceivingGoods.setDeptId(getDeptId()); + List list = tRkReceivingGoodsService.selectTRkReceivingGoodsList(tRkReceivingGoods); + ExcelUtil util = new ExcelUtil(TRkReceivingGoods.class); + util.exportExcel(response, list, "收货单数据"); + } + + /** + * 获取收货单详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tRkReceivingGoodsService.selectTRkReceivingGoodsById(id)); + } + + /** + * 新增收货单 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:add')") + @Log(title = "收货单", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TRkReceivingGoods tRkReceivingGoods) + { + tRkReceivingGoods.setId(OrderCodeFactory.getOrderCode("R", "")); + return toAjax(tRkReceivingGoodsService.insertTRkReceivingGoods(tRkReceivingGoods)); + } + + /** + * 修改收货单 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:edit')") + @Log(title = "收货单", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TRkReceivingGoods tRkReceivingGoods) + { + return toAjax(tRkReceivingGoodsService.updateTRkReceivingGoods(tRkReceivingGoods)); + } + + /** + * 删除收货单 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:remove')") + @Log(title = "收货单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tRkReceivingGoodsService.deleteTRkReceivingGoodsByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:remove')") + @Log(title = "收货单", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tRkReceivingGoodsService.disabledTRkReceivingGoodsByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:edit')") + @Log(title = "收货单", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tRkReceivingGoodsService.enableTRkReceivingGoodsByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:rkRecevinggoods:edit')") + @Log(title = "收货单", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TRkReceivingGoods tRkReceivingGoods) { + return toAjax(tRkReceivingGoodsService.updateStatus(tRkReceivingGoods)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeBakController.java new file mode 100644 index 0000000..ba480e3 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeBakController.java @@ -0,0 +1,138 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TRkWareNoticeBak; +import com.zbf.system.service.ITRkWareNoticeBakService; + +/** + * 入库通知单历史表Controller + * + * @author tony + * @date 2024-06-18 + */ +@RestController +@RequestMapping("/system/rkWareNoticeBak") +public class TRkWareNoticeBakController extends BaseController { + @Autowired + private ITRkWareNoticeBakService tRkWareNoticeBakService; + + /** + * 查询入库通知单历史表列表 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TRkWareNoticeBak.class) + public TableDataInfo list(TRkWareNoticeBak tRkWareNoticeBak) { + startPage(); + tRkWareNoticeBak.setDeptId(getDeptId()); + List list = tRkWareNoticeBakService.selectTRkWareNoticeBakList(tRkWareNoticeBak); + return getDataTable(list); + } + + /** + * 导出入库通知单历史表列表 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:export')") + @Log(title = "入库通知单历史表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TRkWareNoticeBak tRkWareNoticeBak) { + tRkWareNoticeBak.setDeptId(getDeptId()); + List list = tRkWareNoticeBakService.selectTRkWareNoticeBakList(tRkWareNoticeBak); + ExcelUtil util = new ExcelUtil(TRkWareNoticeBak.class); + util.exportExcel(response, list, "入库通知单历史表数据"); + } + + /** + * 获取入库通知单历史表详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tRkWareNoticeBakService.selectTRkWareNoticeBakById(id)); + } + + /** + * 新增入库通知单历史表 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:add')") + @Log(title = "入库通知单历史表", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TRkWareNoticeBak tRkWareNoticeBak) { + tRkWareNoticeBak.setId(OrderCodeFactory.getOrderCode("TRK", "")); + return toAjax(tRkWareNoticeBakService.insertTRkWareNoticeBak(tRkWareNoticeBak)); + } + + /** + * 修改入库通知单历史表 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:edit')") + @Log(title = "入库通知单历史表", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TRkWareNoticeBak tRkWareNoticeBak) { + return toAjax(tRkWareNoticeBakService.updateTRkWareNoticeBak(tRkWareNoticeBak)); + } + + /** + * 删除入库通知单历史表 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:remove')") + @Log(title = "入库通知单历史表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tRkWareNoticeBakService.deleteTRkWareNoticeBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:remove')") + @Log(title = "入库通知单历史表", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tRkWareNoticeBakService.disabledTRkWareNoticeBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:edit')") + @Log(title = "入库通知单历史表", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tRkWareNoticeBakService.enableTRkWareNoticeBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeBak:edit')") + @Log(title = "入库通知单历史表", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TRkWareNoticeBak tRkWareNoticeBak) { + return toAjax(tRkWareNoticeBakService.updateStatus(tRkWareNoticeBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeController.java new file mode 100644 index 0000000..fbed67f --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeController.java @@ -0,0 +1,344 @@ +package com.zbf.web.controller.system; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.system.domain.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.model.LoginUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.SecurityUtils; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.print.SalesTicket; +import com.zbf.system.print.YcPrinter; +import com.zbf.system.service.ITRkWareNoticeService; +import com.zbf.web.controller.section.EnhanceDataList; + +/** + * 入库通知单Controller + * + * @author tony + * @date 2024-06-18 + */ +@RestController +@RequestMapping("/system/trkNotice") +public class TRkWareNoticeController extends BaseController { + @Autowired + private ITRkWareNoticeService tRkWareNoticeService; + + /** + * 查询入库通知单列表 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:list')") + @GetMapping("/list") + @EnhanceDataList(entityType = TRkWareNotice.class) + public TableDataInfo list(TRkWareNotice tRkWareNotice) { + startPage(); + tRkWareNotice.setDeptId(getDeptId()); + List list = tRkWareNoticeService.selectTRkWareNoticeList(tRkWareNotice); + return getDataTable(list); + } + + /** + * 导出入库通知单列表 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:export')") + @Log(title = "入库通知单", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TRkWareNotice tRkWareNotice) { + tRkWareNotice.setDeptId(getDeptId()); + List list = tRkWareNoticeService.exportTRkWareNoticeList(tRkWareNotice); + ExcelUtil util = new ExcelUtil(TRkWareNotice.class); + util.exportExcel(response, list, "入库通知单数据"); + } + + /** + * 获取入库通知单详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + TRkWareNotice tRkWareNotice = tRkWareNoticeService.selectTRkWareNoticeById(id); + if (tRkWareNotice == null) { + tRkWareNotice = new TRkWareNotice(); + List tabs = new ArrayList(); + tRkWareNotice.setTRkWareNoticeTabList(tabs); + } + return success(tRkWareNotice); + } + + /** + * 获取入库通知单详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:query')") + @GetMapping(value = "/noticeId/{id}") + public AjaxResult getNoticeInfo(@PathVariable("id") String id) { + TRkWareNotice tRkWareNotice = tRkWareNoticeService.selectTRkWareNoticeByDeliveryId(id); + if (tRkWareNotice == null) { + tRkWareNotice = new TRkWareNotice(); + List tabs = new ArrayList(); + tRkWareNotice.setTRkWareNoticeTabList(tabs); + } + return success(tRkWareNotice); + } + + /** + * 新增入库通知单 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:add')") + @Log(title = "入库通知单", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TRkWareNotice tRkWareNotice) { + tRkWareNotice.setDeptId(getDeptId()); + tRkWareNotice.setId(OrderCodeFactory.getOrderCode("", "")); + tRkWareNotice.setNoticeId(OrderCodeFactory.getOrderCode("TWO", "")); + tRkWareNotice.setApplicant(SecurityUtils.getUserNick()); + tRkWareNotice.setCreateBy(getUsername()); + tRkWareNotice.setReceivingStatus("0"); + return toAjax(tRkWareNoticeService.insertTRkWareNotice(tRkWareNotice)); + } + + /** + * 修改入库通知单 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:edit')") + @Log(title = "入库通知单", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TRkWareNotice tRkWareNotice) { + return toAjax(tRkWareNoticeService.updateTRkWareNotice(tRkWareNotice)); + } + + /** + * 删除入库通知单 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:remove')") + @Log(title = "入库通知单", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult removeTabs(@PathVariable String[] ids) { + return toAjax(tRkWareNoticeService.deleteTRkWareNoticeByIds(ids)); + } + + /** + * 删除入库通知单明细 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:remove')") + @Log(title = "入库通知单", businessType = BusinessType.DELETE) + @DeleteMapping("/tabs/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + Map result = tRkWareNoticeService.deleteTRkWareNoticeTabByIds(ids); + return success(result); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:remove')") + @Log(title = "入库通知单", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) { + return toAjax(tRkWareNoticeService.disabledTRkWareNoticeByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:edit')") + @Log(title = "入库通知单", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) { + return toAjax(tRkWareNoticeService.enableTRkWareNoticeByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:edit')") + @Log(title = "入库通知单", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TRkWareNotice tRkWareNotice) { + return toAjax(tRkWareNoticeService.updateStatus(tRkWareNotice)); + } + + /** + * 收货接口 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:add')") + @Log(title = "确认入库通知单明细", businessType = BusinessType.INSERT) + @PostMapping("/confirmNoticeTab") + public AjaxResult confirmNoticeTab(@RequestBody TRkWareNoticeTabUpdate update) { + update.setDeptId(getDeptId()); + update.setUserName(getLoginUser().getUser().getNickName()); + Map result = tRkWareNoticeService.confirmNoticeTab(update); + return success(result); + } + + /** + * 入库通知单明细保存 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:add')") + @Log(title = "保存入库通知单明细", businessType = BusinessType.INSERT) + @PostMapping("/saveNoticeTab") + public AjaxResult saveNoticeTab(@RequestBody TRkWareNoticeTabUpdate update) { + update.setDeptId(getDeptId()); + update.setUserName(getLoginUser().getUser().getNickName()); + Map result = tRkWareNoticeService.saveNoticeTab(update); + return success(result); + } + + /** + * 入库通知单明细手动完成 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:add')") + @Log(title = "手动完成入库通知单明细", businessType = BusinessType.INSERT) + @PostMapping("/manualCompletion") + public AjaxResult manualCompletion(@RequestBody TRkWareNoticeTabUpdate update) { + update.setDeptId(getDeptId()); + update.setUserName(getLoginUser().getUser().getNickName()); + Map result = tRkWareNoticeService.manualCompletion(update); + return success(result); + } + + /** + * 上架入库 + */ + @PreAuthorize("@ss.hasPermi('system:trkNotice:add')") + @Log(title = "入库任务上架入库", businessType = BusinessType.INSERT) + @PostMapping("/shelvesConfirm") + public AjaxResult shelvesConfirm(@RequestBody TRkWareNoticeTabUpdate update) { + update.setDeptId(getDeptId()); + update.setUserName(getLoginUser().getUser().getNickName()); + Map result = tRkWareNoticeService.shelvesConfirm(update); + return success(result); + } + /** + * 导入 + */ + @Log(title = "入库数据", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { + ExcelUtil util = new ExcelUtil(TRkWareNoticeTab.class); + List trList = util.importExcel(file.getInputStream()); + LoginUser loginUser = getLoginUser(); + String operName = loginUser.getUser().getNickName(); + String message = tRkWareNoticeService.importData(trList, updateSupport, operName); + return AjaxResult.success(message); + } + + /** + * 一级库导入 + */ + @Log(title = "入库数据", businessType = BusinessType.IMPORT) + @PostMapping("/importExcelData") + public AjaxResult importExcelData(MultipartFile file, boolean updateSupport) throws Exception + { + ExcelUtil util = new ExcelUtil(TRkWareNoticeTabExcel.class); + List trList = util.importExcel(file.getInputStream()); + LoginUser loginUser = getLoginUser(); + String operName = loginUser.getUser().getNickName(); + String message = tRkWareNoticeService.importExcelData(trList, updateSupport, operName); + return AjaxResult.success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(TRkWareNoticeTab.class); + util.importTemplateExcel(response,"入库通知单"); + } + + @PostMapping("/importExcelTemplate") + public void importExcelTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(TRkWareNoticeTabExcel.class); + util.importTemplateExcel(response,"一级入库通知单"); + } + + @Log(title = "入库单条码打印", businessType = BusinessType.INSERT) + @PostMapping("/printBarCode") + public AjaxResult printBarCode(@RequestBody TRkWareNoticeTabUpdate update) { + int count = update.getPrintNum(); + for (int i = 0; i < count; i++) { + SalesTicket stk = new SalesTicket(update,null); + YcPrinter p = new YcPrinter(stk); + p.printer(); + } + + return AjaxResult.success("打印成功"); + } + + /** + * 发送入库通知单消息 + */ + @Log(title = "发送入库通知单消息", businessType = BusinessType.UPDATE) + @PostMapping("/sendOrderNotice") + public AjaxResult sendNotice(@RequestBody TRkWareNoticeTabUpdate update) { + update.setCreateBy(getLoginUser().getUser().getNickName()); + update.setDeptId(getDeptId()); + return AjaxResult.success(tRkWareNoticeService.sendOrderNotice(update)); + } + + + @Log(title = "推送入库通知单", businessType = BusinessType.UPDATE) + @PostMapping("/sendIwms") + public AjaxResult sendIwms(@RequestBody TRkWareNoticeTabUpdate update) { + update.setCreateBy(getLoginUser().getUser().getNickName()); + update.setDeptId(getDeptId()); + return AjaxResult.success(tRkWareNoticeService.sendIwmsUnified(update)); + } + + + + /** + * 手动入库 + */ + @Log(title = "无单收货", businessType = BusinessType.UPDATE) + @PostMapping("/handAddGoodsTab") + public AjaxResult handAddGoodsTab(@RequestBody TRkWareNoticeTabUpdate update) { + update.setId(OrderCodeFactory.getOrderCode("", "")); + update.setNoticeId(OrderCodeFactory.getOrderCode("TWO", "")); + return AjaxResult.success(tRkWareNoticeService.handAddGoodsTab(update)); + } + + + /** + * 虚拟库位上架 + */ + @Log(title = "虚拟库位上架", businessType = BusinessType.UPDATE) + @PostMapping("/virtualListing") + public AjaxResult virtualListing(@RequestBody TCkOrders orders) { + return AjaxResult.success(tRkWareNoticeService.virtualListing(orders)); + } + + /** + * 车间退货入库 + */ + @Log(title = "车间退货入库", businessType = BusinessType.UPDATE) + @PostMapping("/workshopReturn") + public AjaxResult workshopReturn(@RequestBody TckOrdersBak orders) { + orders.setApplicant(getLoginUser().getUser().getNickName()); + orders.setRecordPerson(getLoginUser().getUser().getNickName()); + orders.setDeptId(getDeptId()); + return AjaxResult.success(tRkWareNoticeService.workshopReturn(orders)); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabBakController.java new file mode 100644 index 0000000..e9793ed --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabBakController.java @@ -0,0 +1,193 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import com.zbf.system.domain.TRkWareNoticeBak; +import com.zbf.system.mapper.TRkWareNoticeTabBakMapper; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TRkWareNoticeTabBak; +import com.zbf.system.service.ITRkWareNoticeTabBakService; + +/** + * 入库通知单明细备份Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/rkWareNoticeTabBak") +public class TRkWareNoticeTabBakController extends BaseController +{ + @Autowired + private ITRkWareNoticeTabBakService tRkWareNoticeTabBakService; + + @Autowired + private TRkWareNoticeTabBakMapper tRkWareNoticeTabBakMapper; + +/** + * 查询入库通知单明细备份列表 + */ +@GetMapping("/list") +@EnhanceDataList(entityType = TRkWareNoticeTabBak.class) + public TableDataInfo list(TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + startPage(); +// tMiStock.setDeptId(getDeptId()); + if (tRkWareNoticeTabBak.getDate()!=null){ + String[] date = tRkWareNoticeTabBak.getDate(); + tRkWareNoticeTabBak.setStartTime(date[0]); + tRkWareNoticeTabBak.setEndTime(date[1]); + } + List list = tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakList(tRkWareNoticeTabBak); + return getDataTable(list); + } + + @GetMapping("/listSupplier") + @EnhanceDataList(entityType = TRkWareNoticeTabBak.class) + public TableDataInfo listSupplier() + { + TRkWareNoticeTabBak tRkWareNoticeTabBak = new TRkWareNoticeTabBak(); + List list = tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakList(tRkWareNoticeTabBak); + return getDataTable(list); + } + + + + + @GetMapping("/syList") + public TableDataInfo syList(TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + if (tRkWareNoticeTabBak.getDate()!=null){ + String[] date = tRkWareNoticeTabBak.getDate(); + tRkWareNoticeTabBak.setStartTime(date[0]); + tRkWareNoticeTabBak.setEndTime(date[1]); + } + List list = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakLists(); + return getDataTable(list); + } + + @GetMapping("/listTotal") + public AjaxResult listTotal(TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + if (tRkWareNoticeTabBak.getDate()!=null){ + String[] date = tRkWareNoticeTabBak.getDate(); + tRkWareNoticeTabBak.setStartTime(date[0]); + tRkWareNoticeTabBak.setEndTime(date[1]); + } + List list = tRkWareNoticeTabBakService.select(tRkWareNoticeTabBak); + return AjaxResult.success(list); + } + + + + /** + * 导出入库通知单明细备份列表 + */ +// @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:export')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + List list = tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakList(tRkWareNoticeTabBak); + ExcelUtil util = new ExcelUtil<>(TRkWareNoticeTabBak.class); + util.exportExcel(response, list, "入库通知单明细备份数据"); + } + + /** + * 获取入库通知单明细备份详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakById(id)); + } + + /** + * 新增入库通知单明细备份 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:add')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + tRkWareNoticeTabBak.setId(OrderCodeFactory.getOrderCode("TRKTAB", "")); + return toAjax(tRkWareNoticeTabBakService.insertTRkWareNoticeTabBak(tRkWareNoticeTabBak)); + } + + /** + * 修改入库通知单明细备份 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:edit')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + return toAjax(tRkWareNoticeTabBakService.updateTRkWareNoticeTabBak(tRkWareNoticeTabBak)); + } + + /** + * 删除入库通知单明细备份 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:remove')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabBakService.deleteTRkWareNoticeTabBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:remove')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabBakService.disabledTRkWareNoticeTabBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:edit')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabBakService.enableTRkWareNoticeTabBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:edit')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TRkWareNoticeTabBak tRkWareNoticeTabBak) { + return toAjax(tRkWareNoticeTabBakService.updateStatus(tRkWareNoticeTabBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabController.java new file mode 100644 index 0000000..9a44236 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkWareNoticeTabController.java @@ -0,0 +1,141 @@ +package com.zbf.web.controller.system; + +import java.util.List; + +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TRkWareNoticeTab; +import com.zbf.system.service.ITRkWareNoticeTabService; + +/** + * 入库通知单明细Controller + * + * @author tony + * @date 2024-08-16 + */ +@RestController +@RequestMapping("/system/trkWareNoticeTab") +public class TRkWareNoticeTabController extends BaseController +{ + @Autowired + private ITRkWareNoticeTabService tRkWareNoticeTabService; + +/** + * 查询入库通知单明细列表 + */ +@PreAuthorize("@ss.hasPermi('system:trkNotice:list')") +@GetMapping("/list") + public TableDataInfo list(TRkWareNoticeTab tRkWareNoticeTab) + { + startPage(); + List list = tRkWareNoticeTabService.selectTRkWareNoticeTabList(tRkWareNoticeTab); + return getDataTable(list); + } + + /** + * 导出入库通知单明细列表 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:export')") + @Log(title = "入库通知单明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TRkWareNoticeTab tRkWareNoticeTab) + { + List list = tRkWareNoticeTabService.selectTRkWareNoticeTabList(tRkWareNoticeTab); + ExcelUtil util = new ExcelUtil(TRkWareNoticeTab.class); + util.exportExcel(response, list, "入库通知单明细数据"); + } + + /** + * 获取入库通知单明细详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tRkWareNoticeTabService.selectTRkWareNoticeTabById(id)); + } + + /** + * 新增入库通知单明细 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:add')") + @Log(title = "入库通知单明细", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TRkWareNoticeTab tRkWareNoticeTab) + { + return toAjax(tRkWareNoticeTabService.insertTRkWareNoticeTab(tRkWareNoticeTab)); + } + + /** + * 修改入库通知单明细 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:edit')") + @Log(title = "入库通知单明细", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TRkWareNoticeTab tRkWareNoticeTab) + { + return toAjax(tRkWareNoticeTabService.updateTRkWareNoticeTab(tRkWareNoticeTab)); + } + + /** + * 删除入库通知单明细 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:remove')") + @Log(title = "入库通知单明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabService.deleteTRkWareNoticeTabByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:remove')") + @Log(title = "入库通知单明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabService.disabledTRkWareNoticeTabByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:edit')") + @Log(title = "入库通知单明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabService.enableTRkWareNoticeTabByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:trkWareNoticeTab:edit')") + @Log(title = "入库通知单明细", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TRkWareNoticeTab tRkWareNoticeTab) { + return toAjax(tRkWareNoticeTabService.updateStatus(tRkWareNoticeTab)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkXnWareNoticeTabBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkXnWareNoticeTabBakController.java new file mode 100644 index 0000000..ed1f4f0 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TRkXnWareNoticeTabBakController.java @@ -0,0 +1,208 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.OrderCodeFactory; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TRkWareNoticeTabBak; +import com.zbf.system.domain.TRkXnWareNoticeTabBak; +import com.zbf.system.domain.TckXnOrderdetailBak; +import com.zbf.system.mapper.TRkWareNoticeTabBakMapper; +import com.zbf.system.mapper.TRkXnWareNoticeTabBakMapper; +import com.zbf.system.service.ITRkWareNoticeTabBakService; +import com.zbf.system.service.ITRkXnWareNoticeTabBakService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 入库通知单明细备份Controller + * + * @author tony + * @date 2024-06-14 + */ +@RestController +@RequestMapping("/system/rkXnWareNoticeTabBak") +public class TRkXnWareNoticeTabBakController extends BaseController +{ + @Autowired + private ITRkXnWareNoticeTabBakService tRkWareNoticeTabBakService; + + @Autowired + private TRkXnWareNoticeTabBakMapper tRkWareNoticeTabBakMapper; + +/** + * 查询入库通知单明细备份列表 + */ +@GetMapping("/list") +@EnhanceDataList(entityType = TRkXnWareNoticeTabBak.class) + public TableDataInfo list(TRkXnWareNoticeTabBak tRkWareNoticeTabBak) + { + startPage(); +// tMiStock.setDeptId(getDeptId()); + if (tRkWareNoticeTabBak.getDate()!=null){ + String[] date = tRkWareNoticeTabBak.getDate(); + tRkWareNoticeTabBak.setStartTime(date[0]); + tRkWareNoticeTabBak.setEndTime(date[1]); + } + List list = tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakList(tRkWareNoticeTabBak); + return getDataTable(list); + } + + @GetMapping("/listSupplier") + @EnhanceDataList(entityType = TRkWareNoticeTabBak.class) + public TableDataInfo listSupplier() + { + TRkXnWareNoticeTabBak tRkWareNoticeTabBak = new TRkXnWareNoticeTabBak(); + List list = tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakList(tRkWareNoticeTabBak); + return getDataTable(list); + } + + + + + @GetMapping("/syList") + public TableDataInfo syList(TRkWareNoticeTabBak tRkWareNoticeTabBak) + { + if (tRkWareNoticeTabBak.getDate()!=null){ + String[] date = tRkWareNoticeTabBak.getDate(); + tRkWareNoticeTabBak.setStartTime(date[0]); + tRkWareNoticeTabBak.setEndTime(date[1]); + } + List list = tRkWareNoticeTabBakMapper.selectTRkWareNoticeTabBakLists(); + return getDataTable(list); + } + + @GetMapping("/listTotal") + public AjaxResult listTotal(TRkXnWareNoticeTabBak tRkWareNoticeTabBak) + { + if (tRkWareNoticeTabBak.getDate()!=null){ + String[] date = tRkWareNoticeTabBak.getDate(); + tRkWareNoticeTabBak.setStartTime(date[0]); + tRkWareNoticeTabBak.setEndTime(date[1]); + } + List list = tRkWareNoticeTabBakService.select(tRkWareNoticeTabBak); + return AjaxResult.success(list); + } + + + + /** + * 导出入库通知单明细备份列表 + */ +// @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:export')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TRkXnWareNoticeTabBak tRkWareNoticeTabBak) + { + List list = tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakList(tRkWareNoticeTabBak); + ExcelUtil util = new ExcelUtil<>(TRkXnWareNoticeTabBak.class); + util.exportExcel(response, list, "入库通知单明细备份数据"); + } + /** + * 导入 + */ + @Log(title = "出库数据", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) throws Exception + { + ExcelUtil util = new ExcelUtil(TRkXnWareNoticeTabBak.class); + List trList = util.importExcel(file.getInputStream()); + String message = tRkWareNoticeTabBakService.importData(trList, ""); + return AjaxResult.success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(TRkXnWareNoticeTabBak.class); + util.importTemplateExcel(response,"虚拟出库记录"); + } + + + /** + * 获取入库通知单明细备份详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tRkWareNoticeTabBakService.selectTRkWareNoticeTabBakById(id)); + } + + /** + * 新增入库通知单明细备份 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:add')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TRkXnWareNoticeTabBak tRkWareNoticeTabBak) + { + tRkWareNoticeTabBak.setId(OrderCodeFactory.getOrderCode("TRKTAB", "")); + return toAjax(tRkWareNoticeTabBakService.insertTRkWareNoticeTabBak(tRkWareNoticeTabBak)); + } + + /** + * 修改入库通知单明细备份 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:edit')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TRkXnWareNoticeTabBak tRkWareNoticeTabBak) + { + return toAjax(tRkWareNoticeTabBakService.updateTRkWareNoticeTabBak(tRkWareNoticeTabBak)); + } + + /** + * 删除入库通知单明细备份 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:remove')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabBakService.deleteTRkWareNoticeTabBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:remove')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabBakService.disabledTRkWareNoticeTabBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:edit')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tRkWareNoticeTabBakService.enableTRkWareNoticeTabBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:rkWareNoticeTabBak:edit')") + @Log(title = "入库通知单明细备份", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TRkXnWareNoticeTabBak tRkWareNoticeTabBak) { + return toAjax(tRkWareNoticeTabBakService.updateStatus(tRkWareNoticeTabBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TSafetyStockController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TSafetyStockController.java new file mode 100644 index 0000000..aa91feb --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TSafetyStockController.java @@ -0,0 +1,62 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.SafetyStockVO; +import com.zbf.system.service.ITSafetyStockService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 安全库存Controller + * + * @author sunits + * @date 2024-06-18 + */ +@RestController +@RequestMapping("/system/safetyStock") +@Api(value = "安全库存控制器", tags = {"安全库存管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class TSafetyStockController extends BaseController { + + + private final ITSafetyStockService safetyStockService; + + /** + * 查询库存列表 + */ + @ApiOperation("查询库存列表") + @PreAuthorize("@ss.hasPermi('system:safetyStock:list')") + @GetMapping("/list") + public TableDataInfo list(SafetyStockVO safetyStockVO) { + startPage(); + List list = safetyStockService.selectList(safetyStockVO); + return getDataTable(list); + } + + /** + * 导出库存列表 + */ + @ApiOperation("导出库存列表") + @PreAuthorize("@ss.hasPermi('system:safetyStock:export')") + @Log(title = "库存", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, SafetyStockVO safetyStockVO) { + List list = safetyStockService.selectList(safetyStockVO); + ExcelUtil util = new ExcelUtil(SafetyStockVO.class); + util.exportExcel(response, list, "库存数据"); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TStockCheckController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TStockCheckController.java new file mode 100644 index 0000000..b82b3f7 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TStockCheckController.java @@ -0,0 +1,105 @@ +package com.zbf.web.controller.system; + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TStockCheck; +import com.zbf.system.service.ITStockCheckService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 盘点库存数据Controller + * + * @author tony + * @date 2024-10-31 + */ +@RestController +@RequestMapping("/system/checkStock") +public class TStockCheckController extends BaseController +{ + @Autowired + private ITStockCheckService tStockCheckService; + + /** + * 查询盘点库存数据列表 + */ + @PreAuthorize("@ss.hasPermi('system:check:list')") + @GetMapping("/list") + public TableDataInfo list(TStockCheck tStockCheck) + { + startPage(); + List list = tStockCheckService.selectTStockCheckList(tStockCheck); + return getDataTable(list); + } + + /** + * 导出盘点库存数据列表 + */ + @PreAuthorize("@ss.hasPermi('system:check:export')") + @Log(title = "盘点库存数据", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TStockCheck tStockCheck) + { + List list = tStockCheckService.selectTStockCheckList(tStockCheck); + ExcelUtil util = new ExcelUtil(TStockCheck.class); + util.exportExcel(response, list, "盘点库存数据数据"); + } + + /** + * 获取盘点库存数据详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:check:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("checkId") String checkId) + + { + startPage(); + return success(tStockCheckService.selectTStockCheckById(checkId)); + } + + /** + * 新增盘点库存数据 + */ + @PreAuthorize("@ss.hasPermi('system:check:add')") + @Log(title = "盘点库存数据", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TStockCheck tStockCheck) + { + return toAjax(tStockCheckService.insertTStockCheck(tStockCheck)); + } + + /** + * 修改盘点库存数据 + */ + @PreAuthorize("@ss.hasPermi('system:check:edit')") + @Log(title = "盘点库存数据", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TStockCheck tStockCheck) + { + return toAjax(tStockCheckService.updateTStockCheck(tStockCheck)); + } + + + + + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:check:edit')") + @Log(title = "盘点库存数据", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TStockCheck tStockCheck) { + return toAjax(tStockCheckService.updateStatus(tStockCheck)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TUserConfigController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TUserConfigController.java new file mode 100644 index 0000000..d5a2306 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TUserConfigController.java @@ -0,0 +1,135 @@ +package com.zbf.web.controller.system; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.system.mapper.TUserConfigMapper; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TUserConfig; +import com.zbf.system.service.ITUserConfigService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 用户配置文件Controller + * + * @author tony + * @date 2024-07-10 + */ +@RestController +@RequestMapping("/system/UserConfiguration") +public class TUserConfigController extends BaseController { + @Autowired + private ITUserConfigService tUserConfigService; + @Autowired + private TUserConfigMapper tUserConfigMapper; + + + /** + * 查询用户配置文件列表 + */ + @GetMapping("/list") + public TableDataInfo list(TUserConfig tUserConfig) { + startPage(); + List list = tUserConfigService.list(new LambdaQueryWrapper<>(tUserConfig)); + return getDataTable(list); + } + + /** + * 导出用户配置文件列表 + */ + @Log(title = "用户配置文件", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TUserConfig tUserConfig) { + List list = tUserConfigService.list(new LambdaQueryWrapper<>(tUserConfig)); + ExcelUtil util = new ExcelUtil(TUserConfig.class); + util.exportExcel(response, list, "用户配置文件数据"); + } + + /** + * 获取用户配置文件详细信息 + */ + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(tUserConfigService.getById(id)); + } + + /** + * 新增用户配置文件 + */ + @Log(title = "用户配置文件", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TUserConfig tUserConfig) { + return toAjax(tUserConfigMapper.insert(tUserConfig)); + } + + /** + * 修改用户配置文件 + */ + @Log(title = "用户配置文件", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TUserConfig tUserConfig) { + LambdaQueryWrapper query = new LambdaQueryWrapper<>(); + query.eq(TUserConfig::getUserId, tUserConfig.getUserId()); + query.eq(TUserConfig::getRouterPath, tUserConfig.getRouterPath()); + query.eq(TUserConfig::getCompName, tUserConfig.getCompName()); + + List tUserConfigs = tUserConfigMapper.selectList(query); + if (tUserConfigs.size() > 0) { + TUserConfig userConfig = tUserConfigs.get(0); + userConfig.setCnfJson(tUserConfig.getCnfJson()); + return toAjax(tUserConfigService.updateById(userConfig)); + } else { + return toAjax(tUserConfigMapper.insert(tUserConfig)); + } + } + + /** + * 删除用户配置文件 + */ + @Log(title = "用户配置文件", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(tUserConfigService.removeById(ids)); + } + + /** + * 修改状态 + */ + @Log(title = "用户配置文件", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TUserConfig tUserConfig) { + return toAjax(tUserConfigService.updateById(tUserConfig)); + } + + /** + * 根据id 和菜单查询 + * + * @param config + * @return + */ + @PostMapping(value = "/information") + public AjaxResult getInfo(@RequestBody TUserConfig config) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TUserConfig::getUserId, config.getUserId()); // 确保这里传入的是有效的userId + queryWrapper.eq(TUserConfig::getRouterPath, config.getRouterPath()); // 确保这里传入的是有效的routerPath + TUserConfig object = tUserConfigService.getOne(queryWrapper); + return AjaxResult.success(object); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TUserFavoritesController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TUserFavoritesController.java new file mode 100644 index 0000000..9a4d4a0 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TUserFavoritesController.java @@ -0,0 +1,129 @@ +package com.zbf.web.controller.system; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TUserFavorites; +import com.zbf.system.mapper.TUserFavoritesMapper; +import com.zbf.system.service.ITUserFavoritesService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 常用功能收藏夹Controller + * + * @author tony + * @date 2024-07-03 + */ +@RestController +@RequestMapping("/system/favorites") +public class TUserFavoritesController extends BaseController { + private final ITUserFavoritesService tUserFavoritesService; + private TUserFavoritesMapper favoritesMapper; + + public TUserFavoritesController(ITUserFavoritesService tUserFavoritesService, TUserFavoritesMapper favoritesMapper) { + this.tUserFavoritesService = tUserFavoritesService; + this.favoritesMapper = favoritesMapper; + } + + /** + * 查询常用功能收藏夹列表 + */ + @GetMapping("/list") + public TableDataInfo list(TUserFavorites tUserFavorites) { + LambdaQueryWrapper query = new LambdaQueryWrapper(tUserFavorites); + List list = favoritesMapper.selectList(query); + return getDataTable(list); + } + + /** + * 导出常用功能收藏夹列表 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TUserFavorites tUserFavorites) { + List list = tUserFavoritesService.selectTUserFavoritesList(tUserFavorites); + ExcelUtil util = new ExcelUtil(TUserFavorites.class); + util.exportExcel(response, list, "常用功能收藏夹数据"); + } + + /** + * 获取常用功能收藏夹详细信息 + */ + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) { + return success(tUserFavoritesService.selectTUserFavoritesById(id)); + } + + /** + * 新增常用功能收藏夹 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TUserFavorites tUserFavorites) { + favoritesMapper.insert(tUserFavorites); + AjaxResult ajax = AjaxResult.success(); + ajax.put("favorites", tUserFavorites); + return ajax; + } + + /** + * 修改常用功能收藏夹 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TUserFavorites tUserFavorites) { + return toAjax(favoritesMapper.updateById(tUserFavorites)); + } + + /** + * 删除常用功能收藏夹 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(tUserFavoritesService.deleteTUserFavoritesByIds(ids)); + } + + /** + * 禁用 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{id}") + public AjaxResult disable(@PathVariable String id) { + TUserFavorites favorites = new TUserFavorites(); + favorites.setId(id); + favorites.setStatus("1"); // state=1 表示禁用 + return toAjax(favoritesMapper.updateById(favorites)); + } + + /** + * 启用 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{id}") + public AjaxResult enable(@PathVariable String id) { + TUserFavorites favorites = new TUserFavorites(); + favorites.setId(id); + favorites.setStatus("0");// state=1 表示启用 + return toAjax(favoritesMapper.updateById(favorites)); + } + + /** + * 修改状态 + */ + @Log(title = "常用功能收藏夹", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TUserFavorites tUserFavorites) { + return toAjax(tUserFavoritesService.updateStatus(tUserFavorites)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrderdetailBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrderdetailBakController.java new file mode 100644 index 0000000..e27ed2f --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrderdetailBakController.java @@ -0,0 +1,247 @@ +package com.zbf.web.controller.system; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletResponse; + +import com.github.pagehelper.util.StringUtil; +import com.zbf.common.core.domain.TreeSelect; +import com.zbf.common.core.domain.entity.SysDept; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.service.ISysDeptService; +import com.zbf.system.service.ISysUserService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.apache.commons.lang3.ObjectUtils; +import org.dom4j.util.StringUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.enums.BusinessType; +import com.zbf.system.domain.TckOrderdetailBak; +import com.zbf.system.service.ITckOrderdetailBakService; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.common.core.page.TableDataInfo; + +/** + * 出库物料明细Controller + * + * @author tony + * @date 2024-09-09 + */ +@RestController +@RequestMapping("/system/tckOrderDetailbak") +public class TckOrderdetailBakController extends BaseController +{ + @Autowired + private ITckOrderdetailBakService tckOrderdetailBakService; + @Autowired + private ISysDeptService sysDeptService; + @Autowired + private ISysUserService sysUserService; + +/** + * 查询出库物料明细列表 + */ +@GetMapping("/list") +@EnhanceDataList(entityType = TckOrderdetailBak.class) + public TableDataInfo list(TckOrderdetailBak tckOrderdetailBak) + { + startPage(); + if (tckOrderdetailBak.getDate()!=null){ + String[] date = tckOrderdetailBak.getDate(); + tckOrderdetailBak.setStartTime(date[0]); + tckOrderdetailBak.setEndTime(date[1]); + } + if(StringUtil.isNotEmpty(tckOrderdetailBak.getSupplier())){ + //查找该部门下对应的子部门 + SysDept sysDept = new SysDept(); + sysDept.setDeptName(tckOrderdetailBak.getSupplier()); + List sysDepts = sysDeptService.selectDeptList(sysDept); + String deptId = String.valueOf(sysDepts.get(0).getDeptId()); + List treeSelects = sysDeptService.selectDeptList(new SysDept()); + List collect = treeSelects.stream() + .filter(f -> Arrays.asList(f.getAncestors().split(",")).contains(String.valueOf(deptId)) + || f.getDeptId() == sysDepts.get(0).getDeptId() ) + .collect(Collectors.toList()); + Long[] ids = collect.stream() + .map(SysDept::getDeptId) // 提取 ID + .toArray(Long[]::new); + + //查询该部门下的所有员工 + List sysUsers = sysUserService.selectUserByDeptIds(ids); + String[] nickName = sysUsers.stream().map(SysUser::getNickName).toArray(String[]::new); + if(StringUtil.isNotEmpty(tckOrderdetailBak.getApplicant())){ + if (Arrays.asList(nickName).contains(tckOrderdetailBak.getApplicant())) { + // 包含 + return getDataTable(tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak)); + }else{ + TckOrderdetailBak tckOrderdetailBak1 = new TckOrderdetailBak(); + tckOrderdetailBak1.setApplicant("不存在"); + return getDataTable(tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak1)); + } + } + List list = tckOrderdetailBakService.selectTckOrderdetailBakList(new TckOrderdetailBak()); + //查找表中符合的员工对应的数据 + List filteredList = list.stream() + .filter(f -> StringUtil.isNotEmpty(f.getApplicant())&& + Arrays.stream(nickName) + .anyMatch(n -> f.getApplicant().contains(n))) + .collect(Collectors.toList()); + return getDataTable(filteredList); + }else{ + List list = tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak); + for (TckOrderdetailBak t : list) { + SysUser sysUser = new SysUser(); + sysUser.setNickName(t.getApplicant()); + List sysUsers = sysUserService.selectUserList(sysUser); + if(ObjectUtils.isEmpty(sysUsers)){ + t.setSupplier(""); + }else{ + Long deptId = sysUsers.get(0).getDeptId(); + SysDept sysDept = new SysDept(); + sysDept.setDeptId(deptId); + List sysDepts = sysDeptService.selectDeptList(sysDept); + if(ObjectUtils.isEmpty(sysDepts)){ + t.setSupplier(""); + }else{ + SysDept sysDept1 = sysDepts.get(0); + if(sysDept1.getAncestors().split(",").length>3){ + String s = sysDept1.getAncestors().split(",")[2]; + sysDept.setDeptId(Long.valueOf(s)); + List sysDepts1 = sysDeptService.selectDeptList(sysDept); + t.setSupplier(sysDepts1.get(0).getDeptName()); + }else{ + t.setSupplier(sysDept1.getDeptName()); + } + } + } + } + return getDataTable(list); + } + + } + +// @GetMapping("/supplier") +// @EnhanceDataList(entityType = TckOrderdetailBak.class) +// public TableDataInfo supplier() +// { +// TckOrderdetailBak tckOrderdetailBak = new TckOrderdetailBak(); +// List list = tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak); +// return getDataTable(list); +// } + + @GetMapping("/lists") + @EnhanceDataList(entityType = TMiStock.class) + public AjaxResult lists(TckOrderdetailBak tckOrderdetailBak) { + if (tckOrderdetailBak.getDate()!=null){ + String[] date = tckOrderdetailBak.getDate(); + tckOrderdetailBak.setStartTime(date[0]); + tckOrderdetailBak.setEndTime(date[1]); + } + List list = tckOrderdetailBakService.select(tckOrderdetailBak); + return AjaxResult.success(list); + } + + /** + * 导出出库物料明细列表 + */ +// @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:export')") + @Log(title = "出库物料明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TckOrderdetailBak tckOrderdetailBak) + { + List list = tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak); + ExcelUtil util = new ExcelUtil(TckOrderdetailBak.class); + util.exportExcel(response, list, "出库物料明细数据"); + } + + /** + * 获取出库物料明细详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tckOrderdetailBakService.selectTckOrderdetailBakById(id)); + } + + /** + * 新增出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:add')") + @Log(title = "出库物料明细", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TckOrderdetailBak tckOrderdetailBak) + { + return toAjax(tckOrderdetailBakService.insertTckOrderdetailBak(tckOrderdetailBak)); + } + + /** + * 修改出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TckOrderdetailBak tckOrderdetailBak) + { + return toAjax(tckOrderdetailBakService.updateTckOrderdetailBak(tckOrderdetailBak)); + } + + /** + * 删除出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:remove')") + @Log(title = "出库物料明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tckOrderdetailBakService.deleteTckOrderdetailBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:remove')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tckOrderdetailBakService.disabledTckOrderdetailBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tckOrderdetailBakService.enableTckOrderdetailBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TckOrderdetailBak tckOrderdetailBak) { + return toAjax(tckOrderdetailBakService.updateStatus(tckOrderdetailBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrdersBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrdersBakController.java new file mode 100644 index 0000000..db16d40 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TckOrdersBakController.java @@ -0,0 +1,155 @@ +package com.zbf.web.controller.system; + +import com.alibaba.druid.util.StringUtils; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TckOrderdetailBak; +import com.zbf.system.domain.TckOrdersBak; +import com.zbf.system.service.ITckOrdersBakService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 出库单历史表Controller + * + * @author tony + * @date 2024-07-03 + */ +@RestController +@RequestMapping("/system/tckOrdersbak") +public class TckOrdersBakController extends BaseController +{ + @Autowired + private ITckOrdersBakService tckOrdersBakService; + + /** + * 查询出库单历史表列表 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:list')") + @EnhanceDataList(entityType = TckOrdersBak.class) + @GetMapping("/list") + public TableDataInfo list(TckOrdersBak tckOrdersBak) + { + startPage(); + List list = tckOrdersBakService.selectTckOrdersBakList(tckOrdersBak); + return getDataTable(list); + } + + /* * + * 查询出库单历史表列表(退库入库)*/ + @EnhanceDataList(entityType = TckOrdersBak.class) + @GetMapping("/selectList") + public TableDataInfo ckOrders(TckOrderdetailBak tckOrderdetailBak) + { + startPage(); + if(!StringUtils.isEmpty(tckOrderdetailBak.getStartDate())) { + tckOrderdetailBak.setStartDate(tckOrderdetailBak.getStartDate() + " 00:00:00"); + } + + if(!StringUtils.isEmpty(tckOrderdetailBak.getEndDate())) { + tckOrderdetailBak.setEndDate(tckOrderdetailBak.getEndDate() + " 23:59:59"); + } + List list = tckOrdersBakService.selectReturnTckOrdersBakList(tckOrderdetailBak); + return getDataTable(list); + } + + + /** + * 导出出库单历史表列表 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:export')") + @Log(title = "出库单历史表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TckOrdersBak tckOrdersBak) + { + List list = tckOrdersBakService.selectTckOrdersBakList(tckOrdersBak); + ExcelUtil util = new ExcelUtil(TckOrdersBak.class); + util.exportExcel(response, list, "出库单历史表数据"); + } + + /** + * 获取出库单历史表详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tckOrdersBakService.selectTckOrdersBakById(id)); + } + + /** + * 新增出库单历史表 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:add')") + @Log(title = "出库单历史表", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TckOrdersBak tckOrdersBak) + { + return toAjax(tckOrdersBakService.insertTckOrdersBak(tckOrdersBak)); + } + + /** + * 修改出库单历史表 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:edit')") + @Log(title = "出库单历史表", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TckOrdersBak tckOrdersBak) + { + return toAjax(tckOrdersBakService.updateTckOrdersBak(tckOrdersBak)); + } + + /** + * 删除出库单历史表 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:remove')") + @Log(title = "出库单历史表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tckOrdersBakService.deleteTckOrdersBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:remove')") + @Log(title = "出库单历史表", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tckOrdersBakService.disabledTckOrdersBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:edit')") + @Log(title = "出库单历史表", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tckOrdersBakService.enableTckOrdersBakByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:tckOrdersbak:edit')") + @Log(title = "出库单历史表", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TckOrdersBak tckOrdersBak) { + return toAjax(tckOrdersBakService.updateStatus(tckOrdersBak)); + } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TckXnOrderdetailBakController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TckXnOrderdetailBakController.java new file mode 100644 index 0000000..698250e --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TckXnOrderdetailBakController.java @@ -0,0 +1,233 @@ +package com.zbf.web.controller.system; + +import com.github.pagehelper.util.StringUtil; +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.domain.entity.SysDept; +import com.zbf.common.core.domain.entity.SysUser; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TMiStock; +import com.zbf.system.domain.TMiXnStock; +import com.zbf.system.domain.TckOrderdetailBak; +import com.zbf.system.domain.TckXnOrderdetailBak; +import com.zbf.system.service.ISysDeptService; +import com.zbf.system.service.ISysUserService; +import com.zbf.system.service.ITckOrderdetailBakService; +import com.zbf.system.service.ITckXnOrderdetailBakService; +import com.zbf.web.controller.section.EnhanceDataList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 出库物料明细Controller + * + * @author tony + * @date 2024-09-09 + */ +@RestController +@RequestMapping("/system/tckXnOrderDetailbak") +public class TckXnOrderdetailBakController extends BaseController +{ + @Autowired + private ITckXnOrderdetailBakService tckOrderdetailBakService; + @Autowired + private ISysDeptService sysDeptService; + @Autowired + private ISysUserService sysUserService; + +/** + * 查询出库物料明细列表 + */ +@GetMapping("/list") +@EnhanceDataList(entityType = TckXnOrderdetailBak.class) + public TableDataInfo list(TckXnOrderdetailBak tckOrderdetailBak) + { + startPage(); + if (tckOrderdetailBak.getDate()!=null){ + String[] date = tckOrderdetailBak.getDate(); + tckOrderdetailBak.setStartTime(date[0]); + tckOrderdetailBak.setEndTime(date[1]); + } + if(StringUtil.isNotEmpty(tckOrderdetailBak.getSupplier())){ + //查找该部门下对应的子部门 + SysDept sysDept = new SysDept(); + sysDept.setDeptName(tckOrderdetailBak.getSupplier()); + List sysDepts = sysDeptService.selectDeptList(sysDept); + String deptId = String.valueOf(sysDepts.get(0).getDeptId()); + List treeSelects = sysDeptService.selectDeptList(new SysDept()); + List collect = treeSelects.stream() + .filter(f -> Arrays.asList(f.getAncestors().split(",")).contains(String.valueOf(deptId)) + || f.getDeptId() == sysDepts.get(0).getDeptId() ) + .collect(Collectors.toList()); + Long[] ids = collect.stream() + .map(SysDept::getDeptId) // 提取 ID + .toArray(Long[]::new); + + //查询该部门下的所有员工 + List sysUsers = sysUserService.selectUserByDeptIds(ids); + String[] nickName = sysUsers.stream().map(SysUser::getNickName).toArray(String[]::new); + if(StringUtil.isNotEmpty(tckOrderdetailBak.getApplicant())){ + if (Arrays.asList(nickName).contains(tckOrderdetailBak.getApplicant())) { + // 包含 + return getDataTable(tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak)); + }else{ + TckXnOrderdetailBak tckOrderdetailBak1 = new TckXnOrderdetailBak(); + tckOrderdetailBak1.setApplicant("不存在"); + return getDataTable(tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak1)); + } + } + List list = tckOrderdetailBakService.selectTckOrderdetailBakList(new TckXnOrderdetailBak()); + //查找表中符合的员工对应的数据 + List filteredList = list.stream() + .filter(f -> StringUtil.isNotEmpty(f.getApplicant())&& + Arrays.stream(nickName) + .anyMatch(n -> f.getApplicant().contains(n))) + .collect(Collectors.toList()); + return getDataTable(filteredList); + }else{ + List list = tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak); + return getDataTable(list); + } + + } + /** + * 导入 + */ + @Log(title = "出库数据", businessType = BusinessType.IMPORT) + @PostMapping("/importData") + public AjaxResult importData(MultipartFile file) throws Exception + { + ExcelUtil util = new ExcelUtil(TckXnOrderdetailBak.class); + List trList = util.importExcel(file.getInputStream()); + String message = tckOrderdetailBakService.importData(trList, ""); + return AjaxResult.success(message); + } + + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) + { + ExcelUtil util = new ExcelUtil(TckXnOrderdetailBak.class); + util.importTemplateExcel(response,"虚拟出库记录"); + } + +// @GetMapping("/supplier") +// @EnhanceDataList(entityType = TckOrderdetailBak.class) +// public TableDataInfo supplier() +// { +// TckOrderdetailBak tckOrderdetailBak = new TckOrderdetailBak(); +// List list = tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak); +// return getDataTable(list); +// } + + @GetMapping("/lists") + @EnhanceDataList(entityType = TMiStock.class) + public AjaxResult lists(TckXnOrderdetailBak tckOrderdetailBak) { + if (tckOrderdetailBak.getDate()!=null){ + String[] date = tckOrderdetailBak.getDate(); + tckOrderdetailBak.setStartTime(date[0]); + tckOrderdetailBak.setEndTime(date[1]); + } + List list = tckOrderdetailBakService.select(tckOrderdetailBak); + return AjaxResult.success(list); + } + + /** + * 导出出库物料明细列表 + */ +// @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:export')") + @Log(title = "出库物料明细", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TckXnOrderdetailBak tckOrderdetailBak) + { + List list = tckOrderdetailBakService.selectTckOrderdetailBakList(tckOrderdetailBak); + ExcelUtil util = new ExcelUtil(TckXnOrderdetailBak.class); + util.exportExcel(response, list, "出库物料明细数据"); + } + + /** + * 获取出库物料明细详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:tckXnOrdersbak:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") String id) + { + return success(tckOrderdetailBakService.selectTckOrderdetailBakById(id)); + } + + /** + * 新增出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:tckXnOrdersbak:add')") + @Log(title = "出库物料明细", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TckXnOrderdetailBak tckOrderdetailBak) + { + return toAjax(tckOrderdetailBakService.insertTckOrderdetailBak(tckOrderdetailBak)); + } + + /** + * 修改出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:tckXnOrdersbak:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TckXnOrderdetailBak tckOrderdetailBak) + { + return toAjax(tckOrderdetailBakService.updateTckOrderdetailBak(tckOrderdetailBak)); + } + + /** + * 删除出库物料明细 + */ + @PreAuthorize("@ss.hasPermi('system:tckXnOrdersbak:remove')") + @Log(title = "出库物料明细", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(tckOrderdetailBakService.deleteTckOrderdetailBakByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:tckXnOrdersbak:remove')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable String[] ids) + { + return toAjax(tckOrderdetailBakService.disabledTckOrderdetailBakByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:tckXnOrdersbak:edit')") + @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable String[] ids) + { + return toAjax(tckOrderdetailBakService.enableTckOrderdetailBakByIds(ids)); + } + + /** + * 修改状态 + */ +// @PreAuthorize("@ss.hasPermi('system:tckOrderDetailbak:edit')") +// @Log(title = "出库物料明细", businessType = BusinessType.UPDATE) +// @PutMapping("/changeStatus") +// public AjaxResult changeStatus(@RequestBody TckXnOrderdetailBak tckOrderdetailBak) { +// return toAjax(tckOrderdetailBakService.updateStatus(tckOrderdetailBak)); +// } + +} + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/system/TransferOrderController.java b/zbf-admin/src/main/java/com/zbf/web/controller/system/TransferOrderController.java new file mode 100644 index 0000000..c28097f --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/system/TransferOrderController.java @@ -0,0 +1,128 @@ +package com.zbf.web.controller.system; + + +import com.zbf.common.annotation.Log; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.AjaxResult; +import com.zbf.common.core.page.TableDataInfo; +import com.zbf.common.enums.BusinessType; +import com.zbf.common.utils.poi.ExcelUtil; +import com.zbf.system.domain.TransferOrder; +import com.zbf.system.service.ITransferOrderService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 调拨单 + * Controller + * + * @author tony + * @date 2024-11-03 + */ +@RestController +@RequestMapping("/system/order") +public class TransferOrderController extends BaseController { + @Autowired + private ITransferOrderService transferOrderService; + + /** + * 查询调拨单 + * 列表 + */ + @PreAuthorize("@ss.hasPermi('system:order:list')") + @GetMapping("/list") + public TableDataInfo list(TransferOrder transferOrder) { + startPage(); + List list = transferOrderService.selectTransferOrderList(transferOrder); + return getDataTable(list); + } + + /** + * 导出调拨单 + * 列表 + */ + @PreAuthorize("@ss.hasPermi('system:order:export')") + @Log(title = "调拨单 ", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, TransferOrder transferOrder) { + List list = transferOrderService.selectTransferOrderList(transferOrder); + ExcelUtil util = new ExcelUtil(TransferOrder.class); + util.exportExcel(response, list, "调拨单数据"); + } + + /** + * 获取调拨单 + * 详细信息 + */ + @PreAuthorize("@ss.hasPermi('system:order:query')") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) { + return success(transferOrderService.selectTransferOrderById(id)); + } + + /** + * 新增调拨单 + */ + @PreAuthorize("@ss.hasPermi('system:order:add')") + @Log(title = "调拨单 ", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody TransferOrder transferOrder) { + return toAjax(transferOrderService.insertTransferOrder(transferOrder)); + } + + /** + * 修改调拨单 + */ + @PreAuthorize("@ss.hasPermi('system:order:edit')") + @Log(title = "调拨单 ", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody TransferOrder transferOrder) { + return toAjax(transferOrderService.updateTransferOrder(transferOrder)); + } + + /** + * 删除调拨单 + */ + @PreAuthorize("@ss.hasPermi('system:order:remove')") + @Log(title = "调拨单 ", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(transferOrderService.deleteTransferOrderByIds(ids)); + } + + /** + * 启用 + */ + @PreAuthorize("@ss.hasPermi('system:order:remove')") + @Log(title = "调拨单 ", businessType = BusinessType.UPDATE) + @DeleteMapping("/disable/{ids}") + public AjaxResult disable(@PathVariable Long[] ids) { + return toAjax(transferOrderService.disabledTransferOrderByIds(ids)); + } + + /** + * 禁用 + */ + @PreAuthorize("@ss.hasPermi('system:order:edit')") + @Log(title = "调拨单 ", businessType = BusinessType.UPDATE) + @DeleteMapping("/enable/{ids}") + public AjaxResult enable(@PathVariable Long[] ids) { + return toAjax(transferOrderService.enableTransferOrderByIds(ids)); + } + + /** + * 修改状态 + */ + @PreAuthorize("@ss.hasPermi('system:order:edit')") + @Log(title = "调拨单 ", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody TransferOrder transferOrder) { + return toAjax(transferOrderService.updateStatus(transferOrder)); + } +} + + diff --git a/zbf-admin/src/main/java/com/zbf/web/controller/tool/TestController.java b/zbf-admin/src/main/java/com/zbf/web/controller/tool/TestController.java new file mode 100644 index 0000000..932b7f4 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/controller/tool/TestController.java @@ -0,0 +1,183 @@ +package com.zbf.web.controller.tool; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.zbf.common.core.controller.BaseController; +import com.zbf.common.core.domain.R; +import com.zbf.common.utils.StringUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiOperation; + +/** + * swagger 用户测试方法 + * + * @author ruoyi + */ +@Api("用户信息管理") +@RestController +@RequestMapping("/test/user") +public class TestController extends BaseController +{ + private final static Map users = new LinkedHashMap(); + { + users.put(1, new UserEntity(1, "admin", "admin123", "15888888888")); + users.put(2, new UserEntity(2, "ry", "admin123", "15666666666")); + } + + @ApiOperation("获取用户列表") + @GetMapping("/list") + public R> userList() + { + List userList = new ArrayList(users.values()); + return R.ok(userList); + } + + @ApiOperation("获取用户详细") + @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) + @GetMapping("/{userId}") + public R getUser(@PathVariable Integer userId) + { + if (!users.isEmpty() && users.containsKey(userId)) + { + return R.ok(users.get(userId)); + } + else + { + return R.fail("用户不存在"); + } + } + + @ApiOperation("新增用户") + @ApiImplicitParams({ + @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class), + @ApiImplicitParam(name = "username", value = "登录账号", dataType = "String", dataTypeClass = String.class), + @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class), + @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class) + }) + @PostMapping("/save") + public R save(UserEntity user) + { + if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) + { + return R.fail("用户ID不能为空"); + } + users.put(user.getUserId(), user); + return R.ok(); + } + + @ApiOperation("更新用户") + @PutMapping("/update") + public R update(@RequestBody UserEntity user) + { + if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) + { + return R.fail("用户ID不能为空"); + } + if (users.isEmpty() || !users.containsKey(user.getUserId())) + { + return R.fail("用户不存在"); + } + users.remove(user.getUserId()); + users.put(user.getUserId(), user); + return R.ok(); + } + + @ApiOperation("删除用户信息") + @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class) + @DeleteMapping("/{userId}") + public R delete(@PathVariable Integer userId) + { + if (!users.isEmpty() && users.containsKey(userId)) + { + users.remove(userId); + return R.ok(); + } + else + { + return R.fail("用户不存在"); + } + } +} + +@ApiModel(value = "UserEntity", description = "用户实体") +class UserEntity +{ + @ApiModelProperty("用户ID") + private Integer userId; + + @ApiModelProperty("用户名称") + private String username; + + @ApiModelProperty("用户密码") + private String password; + + @ApiModelProperty("用户手机") + private String mobile; + + public UserEntity() + { + + } + + public UserEntity(Integer userId, String username, String password, String mobile) + { + this.userId = userId; + this.username = username; + this.password = password; + this.mobile = mobile; + } + + public Integer getUserId() + { + return userId; + } + + public void setUserId(Integer userId) + { + this.userId = userId; + } + + public String getUsername() + { + return username; + } + + public void setUsername(String username) + { + this.username = username; + } + + public String getPassword() + { + return password; + } + + public void setPassword(String password) + { + this.password = password; + } + + public String getMobile() + { + return mobile; + } + + public void setMobile(String mobile) + { + this.mobile = mobile; + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/core/config/SwaggerConfig.java b/zbf-admin/src/main/java/com/zbf/web/core/config/SwaggerConfig.java new file mode 100644 index 0000000..2e2c3d5 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/core/config/SwaggerConfig.java @@ -0,0 +1,125 @@ +package com.zbf.web.core.config; + +import java.util.ArrayList; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.zbf.common.config.RuoYiConfig; +import io.swagger.annotations.ApiOperation; +import io.swagger.models.auth.In; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.service.AuthorizationScope; +import springfox.documentation.service.Contact; +import springfox.documentation.service.SecurityReference; +import springfox.documentation.service.SecurityScheme; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; + +/** + * Swagger2的接口配置 + * + * @author ruoyi + */ +@Configuration +public class SwaggerConfig +{ + /** 系统基础配置 */ + @Autowired + private RuoYiConfig ruoyiConfig; + + /** 是否开启swagger */ + @Value("${swagger.enabled}") + private boolean enabled; + + /** 设置请求的统一前缀 */ + @Value("${swagger.pathMapping}") + private String pathMapping; + + /** + * 创建API + */ + @Bean + public Docket createRestApi() + { + return new Docket(DocumentationType.OAS_30) + // 是否启用Swagger + .enable(enabled) + // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) + .apiInfo(apiInfo()) + // 设置哪些接口暴露给Swagger展示 + .select() + // 扫描所有有注解的api,用这种方式更灵活 + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + // 扫描指定包中的swagger注解 + // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger")) + // 扫描所有 .apis(RequestHandlerSelectors.any()) + .paths(PathSelectors.any()) + .build() + /* 设置安全模式,swagger可以设置访问token */ + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()) + .pathMapping(pathMapping); + } + + /** + * 安全模式,这里指定token通过Authorization头请求头传递 + */ + private List securitySchemes() + { + List apiKeyList = new ArrayList(); + apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue())); + return apiKeyList; + } + + /** + * 安全上下文 + */ + private List securityContexts() + { + List securityContexts = new ArrayList<>(); + securityContexts.add( + SecurityContext.builder() + .securityReferences(defaultAuth()) + .operationSelector(o -> o.requestMappingPattern().matches("/.*")) + .build()); + return securityContexts; + } + + /** + * 默认的安全上引用 + */ + private List defaultAuth() + { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List securityReferences = new ArrayList<>(); + securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); + return securityReferences; + } + + /** + * 添加摘要信息 + */ + private ApiInfo apiInfo() + { + // 用ApiInfoBuilder进行定制 + return new ApiInfoBuilder() + // 设置标题 + .title("标题:若依管理系统_接口文档") + // 描述 + .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") + // 作者信息 + .contact(new Contact(ruoyiConfig.getName(), null, null)) + // 版本 + .version("版本号:" + ruoyiConfig.getVersion()) + .build(); + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttConfig.java b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttConfig.java new file mode 100644 index 0000000..68dcb0a --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttConfig.java @@ -0,0 +1,172 @@ +package com.zbf.web.mqtt; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.client.mqttv3.*; +import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import javax.annotation.PreDestroy; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +@Slf4j +@Configuration +public class MqttConfig { + + @Autowired + private MqttProperties mqttProperties; + + @Autowired + private MqttMessageHandler mqttMessageHandler; + + private MqttClient mqttClient; + private volatile boolean isConnecting = false; + private final AtomicInteger reconnectAttempts = new AtomicInteger(0); + private static final int MAX_RECONNECT_ATTEMPTS = 5; + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + +/* + @EventListener(ApplicationReadyEvent.class) +*/ + public void onApplicationReady() { + log.info("应用程序启动完成,准备连接MQTT..."); + scheduler.schedule(this::connect, 5, TimeUnit.SECONDS); + } + + private synchronized void connect() { + try { + if (mqttClient != null && mqttClient.isConnected()) { + log.info("MQTT客户端已连接,无需重新连接"); + return; + } + + if (isConnecting) { + log.info("MQTT客户端正在连接中,请稍候..."); + return; + } + + isConnecting = true; + + if (mqttClient == null) { + MemoryPersistence persistence = new MemoryPersistence(); + mqttClient = new MqttClient( + mqttProperties.getHostUrl(), + mqttProperties.getClientId() + "_" + System.currentTimeMillis(), + persistence + ); + } + + setupMqttCallback(); + MqttConnectOptions options = createConnectOptions(); + + log.info("正在连接到MQTT服务器: {}", mqttProperties.getHostUrl()); + mqttClient.connect(options); + log.info("MQTT连接成功"); + reconnectAttempts.set(0); + + subscribeToTopics(); + + } catch (MqttException e) { + log.error("MQTT连接失败: {}", e.getMessage(), e); + handleReconnect(); + } finally { + isConnecting = false; + } + } + + private void setupMqttCallback() { + mqttClient.setCallback(new MqttCallback() { + @Override + public void connectionLost(Throwable cause) { + log.error("MQTT连接丢失: {}", cause.getMessage(), cause); + reconnectAttempts.set(0); + handleReconnect(); + } + + @Override + public void messageArrived(String topic, MqttMessage message) { + try { + log.info("收到消息 -> Topic: {}, QoS: {}, Message: {}", + topic, + message.getQos(), + new String(message.getPayload())); + mqttMessageHandler.handleMessage(topic, new String(message.getPayload())); + } catch (Exception e) { + log.error("处理消息时发生错误: {}", e.getMessage(), e); + } + } + + @Override + public void deliveryComplete(IMqttDeliveryToken token) { + // 不需要实现 + } + }); + } + + private MqttConnectOptions createConnectOptions() { + MqttConnectOptions options = new MqttConnectOptions(); + options.setUserName(mqttProperties.getUsername()); + options.setPassword(mqttProperties.getPassword().toCharArray()); + options.setConnectionTimeout(mqttProperties.getTimeout()); + options.setKeepAliveInterval(mqttProperties.getKeepalive()); + options.setAutomaticReconnect(false); + options.setCleanSession(true); + return options; + } + + private void subscribeToTopics() throws MqttException { + if (mqttProperties.getTopics() != null) { + for (String topic : mqttProperties.getTopics()) { + mqttClient.subscribe(topic, mqttProperties.getQos()); + log.info("已订阅主题: {}, QoS: {}", topic, mqttProperties.getQos()); + } + } + } + + private void handleReconnect() { + if (reconnectAttempts.incrementAndGet() > MAX_RECONNECT_ATTEMPTS) { + log.error("MQTT重连次数超过最大限制 ({}),停止重连", MAX_RECONNECT_ATTEMPTS); + return; + } + + long delay = Math.min(30, reconnectAttempts.get() * 5); + log.info("等待{}秒后进行第 {} 次重连...", delay, reconnectAttempts.get()); + scheduler.schedule(this::connect, delay, TimeUnit.SECONDS); + } + + + public void sendMessage(String topic, String payload, int qos) { + try { + if (mqttClient != null && mqttClient.isConnected()) { + MqttMessage message = new MqttMessage(payload.getBytes()); + message.setQos(qos); + mqttClient.publish(topic, message); + log.info("消息已发送到主题 {}: {}", topic, payload); + } else { + log.error("MQTT客户端未连接,无法发送消息"); + handleReconnect(); + } + } catch (MqttException e) { + log.error("发送消息失败: {}", e.getMessage(), e); + } + } + + @PreDestroy + public void disconnect() { + try { + if (mqttClient != null && mqttClient.isConnected()) { + mqttClient.disconnect(); + log.info("MQTT连接已断开"); + } + } catch (MqttException e) { + log.error("断开MQTT连接时发生错误: {}", e.getMessage(), e); + } finally { + scheduler.shutdownNow(); + } + } +} \ No newline at end of file diff --git a/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageHandler.java b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageHandler.java new file mode 100644 index 0000000..3659fb9 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageHandler.java @@ -0,0 +1,257 @@ +package com.zbf.web.mqtt; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zbf.common.utils.bean.BeanUtils; +import com.zbf.system.domain.*; +import com.zbf.system.mapper.InventoryCheckMapper; +import com.zbf.system.mapper.TBaseGoodsMapper; +import com.zbf.system.mapper.TBasePalletMapper; +import com.zbf.system.mapper.TMiStockMapper; +import com.zbf.system.service.impl.TStockCheckServiceImpl; +import com.zbf.web.util.Check; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Component +public class MqttMessageHandler { + + @Autowired + private TMiStockMapper mapper; + + @Autowired + private InventoryCheckMapper inventoryCheckMapper; + + @Autowired + private TStockCheckServiceImpl stockCheckService; + + @Autowired + private TBaseGoodsMapper stockCheckMapper; + + @Autowired + private TBasePalletMapper basePalletMapper; + + @Autowired + private MqttConfig mqttConfig; + + @Autowired + private Environment env; + + public void handleMessage(String topic, String payload) { + try { + JSONObject message = JSON.parseObject(payload); + String method = message.getString("method"); + + switch (method) { + case "inventory": + processInventoryMessage(message); + break; + case "setPoint": + processSetPointMessage(message); + break; + case "go": + goMessage(message); + break; + default: + log.warn("未知的消息类型: {}", method); + } + } catch (Exception e) { + log.error("消息处理失败: {}", payload, e); + } + } + + private void goMessage(JSONObject message) { + log.warn("go: {}", message); + } + + @Transactional + public void processInventoryMessage(JSONObject message) { + try { + String dateString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + JSONArray params = message.getJSONArray("params"); + + if (params == null || params.isEmpty()) { + log.warn("未收到有效的盘点数据"); + return; + } + + JSONObject data = params.getJSONObject(0); + String wq = data.getString("wp"); + JSONArray tagsArray = data.getJSONArray("tags"); + + if (tagsArray == null || tagsArray.isEmpty()) { + log.warn("未检测到标签数据"); + return; + } + + // 处理标签数据 + List pallets = new ArrayList<>(); + List identifiers = new ArrayList<>(); + + for (int i = 0; i < tagsArray.size(); i++) { + JSONObject tagObj = tagsArray.getJSONObject(i); + String epc = tagObj.getString("epc"); + String tid = tagObj.getString("tid"); + + TBasePallet tBasePallet = new TBasePallet(); + tBasePallet.setPalletEpc(epc); + tBasePallet.setPalletId(tid); + pallets.add(tBasePallet); + identifiers.add(tid); + + // 只在一楼模式下更新EPC + if ("1".equals(wq)) { + basePalletMapper.updateEcp(tBasePallet); + } + } + + if (pallets.isEmpty()) { + log.warn("未处理到有效的标签数据"); + return; + } + + // 获取库存数据 + List tMiStocks; + String type; + + if ("1".equals(wq)) { + // 一楼逻辑 + type = "一楼"; + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(TMiStock::getCtl, identifiers); + tMiStocks = mapper.selectList(wrapper); + } else if ("2".equals(wq) || "3".equals(wq)) { + // 二楼和抽盘逻辑 + type = "2".equals(wq) ? "二楼" : "抽盘"; + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(TBaseGoods::getGoodsTid, identifiers); + List goodsIds = stockCheckMapper.selectList(queryWrapper) + .stream() + .map(TBaseGoods::getGoodsId) + .collect(Collectors.toList()); + + if (goodsIds.isEmpty()) { + log.warn("未找到对应的商品信息"); + return; + } + + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.in(TMiStock::getGoodsId, goodsIds); + tMiStocks = mapper.selectList(wrapper); + } else { + log.warn("无效的盘点类型: {}", wq); + return; + } + + if (tMiStocks.isEmpty()) { + log.warn("未找到对应的库存数据"); + return; + } + + log.info("收到盘点数据 -> 时间: {}, 标签数量: {}, 盘点类型:{}", dateString, pallets.size(), type); + log.info("库存数据数量: {}", tMiStocks.size()); + + // 创建盘点记录 + String checkId = Check.generateUniqueId(); + InventoryCheck inventoryCheck = new InventoryCheck(); + inventoryCheck.setCheckTime(dateString); + inventoryCheck.setCheckType(type); + inventoryCheck.setTaskNumber(checkId); + inventoryCheckMapper.insertInventoryCheck(inventoryCheck); + + // 批量保存盘点数据 + List stockChecks = new ArrayList<>(); + for (TMiStock stock : tMiStocks) { + TStockCheck stockCheck = new TStockCheck(); + BeanUtils.copyProperties(stock, stockCheck); + stockCheck.setCheckId(checkId); + // 处理日期格式 + if (stock.getPlanDate() != null && stock.getPlanDate().length() > 10) { + stockCheck.setPlanDate(stock.getPlanDate().substring(0, 10)); + } + // 处理数值精度 + if (stock.getShelvesNum() != null) { + stockCheck.setShelvesNum(new BigDecimal(String.valueOf(stock.getShelvesNum())) + .setScale(3, RoundingMode.HALF_UP)); + } + stockChecks.add(stockCheck); + } + + // 分批保存数据 + if (!stockChecks.isEmpty()) { + try { + stockCheckService.saveBatch(stockChecks); + log.info("盘点数据处理完成,共保存 {} 条记录", stockChecks.size()); + } catch (Exception e) { + log.error("保存盘点数据失败: {}", e.getMessage()); + throw new RuntimeException("保存盘点数据失败", e); + } + } + + } catch (Exception e) { + log.error("处理inventory消息时发生错误: {}", e.getMessage(), e); + throw new RuntimeException("盘点数据处理失败", e); + } + } + + private void processSetPointMessage(JSONObject message) { + log.info("处理setPoint消息: {}", message); + // TODO: 在这里添加处理setPoint消息的具体逻辑 + } + + private String formatDateTimeString(String dateTimeStr) { + try { + // 验证输入长度 + if (dateTimeStr == null || dateTimeStr.length() != 14) { + log.error("无效的日期时间字符串: {}", dateTimeStr); + return "Invalid date format"; + } + + // 使用 SimpleDateFormat 进行转换 + SimpleDateFormat inputFormat = new SimpleDateFormat("yyyyMMddHHmmss"); + SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + Date date = inputFormat.parse(dateTimeStr); + return outputFormat.format(date); + + } catch (Exception e) { + log.error("日期时间格式化失败: {}, 错误: {}", dateTimeStr, e.getMessage()); + return "Format Error"; + } + } + + /** + * 发送 MQTT 消息 + * @param topicKey 配置文件中定义的主题 key + * @param payload 消息内容 + */ + /*public void sendMessage(String topicKey, String payload) { + try { + String topic = env.getProperty("mqtt.topic." + topicKey); + if (topic == null) { + log.error("未找到主题配置: {}", topicKey); + return; + } + + MqttMessage message = new MqttMessage(payload.getBytes()); + mqttConfig.sendMessage(topic, message); + log.info("消息已发送到主题 {}: {}", topic, payload); + } catch (MqttException e) { + log.error("发送消息失败: {}", e.getMessage(), e); + } + }*/ +} \ No newline at end of file diff --git a/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageSender.java b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageSender.java new file mode 100644 index 0000000..64584a3 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttMessageSender.java @@ -0,0 +1,38 @@ +package com.zbf.web.mqtt; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class MqttMessageSender { + + @Autowired + private MqttConfig mqttConfig; + + @Autowired + private MqttProperties mqttProperties; + + public boolean sendMessage(String method, Object[] params, String id) { + JSONObject message = new JSONObject(); + message.put("jsonrpc", "2.0"); + message.put("method", method); + message.put("params", params); + message.put("id", id); + + String topic = mqttProperties.getTopics()[0]; // 使用topics数组中的第一个元素(即"test"主题) + String payload = JSON.toJSONString(message); + + try { + mqttConfig.sendMessage(topic, payload, mqttProperties.getQos()); + log.info("消息发送成功 - Topic: {}, Payload: {}", topic, payload); + return true; + } catch (RuntimeException e) { + log.error("消息发送失败 - Topic: {}, Payload: {}, 错误: {}", topic, payload, e.getMessage()); + return false; + } + } +} \ No newline at end of file diff --git a/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttProperties.java b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttProperties.java new file mode 100644 index 0000000..0c7c77d --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/mqtt/MqttProperties.java @@ -0,0 +1,19 @@ +package com.zbf.web.mqtt; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Data +@Component +@ConfigurationProperties(prefix = "mqtt") +public class MqttProperties { + private String username; + private String password; + private String hostUrl; + private String clientId; + private String[] topics; // 订阅的主题数组 + private Integer timeout; + private Integer keepalive; + private Integer qos = 1; +} diff --git a/zbf-admin/src/main/java/com/zbf/web/util/ActivitiTracingChart.java b/zbf-admin/src/main/java/com/zbf/web/util/ActivitiTracingChart.java new file mode 100644 index 0000000..8a74e79 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/util/ActivitiTracingChart.java @@ -0,0 +1,88 @@ +package com.zbf.web.util; + +import org.apache.commons.lang3.StringUtils; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.common.engine.impl.util.IoUtil; +import org.flowable.engine.HistoryService; +import org.flowable.engine.ProcessEngineConfiguration; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.image.ProcessDiagramGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * 流程追踪图 + */ +@Component +public class ActivitiTracingChart { + + private static final Logger logger = LoggerFactory.getLogger(ActivitiTracingChart.class); + + + @Resource + private HistoryService historyService; + + @Resource + private RepositoryService repositoryService; + + @Resource + private ProcessEngineConfiguration processEngineConfiguration; + + /** + * 生成流程追踪图 + * + * @param processInstanceId 流程实例id + * @param outputStream 输出流 + */ + public void generateFlowChart(String processInstanceId, OutputStream outputStream) { + if (StringUtils.isEmpty(processInstanceId)) { + logger.error("processInstanceId is null"); + return; + } + // 获取历史流程实例 + HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId) + .singleResult(); + // 获取流程中已经执行的节点 + String processDefinitionId = historicProcessInstance.getProcessDefinitionId(); + List highLightedActivities = new ArrayList<>(); + // 获得活动的节点 + List highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list(); + List highLightedFlows = new ArrayList<>(); + for (HistoricActivityInstance tempActivity : highLightedActivityList) { + String activityId = tempActivity.getActivityId(); + highLightedActivities.add(activityId); + if ("sequenceFlow".equals(tempActivity.getActivityType())) { + highLightedFlows.add(tempActivity.getActivityId()); + } + } + // 获取流程图 + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); + ProcessEngineConfiguration engConf = processEngineConfiguration.getProcessEngineConfiguration(); + + ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator(); + InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, highLightedFlows, "宋体", + "宋体", "宋体", engConf.getClassLoader(), 1.0, true); + byte[] buf = new byte[1024]; + int length; + try { + while ((length = in.read(buf)) != -1) { + outputStream.write(buf, 0, length); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + IoUtil.closeSilently(outputStream); + IoUtil.closeSilently(in); + } + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/util/Check.java b/zbf-admin/src/main/java/com/zbf/web/util/Check.java new file mode 100644 index 0000000..8a77e33 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/util/Check.java @@ -0,0 +1,23 @@ +package com.zbf.web.util; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Check { + private static final String PREFIX = "INV"; // 盘点类型标识 + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化为年月日时分秒 + + public static String generateUniqueId() { + // 获取当前时间的格式化字符串 + String timestamp = dateFormat.format(new Date()); + // 生成唯一 ID + return PREFIX + timestamp; + } + + public static void main(String[] args) { + // 测试生成多个 ID + for (int i = 0; i < 10; i++) { + System.out.println(generateUniqueId()); + } + } +} diff --git a/zbf-admin/src/main/java/com/zbf/web/util/RID.java b/zbf-admin/src/main/java/com/zbf/web/util/RID.java new file mode 100644 index 0000000..af40955 --- /dev/null +++ b/zbf-admin/src/main/java/com/zbf/web/util/RID.java @@ -0,0 +1,36 @@ +package com.zbf.web.util; +import java.util.HashSet; +import java.util.Random; +import java.util.Set; + +public class RID { + + + private static final String PREFIX = "RK"; + private static final int MIN_LENGTH = 6; + private static final int MAX_LENGTH = 8; + private static final Set generatedIds = new HashSet<>(); // 用于存储已生成的 ID + private static final Random random = new Random(); + + public static String generateUniqueId() { + int length = random.nextInt(MAX_LENGTH - MIN_LENGTH + 1) + MIN_LENGTH; // 随机生成长度 + StringBuilder idBuilder = new StringBuilder(PREFIX); + + // 生成随机数字 + for (int i = 0; i < length - PREFIX.length(); i++) { + char randomChar = (char) (random.nextInt(10) + '0'); // 生成数字字符 + idBuilder.append(randomChar); + } + + String uniqueId = idBuilder.toString(); + + // 确保 ID 不重复 + while (generatedIds.contains(uniqueId)) { + uniqueId = generateUniqueId(); // 递归调用以生成新的 ID + } + + generatedIds.add(uniqueId); // 添加到已生成的 ID 集合中 + return uniqueId; + + } +} diff --git a/zbf-admin/src/main/resources/META-INF/spring-devtools.properties b/zbf-admin/src/main/resources/META-INF/spring-devtools.properties new file mode 100644 index 0000000..37e7b58 --- /dev/null +++ b/zbf-admin/src/main/resources/META-INF/spring-devtools.properties @@ -0,0 +1 @@ +restart.include.json=/com.alibaba.fastjson2.*.jar \ No newline at end of file diff --git a/zbf-admin/src/main/resources/application-druid.yml b/zbf-admin/src/main/resources/application-druid.yml new file mode 100644 index 0000000..f0d278d --- /dev/null +++ b/zbf-admin/src/main/resources/application-druid.yml @@ -0,0 +1,82 @@ +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + driverClassName: com.mysql.cj.jdbc.Driver + druid: + # 主库数据源 + master: + #url: jdbc:mysql://172.18.29.93:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + #username: root + #password: Rzg@123567 + #url: jdbc:mysql://172.22.28.158:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + #username: root + #password: Rzg@123567 +# url: jdbc:mysql://39.98.53.180:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true +# username: tony +# password: Tony123 + url: jdbc:mysql://localhost:3306/leader_wms?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + username: root + password: 123456 +# # 从库数据源 + slave: + # 从数据源开关/默认关闭 + enabled: false + #url: jdbc:mysql://172.18.26.15:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + #username: root + #password: Rzg@123567 + #url: jdbc:mysql://172.22.28.158:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + #username: root + #password: Rzg@123567 +# url: jdbc:mysql://39.98.53.180:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true +# username: tony +# password: Tony123 + url: jdbc:mysql://localhost:3306/rzg_wms1?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true + username: root + password: root5058 + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置连接超时时间 + connectTimeout: 30000 + # 配置网络超时时间 + socketTimeout: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: ruoyi + login-password: 123456 + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + path: + includes: /monitor/test + + wall: + config: + multi-statement-allow: true diff --git a/zbf-admin/src/main/resources/application.yml b/zbf-admin/src/main/resources/application.yml new file mode 100644 index 0000000..e90fc7f --- /dev/null +++ b/zbf-admin/src/main/resources/application.yml @@ -0,0 +1,183 @@ +# 项目相关配置 +ruoyi: + # 名称 + name: Zbf + # 版本 + version: 3.8.7 + # 版权年份 + copyrightYear: 2024 + # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) + profile: /usr/rzg/uploadPath + # 获取ip地址开关 + addressEnabled: false + # 验证码类型 math 数字计算 char 字符验证 + captchaType: math + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8089 + servlet: + # 应用的访问路径 + context-path: / + tomcat: + # tomcat的URI编码 + uri-encoding: UTF-8 + # 连接数满后的排队数,默认为100 + accept-count: 1000 + threads: + # tomcat最大线程数,默认为200 + max: 800 + # Tomcat启动初始化的线程数,默认值10 + min-spare: 100 + +logging: + level: + com.zbf: debug + org.springframework: warn + org.quartz: warn + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# Spring配置 +spring: + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: druid + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 10MB + # 设置总上传的文件大小 + max-request-size: 20MB + # 服务模块 + devtools: + restart: + # 热部署开关 + enabled: true + # redis 配置 + redis: + # 地址 + host: localhost + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码 +# password: Rzg@2024#! + password: 123456 + # 连接超时时间 + timeout: 10m + lettuce: + pool: + # 连接池中的最小空闲连接 + min-idle: 0 + # 连接池中的最大空闲连接 + max-idle: 8 + # 连接池的最大数据库连接数 + max-active: 8 + # #连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + +# token配置 +token: + # 令牌自定义标识 + header: Authorization + # 令牌密钥 + secret: abcdefghijklmnopqrstuvwxyz + # 令牌有效期(默认30分钟) + expireTime: 30 + # 是否允许账户多终端同时登录(true允许 false不允许) + soloLogin: true + + +# MyBatis配置 +#mybatis: +# # 搜索指定包别名 +# typeAliasesPackage: com.zbf.**.domain +# # 配置mapper的扫描,找到所有的mapper.xml映射文件 +# mapperLocations: classpath*:mapper/**/*Mapper.xml +# # 加载全局的配置文件 +# configLocation: classpath:mybatis/mybatis-config.xml + +mybatis-plus: + typeAliasesPackage: com.zbf.**.domain + mapperLocations: classpath*:mapper/**/*Mapper.xml + configLocation: classpath:mybatis/mybatis-config.xml + global-config: + db-config: + logic-delete-field: isDelete # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2) + logic-delete-value: 0 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 1 # 逻辑未删除值(默认为 0) + # 主键类型 0:数据库ID自增 1.未定义 2.用户输入 3 id_worker 4.uuid 5.id_worker字符串表示 + id-type: auto + enable-sql-runner: true + +# PageHelper分页插件 +pagehelper: + helperDialect: mysql + supportMethodsArguments: true + params: count=countSql + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true + # 请求前缀 + pathMapping: /dev-api + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* + +# flowable相关表 +flowable: + # true 会对数据库中所有表进行更新操作。如果表不存在,则自动创建(建议开发时使用) + database-schema-update: false + # 关闭定时任务JOB + async-executor-activate: false +#审核人 +deptmanager: zhangsan +managerName: lisi + +deviceIp: "https://36.139.3.75:38443/datalinkprobackend/aksk/formentity/entityManagement/saveEntity" +mqtt: + username: vendor + password: vendor01 + hostUrl: tcp://172.22.28.156:1883 + #username: admin + #password: 123456 + #hostUrl: tcp://broker.emqx.io + clientId: wms + topics: + - $sapi/2/raas/raas-none-2cf7f12057da/rpc/req/ + - $sapi/1/raas/rpc/rsp/# + - test + timeout: 100 + keepalive: 60 + qos: 1 +# 钉钉相关信息158 +appkey: dingey9uhem8tpi36c5u +appSecret: 5oPLdAz6MFPXDBsLZo6vRTVbqLGTBaI_wXBgw8kRfb3VI675XcW3N59kIabME2zB + + +#appkey: dingtc5r3gbt1rt6u5p2 +#appSecret: 9sZtsv9i0MjvylZK_i3R5_cfs7_W1QuyjDeBtDAaTyjHk7tHocaYpskkbYhEMNPN + + + diff --git a/zbf-admin/src/main/resources/banner.txt b/zbf-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..fc332ab --- /dev/null +++ b/zbf-admin/src/main/resources/banner.txt @@ -0,0 +1,24 @@ +Application Version: ${ruoyi.version} +Spring Boot Version: ${spring-boot.version} +//////////////////////////////////////////////////////////////////// +// _ooOoo_ // +// o8888888o // +// 88" . "88 // +// (|ʕ•ᴥ•ʔ|) // +// O\ = /O // +// ____/`---'\____ // +// .' \\| |// `. // +// / \\||| : |||// \ // +// / _||||| -:- |||||- \ // +// | | \\\ - /// | | // +// | \_| ''\---/'' | | // +// \ .-\__ `-` ___/-. / // +// ___`. .' /--.--\ `. . ___ // +// ."" '< `.___\_<|>_/___.' >'"". // +// | | : `- \`.;`\ _ /`;.`/ - ` : | | // +// \ \ `-. \_ __\ /__ _/ .-` / / // +// ========`-.____`-.___\_____/___.-`____.-'======== // +// `=---=' // +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // +// 日照港之神 高鹏保佑 永不宕机 永无BUG 哈哈哈哈 // +//////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/zbf-admin/src/main/resources/i18n/messages.properties b/zbf-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..93de005 --- /dev/null +++ b/zbf-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,38 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=用户不存在/密码错误 +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号已被删除 +user.blocked=用户已封禁,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +login.blocked=很遗憾,访问IP已被列入系统黑名单 +user.logout.success=退出成功 + +length.not.valid=长度必须在{min}到{max}个字符之间 + +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.password.not.valid=* 5-50个字符 + +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 + +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 + +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] diff --git a/zbf-admin/src/main/resources/logback.xml b/zbf-admin/src/main/resources/logback.xml new file mode 100644 index 0000000..5212e6c --- /dev/null +++ b/zbf-admin/src/main/resources/logback.xml @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log.path}/sys-user.log + + + ${log.path}/sys-user.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zbf-admin/src/main/resources/mybatis/mybatis-config.xml b/zbf-admin/src/main/resources/mybatis/mybatis-config.xml new file mode 100644 index 0000000..ac47c03 --- /dev/null +++ b/zbf-admin/src/main/resources/mybatis/mybatis-config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/zbf-admin/src/main/resources/processes/Flowable_Pickingout.bpmn20.xml b/zbf-admin/src/main/resources/processes/Flowable_Pickingout.bpmn20.xml new file mode 100644 index 0000000..5523214 --- /dev/null +++ b/zbf-admin/src/main/resources/processes/Flowable_Pickingout.bpmn20.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zbf-admin/src/main/resources/processes/Pickingout_Audit.bpmn20.xml b/zbf-admin/src/main/resources/processes/Pickingout_Audit.bpmn20.xml new file mode 100644 index 0000000..db8d98d --- /dev/null +++ b/zbf-admin/src/main/resources/processes/Pickingout_Audit.bpmn20.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zbf-admin/src/main/resources/processes/leave.bpmn b/zbf-admin/src/main/resources/processes/leave.bpmn new file mode 100644 index 0000000..6224542 --- /dev/null +++ b/zbf-admin/src/main/resources/processes/leave.bpmn @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/processes/meeting.bpmn b/zbf-admin/src/main/resources/processes/meeting.bpmn new file mode 100644 index 0000000..067de40 --- /dev/null +++ b/zbf-admin/src/main/resources/processes/meeting.bpmn @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/processes/purchase.bpmn20.xml b/zbf-admin/src/main/resources/processes/purchase.bpmn20.xml new file mode 100644 index 0000000..76501b1 --- /dev/null +++ b/zbf-admin/src/main/resources/processes/purchase.bpmn20.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10000}]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/404.html b/zbf-admin/src/main/resources/static/designer/404.html new file mode 100644 index 0000000..ec98e3c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/404.html @@ -0,0 +1,157 @@ + + + + + Page Not Found :( + + + +
+

Not found :(

+

Sorry, but the page you were trying to view does not exist.

+

It looks like this was the result of either:

+
    +
  • a mistyped address
  • +
  • an out-of-date link
  • +
+ + +
+ + diff --git a/zbf-admin/src/main/resources/static/designer/browserconfig.xml b/zbf-admin/src/main/resources/static/designer/browserconfig.xml new file mode 100644 index 0000000..006d54a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-draw.js b/zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-draw.js new file mode 100644 index 0000000..039c392 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-draw.js @@ -0,0 +1,491 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function _cmmnGetColor(element, defaultColor) +{ + var strokeColor; + if(element.current) { + strokeColor = CURRENT_COLOR; + } else if(element.completed) { + strokeColor = COMPLETED_COLOR; + } else { + strokeColor = defaultColor; + } + return strokeColor; +} + +function _drawPlanModel(planModel) +{ + var rect = paper.rect(planModel.x, planModel.y, planModel.width, planModel.height); + + rect.attr({"stroke-width": 1, + "stroke": "#000000", + "fill": "white" + }); + + if (planModel.name) + { + var planModelName = paper.text(planModel.x + 14, planModel.y + (planModel.height / 2), planModel.name).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + planModelName.transform("r270"); + } +} + +function _drawSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _cmmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); +} + +function _drawVariableServiceTaskIcon(element) +{ + _drawTask(element); + if (element.taskType === "mail") + { + _drawSendTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "camel") + { + _drawCamelTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "mule") + { + _drawMuleTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "http") + { + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.stencilIconId) + { + paper.image("../service/stencilitem/" + element.stencilIconId + "/icon", element.x + 4, element.y + 4, 16, 16); + } + else + { + _drawServiceTaskIcon(paper, element.x + 4, element.y + 4); + } + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawHttpServiceTask(element) +{ + _drawTask(element); + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawHumanTask(element) +{ + _drawTask(element); + _drawHumanTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawCaseTask(element) +{ + _drawTask(element); + _drawCaseTaskIcon(paper, element.x + 1, element.y + 1); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawProcessTask(element) +{ + _drawTask(element); + _drawProcessTaskIcon(paper, element.x + 1, element.y + 1); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawScriptTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 5,2 0,0.094 c 0.23706,0.064 0.53189,0.1645 0.8125,0.375 0.5582,0.4186 1.05109,1.228 1.15625,2.5312 l 8.03125,0 1,0 1,0 c 0,-3 -2,-3 -2,-3 l -10,0 z M 4,3 4,13 2,13 c 0,3 2,3 2,3 l 9,0 c 0,0 2,0 2,-3 L 15,6 6,6 6,5.5 C 6,4.1111 5.5595,3.529 5.1875,3.25 4.8155,2.971 4.5,3 4.5,3 L 4,3 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var scriptTaskIcon = paper.set(); + scriptTaskIcon.push(path1); + + scriptTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawScriptServiceTask(element) +{ + _drawTask(element); + _drawScriptTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawDecisionTask(element) +{ + _drawTask(element); + _drawDecisionTaskIcon(paper, element.x + 1, element.y + 1); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawServiceTask(element) +{ + _drawTask(element); + _drawVariableServiceTaskIcon(element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawTask(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = ACTIVITY_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } +} + +function _drawTimerEventListener(element) +{ + _drawEventListener(element); + _drawTimerEventListenerIcon(paper, element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawUserEventListener(element) +{ + _drawEventListener(element); + _drawUserEventListenerIcon(paper, element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawGenericEventListener(element) +{ + _drawEventListener(element); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawEventListener(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + circle.attr({"stroke-width": 1, + "stroke": "black", + "fill": "white" + }); + + circle.id = element.id; +} + +function _drawMilestone(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 24); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = WHITE_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } +} + +function _drawStage(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 16); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = WHITE_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x + 10, element.y + 5, element.width, element.height, "start", "top", 11); + } +} + +function _drawPlanModel(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _cmmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + rectAttrs['fill'] = WHITE_FILL_COLOR; + + rect.attr(rectAttrs); + rect.id = element.id; + + var path1 = paper.path("M20 55 L37 34 L275 34 L291 55"); + path1.attr({ + "opacity": 1, + "stroke": strokeColor, + "fill": "#ffffff" + }); + + var planModelHeader = paper.set(); + planModelHeader.push(path1); + + planModelHeader.translate(element.x, element.y - 55); + if (element.name) { + this._drawMultilineText(element.name, element.x + 10, element.y - 16, 275, element.height, "middle", "top", 11); + } +} + +function _drawEntryCriterion(element) +{ + var strokeColor = _cmmnGetColor(element, MAIN_STROKE_COLOR); + + var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + + // Fill + var gatewayFillColor = WHITE_FILL_COLOR; + + // Opacity + var gatewayOpacity = 1.0; + + rhombus.attr("stroke-width", 1); + rhombus.attr("stroke", strokeColor); + rhombus.attr("fill", gatewayFillColor); + rhombus.attr("fill-opacity", gatewayOpacity); + + rhombus.id = element.id; +} + +function _drawExitCriterion(element) +{ + var strokeColor = _cmmnGetColor(element, MAIN_STROKE_COLOR); + + var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + + // Fill + var gatewayFillColor = '#000000'; + + // Opacity + var gatewayOpacity = 1.0; + + rhombus.attr("stroke-width", 1); + rhombus.attr("stroke", strokeColor); + rhombus.attr("fill", gatewayFillColor); + rhombus.attr("fill-opacity", gatewayOpacity); + + rhombus.id = element.id; +} + +function _drawMultilineText(text, x, y, boxWidth, boxHeight, horizontalAnchor, verticalAnchor, fontSize) +{ + if (!text || text == "") + { + return; + } + + var textBoxX, textBoxY; + var width = boxWidth - (2 * TEXT_PADDING); + + if (horizontalAnchor === "middle") + { + textBoxX = x + (boxWidth / 2); + } + else if (horizontalAnchor === "start") + { + textBoxX = x; + } + + textBoxY = y + (boxHeight / 2); + + var t = paper.text(textBoxX + TEXT_PADDING, textBoxY + TEXT_PADDING).attr({ + "text-anchor" : horizontalAnchor, + "font-family" : "Arial", + "font-size" : fontSize, + "fill" : "#373e48" + }); + + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + t.attr({ + "text" : abc + }); + var letterWidth = t.getBBox().width / abc.length; + + t.attr({ + "text" : text + }); + var removedLineBreaks = text.split("\n"); + var x = 0, s = []; + for (var r = 0; r < removedLineBreaks.length; r++) + { + var words = removedLineBreaks[r].split(" "); + for ( var i = 0; i < words.length; i++) { + + var l = words[i].length; + if (x + (l * letterWidth) > width) { + s.push("\n"); + x = 0; + } + x += l * letterWidth; + s.push(words[i] + " "); + } + s.push("\n"); + x = 0; + } + t.attr({ + "text" : s.join("") + }); + + if (verticalAnchor && verticalAnchor === "top") + { + t.attr({"y": y + (t.getBBox().height / 2)}); + } +} + +function _drawAssociation(flow){ + + var polyline = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + polyline.element = paper.path(polyline.path); + polyline.element.attr({"stroke-width": ASSOCIATION_STROKE}); + polyline.element.attr({"stroke-dasharray": ". "}); + polyline.element.attr({"stroke":"#585858"}); + + polyline.element.id = flow.id; + + var polylineInvisible = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + + polylineInvisible.element = paper.path(polyline.path); + polylineInvisible.element.attr({ + "opacity": 0, + "stroke-width": 8, + "stroke" : "#000000" + }); + + _showTip(jQuery(polylineInvisible.element.node), flow); + + polylineInvisible.element.mouseover(function() { + paper.getById(polyline.element.id).attr({"stroke":"blue"}); + }); + + polylineInvisible.element.mouseout(function() { + paper.getById(polyline.element.id).attr({"stroke":"#585858"}); + }); +} + +function _drawArrowHead(line, connectionType) +{ + var doubleArrowWidth = 2 * ARROW_WIDTH; + + var arrowHead = paper.path("M0 0L-" + (ARROW_WIDTH / 2 + .5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2 + .5) + " -" + doubleArrowWidth + "z"); + + // anti smoothing + if (this.strokeWidth%2 == 1) + line.x2 += .5, line.y2 += .5; + + arrowHead.transform("t" + line.x2 + "," + line.y2 + ""); + arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0); + + arrowHead.attr("fill", "#585858"); + + arrowHead.attr("stroke-width", SEQUENCEFLOW_STROKE); + arrowHead.attr("stroke", "#585858"); + + return arrowHead; +} diff --git a/zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-icons.js b/zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-icons.js new file mode 100644 index 0000000..e15023b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display-cmmn/cmmn-icons.js @@ -0,0 +1,180 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function _drawHumanTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#d1b575" + }); + + var userTaskIcon = paper.set(); + userTaskIcon.push(path1); + + userTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawServiceTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M 8,1 7.5,2.875 c 0,0 -0.02438,0.250763 -0.40625,0.4375 C 7.05724,3.330353 7.04387,3.358818 7,3.375 6.6676654,3.4929791 6.3336971,3.6092802 6.03125,3.78125 6.02349,3.78566 6.007733,3.77681 6,3.78125 5.8811373,3.761018 5.8125,3.71875 5.8125,3.71875 l -1.6875,-1 -1.40625,1.4375 0.96875,1.65625 c 0,0 0.065705,0.068637 0.09375,0.1875 0.002,0.00849 -0.00169,0.022138 0,0.03125 C 3.6092802,6.3336971 3.4929791,6.6676654 3.375,7 3.3629836,7.0338489 3.3239228,7.0596246 3.3125,7.09375 3.125763,7.4756184 2.875,7.5 2.875,7.5 L 1,8 l 0,2 1.875,0.5 c 0,0 0.250763,0.02438 0.4375,0.40625 0.017853,0.03651 0.046318,0.04988 0.0625,0.09375 0.1129372,0.318132 0.2124732,0.646641 0.375,0.9375 -0.00302,0.215512 -0.09375,0.34375 -0.09375,0.34375 L 2.6875,13.9375 4.09375,15.34375 5.78125,14.375 c 0,0 0.1229911,-0.09744 0.34375,-0.09375 0.2720511,0.147787 0.5795915,0.23888 0.875,0.34375 0.033849,0.01202 0.059625,0.05108 0.09375,0.0625 C 7.4756199,14.874237 7.5,15.125 7.5,15.125 L 8,17 l 2,0 0.5,-1.875 c 0,0 0.02438,-0.250763 0.40625,-0.4375 0.03651,-0.01785 0.04988,-0.04632 0.09375,-0.0625 0.332335,-0.117979 0.666303,-0.23428 0.96875,-0.40625 0.177303,0.0173 0.28125,0.09375 0.28125,0.09375 l 1.65625,0.96875 1.40625,-1.40625 -0.96875,-1.65625 c 0,0 -0.07645,-0.103947 -0.09375,-0.28125 0.162527,-0.290859 0.262063,-0.619368 0.375,-0.9375 0.01618,-0.04387 0.04465,-0.05724 0.0625,-0.09375 C 14.874237,10.52438 15.125,10.5 15.125,10.5 L 17,10 17,8 15.125,7.5 c 0,0 -0.250763,-0.024382 -0.4375,-0.40625 C 14.669647,7.0572406 14.641181,7.0438697 14.625,7 14.55912,6.8144282 14.520616,6.6141566 14.4375,6.4375 c -0.224363,-0.4866 0,-0.71875 0,-0.71875 L 15.40625,4.0625 14,2.625 l -1.65625,1 c 0,0 -0.253337,0.1695664 -0.71875,-0.03125 l -0.03125,0 C 11.405359,3.5035185 11.198648,3.4455201 11,3.375 10.95613,3.3588185 10.942759,3.3303534 10.90625,3.3125 10.524382,3.125763 10.5,2.875 10.5,2.875 L 10,1 8,1 z m 1,5 c 1.656854,0 3,1.3431458 3,3 0,1.656854 -1.343146,3 -3,3 C 7.3431458,12 6,10.656854 6,9 6,7.3431458 7.3431458,6 9,6 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var serviceTaskIcon = paper.set(); + serviceTaskIcon.push(path1); + + serviceTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawCaseTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M5 8 L9 4 L18 4 L 21 7"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#000000" + }); + + var path2 = paper.path("M1 23 L1 4 L30 4 L30 23z"); + path2.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var caseTaskIcon = paper.set(); + caseTaskIcon.push(path1); + caseTaskIcon.push(path2); + + caseTaskIcon.translate(startX, startY); + caseTaskIcon.scale(0.7, 0.7); +} + +function _drawProcessTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M1 23 L7 11 L1 0 L30 0 L 35 11 L 30 23z"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var processTaskIcon = paper.set(); + processTaskIcon.push(path1); + + processTaskIcon.translate(startX, startY); + processTaskIcon.scale(0.7, 0.7); +} + +function _drawDecisionTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.9,2.4000386 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var decisionTaskIcon = paper.set(); + decisionTaskIcon.push(path1); + + decisionTaskIcon.translate(startX, startY); + decisionTaskIcon.scale(0.7, 0.7); +} + +function _drawHttpTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 16.704699,5.9229055 q 0.358098,0 0.608767,0.2506681 0.250669,0.250668 0.250669,0.6087677 0,0.3580997 -0.250669,0.6087677 -0.250669,0.2506679 -0.608767,0.2506679 -0.358098,0 -0.608767,-0.2506679 -0.250669,-0.250668 -0.250669,-0.6087677 0,-0.3580997 0.250669,-0.6087677 0.250669,-0.2506681 0.608767,-0.2506681 z m 2.578308,-2.0053502 q -2.229162,0 -3.854034,0.6759125 -1.624871,0.6759067 -3.227361,2.2694472 -0.716197,0.725146 -1.575633,1.7457293 L 7.2329969,8.7876913 Q 7.0897576,8.8055849 7.000233,8.9309334 L 4.9948821,12.368677 q -0.035811,0.06267 -0.035811,0.143242 0,0.107426 0.080572,0.205905 l 0.5729577,0.572957 q 0.125334,0.116384 0.2864786,0.07162 l 2.4708789,-0.760963 2.5156417,2.515645 -0.76096,2.470876 q -0.009,0.02687 -0.009,0.08057 0,0.125338 0.08058,0.205905 l 0.572957,0.572958 q 0.170096,0.152194 0.349146,0.04476 l 3.437744,-2.005351 q 0.125335,-0.08953 0.143239,-0.232763 l 0.17905,-3.392986 q 1.02058,-0.859435 1.745729,-1.575629 1.67411,-1.6830612 2.309735,-3.2049805 0.635625,-1.5219191 0.635625,-3.8585111 0,-0.1253369 -0.08505,-0.2148575 -0.08505,-0.089526 -0.201431,-0.089526 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + + startX += -2; + startY += -2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawBusinessRuleTaskIcon(paper, startX, startY) { + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.45458,5.6000386 2.90906,0 0,2.7999224 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.7999224 -8.72718,0 z m -4.36364,4.1998844 2.90906,0 0,2.800116 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.800116 -8.72718,0 z"); + path1.attr({ + "stroke": "none", + "fill": "#72a7d0" + }); + + var businessRuleTaskIcon = paper.set(); + businessRuleTaskIcon.push(path1); + + businessRuleTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawTimerEventListenerIcon(paper, element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 10); + + circle.attr({"stroke-width": 1, + "stroke": "black", + "fill": "none" + }); + + var path = paper.path("M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z"); + path.attr({ + "stroke": "none", + "fill": "#585858" + }); + path.transform("T" + (element.x + 5) + "," + (element.y + 5)); + return path; +} + +function _drawUserEventListenerIcon(paper, element) { + var userTaskIcon = paper.set(); + var path1 = paper.path("M0.585,24.167h24.083v-7.833c0,0-2.333-3.917-7.083-5.167h-9.25 c-4.417,1.333-7.833,5.75-7.833,5.75L0.585,24.167z"); + path1.attr({"opacity": 1, "stroke": "none", "fill": "#F4F6F7"}); + userTaskIcon.push(path1); + + var path2 = paper.path("M6,20L6,24"); + path2.attr({"opacity": 1, "stroke": "white", "fill": "none"}); + userTaskIcon.push(path2); + + var path3 = paper.path("M20,20L20,24"); + path3.attr({"opacity": 1, "stroke": "white", "fill": "none"}); + userTaskIcon.push(path3); + + var circle = paper.circle(13.002, 5.916, 5.417); + circle.attr({"stroke-width": 1, "stroke": "black", "fill": "#000000"}); + userTaskIcon.push(circle); + + var path4 = paper.path("M8.043,7.083c0,0,2.814-2.426,5.376-1.807s4.624-0.693,4.624-0.693 c0.25,1.688,0.042,3.75-1.458,5.584c0,0,1.083,0.75,1.083,1.5s0.125,1.875-1,3s-5.5,1.25-6.75,0S8.668,12.834,8.668,12 s0.583-1.25,1.25-1.917C8.835,9.5,7.419,7.708,8.043,7.083z"); + path4.attr({"opacity": 1, "stroke": "none", "fill": "#F0EFF0"}); + userTaskIcon.push(path4); + + var x = (element.width / 2) - 2; + var y = (element.height / 2) - 2; + var circle2 = paper.circle(x, y, 17); + circle2.attr({"stroke-width": 1, "stroke": "#F0EFF0", "fill": "none"}); + userTaskIcon.push(circle2); + + userTaskIcon.transform("S0.7,0.7" + "T" + (element.x + 2) + "," + (element.y + 2)); + return userTaskIcon; +} diff --git a/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.css b/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.css new file mode 100644 index 0000000..ddaf36e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.css @@ -0,0 +1,24 @@ +div[class*='ui-tooltip-flowable-'] { + background-color: #ffffff; + border-color: #c5c5c5; + color: #4a4a4a; + font-family: Verdana; + font-size: 12px; +} + +div[class*='ui-tooltip-flowable-'] .qtip-content { + color: #4a4a4a; + background-color: #ffffff; + font-family: Verdana; + font-size: 12px; +} + +.ui-tooltip-flowable-cmmn .qtip-titlebar { + color: #FFFFFF; + font-size: 12px; + background: #2B414F; +} + +.ui-tooltip-flowable-cmmn .qtip-tip { + background-color: #2B414F; +} diff --git a/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.html b/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.html new file mode 100644 index 0000000..a56de7d --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.js b/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.js new file mode 100644 index 0000000..a4c2d2e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display-cmmn/displaymodel.js @@ -0,0 +1,272 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var NORMAL_STROKE = 1; +var ASSOCIATION_STROKE = 2; +var TASK_STROKE = 1; +var TASK_HIGHLIGHT_STROKE = 2; + +var TEXT_COLOR= "#373e48"; +var CURRENT_COLOR= "#017501"; +var HOVER_COLOR= "#666666"; +var ACTIVITY_STROKE_COLOR = "#bbbbbb"; +var ACTIVITY_FILL_COLOR = "#f9f9f9"; +var WHITE_FILL_COLOR = "#ffffff"; +var MAIN_STROKE_COLOR = "#585858"; + +var TEXT_PADDING = 3; +var ARROW_WIDTH = 4; +var MARKER_WIDTH = 12; + +var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Raphael.rgb(0, 0, 0)}; + +// icons +var ICON_SIZE = 16; +var ICON_PADDING = 4; + +var INITIAL_CANVAS_WIDTH; +var INITIAL_CANVAS_HEIGHT; + +var paper; +var viewBox; +var viewBoxWidth; +var viewBoxHeight; + +var canvasWidth; +var canvasHeight; + +var modelDiv = jQuery('#cmmnModel'); +var modelId = modelDiv.attr('data-model-id'); +var historyModelId = modelDiv.attr('data-history-id'); +var caseDefinitionId = modelDiv.attr('data-case-definition-id'); +var modelType = modelDiv.attr('data-model-type'); + +var elementsAdded = new Array(); +var elementsRemoved = new Array(); + +function _showTip(htmlNode, element) +{ + // Default tooltip, no custom tool tip set + if (documentation === undefined) { + var documentation = ""; + if (element.name && element.name.length > 0) { + documentation += "Name: " + element.name + "

"; + } + + if (element.properties) { + for (var i = 0; i < element.properties.length; i++) { + var propName = element.properties[i].name; + if (element.properties[i].type && element.properties[i].type === 'list') { + documentation += '' + propName + ':
'; + for (var j = 0; j < element.properties[i].value.length; j++) { + documentation += '' + element.properties[i].value[j] + '
'; + } + } + else { + documentation += '' + propName + ': ' + element.properties[i].value + '
'; + } + } + } + } + + var text = element.type + " "; + if (element.name && element.name.length > 0) + { + text += element.name; + } + else + { + text += element.id; + } + + htmlNode.qtip({ + content: { + text: documentation, + title: { + text: text + } + }, + position: { + my: 'top left', + at: 'bottom center', + viewport: jQuery('#cmmnModel') + }, + hide: { + fixed: true, delay: 500, + event: 'click mouseleave' + }, + style: { + classes: 'ui-tooltip-flowable-cmmn' + } + }); +} + +function _addHoverLogic(element, type, defaultColor) +{ + var strokeColor = _cmmnGetColor(element, defaultColor); + var topBodyRect = null; + if (type === "rect") + { + topBodyRect = paper.rect(element.x, element.y, element.width, element.height); + } + else if (type === "circle") + { + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + topBodyRect = paper.circle(x, y, 15); + } + else if (type === "rhombus") + { + topBodyRect = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + } + + var opacity = 0; + var fillColor = "#ffffff"; + if (jQuery.inArray(element.id, elementsAdded) >= 0) + { + opacity = 0.2; + fillColor = "green"; + } + + if (jQuery.inArray(element.id, elementsRemoved) >= 0) + { + opacity = 0.2; + fillColor = "red"; + } + + topBodyRect.attr({ + "opacity": opacity, + "stroke" : "none", + "fill" : fillColor + }); + _showTip(jQuery(topBodyRect.node), element); + + topBodyRect.mouseover(function() { + paper.getById(element.id).attr({"stroke":HOVER_COLOR}); + }); + + topBodyRect.mouseout(function() { + paper.getById(element.id).attr({"stroke":strokeColor}); + }); +} + +function _zoom(zoomIn) +{ + var tmpCanvasWidth, tmpCanvasHeight; + if (zoomIn) + { + tmpCanvasWidth = canvasWidth * (1.0/0.90); + tmpCanvasHeight = canvasHeight * (1.0/0.90); + } + else + { + tmpCanvasWidth = canvasWidth * (1.0/1.10); + tmpCanvasHeight = canvasHeight * (1.0/1.10); + } + + if (tmpCanvasWidth != canvasWidth || tmpCanvasHeight != canvasHeight) + { + canvasWidth = tmpCanvasWidth; + canvasHeight = tmpCanvasHeight; + paper.setSize(canvasWidth, canvasHeight); + } +} + +var modelUrl; + +if (modelType == 'runtime') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getCaseInstancesHistoryModelJsonUrl(historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getCaseInstancesModelJsonUrl(modelId); + } +} else if (modelType == 'design') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getModelHistoryModelJsonUrl(modelId, historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getModelModelJsonUrl(modelId); + } +} else if (modelType == 'case-definition') { + modelUrl = FLOWABLE.APP_URL.getCaseDefinitionModelJsonUrl(caseDefinitionId); +} + +var request = jQuery.ajax({ + type: 'get', + url: modelUrl + '?nocaching=' + new Date().getTime() +}); + +request.success(function(data, textStatus, jqXHR) { + + if ((!data.elements || data.elements.length == 0) && (!data.pools || data.pools.length == 0)) return; + + INITIAL_CANVAS_WIDTH = data.diagramWidth; + + if (modelType == 'design') { + INITIAL_CANVAS_WIDTH += 20; + } else { + INITIAL_CANVAS_WIDTH += 30; + } + + INITIAL_CANVAS_HEIGHT = data.diagramHeight + 50; + canvasWidth = INITIAL_CANVAS_WIDTH; + canvasHeight = INITIAL_CANVAS_HEIGHT; + viewBoxWidth = INITIAL_CANVAS_WIDTH; + viewBoxHeight = INITIAL_CANVAS_HEIGHT; + + if (modelType == 'design') { + var headerBarHeight = 170; + var offsetY = 0; + if (jQuery(window).height() > (canvasHeight + headerBarHeight)) + { + offsetY = (jQuery(window).height() - headerBarHeight - canvasHeight) / 2; + } + + if (offsetY > 50) { + offsetY = 50; + } + + jQuery('#cmmnModel').css('marginTop', offsetY); + } + + jQuery('#cmmnModel').width(INITIAL_CANVAS_WIDTH); + jQuery('#cmmnModel').height(INITIAL_CANVAS_HEIGHT); + paper = Raphael(document.getElementById('cmmnModel'), canvasWidth, canvasHeight); + paper.setViewBox(0, 0, viewBoxWidth, viewBoxHeight, false); + paper.renderfix(); + + var modelElements = data.elements; + for (var i = 0; i < modelElements.length; i++) + { + var element = modelElements[i]; + //try { + var drawFunction = eval("_draw" + element.type); + drawFunction(element); + //} catch(err) {console.log(err);} + } + + if (data.flows) + { + for (var i = 0; i < data.flows.length; i++) + { + var flow = data.flows[i]; + _drawAssociation(flow); + } + } +}); + +request.error(function(jqXHR, textStatus, errorThrown) { + alert("error"); +}); diff --git a/zbf-admin/src/main/resources/static/designer/display/.gitignore b/zbf-admin/src/main/resources/static/designer/display/.gitignore new file mode 100644 index 0000000..26e82b0 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/.gitignore @@ -0,0 +1,3 @@ +/dist +/node_modules +/displaymodel_temp.html diff --git a/zbf-admin/src/main/resources/static/designer/display/Gruntfile.js b/zbf-admin/src/main/resources/static/designer/display/Gruntfile.js new file mode 100644 index 0000000..9aac21f --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/Gruntfile.js @@ -0,0 +1,153 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +module.exports = function (grunt) { + + require('load-grunt-tasks')(grunt); + require('time-grunt')(grunt); + + grunt.initConfig({ + yeoman: { + app: require('./package.json').appPath || 'app', + dist: 'dist' + }, + clean: { + dist: { + files: [ + { + dot: true, + src: [ + '.tmp', + '<%= yeoman.dist %>/*', + '!<%= yeoman.dist %>/.git*' + ] + } + ] + }, + server: '.tmp' + }, + useminPrepare: { + html: 'displaymodel.html', + options: { + dest: '<%= yeoman.dist %>/' + } + }, + usemin: { + html: ['<%= yeoman.dist %>/{,*/}*.html'], + css: ['<%= yeoman.dist %>/display/styles/{,*/}*.css'], + options: { + dirs: ['<%= yeoman.dist %>'] + } + }, + // Put files not handled in other tasks here + copy: { + dist: { + files: [{ + expand: true, + dot: true, + cwd: '.', + dest: '<%= yeoman.dist %>', + src: [ + 'fonts/*' + ] + }, { + expand: true, + cwd: '.tmp/images', + dest: '<%= yeoman.dist %>/images', + src: [ + 'generated/*' + ] + }] + }, + styles: { + expand: true, + cwd: 'styles', + dest: '.tmp/styles/', + src: '{,*/}*.css' + }, + index: { + expand: true, + cwd: './', + src: ['*.html', 'views/**/**.html'], + dest: '<%= yeoman.dist %>' + }, + copyCss : { + files: [ + {expand: true, cwd:'.tmp/concat/display/styles/', src:'*.css', dest:'<%= yeoman.dist %>/display/styles/', filter: 'isFile'} + ] + }, + copyJs : { + files: [ + {expand: true, cwd:'.tmp/concat/display/scripts', src:'*.js', dest:'<%= yeoman.dist %>/display/scripts/', filter: 'isFile'} + ] + }, + }, + ngAnnotate: { + dist: { + files: [ + { + expand: true, + cwd: '.tmp/concat/display/scripts', + src: '*.js', + dest: '.tmp/concat/display/scripts' + } + ] + } + }, + uglify: { + dist: { + options: { + mangle: true + }, + files: { + '<%= yeoman.dist %>/display/scripts/displaymodel-logic.js': [ + '<%= yeoman.dist %>/display/scripts/displaymodel-logic.js' + ] + } + } + }, + rev: { + dist: { + files: { + src: [ + '<%= yeoman.dist %>/display/{,*/}*.js', + '<%= yeoman.dist %>/display/{,*/}*.css', + '<%= yeoman.dist %>/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' + ] + } + } + } + }); + + grunt.registerTask('buildApp', [ + 'clean:dist', + 'useminPrepare', + 'copy:styles', + 'concat', + 'copy:dist', + 'ngAnnotate', + 'copy:copyCss', + 'copy:copyJs', + 'copy:index', + 'uglify', + 'rev', + 'usemin' + ]); + + + grunt.registerTask('default', [ + 'buildApp' + ]); + +}; diff --git a/zbf-admin/src/main/resources/static/designer/display/Polyline.js b/zbf-admin/src/main/resources/static/designer/display/Polyline.js new file mode 100644 index 0000000..aafef8f --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/Polyline.js @@ -0,0 +1,387 @@ +/* Copyright 2005-2015 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Class to generate polyline + * + * @author Dmitry Farafonov + */ + +var ANCHOR_TYPE= { + main: "main", + middle: "middle", + first: "first", + last: "last" +}; + +function Anchor(uuid, type, x, y) { + this.uuid = uuid; + this.x = x; + this.y = y; + this.type = (type == ANCHOR_TYPE.middle) ? ANCHOR_TYPE.middle : ANCHOR_TYPE.main; +}; +Anchor.prototype = { + uuid: null, + x: 0, + y: 0, + type: ANCHOR_TYPE.main, + isFirst: false, + isLast: false, + ndex: 0, + typeIndex: 0 +}; + +function Polyline(uuid, points, strokeWidth, paper) { + /* Array on coordinates: + * points: [{x: 410, y: 110}, 1 + * {x: 570, y: 110}, 1 2 + * {x: 620, y: 240}, 2 3 + * {x: 750, y: 270}, 3 4 + * {x: 650, y: 370}]; 4 + */ + this.points = points; + + /* + * path for graph + * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]] + */ + this.path = []; + + this.anchors = []; + + if (strokeWidth) this.strokeWidth = strokeWidth; + + this.paper = paper; + + this.closePath = false; + + this.init(); +}; + +Polyline.prototype = { + id: null, + points: [], + path: [], + anchors: [], + strokeWidth: 1, + radius: 1, + showDetails: false, + paper: null, + element: null, + isDefaultConditionAvailable: false, + closePath: false, + + init: function(points){ + var linesCount = this.getLinesCount(); + if (linesCount < 1) + return; + + this.normalizeCoordinates(); + + // create anchors + + this.pushAnchor(ANCHOR_TYPE.first, this.getLine(0).x1, this.getLine(0).y1); + + for (var i = 1; i < linesCount; i++) + { + var line1 = this.getLine(i-1); + this.pushAnchor(ANCHOR_TYPE.main, line1.x2, line1.y2); + } + + this.pushAnchor(ANCHOR_TYPE.last, this.getLine(linesCount-1).x2, this.getLine(linesCount-1).y2); + + this.rebuildPath(); + }, + + normalizeCoordinates: function(){ + for(var i=0; i < this.points.length; i++){ + this.points[i].x = parseFloat(this.points[i].x); + this.points[i].y = parseFloat(this.points[i].y); + } + }, + + getLinesCount: function(){ + return this.points.length-1; + }, + _getLine: function(i){ + if (this.points.length > i && this.points[i]) { + return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y}; + } else { + return undefined; + } + }, + getLine: function(i){ + var line = this._getLine(i); + if (line != undefined) { + line.angle = this.getLineAngle(i); + } + return line; + }, + getLineAngle: function(i){ + var line = this._getLine(i); + return Math.atan2(line.y2 - line.y1, line.x2 - line.x1); + }, + getLineLengthX: function(i){ + var line = this.getLine(i); + return (line.x2 - line.x1); + }, + getLineLengthY: function(i){ + var line = this.getLine(i); + return (line.y2 - line.y1); + }, + getLineLength: function(i){ + return Math.sqrt(Math.pow(this.getLineLengthX(i), 2) + Math.pow(this.getLineLengthY(i), 2)); + }, + + getAnchors: function(){ + return this.anchors; + }, + getAnchorsCount: function(type){ + if (!type) + return this.anchors.length; + else { + var count = 0; + for(var i=0; i < this.getAnchorsCount(); i++){ + var anchor = this.anchors[i]; + if (anchor.getType() == type) { + count++; + } + } + return count; + } + }, + + pushAnchor: function(type, x, y, index){ + if (type == ANCHOR_TYPE.first) { + index = 0; + typeIndex = 0; + } else if (type == ANCHOR_TYPE.last) { + index = this.getAnchorsCount(); + typeIndex = 0; + } else if (!index) { + index = this.anchors.length; + } else { + for(var i=0; i < this.getAnchorsCount(); i++){ + var anchor = this.anchors[i]; + if (anchor.index > index) { + anchor.index++; + anchor.typeIndex++; + } + } + } + + var anchor = new Anchor(this.id, ANCHOR_TYPE.main, x, y, index, typeIndex); + + this.anchors.push(anchor); + }, + + getAnchor: function(position){ + return this.anchors[position]; + }, + + getAnchorByType: function(type, position){ + if (type == ANCHOR_TYPE.first) + return this.anchors[0]; + if (type == ANCHOR_TYPE.last) + return this.anchors[this.getAnchorsCount()-1]; + + for(var i=0; i < this.getAnchorsCount(); i++){ + var anchor = this.anchors[i]; + if (anchor.type == type) { + if( position == anchor.position) + return anchor; + } + } + return null; + }, + + addNewPoint: function(position, x, y){ + // + for(var i = 0; i < this.getLinesCount(); i++){ + var line = this.getLine(i); + if (x > line.x1 && x < line.x2 && y > line.y1 && y < line.y2) { + this.points.splice(i+1,0,{x: x, y: y}); + break; + } + } + + this.rebuildPath(); + }, + + rebuildPath: function(){ + var path = []; + + for(var i = 0; i < this.getAnchorsCount(); i++){ + var anchor = this.getAnchor(i); + + var pathType = ""; + if (i == 0) + pathType = "M"; + else + pathType = "L"; + + // TODO: save previous points and calculate new path just if points are updated, and then save currents values as previous + + var targetX = anchor.x, targetY = anchor.y; + if (i>0 && i < this.getAnchorsCount()-1) { + // get new x,y + var cx = anchor.x, cy = anchor.y; + + // pivot point of prev line + var AO = this.getLineLength(i-1); + if (AO < this.radius) { + AO = this.radius; + } + + this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10)); + + var ED = this.getLineLengthY(i-1) * this.radius / AO; + var OD = this.getLineLengthX(i-1) * this.radius / AO; + targetX = anchor.x - OD; + targetY = anchor.y - ED; + + if (AO < 2*this.radius && i>1) { + targetX = anchor.x - this.getLineLengthX(i-1)/2; + targetY = anchor.y - this.getLineLengthY(i-1)/2;; + } + + // pivot point of next line + var AO = this.getLineLength(i); + if (AO < this.radius) { + AO = this.radius; + } + var ED = this.getLineLengthY(i) * this.radius / AO; + var OD = this.getLineLengthX(i) * this.radius / AO; + var nextSrcX = anchor.x + OD; + var nextSrcY = anchor.y + ED; + + if (AO < 2*this.radius && i 10)); + } + + // anti smoothing + if (this.strokeWidth%2 == 1) { + targetX += 0.5; + targetY += 0.5; + } + + path.push([pathType, targetX, targetY]); + + if (i>0 && i < this.getAnchorsCount()-1) { + path.push(["C", ax, ay, bx, by, zx, zy]); + } + } + + if (this.closePath) + { + path.push(["Z"]); + } + + this.path = path; + }, + + transform: function(transformation) + { + this.element.transform(transformation); + }, + attr: function(attrs) + { + // TODO: foreach and set each + this.element.attr(attrs); + } +}; + +function Polygone(points, strokeWidth) { + /* Array on coordinates: + * points: [{x: 410, y: 110}, 1 + * {x: 570, y: 110}, 1 2 + * {x: 620, y: 240}, 2 3 + * {x: 750, y: 270}, 3 4 + * {x: 650, y: 370}]; 4 + */ + this.points = points; + + /* + * path for graph + * [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]] + */ + this.path = []; + + this.anchors = []; + + if (strokeWidth) this.strokeWidth = strokeWidth; + + this.closePath = true; + this.init(); +}; + + +/* + * Poligone is inherited from Poliline: draws closedPath of polyline + */ + +var Foo = function () { }; +Foo.prototype = Polyline.prototype; + +Polygone.prototype = new Foo(); + +Polygone.prototype.rebuildPath = function(){ + var path = []; + for(var i = 0; i < this.getAnchorsCount(); i++){ + var anchor = this.getAnchor(i); + + var pathType = ""; + if (i == 0) + pathType = "M"; + else + pathType = "L"; + + var targetX = anchor.x, targetY = anchor.y; + + // anti smoothing + if (this.strokeWidth%2 == 1) { + targetX += 0.5; + targetY += 0.5; + } + + path.push([pathType, targetX, targetY]); + } + if (this.closePath) + path.push(["Z"]); + + this.path = path; +}; diff --git a/zbf-admin/src/main/resources/static/designer/display/bpmn-draw.js b/zbf-admin/src/main/resources/static/designer/display/bpmn-draw.js new file mode 100644 index 0000000..b573976 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/bpmn-draw.js @@ -0,0 +1,866 @@ +/* Copyright 2005-2015 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +function _bpmnGetColor(element, defaultColor) +{ + var strokeColor; + if(element.current) { + strokeColor = CURRENT_COLOR; + } else if(element.completed) { + strokeColor = COMPLETED_COLOR; + } else { + strokeColor = defaultColor; + } + return strokeColor; +} + +function _drawPool(pool) +{ + var rect = paper.rect(pool.x, pool.y, pool.width, pool.height); + + rect.attr({"stroke-width": 1, + "stroke": "#000000", + "fill": "white" + }); + + if (pool.name) + { + var poolName = paper.text(pool.x + 14, pool.y + (pool.height / 2), pool.name).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + poolName.transform("r270"); + } + + if (pool.lanes) + { + for (var i = 0; i < pool.lanes.length; i++) + { + var lane = pool.lanes[i]; + _drawLane(lane); + } + } +} + +function _drawLane(lane) +{ + var rect = paper.rect(lane.x, lane.y, lane.width, lane.height); + + rect.attr({"stroke-width": 1, + "stroke": "#000000", + "fill": "white" + }); + + if (lane.name) + { + var laneName = paper.text(lane.x + 10, lane.y + (lane.height / 2), lane.name).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + laneName.transform("r270"); + } +} + +function _drawSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); +} + +function _drawTransaction(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + var borderRect = paper.rect(element.x + 2, element.y + 2, element.width - 4, element.height -4, 4); + + borderRect.attr({"stroke-width": 1, + "stroke": "black", + "fill": "none" + }); +} + +function _drawEventSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "stroke-dasharray": ".", + "fill": "white" + }); +} + +function _drawAdhocSubProcess(element) +{ + var rect = paper.rect(element.x, element.y, element.width, element.height, 4); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + rect.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + paper.text(element.x + (element.width / 2), element.y + element.height - 8).attr({ + "text-anchor" : "middle", + "font-family" : "Arial", + "font-size" : 20, + "text" : "~", + "fill" : "#373e48" + }); +} + +function _drawStartEvent(element) +{ + var startEvent = _drawEvent(element, NORMAL_STROKE, 15); + startEvent.click(function() { + _zoom(true); + }); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); +} + +function _drawEndEvent(element) +{ + var endEvent = _drawEvent(element, ENDEVENT_STROKE, 14); + endEvent.click(function() { + _zoom(false); + }); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); +} + +function _drawEvent(element, strokeWidth, radius) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, radius); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + // Fill + var eventFillColor = _determineCustomFillColor(element, "#ffffff"); + + // Opacity + var eventOpacity = 1.0; + if (customActivityBackgroundOpacity) { + eventOpacity = customActivityBackgroundOpacity; + } + + if (element.interrupting === undefined || element.interrupting) { + circle.attr({ + "stroke-width": strokeWidth, + "stroke": strokeColor, + "fill": eventFillColor, + "fill-opacity": eventOpacity + }); + + } else { + circle.attr({ + "stroke-width": strokeWidth, + "stroke": strokeColor, + "stroke-dasharray": ".", + "fill": eventFillColor, + "fill-opacity": eventOpacity + }); + } + + circle.id = element.id; + + _drawEventIcon(paper, element); + + return circle; +} + +function _drawServiceTask(element) +{ + _drawTask(element); + if (element.taskType === "mail") + { + _drawSendTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "camel") + { + _drawCamelTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "mule") + { + _drawMuleTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "http") + { + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "shell") + { + _drawShellTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.taskType === "dmn") { + _drawDecisionTaskIcon(paper, element.x + 4, element.y + 4); + } + else if (element.stencilIconId) + { + paper.image("../service/stencilitem/" + element.stencilIconId + "/icon", element.x + 4, element.y + 4, 16, 16); + } + else + { + _drawServiceTaskIcon(paper, element.x + 4, element.y + 4); + } + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawHttpServiceTask(element) +{ + _drawTask(element); + _drawHttpTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawCallActivity(element) +{ + var width = element.width - (CALL_ACTIVITY_STROKE / 2); + var height = element.height - (CALL_ACTIVITY_STROKE / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + + var strokeColor = _bpmnGetColor(element, ACTIVITY_STROKE_COLOR); + + // Fill + var callActivityFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var callActivityOpacity = 1.0; + if (customActivityBackgroundOpacity) { + callActivityOpacity = customActivityBackgroundOpacity; + } + + rect.attr({"stroke-width": CALL_ACTIVITY_STROKE, + "stroke": strokeColor, + "fill": callActivityFillColor, + "fill-opacity": callActivityOpacity + }); + + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawScriptTask(element) +{ + _drawTask(element); + _drawScriptTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawUserTask(element) +{ + _drawTask(element); + _drawUserTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawBusinessRuleTask(element) +{ + _drawTask(element); + _drawBusinessRuleTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawManualTask(element) +{ + _drawTask(element); + _drawManualTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawSendTask(element) +{ + _drawTask(element); + _drawSendTaskIcon(paper, element.x + 4, element.y + 4); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawReceiveTask(element) +{ + _drawTask(element); + _drawReceiveTaskIcon(paper, element.x, element.y); + _addHoverLogic(element, "rect", ACTIVITY_STROKE_COLOR); +} + +function _drawTask(element) +{ + var rectAttrs = {}; + + // Stroke + var strokeColor = _bpmnGetColor(element, ACTIVITY_STROKE_COLOR); + rectAttrs['stroke'] = strokeColor; + + var strokeWidth; + if (strokeColor === ACTIVITY_STROKE_COLOR) { + strokeWidth = TASK_STROKE; + } else { + strokeWidth = TASK_HIGHLIGHT_STROKE; + } + + var width = element.width - (strokeWidth / 2); + var height = element.height - (strokeWidth / 2); + + var rect = paper.rect(element.x, element.y, width, height, 4); + rectAttrs['stroke-width'] = strokeWidth; + + // Fill + var fillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + rectAttrs['fill'] = fillColor; + + // Opacity + if (customActivityBackgroundOpacity) { + rectAttrs['fill-opacity'] = customActivityBackgroundOpacity; + } + + rect.attr(rectAttrs); + rect.id = element.id; + + if (element.name) { + this._drawMultilineText(element.name, element.x, element.y, element.width, element.height, "middle", "middle", 11); + } +} + +function _drawExclusiveGateway(element) +{ + _drawGateway(element); + var quarterWidth = element.width / 4; + var quarterHeight = element.height / 4; + + var iks = paper.path( + "M" + (element.x + quarterWidth + 3) + " " + (element.y + quarterHeight + 3) + + "L" + (element.x + 3 * quarterWidth - 3) + " " + (element.y + 3 * quarterHeight - 3) + + "M" + (element.x + quarterWidth + 3) + " " + (element.y + 3 * quarterHeight - 3) + + "L" + (element.x + 3 * quarterWidth - 3) + " " + (element.y + quarterHeight + 3) + ); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + + iks.attr({"stroke-width": 3, "stroke": strokeColor, "fill": gatewayFillColor, "fill-opacity": gatewayOpacity}); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawParallelGateway(element) +{ + _drawGateway(element); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var path1 = paper.path("M 6.75,16 L 25.75,16 M 16,6.75 L 16,25.75"); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + path1.attr({ + "stroke-width": 3, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + path1.transform("T" + (element.x + 4) + "," + (element.y + 4)); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawInclusiveGateway(element) +{ + _drawGateway(element); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var circle1 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 9.75); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + circle1.attr({ + "stroke-width": 2.5, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawEventGateway(element) +{ + _drawGateway(element); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var circle1 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 10.4); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + circle1.attr({ + "stroke-width": 0.5, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + var circle2 = paper.circle(element.x + (element.width / 2), element.y + (element.height / 2), 11.7); + circle2.attr({ + "stroke-width": 0.5, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity + }); + + var path1 = paper.path("M 20.327514,22.344972 L 11.259248,22.344216 L 8.4577203,13.719549 L 15.794545,8.389969 L 23.130481,13.720774 L 20.327514,22.344972 z"); + path1.attr({ + "stroke-width": 1.39999998, + "stroke": strokeColor, + "fill": gatewayFillColor, + "fill-opacity": gatewayOpacity, + "stroke-linejoin": "bevel" + }); + + path1.transform("T" + (element.x + 4) + "," + (element.y + 4)); + + _addHoverLogic(element, "rhombus", MAIN_STROKE_COLOR); +} + +function _drawGateway(element) +{ + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + var rhombus = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + + // Fill + var gatewayFillColor = _determineCustomFillColor(element, ACTIVITY_FILL_COLOR); + + // Opacity + var gatewayOpacity = 1.0; + if (customActivityBackgroundOpacity) { + gatewayOpacity = customActivityBackgroundOpacity; + } + + rhombus.attr("stroke-width", 2); + rhombus.attr("stroke", strokeColor); + rhombus.attr("fill", gatewayFillColor); + rhombus.attr("fill-opacity", gatewayOpacity); + + rhombus.id = element.id; + + return rhombus; +} + +function _drawBoundaryEvent(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + if (element.cancelActivity) { + circle.attr({ + "stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + } else { + circle.attr({ + "stroke-width": 1, + "stroke-dasharray": ".", + "stroke": strokeColor, + "fill": "white" + }); + } + + var innerCircle = paper.circle(x, y, 12); + + if (element.cancelActivity) { + innerCircle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "none" + }); + + } else { + innerCircle.attr({ + "stroke-width": 1, + "stroke-dasharray": ".", + "stroke": strokeColor, + "fill": "none" + }); + } + + _drawEventIcon(paper, element); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); + + circle.id = element.id; + innerCircle.id = element.id + "_inner"; +} + +function _drawIntermediateCatchEvent(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + circle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + var innerCircle = paper.circle(x, y, 12); + + innerCircle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "none" + }); + + _drawEventIcon(paper, element); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); + + circle.id = element.id; + innerCircle.id = element.id + "_inner"; +} + +function _drawThrowEvent(element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 15); + + var strokeColor = _bpmnGetColor(element, MAIN_STROKE_COLOR); + + circle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "white" + }); + + var innerCircle = paper.circle(x, y, 12); + + innerCircle.attr({"stroke-width": 1, + "stroke": strokeColor, + "fill": "none" + }); + + _drawEventIcon(paper, element); + _addHoverLogic(element, "circle", MAIN_STROKE_COLOR); + + circle.id = element.id; + innerCircle.id = element.id + "_inner"; +} + +function _drawMultilineText(text, x, y, boxWidth, boxHeight, horizontalAnchor, verticalAnchor, fontSize) +{ + if (!text || text == "") + { + return; + } + + var textBoxX, textBoxY; + var width = boxWidth - (2 * TEXT_PADDING); + + if (horizontalAnchor === "middle") + { + textBoxX = x + (boxWidth / 2); + } + else if (horizontalAnchor === "start") + { + textBoxX = x; + } + + textBoxY = y + (boxHeight / 2); + + var t = paper.text(textBoxX + TEXT_PADDING, textBoxY + TEXT_PADDING).attr({ + "text-anchor" : horizontalAnchor, + "font-family" : "Arial", + "font-size" : fontSize, + "fill" : "#373e48" + }); + + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + t.attr({ + "text" : abc + }); + var letterWidth = t.getBBox().width / abc.length; + + t.attr({ + "text" : text + }); + var removedLineBreaks = text.split("\n"); + var x = 0, s = []; + for (var r = 0; r < removedLineBreaks.length; r++) + { + var words = removedLineBreaks[r].split(" "); + for ( var i = 0; i < words.length; i++) { + + var l = words[i].length; + if (x + (l * letterWidth) > width) { + s.push("\n"); + x = 0; + } + x += l * letterWidth; + s.push(words[i] + " "); + } + s.push("\n"); + x = 0; + } + t.attr({ + "text" : s.join("") + }); + + if (verticalAnchor && verticalAnchor === "top") + { + t.attr({"y": y + (t.getBBox().height / 2)}); + } +} + +function _drawTextAnnotation(element) +{ + var path1 = paper.path("M20,1 L1,1 L1,50 L20,50"); + path1.attr({ + "stroke": "#585858", + "fill": "none" + }); + + var annotation = paper.set(); + annotation.push(path1); + + annotation.transform("T" + element.x + "," + element.y); + + if (element.text) { + this._drawMultilineText(element.text, element.x + 2, element.y, element.width, element.height, "start", "middle", 11); + } +} + +function _drawFlow(flow){ + + var polyline = new Polyline(flow.id, flow.waypoints, SEQUENCEFLOW_STROKE, paper); + + var strokeColor = _bpmnGetColor(flow, MAIN_STROKE_COLOR); + + polyline.element = paper.path(polyline.path); + polyline.element.attr({"stroke-width":SEQUENCEFLOW_STROKE}); + polyline.element.attr({"stroke":strokeColor}); + + polyline.element.id = flow.id; + + var lastLineIndex = polyline.getLinesCount() - 1; + var line = polyline.getLine(lastLineIndex); + + if (line == undefined) return; + + if (flow.type == "connection" && flow.conditions) + { + var middleX = (line.x1 + line.x2) / 2; + var middleY = (line.y1 + line.y2) / 2; + var image = paper.image("../editor/images/condition-flow.png", middleX - 8, middleY - 8, 16, 16); + } + + var polylineInvisible = new Polyline(flow.id, flow.waypoints, SEQUENCEFLOW_STROKE, paper); + + polylineInvisible.element = paper.path(polyline.path); + polylineInvisible.element.attr({ + "opacity": 0, + "stroke-width": 8, + "stroke" : "#000000" + }); + + if (flow.name) { + var firstLine = polyline.getLine(0); + + var angle; + if (firstLine.x1 !== firstLine.x2) { + angle = Math.atan((firstLine.y2 - firstLine.y1) / (firstLine.x2 - firstLine.x1)); + } else if (firstLine.y1 < firstLine.y2) { + angle = Math.PI / 2; + } else { + angle = -Math.PI / 2; + } + var flowName = paper.text(firstLine.x1, firstLine.y1, flow.name).attr({ + "text-anchor": "middle", + "font-family" : "Arial", + "font-size" : "12", + "fill" : "#000000" + }); + + var offsetX = (flowName.getBBox().width / 2 + 5); + var offsetY = -(flowName.getBBox().height / 2 + 5); + + if (firstLine.x1 > firstLine.x2) { + offsetX = -offsetX; + } + var rotatedOffsetX = offsetX * Math.cos(angle) - offsetY * Math.sin(angle); + var rotatedOffsetY = offsetX * Math.sin(angle) + offsetY * Math.cos(angle); + + flowName.attr({ + x: firstLine.x1 + rotatedOffsetX, + y: firstLine.y1 + rotatedOffsetY + }); + + flowName.transform("r" + ((angle) * 180) / Math.PI); + } + + _showTip(jQuery(polylineInvisible.element.node), flow); + + polylineInvisible.element.mouseover(function() { + paper.getById(polyline.element.id).attr({"stroke":"blue"}); + }); + + polylineInvisible.element.mouseout(function() { + paper.getById(polyline.element.id).attr({"stroke":"#585858"}); + }); + + _drawArrowHead(line); +} + +function _drawAssociation(flow){ + + var polyline = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + + polyline.element = paper.path(polyline.path); + polyline.element.attr({"stroke-width": ASSOCIATION_STROKE}); + polyline.element.attr({"stroke-dasharray": ". "}); + polyline.element.attr({"stroke":"#585858"}); + + polyline.element.id = flow.id; + + var polylineInvisible = new Polyline(flow.id, flow.waypoints, ASSOCIATION_STROKE, paper); + + polylineInvisible.element = paper.path(polyline.path); + polylineInvisible.element.attr({ + "opacity": 0, + "stroke-width": 8, + "stroke" : "#000000" + }); + + _showTip(jQuery(polylineInvisible.element.node), flow); + + polylineInvisible.element.mouseover(function() { + paper.getById(polyline.element.id).attr({"stroke":"blue"}); + }); + + polylineInvisible.element.mouseout(function() { + paper.getById(polyline.element.id).attr({"stroke":"#585858"}); + }); +} + +function _drawArrowHead(line, connectionType) +{ + var doubleArrowWidth = 2 * ARROW_WIDTH; + + var arrowHead = paper.path("M0 0L-" + (ARROW_WIDTH / 2 + .5) + " -" + doubleArrowWidth + "L" + (ARROW_WIDTH/2 + .5) + " -" + doubleArrowWidth + "z"); + + // anti smoothing + if (this.strokeWidth%2 == 1) + line.x2 += .5, line.y2 += .5; + + arrowHead.transform("t" + line.x2 + "," + line.y2 + ""); + arrowHead.transform("...r" + Raphael.deg(line.angle - Math.PI / 2) + " " + 0 + " " + 0); + + arrowHead.attr("fill", "#585858"); + + arrowHead.attr("stroke-width", SEQUENCEFLOW_STROKE); + arrowHead.attr("stroke", "#585858"); + + return arrowHead; +} + +function _determineCustomFillColor(element, defaultColor) { + + var color; + + // By name + if (customActivityColors && customActivityColors[element.name]) { + color = customActivityColors[element.name]; + } + + if (color !== null && color !== undefined) { + return color; + } + + // By id + if (customActivityColors && customActivityColors[element.id]) { + color = customActivityColors[element.id]; + } + + if (color !== null && color !== undefined) { + return color; + } + + return defaultColor; +} diff --git a/zbf-admin/src/main/resources/static/designer/display/bpmn-icons.js b/zbf-admin/src/main/resources/static/designer/display/bpmn-icons.js new file mode 100644 index 0000000..d99cc2b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/bpmn-icons.js @@ -0,0 +1,342 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +function _drawUserTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,17 16,0 0,-1.7778 -5.333332,-3.5555 0,-1.7778 c 1.244444,0 1.244444,-2.3111 1.244444,-2.3111 l 0,-3.0222 C 12.555557,0.8221 9.0000001,1.0001 9.0000001,1.0001 c 0,0 -3.5555556,-0.178 -3.9111111,3.5555 l 0,3.0222 c 0,0 0,2.3111 1.2444443,2.3111 l 0,1.7778 L 1,15.2222 1,17 17,17"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#d1b575" + }); + + var userTaskIcon = paper.set(); + userTaskIcon.push(path1); + + userTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawServiceTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M 8,1 7.5,2.875 c 0,0 -0.02438,0.250763 -0.40625,0.4375 C 7.05724,3.330353 7.04387,3.358818 7,3.375 6.6676654,3.4929791 6.3336971,3.6092802 6.03125,3.78125 6.02349,3.78566 6.007733,3.77681 6,3.78125 5.8811373,3.761018 5.8125,3.71875 5.8125,3.71875 l -1.6875,-1 -1.40625,1.4375 0.96875,1.65625 c 0,0 0.065705,0.068637 0.09375,0.1875 0.002,0.00849 -0.00169,0.022138 0,0.03125 C 3.6092802,6.3336971 3.4929791,6.6676654 3.375,7 3.3629836,7.0338489 3.3239228,7.0596246 3.3125,7.09375 3.125763,7.4756184 2.875,7.5 2.875,7.5 L 1,8 l 0,2 1.875,0.5 c 0,0 0.250763,0.02438 0.4375,0.40625 0.017853,0.03651 0.046318,0.04988 0.0625,0.09375 0.1129372,0.318132 0.2124732,0.646641 0.375,0.9375 -0.00302,0.215512 -0.09375,0.34375 -0.09375,0.34375 L 2.6875,13.9375 4.09375,15.34375 5.78125,14.375 c 0,0 0.1229911,-0.09744 0.34375,-0.09375 0.2720511,0.147787 0.5795915,0.23888 0.875,0.34375 0.033849,0.01202 0.059625,0.05108 0.09375,0.0625 C 7.4756199,14.874237 7.5,15.125 7.5,15.125 L 8,17 l 2,0 0.5,-1.875 c 0,0 0.02438,-0.250763 0.40625,-0.4375 0.03651,-0.01785 0.04988,-0.04632 0.09375,-0.0625 0.332335,-0.117979 0.666303,-0.23428 0.96875,-0.40625 0.177303,0.0173 0.28125,0.09375 0.28125,0.09375 l 1.65625,0.96875 1.40625,-1.40625 -0.96875,-1.65625 c 0,0 -0.07645,-0.103947 -0.09375,-0.28125 0.162527,-0.290859 0.262063,-0.619368 0.375,-0.9375 0.01618,-0.04387 0.04465,-0.05724 0.0625,-0.09375 C 14.874237,10.52438 15.125,10.5 15.125,10.5 L 17,10 17,8 15.125,7.5 c 0,0 -0.250763,-0.024382 -0.4375,-0.40625 C 14.669647,7.0572406 14.641181,7.0438697 14.625,7 14.55912,6.8144282 14.520616,6.6141566 14.4375,6.4375 c -0.224363,-0.4866 0,-0.71875 0,-0.71875 L 15.40625,4.0625 14,2.625 l -1.65625,1 c 0,0 -0.253337,0.1695664 -0.71875,-0.03125 l -0.03125,0 C 11.405359,3.5035185 11.198648,3.4455201 11,3.375 10.95613,3.3588185 10.942759,3.3303534 10.90625,3.3125 10.524382,3.125763 10.5,2.875 10.5,2.875 L 10,1 8,1 z m 1,5 c 1.656854,0 3,1.3431458 3,3 0,1.656854 -1.343146,3 -3,3 C 7.3431458,12 6,10.656854 6,9 6,7.3431458 7.3431458,6 9,6 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var serviceTaskIcon = paper.set(); + serviceTaskIcon.push(path1); + + serviceTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawScriptTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 5,2 0,0.094 c 0.23706,0.064 0.53189,0.1645 0.8125,0.375 0.5582,0.4186 1.05109,1.228 1.15625,2.5312 l 8.03125,0 1,0 1,0 c 0,-3 -2,-3 -2,-3 l -10,0 z M 4,3 4,13 2,13 c 0,3 2,3 2,3 l 9,0 c 0,0 2,0 2,-3 L 15,6 6,6 6,5.5 C 6,4.1111 5.5595,3.529 5.1875,3.25 4.8155,2.971 4.5,3 4.5,3 L 4,3 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#72a7d0" + }); + + var scriptTaskIcon = paper.set(); + scriptTaskIcon.push(path1); + + scriptTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawBusinessRuleTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.45458,5.6000386 2.90906,0 0,2.7999224 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.7999224 -8.72718,0 z m -4.36364,4.1998844 2.90906,0 0,2.800116 -2.90906,0 z m 4.36364,0 8.72718,0 0,2.800116 -8.72718,0 z"); + path1.attr({ + "stroke": "none", + "fill": "#72a7d0" + }); + + var businessRuleTaskIcon = paper.set(); + businessRuleTaskIcon.push(path1); + + businessRuleTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawSendTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z"); + path1.attr({ + "stroke": "none", + "fill": "#16964d" + }); + + var sendTaskIcon = paper.set(); + sendTaskIcon.push(path1); + + sendTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawManualTaskIcon(paper, startX, startY) +{ + var path1 = paper.path("m 17,9.3290326 c -0.0069,0.5512461 -0.455166,1.0455894 -0.940778,1.0376604 l -5.792746,0 c 0.0053,0.119381 0.0026,0.237107 0.0061,0.355965 l 5.154918,0 c 0.482032,-0.0096 0.925529,0.49051 0.919525,1.037574 -0.0078,0.537128 -0.446283,1.017531 -0.919521,1.007683 l -5.245273,0 c -0.01507,0.104484 -0.03389,0.204081 -0.05316,0.301591 l 2.630175,0 c 0.454137,-0.0096 0.872112,0.461754 0.866386,0.977186 C 13.619526,14.554106 13.206293,15.009498 12.75924,15 L 3.7753054,15 C 3.6045812,15 3.433552,14.94423 3.2916363,14.837136 c -0.00174,0 -0.00436,0 -0.00609,0 C 1.7212035,14.367801 0.99998255,11.458641 1,11.458641 L 1,7.4588393 c 0,0 0.6623144,-1.316333 1.8390583,-2.0872584 1.1767614,-0.7711868 6.8053358,-2.40497 7.2587847,-2.8052901 0.453484,-0.40032 1.660213,1.4859942 0.04775,2.4010487 C 8.5332315,5.882394 8.507351,5.7996113 8.4370292,5.7936859 l 6.3569748,-0.00871 c 0.497046,-0.00958 0.952273,0.5097676 0.94612,1.0738232 -0.0053,0.556126 -0.456176,1.0566566 -0.94612,1.0496854 l -4.72435,0 c 0.01307,0.1149374 0.0244,0.2281319 0.03721,0.3498661 l 5.952195,0 c 0.494517,-0.00871 0.947906,0.5066305 0.940795,1.0679848 z"); + path1.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#d1b575" + }); + + var manualTaskIcon = paper.set(); + manualTaskIcon.push(path1); + + manualTaskIcon.transform("T" + startX + "," + startY); +} + +function _drawReceiveTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 0.5,2.5 0,13 17,0 0,-13 z M 2,4 6.5,8.5 2,13 z M 4,4 14,4 9,9 z m 12,0 0,9 -4.5,-4.5 z M 7.5,9.5 9,11 10.5,9.5 15,14 3,14 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + + startX += 4; + startY += 2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawCamelTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 8.1878027,15.383782 c -0.824818,-0.3427 0.375093,-1.1925 0.404055,-1.7743 0.230509,-0.8159 -0.217173,-1.5329 -0.550642,-2.2283 -0.106244,-0.5273 -0.03299,-1.8886005 -0.747194,-1.7818005 -0.712355,0.3776 -0.9225,1.2309005 -1.253911,1.9055005 -0.175574,1.0874 -0.630353,2.114 -0.775834,3.2123 -0.244009,0.4224 -1.741203,0.3888 -1.554386,-0.1397 0.651324,-0.3302 1.13227,-0.9222 1.180246,-1.6705 0.0082,-0.7042 -0.133578,-1.3681 0.302178,-2.0083 0.08617,-0.3202 0.356348,-1.0224005 -0.218996,-0.8051 -0.694517,0.2372 -1.651062,0.6128 -2.057645,-0.2959005 -0.696769,0.3057005 -1.102947,-0.611 -1.393127,-1.0565 -0.231079,-0.6218 -0.437041,-1.3041 -0.202103,-1.9476 -0.185217,-0.7514 -0.39751099,-1.5209 -0.35214999,-2.301 -0.243425,-0.7796 0.86000899,-1.2456 0.08581,-1.8855 -0.76078999,0.1964 -1.41630099,-0.7569 -0.79351899,-1.2877 0.58743,-0.52829998 1.49031699,-0.242 2.09856399,-0.77049998 0.816875,-0.3212 1.256619,0.65019998 1.923119,0.71939998 0.01194,0.7333 -0.0031,1.5042 -0.18417,2.2232 -0.194069,0.564 -0.811196,1.6968 0.06669,1.9398 0.738382,-0.173 1.095723,-0.9364 1.659041,-1.3729 0.727298,-0.3962 1.093982,-1.117 1.344137,-1.8675 0.400558,-0.8287 1.697676,-0.6854 1.955367,0.1758 0.103564,0.5511 0.9073983,1.7538 1.2472763,0.6846 0.121868,-0.6687 0.785541,-1.4454 1.518183,-1.0431 0.813587,0.4875 0.658233,1.6033 1.285504,2.2454 0.768715,0.8117 1.745394,1.4801 2.196633,2.5469 0.313781,0.8074 0.568552,1.707 0.496624,2.5733 -0.35485,0.8576005 -1.224508,-0.216 -0.64725,-0.7284 0.01868,-0.3794 -0.01834,-1.3264 -0.370249,-1.3272 -0.123187,0.7586 -0.152778,1.547 -0.10869,2.3154 0.270285,0.6662005 1.310741,0.7653005 1.060553,1.6763005 -0.03493,0.9801 0.294343,1.9505 0.148048,2.9272 -0.320479,0.2406 -0.79575,0.097 -1.185062,0.1512 -0.165725,0.3657 -0.40138,0.921 -1.020848,0.6744 -0.564671,0.1141 -1.246404,-0.266 -0.578559,-0.7715 0.679736,-0.5602 0.898618,-1.5362 0.687058,-2.3673 -0.529674,-1.108 -1.275984,-2.0954005 -1.839206,-3.1831005 -0.634619,-0.1004 -1.251945,0.6779 -1.956789,0.7408 -0.6065893,-0.038 -1.0354363,-0.06 -0.8495673,0.6969005 0.01681,0.711 0.152396,1.3997 0.157345,2.1104 0.07947,0.7464 0.171287,1.4944 0.238271,2.2351 0.237411,1.0076 -0.687542,1.1488 -1.414811,0.8598 z m 6.8675483,-1.8379 c 0.114364,-0.3658 0.206751,-1.2704 -0.114466,-1.3553 -0.152626,0.5835 -0.225018,1.1888 -0.227537,1.7919 0.147087,-0.1166 0.265559,-0.2643 0.342003,-0.4366 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#bd4848" + }); + + startX += 4; + startY += 2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawMuleTaskIcon(paper, startX, startY) +{ + var path = paper.path("M 8,0 C 3.581722,0 0,3.5817 0,8 c 0,4.4183 3.581722,8 8,8 4.418278,0 8,-3.5817 8,-8 L 16,7.6562 C 15.813571,3.3775 12.282847,0 8,0 z M 5.1875,2.7812 8,7.3437 10.8125,2.7812 c 1.323522,0.4299 2.329453,1.5645 2.8125,2.8438 1.136151,2.8609 -0.380702,6.4569 -3.25,7.5937 -0.217837,-0.6102 -0.438416,-1.2022 -0.65625,-1.8125 0.701032,-0.2274 1.313373,-0.6949 1.71875,-1.3125 0.73624,-1.2317 0.939877,-2.6305 -0.03125,-4.3125 l -2.75,4.0625 -0.65625,0 -0.65625,0 -2.75,-4 C 3.5268433,7.6916 3.82626,8.862 4.5625,10.0937 4.967877,10.7113 5.580218,11.1788 6.28125,11.4062 6.063416,12.0165 5.842837,12.6085 5.625,13.2187 2.755702,12.0819 1.238849,8.4858 2.375,5.625 2.858047,4.3457 3.863978,3.2112 5.1875,2.7812 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#bd4848" + }); + + startX += 4; + startY += 2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawAlfrescoPublishTaskIcon(paper, startX, startY) +{ + + startX += 2; + startY += 2; + + var path = paper.path("M4.11870968,2.12890323 L6.12954839,0.117935484 L3.10993548,0.118064516 L3.10270968,0.118064516 C1.42941935,0.118064516 0.0729032258,1.47458065 0.0729032258,3.14774194 C0.0729032258,4.82116129 1.42929032,6.17754839 3.10258065,6.17754839 C3.22967742,6.17754839 3.35470968,6.16877419 3.47767742,6.15354839 C2.8163871,4.85083871 3.02954839,3.21793548 4.11870968,2.12890323M6.57032258,3.144 L6.57032258,0.300258065 L4.43522581,2.4356129 L4.43006452,2.44064516 C3.24683871,3.62387097 3.24683871,5.54219355 4.43006452,6.72541935 C5.61329032,7.90864516 7.5316129,7.90864516 8.71483871,6.72541935 C8.80464516,6.6356129 8.88529032,6.54025806 8.96154839,6.44270968 C7.57341935,5.98864516 6.57045161,4.68387097 6.57032258,3.144"); + path.attr({"fill": "#87C040"}); + + var startX1 = startX + 1.419355; + var startY1 = startY + 8.387097; + path.transform("T" + startX1 + "," + startY1); + + path = paper.path("M10.4411613,10.5153548 L8.43032258,8.50451613 L8.43032258,11.5313548 C8.43032258,13.2047742 9.78683871,14.5611613 11.460129,14.5611613 C13.1334194,14.5611613 14.4899355,13.2047742 14.4899355,11.5314839 C14.4899355,11.4043871 14.4811613,11.2793548 14.4659355,11.1563871 C13.1632258,11.8178065 11.5303226,11.6045161 10.4411613,10.5153548M15.0376774,5.91935484 C14.947871,5.82954839 14.8526452,5.74890323 14.7550968,5.67264516 C14.3010323,7.06064516 12.996129,8.06374194 11.4563871,8.06374194 L8.61277419,8.06374194 L10.7529032,10.204 C11.936129,11.3872258 13.8545806,11.3872258 15.0376774,10.204 C16.2209032,9.02077419 16.2209032,7.10245161 15.0376774,5.91935484"); + path.attr({"fill": "#87C040"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M5.9083871,1.5636129 C5.78129032,1.5636129 5.65625806,1.57225806 5.53329032,1.58748387 C6.19458065,2.89032258 5.98141935,4.52309677 4.89225806,5.61225806 L2.88154839,7.62309677 L5.9083871,7.62309677 C7.58154839,7.62309677 8.93806452,6.26658065 8.93806452,4.59329032 C8.93819355,2.92 7.58167742,1.5636129 5.9083871,1.5636129"); + path.attr({"fill": "#ED9A2D"}); + var startX2 = startX + 5.548387; + path.transform("T" + startX2 + "," + startY); + path = paper.path("M4.58090323,1.0156129 C3.39767742,-0.167483871 1.47935484,-0.167483871 0.296129032,1.01574194 C0.206451613,1.10554839 0.125806452,1.20077419 0.0495483871,1.29845161 C1.43754839,1.75251613 2.44064516,3.05729032 2.44064516,4.59703226 L2.44064516,7.44077419 L4.57574194,5.30554839 L4.58090323,5.30051613 C5.76412903,4.11729032 5.76412903,2.19896774 4.58090323,1.0156129"); + path.attr({"fill": "#5698C6"}); + path.transform("T" + startX2 + "," + startY); + + path = paper.path("M5.54051613,5.61432258 L5.62670968,5.70425806 L7.54632258,7.62387097 L7.5483871,7.62387097 L7.5483871,4.604 L7.5483871,4.59677419 C7.5483871,2.92348387 6.19187097,1.56696774 4.51858065,1.56696774 C2.84529032,1.56696774 1.48877419,2.92335484 1.48890323,4.59664516 C1.48890323,4.72348387 1.49754839,4.84812903 1.51264516,4.97083871 C2.81625806,4.30993548 4.45122581,4.52503226 5.54051613,5.61432258M1.23251613,10.4292903 C1.25625806,10.3588387 1.28180645,10.2894194 1.30980645,10.2210323 C1.31329032,10.2123871 1.3163871,10.2036129 1.32,10.1952258 C1.35070968,10.1216774 1.38451613,10.0500645 1.42,9.97935484 C1.42774194,9.96374194 1.43574194,9.9483871 1.44387097,9.93277419 C1.4803871,9.86258065 1.51883871,9.79354839 1.55987097,9.72632258 C1.56425806,9.71909677 1.56903226,9.71225806 1.57341935,9.70529032 C1.6123871,9.64245161 1.65354839,9.58141935 1.6963871,9.52141935 C1.70516129,9.50903226 1.71380645,9.49651613 1.72283871,9.48425806 C1.76890323,9.42154839 1.81690323,9.36064516 1.86683871,9.30129032 C1.87703226,9.28916129 1.88735484,9.27741935 1.89780645,9.26567742 C1.94658065,9.20916129 1.99690323,9.15406452 2.04916129,9.10090323 C2.05380645,9.09625806 2.05806452,9.09135484 2.06270968,9.08670968 C2.11832258,9.03083871 2.17625806,8.97741935 2.23548387,8.92554839 C2.2483871,8.91419355 2.26129032,8.90296774 2.27432258,8.89187097 C2.33393548,8.84103226 2.39496774,8.79212903 2.45780645,8.74529032 C2.46606452,8.73922581 2.47470968,8.73354839 2.48296774,8.7276129 C2.54167742,8.68490323 2.60180645,8.64412903 2.66322581,8.60503226 C2.67535484,8.59729032 2.68735484,8.58929032 2.6996129,8.58167742 C2.76593548,8.54064516 2.83380645,8.50206452 2.90296774,8.46541935 C2.91754839,8.45780645 2.93225806,8.45045161 2.94696774,8.44296774 C3.016,8.40774194 3.08593548,8.37406452 3.15741935,8.34348387 C3.16090323,8.34206452 3.16425806,8.3403871 3.16774194,8.33883871 C3.24167742,8.30748387 3.31729032,8.27948387 3.39380645,8.25316129 C3.41032258,8.24748387 3.42670968,8.24180645 3.44335484,8.2363871 C3.51909677,8.21174194 3.59587097,8.18903226 3.67380645,8.16929032 C3.68567742,8.16645161 3.69793548,8.16387097 3.70980645,8.16116129 C3.78206452,8.14374194 3.85509677,8.12877419 3.92890323,8.116 C3.94270968,8.11367742 3.9563871,8.11083871 3.97019355,8.10877419 C4.05032258,8.09587097 4.13148387,8.08619355 4.21329032,8.07896774 C4.23096774,8.07741935 4.24877419,8.07625806 4.26645161,8.07483871 C4.35109677,8.06877419 4.43612903,8.06451613 4.52232258,8.06451613 L7.36606452,8.0643871 L5.22580645,5.92412903 C4.04258065,4.74103226 2.12412903,4.74090323 0.941032258,5.92412903 C-0.242193548,7.10735484 -0.242193548,9.02567742 0.941032258,10.2089032 C1.03070968,10.2985806 1.12464516,10.3814194 1.22206452,10.4575484 C1.22529032,10.448 1.22929032,10.4388387 1.23251613,10.4292903"); + path.attr({"fill": "#5698C6"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M5.23290323,5.92412903 L6.92748387,7.61870968 L4.64980645,7.61870968 L4.52064516,7.62141935 C3.13354839,7.62141935 1.96425806,6.68929032 1.60477419,5.41729032 C2.75870968,4.77019355 4.24619355,4.93754839 5.22787097,5.91909677 L5.23290323,5.92412903M7.54722581,4.59612903 L7.54722581,6.99264516 L5.93664516,5.38206452 L5.84348387,5.29264516 C4.86258065,4.31187097 4.69483871,2.82580645 5.34012903,1.67225806 C6.61367742,2.03070968 7.54722581,3.20090323 7.54722581,4.58890323 L7.54722581,4.59612903M10.1385806,5.29819355 L8.444,6.99290323 L8.444,4.71522581 L8.44129032,4.58606452 C8.44129032,3.19896774 9.37341935,2.02954839 10.6454194,1.67019355 C11.2925161,2.82412903 11.1251613,4.3116129 10.1436129,5.29316129 L10.1385806,5.29819355"); + path.attr({"fill": "#446BA5"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M11.4548387,7.61677419 L9.05832258,7.61677419 L10.6689032,6.00619355 L10.7583226,5.91303226 C11.7390968,4.93212903 13.2251613,4.7643871 14.3787097,5.40967742 C14.0202581,6.68322581 12.8500645,7.61677419 11.4620645,7.61677419 L11.4548387,7.61677419"); + path.attr({"fill": "#FFF101"}); + path.transform("T" + startX + "," + startY); + + path = paper.path("M10.7470968,10.192 L9.05251613,8.49741935 L11.3301935,8.49741935 L11.4593548,8.49470968 C12.8464516,8.49483871 14.0157419,9.42696774 14.3752258,10.6989677 C13.2211613,11.3459355 11.7338065,11.1787097 10.752129,10.1970323 L10.7470968,10.192M8.43729032,11.5174194 L8.43729032,9.12090323 L10.047871,10.7314839 L10.1411613,10.8209032 C11.1219355,11.8018065 11.2896774,13.2876129 10.6443871,14.4412903 C9.37083871,14.0828387 8.43729032,12.9127742 8.43729032,11.5245161 L8.43729032,11.5174194M5.86193548,10.8296774 L7.55651613,9.13496774 L7.55651613,11.4126452 L7.55922581,11.5418065 C7.55922581,12.9289032 6.62709677,14.0983226 5.35509677,14.4578065 C4.708,13.3036129 4.87535484,11.8162581 5.85690323,10.8347097 L5.86193548,10.8296774M4.53251613,8.50993548 L6.92903226,8.50993548 L5.31845161,10.1205161 L5.22903226,10.2136774 C4.24812903,11.1945806 2.76219355,11.3623226 1.60851613,10.7170323 C1.96709677,9.44335484 3.13716129,8.50993548 4.52529032,8.50993548 L4.53251613,8.50993548"); + path.attr({"fill": "#45AB47"}); + path.transform("T" + startX + "," + startY); +} + +function _drawHttpTaskIcon(paper, startX, startY) +{ + var path = paper.path("m 16.704699,5.9229055 q 0.358098,0 0.608767,0.2506681 0.250669,0.250668 0.250669,0.6087677 0,0.3580997 -0.250669,0.6087677 -0.250669,0.2506679 -0.608767,0.2506679 -0.358098,0 -0.608767,-0.2506679 -0.250669,-0.250668 -0.250669,-0.6087677 0,-0.3580997 0.250669,-0.6087677 0.250669,-0.2506681 0.608767,-0.2506681 z m 2.578308,-2.0053502 q -2.229162,0 -3.854034,0.6759125 -1.624871,0.6759067 -3.227361,2.2694472 -0.716197,0.725146 -1.575633,1.7457293 L 7.2329969,8.7876913 Q 7.0897576,8.8055849 7.000233,8.9309334 L 4.9948821,12.368677 q -0.035811,0.06267 -0.035811,0.143242 0,0.107426 0.080572,0.205905 l 0.5729577,0.572957 q 0.125334,0.116384 0.2864786,0.07162 l 2.4708789,-0.760963 2.5156417,2.515645 -0.76096,2.470876 q -0.009,0.02687 -0.009,0.08057 0,0.125338 0.08058,0.205905 l 0.572957,0.572958 q 0.170096,0.152194 0.349146,0.04476 l 3.437744,-2.005351 q 0.125335,-0.08953 0.143239,-0.232763 l 0.17905,-3.392986 q 1.02058,-0.859435 1.745729,-1.575629 1.67411,-1.6830612 2.309735,-3.2049805 0.635625,-1.5219191 0.635625,-3.8585111 0,-0.1253369 -0.08505,-0.2148575 -0.08505,-0.089526 -0.201431,-0.089526 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + + startX += -2; + startY += -2; + + path.transform("T" + startX + "," + startY); + +} + +function _drawShellTaskIcon(paper, startX, startY) { + var path = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.4,3 12.7,0 0,10 -12.7,0 z"); + path.attr({ + "opacity": 1, + "stroke": "none", + "fill": "#16964d" + }); + var text = paper.text(3, 9, ">_").attr({ + "font-size": "5px", + "fill": "#16964d" + }); + + startY += -2; + text.transform("T" + startX + "," + startY); + startX += -2; + path.transform("T" + startX + "," + startY); +} + +function _drawDecisionTaskIcon(paper, startX, startY) { + var path1 = paper.path("m 1,2 0,14 16,0 0,-14 z m 1.9,2.4000386 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m -8.67364,3.9 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z m 4.36364,0 3.7,0 0,2.7999224 -3.7,0 z"); + path1.attr({ + "opacity": 1, + "stroke": "#000000", + "fill": "#F4F6F7" + }); + + var decisionTaskIcon = paper.set(); + decisionTaskIcon.push(path1); + + decisionTaskIcon.translate(startX, startY); + decisionTaskIcon.scale(0.7, 0.7); +} + +function _drawEventIcon(paper, element) +{ + if (element.eventDefinition && element.eventDefinition.type) + { + if ("timer" === element.eventDefinition.type) + { + _drawTimerIcon(paper, element); + } + else if ("error" === element.eventDefinition.type) + { + _drawErrorIcon(paper, element); + } + else if ("signal" === element.eventDefinition.type) + { + _drawSignalIcon(paper, element); + } + else if ("message" === element.eventDefinition.type) + { + _drawMessageIcon(paper, element); + } + } +} + +function _drawTimerIcon(paper, element) +{ + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + + var circle = paper.circle(x, y, 10); + + circle.attr({"stroke-width": 1, + "stroke": "black", + "fill": "none" + }); + + var path = paper.path("M 10 0 C 4.4771525 0 0 4.4771525 0 10 C 0 15.522847 4.4771525 20 10 20 C 15.522847 20 20 15.522847 20 10 C 20 4.4771525 15.522847 1.1842379e-15 10 0 z M 9.09375 1.03125 C 9.2292164 1.0174926 9.362825 1.0389311 9.5 1.03125 L 9.5 3.5 L 10.5 3.5 L 10.5 1.03125 C 15.063526 1.2867831 18.713217 4.9364738 18.96875 9.5 L 16.5 9.5 L 16.5 10.5 L 18.96875 10.5 C 18.713217 15.063526 15.063526 18.713217 10.5 18.96875 L 10.5 16.5 L 9.5 16.5 L 9.5 18.96875 C 4.9364738 18.713217 1.2867831 15.063526 1.03125 10.5 L 3.5 10.5 L 3.5 9.5 L 1.03125 9.5 C 1.279102 5.0736488 4.7225326 1.4751713 9.09375 1.03125 z M 9.5 5 L 9.5 8.0625 C 8.6373007 8.2844627 8 9.0680195 8 10 C 8 11.104569 8.8954305 12 10 12 C 10.931981 12 11.715537 11.362699 11.9375 10.5 L 14 10.5 L 14 9.5 L 11.9375 9.5 C 11.756642 8.7970599 11.20294 8.2433585 10.5 8.0625 L 10.5 5 L 9.5 5 z"); + path.attr({ + "stroke": "none", + "fill": "#585858" + }); + path.transform("T" + (element.x + 5) + "," + (element.y + 5)); + return path; +} + +function _drawErrorIcon(paper, element) +{ + var path = paper.path("M 22.820839,11.171502 L 19.36734,24.58992 L 13.54138,14.281819 L 9.3386512,20.071607 L 13.048949,6.8323057 L 18.996148,16.132659 L 22.820839,11.171502 z"); + + var fill = "none"; + var x = element.x - 1; + var y = element.y - 1; + if (element.type === "EndEvent") + { + fill = "black"; + x -= 1; + y -= 1; + } + + path.attr({ + "stroke": "black", + "stroke-width": 1, + "fill": fill + }); + + path.transform("T" + x + "," + y); + return path; +} + +function _drawSignalIcon(paper, element) +{ + var fill = "none"; + if (element.type === "ThrowEvent") + { + fill = "black"; + } + + var path = paper.path("M 8.7124971,21.247342 L 23.333334,21.247342 L 16.022915,8.5759512 L 8.7124971,21.247342 z"); + path.attr({ + "stroke": "black", + "stroke-width": 1, + "fill": fill + }); + path.transform("T" + (element.x - 1) + "," + (element.y - 1)); + return path; +} + +function _drawMessageIcon(paper, element) +{ + var fill = "none"; + if (element.type === "ThrowEvent") + { + fill = "black"; + } + + var path = paper.path("M 1 3 L 9 11 L 17 3 L 1 3 z M 1 5 L 1 13 L 5 9 L 1 5 z M 17 5 L 13 9 L 17 13 L 17 5 z M 6 10 L 1 15 L 17 15 L 12 10 L 9 13 L 6 10 z"); + path.attr({ + "stroke": "black", + "stroke-width": 1, + "fill": fill + }); + path.transform("T" + (element.x + 6) + "," + (element.y + 6)); + return path; +} diff --git a/zbf-admin/src/main/resources/static/designer/display/displaymodel.css b/zbf-admin/src/main/resources/static/designer/display/displaymodel.css new file mode 100644 index 0000000..272b258 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/displaymodel.css @@ -0,0 +1,24 @@ +div[class*='ui-tooltip-kisbpm-'] { + background-color: #ffffff; + border-color: #c5c5c5; + color: #4a4a4a; + font-family: Verdana; + font-size: 12px; +} + +div[class*='ui-tooltip-kisbpm-'] .qtip-content { + color: #4a4a4a; + background-color: #ffffff; + font-family: Verdana; + font-size: 12px; +} + +.ui-tooltip-kisbpm-bpmn .qtip-titlebar { + color: #FFFFFF; + font-size: 12px; + background: #2B414F; +} + +.ui-tooltip-kisbpm-bpmn .qtip-tip { + background-color: #2B414F; +} diff --git a/zbf-admin/src/main/resources/static/designer/display/displaymodel.html b/zbf-admin/src/main/resources/static/designer/display/displaymodel.html new file mode 100644 index 0000000..a6d5a9e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/displaymodel.html @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/display/displaymodel.js b/zbf-admin/src/main/resources/static/designer/display/displaymodel.js new file mode 100644 index 0000000..9b81a69 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/displaymodel.js @@ -0,0 +1,317 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var NORMAL_STROKE = 1; +var SEQUENCEFLOW_STROKE = 1.5; +var ASSOCIATION_STROKE = 2; +var TASK_STROKE = 1; +var TASK_HIGHLIGHT_STROKE = 2; +var CALL_ACTIVITY_STROKE = 2; +var ENDEVENT_STROKE = 3; + +var COMPLETED_COLOR= "#2632aa"; +var TEXT_COLOR= "#373e48"; +var CURRENT_COLOR= "#017501"; +var HOVER_COLOR= "#666666"; +var ACTIVITY_STROKE_COLOR = "#bbbbbb"; +var ACTIVITY_FILL_COLOR = "#f9f9f9"; +var MAIN_STROKE_COLOR = "#585858"; + +var TEXT_PADDING = 3; +var ARROW_WIDTH = 4; +var MARKER_WIDTH = 12; + +var TASK_FONT = {font: "11px Arial", opacity: 1, fill: Raphael.rgb(0, 0, 0)}; + +// icons +var ICON_SIZE = 16; +var ICON_PADDING = 4; + +var INITIAL_CANVAS_WIDTH; +var INITIAL_CANVAS_HEIGHT; + +var paper; +var viewBox; +var viewBoxWidth; +var viewBoxHeight; + +var canvasWidth; +var canvasHeight; + +var modelDiv = jQuery('#bpmnModel'); +var modelId = modelDiv.attr('data-model-id'); +var historyModelId = modelDiv.attr('data-history-id'); +var processDefinitionId = modelDiv.attr('data-process-definition-id'); +var modelType = modelDiv.attr('data-model-type'); + +// Support for custom background colors for activities +var customActivityColors = modelDiv.attr('data-activity-color-mapping'); +if (customActivityColors !== null && customActivityColors !== undefined && customActivityColors.length > 0) { + // Stored on the attribute as a string + customActivityColors = JSON.parse(customActivityColors); +} + +var customActivityToolTips = modelDiv.attr('data-activity-tooltips'); +if (customActivityToolTips !== null && customActivityToolTips !== undefined && customActivityToolTips.length > 0) { + // Stored on the attribute as a string + customActivityToolTips = JSON.parse(customActivityToolTips); +} + +// Support for custom opacity for activity backgrounds +var customActivityBackgroundOpacity = modelDiv.attr('data-activity-opacity'); + +var elementsAdded = new Array(); +var elementsRemoved = new Array(); + +function _showTip(htmlNode, element) +{ + + // Custom tooltip + var documentation = undefined; + if (customActivityToolTips) { + if (customActivityToolTips[element.name]) { + documentation = customActivityToolTips[element.name]; + } else if (customActivityToolTips[element.id]) { + documentation = customActivityToolTips[element.id]; + } else { + documentation = ''; // Show nothing if custom tool tips are enabled + } + } + + // Default tooltip, no custom tool tip set + if (documentation === undefined) { + var documentation = ""; + if (element.name && element.name.length > 0) { + documentation += "Name: " + element.name + "

"; + } + + if (element.properties) { + for (var i = 0; i < element.properties.length; i++) { + var propName = element.properties[i].name; + if (element.properties[i].type && element.properties[i].type === 'list') { + documentation += '' + propName + ':
'; + for (var j = 0; j < element.properties[i].value.length; j++) { + documentation += '' + element.properties[i].value[j] + '
'; + } + } + else { + documentation += '' + propName + ': ' + element.properties[i].value + '
'; + } + } + } + } + + var text = element.type + " "; + if (element.name && element.name.length > 0) + { + text += element.name; + } + else + { + text += element.id; + } + + htmlNode.qtip({ + content: { + text: documentation, + title: { + text: text + } + }, + position: { + my: 'top left', + at: 'bottom center', + viewport: jQuery('#bpmnModel') + }, + hide: { + fixed: true, delay: 500, + event: 'click mouseleave' + }, + style: { + classes: 'ui-tooltip-kisbpm-bpmn' + } + }); +} + +function _addHoverLogic(element, type, defaultColor) +{ + var strokeColor = _bpmnGetColor(element, defaultColor); + var topBodyRect = null; + if (type === "rect") + { + topBodyRect = paper.rect(element.x, element.y, element.width, element.height); + } + else if (type === "circle") + { + var x = element.x + (element.width / 2); + var y = element.y + (element.height / 2); + topBodyRect = paper.circle(x, y, 15); + } + else if (type === "rhombus") + { + topBodyRect = paper.path("M" + element.x + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + (element.y + element.height) + + "L" + (element.x + element.width) + " " + (element.y + (element.height / 2)) + + "L" + (element.x + (element.width / 2)) + " " + element.y + "z" + ); + } + + var opacity = 0; + var fillColor = "#ffffff"; + if (jQuery.inArray(element.id, elementsAdded) >= 0) + { + opacity = 0.2; + fillColor = "green"; + } + + if (jQuery.inArray(element.id, elementsRemoved) >= 0) + { + opacity = 0.2; + fillColor = "red"; + } + + topBodyRect.attr({ + "opacity": opacity, + "stroke" : "none", + "fill" : fillColor + }); + _showTip(jQuery(topBodyRect.node), element); + + topBodyRect.mouseover(function() { + paper.getById(element.id).attr({"stroke":HOVER_COLOR}); + }); + + topBodyRect.mouseout(function() { + paper.getById(element.id).attr({"stroke":strokeColor}); + }); +} + +function _zoom(zoomIn) +{ + var tmpCanvasWidth, tmpCanvasHeight; + if (zoomIn) + { + tmpCanvasWidth = canvasWidth * (1.0/0.90); + tmpCanvasHeight = canvasHeight * (1.0/0.90); + } + else + { + tmpCanvasWidth = canvasWidth * (1.0/1.10); + tmpCanvasHeight = canvasHeight * (1.0/1.10); + } + + if (tmpCanvasWidth != canvasWidth || tmpCanvasHeight != canvasHeight) + { + canvasWidth = tmpCanvasWidth; + canvasHeight = tmpCanvasHeight; + paper.setSize(canvasWidth, canvasHeight); + } +} + +var modelUrl; + +if (modelType == 'runtime') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getProcessInstanceModelJsonHistoryUrl(historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getProcessInstanceModelJsonUrl(modelId); + } +} else if (modelType == 'design') { + if (historyModelId) { + modelUrl = FLOWABLE.APP_URL.getModelHistoryModelJsonUrl(modelId, historyModelId); + } else { + modelUrl = FLOWABLE.APP_URL.getModelModelJsonUrl(modelId); + } +} else if (modelType == 'process-definition') { + modelUrl = FLOWABLE.APP_URL.getProcessDefinitionModelJsonUrl(processDefinitionId); +} + +var request = jQuery.ajax({ + type: 'get', + url: modelUrl + '?nocaching=' + new Date().getTime() +}); + +request.success(function(data, textStatus, jqXHR) { + + if ((!data.elements || data.elements.length == 0) && (!data.pools || data.pools.length == 0)) return; + + INITIAL_CANVAS_WIDTH = data.diagramWidth; + + if (modelType == 'design') { + INITIAL_CANVAS_WIDTH += 20; + } else { + INITIAL_CANVAS_WIDTH += 30; + } + + INITIAL_CANVAS_HEIGHT = data.diagramHeight + 50; + canvasWidth = INITIAL_CANVAS_WIDTH; + canvasHeight = INITIAL_CANVAS_HEIGHT; + viewBoxWidth = INITIAL_CANVAS_WIDTH; + viewBoxHeight = INITIAL_CANVAS_HEIGHT; + + if (modelType == 'design') { + var headerBarHeight = 170; + var offsetY = 0; + if (jQuery(window).height() > (canvasHeight + headerBarHeight)) + { + offsetY = (jQuery(window).height() - headerBarHeight - canvasHeight) / 2; + } + + if (offsetY > 50) { + offsetY = 50; + } + + jQuery('#bpmnModel').css('marginTop', offsetY); + } + + jQuery('#bpmnModel').width(INITIAL_CANVAS_WIDTH); + jQuery('#bpmnModel').height(INITIAL_CANVAS_HEIGHT); + paper = Raphael(document.getElementById('bpmnModel'), canvasWidth, canvasHeight); + paper.setViewBox(0, 0, viewBoxWidth, viewBoxHeight, false); + paper.renderfix(); + + if (data.pools) + { + for (var i = 0; i < data.pools.length; i++) + { + var pool = data.pools[i]; + _drawPool(pool); + } + } + + var modelElements = data.elements; + for (var i = 0; i < modelElements.length; i++) + { + var element = modelElements[i]; + //try { + var drawFunction = eval("_draw" + element.type); + drawFunction(element); + //} catch(err) {console.log(err);} + } + + if (data.flows) + { + for (var i = 0; i < data.flows.length; i++) + { + var flow = data.flows[i]; + if (flow.type === 'sequenceFlow') { + _drawFlow(flow); + } else if (flow.type === 'association') { + _drawAssociation(flow); + } + } + } +}); + +request.error(function(jqXHR, textStatus, errorThrown) { + alert("error"); +}); diff --git a/zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.css b/zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.css new file mode 100644 index 0000000..aef428d --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.css @@ -0,0 +1,2 @@ +/* qTip2 v2.2.0 basic css3 | qtip2.com | Licensed MIT, GPL | Wed Dec 18 2013 05:02:24 */ +.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;direction:ltr;box-shadow:none;padding:0}.qtip-content{position:relative;padding:5px 9px;overflow:hidden;text-align:left;word-wrap:break-word}.qtip-titlebar{position:relative;padding:5px 35px 5px 10px;overflow:hidden;border-width:0 0 1px;font-weight:700}.qtip-titlebar+.qtip-content{border-top-width:0!important}.qtip-close{position:absolute;right:-9px;top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;border-color:transparent}.qtip-titlebar .qtip-close{right:4px;top:50%;margin-top:-9px}* html .qtip-titlebar .qtip-close{top:16px}.qtip-titlebar .ui-icon,.qtip-icon .ui-icon{display:block;text-indent:-1000em;direction:ltr}.qtip-icon,.qtip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;text-decoration:none}.qtip-icon .ui-icon{width:18px;height:14px;line-height:14px;text-align:center;text-indent:0;font:400 bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}.qtip-focus{}.qtip-hover{}.qtip-default{border-width:1px;border-style:solid;border-color:#F1D031;background-color:#FFFFA3;color:#555}.qtip-default .qtip-titlebar{background-color:#FFEF93}.qtip-default .qtip-icon{border-color:#CCC;background:#F1F1F1;color:#777}.qtip-default .qtip-titlebar .qtip-close{border-color:#AAA;color:#111} .qtip-light{background-color:#fff;border-color:#E2E2E2;color:#454545}.qtip-light .qtip-titlebar{background-color:#f1f1f1} .qtip-dark{background-color:#505050;border-color:#303030;color:#f3f3f3}.qtip-dark .qtip-titlebar{background-color:#404040}.qtip-dark .qtip-icon{border-color:#444}.qtip-dark .qtip-titlebar .ui-state-hover{border-color:#303030} .qtip-cream{background-color:#FBF7AA;border-color:#F9E98E;color:#A27D35}.qtip-cream .qtip-titlebar{background-color:#F0DE7D}.qtip-cream .qtip-close .qtip-icon{background-position:-82px 0} .qtip-red{background-color:#F78B83;border-color:#D95252;color:#912323}.qtip-red .qtip-titlebar{background-color:#F06D65}.qtip-red .qtip-close .qtip-icon{background-position:-102px 0}.qtip-red .qtip-icon{border-color:#D95252}.qtip-red .qtip-titlebar .ui-state-hover{border-color:#D95252} .qtip-green{background-color:#CAED9E;border-color:#90D93F;color:#3F6219}.qtip-green .qtip-titlebar{background-color:#B0DE78}.qtip-green .qtip-close .qtip-icon{background-position:-42px 0} .qtip-blue{background-color:#E5F6FE;border-color:#ADD9ED;color:#5E99BD}.qtip-blue .qtip-titlebar{background-color:#D0E9F5}.qtip-blue .qtip-close .qtip-icon{background-position:-2px 0}.qtip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,.15)}.qtip-rounded,.qtip-tipsy,.qtip-bootstrap{-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.qtip-rounded .qtip-titlebar{-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.qtip-youtube{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;color:#fff;border-width:0;background:#4A4A4A;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,#000));background-image:-webkit-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-moz-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-ms-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-o-linear-gradient(top,#4A4A4A 0,#000 100%)}.qtip-youtube .qtip-titlebar{background-color:#4A4A4A;background-color:rgba(0,0,0,0)}.qtip-youtube .qtip-content{padding:.75em;font:12px arial,sans-serif;filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);-ms-filter:"progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);"}.qtip-youtube .qtip-icon{border-color:#222}.qtip-youtube .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-jtools{background:#232323;background:rgba(0,0,0,.7);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-linear-gradient(top,#717171,#232323);background-image:-ms-linear-gradient(top,#717171,#232323);background-image:-o-linear-gradient(top,#717171,#232323);border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333}.qtip-jtools .qtip-titlebar{background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A)"}.qtip-jtools .qtip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323)"}.qtip-jtools .qtip-titlebar,.qtip-jtools .qtip-content{background:transparent;color:#fff;border:0 dashed transparent}.qtip-jtools .qtip-icon{border-color:#555}.qtip-jtools .qtip-titlebar .ui-state-hover{border-color:#333}.qtip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,.4);box-shadow:4px 4px 5px rgba(0,0,0,.4);background-color:#D9D9C2;color:#111;border:0 dashed transparent}.qtip-cluetip .qtip-titlebar{background-color:#87876A;color:#fff;border:0 dashed transparent}.qtip-cluetip .qtip-icon{border-color:#808064}.qtip-cluetip .qtip-titlebar .ui-state-hover{border-color:#696952;color:#696952}.qtip-tipsy{background:#000;background:rgba(0,0,0,.87);color:#fff;border:0 solid transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:700;line-height:16px;text-shadow:0 1px #000}.qtip-tipsy .qtip-titlebar{padding:6px 35px 0 10px;background-color:transparent}.qtip-tipsy .qtip-content{padding:6px 10px}.qtip-tipsy .qtip-icon{border-color:#222;text-shadow:none}.qtip-tipsy .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-tipped{border:3px solid #959FA9;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-color:#F9F9F9;color:#454545;font-weight:400;font-family:serif}.qtip-tipped .qtip-titlebar{border-bottom-width:0;color:#fff;background:#3A79B8;background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));background-image:-webkit-linear-gradient(top,#3A79B8,#2E629D);background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-ms-linear-gradient(top,#3A79B8,#2E629D);background-image:-o-linear-gradient(top,#3A79B8,#2E629D);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D)"}.qtip-tipped .qtip-icon{border:2px solid #285589;background:#285589}.qtip-tipped .qtip-icon .ui-icon{background-color:#FBFBFB;color:#555}.qtip-bootstrap{font-size:14px;line-height:20px;color:#333;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.qtip-bootstrap .qtip-titlebar{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.qtip-bootstrap .qtip-titlebar .qtip-close{right:11px;top:45%;border-style:none}.qtip-bootstrap .qtip-content{padding:9px 14px}.qtip-bootstrap .qtip-icon{background:transparent}.qtip-bootstrap .qtip-icon .ui-icon{width:auto;height:auto;float:right;font-size:20px;font-weight:700;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.qtip-bootstrap .qtip-icon .ui-icon:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.qtip:not(.ie9haxors) div.qtip-content,.qtip:not(.ie9haxors) div.qtip-titlebar{filter:none;-ms-filter:none}.qtip .qtip-tip{margin:0 auto;overflow:hidden;z-index:10}x:-o-prefocus,.qtip .qtip-tip{visibility:hidden}.qtip .qtip-tip,.qtip .qtip-tip .qtip-vml,.qtip .qtip-tip canvas{position:absolute;color:#123456;background:transparent;border:0 dashed transparent}.qtip .qtip-tip canvas{top:0;left:0}.qtip .qtip-tip .qtip-vml{behavior:url(#default#VML);display:inline-block;visibility:visible}#qtip-overlay{position:fixed;left:0;top:0;width:100%;height:100%}#qtip-overlay.blurs{cursor:pointer}#qtip-overlay div{position:absolute;left:0;top:0;width:100%;height:100%;background-color:#000;opacity:.7;filter:alpha(opacity=70);-ms-filter:"alpha(Opacity=70)"} \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.js b/zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.js new file mode 100644 index 0000000..25bf424 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/jquery.qtip.min.js @@ -0,0 +1,5 @@ +/* qTip2 v2.2.0 tips viewport svg modal | qtip2.com | Licensed MIT, GPL | Wed Dec 18 2013 05:02:22 */ + +!function(a,b,c){!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):jQuery&&!jQuery.fn.qtip&&a(jQuery)}(function(d){"use strict";function e(a,b,c,e){this.id=c,this.target=a,this.tooltip=F,this.elements={target:a},this._id=S+"-"+c,this.timers={img:{}},this.options=b,this.plugins={},this.cache={event:{},target:d(),disabled:E,attr:e,onTooltip:E,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=E}function f(a){return a===F||"object"!==d.type(a)}function g(a){return!(d.isFunction(a)||a&&a.attr||a.length||"object"===d.type(a)&&(a.jquery||a.then))}function h(a){var b,c,e,h;return f(a)?E:(f(a.metadata)&&(a.metadata={type:a.metadata}),"content"in a&&(b=a.content,f(b)||b.jquery||b.done?b=a.content={text:c=g(b)?E:b}:c=b.text,"ajax"in b&&(e=b.ajax,h=e&&e.once!==E,delete b.ajax,b.text=function(a,b){var f=c||d(this).attr(b.options.content.attr)||"Loading...",g=d.ajax(d.extend({},e,{context:b})).then(e.success,F,e.error).then(function(a){return a&&h&&b.set("content.text",a),a},function(a,c,d){b.destroyed||0===a.status||b.set("content.text",c+": "+d)});return h?f:(b.set("content.text",f),g)}),"title"in b&&(f(b.title)||(b.button=b.title.button,b.title=b.title.text),g(b.title||E)&&(b.title=E))),"position"in a&&f(a.position)&&(a.position={my:a.position,at:a.position}),"show"in a&&f(a.show)&&(a.show=a.show.jquery?{target:a.show}:a.show===D?{ready:D}:{event:a.show}),"hide"in a&&f(a.hide)&&(a.hide=a.hide.jquery?{target:a.hide}:{event:a.hide}),"style"in a&&f(a.style)&&(a.style={classes:a.style}),d.each(R,function(){this.sanitize&&this.sanitize(a)}),a)}function i(a,b){for(var c,d=0,e=a,f=b.split(".");e=e[f[d++]];)d0?setTimeout(d.proxy(a,this),b):(a.call(this),void 0)}function n(a){return this.tooltip.hasClass(ab)?E:(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=m.call(this,function(){this.toggle(D,a)},this.options.show.delay),void 0)}function o(a){if(this.tooltip.hasClass(ab))return E;var b=d(a.relatedTarget),c=b.closest(W)[0]===this.tooltip[0],e=b[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==b[0]&&"mouse"===this.options.position.target&&c||this.options.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(c||e))try{a.preventDefault(),a.stopImmediatePropagation()}catch(f){}else this.timers.hide=m.call(this,function(){this.toggle(E,a)},this.options.hide.delay,this)}function p(a){return this.tooltip.hasClass(ab)||!this.options.hide.inactive?E:(clearTimeout(this.timers.inactive),this.timers.inactive=m.call(this,function(){this.hide(a)},this.options.hide.inactive),void 0)}function q(a){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(a)}function r(a,c,e){d(b.body).delegate(a,(c.split?c:c.join(hb+" "))+hb,function(){var a=y.api[d.attr(this,U)];a&&!a.disabled&&e.apply(a,arguments)})}function s(a,c,f){var g,i,j,k,l,m=d(b.body),n=a[0]===b?m:a,o=a.metadata?a.metadata(f.metadata):F,p="html5"===f.metadata.type&&o?o[f.metadata.name]:F,q=a.data(f.metadata.name||"qtipopts");try{q="string"==typeof q?d.parseJSON(q):q}catch(r){}if(k=d.extend(D,{},y.defaults,f,"object"==typeof q?h(q):F,h(p||o)),i=k.position,k.id=c,"boolean"==typeof k.content.text){if(j=a.attr(k.content.attr),k.content.attr===E||!j)return E;k.content.text=j}if(i.container.length||(i.container=m),i.target===E&&(i.target=n),k.show.target===E&&(k.show.target=n),k.show.solo===D&&(k.show.solo=i.container.closest("body")),k.hide.target===E&&(k.hide.target=n),k.position.viewport===D&&(k.position.viewport=i.container),i.container=i.container.eq(0),i.at=new A(i.at,D),i.my=new A(i.my),a.data(S))if(k.overwrite)a.qtip("destroy",!0);else if(k.overwrite===E)return E;return a.attr(T,c),k.suppress&&(l=a.attr("title"))&&a.removeAttr("title").attr(cb,l).attr("title",""),g=new e(a,k,c,!!j),a.data(S,g),a.one("remove.qtip-"+c+" removeqtip.qtip-"+c,function(){var a;(a=d(this).data(S))&&a.destroy(!0)}),g}function t(a){return a.charAt(0).toUpperCase()+a.slice(1)}function u(a,b){var d,e,f=b.charAt(0).toUpperCase()+b.slice(1),g=(b+" "+sb.join(f+" ")+f).split(" "),h=0;if(rb[b])return a.css(rb[b]);for(;d=g[h++];)if((e=a.css(d))!==c)return rb[b]=d,e}function v(a,b){return Math.ceil(parseFloat(u(a,b)))}function w(a,b){this._ns="tip",this.options=b,this.offset=b.offset,this.size=[b.width,b.height],this.init(this.qtip=a)}function x(a,b){this.options=b,this._ns="-modal",this.init(this.qtip=a)}var y,z,A,B,C,D=!0,E=!1,F=null,G="x",H="y",I="width",J="height",K="top",L="left",M="bottom",N="right",O="center",P="flipinvert",Q="shift",R={},S="qtip",T="data-hasqtip",U="data-qtip-id",V=["ui-widget","ui-tooltip"],W="."+S,X="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),Y=S+"-fixed",Z=S+"-default",$=S+"-focus",_=S+"-hover",ab=S+"-disabled",bb="_replacedByqTip",cb="oldtitle",db={ie:function(){for(var a=3,c=b.createElement("div");(c.innerHTML="")&&c.getElementsByTagName("i")[0];);return a>4?a:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||E};z=e.prototype,z._when=function(a){return d.when.apply(d,a)},z.render=function(a){if(this.rendered||this.destroyed)return this;var b,c=this,e=this.options,f=this.cache,g=this.elements,h=e.content.text,i=e.content.title,j=e.content.button,k=e.position,l=("."+this._id+" ",[]);return d.attr(this.target[0],"aria-describedby",this._id),this.tooltip=g.tooltip=b=d("
",{id:this._id,"class":[S,Z,e.style.classes,S+"-pos-"+e.position.my.abbrev()].join(" "),width:e.style.width||"",height:e.style.height||"",tracking:"mouse"===k.target&&k.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":E,"aria-describedby":this._id+"-content","aria-hidden":D}).toggleClass(ab,this.disabled).attr(U,this.id).data(S,this).appendTo(k.container).append(g.content=d("
",{"class":S+"-content",id:this._id+"-content","aria-atomic":D})),this.rendered=-1,this.positioning=D,i&&(this._createTitle(),d.isFunction(i)||l.push(this._updateTitle(i,E))),j&&this._createButton(),d.isFunction(h)||l.push(this._updateContent(h,E)),this.rendered=D,this._setWidget(),d.each(R,function(a){var b;"render"===this.initialize&&(b=this(c))&&(c.plugins[a]=b)}),this._unassignEvents(),this._assignEvents(),this._when(l).then(function(){c._trigger("render"),c.positioning=E,c.hiddenDuringWait||!e.show.ready&&!a||c.toggle(D,f.event,E),c.hiddenDuringWait=E}),y.api[this.id]=this,this},z.destroy=function(a){function b(){if(!this.destroyed){this.destroyed=D;var a=this.target,b=a.attr(cb);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),d.each(this.plugins,function(){this.destroy&&this.destroy()}),clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this._unassignEvents(),a.removeData(S).removeAttr(U).removeAttr(T).removeAttr("aria-describedby"),this.options.suppress&&b&&a.attr("title",b).removeAttr(cb),this._unbind(a),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=F,delete y.api[this.id]}}return this.destroyed?this.target:(a===D&&"hide"!==this.triggering||!this.rendered?b.call(this):(this.tooltip.one("tooltiphidden",d.proxy(b,this)),!this.triggering&&this.hide()),this.target)},B=z.checks={builtin:{"^id$":function(a,b,c,e){var f=c===D?y.nextid:c,g=S+"-"+f;f!==E&&f.length>0&&!d("#"+g).length?(this._id=g,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):a[b]=e},"^prerender":function(a,b,c){c&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(a,b,c){this._updateContent(c)},"^content.attr$":function(a,b,c,d){this.options.content.text===this.target.attr(d)&&this._updateContent(this.target.attr(c))},"^content.title$":function(a,b,c){return c?(c&&!this.elements.title&&this._createTitle(),this._updateTitle(c),void 0):this._removeTitle()},"^content.button$":function(a,b,c){this._updateButton(c)},"^content.title.(text|button)$":function(a,b,c){this.set("content."+b,c)},"^position.(my|at)$":function(a,b,c){"string"==typeof c&&(a[b]=new A(c,"at"===b))},"^position.container$":function(a,b,c){this.rendered&&this.tooltip.appendTo(c)},"^show.ready$":function(a,b,c){c&&(!this.rendered&&this.render(D)||this.toggle(D))},"^style.classes$":function(a,b,c,d){this.rendered&&this.tooltip.removeClass(d).addClass(c)},"^style.(width|height)":function(a,b,c){this.rendered&&this.tooltip.css(b,c)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(a,b,c){this.rendered&&this.tooltip.toggleClass(Z,!!c)},"^events.(render|show|move|hide|focus|blur)$":function(a,b,c){this.rendered&&this.tooltip[(d.isFunction(c)?"":"un")+"bind"]("tooltip"+b,c)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var a=this.options.position;this.tooltip.attr("tracking","mouse"===a.target&&a.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},z.get=function(a){if(this.destroyed)return this;var b=i(this.options,a.toLowerCase()),c=b[0][b[1]];return c.precedance?c.string():c};var eb=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,fb=/^prerender|show\.ready/i;z.set=function(a,b){if(this.destroyed)return this;{var c,e=this.rendered,f=E,g=this.options;this.checks}return"string"==typeof a?(c=a,a={},a[c]=b):a=d.extend({},a),d.each(a,function(b,c){if(e&&fb.test(b))return delete a[b],void 0;var h,j=i(g,b.toLowerCase());h=j[0][j[1]],j[0][j[1]]=c&&c.nodeType?d(c):c,f=eb.test(b)||f,a[b]=[j[0],j[1],c,h]}),h(g),this.positioning=D,d.each(a,d.proxy(j,this)),this.positioning=E,this.rendered&&this.tooltip[0].offsetWidth>0&&f&&this.reposition("mouse"===g.position.target?F:this.cache.event),this},z._update=function(a,b){var c=this,e=this.cache;return this.rendered&&a?(d.isFunction(a)&&(a=a.call(this.elements.target,e.event,this)||""),d.isFunction(a.then)?(e.waiting=D,a.then(function(a){return e.waiting=E,c._update(a,b)},F,function(a){return c._update(a,b)})):a===E||!a&&""!==a?E:(a.jquery&&a.length>0?b.empty().append(a.css({display:"block",visibility:"visible"})):b.html(a),this._waitForContent(b).then(function(a){a.images&&a.images.length&&c.rendered&&c.tooltip[0].offsetWidth>0&&c.reposition(e.event,!a.length)}))):E},z._waitForContent=function(a){var b=this.cache;return b.waiting=D,(d.fn.imagesLoaded?a.imagesLoaded():d.Deferred().resolve([])).done(function(){b.waiting=E}).promise()},z._updateContent=function(a,b){this._update(a,this.elements.content,b)},z._updateTitle=function(a,b){this._update(a,this.elements.title,b)===E&&this._removeTitle(E)},z._createTitle=function(){var a=this.elements,b=this._id+"-title";a.titlebar&&this._removeTitle(),a.titlebar=d("
",{"class":S+"-titlebar "+(this.options.style.widget?k("header"):"")}).append(a.title=d("
",{id:b,"class":S+"-title","aria-atomic":D})).insertBefore(a.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(a){d(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(a){d(this).toggleClass("ui-state-hover","mouseover"===a.type)}),this.options.content.button&&this._createButton()},z._removeTitle=function(a){var b=this.elements;b.title&&(b.titlebar.remove(),b.titlebar=b.title=b.button=F,a!==E&&this.reposition())},z.reposition=function(c,e){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=D;var f,g,h=this.cache,i=this.tooltip,j=this.options.position,k=j.target,l=j.my,m=j.at,n=j.viewport,o=j.container,p=j.adjust,q=p.method.split(" "),r=i.outerWidth(E),s=i.outerHeight(E),t=0,u=0,v=i.css("position"),w={left:0,top:0},x=i[0].offsetWidth>0,y=c&&"scroll"===c.type,z=d(a),A=o[0].ownerDocument,B=this.mouse;if(d.isArray(k)&&2===k.length)m={x:L,y:K},w={left:k[0],top:k[1]};else if("mouse"===k)m={x:L,y:K},!B||!B.pageX||!p.mouse&&c&&c.pageX?c&&c.pageX||((!p.mouse||this.options.show.distance)&&h.origin&&h.origin.pageX?c=h.origin:(!c||c&&("resize"===c.type||"scroll"===c.type))&&(c=h.event)):c=B,"static"!==v&&(w=o.offset()),A.body.offsetWidth!==(a.innerWidth||A.documentElement.clientWidth)&&(g=d(b.body).offset()),w={left:c.pageX-w.left+(g&&g.left||0),top:c.pageY-w.top+(g&&g.top||0)},p.mouse&&y&&B&&(w.left-=(B.scrollX||0)-z.scrollLeft(),w.top-=(B.scrollY||0)-z.scrollTop());else{if("event"===k?c&&c.target&&"scroll"!==c.type&&"resize"!==c.type?h.target=d(c.target):c.target||(h.target=this.elements.target):"event"!==k&&(h.target=d(k.jquery?k:this.elements.target)),k=h.target,k=d(k).eq(0),0===k.length)return this;k[0]===b||k[0]===a?(t=db.iOS?a.innerWidth:k.width(),u=db.iOS?a.innerHeight:k.height(),k[0]===a&&(w={top:(n||k).scrollTop(),left:(n||k).scrollLeft()})):R.imagemap&&k.is("area")?f=R.imagemap(this,k,m,R.viewport?q:E):R.svg&&k&&k[0].ownerSVGElement?f=R.svg(this,k,m,R.viewport?q:E):(t=k.outerWidth(E),u=k.outerHeight(E),w=k.offset()),f&&(t=f.width,u=f.height,g=f.offset,w=f.position),w=this.reposition.offset(k,w,o),(db.iOS>3.1&&db.iOS<4.1||db.iOS>=4.3&&db.iOS<4.33||!db.iOS&&"fixed"===v)&&(w.left-=z.scrollLeft(),w.top-=z.scrollTop()),(!f||f&&f.adjustable!==E)&&(w.left+=m.x===N?t:m.x===O?t/2:0,w.top+=m.y===M?u:m.y===O?u/2:0)}return w.left+=p.x+(l.x===N?-r:l.x===O?-r/2:0),w.top+=p.y+(l.y===M?-s:l.y===O?-s/2:0),R.viewport?(w.adjusted=R.viewport(this,w,j,t,u,r,s),g&&w.adjusted.left&&(w.left+=g.left),g&&w.adjusted.top&&(w.top+=g.top)):w.adjusted={left:0,top:0},this._trigger("move",[w,n.elem||n],c)?(delete w.adjusted,e===E||!x||isNaN(w.left)||isNaN(w.top)||"mouse"===k||!d.isFunction(j.effect)?i.css(w):d.isFunction(j.effect)&&(j.effect.call(i,this,d.extend({},w)),i.queue(function(a){d(this).css({opacity:"",height:""}),db.ie&&this.style.removeAttribute("filter"),a()})),this.positioning=E,this):this},z.reposition.offset=function(a,c,e){function f(a,b){c.left+=b*a.scrollLeft(),c.top+=b*a.scrollTop()}if(!e[0])return c;var g,h,i,j,k=d(a[0].ownerDocument),l=!!db.ie&&"CSS1Compat"!==b.compatMode,m=e[0];do"static"!==(h=d.css(m,"position"))&&("fixed"===h?(i=m.getBoundingClientRect(),f(k,-1)):(i=d(m).position(),i.left+=parseFloat(d.css(m,"borderLeftWidth"))||0,i.top+=parseFloat(d.css(m,"borderTopWidth"))||0),c.left-=i.left+(parseFloat(d.css(m,"marginLeft"))||0),c.top-=i.top+(parseFloat(d.css(m,"marginTop"))||0),g||"hidden"===(j=d.css(m,"overflow"))||"visible"===j||(g=d(m)));while(m=m.offsetParent);return g&&(g[0]!==k[0]||l)&&f(g,1),c};var gb=(A=z.reposition.Corner=function(a,b){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,O).toLowerCase(),this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!b;var c=a.charAt(0);this.precedance="t"===c||"b"===c?H:G}).prototype;gb.invert=function(a,b){this[a]=this[a]===L?N:this[a]===N?L:b||this[a]},gb.string=function(){var a=this.x,b=this.y;return a===b?a:this.precedance===H||this.forceY&&"center"!==b?b+" "+a:a+" "+b},gb.abbrev=function(){var a=this.string().split(" ");return a[0].charAt(0)+(a[1]&&a[1].charAt(0)||"")},gb.clone=function(){return new A(this.string(),this.forceY)},z.toggle=function(a,c){var e=this.cache,f=this.options,g=this.tooltip;if(c){if(/over|enter/.test(c.type)&&/out|leave/.test(e.event.type)&&f.show.target.add(c.target).length===f.show.target.length&&g.has(c.relatedTarget).length)return this;e.event=l(c)}if(this.waiting&&!a&&(this.hiddenDuringWait=D),!this.rendered)return a?this.render(1):this;if(this.destroyed||this.disabled)return this;var h,i,j,k=a?"show":"hide",m=this.options[k],n=(this.options[a?"hide":"show"],this.options.position),o=this.options.content,p=this.tooltip.css("width"),q=this.tooltip.is(":visible"),r=a||1===m.target.length,s=!c||m.target.length<2||e.target[0]===c.target;return(typeof a).search("boolean|number")&&(a=!q),h=!g.is(":animated")&&q===a&&s,i=h?F:!!this._trigger(k,[90]),this.destroyed?this:(i!==E&&a&&this.focus(c),!i||h?this:(d.attr(g[0],"aria-hidden",!a),a?(e.origin=l(this.mouse),d.isFunction(o.text)&&this._updateContent(o.text,E),d.isFunction(o.title)&&this._updateTitle(o.title,E),!C&&"mouse"===n.target&&n.adjust.mouse&&(d(b).bind("mousemove."+S,this._storeMouse),C=D),p||g.css("width",g.outerWidth(E)),this.reposition(c,arguments[2]),p||g.css("width",""),m.solo&&("string"==typeof m.solo?d(m.solo):d(W,m.solo)).not(g).not(m.target).qtip("hide",d.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete e.origin,C&&!d(W+'[tracking="true"]:visible',m.solo).not(g).length&&(d(b).unbind("mousemove."+S),C=E),this.blur(c)),j=d.proxy(function(){a?(db.ie&&g[0].style.removeAttribute("filter"),g.css("overflow",""),"string"==typeof m.autofocus&&d(this.options.show.autofocus,g).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):g.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(a?"visible":"hidden")},this),m.effect===E||r===E?(g[k](),j()):d.isFunction(m.effect)?(g.stop(1,1),m.effect.call(g,this),g.queue("fx",function(a){j(),a()})):g.fadeTo(90,a?1:0,j),a&&m.target.trigger("qtip-"+this.id+"-inactive"),this))},z.show=function(a){return this.toggle(D,a)},z.hide=function(a){return this.toggle(E,a)},z.focus=function(a){if(!this.rendered||this.destroyed)return this;var b=d(W),c=this.tooltip,e=parseInt(c[0].style.zIndex,10),f=y.zindex+b.length;return c.hasClass($)||this._trigger("focus",[f],a)&&(e!==f&&(b.each(function(){this.style.zIndex>e&&(this.style.zIndex=this.style.zIndex-1)}),b.filter("."+$).qtip("blur",a)),c.addClass($)[0].style.zIndex=f),this},z.blur=function(a){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass($),this._trigger("blur",[this.tooltip.css("zIndex")],a),this)},z.disable=function(a){return this.destroyed?this:("toggle"===a?a=!(this.rendered?this.tooltip.hasClass(ab):this.disabled):"boolean"!=typeof a&&(a=D),this.rendered&&this.tooltip.toggleClass(ab,a).attr("aria-disabled",a),this.disabled=!!a,this)},z.enable=function(){return this.disable(E)},z._createButton=function(){var a=this,b=this.elements,c=b.tooltip,e=this.options.content.button,f="string"==typeof e,g=f?e:"Close tooltip";b.button&&b.button.remove(),b.button=e.jquery?e:d("",{"class":"qtip-close "+(this.options.style.widget?"":S+"-icon"),title:g,"aria-label":g}).prepend(d("",{"class":"ui-icon ui-icon-close",html:"×"})),b.button.appendTo(b.titlebar||c).attr("role","button").click(function(b){return c.hasClass(ab)||a.hide(b),E})},z._updateButton=function(a){if(!this.rendered)return E;var b=this.elements.button;a?this._createButton():b.remove()},z._setWidget=function(){var a=this.options.style.widget,b=this.elements,c=b.tooltip,d=c.hasClass(ab);c.removeClass(ab),ab=a?"ui-state-disabled":"qtip-disabled",c.toggleClass(ab,d),c.toggleClass("ui-helper-reset "+k(),a).toggleClass(Z,this.options.style.def&&!a),b.content&&b.content.toggleClass(k("content"),a),b.titlebar&&b.titlebar.toggleClass(k("header"),a),b.button&&b.button.toggleClass(S+"-icon",!a)},z._storeMouse=function(a){(this.mouse=l(a)).type="mousemove"},z._bind=function(a,b,c,e,f){var g="."+this._id+(e?"-"+e:"");b.length&&d(a).bind((b.split?b:b.join(g+" "))+g,d.proxy(c,f||this))},z._unbind=function(a,b){d(a).unbind("."+this._id+(b?"-"+b:""))};var hb="."+S;d(function(){r(W,["mouseenter","mouseleave"],function(a){var b="mouseenter"===a.type,c=d(a.currentTarget),e=d(a.relatedTarget||a.target),f=this.options;b?(this.focus(a),c.hasClass(Y)&&!c.hasClass(ab)&&clearTimeout(this.timers.hide)):"mouse"===f.position.target&&f.hide.event&&f.show.target&&!e.closest(f.show.target[0]).length&&this.hide(a),c.toggleClass(_,b)}),r("["+U+"]",X,p)}),z._trigger=function(a,b,c){var e=d.Event("tooltip"+a);return e.originalEvent=c&&d.extend({},c)||this.cache.event||F,this.triggering=a,this.tooltip.trigger(e,[this].concat(b||[])),this.triggering=E,!e.isDefaultPrevented()},z._bindEvents=function(a,b,c,e,f,g){if(e.add(c).length===e.length){var h=[];b=d.map(b,function(b){var c=d.inArray(b,a);return c>-1?(h.push(a.splice(c,1)[0]),void 0):b}),h.length&&this._bind(c,h,function(a){var b=this.rendered?this.tooltip[0].offsetWidth>0:!1;(b?g:f).call(this,a)})}this._bind(c,a,f),this._bind(e,b,g)},z._assignInitialEvents=function(a){function b(a){return this.disabled||this.destroyed?E:(this.cache.event=l(a),this.cache.target=a?d(a.target):[c],clearTimeout(this.timers.show),this.timers.show=m.call(this,function(){this.render("object"==typeof a||e.show.ready)},e.show.delay),void 0)}var e=this.options,f=e.show.target,g=e.hide.target,h=e.show.event?d.trim(""+e.show.event).split(" "):[],i=e.hide.event?d.trim(""+e.hide.event).split(" "):[];/mouse(over|enter)/i.test(e.show.event)&&!/mouse(out|leave)/i.test(e.hide.event)&&i.push("mouseleave"),this._bind(f,"mousemove",function(a){this._storeMouse(a),this.cache.onTarget=D}),this._bindEvents(h,i,f,g,b,function(){clearTimeout(this.timers.show)}),(e.show.ready||e.prerender)&&b.call(this,a)},z._assignEvents=function(){var c=this,e=this.options,f=e.position,g=this.tooltip,h=e.show.target,i=e.hide.target,j=f.container,k=f.viewport,l=d(b),m=(d(b.body),d(a)),r=e.show.event?d.trim(""+e.show.event).split(" "):[],s=e.hide.event?d.trim(""+e.hide.event).split(" "):[];d.each(e.events,function(a,b){c._bind(g,"toggle"===a?["tooltipshow","tooltiphide"]:["tooltip"+a],b,null,g)}),/mouse(out|leave)/i.test(e.hide.event)&&"window"===e.hide.leave&&this._bind(l,["mouseout","blur"],function(a){/select|option/.test(a.target.nodeName)||a.relatedTarget||this.hide(a)}),e.hide.fixed?i=i.add(g.addClass(Y)):/mouse(over|enter)/i.test(e.show.event)&&this._bind(i,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+e.hide.event).indexOf("unfocus")>-1&&this._bind(j.closest("html"),["mousedown","touchstart"],function(a){var b=d(a.target),c=this.rendered&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0,e=b.parents(W).filter(this.tooltip[0]).length>0;b[0]===this.target[0]||b[0]===this.tooltip[0]||e||this.target.has(b[0]).length||!c||this.hide(a)}),"number"==typeof e.hide.inactive&&(this._bind(h,"qtip-"+this.id+"-inactive",p),this._bind(i.add(g),y.inactiveEvents,p,"-inactive")),this._bindEvents(r,s,h,i,n,o),this._bind(h.add(g),"mousemove",function(a){if("number"==typeof e.hide.distance){var b=this.cache.origin||{},c=this.options.hide.distance,d=Math.abs;(d(a.pageX-b.pageX)>=c||d(a.pageY-b.pageY)>=c)&&this.hide(a)}this._storeMouse(a)}),"mouse"===f.target&&f.adjust.mouse&&(e.hide.event&&this._bind(h,["mouseenter","mouseleave"],function(a){this.cache.onTarget="mouseenter"===a.type}),this._bind(l,"mousemove",function(a){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ab)&&this.tooltip[0].offsetWidth>0&&this.reposition(a)})),(f.adjust.resize||k.length)&&this._bind(d.event.special.resize?k:m,"resize",q),f.adjust.scroll&&this._bind(m.add(f.container),"scroll",q)},z._unassignEvents=function(){var c=[this.options.show.target[0],this.options.hide.target[0],this.rendered&&this.tooltip[0],this.options.position.container[0],this.options.position.viewport[0],this.options.position.container.closest("html")[0],a,b];this._unbind(d([]).pushStack(d.grep(c,function(a){return"object"==typeof a})))},y=d.fn.qtip=function(a,b,e){var f=(""+a).toLowerCase(),g=F,i=d.makeArray(arguments).slice(1),j=i[i.length-1],k=this[0]?d.data(this[0],S):F;return!arguments.length&&k||"api"===f?k:"string"==typeof a?(this.each(function(){var a=d.data(this,S);if(!a)return D;if(j&&j.timeStamp&&(a.cache.event=j),!b||"option"!==f&&"options"!==f)a[f]&&a[f].apply(a,i);else{if(e===c&&!d.isPlainObject(b))return g=a.get(b),E;a.set(b,e)}}),g!==F?g:this):"object"!=typeof a&&arguments.length?void 0:(k=h(d.extend(D,{},a)),this.each(function(a){var b,c;return c=d.isArray(k.id)?k.id[a]:k.id,c=!c||c===E||c.length<1||y.api[c]?y.nextid++:c,b=s(d(this),c,k),b===E?D:(y.api[c]=b,d.each(R,function(){"initialize"===this.initialize&&this(b)}),b._assignInitialEvents(j),void 0)}))},d.qtip=e,y.api={},d.each({attr:function(a,b){if(this.length){var c=this[0],e="title",f=d.data(c,"qtip");if(a===e&&f&&"object"==typeof f&&f.options.suppress)return arguments.length<2?d.attr(c,cb):(f&&f.options.content.attr===e&&f.cache.attr&&f.set("content.text",b),this.attr(cb,b))}return d.fn["attr"+bb].apply(this,arguments)},clone:function(a){var b=(d([]),d.fn["clone"+bb].apply(this,arguments));return a||b.filter("["+cb+"]").attr("title",function(){return d.attr(this,cb)}).removeAttr(cb),b}},function(a,b){if(!b||d.fn[a+bb])return D;var c=d.fn[a+bb]=d.fn[a];d.fn[a]=function(){return b.apply(this,arguments)||c.apply(this,arguments)}}),d.ui||(d["cleanData"+bb]=d.cleanData,d.cleanData=function(a){for(var b,c=0;(b=d(a[c])).length;c++)if(b.attr(T))try{b.triggerHandler("removeqtip")}catch(e){}d["cleanData"+bb].apply(this,arguments)}),y.version="2.2.0",y.nextid=0,y.inactiveEvents=X,y.zindex=15e3,y.defaults={prerender:E,id:E,overwrite:D,suppress:D,content:{text:D,attr:"title",title:E,button:E},position:{my:"top left",at:"bottom right",target:E,container:E,viewport:E,adjust:{x:0,y:0,mouse:D,scroll:D,resize:D,method:"flipinvert flipinvert"},effect:function(a,b){d(this).animate(b,{duration:200,queue:E})}},show:{target:E,event:"mouseenter",effect:D,delay:90,solo:E,ready:E,autofocus:E},hide:{target:E,event:"mouseleave",effect:D,delay:0,fixed:E,inactive:E,leave:"window",distance:E},style:{classes:"",widget:E,width:E,height:E,def:D},events:{render:F,move:F,show:F,hide:F,toggle:F,visible:F,hidden:F,focus:F,blur:F}};var ib,jb="margin",kb="border",lb="color",mb="background-color",nb="transparent",ob=" !important",pb=!!b.createElement("canvas").getContext,qb=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,rb={},sb=["Webkit","O","Moz","ms"];if(pb)var tb=a.devicePixelRatio||1,ub=function(){var a=b.createElement("canvas").getContext("2d");return a.backingStorePixelRatio||a.webkitBackingStorePixelRatio||a.mozBackingStorePixelRatio||a.msBackingStorePixelRatio||a.oBackingStorePixelRatio||1}(),vb=tb/ub;else var wb=function(a,b,c){return"'};d.extend(w.prototype,{init:function(a){var b,c;c=this.element=a.elements.tip=d("
",{"class":S+"-tip"}).prependTo(a.tooltip),pb?(b=d("").appendTo(this.element)[0].getContext("2d"),b.lineJoin="miter",b.miterLimit=1e5,b.save()):(b=wb("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(b+b),a._bind(d("*",c).add(c),["click","mousedown"],function(a){a.stopPropagation()},this._ns)),a._bind(a.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(a){var b=this.qtip.elements.titlebar;return b&&(a.y===K||a.y===O&&this.element.position().top+this.size[1]/2+this.options.offsetl&&!qb.test(e[1])&&(e[0]=e[1]),this.border=l=p.border!==D?p.border:l):this.border=l=0,k=this.size=this._calculateSize(b),n.css({width:k[0],height:k[1],lineHeight:k[1]+"px"}),j=b.precedance===H?[s(r.x===L?l:r.x===N?k[0]-q[0]-l:(k[0]-q[0])/2),s(r.y===K?k[1]-q[1]:0)]:[s(r.x===L?k[0]-q[0]:0),s(r.y===K?l:r.y===M?k[1]-q[1]-l:(k[1]-q[1])/2)],pb?(g=o[0].getContext("2d"),g.restore(),g.save(),g.clearRect(0,0,6e3,6e3),h=this._calculateTip(r,q,vb),i=this._calculateTip(r,this.size,vb),o.attr(I,k[0]*vb).attr(J,k[1]*vb),o.css(I,k[0]).css(J,k[1]),this._drawCoords(g,i),g.fillStyle=e[1],g.fill(),g.translate(j[0]*vb,j[1]*vb),this._drawCoords(g,h),g.fillStyle=e[0],g.fill()):(h=this._calculateTip(r),h="m"+h[0]+","+h[1]+" l"+h[2]+","+h[3]+" "+h[4]+","+h[5]+" xe",j[2]=l&&/^(r|b)/i.test(b.string())?8===db.ie?2:1:0,o.css({coordsize:k[0]+l+" "+(k[1]+l),antialias:""+(r.string().indexOf(O)>-1),left:j[0]-j[2]*Number(f===G),top:j[1]-j[2]*Number(f===H),width:k[0]+l,height:k[1]+l}).each(function(a){var b=d(this);b[b.prop?"prop":"attr"]({coordsize:k[0]+l+" "+(k[1]+l),path:h,fillcolor:e[0],filled:!!a,stroked:!a}).toggle(!(!l&&!a)),!a&&b.html(wb("stroke",'weight="'+2*l+'px" color="'+e[1]+'" miterlimit="1000" joinstyle="miter"'))})),a.opera&&setTimeout(function(){m.tip.css({display:"inline-block",visibility:"visible"})},1),c!==E&&this.calculate(b,k)},calculate:function(a,b){if(!this.enabled)return E;var c,e,f=this,g=this.qtip.elements,h=this.element,i=this.options.offset,j=(g.tooltip.hasClass("ui-widget"),{});return a=a||this.corner,c=a.precedance,b=b||this._calculateSize(a),e=[a.x,a.y],c===G&&e.reverse(),d.each(e,function(d,e){var h,k,l;e===O?(h=c===H?L:K,j[h]="50%",j[jb+"-"+h]=-Math.round(b[c===H?0:1]/2)+i):(h=f._parseWidth(a,e,g.tooltip),k=f._parseWidth(a,e,g.content),l=f._parseRadius(a),j[e]=Math.max(-f.border,d?k:i+(l>h?l:-h))) +}),j[a[c]]-=b[c===G?0:1],h.css({margin:"",top:"",bottom:"",left:"",right:""}).css(j),j},reposition:function(a,b,d){function e(a,b,c,d,e){a===Q&&j.precedance===b&&k[d]&&j[c]!==O?j.precedance=j.precedance===G?H:G:a!==Q&&k[d]&&(j[b]=j[b]===O?k[d]>0?d:e:j[b]===d?e:d)}function f(a,b,e){j[a]===O?p[jb+"-"+b]=o[a]=g[jb+"-"+b]-k[b]:(h=g[e]!==c?[k[b],-g[b]]:[-k[b],g[b]],(o[a]=Math.max(h[0],h[1]))>h[0]&&(d[b]-=k[b],o[b]=E),p[g[e]!==c?e:b]=o[a])}if(this.enabled){var g,h,i=b.cache,j=this.corner.clone(),k=d.adjusted,l=b.options.position.adjust.method.split(" "),m=l[0],n=l[1]||l[0],o={left:E,top:E,x:0,y:0},p={};this.corner.fixed!==D&&(e(m,G,H,L,N),e(n,H,G,K,M),j.string()===i.corner.string()||i.cornerTop===k.top&&i.cornerLeft===k.left||this.update(j,E)),g=this.calculate(j),g.right!==c&&(g.left=-g.right),g.bottom!==c&&(g.top=-g.bottom),g.user=this.offset,(o.left=m===Q&&!!k.left)&&f(G,L,N),(o.top=n===Q&&!!k.top)&&f(H,K,M),this.element.css(p).toggle(!(o.x&&o.y||j.x===O&&o.y||j.y===O&&o.x)),d.left-=g.left.charAt?g.user:m!==Q||o.top||!o.left&&!o.top?g.left+this.border:0,d.top-=g.top.charAt?g.user:n!==Q||o.left||!o.left&&!o.top?g.top+this.border:0,i.cornerLeft=k.left,i.cornerTop=k.top,i.corner=j.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),ib=R.tip=function(a){return new w(a,a.options.style.tip)},ib.initialize="render",ib.sanitize=function(a){if(a.style&&"tip"in a.style){var b=a.style.tip;"object"!=typeof b&&(b=a.style.tip={corner:b}),/string|boolean/i.test(typeof b.corner)||(b.corner=D)}},B.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(a){this.size=[a.width,a.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},d.extend(D,y.defaults,{style:{tip:{corner:D,mimic:E,width:6,height:6,border:D,offset:0}}}),R.viewport=function(c,d,e,f,g,h,i){function j(a,b,c,e,f,g,h,i,j){var k=d[f],m=v[a],t=w[a],u=c===Q,x=m===f?j:m===g?-j:-j/2,y=t===f?i:t===g?-i:-i/2,z=r[f]+s[f]-(o?0:n[f]),A=z-k,B=k+j-(h===I?p:q)-z,C=x-(v.precedance===a||m===v[b]?y:0)-(t===O?i/2:0);return u?(C=(m===f?1:-1)*x,d[f]+=A>0?A:B>0?-B:0,d[f]=Math.max(-n[f]+s[f],k-C,Math.min(Math.max(-n[f]+s[f]+(h===I?p:q),k+C),d[f],"center"===m?k-x:1e9))):(e*=c===P?2:0,A>0&&(m!==f||B>0)?(d[f]-=C+e,l.invert(a,f)):B>0&&(m!==g||A>0)&&(d[f]-=(m===O?-C:C)+e,l.invert(a,g)),d[f]B&&(d[f]=k,l=v.clone())),d[f]-k}var k,l,m,n,o,p,q,r,s,t=e.target,u=c.elements.tooltip,v=e.my,w=e.at,x=e.adjust,y=x.method.split(" "),z=y[0],A=y[1]||y[0],B=e.viewport,C=e.container,D=c.cache,F={left:0,top:0};return B.jquery&&t[0]!==a&&t[0]!==b.body&&"none"!==x.method?(n=C.offset()||F,o="static"===C.css("position"),k="fixed"===u.css("position"),p=B[0]===a?B.width():B.outerWidth(E),q=B[0]===a?B.height():B.outerHeight(E),r={left:k?0:B.scrollLeft(),top:k?0:B.scrollTop()},s=B.offset()||F,("shift"!==z||"shift"!==A)&&(l=v.clone()),F={left:"none"!==z?j(G,H,z,x.x,L,N,I,f,h):0,top:"none"!==A?j(H,G,A,x.y,K,M,J,g,i):0},l&&D.lastClass!==(m=S+"-pos-"+l.abbrev())&&u.removeClass(c.cache.lastClass).addClass(c.cache.lastClass=m),F):F},R.polys={polygon:function(a,b){var c,d,e,f={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:E},g=0,h=[],i=1,j=1,k=0,l=0;for(g=a.length;g--;)c=[parseInt(a[--g],10),parseInt(a[g+1],10)],c[0]>f.position.right&&(f.position.right=c[0]),c[0]f.position.bottom&&(f.position.bottom=c[1]),c[1]0&&e>0&&i>0&&j>0;)for(d=Math.floor(d/2),e=Math.floor(e/2),b.x===L?i=d:b.x===N?i=f.width-d:i+=Math.floor(d/2),b.y===K?j=e:b.y===M?j=f.height-e:j+=Math.floor(e/2),g=h.length;g--&&!(h.length<2);)k=h[g][0]-f.position.left,l=h[g][1]-f.position.top,(b.x===L&&k>=i||b.x===N&&i>=k||b.x===O&&(i>k||k>f.width-i)||b.y===K&&l>=j||b.y===M&&j>=l||b.y===O&&(j>l||l>f.height-j))&&h.splice(g,1);f.position={left:h[0][0],top:h[0][1]}}return f},rect:function(a,b,c,d){return{width:Math.abs(c-a),height:Math.abs(d-b),position:{left:Math.min(a,c),top:Math.min(b,d)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(a,b,c,d,e){var f=R.polys._angles[e.abbrev()],g=0===f?0:c*Math.cos(f*Math.PI),h=d*Math.sin(f*Math.PI);return{width:2*c-Math.abs(g),height:2*d-Math.abs(h),position:{left:a+g,top:b+h},adjustable:E}},circle:function(a,b,c,d){return R.polys.ellipse(a,b,c,c,d)}},R.svg=function(a,c,e){for(var f,g,h,i,j,k,l,m,n,o,p,q=d(b),r=c[0],s=d(r.ownerSVGElement),t=1,u=1,v=!0;!r.getBBox;)r=r.parentNode;if(!r.getBBox||!r.parentNode)return E;f=s.attr("width")||s.width()||parseInt(s.css("width"),10),g=s.attr("height")||s.height()||parseInt(s.css("height"),10);var w=(parseInt(c.css("stroke-width"),10)||0)/2;switch(w&&(t+=w/f,u+=w/g),r.nodeName){case"ellipse":case"circle":o=R.polys.ellipse(r.cx.baseVal.value,r.cy.baseVal.value,(r.rx||r.r).baseVal.value+w,(r.ry||r.r).baseVal.value+w,e);break;case"line":case"polygon":case"polyline":for(n=r.points||[{x:r.x1.baseVal.value,y:r.y1.baseVal.value},{x:r.x2.baseVal.value,y:r.y2.baseVal.value}],o=[],m=-1,k=n.numberOfItems||n.length;++mparseInt(h[0].style.zIndex,10),b||e.closest(W)[0]===h[0]||c(e),g=a.target===k[k.length-1]}}var f,g,h,i,j=this,k={};d.extend(j,{init:function(){return i=j.elem=d("
",{id:"qtip-overlay",html:"
",mousedown:function(){return E}}).hide(),d(b.body).bind("focusin"+Ab,e),d(b).bind("keydown"+Ab,function(a){f&&f.options.show.modal.escape&&27===a.keyCode&&f.hide(a)}),i.bind("click"+Ab,function(a){f&&f.options.show.modal.blur&&f.hide(a)}),j},update:function(b){f=b,k=b.options.show.modal.stealfocus!==E?b.tooltip.find("*").filter(function(){return a(this)}):[]},toggle:function(a,e,g){var k=(d(b.body),a.tooltip),l=a.options.show.modal,m=l.effect,n=e?"show":"hide",o=i.is(":visible"),p=d(Ab).filter(":visible:not(:animated)").not(k);return j.update(a),e&&l.stealfocus!==E&&c(d(":focus")),i.toggleClass("blurs",l.blur),e&&i.appendTo(b.body),i.is(":animated")&&o===e&&h!==E||!e&&p.length?j:(i.stop(D,E),d.isFunction(m)?m.call(i,e):m===E?i[n]():i.fadeTo(parseInt(g,10)||90,e?1:0,function(){e||i.hide()}),e||i.queue(function(a){i.css({left:"",top:""}),d(Ab).length||i.detach(),a()}),h=e,f.destroyed&&(f=F),j)}}),j.init()},yb=new yb,d.extend(x.prototype,{init:function(a){var b=a.tooltip;return this.options.on?(a.elements.overlay=yb.elem,b.addClass(zb).css("z-index",y.modal_zindex+d(Ab).length),a._bind(b,["tooltipshow","tooltiphide"],function(a,c,e){var f=a.originalEvent;if(a.target===b[0])if(f&&"tooltiphide"===a.type&&/mouse(leave|enter)/.test(f.type)&&d(f.relatedTarget).closest(yb.elem[0]).length)try{a.preventDefault()}catch(g){}else(!f||f&&"tooltipsolo"!==f.type)&&this.toggle(a,"tooltipshow"===a.type,e)},this._ns,this),a._bind(b,"tooltipfocus",function(a,c){if(!a.isDefaultPrevented()&&a.target===b[0]){var e=d(Ab),f=y.modal_zindex+e.length,g=parseInt(b[0].style.zIndex,10);yb.elem[0].style.zIndex=f-1,e.each(function(){this.style.zIndex>g&&(this.style.zIndex-=1)}),e.filter("."+$).qtip("blur",a.originalEvent),b.addClass($)[0].style.zIndex=f,yb.update(c);try{a.preventDefault()}catch(h){}}},this._ns,this),a._bind(b,"tooltiphide",function(a){a.target===b[0]&&d(Ab).filter(":visible").not(b).last().qtip("focus",a)},this._ns,this),void 0):this},toggle:function(a,b,c){return a&&a.isDefaultPrevented()?this:(yb.toggle(this.qtip,!!b,c),void 0)},destroy:function(){this.qtip.tooltip.removeClass(zb),this.qtip._unbind(this.qtip.tooltip,this._ns),yb.toggle(this.qtip,E),delete this.qtip.elements.overlay}}),xb=R.modal=function(a){return new x(a,a.options.show.modal)},xb.sanitize=function(a){a.show&&("object"!=typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"==typeof a.show.modal.on&&(a.show.modal.on=D))},y.modal_zindex=y.zindex-200,xb.initialize="render",B.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},d.extend(D,y.defaults,{show:{modal:{on:E,effect:D,blur:D,stealfocus:D,escape:D}}})})}(window,document); +//# sourceMappingURL=http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0//var/www/qtip2/build/tmp/tmp-11954vgjofvk/jquery.qtip.min.map \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/display/package.json b/zbf-admin/src/main/resources/static/designer/display/package.json new file mode 100644 index 0000000..29c70e5 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/package.json @@ -0,0 +1,37 @@ +{ + "name": "displaymodel", + "version": "1.0.0", + "dependencies": {}, + "devDependencies": { + "grunt": "0.4.2", + "grunt-autoprefixer": "0.4.0", + "grunt-bower-install": "0.7.0", + "grunt-concurrent": "0.4.1", + "grunt-contrib-clean": "0.5.0", + "grunt-contrib-coffee": "0.7.0", + "grunt-contrib-compass": "0.6.0", + "grunt-contrib-concat": "0.3.0", + "grunt-contrib-connect": "0.5.0", + "grunt-contrib-copy": "0.4.1", + "grunt-contrib-cssmin": "0.7.0", + "grunt-contrib-htmlmin": "0.1.3", + "grunt-contrib-imagemin": "0.3.0", + "grunt-contrib-jshint": "0.7.1", + "grunt-contrib-uglify": "0.2.0", + "grunt-contrib-watch": "0.5.2", + "grunt-google-cdn": "0.2.0", + "grunt-newer": "0.5.4", + "grunt-ng-annotate": "0.5.0", + "grunt-rev": "0.1.0", + "grunt-svgmin": "0.2.0", + "grunt-usemin": "2.0.0", + "jshint-stylish": "0.1.3", + "load-grunt-tasks": "0.2.0", + "time-grunt": "0.2.1", + "grunt-text-replace": "0.3.11", + "grunt-contrib-rename": "0.0.3" + }, + "engines": { + "node": ">=0.8.0" + } +} diff --git a/zbf-admin/src/main/resources/static/designer/display/raphael.min.js b/zbf-admin/src/main/resources/static/designer/display/raphael.min.js new file mode 100644 index 0000000..a901777 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/display/raphael.min.js @@ -0,0 +1 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Raphael=e():t.Raphael=e()}(window,function(){return function(t){var e={};function r(i){if(e[i])return e[i].exports;var n=e[i]={i:i,l:!1,exports:{}};return t[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}return r.m=t,r.c=e,r.d=function(t,e,i){r.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:i})},r.r=function(t){Object.defineProperty(t,"__esModule",{value:!0})},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=4)}([function(t,e,r){var i,n;i=[r(3)],void 0===(n=function(t){function e(i){if(e.is(i,"function"))return r?i():t.on("raphael.DOMload",i);if(e.is(i,T))return e._engine.create[c](e,i.splice(0,3+e.is(i[0],A))).add(i);var n=Array.prototype.slice.call(arguments,0);if(e.is(n[n.length-1],"function")){var a=n.pop();return r?a.call(e._engine.create[c](e,n)):t.on("raphael.DOMload",function(){a.call(e._engine.create[c](e,n))})}return e._engine.create[c](e,arguments)}e.version="2.2.0",e.eve=t;var r,i,n=/[, ]+/,a={circle:1,rect:1,path:1,ellipse:1,text:1,image:1},s=/\{(\d+)\}/g,o="hasOwnProperty",l={doc:document,win:window},h={was:Object.prototype[o].call(l.win,"Raphael"),is:l.win.Raphael},u=function(){this.ca=this.customAttributes={}},c="apply",f="concat",p="ontouchstart"in l.win||l.win.DocumentTouch&&l.doc instanceof DocumentTouch,d="",g=" ",x=String,v="split",y="click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[v](g),m={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},b=x.prototype.toLowerCase,_=Math,w=_.max,k=_.min,B=_.abs,C=_.pow,S=_.PI,A="number",T="array",M=Object.prototype.toString,E=(e._ISURL=/^url\(['"]?(.+?)['"]?\)$/i,/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i),N={NaN:1,Infinity:1,"-Infinity":1},L=/^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/,P=_.round,z=parseFloat,F=parseInt,R=x.prototype.toUpperCase,j=e._availableAttrs={"arrow-end":"none","arrow-start":"none",blur:0,"clip-rect":"0 0 1e9 1e9",cursor:"default",cx:0,cy:0,fill:"#fff","fill-opacity":1,font:'10px "Arial"',"font-family":'"Arial"',"font-size":"10","font-style":"normal","font-weight":400,gradient:0,height:0,href:"http://raphaeljs.com/","letter-spacing":0,opacity:1,path:"M0,0",r:0,rx:0,ry:0,src:"",stroke:"#000","stroke-dasharray":"","stroke-linecap":"butt","stroke-linejoin":"butt","stroke-miterlimit":0,"stroke-opacity":1,"stroke-width":1,target:"_blank","text-anchor":"middle",title:"Raphael",transform:"",width:0,x:0,y:0,class:""},I=e._availableAnimAttrs={blur:A,"clip-rect":"csv",cx:A,cy:A,fill:"colour","fill-opacity":A,"font-size":A,height:A,opacity:A,path:"path",r:A,rx:A,ry:A,stroke:"colour","stroke-opacity":A,"stroke-width":A,transform:"transform",width:A,x:A,y:A},D=/[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/,q={hs:1,rg:1},O=/,?([achlmqrstvxz]),?/gi,V=/([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/gi,Y=/([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/gi,W=/(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/gi,G=(e._radial_gradient=/^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/,{}),H=function(t,e){return z(t)-z(e)},X=function(t){return t},U=e._rectPath=function(t,e,r,i,n){return n?[["M",t+n,e],["l",r-2*n,0],["a",n,n,0,0,1,n,n],["l",0,i-2*n],["a",n,n,0,0,1,-n,n],["l",2*n-r,0],["a",n,n,0,0,1,-n,-n],["l",0,2*n-i],["a",n,n,0,0,1,n,-n],["z"]]:[["M",t,e],["l",r,0],["l",0,i],["l",-r,0],["z"]]},$=function(t,e,r,i){return null==i&&(i=r),[["M",t,e],["m",0,-i],["a",r,i,0,1,1,0,2*i],["a",r,i,0,1,1,0,-2*i],["z"]]},Z=e._getPath={path:function(t){return t.attr("path")},circle:function(t){var e=t.attrs;return $(e.cx,e.cy,e.r)},ellipse:function(t){var e=t.attrs;return $(e.cx,e.cy,e.rx,e.ry)},rect:function(t){var e=t.attrs;return U(e.x,e.y,e.width,e.height,e.r)},image:function(t){var e=t.attrs;return U(e.x,e.y,e.width,e.height)},text:function(t){var e=t._getBBox();return U(e.x,e.y,e.width,e.height)},set:function(t){var e=t._getBBox();return U(e.x,e.y,e.width,e.height)}},Q=e.mapPath=function(t,e){if(!e)return t;var r,i,n,a,s,o,l;for(n=0,s=(t=At(t)).length;n',(J=K.firstChild).style.behavior="url(#default#VML)",!J||"object"!=typeof J.adj)return e.type=d;K=null}function tt(t){if("function"==typeof t||Object(t)!==t)return t;var e=new t.constructor;for(var r in t)t[o](r)&&(e[r]=tt(t[r]));return e}e.svg=!(e.vml="VML"==e.type),e._Paper=u,e.fn=i=u.prototype=e.prototype,e._id=0,e.is=function(t,e){return"finite"==(e=b.call(e))?!N[o](+t):"array"==e?t instanceof Array:"null"==e&&null===t||e==typeof t&&null!==t||"object"==e&&t===Object(t)||"array"==e&&Array.isArray&&Array.isArray(t)||M.call(t).slice(8,-1).toLowerCase()==e},e.angle=function(t,r,i,n,a,s){if(null==a){var o=t-i,l=r-n;return o||l?(180+180*_.atan2(-l,-o)/S+360)%360:0}return e.angle(t,r,a,s)-e.angle(i,n,a,s)},e.rad=function(t){return t%360*S/180},e.deg=function(t){return Math.round(180*t/S%360*1e3)/1e3},e.snapTo=function(t,r,i){if(i=e.is(i,"finite")?i:10,e.is(t,T)){for(var n=t.length;n--;)if(B(t[n]-r)<=i)return t[n]}else{var a=r%(t=+t);if(at-i)return r-a+t}return r};var et,rt;e.createUUID=(et=/[xy]/g,rt=function(t){var e=16*_.random()|0;return("x"==t?e:3&e|8).toString(16)},function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(et,rt).toUpperCase()});e.setWindow=function(r){t("raphael.setWindow",e,l.win,r),l.win=r,l.doc=l.win.document,e._engine.initWin&&e._engine.initWin(l.win)};var it=function(t){if(e.vml){var r,i=/^\s+|\s+$/g;try{var n=new ActiveXObject("htmlfile");n.write(""),n.close(),r=n.body}catch(t){r=createPopup().document.body}var a=r.createTextRange();it=ht(function(t){try{r.style.color=x(t).replace(i,d);var e=a.queryCommandValue("ForeColor");return"#"+("000000"+(e=(255&e)<<16|65280&e|(16711680&e)>>>16).toString(16)).slice(-6)}catch(t){return"none"}})}else{var s=l.doc.createElement("i");s.title="Raphaël Colour Picker",s.style.display="none",l.doc.body.appendChild(s),it=ht(function(t){return s.style.color=t,l.doc.defaultView.getComputedStyle(s,d).getPropertyValue("color")})}return it(t)},nt=function(){return"hsb("+[this.h,this.s,this.b]+")"},at=function(){return"hsl("+[this.h,this.s,this.l]+")"},st=function(){return this.hex},ot=function(t,r,i){if(null==r&&e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t&&(i=t.b,r=t.g,t=t.r),null==r&&e.is(t,"string")){var n=e.getRGB(t);t=n.r,r=n.g,i=n.b}return(t>1||r>1||i>1)&&(t/=255,r/=255,i/=255),[t,r,i]},lt=function(t,r,i,n){var a={r:t*=255,g:r*=255,b:i*=255,hex:e.rgb(t,r,i),toString:st};return e.is(n,"finite")&&(a.opacity=n),a};function ht(t,e,r){return function i(){var n=Array.prototype.slice.call(arguments,0),a=n.join("␀"),s=i.cache=i.cache||{},l=i.count=i.count||[];return s[o](a)?(function(t,e){for(var r=0,i=t.length;r=1e3&&delete s[l.shift()],l.push(a),s[a]=t[c](e,n),r?r(s[a]):s[a])}}e.color=function(t){var r;return e.is(t,"object")&&"h"in t&&"s"in t&&"b"in t?(r=e.hsb2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):e.is(t,"object")&&"h"in t&&"s"in t&&"l"in t?(r=e.hsl2rgb(t),t.r=r.r,t.g=r.g,t.b=r.b,t.hex=r.hex):(e.is(t,"string")&&(t=e.getRGB(t)),e.is(t,"object")&&"r"in t&&"g"in t&&"b"in t?(r=e.rgb2hsl(t),t.h=r.h,t.s=r.s,t.l=r.l,r=e.rgb2hsb(t),t.v=r.b):(t={hex:"none"}).r=t.g=t.b=t.h=t.s=t.v=t.l=-1),t.toString=st,t},e.hsb2rgb=function(t,e,r,i){var n,a,s,o,l;return this.is(t,"object")&&"h"in t&&"s"in t&&"b"in t&&(r=t.b,e=t.s,i=t.o,t=t.h),o=(l=r*e)*(1-B((t=(t*=360)%360/60)%2-1)),n=a=s=r-l,lt(n+=[l,o,0,0,o,l][t=~~t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],i)},e.hsl2rgb=function(t,e,r,i){var n,a,s,o,l;return this.is(t,"object")&&"h"in t&&"s"in t&&"l"in t&&(r=t.l,e=t.s,t=t.h),(t>1||e>1||r>1)&&(t/=360,e/=100,r/=100),t=(t*=360)%360/60,o=(l=2*e*(r<.5?r:1-r))*(1-B(t%2-1)),n=a=s=r-l/2,lt(n+=[l,o,0,0,o,l][t=~~t],a+=[o,l,l,o,0,0][t],s+=[0,0,o,l,l,o][t],i)},e.rgb2hsb=function(t,e,r){var i,n;return t=(r=ot(t,e,r))[0],e=r[1],r=r[2],{h:((0==(n=(i=w(t,e,r))-k(t,e,r))?null:i==t?(e-r)/n:i==e?(r-t)/n+2:(t-e)/n+4)+360)%6*60/360,s:0==n?0:n/i,b:i,toString:nt}},e.rgb2hsl=function(t,e,r){var i,n,a,s;return t=(r=ot(t,e,r))[0],e=r[1],r=r[2],i=((n=w(t,e,r))+(a=k(t,e,r)))/2,{h:((0==(s=n-a)?null:n==t?(e-r)/s:n==e?(r-t)/s+2:(t-e)/s+4)+360)%6*60/360,s:0==s?0:i<.5?s/(2*i):s/(2-2*i),l:i,toString:at}},e._path2string=function(){return this.join(",").replace(O,"$1")};e._preload=function(t,e){var r=l.doc.createElement("img");r.style.cssText="position:absolute;left:-9999em;top:-9999em",r.onload=function(){e.call(this),this.onload=null,l.doc.body.removeChild(this)},r.onerror=function(){l.doc.body.removeChild(this)},l.doc.body.appendChild(r),r.src=t};function ut(){return this.hex}function ct(t,e){for(var r=[],i=0,n=t.length;n-2*!e>i;i+=2){var a=[{x:+t[i-2],y:+t[i-1]},{x:+t[i],y:+t[i+1]},{x:+t[i+2],y:+t[i+3]},{x:+t[i+4],y:+t[i+5]}];e?i?n-4==i?a[3]={x:+t[0],y:+t[1]}:n-2==i&&(a[2]={x:+t[0],y:+t[1]},a[3]={x:+t[2],y:+t[3]}):a[0]={x:+t[n-2],y:+t[n-1]}:n-4==i?a[3]=a[2]:i||(a[0]={x:+t[i],y:+t[i+1]}),r.push(["C",(-a[0].x+6*a[1].x+a[2].x)/6,(-a[0].y+6*a[1].y+a[2].y)/6,(a[1].x+6*a[2].x-a[3].x)/6,(a[1].y+6*a[2].y-a[3].y)/6,a[2].x,a[2].y])}return r}e.getRGB=ht(function(t){if(!t||(t=x(t)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:ut};if("none"==t)return{r:-1,g:-1,b:-1,hex:"none",toString:ut};!q[o](t.toLowerCase().substring(0,2))&&"#"!=t.charAt()&&(t=it(t));var r,i,n,a,s,l,h=t.match(E);return h?(h[2]&&(n=F(h[2].substring(5),16),i=F(h[2].substring(3,5),16),r=F(h[2].substring(1,3),16)),h[3]&&(n=F((s=h[3].charAt(3))+s,16),i=F((s=h[3].charAt(2))+s,16),r=F((s=h[3].charAt(1))+s,16)),h[4]&&(l=h[4][v](D),r=z(l[0]),"%"==l[0].slice(-1)&&(r*=2.55),i=z(l[1]),"%"==l[1].slice(-1)&&(i*=2.55),n=z(l[2]),"%"==l[2].slice(-1)&&(n*=2.55),"rgba"==h[1].toLowerCase().slice(0,4)&&(a=z(l[3])),l[3]&&"%"==l[3].slice(-1)&&(a/=100)),h[5]?(l=h[5][v](D),r=z(l[0]),"%"==l[0].slice(-1)&&(r*=2.55),i=z(l[1]),"%"==l[1].slice(-1)&&(i*=2.55),n=z(l[2]),"%"==l[2].slice(-1)&&(n*=2.55),("deg"==l[0].slice(-3)||"°"==l[0].slice(-1))&&(r/=360),"hsba"==h[1].toLowerCase().slice(0,4)&&(a=z(l[3])),l[3]&&"%"==l[3].slice(-1)&&(a/=100),e.hsb2rgb(r,i,n,a)):h[6]?(l=h[6][v](D),r=z(l[0]),"%"==l[0].slice(-1)&&(r*=2.55),i=z(l[1]),"%"==l[1].slice(-1)&&(i*=2.55),n=z(l[2]),"%"==l[2].slice(-1)&&(n*=2.55),("deg"==l[0].slice(-3)||"°"==l[0].slice(-1))&&(r/=360),"hsla"==h[1].toLowerCase().slice(0,4)&&(a=z(l[3])),l[3]&&"%"==l[3].slice(-1)&&(a/=100),e.hsl2rgb(r,i,n,a)):((h={r:r,g:i,b:n,toString:ut}).hex="#"+(16777216|n|i<<8|r<<16).toString(16).slice(1),e.is(a,"finite")&&(h.opacity=a),h)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:ut}},e),e.hsb=ht(function(t,r,i){return e.hsb2rgb(t,r,i).hex}),e.hsl=ht(function(t,r,i){return e.hsl2rgb(t,r,i).hex}),e.rgb=ht(function(t,e,r){function i(t){return t+.5|0}return"#"+(16777216|i(r)|i(e)<<8|i(t)<<16).toString(16).slice(1)}),e.getColor=function(t){var e=this.getColor.start=this.getColor.start||{h:0,s:1,b:t||.75},r=this.hsb2rgb(e.h,e.s,e.b);return e.h+=.075,e.h>1&&(e.h=0,e.s-=.2,e.s<=0&&(this.getColor.start={h:0,s:1,b:e.b})),r.hex},e.getColor.reset=function(){delete this.start},e.parsePathString=function(t){if(!t)return null;var r=ft(t);if(r.arr)return mt(r.arr);var i={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},n=[];return e.is(t,T)&&e.is(t[0],T)&&(n=mt(t)),n.length||x(t).replace(V,function(t,e,r){var a=[],s=e.toLowerCase();if(r.replace(W,function(t,e){e&&a.push(+e)}),"m"==s&&a.length>2&&(n.push([e][f](a.splice(0,2))),s="l",e="m"==e?"l":"L"),"r"==s)n.push([e][f](a));else for(;a.length>=i[s]&&(n.push([e][f](a.splice(0,i[s]))),i[s]););}),n.toString=e._path2string,r.arr=mt(n),n},e.parseTransformString=ht(function(t){if(!t)return null;var r=[];return e.is(t,T)&&e.is(t[0],T)&&(r=mt(t)),r.length||x(t).replace(Y,function(t,e,i){var n=[];b.call(e);i.replace(W,function(t,e){e&&n.push(+e)}),r.push([e][f](n))}),r.toString=e._path2string,r});var ft=function(t){var e=ft.ps=ft.ps||{};return e[t]?e[t].sleep=100:e[t]={sleep:100},setTimeout(function(){for(var r in e)e[o](r)&&r!=t&&(e[r].sleep--,!e[r].sleep&&delete e[r])}),e[t]};function pt(t,e,r,i,n){return t*(t*(-3*e+9*r-9*i+3*n)+6*e-12*r+6*i)-3*e+3*r}function dt(t,e,r,i,n,a,s,o,l){null==l&&(l=1);for(var h=(l=l>1?1:l<0?0:l)/2,u=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],c=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],f=0,p=0;p<12;p++){var d=h*u[p]+h,g=pt(d,t,r,n,s),x=pt(d,e,i,a,o),v=g*g+x*x;f+=c[p]*_.sqrt(v)}return h*f}function gt(t,e,r,i,n,a,s,o){if(!(w(t,r)w(n,s)||w(e,i)w(a,o))){var l=(t-r)*(a-o)-(e-i)*(n-s);if(l){var h=((t*i-e*r)*(n-s)-(t-r)*(n*o-a*s))/l,u=((t*i-e*r)*(a-o)-(e-i)*(n*o-a*s))/l,c=+h.toFixed(2),f=+u.toFixed(2);if(!(c<+k(t,r).toFixed(2)||c>+w(t,r).toFixed(2)||c<+k(n,s).toFixed(2)||c>+w(n,s).toFixed(2)||f<+k(e,i).toFixed(2)||f>+w(e,i).toFixed(2)||f<+k(a,o).toFixed(2)||f>+w(a,o).toFixed(2)))return{x:h,y:u}}}}function xt(t,r,i){var n=e.bezierBBox(t),a=e.bezierBBox(r);if(!e.isBBoxIntersect(n,a))return i?0:[];for(var s=dt.apply(0,t),o=dt.apply(0,r),l=w(~~(s/5),1),h=w(~~(o/5),1),u=[],c=[],f={},p=i?0:[],d=0;d=0&&A<=1.001&&T>=0&&T<=1.001&&(i?p++:p.push({x:S.x,y:S.y,t1:k(A,1),t2:k(T,1)}))}}return p}function vt(t,r,i){t=e._path2curve(t),r=e._path2curve(r);for(var n,a,s,o,l,h,u,c,f,p,d=i?0:[],g=0,x=t.length;gy||v=t.x&&e<=t.x2&&r>=t.y&&r<=t.y2},e.isBBoxIntersect=function(t,r){var i=e.isPointInsideBBox;return i(r,t.x,t.y)||i(r,t.x2,t.y)||i(r,t.x,t.y2)||i(r,t.x2,t.y2)||i(t,r.x,r.y)||i(t,r.x2,r.y)||i(t,r.x,r.y2)||i(t,r.x2,r.y2)||(t.xr.x||r.xt.x)&&(t.yr.y||r.yt.y)},e.pathIntersection=function(t,e){return vt(t,e)},e.pathIntersectionNumber=function(t,e){return vt(t,e,1)},e.isPointInsidePath=function(t,r,i){var n=e.pathBBox(t);return e.isPointInsideBBox(n,r,i)&&vt(t,[["M",r,i],["H",n.x2+10]],1)%2==1},e._removedFactory=function(e){return function(){t("raphael.log",null,"Raphaël: you are calling to method “"+e+"” of removed object",e)}};var yt=e.pathBBox=function(t){var e=ft(t);if(e.bbox)return tt(e.bbox);if(!t)return{x:0,y:0,width:0,height:0,x2:0,y2:0};for(var r,i=0,n=0,a=[],s=[],o=0,l=(t=At(t)).length;o1&&(r*=m=_.sqrt(m),i*=m);var b=r*r,w=i*i,k=(a==s?-1:1)*_.sqrt(B((b*w-b*y*y-w*x*x)/(b*y*y+w*x*x))),C=k*r*y/i+(t+o)/2,A=k*-i*x/r+(e+l)/2,T=_.asin(((e-A)/i).toFixed(9)),M=_.asin(((l-A)/i).toFixed(9));T=tM&&(T-=2*S),!s&&M>T&&(M-=2*S)}var E=M-T;if(B(E)>c){var N=M,L=o,P=l;M=T+c*(s&&M>T?1:-1),o=C+r*_.cos(M),l=A+i*_.sin(M),d=Bt(o,l,r,i,n,0,s,L,P,[M,N,C,A])}E=M-T;var z=_.cos(T),F=_.sin(T),R=_.cos(M),j=_.sin(M),I=_.tan(E/4),D=4/3*r*I,q=4/3*i*I,O=[t,e],V=[t+D*F,e-q*z],Y=[o+D*j,l-q*R],W=[o,l];if(V[0]=2*O[0]-V[0],V[1]=2*O[1]-V[1],h)return[V,Y,W][f](d);for(var G=[],H=0,X=(d=[V,Y,W][f](d).join()[v](",")).length;H"1e12"&&(p=.5),B(d)>"1e12"&&(d=.5),p>0&&p<1&&(l=Ct(t,e,r,i,n,a,s,o,p),x.push(l.x),g.push(l.y)),d>0&&d<1&&(l=Ct(t,e,r,i,n,a,s,o,d),x.push(l.x),g.push(l.y)),h=a-2*i+e-(o-2*a+i),f=e-i,p=(-(u=2*(i-e)-2*(a-i))+_.sqrt(u*u-4*h*f))/2/h,d=(-u-_.sqrt(u*u-4*h*f))/2/h,B(p)>"1e12"&&(p=.5),B(d)>"1e12"&&(d=.5),p>0&&p<1&&(l=Ct(t,e,r,i,n,a,s,o,p),x.push(l.x),g.push(l.y)),d>0&&d<1&&(l=Ct(t,e,r,i,n,a,s,o,d),x.push(l.x),g.push(l.y)),{min:{x:k[c](0,x),y:k[c](0,g)},max:{x:w[c](0,x),y:w[c](0,g)}}}),At=e._path2curve=ht(function(t,e){var r=!e&&ft(t);if(!e&&r.curve)return mt(r.curve);for(var i=_t(t),n=e&&_t(e),a={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},s={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},o=function(t,e,r){var i,n;if(!t)return["C",e.x,e.y,e.x,e.y,e.x,e.y];switch(!(t[0]in{T:1,Q:1})&&(e.qx=e.qy=null),t[0]){case"M":e.X=t[1],e.Y=t[2];break;case"A":t=["C"][f](Bt[c](0,[e.x,e.y][f](t.slice(1))));break;case"S":"C"==r||"S"==r?(i=2*e.x-e.bx,n=2*e.y-e.by):(i=e.x,n=e.y),t=["C",i,n][f](t.slice(1));break;case"T":"Q"==r||"T"==r?(e.qx=2*e.x-e.qx,e.qy=2*e.y-e.qy):(e.qx=e.x,e.qy=e.y),t=["C"][f](kt(e.x,e.y,e.qx,e.qy,t[1],t[2]));break;case"Q":e.qx=t[1],e.qy=t[2],t=["C"][f](kt(e.x,e.y,t[1],t[2],t[3],t[4]));break;case"L":t=["C"][f](wt(e.x,e.y,t[1],t[2]));break;case"H":t=["C"][f](wt(e.x,e.y,t[1],e.y));break;case"V":t=["C"][f](wt(e.x,e.y,e.x,t[1]));break;case"Z":t=["C"][f](wt(e.x,e.y,e.X,e.Y))}return t},l=function(t,e){if(t[e].length>7){t[e].shift();for(var r=t[e];r.length;)u[e]="A",n&&(p[e]="A"),t.splice(e++,0,["C"][f](r.splice(0,6)));t.splice(e,1),v=w(i.length,n&&n.length||0)}},h=function(t,e,r,a,s){t&&e&&"M"==t[s][0]&&"M"!=e[s][0]&&(e.splice(s,0,["M",a.x,a.y]),r.bx=0,r.by=0,r.x=t[s][1],r.y=t[s][2],v=w(i.length,n&&n.length||0))},u=[],p=[],d="",g="",x=0,v=w(i.length,n&&n.length||0);x.01;)u/=2,h=dt(t,e,r,i,n,a,s,o,c+=(hn){if(r&&!f.start){if(c+=["C"+(u=Xt(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p)).start.x,u.start.y,u.m.x,u.m.y,u.x,u.y],a)return c;f.start=c,c=["M"+u.x,u.y+"C"+u.n.x,u.n.y,u.end.x,u.end.y,l[5],l[6]].join(),p+=h,s=+l[5],o=+l[6];continue}if(!t&&!r)return{x:(u=Xt(s,o,l[1],l[2],l[3],l[4],l[5],l[6],n-p)).x,y:u.y,alpha:u.alpha}}p+=h,s=+l[5],o=+l[6]}c+=l.shift()+l}return f.end=c,(u=t?p:r?f:e.findDotsAtSegment(s,o,l[0],l[1],l[2],l[3],l[4],l[5],1)).alpha&&(u={x:u.x,y:u.y,alpha:u.alpha}),u}},$t=Ut(1),Zt=Ut(),Qt=Ut(0,1);e.getTotalLength=$t,e.getPointAtLength=Zt,e.getSubpath=function(t,e,r){if(this.getTotalLength(t)-r<1e-6)return Qt(t,e).end;var i=Qt(t,r,1);return e?Qt(i,e).end:i},Yt.getTotalLength=function(){var t=this.getPath();if(t)return this.node.getTotalLength?this.node.getTotalLength():$t(t)},Yt.getPointAtLength=function(t){var e=this.getPath();if(e)return Zt(e,t)},Yt.getPath=function(){var t,r=e._getPath[this.type];if("text"!=this.type&&"set"!=this.type)return r&&(t=r(this)),t},Yt.getSubpath=function(t,r){var i=this.getPath();if(i)return e.getSubpath(i,t,r)};var Jt=e.easing_formulas={linear:function(t){return t},"<":function(t){return C(t,1.7)},">":function(t){return C(t,.48)},"<>":function(t){var e=.48-t/1.04,r=_.sqrt(.1734+e*e),i=r-e,n=-r-e,a=C(B(i),1/3)*(i<0?-1:1)+C(B(n),1/3)*(n<0?-1:1)+.5;return 3*(1-a)*a*a+a*a*a},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},elastic:function(t){return t==!!t?t:C(2,-10*t)*_.sin(2*S*(t-.075)/.3)+1},bounce:function(t){var e=7.5625,r=2.75;return t<1/r?e*t*t:t<2/r?e*(t-=1.5/r)*t+.75:t<2.5/r?e*(t-=2.25/r)*t+.9375:e*(t-=2.625/r)*t+.984375}};Jt.easeIn=Jt["ease-in"]=Jt["<"],Jt.easeOut=Jt["ease-out"]=Jt[">"],Jt.easeInOut=Jt["ease-in-out"]=Jt["<>"],Jt["back-in"]=Jt.backIn,Jt["back-out"]=Jt.backOut;var Kt=[],te=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){setTimeout(t,16)},ee=function(){for(var r=+new Date,i=0;i1&&!n.next){for(s in d)d[o](s)&&(y[s]=n.totalOrigin[s]);n.el.attr(y),ae(n.anim,n.el,n.anim.percents[0],null,n.totalOrigin,n.repeat-1)}n.next&&!n.stop&&ae(n.anim,n.el,n.next,null,n.totalOrigin,n.repeat)}}}Kt.length&&te(ee)},re=function(t){return t>255?255:t<0?0:t};function ie(t,e,r,i,n,a){var s=3*e,o=3*(i-e)-s,l=1-s-o,h=3*r,u=3*(n-r)-h,c=1-h-u;function f(t){return((l*t+o)*t+s)*t}return function(t,e){var r=function(t,e){var r,i,n,a,h,u;for(n=t,u=0;u<8;u++){if(a=f(n)-t,B(a)i)return i;for(;ra?r=n:i=n,n=(i-r)/2+r}return n}(t,e);return((c*r+u)*r+h)*r}(t,1/(200*a))}function ne(t,e){var r=[],i={};if(this.ms=e,this.times=1,t){for(var n in t)t[o](n)&&(i[z(n)]=t[n],r.push(z(n)));r.sort(H)}this.anim=i,this.top=r[r.length-1],this.percents=r}function ae(r,i,a,s,l,h){a=z(a);var u,c,p,d,g,y,m=r.ms,b={},_={},w={};if(s)for(B=0,C=Kt.length;Bs*r.top){a=r.percents[B],g=r.percents[B-1]||0,m=m/r.top*(a-g),d=r.percents[B+1],u=r.anim[a];break}s&&i.attr(r.anim[r.percents[B]])}if(u){if(c)c.initstatus=s,c.start=new Date-c.ms*s;else{for(var S in u)if(u[o](S)&&(I[o](S)||i.paper.customAttributes[o](S)))switch(b[S]=i.attr(S),null==b[S]&&(b[S]=j[S]),_[S]=u[S],I[S]){case A:w[S]=(_[S]-b[S])/m;break;case"colour":b[S]=e.getRGB(b[S]);var T=e.getRGB(_[S]);w[S]={r:(T.r-b[S].r)/m,g:(T.g-b[S].g)/m,b:(T.b-b[S].b)/m};break;case"path":var M=At(b[S],_[S]),E=M[1];for(b[S]=M[0],w[S]=[],B=0,C=b[S].length;Bh&&(h=c)}!t[h+="%"].callback&&(t[h].callback=n)}return new ne(t,r)},Yt.animate=function(t,r,i,n){if(this.removed)return n&&n.call(this),this;var a=t instanceof ne?t:e.animation(t,r,i,n);return ae(a,this,a.percents[0],null,this.attr()),this},Yt.setTime=function(t,e){return t&&null!=e&&this.status(t,k(e,t.ms)/t.ms),this},Yt.status=function(t,e){var r,i,n=[],a=0;if(null!=e)return ae(t,this,-1,k(e,1)),this;for(r=Kt.length;a"));var U=H.getBoundingClientRect();A.W=g.w=(U.right-U.left)/100,A.H=g.h=(U.bottom-U.top)/100,A.X=g.x,A.Y=g.y+A.H/2,("x"in l||"y"in l)&&(A.path.v=t.format("m{0},{1}l{2},{1}",a(g.x*y),a(g.y*y),a(g.x*y)+1));for(var $=["x","y","text","font","font-family","font-weight","font-style","font-size"],Z=0,Q=$.length;Z.25&&(r=n.sqrt(.25-o(e-.5,2))*(2*(r>.5)-1)+.5),h=e+c+r),f})).split(/\s*\-\s*/),"linear"==l){var u=a.shift();if(u=-i(u),isNaN(u))return null}var p=t._parseDots(a);if(!p)return null;if(e=e.shape||e.node,p.length){e.removeChild(s),s.on=!0,s.method="none",s.color=p[0].color,s.color2=p[p.length-1].color;for(var d=[],g=0,x=p.length;g')}}catch(t){k=function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},t._engine.initWin(t._g.win),t._engine.create=function(){var e=t._getContainer.apply(0,arguments),r=e.container,i=e.height,n=e.width,a=e.x,s=e.y;if(!r)throw new Error("VML container not found.");var o=new t._Paper,l=o.canvas=t._g.doc.createElement("div"),h=l.style;return a=a||0,s=s||0,n=n||512,i=i||342,o.width=n,o.height=i,n==+n&&(n+="px"),i==+i&&(i+="px"),o.coordsize=216e5+c+216e5,o.coordorigin="0 0",o.span=t._g.doc.createElement("span"),o.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",l.appendChild(o.span),h.cssText=t.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",n,i),1==r?(t._g.doc.body.appendChild(l),h.left=a+"px",h.top=s+"px",h.position="absolute"):r.firstChild?r.insertBefore(l,r.firstChild):r.appendChild(l),o.renderfix=function(){},o},t.prototype.clear=function(){t.eve("raphael.clear",this),this.canvas.innerHTML=f,this.span=t._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},t.prototype.remove=function(){for(var e in t.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas),this)this[e]="function"==typeof this[e]?t._removedFactory(e):null;return!0};var M=t.st;for(var E in T)T[e](E)&&!M[e](E)&&(M[E]=function(t){return function(){var e=arguments;return this.forEach(function(r){r[t].apply(r,e)})}}(E))}}.apply(e,i))||(t.exports=n)},function(t,e,r){var i,n;i=[r(0)],void 0===(n=function(t){if(!t||t.svg){var e="hasOwnProperty",r=String,i=parseFloat,n=parseInt,a=Math,s=a.max,o=a.abs,l=a.pow,h=/[, ]+/,u=t.eve,c="",f=" ",p="http://www.w3.org/1999/xlink",d={block:"M5,0 0,2.5 5,5z",classic:"M5,0 0,2.5 5,5 3.5,3 3.5,2z",diamond:"M2.5,0 5,2.5 2.5,5 0,2.5z",open:"M6,1 1,3.5 6,6",oval:"M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"},g={};t.toString=function(){return"Your browser supports SVG.\nYou are running Raphaël "+this.version};var x=function(i,n){if(n)for(var a in"string"==typeof i&&(i=x(i)),n)n[e](a)&&("xlink:"==a.substring(0,6)?i.setAttributeNS(p,a.substring(6),r(n[a])):i.setAttribute(a,r(n[a])));else(i=t._g.doc.createElementNS("http://www.w3.org/2000/svg",i)).style&&(i.style.webkitTapHighlightColor="rgba(0,0,0,0)");return i},v=function(e,n){var h="linear",u=e.id+n,f=.5,p=.5,d=e.node,g=e.paper,v=d.style,m=t._g.doc.getElementById(u);if(!m){if(n=(n=r(n).replace(t._radial_gradient,function(t,e,r){if(h="radial",e&&r){f=i(e);var n=2*((p=i(r))>.5)-1;l(f-.5,2)+l(p-.5,2)>.25&&(p=a.sqrt(.25-l(f-.5,2))*n+.5)&&.5!=p&&(p=p.toFixed(5)-1e-5*n)}return c})).split(/\s*\-\s*/),"linear"==h){var b=n.shift();if(b=-i(b),isNaN(b))return null;var _=[0,0,a.cos(t.rad(b)),a.sin(t.rad(b))],w=1/(s(o(_[2]),o(_[3]))||1);_[2]*=w,_[3]*=w,_[2]<0&&(_[0]=-_[2],_[2]=0),_[3]<0&&(_[1]=-_[3],_[3]=0)}var k=t._parseDots(n);if(!k)return null;if(u=u.replace(/[\(\)\s,\xb0#]/g,"_"),e.gradient&&u!=e.gradient.id&&(g.defs.removeChild(e.gradient),delete e.gradient),!e.gradient){m=x(h+"Gradient",{id:u}),e.gradient=m,x(m,"radial"==h?{fx:f,fy:p}:{x1:_[0],y1:_[1],x2:_[2],y2:_[3],gradientTransform:e.matrix.invert()}),g.defs.appendChild(m);for(var B=0,C=k.length;B1?P.opacity/100:P.opacity});case"stroke":P=t.getRGB(g),l.setAttribute(d,P.hex),"stroke"==d&&P[e]("opacity")&&x(l,{"stroke-opacity":P.opacity>1?P.opacity/100:P.opacity}),"stroke"==d&&i._.arrows&&("startString"in i._.arrows&&b(i,i._.arrows.startString),"endString"in i._.arrows&&b(i,i._.arrows.endString,1));break;case"gradient":("circle"==i.type||"ellipse"==i.type||"r"!=r(g).charAt())&&v(i,g);break;case"opacity":u.gradient&&!u[e]("stroke-opacity")&&x(l,{"stroke-opacity":g>1?g/100:g});case"fill-opacity":if(u.gradient){(z=t._g.doc.getElementById(l.getAttribute("fill").replace(/^url\(#|\)$/g,c)))&&(F=z.getElementsByTagName("stop"),x(F[F.length-1],{"stop-opacity":g}));break}default:"font-size"==d&&(g=n(g,10)+"px");var R=d.replace(/(\-.)/g,function(t){return t.substring(1).toUpperCase()});l.style[R]=g,i._.dirty=1,l.setAttribute(d,g)}}B(i,a),l.style.visibility=f},B=function(i,a){if("text"==i.type&&(a[e]("text")||a[e]("font")||a[e]("font-size")||a[e]("x")||a[e]("y"))){var s=i.attrs,o=i.node,l=o.firstChild?n(t._g.doc.defaultView.getComputedStyle(o.firstChild,c).getPropertyValue("font-size"),10):10;if(a[e]("text")){for(s.text=a.text;o.firstChild;)o.removeChild(o.firstChild);for(var h,u=r(a.text).split("\n"),f=[],p=0,d=u.length;p1)for(var i=0,n=r.length;i 0) { + for (var i = 0; i < $scope.assignment.idm.candidateUsers.length; i++) { + $scope.popup.assignmentObject.idm.candidateUsers.push($scope.assignment.idm.candidateUsers[i]); + } + } + + if ($scope.assignment.idm.candidateGroups && $scope.assignment.idm.candidateGroups.length > 0) { + for (var i = 0; i < $scope.assignment.idm.candidateGroups.length; i++) { + $scope.popup.assignmentObject.idm.candidateGroups.push($scope.assignment.idm.candidateGroups[i]); + } + } + } + } + + //fill the static area + if ($scope.assignment.assignee) { + $scope.popup.assignmentObject.static.assignee = $scope.assignment.assignee; + } + + if ($scope.assignment.candidateUsers && $scope.assignment.candidateUsers.length > 0) { + for (var i = 0; i < $scope.assignment.candidateUsers.length; i++) { + $scope.popup.assignmentObject.static.candidateUsers.push($scope.assignment.candidateUsers[i]); + } + } + + if ($scope.assignment.candidateGroups && $scope.assignment.candidateGroups.length > 0) { + for (var i = 0; i < $scope.assignment.candidateGroups.length; i++) { + $scope.popup.assignmentObject.static.candidateGroups.push($scope.assignment.candidateGroups[i]); + } + } + + initStaticContextForEditing($scope); + + $scope.$watch('popup.groupFilter', function () { + $scope.updateGroupFilter(); + }); + + $scope.$watch('popup.filter', function() { + $scope.updateFilter(); + }); + + $scope.updateFilter = function() { + if ($scope.popup.oldFilter == undefined || $scope.popup.oldFilter != $scope.popup.filter) { + if (!$scope.popup.filter) { + $scope.popup.oldFilter = ''; + } else { + $scope.popup.oldFilter = $scope.popup.filter; + } + + if ($scope.popup.filter !== null && $scope.popup.filter !== undefined) { + UserService.getFilteredUsers($scope.popup.filter).then(function (result) { + var filteredUsers = []; + for (var i=0; i= 0 && $scope.popup.selectedIndex < users.length) { + user = users[$scope.popup.selectedIndex]; + } + } + + if (user) { + if ("user" == $scope.assignmentOption.id) { + $scope.popup.assignmentObject.idm.assignee = user; + } else if ("users" == $scope.assignmentOption.id) { + + // Only add if not yet part of candidate users + var found = false; + if ($scope.popup.assignmentObject.idm.candidateUsers) { + for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateUsers.length; i++) { + if ($scope.popup.assignmentObject.idm.candidateUsers[i].id === user.id) { + found = true; + break; + } + } + } + + if (!found) { + $scope.addCandidateUser(user); + } + } + } + }; + + $scope.confirmEmail = function() { + if ("user" == $scope.assignmentOption.id) { + $scope.popup.assignmentObject.idm.assignee = {email: $scope.popup.email}; + } else if ("users" == $scope.assignmentOption.id) { + + // Only add if not yet part of candidate users + var found = false; + if ($scope.popup.assignmentObject.idm.candidateUsers) { + for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateUsers.length; i++) { + + if ($scope.popup.assignmentObject.idm.candidateUsers[i].id) { + if ($scope.popup.assignmentObject.idm.candidateUsers[i].id === user.id) { + found = true; + break; + } + } else if ($scope.popup.assignmentObject.idm.candidateUsers[i].email) { + if ($scope.popup.assignmentObject.idm.candidateUsers[i].email === $scope.popup.email) { + found = true; + break; + } + } + } + } + + if (!found) { + $scope.addCandidateUser({email: $scope.popup.email}); + } + } + }; + + $scope.confirmGroup = function(group) { + if (!group) { + // Selection is done with keyboard, use selection index + var groups = $scope.popup.groupResults; + if ($scope.popup.selectedGroupIndex >= 0 && $scope.popup.selectedGroupIndex < groups.length) { + group = groups[$scope.popup.selectedGroupIndex]; + } + } + + if (group) { + // Only add if not yet part of candidate groups + var found = false; + if ($scope.popup.assignmentObject.idm.candidateGroups) { + for (var i = 0; i < $scope.popup.assignmentObject.idm.candidateGroups.length; i++) { + if ($scope.popup.assignmentObject.idm.candidateGroups[i].id === group.id) { + found = true; + break; + } + } + } + + if (!found) { + $scope.addCandidateGroup(group); + } + } + }; + + $scope.addCandidateUser = function(user) { + $scope.popup.assignmentObject.idm.candidateUsers.push(user); + }; + + $scope.removeCandidateUser = function(user) { + var users = $scope.popup.assignmentObject.idm.candidateUsers; + var indexToRemove = -1; + for (var i = 0; i < users.length; i++) { + if (user.id) { + if (user.id === users[i].id) { + indexToRemove = i; + break; + } + } else { + if (user.email === users[i].email) { + indexToRemove = i; + break; + } + } + } + if (indexToRemove >= 0) { + users.splice(indexToRemove, 1); + } + }; + + $scope.addCandidateGroup = function(group) { + $scope.popup.assignmentObject.idm.candidateGroups.push(group); + }; + + $scope.removeCandidateGroup = function(group) { + var groups = $scope.popup.assignmentObject.idm.candidateGroups; + var indexToRemove = -1; + for (var i = 0; i < groups.length; i++) { + if (group.id == groups[i].id) { + indexToRemove = i; + break; + } + } + if (indexToRemove >= 0) { + groups.splice(indexToRemove, 1); + } + }; + + $scope.resetSelection = function() { + if ($scope.popup.userResults && $scope.popup.userResults.length > 0) { + $scope.popup.selectedIndex = 0; + } else { + $scope.popup.selectedIndex = -1; + } + }; + + $scope.nextUser = function() { + var users = $scope.popup.userResults; + if (users && users.length > 0 && $scope.popup.selectedIndex < users.length -1) { + $scope.popup.selectedIndex += 1; + } + }; + + $scope.previousUser = function() { + var users = $scope.popup.userResults; + if (users && users.length > 0 && $scope.popup.selectedIndex > 0) { + $scope.popup.selectedIndex -= 1; + } + }; + + $scope.resetGroupSelection = function() { + if ($scope.popup.groupResults && $scope.popup.groupResults.length > 0) { + $scope.popup.selectedGroupIndex = 0; + } else { + $scope.popup.selectedGroupIndex = -1; + } + }; + + $scope.nextGroup = function() { + var groups = $scope.popup.groupResults; + if (groups && groups.length > 0 && $scope.popup.selectedGroupIndex < groups.length -1) { + $scope.popup.selectedGroupIndex += 1; + } + }; + + $scope.previousGroup = function() { + var groups = $scope.popup.groupResults; + if (groups && groups.length > 0 && $scope.popup.selectedGroupIndex > 0) { + $scope.popup.selectedGroupIndex -= 1; + } + }; + + $scope.removeAssignee = function() { + $scope.popup.assignmentObject.idm.assignee = undefined; + }; + + // Click handler for + button after enum value + $scope.addCandidateUserValue = function(index) { + $scope.popup.assignmentObject.static.candidateUsers.splice(index + 1, 0, {value: ''}); + }; + + // Click handler for - button after enum value + $scope.removeCandidateUserValue = function(index) { + $scope.popup.assignmentObject.static.candidateUsers.splice(index, 1); + }; + + // Click handler for + button after enum value + $scope.addCandidateGroupValue = function(index) { + $scope.popup.assignmentObject.static.candidateGroups.splice(index + 1, 0, {value: ''}); + }; + + // Click handler for - button after enum value + $scope.removeCandidateGroupValue = function(index) { + $scope.popup.assignmentObject.static.candidateGroups.splice(index, 1); + }; + + $scope.setSearchType = function() { + $scope.popup.assignmentObject.assignmentSourceType = 'search'; + }; + + $scope.allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $scope.save = function () { + + handleAssignmentInput($scope.popup.assignmentObject.static); + + $scope.assignment.type = $scope.popup.assignmentObject.type; + + if ('idm' === $scope.popup.assignmentObject.type) { // IDM + $scope.popup.assignmentObject.static = undefined; + + //Construct an IDM object to be saved to the process model. + var idm = {type: $scope.assignmentOption.id}; + if ('user' == idm.type) { + if ($scope.popup.assignmentObject.idm.assignee) { + idm.assignee = $scope.popup.assignmentObject.idm.assignee; + } + } else if ('users' == idm.type) { + if ($scope.popup.assignmentObject.idm.candidateUsers && $scope.popup.assignmentObject.idm.candidateUsers.length > 0) { + idm.candidateUsers = $scope.popup.assignmentObject.idm.candidateUsers; + } + } else if ('groups' == idm.type) { + if ($scope.popup.assignmentObject.idm.candidateGroups && $scope.popup.assignmentObject.idm.candidateGroups.length > 0) { + idm.candidateGroups = $scope.popup.assignmentObject.idm.candidateGroups; + } + } + $scope.assignment.idm = idm; + $scope.assignment.assignee = undefined; + $scope.assignment.candidateUsers = undefined; + $scope.assignment.candidateGroups = undefined; + + } + + if ('static' === $scope.popup.assignmentObject.type) { // IDM + $scope.popup.assignmentObject.idm = undefined; + $scope.assignment.idm = undefined; + $scope.assignment.assignee = $scope.popup.assignmentObject.static.assignee; + $scope.assignment.candidateUsers = $scope.popup.assignmentObject.static.candidateUsers; + $scope.assignment.candidateGroups = $scope.popup.assignmentObject.static.candidateGroups; + } + + $scope.property.value = {}; + $scope.property.value.assignment = $scope.assignment; + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + var handleAssignmentInput = function ($assignment) { + + function isEmptyString(value) { + return (value === undefined || value === null || value.trim().length === 0); + } + + if (isEmptyString($assignment.assignee)){ + $assignment.assignee = undefined; + } + var toRemoveIndexes; + var removedItems=0; + var i = 0; + if ($assignment.candidateUsers) { + toRemoveIndexes = []; + for (i = 0; i < $assignment.candidateUsers.length; i++) { + if (isEmptyString($assignment.candidateUsers[i].value)) { + toRemoveIndexes[toRemoveIndexes.length] = i; + } + } + + if (toRemoveIndexes.length == $assignment.candidateUsers.length) { + $assignment.candidateUsers = undefined; + } else { + removedItems=0; + for (i = 0; i < toRemoveIndexes.length; i++) { + $assignment.candidateUsers.splice(toRemoveIndexes[i]-removedItems, 1); + removedItems++; + } + } + } + + if ($assignment.candidateGroups) { + toRemoveIndexes = []; + for (i = 0; i < $assignment.candidateGroups.length; i++) { + if (isEmptyString($assignment.candidateGroups[i].value)) { + toRemoveIndexes[toRemoveIndexes.length] = i; + } + } + + if (toRemoveIndexes.length == $assignment.candidateGroups.length) { + $assignment.candidateGroups = undefined; + } else { + removedItems=0; + for (i = 0; i < toRemoveIndexes.length; i++) { + $assignment.candidateGroups.splice(toRemoveIndexes[i]-removedItems, 1); + removedItems++; + } + } + } + }; + + function initStaticContextForEditing($scope) { + if (!$scope.popup.assignmentObject.static.candidateUsers || $scope.popup.assignmentObject.static.candidateUsers.length==0) { + $scope.popup.assignmentObject.static.candidateUsers = [{value: ''}]; + } + if (!$scope.popup.assignmentObject.static.candidateGroups || $scope.popup.assignmentObject.static.candidateGroups.length==0) { + $scope.popup.assignmentObject.static.candidateGroups = [{value: ''}]; + } + } +}]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-calledelementtype-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-calledelementtype-controller.js new file mode 100644 index 0000000..c07775c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-calledelementtype-controller.js @@ -0,0 +1,28 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Call activity calledElement type property + */ + +angular.module('flowableModeler').controller('FlowableCalledElementTypeCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'key'; + } + + $scope.calledElementTypeChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-case-reference-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-case-reference-controller.js new file mode 100644 index 0000000..1f3d02e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-case-reference-controller.js @@ -0,0 +1,80 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableCaseReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/case-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableCaseReferencePopupCtrl', [ '$scope', '$http', 'editorManager', function($scope, $http, editorManager) { + + $scope.state = {'loadingCases' : true, 'error' : false}; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a case + $scope.selectCase = function(caseModel, $event) { + $event.stopPropagation(); + if ($scope.selectedCase && $scope.selectedCase.id && caseModel.id == $scope.selectedCase.id) { + // un-select the current selection + $scope.selectedCase = null; + } else { + $scope.selectedCase = caseModel; + } + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedCase) { + $scope.property.value = {'id' : $scope.selectedCase.id, 'name' : $scope.selectedCase.name}; + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.loadCases = function() { + var modelMetaData = editorManager.getBaseModelData(); + $http.get(FLOWABLE.APP_URL.getCaseModelsUrl('?excludeId=' + modelMetaData.modelId)) + .success( + function(response) { + $scope.state.loadingCases = false; + $scope.state.caseError = false; + $scope.caseModels = response.data; + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingCases = false; + $scope.state.caseError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedCase = $scope.property.value; + } + + $scope.loadCases(); +}]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-condition-expression-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-condition-expression-controller.js new file mode 100644 index 0000000..0ef677e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-condition-expression-controller.js @@ -0,0 +1,59 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Condition expression + */ + +angular.module('flowableModeler').controller('FlowableConditionExpressionCtrl', [ '$scope', '$modal', function($scope, $modal) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/condition-expression-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableConditionExpressionPopupCtrl', + [ '$rootScope', '$scope', '$translate', 'FormBuilderService', function($rootScope, $scope, $translate, FormBuilderService) { + + // Put json representing assignment on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.expression !== undefined + && $scope.property.value.expression !== null) { + + $scope.expression = $scope.property.value.expression; + + } else if ($scope.property.value !== undefined && $scope.property.value !== null) { + $scope.expression = {type: 'static', staticValue: $scope.property.value}; + + } else { + $scope.expression = {}; + } + + $scope.save = function() { + $scope.property.value = {expression: $scope.expression}; + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-custom-controllers.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-custom-controllers.js new file mode 100644 index 0000000..72ac304 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-custom-controllers.js @@ -0,0 +1,12 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-data-properties-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-data-properties-controller.js new file mode 100644 index 0000000..547bd30 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-data-properties-controller.js @@ -0,0 +1,330 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Data Properties + */ + +angular.module('flowableModeler').controller('FlowableDataPropertiesCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/data-properties-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableDataPropertiesPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing data properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.items !== undefined + && $scope.property.value.items !== null) { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.dataProperties = angular.copy($scope.property.value.items); + + for (var i = 0; i < $scope.dataProperties.length; i++) { + var dataProperty = $scope.dataProperties[i]; + if (dataProperty.enumValues && dataProperty.enumValues.length > 0) { + for (var j = 0; j < dataProperty.enumValues.length; j++) { + var enumValue = dataProperty.enumValues[j]; + if (!enumValue.id && !enumValue.name && enumValue.value) { + enumValue.id = enumValue.value; + enumValue.name = enumValue.value; + } + } + } + } + + } else { + $scope.dataProperties = []; + } + + $scope.enumValues = []; + + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var idPromise = $translate('PROPERTY.DATAPROPERTIES.ID'); + var namePromise = $translate('PROPERTY.DATAPROPERTIES.NAME'); + var typePromise = $translate('PROPERTY.DATAPROPERTIES.TYPE'); + var valuePromise = $translate('PROPERTY.DATAPROPERTIES.VALUE'); + + $q.all([idPromise, namePromise, typePromise, valuePromise]).then(function (results) { + $scope.labels.idLabel = results[0]; + $scope.labels.nameLabel = results[1]; + $scope.labels.typeLabel = results[2]; + $scope.labels.valueLabel = results[3]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.dataProperties, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'dataproperty_id', displayName: $scope.labels.idLabel}, + {field: 'dataproperty_name', displayName: $scope.labels.nameLabel}, + {field: 'dataproperty_type', displayName: $scope.labels.typeLabel}, + {field: 'dataproperty_value', displayName: $scope.labels.valueLabel}] + }; + + $scope.enumGridOptions = { + data: $scope.enumValues, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel }, + { field: 'name', displayName: $scope.labels.nameLabel}] + } + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedProperty = row.entity; + $scope.selectedEnumValue = undefined; + if ($scope.selectedProperty && $scope.selectedProperty.enumValues) { + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + } + }); + }; + + $scope.enumGridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.enumGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedEnumValue = row.entity; + }); + }; + }); + + // Handler for when the value of the type dropdown changes + $scope.propertyTypeChanged = function () { + + // Check date. If date, show date pattern + if ($scope.selectedProperty.type === 'date') { + $scope.selectedProperty.datePattern = 'MM-dd-yyyy hh:mm'; + } else { + delete $scope.selectedProperty.datePattern; + } + + // Check enum. If enum, show list of options + if ($scope.selectedProperty.type === 'enum') { + $scope.selectedProperty.enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}]; + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + + } else { + delete $scope.selectedProperty.enumValues; + $scope.enumValues.length = 0; + } + }; + + // Click handler for add button + var propertyIndex = 1; + $scope.addNewProperty = function () { + var newProperty = { + dataproperty_id: 'new_data_object_' + propertyIndex++, + dataproperty_name: '', + dataproperty_type: 'string', + readable: true, + writable: true + }; + + $scope.dataProperties.push(newProperty); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newProperty); + }); + }; + + // Click handler for remove button + $scope.removeProperty = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.dataProperties.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.dataProperties.splice(index, 1); + + if ($scope.dataProperties.length == 0) { + $scope.selectedProperty = undefined; + } + + $timeout(function() { + if ($scope.dataProperties.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.dataProperties[0]); + } + }); + } + }; + + // Click handler for up button + $scope.movePropertyUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.dataProperties.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.dataProperties[index]; + $scope.dataProperties.splice(index, 1); + $timeout(function(){ + $scope.dataProperties.splice(index + -1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.movePropertyDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.dataProperties.indexOf(selectedItems[0]); + if (index != $scope.dataProperties.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.dataProperties[index]; + $scope.dataProperties.splice(index, 1); + $timeout(function(){ + $scope.dataProperties.splice(index + 1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + $scope.addNewEnumValue = function() { + if ($scope.selectedProperty) { + var newEnumValue = { id : '', name : ''}; + $scope.selectedProperty.enumValues.push(newEnumValue); + $scope.enumValues.push(newEnumValue); + + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(newEnumValue); + }); + } + }; + + // Click handler for remove button + $scope.removeEnumValue = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + $scope.enumGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + + if ($scope.enumValues.length == 0) { + $scope.selectedEnumValue = undefined; + } + + $timeout(function () { + if ($scope.enumValues.length > 0) { + $scope.enumGridApi.selection.toggleRowSelection($scope.enumValues[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveEnumValueUp = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + -1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + -1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveEnumValueDown = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != $scope.enumValues.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + 1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + 1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.dataProperties.length > 0) { + $scope.property.value = {}; + $scope.property.value.items = $scope.dataProperties; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.$hide(); + $scope.property.mode = 'read'; + }; + + // Close button handler + $scope.close = function () { + $scope.$hide(); + $scope.property.mode = 'read'; + }; + + }]) +; \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-decisiontable-reference-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-decisiontable-reference-controller.js new file mode 100644 index 0000000..a2b697c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-decisiontable-reference-controller.js @@ -0,0 +1,288 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableDecisionTableReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/decisiontable-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableDecisionTableReferencePopupCtrl', ['$rootScope', '$scope', '$http', '$location', 'editorManager', + function($rootScope, $scope, $http, $location, editorManager) { + + $scope.state = { + 'loadingDecisionTables': true, + 'decisionTableError': false + }; + + $scope.popup = { + 'state': 'decisionTableReference' + }; + + $scope.foldersBreadCrumbs = []; + + // Make click outside dialog also call close. + $scope.$parent.$on('modal.hide.before', function() { + $scope.close(); + $scope.$parent.$apply(); + }); + + // Close button handler + $scope.close = function() { + $scope.property.newVariablesMapping = undefined; + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a decision table + $scope.selectDecisionTable = function(decisionTable, $event) { + $event.stopPropagation(); + if ($scope.selectedDecisionTable && $scope.selectedDecisionTable.id && decisionTable.id == $scope.selectedDecisionTable.id) { + // un-select the current selection + $scope.selectedDecisionTable = null; + } else { + $scope.selectedDecisionTable = decisionTable; + } + }; + + $scope.isSelected = function () { + if ($scope.selectedDecisionTable && $scope.selectedDecisionTable.id) { + return true; + } + return false; + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedDecisionTable) { + $scope.property.value = { + 'id': $scope.selectedDecisionTable.id, + 'name': $scope.selectedDecisionTable.name, + 'key': $scope.selectedDecisionTable.key + }; + + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Open the selected value + $scope.open = function() { + if ($scope.selectedDecisionTable) { + $scope.property.value = { + 'id': $scope.selectedDecisionTable.id, + 'name': $scope.selectedDecisionTable.name, + 'key': $scope.selectedDecisionTable.key + }; + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated + }; + + // Update + $http({ + method: 'POST', + data: params, + ignoreErrors: true, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId) + }) + + .success(function(data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('decision-table-editor/' + $scope.selectedDecisionTable.id); + }) + .error(function(data, status, headers, config) { + + }); + + $scope.close(); + } + }; + + $scope.newDecisionTable = function() { + $scope.property.value.variablesmapping = []; + + $scope.popup.state = 'newDecisionTable'; + + var modelMetaData = editorManager.getBaseModelData(); + + $scope.model = { + loading: false, + decisionTable: { + name: '', + key: '', + description: '', + modelType: 4 + }, + defaultStencilSet: undefined, + decisionTableStencilSets: [] + }; + }; + + $scope.createDecisionTable = function() { + + if (!$scope.model.decisionTable.name || $scope.model.decisionTable.name.length == 0 || + !$scope.model.decisionTable.key || $scope.model.decisionTable.key.length == 0) { + + return; + } + + var stencilSetId = $scope.model.decisionTable.stencilSet; + $scope.model.loading = true; + + $http({ + method: 'POST', + url: FLOWABLE.APP_URL.getModelsUrl(), + data: $scope.model.decisionTable + }). + success(function(data, status, headers, config) { + + var newDecisionTableId = data.id; + $scope.property.value = { + 'id': newDecisionTableId, + 'name': data.name, + 'key': data.key + }; + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated, + stencilSet: stencilSetId + }; + + // Update + $http({ + method: 'POST', + data: params, + ignoreErrors: true, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' + }, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId) + }) + + .success(function(data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + $scope.model.loading = false; + $scope.$hide(); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('decision-table-editor/' + newDecisionTableId); + }) + .error(function(data, status, headers, config) { + $scope.model.loading = false; + $scope.$hide(); + }); + + }). + error(function(data, status, headers, config) { + $scope.model.loading = false; + $scope.model.errorMessage = data.message; + }); + }; + + $scope.cancel = function() { + $scope.close(); + }; + + $scope.resetCurrent = function () { + for (var i = 0, found = false; i < $scope.decisionTables.length && found === false; i++) { + var table = $scope.decisionTables[i]; + if (table.id === $scope.property.value.id) { + $scope.selectedDecisionTable = table; + found = true; + } + } + }; + + $scope.loadDecisionTables = function() { + var modelMetaData = editorManager.getBaseModelData(); + $http.get(FLOWABLE.APP_URL.getDecisionTableModelsUrl()) + .success( + function(response) { + $scope.state.loadingDecisionTables = false; + $scope.state.decisionTableError = false; + $scope.decisionTables = response.data; + $scope.resetCurrent(); + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingDecisionTables = false; + $scope.state.decisionTableError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedDecisionTable = $scope.property.value; + $scope.storedId = $scope.property.value.id; + } + + $scope.loadDecisionTables(); + } +]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-default-controllers.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-default-controllers.js new file mode 100644 index 0000000..c31fe4d --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-default-controllers.js @@ -0,0 +1,118 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * String controller + */ + +angular.module('flowableModeler').controller('FlowableStringPropertyCtrl', [ '$scope', function ($scope) { + + $scope.shapeId = $scope.selectedShape.id; + $scope.valueFlushed = false; + /** Handler called when input field is blurred */ + $scope.inputBlurred = function() { + $scope.valueFlushed = true; + if ($scope.property.value) { + $scope.property.value = $scope.property.value.replace(/(<([^>]+)>)/ig,""); + } + $scope.updatePropertyInModel($scope.property); + }; + + $scope.enterPressed = function(keyEvent) { + // if enter is pressed + if (keyEvent && keyEvent.which === 13) { + keyEvent.preventDefault(); + $scope.inputBlurred(); // we want to do the same as if the user would blur the input field + } + // else; do nothing + }; + + $scope.$on('$destroy', function controllerDestroyed() { + if(!$scope.valueFlushed) { + if ($scope.property.value) { + $scope.property.value = $scope.property.value.replace(/(<([^>]+)>)/ig,""); + } + $scope.updatePropertyInModel($scope.property, $scope.shapeId); + } + }); + +}]); + +/* + * Boolean controller + */ + +angular.module('flowableModeler').controller('FlowableBooleanPropertyCtrl', ['$scope', function ($scope) { + + $scope.changeValue = function() { + if ($scope.property.key === 'oryx-defaultflow' && $scope.property.value) { + var selectedShape = $scope.selectedShape; + if (selectedShape) { + var incomingNodes = selectedShape.getIncomingShapes(); + if (incomingNodes && incomingNodes.length > 0) { + // get first node, since there can be only one for a sequence flow + var rootNode = incomingNodes[0]; + var flows = rootNode.getOutgoingShapes(); + if (flows && flows.length > 1) { + // in case there are more flows, check if another flow is already defined as default + for (var i = 0; i < flows.length; i++) { + if (flows[i].resourceId != selectedShape.resourceId) { + var defaultFlowProp = flows[i].properties.get('oryx-defaultflow'); + if (defaultFlowProp) { + flows[i].setProperty('oryx-defaultflow', false, true); + } + } + } + } + } + } + } + $scope.updatePropertyInModel($scope.property); + }; + +}]); + +/* + * Text controller + */ + +angular.module('flowableModeler').controller('FlowableTextPropertyCtrl', [ '$scope', '$modal', '$timeout', function($scope, $modal, $timeout) { + + var opts = { + template: 'editor-app/configuration/properties/text-popup.html?version=' + Date.now(), + scope: $scope, + prefixEvent: 'textModalEvent' + }; + + $scope.$on('textModalEvent.hide.before', function() { + $timeout(function() { + $scope.property.mode = 'read'; + }, 0); + }); + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableTextPropertyPopupCtrl', ['$scope', function($scope) { + + $scope.save = function() { + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-duedate-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-duedate-controller.js new file mode 100644 index 0000000..50ff9dd --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-duedate-controller.js @@ -0,0 +1,126 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Due date + */ +'use strict'; + +angular.module('flowableModeler').controller('BpmnEditorDueDateCtrl', [ '$scope', '$modal', function($scope, $modal) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/duedate-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('BpmnEditorDueDatePopupCtrl', + [ '$rootScope', '$scope', '$translate', function($rootScope, $scope, $translate) { + + // Put json representing assignment on scope + if ($scope.property.value !== undefined && $scope.property.value !== null) { + + if ($scope.property.value.duedate !== undefined && $scope.property.value.duedate !== null) { + $scope.popup = {'duedate': $scope.property.value.duedate}; + + } else if ($scope.property.value.duedateExpression !== undefined && $scope.property.value.duedateExpression !== null) { + $scope.popup = {'duedateExpression': $scope.property.value.duedateExpression}; + + } else { + $scope.popup = {'duedateExpression': $scope.property.value}; + } + + } else { + $scope.popup = {}; + } + + $scope.taskDueDateOptions = [ + {id: "none", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE')}, + {id: "expression", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION')}, + {id: "static", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC')}, + {id: "field", title: $translate.instant('PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD')} + ]; + + if (!$scope.popup.duedate && !$scope.popup.duedateExpression) { + // Default, first time opening the popup + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[0].id; + + } else if (!$scope.popup.duedate) { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[1].id; + + } else { + + if ($scope.popup.duedate.fixed) { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[2].id; + + } else if ($scope.popup.duedate.field) { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[3].id; + + } else { + $scope.popup.selectedDueDateOption = $scope.taskDueDateOptions[0].id; + } + } + + $scope.dueDateOptionChanged = function() { + if ($scope.popup.selectedDueDateOption === 'expression') { + $scope.popup.duedate = undefined; + + } else if ($scope.popup.selectedDueDateOption === 'none') { + $scope.popup.duedate = undefined; + $scope.popup.duedateExpression = undefined; + + } else if ($scope.popup.selectedDueDateOption === 'static') { + $scope.popup.duedate = {'fixed': {}}; + $scope.popup.duedateExpression = undefined; + + } else if ($scope.popup.selectedDueDateOption === 'field') { + $scope.popup.duedate = {'field': {}}; + $scope.popup.duedateExpression = undefined; + } + }; + + $scope.setAddCalculationType = function() { + $scope.popup.duedate.field.taskDueDateCalculationType = 'add'; + }; + + $scope.setSubtractCalculationType = function() { + $scope.popup.duedate.field.taskDueDateCalculationType = 'subtract'; + }; + + $scope.allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $scope.save = function () { + $scope.property.value = {}; + if ($scope.popup.duedate) { + $scope.property.value.duedate = $scope.popup.duedate; + + } else if ($scope.popup.duedateExpression) { + $scope.property.value.duedateExpression = $scope.popup.duedateExpression; + + } else { + $scope.property.value = ''; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; +}]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-event-listeners-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-event-listeners-controller.js new file mode 100644 index 0000000..21f9ad4 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-event-listeners-controller.js @@ -0,0 +1,263 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableEventListenersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/event-listeners-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259 +// Will be fixed in a newer version of Angular UI +angular.module('flowableModeler').controller('FlowableEventListenersPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.eventListeners !== undefined + && $scope.property.value.eventListeners !== null) { + + if ($scope.property.value.eventListeners.constructor == String) { + $scope.eventListeners = JSON.parse($scope.property.value.eventListeners); + } + else { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.eventListeners = angular.copy($scope.property.value.eventListeners); + } + + } else { + $scope.eventListeners = []; + } + + $scope.translationsRetrieved = false; + $scope.labels = {}; + + var eventPromise = $translate('PROPERTY.EXECUTIONLISTENERS.EVENT'); + var implementationPromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION'); + var namePromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME'); + + $q.all([eventPromise, implementationPromise, namePromise]).then(function (results) { + $scope.labels.eventLabel = results[0]; + $scope.labels.implementationLabel = results[1]; + $scope.labels.nameLabel = results[2]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.eventListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + + if ($scope.selectedListener) { + var fields = $scope.selectedListener.fields; + if (fields !== undefined && fields !== null) { + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + if (field.stringValue !== undefined && field.stringValue !== '') { + field.implementation = field.stringValue; + } else if (field.expression !== undefined && field.expression !== '') { + field.implementation = field.expression; + } else if (field.string !== undefined && field.string !== '') { + field.implementation = field.string; + } + } + } else { + $scope.selectedListener.fields = []; + } + if (!$scope.selectedListener.events) { + $scope.selectedListener.events = [{event: ''}]; + } + } + }); + }; + }); + + + // Click handler for + button after enum value + $scope.addEventValue = function (index) { + $scope.selectedListener.events.splice(index + 1, 0, {event: ''}); + }; + + // Click handler for - button after enum value + $scope.removeEventValue = function (index) { + $scope.selectedListener.events.splice(index, 1); + $scope.listenerDetailsChanged(); + }; + + $scope.listenerDetailsChanged = function () { + var listener = $scope.selectedListener; + if (listener.events) { + var eventText = ''; + for (var i = 0; i < listener.events.length; i++) { + if (i > 0) { + eventText += ", "; + } + eventText += listener.events[i].event; + } + $scope.selectedListener.event = eventText; + } + + if (listener.rethrowEvent) { + var implementationText = ''; + if (listener.rethrowType && listener.rethrowType.length > 0) { + if (listener.rethrowType === 'error' && listener.errorcode !== '') { + implementationText = "Rethrow as error " + listener.errorcode; + } + else if (listener.rethrowType === 'message' && listener.messagename !== '') { + implementationText = "Rethrow as message " + listener.messagename; + } + else if ((listener.rethrowType === 'signal' || listener.rethrowType === 'globalSignal') && listener.signalname !== '') { + implementationText = "Rethrow as signal " + listener.signalname; + } + } + $scope.selectedListener.implementation = implementationText; + } + else { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } + else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } + else { + $scope.selectedListener.implementation = ''; + } + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + event: '', + implementation: '', + className: '', + delegateExpression: '', + retrowEvent: false + }; + + $scope.eventListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.eventListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.eventListeners.splice(index, 1); + + if ($scope.eventListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.eventListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.eventListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.eventListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.eventListeners[index]; + $scope.eventListeners.splice(index, 1); + $timeout(function () { + $scope.eventListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.eventListeners.indexOf(selectedItems[0]); + if (index != $scope.eventListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.eventListeners[index]; + $scope.eventListeners.splice(index, 1); + $timeout(function () { + $scope.eventListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.eventListeners.length > 0) { + $scope.property.value = {}; + $scope.property.value.eventListeners = $scope.eventListeners; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-execution-listeners-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-execution-listeners-controller.js new file mode 100644 index 0000000..3ca1310 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-execution-listeners-controller.js @@ -0,0 +1,358 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableExecutionListenersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/execution-listeners-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableExecutionListenersPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.executionListeners !== undefined + && $scope.property.value.executionListeners !== null) { + + if ($scope.property.value.executionListeners.constructor == String) { + $scope.executionListeners = JSON.parse($scope.property.value.executionListeners); + } + else { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.executionListeners = angular.copy($scope.property.value.executionListeners); + } + + for (var i = 0; i < $scope.executionListeners.length; i++) { + var executionListener = $scope.executionListeners[i]; + if (executionListener.className !== undefined && executionListener.className !== '') { + executionListener.implementation = executionListener.className; + } + else if (executionListener.expression !== undefined && executionListener.expression !== '') { + executionListener.implementation = executionListener.expression; + } + else if (executionListener.delegateExpression !== undefined && executionListener.delegateExpression !== '') { + executionListener.implementation = executionListener.delegateExpression; + } + } + } else { + $scope.executionListeners = []; + } + + $scope.selectedListener = undefined; + $scope.selectedField = undefined; + $scope.fields = []; + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var eventPromise = $translate('PROPERTY.EXECUTIONLISTENERS.EVENT'); + var implementationPromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION'); + var namePromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME'); + + $q.all([eventPromise, implementationPromise, namePromise]).then(function (results) { + $scope.labels.eventLabel = results[0]; + $scope.labels.implementationLabel = results[1]; + $scope.labels.nameLabel = results[2]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.executionListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + $scope.selectedField = undefined; + if ($scope.selectedListener) { + var fields = $scope.selectedListener.fields; + if (fields !== undefined && fields !== null) { + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + if (field.stringValue !== undefined && field.stringValue !== '') { + field.implementation = field.stringValue; + } else if (field.expression !== undefined && field.expression !== '') { + field.implementation = field.expression; + } else if (field.string !== undefined && field.string !== '') { + field.implementation = field.string; + } + } + } else { + $scope.selectedListener.fields = []; + } + + $scope.fields.length = 0; + for (var i = 0; i < $scope.selectedListener.fields.length; i++) { + $scope.fields.push($scope.selectedListener.fields[i]); + } + } + }); + }; + + // Config for field grid + $scope.gridFieldOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'name', displayName: $scope.labels.name}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridFieldOptions.onRegisterApi = function (gridApi) { + // set gridApi on scope + $scope.fieldGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.listenerDetailsChanged = function () { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } else if ($scope.selectedListener.expression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.expression; + } else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } else { + $scope.selectedListener.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + event: 'start', + implementation: '', + className: '', + expression: '', + delegateExpression: '' + }; + $scope.executionListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.executionListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.executionListeners.splice(index, 1); + + if ($scope.executionListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.executionListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.executionListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.executionListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.executionListeners[index]; + $scope.executionListeners.splice(index, 1); + $timeout(function () { + $scope.executionListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.executionListeners.indexOf(selectedItems[0]); + if (index != $scope.executionListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.executionListeners[index]; + $scope.executionListeners.splice(index, 1); + $timeout(function () { + $scope.executionListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + if ($scope.selectedListener) { + if ($scope.selectedListener.fields == undefined) { + $scope.selectedListener.fields = []; + } + + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + $scope.fields.push(newField); + $scope.selectedListener.fields.push(newField); + + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(newField); + }); + } + }; + + // Click handler for remove button + $scope.removeField = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $scope.selectedListener.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $scope.selectedListener.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.executionListeners.length > 0) { + $scope.property.value = {}; + $scope.property.value.executionListeners = $scope.executionListeners; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.$hide(); + $scope.property.mode = 'read'; + }; + + // Close button handler + $scope.close = function () { + $scope.$hide(); + $scope.property.mode = 'read'; + }; + + }]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-fields-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-fields-controller.js new file mode 100644 index 0000000..2d9445b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-fields-controller.js @@ -0,0 +1,206 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Task listeners + */ + +angular.module('flowableModeler').controller('FlowableFieldsCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/fields-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableFieldsPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.fields !== undefined + && $scope.property.value.fields !== null) { + + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.fields = angular.copy($scope.property.value.fields); + + for (var i = 0; i < $scope.fields.length; i++) { + var field = $scope.fields[i]; + if (field.stringValue !== undefined && field.stringValue !== '') { + field.implementation = field.stringValue; + } + else if (field.expression !== undefined && field.expression !== '') { + field.implementation = field.expression; + } + else if (field.string !== undefined && field.string !== '') { + field.implementation = field.string; + } + } + + } else { + $scope.fields = []; + } + + $scope.translationsRetrieved = false; + $scope.labels = {}; + + var namePromise = $translate('PROPERTY.FIELDS.NAME'); + var implementationPromise = $translate('PROPERTY.FIELDS.IMPLEMENTATION'); + + $q.all([namePromise, implementationPromise]).then(function (results) { + $scope.labels.nameLabel = results[0]; + $scope.labels.implementationLabel = results[1]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'name', displayName: $scope.labels.nameLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } + else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } + else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } + else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + + $scope.fields.push(newField); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newField); + }); + }; + + // Click handler for remove button + $scope.removeField = function () { + + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.fields.length > 0) { + $scope.property.value = {}; + $scope.property.value.fields = $scope.fields; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.$hide(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + }]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-properties-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-properties-controller.js new file mode 100644 index 0000000..ca8f051 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-properties-controller.js @@ -0,0 +1,327 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Form Properties + */ + +angular.module('flowableModeler').controller('FlowableFormPropertiesCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/form-properties-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableFormPropertiesPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.formProperties !== undefined + && $scope.property.value.formProperties !== null) { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happended + $scope.formProperties = angular.copy($scope.property.value.formProperties); + + for (var i = 0; i < $scope.formProperties.length; i++) { + var formProperty = $scope.formProperties[i]; + if (formProperty.enumValues && formProperty.enumValues.length > 0) { + for (var j = 0; j < formProperty.enumValues.length; j++) { + var enumValue = formProperty.enumValues[j]; + if (!enumValue.id && !enumValue.name && enumValue.value) { + enumValue.id = enumValue.value; + enumValue.name = enumValue.value; + } + } + } + } + + } else { + $scope.formProperties = []; + } + + $scope.enumValues = []; + + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var idPromise = $translate('PROPERTY.FORMPROPERTIES.ID'); + var namePromise = $translate('PROPERTY.FORMPROPERTIES.NAME'); + var typePromise = $translate('PROPERTY.FORMPROPERTIES.TYPE'); + + $q.all([idPromise, namePromise, typePromise]).then(function (results) { + $scope.labels.idLabel = results[0]; + $scope.labels.nameLabel = results[1]; + $scope.labels.typeLabel = results[2]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.formProperties, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'id', displayName: $scope.labels.idLabel}, + {field: 'name', displayName: $scope.labels.nameLabel}, + {field: 'type', displayName: $scope.labels.typeLabel}] + }; + + $scope.enumGridOptions = { + data: $scope.enumValues, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel }, + { field: 'name', displayName: $scope.labels.nameLabel}] + } + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedProperty = row.entity; + $scope.selectedEnumValue = undefined; + if ($scope.selectedProperty && $scope.selectedProperty.enumValues) { + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + } + }); + }; + + $scope.enumGridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.enumGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedEnumValue = row.entity; + }); + }; + }); + + // Handler for when the value of the type dropdown changes + $scope.propertyTypeChanged = function () { + + // Check date. If date, show date pattern + if ($scope.selectedProperty.type === 'date') { + $scope.selectedProperty.datePattern = 'MM-dd-yyyy hh:mm'; + } else { + delete $scope.selectedProperty.datePattern; + } + + // Check enum. If enum, show list of options + if ($scope.selectedProperty.type === 'enum') { + $scope.selectedProperty.enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}]; + $scope.enumValues.length = 0; + for (var i = 0; i < $scope.selectedProperty.enumValues.length; i++) { + $scope.enumValues.push($scope.selectedProperty.enumValues[i]); + } + + } else { + delete $scope.selectedProperty.enumValues; + $scope.enumValues.length = 0; + } + }; + + // Click handler for add button + var propertyIndex = 1; + $scope.addNewProperty = function () { + var newProperty = { + id: 'new_property_' + propertyIndex++, + name: '', + type: 'string', + readable: true, + writable: true + }; + + $scope.formProperties.push(newProperty); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newProperty); + }); + }; + + // Click handler for remove button + $scope.removeProperty = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.formProperties.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.formProperties.splice(index, 1); + + if ($scope.formProperties.length == 0) { + $scope.selectedProperty = undefined; + } + + $timeout(function() { + if ($scope.formProperties.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.formProperties[0]); + } + }); + } + }; + + // Click handler for up button + $scope.movePropertyUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.formProperties.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.formProperties[index]; + $scope.formProperties.splice(index, 1); + $timeout(function(){ + $scope.formProperties.splice(index + -1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.movePropertyDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.formProperties.indexOf(selectedItems[0]); + if (index != $scope.formProperties.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.formProperties[index]; + $scope.formProperties.splice(index, 1); + $timeout(function(){ + $scope.formProperties.splice(index + 1, 0, temp); + $timeout(function() { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + $scope.addNewEnumValue = function() { + if ($scope.selectedProperty) { + var newEnumValue = { id : '', name : ''}; + $scope.selectedProperty.enumValues.push(newEnumValue); + $scope.enumValues.push(newEnumValue); + + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(newEnumValue); + }); + } + }; + + // Click handler for remove button + $scope.removeEnumValue = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + $scope.enumGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + + if ($scope.enumValues.length == 0) { + $scope.selectedEnumValue = undefined; + } + + $timeout(function () { + if ($scope.enumValues.length > 0) { + $scope.enumGridApi.selection.toggleRowSelection($scope.enumValues[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveEnumValueUp = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + -1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + -1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveEnumValueDown = function() { + var selectedItems = $scope.enumGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.enumValues.indexOf(selectedItems[0]); + if (index != $scope.enumValues.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.enumValues[index]; + $scope.enumValues.splice(index, 1); + $scope.selectedProperty.enumValues.splice(index, 1); + $timeout(function () { + $scope.enumValues.splice(index + 1, 0, temp); + $scope.selectedProperty.enumValues.splice(index + 1, 0, temp); + $timeout(function () { + $scope.enumGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.formProperties.length > 0) { + $scope.property.value = {}; + $scope.property.value.formProperties = $scope.formProperties; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.$hide(); + $scope.property.mode = 'read'; + }; + + // Close button handler + $scope.close = function () { + $scope.$hide(); + $scope.property.mode = 'read'; + }; + + }]) +; \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-reference-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-reference-controller.js new file mode 100644 index 0000000..a710bce --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-form-reference-controller.js @@ -0,0 +1,261 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableFormReferenceDisplayCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $http.get(FLOWABLE.APP_URL.getModelUrl($scope.property.value.id)) + .success( + function(response) { + $scope.form = { + id: response.id, + name: response.name + }; + }); + } + +}]); + +angular.module('flowableModeler').controller('FlowableFormReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/form-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableFormReferencePopupCtrl', + [ '$rootScope', '$scope', '$http', '$location', 'editorManager', function($rootScope, $scope, $http, $location, editorManager) { + + $scope.state = {'loadingForms' : true, 'formError' : false}; + + $scope.popup = {'state' : 'formReference'}; + + $scope.foldersBreadCrumbs = []; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a subprocess + $scope.selectForm = function(form, $event) { + $event.stopPropagation(); + if ($scope.selectedForm && $scope.selectedForm.id && form.id == $scope.selectedForm.id) { + // un-select the current selection + $scope.selectedForm = null; + } else { + $scope.selectedForm = form; + } + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedForm) { + $scope.property.value = { + 'id' : $scope.selectedForm.id, + 'name' : $scope.selectedForm.name, + 'key' : $scope.selectedForm.key + }; + + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Open the selected value + $scope.open = function() { + if ($scope.selectedForm) { + $scope.property.value = { + 'id' : $scope.selectedForm.id, + 'name' : $scope.selectedForm.name, + 'key' : $scope.selectedForm.key + }; + + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated + }; + + // Update + $http({ method: 'POST', + data: params, + ignoreErrors: true, + headers: {'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId)}) + + .success(function (data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + var allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('form-editor/' + $scope.selectedForm.id); + + }) + .error(function (data, status, headers, config) { + + }); + + $scope.close(); + } + }; + + $scope.newForm = function() { + $scope.popup.state = 'newForm'; + + var modelMetaData = editorManager.getBaseModelData(); + + $scope.model = { + loading: false, + form: { + name: '', + key: '', + description: '', + modelType: 2 + } + }; + }; + + $scope.createForm = function() { + + if (!$scope.model.form.name || $scope.model.form.name.length == 0 || + !$scope.model.form.key || $scope.model.form.key.length == 0) { + + return; + } + + $scope.model.loading = true; + + $http({method: 'POST', url: FLOWABLE.APP_URL.getModelsUrl(), data: $scope.model.form}). + success(function(data, status, headers, config) { + + var newFormId = data.id; + $scope.property.value = { + 'id' : newFormId, + 'name' : data.name, + 'key' : data.key + }; + $scope.updatePropertyInModel($scope.property); + + var modelMetaData = editorManager.getBaseModelData(); + var json = editorManager.getModel(); + json = JSON.stringify(json); + + var params = { + modeltype: modelMetaData.model.modelType, + json_xml: json, + name: modelMetaData.name, + key: modelMetaData.key, + description: modelMetaData.description, + newversion: false, + lastUpdated: modelMetaData.lastUpdated + }; + + // Update + $http({ method: 'POST', + data: params, + ignoreErrors: true, + headers: {'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, + transformRequest: function (obj) { + var str = []; + for (var p in obj) { + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + }, + url: FLOWABLE.URL.putModel(modelMetaData.modelId)}) + + .success(function (data, status, headers, config) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_SAVED + }); + + $scope.model.loading = false; + $scope.$hide(); + + var allSteps = EDITOR.UTIL.collectSortedElementsFromPrecedingElements($scope.selectedShape); + + $rootScope.addHistoryItem($scope.selectedShape.resourceId); + $location.path('form-editor/' + newFormId); + + }) + .error(function (data, status, headers, config) { + $scope.model.loading = false; + $scope.$hide(); + }); + + }). + error(function(data, status, headers, config) { + $scope.model.loading = false; + $scope.model.errorMessage = data.message; + }); + }; + + $scope.cancel = function() { + $scope.close(); + }; + + $scope.loadForms = function() { + var modelMetaData = editorManager.getBaseModelData(); + $http.get(FLOWABLE.APP_URL.getFormModelsUrl()) + .success( + function(response) { + $scope.state.loadingForms = false; + $scope.state.formError = false; + $scope.forms = response.data; + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingForms = false; + $scope.state.formError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedForm = $scope.property.value; + } + + $scope.loadForms(); +}]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-httprequest-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-httprequest-controller.js new file mode 100644 index 0000000..c384e62 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-httprequest-controller.js @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableHttpRequestMethodCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'GET'; + } + + $scope.httpRequestMethodChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-in-parameters-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-in-parameters-controller.js new file mode 100644 index 0000000..37a0d05 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-in-parameters-controller.js @@ -0,0 +1,184 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Input parameters for call activity + */ + +angular.module('flowableModeler').controller('FlowableInParametersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/in-parameters-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableInParametersPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.inParameters !== undefined + && $scope.property.value.inParameters !== null) { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.parameters = angular.copy($scope.property.value.inParameters); + } else { + $scope.parameters = []; + } + + $scope.translationsRetrieved = false; + $scope.labels = {}; + + var sourcePromise = $translate('PROPERTY.PARAMETER.SOURCE'); + var sourceExpressionPromise = $translate('PROPERTY.PARAMETER.SOURCEEXPRESSION'); + var targetPromise = $translate('PROPERTY.PARAMETER.TARGET'); + var targetExpressionPromise = $translate('PROPERTY.PARAMETER.TARGETEXPRESSION'); + + $q.all([sourcePromise, sourceExpressionPromise, targetPromise, targetExpressionPromise]).then(function (results) { + $scope.labels.sourceLabel = results[0]; + $scope.labels.sourceExpressionLabel = results[1]; + $scope.labels.targetLabel = results[2]; + $scope.labels.targetExpressionLabel = results[3]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.parameters, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'source', displayName: $scope.labels.sourceLabel}, + {field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel}, + {field: 'target', displayName: $scope.labels.targetLabel}, + {field: 'targetExpression', displayName: $scope.labels.targetExpressionLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedParameter = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewParameter = function () { + var newParameter = { + source: '', + sourceExpression: '', + target: '', + targetExpression: '' + }; + + $scope.parameters.push(newParameter); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newParameter); + }); + }; + + // Click handler for remove button + $scope.removeParameter = function () { + + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.parameters.splice(index, 1); + + if ($scope.parameters.length == 0) { + $scope.selectedParameter = undefined; + } + + $timeout(function () { + if ($scope.parameters.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.parameters[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveParameterUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveParameterDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.parameters.length > 0) { + $scope.property.value = {}; + $scope.property.value.inParameters = $scope.parameters; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.close(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-definitions-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-definitions-controller.js new file mode 100644 index 0000000..7a80338 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-definitions-controller.js @@ -0,0 +1,145 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableMessageDefinitionsCtrl', ['$scope', '$modal', function ($scope, $modal) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/message-definitions-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259 +// Will be fixed in a newer version of Angular UI +angular.module('flowableModeler').controller('FlowableMessageDefinitionsPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing mesage definitions on scope + if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.length > 0) { + + if ($scope.property.value.constructor == String) { + $scope.messageDefinitions = JSON.parse($scope.property.value); + } + else { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.messageDefinitions = angular.copy($scope.property.value); + } + + } else { + $scope.messageDefinitions = []; + } + + // Array to contain selected mesage definitions (yes - we only can select one, but ng-grid isn't smart enough) + $scope.selectedMessageDefinition = undefined; + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var idPromise = $translate('PROPERTY.MESSAGEDEFINITIONS.ID'); + var namePromise = $translate('PROPERTY.MESSAGEDEFINITIONS.NAME'); + + $q.all([idPromise, namePromise]).then(function (results) { + + $scope.labels.idLabel = results[0]; + $scope.labels.nameLabel = results[1]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.messageDefinitions, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'id', displayName: $scope.labels.idLabel}, + {field: 'name', displayName: $scope.labels.nameLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedMessageDefinition = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewMessageDefinition = function () { + var newMessageDefinition = {id: '', name: ''}; + + $scope.messageDefinitions.push(newMessageDefinition); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newMessageDefinition); + }); + }; + + // Click handler for remove button + $scope.removeMessageDefinition = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.messageDefinitions.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.messageDefinitions.splice(index, 1); + + if ($scope.messageDefinitions.length == 0) { + $scope.selectedMesageDefinition = undefined; + } + + $timeout(function () { + if ($scope.messageDefinitions.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.messageDefinitions[0]); + } + }); + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.messageDefinitions.length > 0) { + $scope.property.value = $scope.messageDefinitions; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-scope-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-scope-controller.js new file mode 100644 index 0000000..91f690b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-message-scope-controller.js @@ -0,0 +1,41 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +angular.module('flowableModeler').controller('FlowableMessageRefCtrl', [ '$scope', function($scope) { + + // Find the parent shape on which the message definitions are defined + var messageDefinitionsProperty = undefined; + var parent = $scope.selectedShape; + while (parent !== null && parent !== undefined && messageDefinitionsProperty === undefined) { + if (parent.properties && parent.properties.get('oryx-messagedefinitions')) { + messageDefinitionsProperty = parent.properties.get('oryx-messagedefinitions'); + } else { + parent = parent.parent; + } + } + + try { + messageDefinitionsProperty = JSON.parse(messageDefinitionsProperty); + if (typeof messageDefinitionsProperty == 'string') { + messageDefinitionsProperty = JSON.parse(messageDefinitionsProperty); + } + } catch (err) { + // Do nothing here, just to be sure we try-catch it + } + + $scope.messageDefinitions = messageDefinitionsProperty; + + + $scope.messageChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-multiinstance-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-multiinstance-controller.js new file mode 100644 index 0000000..6d90a4e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-multiinstance-controller.js @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableMultiInstanceCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'None'; + } + + $scope.multiInstanceChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-ordering-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-ordering-controller.js new file mode 100644 index 0000000..241dfc7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-ordering-controller.js @@ -0,0 +1,28 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Adhoc sub process ordering property + */ + +angular.module('flowableModeler').controller('FlowableOrderingCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'Parallel'; + } + + $scope.orderingChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-out-parameters-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-out-parameters-controller.js new file mode 100644 index 0000000..b7b10ab --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-out-parameters-controller.js @@ -0,0 +1,180 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Input parameters for call activity + */ + +angular.module('flowableModeler').controller('FlowableOutParametersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/out-parameters-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableOutParametersPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.outParameters !== undefined + && $scope.property.value.outParameters !== null) { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.parameters = angular.copy($scope.property.value.outParameters); + } else { + $scope.parameters = []; + } + + $scope.translationsRetrieved = false; + $scope.labels = {}; + + var sourcePromise = $translate('PROPERTY.PARAMETER.SOURCE'); + var sourceExpressionPromise = $translate('PROPERTY.PARAMETER.SOURCEEXPRESSION'); + var targetPromise = $translate('PROPERTY.PARAMETER.TARGET'); + var targetExpressionPromise = $translate('PROPERTY.PARAMETER.TARGETEXPRESSION'); + + $q.all([sourcePromise, sourceExpressionPromise, targetPromise, targetExpressionPromise]).then(function (results) { + $scope.labels.sourceLabel = results[0]; + $scope.labels.sourceExpressionLabel = results[1]; + $scope.labels.targetLabel = results[2]; + $scope.labels.targetExpressionLabel = results[3]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.parameters, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'source', displayName: $scope.labels.sourceLabel}, + {field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel}, + {field: 'target', displayName: $scope.labels.targetLabel}, + {field: 'targetExpression', displayName: $scope.labels.targetExpressionLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedParameter = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewParameter = function () { + var newParameter = { + source: '', + sourceExpression: '', + target: '', + targetExpression: ''}; + + $scope.parameters.push(newParameter); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newParameter); + }); + }; + + // Click handler for remove button + $scope.removeParameter = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.parameters.splice(index, 1); + + if ($scope.parameters.length == 0) { + $scope.selectedParameter = undefined; + } + + $timeout(function () { + if ($scope.parameters.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.parameters[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveParameterUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveParameterDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.parameters.indexOf(selectedItems[0]); + if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.parameters[index]; + $scope.parameters.splice(index, 1); + $timeout(function () { + $scope.parameters.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.parameters.length > 0) { + $scope.property.value = {}; + $scope.property.value.outParameters = $scope.parameters; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.close(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js new file mode 100644 index 0000000..0ae0e0a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-plan-item-lifecycle-listeners-controller.js @@ -0,0 +1,357 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +angular.module('flowableModeler').controller('FlowablePlanItemLifecycleListenersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowablePlanItemLifecycleListenersPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.planItemLifecycleListeners !== undefined + && $scope.property.value.planItemLifecycleListeners !== null) { + + if ($scope.property.value.planItemLifecycleListeners.constructor == String) { + $scope.planItemLifecycleListeners = JSON.parse($scope.property.value.planItemLifecycleListeners); + } + else { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.planItemLifecycleListeners = angular.copy($scope.property.value.planItemLifecycleListeners); + } + + for (var i = 0; i < $scope.planItemLifecycleListeners.length; i++) { + var planItemLifeCycleListener = $scope.planItemLifecycleListeners[i]; + if (planItemLifeCycleListener.className !== undefined && planItemLifeCycleListener.className !== '') { + planItemLifeCycleListener.implementation = planItemLifeCycleListener.className; + } + else if (planItemLifeCycleListener.expression !== undefined && planItemLifeCycleListener.expression !== '') { + planItemLifeCycleListener.implementation = planItemLifeCycleListener.expression; + } + else if (planItemLifeCycleListener.delegateExpression !== undefined && planItemLifeCycleListener.delegateExpression !== '') { + planItemLifeCycleListener.implementation = planItemLifeCycleListener.delegateExpression; + } + } + } else { + $scope.planItemLifecycleListeners = []; + } + + $scope.selectedListener = undefined; + $scope.selectedField = undefined; + $scope.fields = []; + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var sourceStatePromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE'); + var targetStatePromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE'); + var implementationPromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION'); + var namePromise = $translate('PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME'); + + $q.all([sourceStatePromise, targetStatePromise, implementationPromise, namePromise]).then(function (results) { + $scope.labels.sourceStateLabel = results[1]; + $scope.labels.targetStateLabel = results[2]; + $scope.labels.implementationLabel = results[3]; + $scope.labels.nameLabel = results[4]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.planItemLifecycleListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'sourceState', displayName: $scope.labels.sourceStateLabel}, + {field: 'targetState', displayName: $scope.labels.targetStateLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel} + ] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + $scope.selectedField = undefined; + if ($scope.selectedListener) { + var fields = $scope.selectedListener.fields; + if (fields !== undefined && fields !== null) { + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + if (field.stringValue !== undefined && field.stringValue !== '') { + field.implementation = field.stringValue; + } else if (field.expression !== undefined && field.expression !== '') { + field.implementation = field.expression; + } else if (field.string !== undefined && field.string !== '') { + field.implementation = field.string; + } + } + } else { + $scope.selectedListener.fields = []; + } + + $scope.fields.length = 0; + for (var i = 0; i < $scope.selectedListener.fields.length; i++) { + $scope.fields.push($scope.selectedListener.fields[i]); + } + } + }); + }; + + // Config for field grid + $scope.gridFieldOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + columnDefs: [{field: 'name', displayName: $scope.labels.name}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridFieldOptions.onRegisterApi = function (gridApi) { + // set gridApi on scope + $scope.fieldGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.listenerDetailsChanged = function () { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } else if ($scope.selectedListener.expression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.expression; + } else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } else { + $scope.selectedListener.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + sourceState: 'available', + targetState: 'active', + implementation: '', + className: '', + expression: '', + delegateExpression: '' + }; + $scope.planItemLifecycleListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.planItemLifecycleListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.planItemLifecycleListeners.splice(index, 1); + + if ($scope.planItemLifecycleListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.planItemLifecycleListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.planItemLifecycleListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.planItemLifecycleListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.planItemLifecycleListeners[index]; + $scope.planItemLifecycleListeners.splice(index, 1); + $timeout(function () { + $scope.planItemLifecycleListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.planItemLifecycleListeners.indexOf(selectedItems[0]); + if (index != $scope.planItemLifecycleListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.planItemLifecycleListeners[index]; + $scope.planItemLifecycleListeners.splice(index, 1); + $timeout(function () { + $scope.planItemLifecycleListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + if ($scope.selectedListener) { + if ($scope.selectedListener.fields == undefined) { + $scope.selectedListener.fields = []; + } + + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + $scope.fields.push(newField); + $scope.selectedListener.fields.push(newField); + + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(newField); + }); + } + }; + + // Click handler for remove button + $scope.removeField = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $scope.selectedListener.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListeners.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $scope.selectedListener.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.planItemLifecycleListeners.length > 0) { + $scope.property.value = {}; + $scope.property.value.planItemLifecycleListeners = $scope.planItemLifecycleListeners; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.close(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-planitem-dropdown-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-planitem-dropdown-controller.js new file mode 100644 index 0000000..ad2bdb5 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-planitem-dropdown-controller.js @@ -0,0 +1,82 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowablePlanItemDropdownCtrl', [ '$scope', function($scope) { + + // Find all planitems + var selectedShape = $scope.selectedShape; + if (selectedShape) { + + // Go up in parent chain until plan model is found + var planModel; + var parent = selectedShape.parent; + if (parent) { + while (planModel === undefined && parent !== null && parent !== undefined) { + if (parent.resourceId !== null && parent.resourceId !== undefined && 'casePlanModel' === parent.resourceId) { + planModel = parent; + } else { + parent = parent.parent; + } + } + } + + var planItems = []; + if (planModel !== null && planModel !== undefined) { + + var toVisit = []; + for (var i=0; i 0) { + var child = toVisit.pop(); + if (typeof child.getStencil === 'function' + && (child.getStencil()._jsonStencil.groups.indexOf('Activities') >= 0 || (child.getStencil()._jsonStencil.title === 'Stage') )) { + planItems.push(child); + } + if (child.children !== null && child.children !== undefined) { + for (var i=0; i 0) { + simplifiedPlanItems.sort(function(a,b) { + if(a.name < b.name) { + return -1; + } else if (a.name > b.name) { + return 1; + } else { + return 0; + } + }); + } + $scope.planItems = simplifiedPlanItems; + + } + + if ($scope.property.value == undefined && $scope.property.value == null) { + $scope.property.value = ''; + } + + $scope.planItemChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-historylevel-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-historylevel-controller.js new file mode 100644 index 0000000..cc5bda7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-historylevel-controller.js @@ -0,0 +1,24 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableProcessHistoryLevelCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) + { + $scope.property.value = 'None'; + } + + $scope.historyLevelChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-reference-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-reference-controller.js new file mode 100644 index 0000000..dd56e22 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-process-reference-controller.js @@ -0,0 +1,80 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableProcessReferenceCtrl', + [ '$scope', '$modal', '$http', function($scope, $modal, $http) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/process-reference-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableProcessReferencePopupCtrl', [ '$scope', '$http', function($scope, $http) { + + $scope.state = {'loadingProcesses' : true, 'error' : false}; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Selecting/deselecting a process + $scope.selectProcess = function(processModel, $event) { + $event.stopPropagation(); + if ($scope.selectedProcess && $scope.selectedProcess.id && processModel.id == $scope.selectedProcess.id) { + // un-select the current selection + $scope.selectedProcess = null; + } else { + $scope.selectedProcess = processModel; + } + }; + + // Saving the selected value + $scope.save = function() { + if ($scope.selectedProcess) { + $scope.property.value = {'id' : $scope.selectedProcess.id, 'name' : $scope.selectedProcess.name}; + } else { + $scope.property.value = null; + } + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.loadProcesses = function() { + + $http.get(FLOWABLE.APP_URL.getModelsUrl("?modelType=0")) + .success( + function(response) { + $scope.state.loadingProcesses = false; + $scope.state.processError = false; + $scope.processModels = response.data; + }) + .error( + function(data, status, headers, config) { + $scope.state.loadingProcesses = false; + $scope.state.processError = true; + }); + }; + + if ($scope.property && $scope.property.value && $scope.property.value.id) { + $scope.selectedProcess = $scope.property.value; + } + + $scope.loadProcesses(); +}]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-sequenceflow-order-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-sequenceflow-order-controller.js new file mode 100644 index 0000000..a37c8c4 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-sequenceflow-order-controller.js @@ -0,0 +1,126 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Sequence flow order controller + */ + +angular.module('flowableModeler').controller('FlowableSequenceFlowOrderCtrl', + [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/sequenceflow-order-popup.html?version=' + Date.now(), + scope: $scope + }; + + _internalCreateModal(opts, $modal, $scope); +}]); + +angular.module('flowableModeler').controller('FlowableSequenceFlowOrderPopupCtrl', + ['$scope', '$translate', function($scope, $translate) { + + // Find the outgoing sequence flow of the current selected shape + var outgoingSequenceFlow = []; + var selectedShape = $scope.selectedShape; + if (selectedShape) { + var outgoingNodes = selectedShape.getOutgoingShapes(); + for (var i=0; i 0) { + $scope.property.value = {}; + $scope.property.value.sequenceFlowOrder = []; + + for (var flowIndex=0; flowIndex < $scope.outgoingSequenceFlow.length; flowIndex++) { + $scope.property.value.sequenceFlowOrder.push($scope.outgoingSequenceFlow[flowIndex].id); + } + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + // Cancel click handler + $scope.cancel = function() { + $scope.close(); + }; + + // Close button handler + $scope.close = function() { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-definitions-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-definitions-controller.js new file mode 100644 index 0000000..63320ff --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-definitions-controller.js @@ -0,0 +1,151 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableSignalDefinitionsCtrl', ['$scope', '$modal', function ($scope, $modal) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/signal-definitions-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); +}]); + +//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259 +// Will be fixed in a newer version of Angular UI +angular.module('flowableModeler').controller('FlowableSignalDefinitionsPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing signal definitions on scope + if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.length > 0) { + + if ($scope.property.value.constructor == String) { + $scope.signalDefinitions = JSON.parse($scope.property.value); + } + else { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.signalDefinitions = angular.copy($scope.property.value); + } + + } else { + $scope.signalDefinitions = []; + } + + // Array to contain selected signal definitions (yes - we only can select one, but ng-grid isn't smart enough) + $scope.selectedSignalDefinition = undefined; + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var idPromise = $translate('PROPERTY.SIGNALDEFINITIONS.ID'); + var namePromise = $translate('PROPERTY.SIGNALDEFINITIONS.NAME'); + var scopePromise = $translate('PROPERTY.SIGNALDEFINITIONS.SCOPE'); + + $q.all([idPromise, namePromise, scopePromise]).then(function (results) { + + $scope.labels.idLabel = results[0]; + $scope.labels.nameLabel = results[1]; + $scope.labels.scopeLabel = results[2]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.signalDefinitions, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [ + {field: 'id', displayName: $scope.labels.idLabel}, + {field: 'name', displayName: $scope.labels.nameLabel}, + {field: 'scope', displayName: $scope.labels.scopeLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedSignalDefinition = row.entity; + }); + }; + }); + + // Click handler for add button + $scope.addNewSignalDefinition = function () { + var newSignalDefinition = {id: '', name: '', scope: 'global'}; + + $scope.signalDefinitions.push(newSignalDefinition); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newSignalDefinition); + }); + }; + + // Click handler for remove button + $scope.removeSignalDefinition = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.signalDefinitions.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + $scope.signalDefinitions.splice(index, 1); + + if ($scope.signalDefinitions.length == 0) { + $scope.selectedSignalDefinition = undefined; + } + + $timeout(function () { + if ($scope.signalDefinitions.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.signalDefinitions[0]); + } + }); + } + }; + + $scope.scopeOptions = [{'value': 'global', 'translationId': 'PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL'}, + {'value': 'processInstance', 'translationId': 'PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE'}]; + + // Click handler for save button + $scope.save = function () { + + if ($scope.signalDefinitions.length > 0) { + $scope.property.value = $scope.signalDefinitions; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-scope-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-scope-controller.js new file mode 100644 index 0000000..c161991 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-signal-scope-controller.js @@ -0,0 +1,42 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableSignalRefCtrl', [ '$scope', function($scope) { + + // Find the parent shape on which the signal definitions are defined + var signalDefinitionsProperty = undefined; + var parent = $scope.selectedShape; + while (parent !== null && parent !== undefined && signalDefinitionsProperty === undefined) { + if (parent.properties && parent.properties.get('oryx-signaldefinitions')) { + signalDefinitionsProperty = parent.properties.get('oryx-signaldefinitions'); + } else { + parent = parent.parent; + } + } + + try { + signalDefinitionsProperty = JSON.parse(signalDefinitionsProperty); + if (typeof signalDefinitionsProperty == 'string') { + signalDefinitionsProperty = JSON.parse(signalDefinitionsProperty); + } + } catch (err) { + // Do nothing here, just to be sure we try-catch it + } + + $scope.signalDefinitions = signalDefinitionsProperty; + + + $scope.signalChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-task-listeners-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-task-listeners-controller.js new file mode 100644 index 0000000..1c5717d --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-task-listeners-controller.js @@ -0,0 +1,356 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Task listeners + */ + +angular.module('flowableModeler').controller('FlowableTaskListenersCtrl', + ['$scope', '$modal', '$timeout', '$translate', function ($scope, $modal, $timeout, $translate) { + + // Config for the modal window + var opts = { + template: 'editor-app/configuration/properties/task-listeners-popup.html?version=' + Date.now(), + scope: $scope + }; + + // Open the dialog + _internalCreateModal(opts, $modal, $scope); + }]); + +angular.module('flowableModeler').controller('FlowableTaskListenersPopupCtrl', + ['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) { + + // Put json representing form properties on scope + if ($scope.property.value !== undefined && $scope.property.value !== null + && $scope.property.value.taskListeners !== undefined + && $scope.property.value.taskListeners !== null) { + + if ($scope.property.value.taskListeners.constructor == String) { + $scope.taskListeners = JSON.parse($scope.property.value.taskListeners); + } + else { + // Note that we clone the json object rather then setting it directly, + // this to cope with the fact that the user can click the cancel button and no changes should have happened + $scope.taskListeners = angular.copy($scope.property.value.taskListeners); + } + + for (var i = 0; i < $scope.taskListeners.length; i++) { + var taskListener = $scope.taskListeners[i]; + if (taskListener.className !== undefined && taskListener.className !== '') { + taskListener.implementation = taskListener.className; + } + else if (taskListener.expression !== undefined && taskListener.expression !== '') { + taskListener.implementation = taskListener.expression; + } + else if (taskListener.delegateExpression !== undefined && taskListener.delegateExpression !== '') { + taskListener.implementation = taskListener.delegateExpression; + } + } + } else { + $scope.taskListeners = []; + } + + $scope.selectedListener = undefined; + $scope.selectedField = undefined; + $scope.fields = []; + $scope.translationsRetrieved = false; + + $scope.labels = {}; + + var eventPromise = $translate('PROPERTY.TASKLISTENERS.EVENT'); + var implementationPromise = $translate('PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION'); + var namePromise = $translate('PROPERTY.TASKLISTENERS.FIELDS.NAME'); + + $q.all([eventPromise, implementationPromise, namePromise]).then(function (results) { + $scope.labels.eventLabel = results[0]; + $scope.labels.implementationLabel = results[1]; + $scope.labels.nameLabel = results[2]; + $scope.translationsRetrieved = true; + + // Config for grid + $scope.gridOptions = { + data: $scope.taskListeners, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{field: 'event', displayName: $scope.labels.eventLabel}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridOptions.onRegisterApi = function (gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedListener = row.entity; + $scope.selectedField = undefined; + if ($scope.selectedListener) { + var fields = $scope.selectedListener.fields; + if (fields !== undefined && fields !== null) { + for (var i = 0; i < fields.length; i++) { + var field = fields[i]; + if (field.stringValue !== undefined && field.stringValue !== '') { + field.implementation = field.stringValue; + } else if (field.expression !== undefined && field.expression !== '') { + field.implementation = field.expression; + } else if (field.string !== undefined && field.string !== '') { + field.implementation = field.string; + } + } + } else { + $scope.selectedListener.fields = []; + } + + $scope.fields.length = 0; + for (var i = 0; i < $scope.selectedListener.fields.length; i++) { + $scope.fields.push($scope.selectedListener.fields[i]); + } + } + }); + }; + + // Config for field grid + $scope.gridFieldOptions = { + data: $scope.fields, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + columnDefs: [{field: 'name', displayName: $scope.labels.name}, + {field: 'implementation', displayName: $scope.labels.implementationLabel}] + }; + + $scope.gridFieldOptions.onRegisterApi = function (gridApi) { + // set gridApi on scope + $scope.fieldGridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function (row) { + $scope.selectedField = row.entity; + }); + }; + }); + + $scope.listenerDetailsChanged = function () { + if ($scope.selectedListener.className !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.className; + } else if ($scope.selectedListener.expression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.expression; + } else if ($scope.selectedListener.delegateExpression !== '') { + $scope.selectedListener.implementation = $scope.selectedListener.delegateExpression; + } else { + $scope.selectedListener.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewListener = function () { + var newListener = { + event: 'create', + implementation: '', + className: '', + expression: '', + delegateExpression: '' + }; + $scope.taskListeners.push(newListener); + + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(newListener); + }); + }; + + // Click handler for remove button + $scope.removeListener = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.taskListeners.indexOf(selectedItems[0]); + $scope.gridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.taskListeners.splice(index, 1); + + if ($scope.taskListeners.length == 0) { + $scope.selectedListener = undefined; + } + + $timeout(function () { + if ($scope.taskListeners.length > 0) { + $scope.gridApi.selection.toggleRowSelection($scope.taskListeners[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveListenerUp = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.taskListeners.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.taskListeners[index]; + $scope.taskListeners.splice(index, 1); + $timeout(function () { + $scope.taskListeners.splice(index + -1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for down button + $scope.moveListenerDown = function () { + var selectedItems = $scope.gridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.taskListeners.indexOf(selectedItems[0]); + if (index != $scope.taskListeners.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.taskListeners[index]; + $scope.taskListeners.splice(index, 1); + $timeout(function () { + $scope.taskListeners.splice(index + 1, 0, temp); + $timeout(function () { + $scope.gridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + $scope.fieldDetailsChanged = function () { + if ($scope.selectedField.stringValue != '') { + $scope.selectedField.implementation = $scope.selectedField.stringValue; + } else if ($scope.selectedField.expression != '') { + $scope.selectedField.implementation = $scope.selectedField.expression; + } else if ($scope.selectedField.string != '') { + $scope.selectedField.implementation = $scope.selectedField.string; + } else { + $scope.selectedField.implementation = ''; + } + }; + + // Click handler for add button + $scope.addNewField = function () { + if ($scope.selectedListener) { + if ($scope.selectedListener.fields == undefined) { + $scope.selectedListener.fields = []; + } + + var newField = { + name: 'fieldName', + implementation: '', + stringValue: '', + expression: '', + string: '' + }; + $scope.fields.push(newField); + $scope.selectedListener.fields.push(newField); + + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(newField); + }); + } + }; + + // Click handler for remove button + $scope.removeField = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + $scope.fieldGridApi.selection.toggleRowSelection(selectedItems[0]); + + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + + if ($scope.fields.length == 0) { + $scope.selectedField = undefined; + } + + $timeout(function () { + if ($scope.fields.length > 0) { + $scope.fieldGridApi.selection.toggleRowSelection($scope.fields[0]); + } + }); + } + }; + + // Click handler for up button + $scope.moveFieldUp = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != 0) { // If it's the first, no moving up of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListener.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + -1, 0, temp); + $scope.selectedListener.fields.splice(index + -1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + + } + } + }; + + // Click handler for down button + $scope.moveFieldDown = function () { + var selectedItems = $scope.fieldGridApi.selection.getSelectedRows(); + if (selectedItems && selectedItems.length > 0) { + var index = $scope.fields.indexOf(selectedItems[0]); + if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course + var temp = $scope.fields[index]; + $scope.fields.splice(index, 1); + $scope.selectedListeners.fields.splice(index, 1); + $timeout(function () { + $scope.fields.splice(index + 1, 0, temp); + $scope.selectedListener.fields.splice(index + 1, 0, temp); + $timeout(function () { + $scope.fieldGridApi.selection.toggleRowSelection(temp); + }); + }); + } + } + }; + + // Click handler for save button + $scope.save = function () { + + if ($scope.taskListeners.length > 0) { + $scope.property.value = {}; + $scope.property.value.taskListeners = $scope.taskListeners; + } else { + $scope.property.value = null; + } + + $scope.updatePropertyInModel($scope.property); + $scope.close(); + }; + + $scope.cancel = function () { + $scope.close(); + }; + + // Close button handler + $scope.close = function () { + $scope.property.mode = 'read'; + $scope.$hide(); + }; + + }]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-transition-event-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-transition-event-controller.js new file mode 100644 index 0000000..59a33ab --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-transition-event-controller.js @@ -0,0 +1,27 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Execution listeners + */ + +angular.module('flowableModeler').controller('FlowableTransitionEventCtrl', [ '$scope', function($scope) { + + if ($scope.property.value == undefined && $scope.property.value == null) { + $scope.property.value = 'complete'; + } + + $scope.transitionEventChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-trigger-mode-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-trigger-mode-controller.js new file mode 100644 index 0000000..a16041c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties-trigger-mode-controller.js @@ -0,0 +1,23 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('FlowableTriggerModeCtrl', [ '$scope', function($scope) { + + if ($scope.property.value === undefined || $scope.property.value == null) { + $scope.property.value = 'default'; + } + + $scope.triggerModeChanged = function() { + $scope.updatePropertyInModel($scope.property); + }; +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties.js b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties.js new file mode 100644 index 0000000..8b7c264 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties.js @@ -0,0 +1,157 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +'use strict'; + +var FLOWABLE = FLOWABLE || {}; +FLOWABLE.PROPERTY_CONFIG = +{ + "string": { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/string-property-write-mode-template.html" + }, + "boolean": { + "templateUrl": "editor-app/configuration/properties/boolean-property-template.html" + }, + "text" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/text-property-write-template.html" + }, + "flowable-calledelementtype" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/calledelementtype-property-write-template.html" + }, + "flowable-multiinstance" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/multiinstance-property-write-template.html" + }, + "flowable-processhistorylevel" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/process-historylevel-property-write-template.html" + }, + "flowable-ordering" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/ordering-property-write-template.html" + }, + "oryx-dataproperties-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/data-properties-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/data-properties-write-template.html" + }, + "oryx-formproperties-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/form-properties-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/form-properties-write-template.html" + }, + "oryx-executionlisteners-multiplecomplex": { + "readModeTemplateUrl": "editor-app/configuration/properties/execution-listeners-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/execution-listeners-write-template.html" + }, + "oryx-tasklisteners-multiplecomplex": { + "readModeTemplateUrl": "editor-app/configuration/properties/task-listeners-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/task-listeners-write-template.html" + }, + "oryx-eventlisteners-multiplecomplex": { + "readModeTemplateUrl": "editor-app/configuration/properties/event-listeners-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/event-listeners-write-template.html" + }, + "oryx-usertaskassignment-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/assignment-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/assignment-write-template.html" + }, + "oryx-servicetaskfields-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/fields-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/fields-write-template.html" + }, + "oryx-callactivityinparameters-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/in-parameters-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/in-parameters-write-template.html" + }, + "oryx-callactivityoutparameters-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/out-parameters-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/out-parameters-write-template.html" + }, + "oryx-subprocessreference-subprocess-link": { + "readModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-write-template.html" + }, + "oryx-formreference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/form-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/form-reference-write-template.html" + }, + "oryx-sequencefloworder-complex" : { + "readModeTemplateUrl": "editor-app/configuration/properties/sequenceflow-order-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/sequenceflow-order-write-template.html" + }, + "oryx-conditionsequenceflow-complex" : { + "readModeTemplateUrl": "editor-app/configuration/properties/condition-expression-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/condition-expression-write-template.html" + }, + "oryx-signaldefinitions-multiplecomplex" : { + "readModeTemplateUrl": "editor-app/configuration/properties/signal-definitions-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/signal-definitions-write-template.html" + }, + "oryx-signalref-string" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/signal-property-write-template.html" + }, + "oryx-messagedefinitions-multiplecomplex" : { + "readModeTemplateUrl": "editor-app/configuration/properties/message-definitions-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/message-definitions-write-template.html" + }, + "oryx-messageref-string" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/message-property-write-template.html" + }, + "oryx-duedatedefinition-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/duedate-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/duedate-write-template.html" + }, + "oryx-decisiontaskdecisiontablereference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/decisiontable-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/decisiontable-reference-write-template.html" + }, + "oryx-casetaskcasereference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/case-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/case-reference-write-template.html" + }, + "oryx-processtaskprocessreference-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/process-reference-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/process-reference-write-template.html" + }, + "oryx-processtaskinparameters-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/in-parameters-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/in-parameters-write-template.html" + }, + "oryx-processtaskoutparameters-complex": { + "readModeTemplateUrl": "editor-app/configuration/properties/out-parameters-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/out-parameters-write-template.html" + }, + "oryx-planitemlifecyclelisteners-multiplecomplex": { + "readModeTemplateUrl": "editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html" + }, + "flowable-transitionevent" : { + "readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/transition-event-write-template.html" + }, + "flowable-planitem-dropdown" : { + "readModeTemplateUrl": "editor-app/configuration/properties/planitem-dropdown-read-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/planitem-dropdown-write-template.html" + }, + "flowable-http-request-method" : { + "readModeTemplateUrl": "editor-app/configuration/properties/http-request-method-display-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/http-request-method-property-write-template.html" + }, + "flowable-triggermode" : { + "readModeTemplateUrl": "editor-app/configuration/properties/trigger-mode-read-template.html", + "writeModeTemplateUrl": "editor-app/configuration/properties/trigger-mode-write-template.html" + }, +}; diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-display-template.html new file mode 100644 index 0000000..bbe6989 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-display-template.html @@ -0,0 +1,15 @@ + +{{'PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY' | translate:property.value.assignment }} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.candidateUsers}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.candidateGroups}} +{{'PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY' | translate:property.value.assignment.idm.assignee }} +{{'PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY' | translate:property.value.assignment.idm.assignee }} +{{'PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY' | translate:property.value.assignment.idm.assigneeField }} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.idm.candidateUsers}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.idm.candidateGroups}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.idm.candidateUserFields}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.idm.candidateGroupFields}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.idm.candidateUserFields.concat(property.value.assignment.idm.candidateUsers)}} +{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.idm.candidateGroupFields.concat(property.value.assignment.idm.candidateGroups)}} +PROPERTY.ASSIGNMENT.EMPTY +PROPERTY.ASSIGNMENT.IDM_EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-popup.html new file mode 100644 index 0000000..8089e45 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/assignment-popup.html @@ -0,0 +1,268 @@ +
diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/fields-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/fields-write-template.html new file mode 100644 index 0000000..fdc03b7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/fields-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-display-template.html new file mode 100644 index 0000000..1274342 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.FORMPROPERTIES.VALUE' | translate:property.value.formProperties}} +PROPERTY.FORMPROPERTIES.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-popup.html new file mode 100644 index 0000000..c16ed86 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-popup.html @@ -0,0 +1,121 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-write-template.html new file mode 100644 index 0000000..0449718 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-properties-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-display-template.html new file mode 100644 index 0000000..15444f6 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-display-template.html @@ -0,0 +1,4 @@ +
+ {{form.name}} + PROPERTY.FORMREFERENCE.EMPTY +
diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-popup.html new file mode 100644 index 0000000..6c0a2db --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-popup.html @@ -0,0 +1,74 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-write-template.html new file mode 100644 index 0000000..abb945f --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/form-reference-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-display-template.html new file mode 100644 index 0000000..2306527 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-display-template.html @@ -0,0 +1,3 @@ + +{{property.value}} +GET \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-property-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-property-write-template.html new file mode 100644 index 0000000..3a6e2b0 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/http-request-method-property-write-template.html @@ -0,0 +1,8 @@ +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-display-template.html new file mode 100644 index 0000000..961e637 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.INPARAMETERS.VALUE' | translate:property.value.inParameters}} +PROPERTY.INPARAMETERS.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-popup.html new file mode 100644 index 0000000..ac477a1 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-popup.html @@ -0,0 +1,57 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-write-template.html new file mode 100644 index 0000000..d6e1872 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/in-parameters-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-display-template.html new file mode 100644 index 0000000..2a0f3e7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.MESSAGEDEFINITIONS.DISPLAY' | translate:property.value}} +PROPERTY.MESSAGEDEFINITIONS.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-popup.html new file mode 100644 index 0000000..c93cce9 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-popup.html @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-write-template.html new file mode 100644 index 0000000..76e7b88 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-definitions-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-property-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-property-write-template.html new file mode 100644 index 0000000..8e38ea3 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/message-property-write-template.html @@ -0,0 +1,4 @@ +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/multiinstance-property-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/multiinstance-property-write-template.html new file mode 100644 index 0000000..16c36e9 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/multiinstance-property-write-template.html @@ -0,0 +1,8 @@ + +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/ordering-property-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/ordering-property-write-template.html new file mode 100644 index 0000000..150be20 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/ordering-property-write-template.html @@ -0,0 +1,7 @@ + +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-display-template.html new file mode 100644 index 0000000..859b2e4 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.OUTPARAMETERS.VALUE' | translate:property.value.outParameters}} +PROPERTY.OUTPARAMETERS.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-popup.html new file mode 100644 index 0000000..6102f34 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-popup.html @@ -0,0 +1,57 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-write-template.html new file mode 100644 index 0000000..ea6986a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/out-parameters-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html new file mode 100644 index 0000000..88ffb8b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE' | translate:property.value.planItemLifecycleListeners}} +PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html new file mode 100644 index 0000000..9679c41 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-popup.html @@ -0,0 +1,125 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html new file mode 100644 index 0000000..f073c11 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/plan-item-lifecycle-listeners-write-template.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-read-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-read-template.html new file mode 100644 index 0000000..6edb2a2 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-read-template.html @@ -0,0 +1,4 @@ + +{{property.value.name|limitTo:20}} +... +PROPERTY.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-write-template.html new file mode 100644 index 0000000..2ca6944 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/planitem-dropdown-write-template.html @@ -0,0 +1,5 @@ + +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-historylevel-property-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-historylevel-property-write-template.html new file mode 100644 index 0000000..bd4efa1 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-historylevel-property-write-template.html @@ -0,0 +1,10 @@ + +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-display-template.html new file mode 100644 index 0000000..9447d08 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-display-template.html @@ -0,0 +1,3 @@ + +{{property.value.name}} +PROPERTY.PROCESSREFERENCE.EMPTY diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-popup.html new file mode 100644 index 0000000..a8b3067 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-popup.html @@ -0,0 +1,45 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-write-template.html new file mode 100644 index 0000000..56461a1 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/process-reference-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-display-template.html new file mode 100644 index 0000000..90f50e9 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-display-template.html @@ -0,0 +1,3 @@ + +PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY +PROPERTY.SEQUENCEFLOW.ORDER.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-popup.html new file mode 100644 index 0000000..2bc6542 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-popup.html @@ -0,0 +1,47 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-write-template.html new file mode 100644 index 0000000..dd56210 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/sequenceflow-order-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-display-template.html new file mode 100644 index 0000000..7fa105b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.SIGNALDEFINITIONS.DISPLAY' | translate:property.value}} +PROPERTY.SIGNALDEFINITIONS.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-popup.html new file mode 100644 index 0000000..5f21ed7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-popup.html @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-write-template.html new file mode 100644 index 0000000..0ee1953 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-definitions-write-template.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-property-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-property-write-template.html new file mode 100644 index 0000000..b8da432 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/signal-property-write-template.html @@ -0,0 +1,4 @@ +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/string-property-write-mode-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/string-property-write-mode-template.html new file mode 100644 index 0000000..62c3323 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/string-property-write-mode-template.html @@ -0,0 +1,9 @@ + +
+ +
\ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-display-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-display-template.html new file mode 100644 index 0000000..4d07171 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-display-template.html @@ -0,0 +1,3 @@ + +{{'PROPERTY.TASKLISTENERS.VALUE' | translate:property.value.taskListeners}} +PROPERTY.TASKLISTENERS.EMPTY \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-popup.html new file mode 100644 index 0000000..1c50b5a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-popup.html @@ -0,0 +1,102 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-write-template.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-write-template.html new file mode 100644 index 0000000..dda53a1 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/task-listeners-write-template.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/text-popup.html b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/text-popup.html new file mode 100644 index 0000000..98bab62 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/configuration/properties/text-popup.html @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/popups/select-shape.html b/zbf-admin/src/main/resources/static/designer/editor-app/popups/select-shape.html new file mode 100644 index 0000000..ad4ba81 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/popups/select-shape.html @@ -0,0 +1,18 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/popups/unsaved-changes.html b/zbf-admin/src/main/resources/static/designer/editor-app/popups/unsaved-changes.html new file mode 100644 index 0000000..45325c0 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/popups/unsaved-changes.html @@ -0,0 +1,23 @@ + + diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/popups/validate-model.html b/zbf-admin/src/main/resources/static/designer/editor-app/popups/validate-model.html new file mode 100644 index 0000000..824e5e7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/popups/validate-model.html @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/process-navigator-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/process-navigator-controller.js new file mode 100644 index 0000000..fe9ff29 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/process-navigator-controller.js @@ -0,0 +1,81 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +angular.module('flowableModeler').controller('ProcessNavigatorController',['editorManager', '$scope',function(editorManager, $scope){ + //problem here the ORYX editor is bound to the rootscope. In theory this communication should be moved to a service. + + $scope.showSubProcess = function(child){ + var flowableShapes = editorManager.getChildShapeByResourceId(child.resourceId); + editorManager.setSelection([flowableShapes],[],true); + } + + $scope.treeview = {}; + $scope.isEditorReady = false; + + $scope.edit = function(resourceId){ + editorManager.edit(resourceId); + }; + + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_EDITOR_READY, function(event){ + $scope.isEditorReady = true; + renderProcessHierarchy(); + + editorManager.registerOnEvent(ORYX.CONFIG.ACTION_DELETE_COMPLETED, filterEvent); + + //always a single event. + editorManager.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_ROLLBACK, renderProcessHierarchy); + }) + + //if an element is added te properties will catch this event. + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED,filterEvent); + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_ITEM_DROPPED,filterEvent); + FLOWABLE.eventBus.addListener("EDITORMANAGER-EDIT-ACTION",function(){ + renderProcessHierarchy(); + }); + + function filterEvent(event){ + //this event is fired when the user changes a property by the property editor. + if(event.type === "event-type-property-value-changed"){ + if(event.property.key === "oryx-overrideid" || event.property.key === "oryx-name"){ + renderProcessHierarchy() + } + //this event is fired when the stencil / shape's text is changed / updated. + }else if(event.type === "propertyChanged"){ + if(event.name === "oryx-overrideid" || event.name === "oryx-name"){ + renderProcessHierarchy(); + } + }else if(event.type === ORYX.CONFIG.ACTION_DELETE_COMPLETED){ + renderProcessHierarchy(); + //for some reason the new tree does not trigger an ui update. + //$scope.$apply(); + }else if(event.type === "event-type-item-dropped"){ + renderProcessHierarchy(); + } + } + + function renderProcessHierarchy(){ + //only start calculating when the editor has done all his constructor work. + if(!$scope.isEditorReady){ + return false; + } + + if (!editorManager.isLoading()){ + //the current implementation of has a lot of eventlisteners. when calling getTree() it could manipulate + //the canvastracker while the canvas is stille loading stuff. + //TODO: check if its possible to trigger the re-rendering by a single event instead of registering on 10 events... + $scope.treeview = editorManager.getTree(); + } + + } + +}]); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/select-shape-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/select-shape-controller.js new file mode 100644 index 0000000..d752e07 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/select-shape-controller.js @@ -0,0 +1,318 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Controller for morph shape selection + */ + +angular.module('flowableModeler').controller('FlowableBpmShapeSelectionCtrl', + [ '$rootScope', '$scope', '$timeout', '$translate', 'editorManager', function($rootScope, $scope, $timeout, $translate, editorManager) { + + $scope.currentSelectedMorph = undefined; + + $scope.availableMorphShapes = []; + + for (var i = 0; i < $scope.morphShapes.length; i++) { + if ($scope.morphShapes[i].id != $scope.currentSelectedShape.getStencil().idWithoutNs()) { + $scope.availableMorphShapes.push($scope.morphShapes[i]); + } + } + + // Config for grid + $scope.gridOptions = { + data: $scope.availableMorphShapes, + headerRowHeight: 28, + enableRowSelection: true, + enableRowHeaderSelection: false, + multiSelect: false, + modifierKeysToMultiSelect: false, + enableHorizontalScrollbar: 0, + enableColumnMenus: false, + enableSorting: false, + columnDefs: [{ field: 'objectId', displayName: 'Icon', width: 50, cellTemplate: 'editor-app/popups/icon-template.html?version=' + Date.now() }, + { field: 'name', displayName: 'Name', cellTemplate: '
{{"" + row.entity[col.field] | translate}}
'}] + }; + + $scope.gridOptions.onRegisterApi = function(gridApi) { + //set gridApi on scope + $scope.gridApi = gridApi; + gridApi.selection.on.rowSelectionChanged($scope, function(row) { + if (row.isSelected) { + $scope.currentSelectedMorph = row.entity; + } else { + $scope.currentSelectedMorph = undefined; + } + }); + }; + + // Click handler for save button + $scope.select = function() { + + if ($scope.currentSelectedMorph) { + var MorphTo = ORYX.Core.Command.extend({ + construct: function(shape, stencil, facade){ + this.shape = shape; + this.stencil = stencil; + this.facade = facade; + }, + execute: function(){ + + var shape = this.shape; + var stencil = this.stencil; + var resourceId = shape.resourceId; + + // Serialize all attributes + var serialized = shape.serialize(); + stencil.properties().each((function(prop) { + if(prop.readonly()) { + serialized = serialized.reject(function(serProp) { + return serProp.name==prop.id(); + }); + } + }).bind(this)); + + // Get shape if already created, otherwise create a new shape + if (this.newShape){ + newShape = this.newShape; + this.facade.getCanvas().add(newShape); + } else { + newShape = this.facade.createShape({ + type: stencil.id(), + namespace: stencil.namespace(), + resourceId: resourceId + }); + } + + // calculate new bounds using old shape's upperLeft and new shape's width/height + var boundsObj = serialized.find(function(serProp){ + return (serProp.prefix === "oryx" && serProp.name === "bounds"); + }); + + var changedBounds = null; + + if (!this.facade.getRules().preserveBounds(shape.getStencil())) { + + var bounds = boundsObj.value.split(","); + if (parseInt(bounds[0], 10) > parseInt(bounds[2], 10)) { // if lowerRight comes first, swap array items + var tmp = bounds[0]; + bounds[0] = bounds[2]; + bounds[2] = tmp; + tmp = bounds[1]; + bounds[1] = bounds[3]; + bounds[3] = tmp; + } + bounds[2] = parseInt(bounds[0], 10) + newShape.bounds.width(); + bounds[3] = parseInt(bounds[1], 10) + newShape.bounds.height(); + boundsObj.value = bounds.join(","); + + } else { + + var height = shape.bounds.height(); + var width = shape.bounds.width(); + + // consider the minimum and maximum size of + // the new shape + + if (newShape.minimumSize) { + if (shape.bounds.height() < newShape.minimumSize.height) { + height = newShape.minimumSize.height; + } + + + if (shape.bounds.width() < newShape.minimumSize.width) { + width = newShape.minimumSize.width; + } + } + + if (newShape.maximumSize) { + if (shape.bounds.height() > newShape.maximumSize.height) { + height = newShape.maximumSize.height; + } + + if (shape.bounds.width() > newShape.maximumSize.width) { + width = newShape.maximumSize.width; + } + } + + changedBounds = { + a : { + x: shape.bounds.a.x, + y: shape.bounds.a.y + }, + b : { + x: shape.bounds.a.x + width, + y: shape.bounds.a.y + height + } + }; + + } + + var oPos = shape.bounds.center(); + if (changedBounds !== null) { + newShape.bounds.set(changedBounds); + } + + // Set all related dockers + this.setRelatedDockers(shape, newShape); + + // store DOM position of old shape + var parentNode = shape.node.parentNode; + var nextSibling = shape.node.nextSibling; + + // Delete the old shape + this.facade.deleteShape(shape); + + // Deserialize the new shape - Set all attributes + newShape.deserialize(serialized); + /* + * Change color to default if unchanged + * 23.04.2010 + */ + if (shape.getStencil().property("oryx-bgcolor") + && shape.properties["oryx-bgcolor"] + && shape.getStencil().property("oryx-bgcolor").value().toUpperCase()== shape.properties["oryx-bgcolor"].toUpperCase()){ + if (newShape.getStencil().property("oryx-bgcolor")){ + newShape.setProperty("oryx-bgcolor", newShape.getStencil().property("oryx-bgcolor").value()); + } + } + + if (changedBounds !== null) { + newShape.bounds.set(changedBounds); + } + + if (newShape.getStencil().type()==="edge" || (newShape.dockers.length==0 || !newShape.dockers[0].getDockedShape())) { + newShape.bounds.centerMoveTo(oPos); + } + + if (newShape.getStencil().type()==="node" && (newShape.dockers.length==0 || !newShape.dockers[0].getDockedShape())) { + this.setRelatedDockers(newShape, newShape); + + } + + // place at the DOM position of the old shape + if(nextSibling) parentNode.insertBefore(newShape.node, nextSibling); + else parentNode.appendChild(newShape.node); + + // Set selection + this.facade.setSelection([newShape]); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + this.newShape = newShape; + + }, + rollback: function(){ + + if (!this.shape || !this.newShape || !this.newShape.parent) {return;} + + // Append shape to the parent + this.newShape.parent.add(this.shape); + // Set dockers + this.setRelatedDockers(this.newShape, this.shape); + // Delete new shape + this.facade.deleteShape(this.newShape); + // Set selection + this.facade.setSelection([this.shape]); + // Update + this.facade.getCanvas().update(); + this.facade.updateSelection(); + }, + + /** + * Set all incoming and outgoing edges from the shape to the new shape + * @param {Shape} shape + * @param {Shape} newShape + */ + setRelatedDockers: function(shape, newShape){ + + if(shape.getStencil().type()==="node") { + + (shape.incoming||[]).concat(shape.outgoing||[]) + .each(function(i) { + i.dockers.each(function(docker) { + if (docker.getDockedShape() == shape) { + var rPoint = Object.clone(docker.referencePoint); + // Move reference point per percent + + var rPointNew = { + x: rPoint.x*newShape.bounds.width()/shape.bounds.width(), + y: rPoint.y*newShape.bounds.height()/shape.bounds.height() + }; + + docker.setDockedShape(newShape); + // Set reference point and center to new position + docker.setReferencePoint(rPointNew); + if(i instanceof ORYX.Core.Edge) { + docker.bounds.centerMoveTo(rPointNew); + } else { + var absXY = shape.absoluteXY(); + docker.bounds.centerMoveTo({x:rPointNew.x+absXY.x, y:rPointNew.y+absXY.y}); + //docker.bounds.moveBy({x:rPointNew.x-rPoint.x, y:rPointNew.y-rPoint.y}); + } + } + }); + }); + + // for attached events + if(shape.dockers.length>0&&shape.dockers.first().getDockedShape()) { + newShape.dockers.first().setDockedShape(shape.dockers.first().getDockedShape()); + newShape.dockers.first().setReferencePoint(Object.clone(shape.dockers.first().referencePoint)); + } + + } else { // is edge + newShape.dockers.first().setDockedShape(shape.dockers.first().getDockedShape()); + newShape.dockers.first().setReferencePoint(shape.dockers.first().referencePoint); + newShape.dockers.last().setDockedShape(shape.dockers.last().getDockedShape()); + newShape.dockers.last().setReferencePoint(shape.dockers.last().referencePoint); + } + } + }); + + var stencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + + var stencilId = $scope.currentSelectedMorph.id; + if ($scope.currentSelectedMorph.genericTaskId) { + stencilId = $scope.currentSelectedMorph.genericTaskId; + } + + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === stencilId) { + stencil = nodes[j]; + break; + } + } + } + + if (!stencil) return; + + // Create and execute command (for undo/redo) + var command = new MorphTo($scope.currentSelectedShape, stencil, editorManager.getEditor()); + editorManager.executeCommands([command]); + } + + $scope.close(); + }; + + $scope.cancel = function() { + $scope.$hide(); + }; + + // Close button handler + $scope.close = function() { + $scope.$hide(); + }; + +}]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencil-controller.js b/zbf-admin/src/main/resources/static/designer/editor-app/stencil-controller.js new file mode 100644 index 0000000..565001c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/stencil-controller.js @@ -0,0 +1,1487 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +angular.module('flowableModeler') + .controller('StencilController', ['$rootScope', '$scope', '$http', '$modal', '$timeout', '$window', 'editorManager', + function ($rootScope, $scope, $http, $modal, $timeout, $window, editorManager) { + + // Property window toggle state + $scope.propertyWindowState = {'collapsed': false}; + + // Add reference to global header-config + $scope.headerConfig = FLOWABLE.HEADER_CONFIG; + + $scope.propertyWindowState.toggle = function () { + $scope.propertyWindowState.collapsed = !$scope.propertyWindowState.collapsed; + $timeout(function () { + $window.dispatchEvent(new Event("resize")); + }, 100); + }; + + // Code that is dependent on an initialised Editor is wrapped in a promise for the editor + $scope.editorFactory.promise.then(function () { + + /* Build stencil item list */ + + // Build simple json representation of stencil set + var stencilItemGroups = []; + + // Helper method: find a group in an array + var findGroup = function (name, groupArray) { + for (var index = 0; index < groupArray.length; index++) { + if (groupArray[index].name === name) { + return groupArray[index]; + } + } + return null; + }; + + // Helper method: add a new group to an array of groups + var addGroup = function (groupName, groupArray) { + var group = {name: groupName, items: [], paletteItems: [], groups: [], visible: true}; + groupArray.push(group); + return group; + }; + + /* + StencilSet items + */ + var data = editorManager.getStencilData(); + + var quickMenuDefinition = undefined; + var ignoreForPaletteDefinition = undefined; + + if (data.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') { + quickMenuDefinition = ['HumanTask', 'Association']; + ignoreForPaletteDefinition = ['CasePlanModel']; + + } else { + quickMenuDefinition = ['UserTask', 'EndNoneEvent', 'ExclusiveGateway', + 'CatchTimerEvent', 'ThrowNoneEvent', 'TextAnnotation', + 'SequenceFlow', 'Association']; + + ignoreForPaletteDefinition = ['SequenceFlow', 'MessageFlow', 'Association', 'DataAssociation', 'DataStore', 'SendTask']; + } + + var quickMenuItems = []; + + var morphRoles = []; + for (var i = 0; i < data.rules.morphingRules.length; i++) { + var role = data.rules.morphingRules[i].role; + var roleItem = {'role': role, 'morphOptions': []}; + morphRoles.push(roleItem); + } + + // Check all received items + for (var stencilIndex = 0; stencilIndex < data.stencils.length; stencilIndex++) { + + // Check if the root group is the 'diagram' group. If so, this item should not be shown. + var currentGroupName = data.stencils[stencilIndex].groups[0]; + if (currentGroupName === 'Diagram' || currentGroupName === 'Form') { + continue; // go to next item + } + + var removed = false; + if (data.stencils[stencilIndex].removed) { + removed = true; + } + + var currentGroup = undefined; + if (!removed) { + // Check if this group already exists. If not, we create a new one + + if (currentGroupName !== null && currentGroupName !== undefined && currentGroupName.length > 0) { + + currentGroup = findGroup(currentGroupName, stencilItemGroups); // Find group in root groups array + if (currentGroup === null) { + currentGroup = addGroup(currentGroupName, stencilItemGroups); + } + + // Add all child groups (if any) + for (var groupIndex = 1; groupIndex < data.stencils[stencilIndex].groups.length; groupIndex++) { + var childGroupName = data.stencils[stencilIndex].groups[groupIndex]; + var childGroup = findGroup(childGroupName, currentGroup.groups); + if (childGroup === null) { + childGroup = addGroup(childGroupName, currentGroup.groups); + } + + // The current group variable holds the parent of the next group (if any), + // and is basically the last element in the array of groups defined in the stencil item + currentGroup = childGroup; + + } + + } + } + + // Construct the stencil item + var stencilItem = { + 'id': data.stencils[stencilIndex].id, + 'name': data.stencils[stencilIndex].title, + 'description': data.stencils[stencilIndex].description, + 'icon': data.stencils[stencilIndex].icon, + 'type': data.stencils[stencilIndex].type, + 'roles': data.stencils[stencilIndex].roles, + 'removed': removed, + 'customIcon': false, + 'canConnect': false, + 'canConnectTo': false, + 'canConnectAssociation': false + }; + + if (data.stencils[stencilIndex].customIconId && data.stencils[stencilIndex].customIconId > 0) { + stencilItem.customIcon = true; + stencilItem.icon = data.stencils[stencilIndex].customIconId; + } + + if (!removed) { + if (quickMenuDefinition.indexOf(stencilItem.id) >= 0) { + quickMenuItems[quickMenuDefinition.indexOf(stencilItem.id)] = stencilItem; + } + } + + if (stencilItem.id === 'TextAnnotation' || stencilItem.id === 'BoundaryCompensationEvent') { + stencilItem.canConnectAssociation = true; + } + + for (var i = 0; i < data.stencils[stencilIndex].roles.length; i++) { + var stencilRole = data.stencils[stencilIndex].roles[i]; + if (data.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') { + if (stencilRole === 'association_start') { + stencilItem.canConnect = true; + } else if (stencilRole === 'association_end') { + stencilItem.canConnectTo = true; + } + + } else { + if (stencilRole === 'sequence_start') { + stencilItem.canConnect = true; + } else if (stencilRole === 'sequence_end') { + stencilItem.canConnectTo = true; + } + } + + for (var j = 0; j < morphRoles.length; j++) { + if (stencilRole === morphRoles[j].role) { + if (!removed) { + morphRoles[j].morphOptions.push(stencilItem); + } + stencilItem.morphRole = morphRoles[j].role; + break; + } + } + } + + if (currentGroup) { + // Add the stencil item to the correct group + currentGroup.items.push(stencilItem); + if (ignoreForPaletteDefinition.indexOf(stencilItem.id) < 0) { + currentGroup.paletteItems.push(stencilItem); + } + + } else { + // It's a root stencil element + if (!removed) { + stencilItemGroups.push(stencilItem); + } + } + } + + for (var i = 0; i < stencilItemGroups.length; i++) { + if (stencilItemGroups[i].paletteItems && stencilItemGroups[i].paletteItems.length == 0) { + stencilItemGroups[i].visible = false; + } + } + + $scope.stencilItemGroups = stencilItemGroups; + + var containmentRules = []; + for (var i = 0; i < data.rules.containmentRules.length; i++) { + var rule = data.rules.containmentRules[i]; + containmentRules.push(rule); + } + $scope.containmentRules = containmentRules; + + // remove quick menu items which are not available anymore due to custom pallette + var availableQuickMenuItems = []; + for (var i = 0; i < quickMenuItems.length; i++) { + if (quickMenuItems[i]) { + availableQuickMenuItems[availableQuickMenuItems.length] = quickMenuItems[i]; + } + } + + $scope.quickMenuItems = availableQuickMenuItems; + $scope.morphRoles = morphRoles; + + /* + * Listen to selection change events: show properties + */ + editorManager.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { + var shapes = event.elements; + var canvasSelected = false; + if (shapes && shapes.length == 0) { + shapes = [editorManager.getCanvas()]; + canvasSelected = true; + } + if (shapes && shapes.length > 0) { + + var selectedShape = shapes.first(); + var stencil = selectedShape.getStencil(); + + if ($rootScope.selectedElementBeforeScrolling && stencil.id().indexOf('BPMNDiagram') !== -1 && stencil.id().indexOf('CMMNDiagram') !== -1) { + // ignore canvas event because of empty selection when scrolling stops + return; + } + + if ($rootScope.selectedElementBeforeScrolling && $rootScope.selectedElementBeforeScrolling.getId() === selectedShape.getId()) { + $rootScope.selectedElementBeforeScrolling = null; + return; + } + + // Store previous selection + $scope.previousSelectedShape = $scope.selectedShape; + + // Only do something if another element is selected (Oryx fires this event multiple times) + if ($scope.selectedShape !== undefined && $scope.selectedShape.getId() === selectedShape.getId()) { + if ($rootScope.forceSelectionRefresh) { + // Switch the flag again, this run will force refresh + $rootScope.forceSelectionRefresh = false; + } else { + // Selected the same element again, no need to update anything + return; + } + } + + var selectedItem = {'title': '', 'properties': []}; + + if (canvasSelected) { + selectedItem.auditData = { + 'author': $scope.modelData.createdByUser, + 'createDate': $scope.modelData.createDate + }; + } + + // Gather properties of selected item + var properties = stencil.properties(); + for (var i = 0; i < properties.length; i++) { + var property = properties[i]; + if (property.popular() == false) continue; + var key = property.prefix() + "-" + property.id(); + + if (key === 'oryx-name') { + selectedItem.title = selectedShape.properties.get(key); + } + + // First we check if there is a config for 'key-type' and then for 'type' alone + var propertyConfig = FLOWABLE.PROPERTY_CONFIG[key + '-' + property.type()]; + if (propertyConfig === undefined || propertyConfig === null) { + propertyConfig = FLOWABLE.PROPERTY_CONFIG[property.type()]; + } + + if (propertyConfig === undefined || propertyConfig === null) { + console.log('WARNING: no property configuration defined for ' + key + ' of type ' + property.type()); + } else { + + if (selectedShape.properties.get(key) === 'true') { + selectedShape.properties.set(key, true); + } + + if (FLOWABLE.UI_CONFIG.showRemovedProperties == false && property.isHidden()) { + continue; + } + + var currentProperty = { + 'key': key, + 'title': property.title(), + 'description': property.description(), + 'type': property.type(), + 'mode': 'read', + 'hidden': property.isHidden(), + 'value': selectedShape.properties.get(key) + }; + + if ((currentProperty.type === 'complex' || currentProperty.type === 'multiplecomplex') && currentProperty.value && currentProperty.value.length > 0) { + try { + currentProperty.value = JSON.parse(currentProperty.value); + } catch (err) { + // ignore + } + } + + if (propertyConfig.readModeTemplateUrl !== undefined && propertyConfig.readModeTemplateUrl !== null) { + currentProperty.readModeTemplateUrl = propertyConfig.readModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; + } + if (propertyConfig.writeModeTemplateUrl !== null && propertyConfig.writeModeTemplateUrl !== null) { + currentProperty.writeModeTemplateUrl = propertyConfig.writeModeTemplateUrl + '?version=' + $rootScope.staticIncludeVersion; + } + + if (propertyConfig.templateUrl !== undefined && propertyConfig.templateUrl !== null) { + currentProperty.templateUrl = propertyConfig.templateUrl + '?version=' + $rootScope.staticIncludeVersion; + currentProperty.hasReadWriteMode = false; + } else { + currentProperty.hasReadWriteMode = true; + } + + if (currentProperty.value === undefined + || currentProperty.value === null + || currentProperty.value.length == 0) { + currentProperty.noValue = true; + } + + selectedItem.properties.push(currentProperty); + } + } + + // Need to wrap this in an $apply block, see http://jimhoskins.com/2012/12/17/angularjs-and-apply.html + $scope.safeApply(function () { + $scope.selectedItem = selectedItem; + $scope.selectedShape = selectedShape; + }); + + } else { + $scope.safeApply(function () { + $scope.selectedItem = {}; + $scope.selectedShape = null; + }); + } + }); + + editorManager.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, function (event) { + + FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); + var shapes = event.elements; + + if (shapes && shapes.length == 1) { + + var selectedShape = shapes.first(); + + var a = editorManager.getCanvas().node.getScreenCTM(); + + var absoluteXY = selectedShape.absoluteXY(); + + absoluteXY.x *= a.a; + absoluteXY.y *= a.d; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom === 1) { + absoluteXY.y = absoluteXY.y - jQuery("#canvasSection").offset().top + 5; + absoluteXY.x = absoluteXY.x - jQuery("#canvasSection").offset().left; + + } else { + var canvasOffsetLeft = jQuery("#canvasSection").offset().left; + var canvasScrollLeft = jQuery("#canvasSection").scrollLeft(); + var canvasScrollTop = jQuery("#canvasSection").scrollTop(); + + var offset = a.e - (canvasOffsetLeft * additionalIEZoom); + var additionaloffset = 0; + if (offset > 10) { + additionaloffset = (offset / additionalIEZoom) - offset; + } + absoluteXY.y = absoluteXY.y - (jQuery("#canvasSection").offset().top * additionalIEZoom) + 5 + ((canvasScrollTop * additionalIEZoom) - canvasScrollTop); + absoluteXY.x = absoluteXY.x - (canvasOffsetLeft * additionalIEZoom) + additionaloffset + ((canvasScrollLeft * additionalIEZoom) - canvasScrollLeft); + } + + var bounds = new ORYX.Core.Bounds(a.e + absoluteXY.x, a.f + absoluteXY.y, a.e + absoluteXY.x + a.a * selectedShape.bounds.width(), a.f + absoluteXY.y + a.d * selectedShape.bounds.height()); + var shapeXY = bounds.upperLeft(); + + var stencilItem = $scope.getStencilItemById(selectedShape.getStencil().idWithoutNs()); + var morphShapes = []; + if (stencilItem && stencilItem.morphRole) { + for (var i = 0; i < $scope.morphRoles.length; i++) { + if ($scope.morphRoles[i].role === stencilItem.morphRole) { + morphShapes = $scope.morphRoles[i].morphOptions; + } + } + } + + var x = shapeXY.x; + if (bounds.width() < 48) { + x -= 24; + } + + if (morphShapes && morphShapes.length > 0) { + // In case the element is not wide enough, start the 2 bottom-buttons more to the left + // to prevent overflow in the right-menu + + var morphButton = document.getElementById('morph-button'); + morphButton.style.display = "block"; + morphButton.style.left = x + 24 + 'px'; + morphButton.style.top = (shapeXY.y + bounds.height() + 2) + 'px'; + } + + var deleteButton = document.getElementById('delete-button'); + deleteButton.style.display = "block"; + deleteButton.style.left = x + 'px'; + deleteButton.style.top = (shapeXY.y + bounds.height() + 2) + 'px'; + + var editable = selectedShape._stencil._jsonStencil.id.endsWith('CollapsedSubProcess'); + var editButton = document.getElementById('edit-button'); + if (editable) { + editButton.style.display = "block"; + if (morphShapes && morphShapes.length > 0) { + editButton.style.left = x + 24 + 24 + 'px'; + } else { + editButton.style.left = x + 24 + 'px'; + } + editButton.style.top = (shapeXY.y + bounds.height() + 2) + 'px'; + + } else { + editButton.style.display = "none"; + } + + if (stencilItem && (stencilItem.canConnect || stencilItem.canConnectAssociation)) { + var quickButtonCounter = 0; + var quickButtonX = shapeXY.x + bounds.width() + 5; + var quickButtonY = shapeXY.y; + jQuery('.Oryx_button').each(function (i, obj) { + if (obj.id !== 'morph-button' && obj.id != 'delete-button' && obj.id !== 'edit-button') { + quickButtonCounter++; + if (quickButtonCounter > 3) { + quickButtonX = shapeXY.x + bounds.width() + 5; + quickButtonY += 24; + quickButtonCounter = 1; + + } else if (quickButtonCounter > 1) { + quickButtonX += 24; + } + + obj.style.display = "block"; + obj.style.left = quickButtonX + 'px'; + obj.style.top = quickButtonY + 'px'; + } + }); + } + } + }); + + if (!$rootScope.stencilInitialized) { + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS, function (event) { + jQuery('.Oryx_button').each(function (i, obj) { + obj.style.display = "none"; + }); + }); + + /* + * Listen to property updates and act upon them + */ + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, function (event) { + if (event.property && event.property.key) { + // If the name property is been updated, we also need to change the title of the currently selected item + if (event.property.key === 'oryx-name' && $scope.selectedItem !== undefined && $scope.selectedItem !== null) { + $scope.selectedItem.title = event.newValue; + } + + // Update "no value" flag + event.property.noValue = (event.property.value === undefined + || event.property.value === null + || event.property.value.length == 0); + } + }); + + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_SHOW_VALIDATION_POPUP, function (event) { + // Method to open validation dialog + var showValidationDialog = function () { + $rootScope.currentValidationId = event.validationId; + $rootScope.isOnProcessLevel = event.onProcessLevel; + + _internalCreateModal({template: 'editor-app/popups/validation-errors.html?version=' + Date.now()}, $modal, $rootScope); + }; + + showValidationDialog(); + }); + + FLOWABLE.eventBus.addListener(FLOWABLE.eventBus.EVENT_TYPE_NAVIGATE_TO_PROCESS, function (event) { + var modelMetaData = editorManager.getBaseModelData(); + $rootScope.editorHistory.push({ + id: modelMetaData.modelId, + name: modelMetaData.name, + type: 'bpmnmodel' + }); + + $window.location.href = "../editor/#/editor/" + event.processId; + }); + + $rootScope.stencilInitialized = true; + } + + $scope.morphShape = function () { + $scope.safeApply(function () { + + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + $rootScope.currentSelectedShape = shapes.first(); + var stencilItem = $scope.getStencilItemById($rootScope.currentSelectedShape.getStencil().idWithoutNs()); + var morphShapes = []; + for (var i = 0; i < $scope.morphRoles.length; i++) { + if ($scope.morphRoles[i].role === stencilItem.morphRole) { + morphShapes = $scope.morphRoles[i].morphOptions.slice(); + } + } + + // Method to open shape select dialog (used later on) + var showSelectShapeDialog = function () { + $rootScope.morphShapes = morphShapes; + _internalCreateModal({ + backdrop: false, + keyboard: true, + template: 'editor-app/popups/select-shape.html?version=' + Date.now() + }, $modal, $rootScope); + }; + + showSelectShapeDialog(); + } + }); + }; + + $scope.deleteShape = function () { + FLOWABLE.TOOLBAR.ACTIONS.deleteItem({'$scope': $scope, 'editorManager': editorManager}); + }; + + $scope.quickAddItem = function (newItemId) { + $scope.safeApply(function () { + + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + $rootScope.currentSelectedShape = shapes.first(); + + var containedStencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === newItemId) { + containedStencil = nodes[j]; + break; + } + } + } + + if (!containedStencil) return; + + var option = { + type: $scope.currentSelectedShape.getStencil().namespace() + newItemId, + namespace: $scope.currentSelectedShape.getStencil().namespace() + }; + option['connectedShape'] = $rootScope.currentSelectedShape; + option['parent'] = $rootScope.currentSelectedShape.parent; + option['containedStencil'] = containedStencil; + + var args = {sourceShape: $rootScope.currentSelectedShape, targetStencil: containedStencil}; + var targetStencil = editorManager.getRules().connectMorph(args); + + // Check if there can be a target shape + if (!targetStencil) { + return; + } + + option['connectingType'] = targetStencil.id(); + + var command = new FLOWABLE.CreateCommand(option, undefined, undefined, editorManager.getEditor()); + + editorManager.executeCommands([command]); + } + }); + }; + + $scope.editShape = function () { + editorManager.edit($scope.selectedShape.resourceId); + }; + + }); // end of $scope.editorFactory.promise block + + /* Click handler for clicking a property */ + $scope.propertyClicked = function (index) { + if (!$scope.selectedItem.properties[index].hidden) { + $scope.selectedItem.properties[index].mode = "write"; + } + }; + + /* Helper method to retrieve the template url for a property */ + $scope.getPropertyTemplateUrl = function (index) { + return $scope.selectedItem.properties[index].templateUrl; + }; + $scope.getPropertyReadModeTemplateUrl = function (index) { + return $scope.selectedItem.properties[index].readModeTemplateUrl; + }; + $scope.getPropertyWriteModeTemplateUrl = function (index) { + return $scope.selectedItem.properties[index].writeModeTemplateUrl; + }; + + /* Method available to all sub controllers (for property controllers) to update the internal Oryx model */ + $scope.updatePropertyInModel = function (property, shapeId) { + + var shape = $scope.selectedShape; + // Some updates may happen when selected shape is already changed, so when an additional + // shapeId is supplied, we need to make sure the correct shape is updated (current or previous) + if (shapeId) { + if (shape.id != shapeId && $scope.previousSelectedShape && $scope.previousSelectedShape.id == shapeId) { + shape = $scope.previousSelectedShape; + } else { + shape = null; + } + } + + if (!shape) { + // When no shape is selected, or no shape is found for the alternative + // shape ID, do nothing + return; + } + var key = property.key; + var newValue = property.value; + var oldValue = shape.properties.get(key); + + if (newValue != oldValue) { + var commandClass = ORYX.Core.Command.extend({ + construct: function () { + this.key = key; + this.oldValue = oldValue; + this.newValue = newValue; + this.shape = shape; + this.facade = editorManager.getEditor(); + }, + execute: function () { + this.shape.setProperty(this.key, this.newValue); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + }, + rollback: function () { + this.shape.setProperty(this.key, this.oldValue); + this.facade.getCanvas().update(); + this.facade.updateSelection(); + } + }); + // Instantiate the class + var command = new commandClass(); + + // Execute the command + editorManager.executeCommands([command]); + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED, + elements: [shape], + key: key + }); + + // Switch the property back to read mode, now the update is done + property.mode = 'read'; + + // Fire event to all who is interested + // Fire event to all who want to know about this + var event = { + type: FLOWABLE.eventBus.EVENT_TYPE_PROPERTY_VALUE_CHANGED, + property: property, + oldValue: oldValue, + newValue: newValue + }; + FLOWABLE.eventBus.dispatch(event.type, event); + } else { + // Switch the property back to read mode, no update was needed + property.mode = 'read'; + } + + }; + + /** + * Helper method that searches a group for an item with the given id. + * If not found, will return undefined. + */ + $scope.findStencilItemInGroup = function (stencilItemId, group) { + + var item; + + // Check all items directly in this group + for (var j = 0; j < group.items.length; j++) { + item = group.items[j]; + if (item.id === stencilItemId) { + return item; + } + } + + // Check the child groups + if (group.groups && group.groups.length > 0) { + for (var k = 0; k < group.groups.length; k++) { + item = $scope.findStencilItemInGroup(stencilItemId, group.groups[k]); + if (item) { + return item; + } + } + } + + return undefined; + }; + + /** + * Helper method to find a stencil item. + */ + $scope.getStencilItemById = function (stencilItemId) { + for (var i = 0; i < $scope.stencilItemGroups.length; i++) { + var element = $scope.stencilItemGroups[i]; + + // Real group + if (element.items !== null && element.items !== undefined) { + var item = $scope.findStencilItemInGroup(stencilItemId, element); + if (item) { + return item; + } + } else { // Root stencil item + if (element.id === stencilItemId) { + return element; + } + } + } + return undefined; + }; + + /* + * DRAG AND DROP FUNCTIONALITY + */ + + $scope.dropCallback = function (event, ui) { + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.added" + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeMenu" + }); + + FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_HIDE_SHAPE_BUTTONS); + + if ($scope.dragCanContain) { + + var item = $scope.getStencilItemById(ui.draggable[0].id); + + var pos = {x: event.pageX, y: event.pageY}; + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100; + } + } + } + + var screenCTM = editorManager.getCanvas().node.getScreenCTM(); + + // Correcting the UpperLeft-Offset + pos.x -= (screenCTM.e / additionalIEZoom); + pos.y -= (screenCTM.f / additionalIEZoom); + // Correcting the Zoom-Factor + pos.x /= screenCTM.a; + pos.y /= screenCTM.d; + + // Correcting the ScrollOffset + pos.x -= document.documentElement.scrollLeft; + pos.y -= document.documentElement.scrollTop; + + var parentAbs = $scope.dragCurrentParent.absoluteXY(); + pos.x -= parentAbs.x; + pos.y -= parentAbs.y; + + var containedStencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === ui.draggable[0].id) { + containedStencil = nodes[j]; + break; + } + } + + if (!containedStencil) { + var edges = stencilSet.edges(); + for (var j = 0; j < edges.length; j++) { + if (edges[j].idWithoutNs() === ui.draggable[0].id) { + containedStencil = edges[j]; + break; + } + } + } + } + + if (!containedStencil) return; + + if ($scope.quickMenu) { + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + var currentSelectedShape = shapes.first(); + + var option = {}; + option.type = currentSelectedShape.getStencil().namespace() + ui.draggable[0].id; + option.namespace = currentSelectedShape.getStencil().namespace(); + option.connectedShape = currentSelectedShape; + option.parent = $scope.dragCurrentParent; + option.containedStencil = containedStencil; + + // If the ctrl key is not pressed, + // snapp the new shape to the center + // if it is near to the center of the other shape + if (!event.ctrlKey) { + // Get the center of the shape + var cShape = currentSelectedShape.bounds.center(); + // Snapp +-20 Pixel horizontal to the center + if (20 > Math.abs(cShape.x - pos.x)) { + pos.x = cShape.x; + } + // Snapp +-20 Pixel vertical to the center + if (20 > Math.abs(cShape.y - pos.y)) { + pos.y = cShape.y; + } + } + + option.position = pos; + + if (containedStencil.idWithoutNs() !== 'SequenceFlow' && containedStencil.idWithoutNs() !== 'Association' && + containedStencil.idWithoutNs() !== 'MessageFlow' && containedStencil.idWithoutNs() !== 'DataAssociation') { + + var args = {sourceShape: currentSelectedShape, targetStencil: containedStencil}; + var targetStencil = editorManager.getRules().connectMorph(args); + if (!targetStencil) { // Check if there can be a target shape + return; + } + option.connectingType = targetStencil.id(); + } + + var command = new FLOWABLE.CreateCommand(option, $scope.dropTargetElement, pos, editorManager.getEditor()); + + editorManager.executeCommands([command]); + } + + } else { + var canAttach = false; + if (containedStencil.idWithoutNs() === 'BoundaryErrorEvent' || containedStencil.idWithoutNs() === 'BoundaryTimerEvent' || + containedStencil.idWithoutNs() === 'BoundarySignalEvent' || containedStencil.idWithoutNs() === 'BoundaryMessageEvent' || + containedStencil.idWithoutNs() === 'BoundaryCancelEvent' || containedStencil.idWithoutNs() === 'BoundaryCompensationEvent') { + + // Modify position, otherwise boundary event will get position related to left corner of the canvas instead of the container + pos = editorManager.eventCoordinates(event); + canAttach = true; + } + + var option = {}; + option['type'] = $scope.modelData.model.stencilset.namespace + item.id; + option['namespace'] = $scope.modelData.model.stencilset.namespace; + option['position'] = pos; + option['parent'] = $scope.dragCurrentParent; + + var commandClass = ORYX.Core.Command.extend({ + construct: function (option, dockedShape, canAttach, position, facade) { + this.option = option; + this.docker = null; + this.dockedShape = dockedShape; + this.dockedShapeParent = dockedShape.parent || facade.getCanvas(); + this.position = position; + this.facade = facade; + this.selection = this.facade.getSelection(); + this.shape = null; + this.parent = null; + this.canAttach = canAttach; + }, + execute: function () { + if (!this.shape) { + this.shape = this.facade.createShape(option); + this.parent = this.shape.parent; + } else if (this.parent) { + this.parent.add(this.shape); + } + + if (this.canAttach && this.shape.dockers && this.shape.dockers.length) { + this.docker = this.shape.dockers[0]; + + this.dockedShapeParent.add(this.docker.parent); + + // Set the Docker to the new Shape + this.docker.setDockedShape(undefined); + this.docker.bounds.centerMoveTo(this.position); + if (this.dockedShape !== this.facade.getCanvas()) { + this.docker.setDockedShape(this.dockedShape); + } + this.facade.setSelection([this.docker.parent]); + } + + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + }, + rollback: function () { + if (this.shape) { + this.facade.setSelection(this.selection.without(this.shape)); + this.facade.deleteShape(this.shape); + } + if (this.canAttach && this.docker) { + this.docker.setDockedShape(undefined); + } + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + } + }); + + // Update canvas + var command = new commandClass(option, $scope.dragCurrentParent, canAttach, pos, editorManager.getEditor()); + editorManager.executeCommands([command]); + + // Fire event to all who want to know about this + var dropEvent = { + type: FLOWABLE.eventBus.EVENT_TYPE_ITEM_DROPPED, + droppedItem: item, + position: pos + }; + FLOWABLE.eventBus.dispatch(dropEvent.type, dropEvent); + } + } + + $scope.dragCurrentParent = undefined; + $scope.dragCurrentParentId = undefined; + $scope.dragCurrentParentStencil = undefined; + $scope.dragCanContain = undefined; + $scope.quickMenu = undefined; + $scope.dropTargetElement = undefined; + }; + + + $scope.overCallback = function (event, ui) { + $scope.dragModeOver = true; + }; + + $scope.outCallback = function (event, ui) { + $scope.dragModeOver = false; + }; + + $scope.startDragCallback = function (event, ui) { + $scope.dragModeOver = false; + $scope.quickMenu = false; + if (!ui.helper.hasClass('stencil-item-dragged')) { + ui.helper.addClass('stencil-item-dragged'); + } + }; + + $scope.startDragCallbackQuickMenu = function (event, ui) { + $scope.dragModeOver = false; + $scope.quickMenu = true; + }; + + $scope.dragCallback = function (event, ui) { + + if ($scope.dragModeOver != false) { + + var coord = editorManager.eventCoordinatesXY(event.pageX, event.pageY); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + coord.x = coord.x / additionalIEZoom; + coord.y = coord.y / additionalIEZoom; + } + + var aShapes = editorManager.getCanvas().getAbstractShapesAtPosition(coord); + + if (aShapes.length <= 0) { + if (event.helper) { + $scope.dragCanContain = false; + return false; + } + } + + if (aShapes[0] instanceof ORYX.Core.Canvas) { + editorManager.getCanvas().setHightlightStateBasedOnX(coord.x); + } + + if (aShapes.length == 1 && aShapes[0] instanceof ORYX.Core.Canvas) { + var item = $scope.getStencilItemById(event.target.id); + var parentCandidate = aShapes[0]; + + if (item.id === 'Lane' || item.id === 'BoundaryErrorEvent' || item.id === 'BoundaryMessageEvent' || + item.id === 'BoundarySignalEvent' || item.id === 'BoundaryTimerEvent' || + item.id === 'BoundaryCancelEvent' || item.id === 'BoundaryCompensationEvent' || + item.id === 'EntryCriterion') { + + $scope.dragCanContain = false; + + // Show Highlight + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeRepo.added', + elements: [parentCandidate], + style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, + color: ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + + } else { + $scope.dragCanContain = true; + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.added" + }); + } + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + + return false; + + } else { + var item = $scope.getStencilItemById(event.target.id); + + var parentCandidate = aShapes.reverse().find(function (candidate) { + return (candidate instanceof ORYX.Core.Canvas + || candidate instanceof ORYX.Core.Node + || candidate instanceof ORYX.Core.Edge); + }); + + if (!parentCandidate) { + $scope.dragCanContain = false; + return false; + } + + if (item.type === "node") { + + // check if the draggable is a boundary event and the parent an Activity + var _canContain = false; + var parentStencilId = parentCandidate.getStencil().id(); + + if ($scope.dragCurrentParentId && $scope.dragCurrentParentId === parentCandidate.id) { + return false; + } + + var parentItem = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); + if (parentItem.roles.indexOf('Activity') > -1) { + if (item.roles.indexOf('IntermediateEventOnActivityBoundary') > -1 + || item.roles.indexOf('EntryCriterionOnItemBoundary') > -1 + || item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { + _canContain = true; + } + + } else if (parentItem.roles.indexOf('StageActivity') > -1) { + if (item.roles.indexOf('EntryCriterionOnItemBoundary') > -1 + || item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { + _canContain = true; + } + + } else if (parentItem.roles.indexOf('StageModelActivity') > -1) { + if (item.roles.indexOf('ExitCriterionOnItemBoundary') > -1) { + _canContain = true; + } + + } else if (parentCandidate.getStencil().idWithoutNs() === 'Pool') { + if (item.id === 'Lane') { + _canContain = true; + } + } + + if (_canContain) { + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: "shapeRepo.attached", + elements: [parentCandidate], + style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE, + color: ORYX.CONFIG.SELECTION_VALID_COLOR + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.added" + }); + + } else { + for (var i = 0; i < $scope.containmentRules.length; i++) { + var rule = $scope.containmentRules[i]; + if (rule.role === parentItem.id) { + for (var j = 0; j < rule.contains.length; j++) { + if (item.roles.indexOf(rule.contains[j]) > -1) { + _canContain = true; + break; + } + } + + if (_canContain) { + break; + } + } + } + + // Show Highlight + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeRepo.added', + elements: [parentCandidate], + color: _canContain ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + } + + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + $scope.dragCurrentParentStencil = parentStencilId; + $scope.dragCanContain = _canContain; + + } else { + var canvasCandidate = editorManager.getCanvas(); + var canConnect = false; + + var targetStencil = $scope.getStencilItemById(parentCandidate.getStencil().idWithoutNs()); + if (targetStencil) { + var associationConnect = false; + if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { + associationConnect = true; + } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + associationConnect = true; + } + + if (targetStencil.canConnectTo || associationConnect) { + canConnect = true; + } + } + + //Edge + $scope.dragCurrentParent = canvasCandidate; + $scope.dragCurrentParentId = canvasCandidate.id; + $scope.dragCurrentParentStencil = canvasCandidate.getStencil().id(); + $scope.dragCanContain = canConnect; + + // Show Highlight + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeRepo.added', + elements: [canvasCandidate], + color: ORYX.CONFIG.SELECTION_VALID_COLOR + }); + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, + highlightId: "shapeRepo.attached" + }); + } + } + } + }; + + $scope.dragCallbackQuickMenu = function (event, ui) { + + if ($scope.dragModeOver != false) { + var coord = editorManager.eventCoordinatesXY(event.pageX, event.pageY); + + var additionalIEZoom = 1; + if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) { + var ua = navigator.userAgent; + if (ua.indexOf('MSIE') >= 0) { + //IE 10 and below + var zoom = Math.round((screen.deviceXDPI / screen.logicalXDPI) * 100); + if (zoom !== 100) { + additionalIEZoom = zoom / 100 + } + } + } + + if (additionalIEZoom !== 1) { + coord.x = coord.x / additionalIEZoom; + coord.y = coord.y / additionalIEZoom; + } + + var aShapes = editorManager.getCanvas().getAbstractShapesAtPosition(coord); + + if (aShapes.length <= 0) { + if (event.helper) { + $scope.dragCanContain = false; + return false; + } + } + + if (aShapes[0] instanceof ORYX.Core.Canvas) { + editorManager.getCanvas().setHightlightStateBasedOnX(coord.x); + } + + var stencil = undefined; + var stencilSets = editorManager.getStencilSets().values(); + for (var i = 0; i < stencilSets.length; i++) { + var stencilSet = stencilSets[i]; + var nodes = stencilSet.nodes(); + for (var j = 0; j < nodes.length; j++) { + if (nodes[j].idWithoutNs() === event.target.id) { + stencil = nodes[j]; + break; + } + } + + if (!stencil) { + var edges = stencilSet.edges(); + for (var j = 0; j < edges.length; j++) { + if (edges[j].idWithoutNs() === event.target.id) { + stencil = edges[j]; + break; + } + } + } + } + + var candidate = aShapes.last(); + + var isValid = false; + if (stencil.type() === "node") { + //check containment rules + var canContain = editorManager.getRules().canContain({ + containingShape: candidate, + containedStencil: stencil + }); + + var parentCandidate = aShapes.reverse().find(function (candidate) { + return (candidate instanceof ORYX.Core.Canvas + || candidate instanceof ORYX.Core.Node + || candidate instanceof ORYX.Core.Edge); + }); + + if (!parentCandidate) { + $scope.dragCanContain = false; + return false; + } + + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); + $scope.dragCanContain = canContain; + $scope.dropTargetElement = parentCandidate; + isValid = canContain; + + } else { //Edge + + var shapes = editorManager.getSelection(); + if (shapes && shapes.length == 1) { + var currentSelectedShape = shapes.first(); + var curCan = candidate; + var canConnect = false; + + var targetStencil = $scope.getStencilItemById(curCan.getStencil().idWithoutNs()); + if (targetStencil) { + var associationConnect = false; + if (stencil.idWithoutNs() === 'Association' && (curCan.getStencil().idWithoutNs() === 'TextAnnotation' || curCan.getStencil().idWithoutNs() === 'BoundaryCompensationEvent')) { + associationConnect = true; + } else if (stencil.idWithoutNs() === 'DataAssociation' && curCan.getStencil().idWithoutNs() === 'DataStore') { + associationConnect = true; + } + + if (targetStencil.canConnectTo || associationConnect) { + while (!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)) { + candidate = curCan; + //check connection rules + canConnect = editorManager.getRules().canConnect({ + sourceShape: currentSelectedShape, + edgeStencil: stencil, + targetShape: curCan + }); + curCan = curCan.parent; + } + } + } + var parentCandidate = editorManager.getCanvas(); + + isValid = canConnect; + $scope.dragCurrentParent = parentCandidate; + $scope.dragCurrentParentId = parentCandidate.id; + $scope.dragCurrentParentStencil = parentCandidate.getStencil().id(); + $scope.dragCanContain = canConnect; + $scope.dropTargetElement = candidate; + } + + } + + editorManager.handleEvents({ + type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, + highlightId: 'shapeMenu', + elements: [candidate], + color: isValid ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR + }); + } + }; + + }]); + +var FLOWABLE = FLOWABLE || {}; +//create command for undo/redo +FLOWABLE.CreateCommand = ORYX.Core.Command.extend({ + construct: function (option, currentReference, position, facade) { + this.option = option; + this.currentReference = currentReference; + this.position = position; + this.facade = facade; + this.shape; + this.edge; + this.targetRefPos; + this.sourceRefPos; + /* + * clone options parameters + */ + this.connectedShape = option.connectedShape; + this.connectingType = option.connectingType; + this.namespace = option.namespace; + this.type = option.type; + this.containedStencil = option.containedStencil; + this.parent = option.parent; + this.currentReference = currentReference; + this.shapeOptions = option.shapeOptions; + }, + execute: function () { + + if (this.shape) { + if (this.shape instanceof ORYX.Core.Node) { + this.parent.add(this.shape); + if (this.edge) { + this.facade.getCanvas().add(this.edge); + this.edge.dockers.first().setDockedShape(this.connectedShape); + this.edge.dockers.first().setReferencePoint(this.sourceRefPos); + this.edge.dockers.last().setDockedShape(this.shape); + this.edge.dockers.last().setReferencePoint(this.targetRefPos); + } + + this.facade.setSelection([this.shape]); + + } else if (this.shape instanceof ORYX.Core.Edge) { + this.facade.getCanvas().add(this.shape); + this.shape.dockers.first().setDockedShape(this.connectedShape); + this.shape.dockers.first().setReferencePoint(this.sourceRefPos); + } + } else { + this.shape = this.facade.createShape(this.option); + this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined; + } + + if (this.currentReference && this.position) { + + if (this.shape instanceof ORYX.Core.Edge) { + + if (!(this.currentReference instanceof ORYX.Core.Canvas)) { + this.shape.dockers.last().setDockedShape(this.currentReference); + + if (this.currentReference.getStencil().idWithoutNs() === 'TextAnnotation') { + var midpoint = {}; + midpoint.x = 0; + midpoint.y = this.currentReference.bounds.height() / 2; + this.shape.dockers.last().setReferencePoint(midpoint); + } else { + this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint()); + } + } else { + this.shape.dockers.last().bounds.centerMoveTo(this.position); + } + this.sourceRefPos = this.shape.dockers.first().referencePoint; + this.targetRefPos = this.shape.dockers.last().referencePoint; + + } else if (this.edge) { + this.sourceRefPos = this.edge.dockers.first().referencePoint; + this.targetRefPos = this.edge.dockers.last().referencePoint; + } + } else { + var containedStencil = this.containedStencil; + var connectedShape = this.connectedShape; + var bc = connectedShape.bounds; + var bs = this.shape.bounds; + + var pos = bc.center(); + if (containedStencil.defaultAlign() === "north") { + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "northeast") { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "southeast") { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "south") { + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "southwest") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else if (containedStencil.defaultAlign() === "west") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width() / 2); + } else if (containedStencil.defaultAlign() === "northwest") { + pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width() / 2); + pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height() / 2); + } else { + pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width() / 2); + } + + // Move shape to the new position + this.shape.bounds.centerMoveTo(pos); + + // Move all dockers of a node to the position + if (this.shape instanceof ORYX.Core.Node) { + (this.shape.dockers || []).each(function (docker) { + docker.bounds.centerMoveTo(pos); + }); + } + + //this.shape.update(); + this.position = pos; + + if (this.edge) { + this.sourceRefPos = this.edge.dockers.first().referencePoint; + this.targetRefPos = this.edge.dockers.last().referencePoint; + } + } + + this.facade.getCanvas().update(); + this.facade.updateSelection(); + + }, + rollback: function () { + this.facade.deleteShape(this.shape); + if (this.edge) { + this.facade.deleteShape(this.edge); + } + //this.currentParent.update(); + this.facade.setSelection(this.facade.getSelection().without(this.shape, this.edge)); + } +}); diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilset.json b/zbf-admin/src/main/resources/static/designer/editor-app/stencilset.json new file mode 100644 index 0000000..68d185b --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/stencilset.json @@ -0,0 +1,2116 @@ +{ + "title" : "BPMN.TITLE", + "namespace" : "http://b3mn.org/stencilset/bpmn2.0#", + "description" : "BPMN.DESCRIPTION", + "propertyPackages" : [ { + "name" : "process_idpackage", + "properties" : [ { + "id" : "process_id", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_IDPACKAGE.PROCESS_ID.TITLE", + "value" : "process", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_IDPACKAGE.PROCESS_ID.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "overrideidpackage", + "properties" : [ { + "id" : "overrideid", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.OVERRIDEIDPACKAGE.OVERRIDEID.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.OVERRIDEIDPACKAGE.OVERRIDEID.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "namepackage", + "properties" : [ { + "id" : "name", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.NAMEPACKAGE.NAME.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.NAMEPACKAGE.NAME.DESCRIPTION", + "popular" : true, + "refToView" : "text_name" + } ] + }, { + "name" : "documentationpackage", + "properties" : [ { + "id" : "documentation", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.DOCUMENTATIONPACKAGE.DOCUMENTATION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.DOCUMENTATIONPACKAGE.DOCUMENTATION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "categorypackage", + "properties" : [ { + "id" : "categorydefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.CATEGORYPACKAGE.CATEGORYDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CATEGORYPACKAGE.CATEGORYDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_authorpackage", + "properties" : [ { + "id" : "process_author", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_AUTHORPACKAGE.PROCESS_AUTHOR.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_AUTHORPACKAGE.PROCESS_AUTHOR.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_versionpackage", + "properties" : [ { + "id" : "process_version", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_VERSIONPACKAGE.PROCESS_VERSION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_VERSIONPACKAGE.PROCESS_VERSION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_historylevelpackage", + "properties" : [ { + "id" : "process_historylevel", + "type" : "flowable-processhistorylevel", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_HISTORYLEVELPACKAGE.PROCESS_HISTORYLEVEL.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_HISTORYLEVELPACKAGE.PROCESS_HISTORYLEVEL.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "isexecutablepackage", + "properties" : [ { + "id" : "isexecutable", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.ISEXECUTABLEPACKAGE.ISEXECUTABLE.TITLE", + "value" : "true", + "description" : "BPMN.PROPERTYPACKAGES.ISEXECUTABLEPACKAGE.ISEXECUTABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_potentialstarteruserpackage", + "properties" : [ { + "id" : "process_potentialstarteruser", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_POTENTIALSTARTERUSERPACKAGE.PROCESS_POTENTIALSTARTERUSER.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_POTENTIALSTARTERUSERPACKAGE.PROCESS_POTENTIALSTARTERUSER.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_potentialstartergrouppackage", + "properties" : [ { + "id" : "process_potentialstartergroup", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_POTENTIALSTARTERGROUPPACKAGE.PROCESS_POTENTIALSTARTERGROUP.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_POTENTIALSTARTERGROUPPACKAGE.PROCESS_POTENTIALSTARTERGROUP.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_namespacepackage", + "properties" : [ { + "id" : "process_namespace", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_NAMESPACEPACKAGE.PROCESS_NAMESPACE.TITLE", + "value" : "http://www.flowable.org/processdef", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_NAMESPACEPACKAGE.PROCESS_NAMESPACE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "process_iseagerexecutionfetchpackage", + "properties" : [ { + "id" : "iseagerexecutionfetch", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.PROCESS_ISEAGEREXECUTIONFETCHPACKAGE.ISEAGEREXECUTIONFETCH.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.PROCESS_ISEAGEREXECUTIONFETCHPACKAGE.ISEAGEREXECUTIONFETCH.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "asynchronousdefinitionpackage", + "properties" : [ { + "id" : "asynchronousdefinition", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.ASYNCHRONOUSDEFINITIONPACKAGE.ASYNCHRONOUSDEFINITION.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.ASYNCHRONOUSDEFINITIONPACKAGE.ASYNCHRONOUSDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "datapropertiespackage", + "properties" : [ { + "id" : "dataproperties", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.DATAPROPERTIESPACKAGE.DATAPROPERTIES.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.DATAPROPERTIESPACKAGE.DATAPROPERTIES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "exclusivedefinitionpackage", + "properties" : [ { + "id" : "exclusivedefinition", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.EXCLUSIVEDEFINITIONPACKAGE.EXCLUSIVEDEFINITION.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.EXCLUSIVEDEFINITIONPACKAGE.EXCLUSIVEDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "executionlistenerspackage", + "properties" : [ { + "id" : "executionlisteners", + "type" : "multiplecomplex", + "title" : "BPMN.PROPERTYPACKAGES.EXECUTIONLISTENERSPACKAGE.EXECUTIONLISTENERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.EXECUTIONLISTENERSPACKAGE.EXECUTIONLISTENERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "tasklistenerspackage", + "properties" : [ { + "id" : "tasklisteners", + "type" : "multiplecomplex", + "title" : "BPMN.PROPERTYPACKAGES.TASKLISTENERSPACKAGE.TASKLISTENERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.TASKLISTENERSPACKAGE.TASKLISTENERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "eventlistenerspackage", + "properties" : [ { + "id" : "eventlisteners", + "type" : "multiplecomplex", + "title" : "BPMN.PROPERTYPACKAGES.EVENTLISTENERSPACKAGE.EVENTLISTENERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.EVENTLISTENERSPACKAGE.EVENTLISTENERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "usertaskassignmentpackage", + "properties" : [ { + "id" : "usertaskassignment", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.USERTASKASSIGNMENTPACKAGE.USERTASKASSIGNMENT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.USERTASKASSIGNMENTPACKAGE.USERTASKASSIGNMENT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "formpropertiespackage", + "properties" : [ { + "id" : "formproperties", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.FORMPROPERTIESPACKAGE.FORMPROPERTIES.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.FORMPROPERTIESPACKAGE.FORMPROPERTIES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "formkeydefinitionpackage", + "properties" : [ { + "id" : "formkeydefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.FORMKEYDEFINITIONPACKAGE.FORMKEYDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.FORMKEYDEFINITIONPACKAGE.FORMKEYDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "formfieldvalidationpackage", + "properties" : [ { + "id" : "formfieldvalidation", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.FORMFIELDVALIDATIONPACKAGE.FORMFIELDVALIDATION.TITLE", + "value" : "true", + "description" : "BPMN.PROPERTYPACKAGES.FORMFIELDVALIDATIONPACKAGE.FORMFIELDVALIDATION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "duedatedefinitionpackage", + "properties" : [ { + "id" : "duedatedefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.DUEDATEDEFINITIONPACKAGE.DUEDATEDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.DUEDATEDEFINITIONPACKAGE.DUEDATEDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "prioritydefinitionpackage", + "properties" : [ { + "id" : "prioritydefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.PRIORITYDEFINITIONPACKAGE.PRIORITYDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.PRIORITYDEFINITIONPACKAGE.PRIORITYDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetaskclasspackage", + "properties" : [ { + "id" : "servicetaskclass", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKCLASSPACKAGE.SERVICETASKCLASS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKCLASSPACKAGE.SERVICETASKCLASS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetaskexpressionpackage", + "properties" : [ { + "id" : "servicetaskexpression", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKEXPRESSIONPACKAGE.SERVICETASKEXPRESSION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKEXPRESSIONPACKAGE.SERVICETASKEXPRESSION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetaskdelegateexpressionpackage", + "properties" : [ { + "id" : "servicetaskdelegateexpression", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKDELEGATEEXPRESSIONPACKAGE.SERVICETASKDELEGATEEXPRESSION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKDELEGATEEXPRESSIONPACKAGE.SERVICETASKDELEGATEEXPRESSION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetaskfieldspackage", + "properties" : [ { + "id" : "servicetaskfields", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKFIELDSPACKAGE.SERVICETASKFIELDS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKFIELDSPACKAGE.SERVICETASKFIELDS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetaskresultvariablepackage", + "properties" : [ { + "id" : "servicetaskresultvariable", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKRESULTVARIABLEPACKAGE.SERVICETASKRESULTVARIABLE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKRESULTVARIABLEPACKAGE.SERVICETASKRESULTVARIABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetaskresultvariablepackage", + "properties" : [ { + "id" : "servicetaskUseLocalScopeForResultVariable", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKRESULTVARIABLEPACKAGE.SERVICETASKUSELOCALSCOPEFORRESULTVARIABLE.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKRESULTVARIABLEPACKAGE.SERVICETASKUSELOCALSCOPEFORRESULTVARIABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "servicetasktriggerablepackage", + "properties" : [ { + "id" : "servicetasktriggerable", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.SERVICETASKTRIGGERABLEPACKAGE.SERVICETASKTRIGGERABLE.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.SERVICETASKTRIGGERABLEPACKAGE.SERVICETASKTRIGGERABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "scriptformatpackage", + "properties" : [ { + "id" : "scriptformat", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.SCRIPTFORMATPACKAGE.SCRIPTFORMAT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SCRIPTFORMATPACKAGE.SCRIPTFORMAT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "scripttextpackage", + "properties" : [ { + "id" : "scripttext", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SCRIPTTEXTPACKAGE.SCRIPTTEXT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SCRIPTTEXTPACKAGE.SCRIPTTEXT.DESCRIPTION", + "popular" : true + } + ] + }, { + "name" : "scriptautostorevariablespackage", + "properties" : [{ + "id" : "scriptautostorevariables", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.SCRIPTAUTOSTOREVARIABLESPACKAGE.SCRIPTAUTOSTOREVARIABLES.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.SCRIPTAUTOSTOREVARIABLESPACKAGE.SCRIPTAUTOSTOREVARIABLES.DESCRIPTION", + "popular" : true + }] + }, { + "name" : "shellcommandpackage", + "properties" : [ { + "id" : "shellcommand", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.SHELLCOMMANDPACKAGE.SHELLCOMMAND.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLCOMMANDPACKAGE.SHELLCOMMAND.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellarg1package", + "properties" : [ { + "id" : "shellarg1", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLARG1PACKAGE.SHELLARG1.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLARG1PACKAGE.SHELLARG1.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellarg2package", + "properties" : [ { + "id" : "shellarg2", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLARG2PACKAGE.SHELLARG2.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLARG2PACKAGE.SHELLARG2.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellarg3package", + "properties" : [ { + "id" : "shellarg3", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLARG3PACKAGE.SHELLARG3.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLARG3PACKAGE.SHELLARG3.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellarg4package", + "properties" : [ { + "id" : "shellarg4", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLARG4PACKAGE.SHELLARG4.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLARG4PACKAGE.SHELLARG4.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellarg5package", + "properties" : [ { + "id" : "shellarg5", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLARG5PACKAGE.SHELLARG5.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLARG5PACKAGE.SHELLARG5.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellwaitpackage", + "properties" : [ { + "id" : "shellwait", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLWAITPACKAGE.SHELLWAIT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLWAITPACKAGE.SHELLWAIT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shelloutputvariablepackage", + "properties" : [ { + "id" : "shelloutputvariable", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLOUTPUTVARIABLEPACKAGE.SHELLOUTPUTVARIABLE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLOUTPUTVARIABLEPACKAGE.SHELLOUTPUTVARIABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellerrorcodevariablepackage", + "properties" : [ { + "id" : "shellerrorcodevariable", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLERRORCODEVARIABLEPACKAGE.SHELLERRORCODEVARIABLE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLERRORCODEVARIABLEPACKAGE.SHELLERRORCODEVARIABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellredirecterrorpackage", + "properties" : [ { + "id" : "shellredirecterror", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLREDIRECTERRORPACKAGE.SHELLREDIRECTERROR.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLREDIRECTERRORPACKAGE.SHELLREDIRECTERROR.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shellcleanenvpackage", + "properties" : [ { + "id" : "shellcleanenv", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLCLEANENVPACKAGE.SHELLCLEANENV.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLCLEANENVPACKAGE.SHELLCLEANENV.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "shelldirectorypackage", + "properties" : [ { + "id" : "shelldirectory", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.SHELLDIRECTORYPACKAGE.SHELLDIRECTORY.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SHELLDIRECTORYPACKAGE.SHELLDIRECTORY.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "ruletask_rulespackage", + "properties" : [ { + "id" : "ruletask_rules", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.RULETASK_RULESPACKAGE.RULETASK_RULES.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.RULETASK_RULESPACKAGE.RULETASK_RULES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "ruletask_variables_inputpackage", + "properties" : [ { + "id" : "ruletask_variables_input", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.RULETASK_VARIABLES_INPUTPACKAGE.RULETASK_VARIABLES_INPUT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.RULETASK_VARIABLES_INPUTPACKAGE.RULETASK_VARIABLES_INPUT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "ruletask_excludepackage", + "properties" : [ { + "id" : "ruletask_exclude", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.RULETASK_EXCLUDEPACKAGE.RULETASK_EXCLUDE.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.RULETASK_EXCLUDEPACKAGE.RULETASK_EXCLUDE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "ruletask_resultpackage", + "properties" : [ { + "id" : "ruletask_result", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.RULETASK_RESULTPACKAGE.RULETASK_RESULT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.RULETASK_RESULTPACKAGE.RULETASK_RESULT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtaskheaderspackage", + "properties" : [ { + "id" : "mailtaskheaders", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKHEADERSPACKAGE.MAILTASKHEADERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKHEADERSPACKAGE.MAILTASKHEADERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtasktopackage", + "properties" : [ { + "id" : "mailtaskto", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKTOPACKAGE.MAILTASKTO.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKTOPACKAGE.MAILTASKTO.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtaskfrompackage", + "properties" : [ { + "id" : "mailtaskfrom", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKFROMPACKAGE.MAILTASKFROM.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKFROMPACKAGE.MAILTASKFROM.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtasksubjectpackage", + "properties" : [ { + "id" : "mailtasksubject", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKSUBJECTPACKAGE.MAILTASKSUBJECT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKSUBJECTPACKAGE.MAILTASKSUBJECT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtaskccpackage", + "properties" : [ { + "id" : "mailtaskcc", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKCCPACKAGE.MAILTASKCC.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKCCPACKAGE.MAILTASKCC.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtaskbccpackage", + "properties" : [ { + "id" : "mailtaskbcc", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKBCCPACKAGE.MAILTASKBCC.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKBCCPACKAGE.MAILTASKBCC.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtasktextpackage", + "properties" : [ { + "id" : "mailtasktext", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKTEXTPACKAGE.MAILTASKTEXT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKTEXTPACKAGE.MAILTASKTEXT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtaskhtmlpackage", + "properties" : [ { + "id" : "mailtaskhtml", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKHTMLPACKAGE.MAILTASKHTML.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKHTMLPACKAGE.MAILTASKHTML.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "mailtaskcharsetpackage", + "properties" : [ { + "id" : "mailtaskcharset", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MAILTASKCHARSETPACKAGE.MAILTASKCHARSET.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MAILTASKCHARSETPACKAGE.MAILTASKCHARSET.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskrequestmethodpackage", + "properties" : [ { + "id" : "httptaskrequestmethod", + "type" : "flowable-http-request-method", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTMETHODPACKAGE.HTTPTASKREQUESTMETHOD.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTMETHODPACKAGE.HTTPTASKREQUESTMETHOD.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskrequesturlpackage", + "properties" : [ { + "id" : "httptaskrequesturl", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTURLPACKAGE.HTTPTASKREQUESTURL.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTURLPACKAGE.HTTPTASKREQUESTURL.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskrequestheaderspackage", + "properties" : [ { + "id" : "httptaskrequestheaders", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTHEADERSPACKAGE.HTTPTASKREQUESTHEADERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTHEADERSPACKAGE.HTTPTASKREQUESTHEADERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskrequestbodypackage", + "properties" : [ { + "id" : "httptaskrequestbody", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTBODYPACKAGE.HTTPTASKREQUESTBODYPACKAGE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTBODYPACKAGE.HTTPTASKREQUESTBODYPACKAGE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskrequestbodyencodingpackage", + "properties" : [ { + "id" : "httptaskrequestbodyencoding", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTBODYENCODINGPACKAGE.HTTPTASKREQUESTBODYENCODING.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTBODYENCODINGPACKAGE.HTTPTASKREQUESTBODYENCODING.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskrequesttimeoutpackage", + "properties" : [ { + "id" : "httptaskrequesttimeout", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTTIMEOUTPACKAGE.HTTPTASKREQUESTTIMEOUT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKREQUESTTIMEOUTPACKAGE.HTTPTASKREQUESTTIMEOUT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskdisallowredirectspackage", + "properties" : [ { + "id" : "httptaskdisallowredirects", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKDISALLOWREDIRECTSPACKAGE.HTTPTASKDISALLOWREDIRECTS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKDISALLOWREDIRECTSPACKAGE.HTTPTASKDISALLOWREDIRECTS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskfailstatuscodespackage", + "properties" : [ { + "id" : "httptaskfailstatuscodes", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKFAILSTATUSCODESPACKAGE.HTTPTASKFAILSTATUSCODES.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKFAILSTATUSCODESPACKAGE.HTTPTASKFAILSTATUSCODES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskhandlestatuscodespackage", + "properties" : [ { + "id" : "httptaskhandlestatuscodes", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKHANDLESTATUSCODESPACKAGE.HTTPTASKHANDLESTATUSCODES.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKHANDLESTATUSCODESPACKAGE.HTTPTASKHANDLESTATUSCODES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskignoreexceptionpackage", + "properties" : [ { + "id" : "httptaskignoreexception", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKIGNOREEXCEPTIONPACKAGE.HTTPTASKIGNOREEXCEPTION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKIGNOREEXCEPTIONPACKAGE.HTTPTASKIGNOREEXCEPTION.DESCRIPTION", + "popular" : true + } ] + }, + { + "name" : "httptasksaveresponseparameterstransientpackage", + "properties" : [ { + "id" : "httptasksaveresponseparameterstransient", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVERESPONSEPARAMETERSTRANSIENTPACKAGE.HTTPTASKSAVERESPONSEPARAMETERSTRANSIENT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVERESPONSEPARAMETERSTRANSIENTPACKAGE.HTTPTASKSAVERESPONSEPARAMETERSTRANSIENT.DESCRIPTION", + "popular" : true + } ] + }, + { + "name" : "httptasksaveresponseasjsonpackage", + "properties" : [ { + "id" : "httptasksaveresponseasjson", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVERESPONSEASJSONPACKAGE.HTTPTASKSAVERESPONSEASJSON.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVERESPONSEASJSONPACKAGE.HTTPTASKSAVERESPONSEASJSON.DESCRIPTION", + "popular" : true + } ] + }, + { + "name" : "skipexpressionpackage", + "properties" : [ + { + "id" : "skipexpression", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.SKIPEXPRESSIONPACKAGE.SKIPEXPRESSION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SKIPEXPRESSIONPACKAGE.SKIPEXPRESSION.DESCRIPTION", + "popular" : true + } + ] + }, + { + "name" : "httptaskresponsevariablenamepackage", + "properties" : [ { + "id" : "httptaskresponsevariablename", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKRESPONSEVARIABLENAMEPACKAGE.HTTPTASKRESPONSEVARIABLENAME.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKRESPONSEVARIABLENAMEPACKAGE.HTTPTASKRESPONSEVARIABLENAME.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptasksaverequestvariablespackage", + "properties" : [ { + "id" : "httptasksaverequestvariables", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVEREQUESTVARIABLESPACKAGE.HTTPTASKSAVEREQUESTVARIABLES.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVEREQUESTVARIABLESPACKAGE.HTTPTASKSAVEREQUESTVARIABLES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptasksaveresponseparameterspackage", + "properties" : [ { + "id" : "httptasksaveresponseparameters", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVERESPONSEPARAMETERSPACKAGE.HTTPTASKSAVERESPONSEPARAMETERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKSAVERESPONSEPARAMETERSPACKAGE.HTTPTASKSAVERESPONSEPARAMETERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "httptaskresultvariableprefixpackage", + "properties" : [ { + "id" : "httptaskresultvariableprefix", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.HTTPTASKRESULTVARIABLEPREFIXPACKAGE.HTTPTASKRESULTVARIABLEPREFIX.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.HTTPTASKRESULTVARIABLEPREFIXPACKAGE.HTTPTASKRESULTVARIABLEPREFIX.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivitycalledelementpackage", + "properties" : [ { + "id" : "callactivitycalledelement", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYCALLEDELEMENTPACKAGE.CALLACTIVITYCALLEDELEMENT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYCALLEDELEMENTPACKAGE.CALLACTIVITYCALLEDELEMENT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivitycalledelementtypepackage", + "properties" : [ { + "id" : "callactivitycalledelementtype", + "type" : "flowable-calledelementtype", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYCALLEDELEMENTTYPEPACKAGE.CALLACTIVITYCALLEDELEMENTTYPE.TITLE", + "value" : "key", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYCALLEDELEMENTTYPEPACKAGE.CALLACTIVITYCALLEDELEMENTTYPE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityinparameterspackage", + "properties" : [ { + "id" : "callactivityinparameters", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYINPARAMETERSPACKAGE.CALLACTIVITYINPARAMETERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYINPARAMETERSPACKAGE.CALLACTIVITYINPARAMETERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityoutparameterspackage", + "properties" : [ { + "id" : "callactivityoutparameters", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYOUTPARAMETERSPACKAGE.CALLACTIVITYOUTPARAMETERS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYOUTPARAMETERSPACKAGE.CALLACTIVITYOUTPARAMETERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityinheritvariablespackage", + "properties" : [ { + "id" : "callactivityinheritvariables", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYINHERITVARIABLESPACKAGE.CALLACTIVITYINHERITVARIABLES.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYINHERITVARIABLESPACKAGE.CALLACTIVITYINHERITVARIABLES.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivitysamedeploymentpackage", + "properties" : [ { + "id" : "callactivitysamedeployment", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYSAMEDEPLOYMENTPACKAGE.CALLACTIVITYSAMEDEPLOYMENT.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYSAMEDEPLOYMENTPACKAGE.CALLACTIVITYSAMEDEPLOYMENT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityfallbacktodefaulttenantpackage", + "properties" : [ { + "id" : "callactivityfallbacktodefaulttenant", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYFALLBACKTODEFAULTTENANTPACKAGE.CALLACTIVITYFALLBACKTODEFAULTTENANT.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYFALLBACKTODEFAULTTENANTPACKAGE.CALLACTIVITYFALLBACKTODEFAULTTENANT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityprocessinstancenamepackage", + "properties" : [ { + "id" : "callactivityprocessinstancename", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYPROCESSINSTANCENAMEPACKAGE.CALLACTIVITYPROCESSINSTANCENAME.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYPROCESSINSTANCENAMEPACKAGE.CALLACTIVITYPROCESSINSTANCENAME.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityinheritbusinesskeypackage", + "properties" : [ { + "id" : "callactivityinheritbusinesskey", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYINHERITBUSINESSKEYPACKAGE.CALLACTIVITYINHERITBUSINESSKEY.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYINHERITBUSINESSKEYPACKAGE.CALLACTIVITYINHERITBUSINESSKEY.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivityuselocalscopeforoutparameterspackage", + "properties" : [ { + "id" : "callactivityuselocalscopeforoutparameters", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERSPACKAGE.CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERS.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERSPACKAGE.CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivitybusinesskeypackage", + "properties" : [ { + "id" : "callactivitybusinesskey", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYBUSINESSKEYPACKAGE.CALLACTIVITYBUSINESSKEY.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYBUSINESSKEYPACKAGE.CALLACTIVITYBUSINESSKEY.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "callactivitycompleteasyncpackage", + "properties" : [ { + "id" : "callactivitycompleteasync", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYCOMPLETEASYNCPACKAGE.CALLACTIVITYCOMPLETEASYNC.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CALLACTIVITYCOMPLETEASYNCPACKAGE.CALLACTIVITYCOMPLETEASYNC.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "cameltaskcamelcontextpackage", + "properties" : [ { + "id" : "cameltaskcamelcontext", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.CAMELTASKCAMELCONTEXTPACKAGE.CAMELTASKCAMELCONTEXT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CAMELTASKCAMELCONTEXTPACKAGE.CAMELTASKCAMELCONTEXT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "muletaskendpointurlpackage", + "properties" : [ { + "id" : "muletaskendpointurl", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULETASKENDPOINTURLPACKAGE.MULETASKENDPOINTURL.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULETASKENDPOINTURLPACKAGE.MULETASKENDPOINTURL.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "muletasklanguagepackage", + "properties" : [ { + "id" : "muletasklanguage", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULETASKLANGUAGEPACKAGE.MULETASKLANGUAGE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULETASKLANGUAGEPACKAGE.MULETASKLANGUAGE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "muletaskpayloadexpressionpackage", + "properties" : [ { + "id" : "muletaskpayloadexpression", + "type" : "Text", + "title" : "BPMN.PROPERTYPACKAGES.MULETASKPAYLOADEXPRESSIONPACKAGE.MULETASKPAYLOADEXPRESSION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULETASKPAYLOADEXPRESSIONPACKAGE.MULETASKPAYLOADEXPRESSION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "muletaskresultvariablepackage", + "properties" : [ { + "id" : "muletaskresultvariable", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULETASKRESULTVARIABLEPACKAGE.MULETASKRESULTVARIABLE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULETASKRESULTVARIABLEPACKAGE.MULETASKRESULTVARIABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "conditionsequenceflowpackage", + "properties" : [ { + "id" : "conditionsequenceflow", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.CONDITIONSEQUENCEFLOWPACKAGE.CONDITIONSEQUENCEFLOWPACKAGE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CONDITIONSEQUENCEFLOWPACKAGE.CONDITIONSEQUENCEFLOWPACKAGE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "defaultflowpackage", + "properties" : [ { + "id" : "defaultflow", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.DEFAULTFLOWPACKAGE.DEFAULTFLOW.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.DEFAULTFLOWPACKAGE.DEFAULTFLOW.DESCRIPTION", + "popular" : true, + "refToView" : "default" + } ] + }, { + "name" : "conditionalflowpackage", + "properties" : [ { + "id" : "conditionalflow", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CONDITIONALFLOWPACKAGE.CONDITIONALFLOW.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.CONDITIONALFLOWPACKAGE.CONDITIONALFLOW.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "timercycledefinitionpackage", + "properties" : [ { + "id" : "timercycledefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.TIMERCYCLEDEFINITIONPACKAGE.TIMERCYCLEDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.TIMERCYCLEDEFINITIONPACKAGE.TIMERCYCLEDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "timerdatedefinitionpackage", + "properties" : [ { + "id" : "timerdatedefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.TIMERDATEDEFINITIONPACKAGE.TIMERDATEDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.TIMERDATEDEFINITIONPACKAGE.TIMERDATEDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "timerdurationdefinitionpackage", + "properties" : [ { + "id" : "timerdurationdefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.TIMERDURATIONDEFINITIONPACKAGE.TIMERDURATIONDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.TIMERDURATIONDEFINITIONPACKAGE.TIMERDURATIONDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "timerenddatedefinitionpackage", + "properties" : [ { + "id" : "timerenddatedefinition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.TIMERENDDATEDEFINITIONPACKAGE.TIMERENDDATEDEFINITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.TIMERENDDATEDEFINITIONPACKAGE.TIMERENDDATEDEFINITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "messagerefpackage", + "properties" : [ { + "id" : "messageref", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MESSAGEREFPACKAGE.MESSAGEREF.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MESSAGEREFPACKAGE.MESSAGEREF.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "signalrefpackage", + "properties" : [ { + "id" : "signalref", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.SIGNALREFPACKAGE.SIGNALREF.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SIGNALREFPACKAGE.SIGNALREF.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "errorrefpackage", + "properties" : [ { + "id" : "errorref", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.ERRORREFPACKAGE.ERRORREF.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.ERRORREFPACKAGE.ERRORREF.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "escalationrefpackage", + "properties" : [ { + "id" : "escalationref", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.ESCALATIONREFPACKAGE.ESCALATIONREF.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.ESCALATIONREFPACKAGE.ESCALATIONREF.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "cancelactivitypackage", + "properties" : [ { + "id" : "cancelactivity", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CANCELACTIVITYPACKAGE.CANCELACTIVITY.TITLE", + "value" : "true", + "description" : "BPMN.PROPERTYPACKAGES.CANCELACTIVITYPACKAGE.CANCELACTIVITY.DESCRIPTION", + "popular" : true, + "refToView" : [ "frame", "frame2" ] + } ] + }, { + "name" : "conditionaleventpackage", + "properties" : [ { + "id" : "conditionaleventcondition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.CONDITIONALEVENTPACKAGE.CONDITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.CONDITIONALEVENTPACKAGE.CONDITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "initiatorpackage", + "properties" : [ { + "id" : "initiator", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.INITIATORPACKAGE.INITIATOR.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.INITIATORPACKAGE.INITIATOR.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "textpackage", + "properties" : [ { + "id" : "text", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.TEXTPACKAGE.TEXT.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.TEXTPACKAGE.TEXT.DESCRIPTION", + "popular" : true, + "refToView" : "text" + } ] + }, { + "name" : "multiinstance_typepackage", + "properties" : [ { + "id" : "multiinstance_type", + "type" : "flowable-multiinstance", + "title" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_TYPEPACKAGE.MULTIINSTANCE_TYPE.TITLE", + "value" : "None", + "description" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_TYPEPACKAGE.MULTIINSTANCE_TYPE.DESCRIPTION", + "popular" : true, + "refToView" : "multiinstance" + } ] + }, { + "name" : "multiinstance_cardinalitypackage", + "properties" : [ { + "id" : "multiinstance_cardinality", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_CARDINALITYPACKAGE.MULTIINSTANCE_CARDINALITY.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_CARDINALITYPACKAGE.MULTIINSTANCE_CARDINALITY.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "multiinstance_collectionpackage", + "properties" : [ { + "id" : "multiinstance_collection", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_COLLECTIONPACKAGE.MULTIINSTANCE_COLLECTION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_COLLECTIONPACKAGE.MULTIINSTANCE_COLLECTION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "multiinstance_variablepackage", + "properties" : [ { + "id" : "multiinstance_variable", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_VARIABLEPACKAGE.MULTIINSTANCE_VARIABLE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_VARIABLEPACKAGE.MULTIINSTANCE_VARIABLE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "multiinstance_conditionpackage", + "properties" : [ { + "id" : "multiinstance_condition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_CONDITIONPACKAGE.MULTIINSTANCE_CONDITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MULTIINSTANCE_CONDITIONPACKAGE.MULTIINSTANCE_CONDITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "isforcompensationpackage", + "properties" : [ { + "id" : "isforcompensation", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.ISFORCOMPENSATIONPACKAGE.ISFORCOMPENSATION.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.ISFORCOMPENSATIONPACKAGE.ISFORCOMPENSATION.DESCRIPTION", + "popular" : true, + "refToView" : "compensation" + } ] + }, { + "name" : "sequencefloworderpackage", + "properties" : [ { + "id" : "sequencefloworder", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.SEQUENCEFLOWORDERPACKAGE.SEQUENCEFLOWORDER.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SEQUENCEFLOWORDERPACKAGE.SEQUENCEFLOWORDER.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "signaldefinitionspackage", + "properties" : [ { + "id" : "signaldefinitions", + "type" : "multiplecomplex", + "title" : "BPMN.PROPERTYPACKAGES.SIGNALDEFINITIONSPACKAGE.SIGNALDEFINITIONS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.SIGNALDEFINITIONSPACKAGE.SIGNALDEFINITIONS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "messagedefinitionspackage", + "properties" : [ { + "id" : "messagedefinitions", + "type" : "multiplecomplex", + "title" : "BPMN.PROPERTYPACKAGES.MESSAGEDEFINITIONSPACKAGE.MESSAGEDEFINITIONS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.MESSAGEDEFINITIONSPACKAGE.MESSAGEDEFINITIONS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "escalationdefinitionspackage", + "properties" : [ { + "id" : "escalationdefinitions", + "type" : "multiplecomplex", + "title" : "BPMN.PROPERTYPACKAGES.ESCALATIONDEFINITIONSPACKAGE.ESCALATIONDEFINITIONS.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.ESCALATIONDEFINITIONSPACKAGE.ESCALATIONDEFINITIONS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "istransactionpackage", + "properties" : [ { + "id" : "istransaction", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.ISTRANSACTIONPACKAGE.ISTRANSACTION.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.ISTRANSACTIONPACKAGE.ISTRANSACTION.DESCRIPTION", + "popular" : true, + "refToView" : "border" + } ] + }, { + "name" : "formreferencepackage", + "properties" : [ { + "id" : "formreference", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.FORMREFERENCEPACKAGE.FORMREFERENCE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.FORMREFERENCEPACKAGE.FORMREFERENCE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "terminateAllpackage", + "properties" : [ { + "id" : "terminateAll", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.TERMINATEALLPACKAGE.TERMINATEALL.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.TERMINATEALLPACKAGE.TERMINATEALL.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "decisiontaskdecisiontablereferencepackage", + "properties" : [ { + "id" : "decisiontaskdecisiontablereference", + "type" : "Complex", + "title" : "BPMN.PROPERTYPACKAGES.DECISIONTASKDECISIONTABLEREFERENCEPACKAGE.DECISIONTASKDECISIONTABLEREFERENCE.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.DECISIONTASKDECISIONTABLEREFERENCEPACKAGE.DECISIONTASKDECISIONTABLEREFERENCE.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "decisiontaskthrowerroronnohitspackage", + "properties" : [ { + "id" : "decisiontaskthrowerroronnohits", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.DECISIONTASKTHROWERRORONNOHITSPACKAGE.DECISIONTASKTHROWERRORONNOHITS.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.DECISIONTASKTHROWERRORONNOHITSPACKAGE.DECISIONTASKTHROWERRORONNOHITS.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "decisiontaskfallbacktodefaulttenantpackage", + "properties" : [ { + "id" : "decisiontaskfallbacktodefaulttenant", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.DECISIONTASKFALLBACKTODEFAULTTENANTPACKAGE.DECISIONTASKFALLBACKTODEFAULTTENANT.TITLE", + "value" : "false", + "description" : "BPMN.PROPERTYPACKAGES.DECISIONTASKFALLBACKTODEFAULTTENANTPACKAGE.DECISIONTASKFALLBACKTODEFAULTTENANT.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "interruptingpackage", + "properties" : [ { + "id" : "interrupting", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.INTERRUPTINGPACKAGE.INTERRUPTING.TITLE", + "value" : "true", + "description" : "BPMN.PROPERTYPACKAGES.INTERRUPTINGPACKAGE.INTERRUPTING.DESCRIPTION", + "popular" : true, + "refToView" : [ "frame" ] + } ] + }, { + "name" : "completionconditionpackage", + "properties" : [ { + "id" : "completioncondition", + "type" : "String", + "title" : "BPMN.PROPERTYPACKAGES.COMPLETIONCONDITIONPACKAGE.COMPLETIONCONDITION.TITLE", + "value" : "", + "description" : "BPMN.PROPERTYPACKAGES.COMPLETIONCONDITIONPACKAGE.COMPLETIONCONDITION.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "orderingpackage", + "properties" : [ { + "id" : "ordering", + "type" : "flowable-ordering", + "title" : "BPMN.PROPERTYPACKAGES.ORDERINGPACKAGE.ORDERING.TITLE", + "value" : "Parallel", + "description" : "BPMN.PROPERTYPACKAGES.ORDERINGPACKAGE.ORDERING.DESCRIPTION", + "popular" : true + } ] + }, { + "name" : "cancelremaininginstancespackage", + "properties" : [ { + "id" : "cancelremaininginstances", + "type" : "Boolean", + "title" : "BPMN.PROPERTYPACKAGES.CANCELREMAININGINSTANCESPACKAGE.CANCELREMAININGINSTANCES.TITLE", + "value" : "true", + "description" : "BPMN.PROPERTYPACKAGES.CANCELREMAININGINSTANCESPACKAGE.CANCELREMAININGINSTANCES.DESCRIPTION", + "popular" : true + } ] + } ], + "stencils" : [ { + "type" : "node", + "id" : "BPMNDiagram", + "title" : "BPMN.STENCILS.BPMNDIAGRAM.TITLE", + "description" : "BPMN.STENCILS.BPMNDIAGRAM.DESCRIPTION", + "view" : "\n\n \n \n \n \n \t\n \n", + "icon" : "diagram.png", + "groups" : [ "BPMN.STENCILS.GROUPS.DIAGRAM" ], + "mayBeRoot" : true, + "hide" : true, + "propertyPackages" : [ "process_idpackage", "namepackage", "documentationpackage", "process_authorpackage", "process_versionpackage", "process_namespacepackage", "process_historylevelpackage", "isexecutablepackage", "datapropertiespackage", "executionlistenerspackage", "eventlistenerspackage", "signaldefinitionspackage", "messagedefinitionspackage", "escalationdefinitionspackage", "process_potentialstarteruserpackage","process_potentialstartergrouppackage", "process_iseagerexecutionfetchpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ ] + }, { + "type" : "node", + "id" : "StartNoneEvent", + "title" : "BPMN.STENCILS.STARTNONEEVENT.TITLE", + "description" : "BPMN.STENCILS.STARTNONEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n\t\n \n", + "icon" : "startevent/none.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "initiatorpackage", "formkeydefinitionpackage", "formreferencepackage", "formfieldvalidationpackage", "formpropertiespackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "StartTimerEvent", + "title" : "BPMN.STENCILS.STARTTIMEREVENT.TITLE", + "description" : "BPMN.STENCILS.STARTTIMEREVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n \n\t\n \n", + "icon" : "startevent/timer.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "timercycledefinitionpackage", "timerdatedefinitionpackage", "timerdurationdefinitionpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "StartSignalEvent", + "title" : "BPMN.STENCILS.STARTSIGNALEVENT.TITLE", + "description" : "BPMN.STENCILS.STARTSIGNALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n\n \n \n \n\t\n \n", + "icon" : "startevent/signal.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "signalrefpackage", "interruptingpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "StartMessageEvent", + "title" : "BPMN.STENCILS.STARTMESSAGEEVENT.TITLE", + "description" : "BPMN.STENCILS.STARTMESSAGEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n \n\t\n \n", + "icon" : "startevent/message.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "messagerefpackage", "interruptingpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "StartErrorEvent", + "title" : "BPMN.STENCILS.STARTERROREVENT.TITLE", + "description" : "BPMN.STENCILS.STARTERROREVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "startevent/error.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "errorrefpackage", "interruptingpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "StartEscalationEvent", + "title" : "BPMN.STENCILS.STARTESCALATIONEVENT.TITLE", + "description" : "BPMN.STENCILS.STARTESCALATIONEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "startevent/escalation.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "escalationrefpackage", "interruptingpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "StartConditionalEvent", + "title" : "BPMN.STENCILS.STARTCONDITIONALEVENT.TITLE", + "description" : "BPMN.STENCILS.STARTCONDITIONALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "startevent/conditional.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STARTEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "conditionaleventpackage", "interruptingpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "Startevents_all", "StartEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "UserTask", + "title" : "BPMN.STENCILS.USERTASK.TITLE", + "description" : "BPMN.STENCILS.USERTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\t\n\t\n \n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.user.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "usertaskassignmentpackage", "formkeydefinitionpackage", "formreferencepackage", "formfieldvalidationpackage", "duedatedefinitionpackage", "prioritydefinitionpackage", "formpropertiespackage", "tasklistenerspackage", "skipexpressionpackage", "categorypackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "ServiceTask", + "title" : "BPMN.STENCILS.SERVICETASK.TITLE", + "description" : "BPMN.STENCILS.SERVICETASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\n\t\n \n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.service.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "servicetasktriggerablepackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "servicetaskclasspackage", "servicetaskexpressionpackage", "servicetaskdelegateexpressionpackage", "servicetaskfieldspackage", "servicetaskresultvariablepackage", "skipexpressionpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "ScriptTask", + "title" : "BPMN.STENCILS.SCRIPTTASK.TITLE", + "description" : "BPMN.STENCILS.SCRIPTTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\n \n\t\n\t\t\n\t\n\t\n\t\t\n\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.script.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "scriptformatpackage", "scripttextpackage", "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "scriptautostorevariablespackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "BusinessRule", + "title" : "BPMN.STENCILS.BUSINESSRULE.TITLE", + "description" : "BPMN.STENCILS.BUSINESSRULE.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n \t\n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n \n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.business.rule.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "ruletask_rulespackage", "ruletask_variables_inputpackage", "ruletask_excludepackage", "ruletask_resultpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "ReceiveTask", + "title" : "BPMN.STENCILS.RECEIVETASK.TITLE", + "description" : "BPMN.STENCILS.RECEIVETASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n \n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.receive.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "ManualTask", + "title" : "BPMN.STENCILS.MANUALTASK.TITLE", + "description" : "BPMN.STENCILS.MANUALTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n \n \t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.manual.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "MailTask", + "title" : "BPMN.STENCILS.MAILTASK.TITLE", + "description" : "BPMN.STENCILS.MAILTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n \n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.send.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "mailtaskheaderspackage", "mailtasktopackage", "mailtaskfrompackage", "mailtasksubjectpackage", "mailtaskccpackage", "mailtaskbccpackage", "mailtasktextpackage", "mailtaskhtmlpackage", "mailtaskcharsetpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "CamelTask", + "title" : "BPMN.STENCILS.CAMELTASK.TITLE", + "description" : "BPMN.STENCILS.CAMELTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\n \n\t\n\t\t\n\t\n\t\n\t\t\n\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.camel.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "cameltaskcamelcontextpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "HttpTask", + "title" : "BPMN.STENCILS.HTTPTASK.TITLE", + "description" : "BPMN.STENCILS.HTTPTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n \n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.http.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "httptaskrequestmethodpackage", "httptaskrequesturlpackage", "httptaskrequestheaderspackage", "httptaskrequestbodypackage", "httptaskrequestbodyencodingpackage", "httptaskrequesttimeoutpackage", "httptaskdisallowredirectspackage", "httptaskfailstatuscodespackage", "httptaskhandlestatuscodespackage", "httptaskignoreexceptionpackage", "httptaskresponsevariablenamepackage", "httptasksaverequestvariablespackage", "httptasksaveresponseparameterspackage", "httptaskresultvariableprefixpackage", "httptasksaveresponseparameterstransientpackage", "httptasksaveresponseasjsonpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "MuleTask", + "title" : "BPMN.STENCILS.MULETASK.TITLE", + "description" : "BPMN.STENCILS.MULETASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\n \n\t\n\t\t\n\t\n\t\n\t\t\n\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.mule.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "muletaskendpointurlpackage", "muletasklanguagepackage", "muletaskpayloadexpressionpackage", "muletaskresultvariablepackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "SendTask", + "title" : "BPMN.STENCILS.SENDTASK.TITLE", + "description" : "BPMN.STENCILS.SENDTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n \n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.send.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, { + "type" : "node", + "id" : "DecisionTask", + "title" : "BPMN.STENCILS.DECISIONTASK.TITLE", + "description" : "BPMN.STENCILS.DECISIONTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.decision.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ACTIVITIES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage", "decisiontaskdecisiontablereferencepackage", "decisiontaskthrowerroronnohitspackage", "decisiontaskfallbacktodefaulttenantpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "ActivitiesMorph", "all" ] + }, + { + "type": "node", + "id": "ShellTask", + "title" : "BPMN.STENCILS.SHELLTASK.TITLE", + "description" : "BPMN.STENCILS.SHELLTASK.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\n\t\t_]]>\n\t\n \n\t\n\t\t\n\t\n\t\n\t\t\n\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/list/type.shell.png", + "groups" : [ + "BPMN.STENCILS.GROUPS.ACTIVITIES" + ], + "propertyPackages": [ + "overrideidpackage", + "namepackage", + "documentationpackage", + "asynchronousdefinitionpackage", + "shellcommandpackage", + "shellarg1package", + "shellarg2package", + "shellarg3package", + "shellarg4package", + "shellarg5package", + "shellwaitpackage", + "shelloutputvariablepackage", + "shellerrorcodevariablepackage", + "shellredirecterrorpackage", + "shellcleanenvpackage", + "shelldirectorypackage", + "exclusivedefinitionpackage", + "executionlistenerspackage", + "multiinstance_typepackage", + "multiinstance_cardinalitypackage", + "multiinstance_collectionpackage", + "multiinstance_variablepackage", + "multiinstance_conditionpackage", + "isforcompensationpackage" + ], + "hiddenPropertyPackages": [], + "roles": [ + "Activity", + "sequence_start", + "sequence_end", + "ActivitiesMorph", + "all" + ] + },{ + "type" : "node", + "id" : "SubProcess", + "title" : "BPMN.STENCILS.SUBPROCESS.TITLE", + "description" : "BPMN.STENCILS.SUBPROCESS.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n \n\t\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\n\t\n\t\t\n\t\n \n", + "icon" : "activity/expanded.subprocess.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STRUCTURAL" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "datapropertiespackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "istransactionpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "all" ] + },{ + "type" : "node", + "id" : "CollapsedSubProcess", + "title" : "BPMN.STENCILS.COLLAPSEDSUBPROCESS.TITLE", + "description" : "BPMN.STENCILS.COLLAPSEDSUBPROCESS.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n\t\t\n\t\t\n\t\n\t\t\n\t\t\n\t\t\n\t\n \n", + "icon" : "activity/subprocess.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STRUCTURAL" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "datapropertiespackage", "executionlistenerspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "istransactionpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "all" ] + },{ + "type" : "node", + "id" : "EventSubProcess", + "title" : "BPMN.STENCILS.EVENTSUBPROCESS.TITLE", + "description" : "BPMN.STENCILS.EVENTSUBPROCESS.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \n \n\t\n\t\n \t\n\t\t\n \t\n\t\n\t\n \n", + "icon" : "activity/event.subprocess.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STRUCTURAL" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "executionlistenerspackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "all", "EventSubProcess" ] + }, { + "type" : "node", + "id" : "CallActivity", + "title" : "BPMN.STENCILS.CALLACTIVITY.TITLE", + "description" : "BPMN.STENCILS.CALLACTIVITY.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n\t\n \n\t\n\t\t\n\t\t\n \n\t\n\t\t\n\t\n\t\n\t\n\t\t\n\t\n\n\t\n\t\t\n\t\n \n", + "icon" : "activity/task.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STRUCTURAL" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "callactivitycompleteasyncpackage", "executionlistenerspackage", "callactivitycalledelementpackage", "callactivitycalledelementtypepackage", "callactivityinparameterspackage", "callactivityoutparameterspackage", "callactivityinheritvariablespackage", "callactivitysamedeploymentpackage", "callactivityfallbacktodefaulttenantpackage", "callactivityprocessinstancenamepackage", "callactivityinheritbusinesskeypackage", "callactivitybusinesskeypackage", "callactivityuselocalscopeforoutparameterspackage", "multiinstance_typepackage", "multiinstance_cardinalitypackage", "multiinstance_collectionpackage", "multiinstance_variablepackage", "multiinstance_conditionpackage", "isforcompensationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "ExclusiveGateway", + "title" : "BPMN.STENCILS.EXCLUSIVEGATEWAY.TITLE", + "description" : "BPMN.STENCILS.EXCLUSIVEGATEWAY.DESCRIPTION", + "view" : "\n\n \n \n \n \t\t\t\t\t\n \n \n \n \n \n \n \n\t\n\t\n\t\n \n\n", + "icon" : "gateway/exclusive.databased.png", + "groups" : [ "BPMN.STENCILS.GROUPS.GATEWAYS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "sequencefloworderpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "GatewaysMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "ParallelGateway", + "title" : "BPMN.STENCILS.PARALLELGATEWAY.TITLE", + "description" : "BPMN.STENCILS.PARALLELGATEWAY.DESCRIPTION", + "view" : "\n\n \n \n \n \n \n \n \n \n\t\n\t\n \n\n", + "icon" : "gateway/parallel.png", + "groups" : [ "BPMN.STENCILS.GROUPS.GATEWAYS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "sequencefloworderpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "GatewaysMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "InclusiveGateway", + "title" : "BPMN.STENCILS.INCLUSIVEGATEWAY.TITLE", + "description" : "BPMN.STENCILS.INCLUSIVEGATEWAY.DESCRIPTION", + "view" : "\n\n \n \n \n \n\n \n \n \n\t\n\t\n \n\n", + "icon" : "gateway/inclusive.png", + "groups" : [ "BPMN.STENCILS.GROUPS.GATEWAYS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "sequencefloworderpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "GatewaysMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "EventGateway", + "title" : "BPMN.STENCILS.EVENTGATEWAY.TITLE", + "description" : "BPMN.STENCILS.EVENTGATEWAY.DESCRIPTION", + "view" : "\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n\n\n", + "icon" : "gateway/eventbased.png", + "groups" : [ "BPMN.STENCILS.GROUPS.GATEWAYS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "asynchronousdefinitionpackage", "exclusivedefinitionpackage", "sequencefloworderpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "GatewaysMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "BoundaryErrorEvent", + "title" : "BPMN.STENCILS.BOUNDARYERROREVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYERROREVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n \n\t\n \n", + "icon" : "catching/error.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "errorrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundaryEscalationEvent", + "title" : "BPMN.STENCILS.BOUNDARYESCALATIONEVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYESCALATIONEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n \n\t\n \n", + "icon" : "catching/escalation.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "escalationrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundaryTimerEvent", + "title" : "BPMN.STENCILS.BOUNDARYTIMEREVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYTIMEREVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \n \n \n \n \n \t\n\t\n \n", + "icon" : "catching/timer.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "timercycledefinitionpackage", "timerdatedefinitionpackage", "timerdurationdefinitionpackage", "timerenddatedefinitionpackage", "cancelactivitypackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundarySignalEvent", + "title" : "BPMN.STENCILS.BOUNDARYSIGNALEVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYSIGNALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \n \n \n\t\n\t\n \n", + "icon" : "catching/signal.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "signalrefpackage", "cancelactivitypackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundaryMessageEvent", + "title" : "BPMN.STENCILS.BOUNDARYMESSAGEEVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYMESSAGEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \t\n \n \n \n\t\n\t\t\n\t\n\t\n\t\n \n", + "icon" : "catching/message.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "messagerefpackage", "cancelactivitypackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundaryCancelEvent", + "title" : "BPMN.STENCILS.BOUNDARYCANCELEVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYCANCELEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n \n \n\t\n \n", + "icon" : "catching/cancel.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundaryConditionalEvent", + "title" : "BPMN.STENCILS.BOUNDARYCONDITIONALEVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYCONDITIONALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n \n \n\t\n \n", + "icon" : "catching/conditional.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "conditionaleventpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary" ] + }, { + "type" : "node", + "id" : "BoundaryCompensationEvent", + "title" : "BPMN.STENCILS.BOUNDARYCOMPENSATIONEVENT.TITLE", + "description" : "BPMN.STENCILS.BOUNDARYCOMPENSATIONEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n\t\n \n \n \n \n \n\t\n \n", + "icon" : "catching/compensation.png", + "groups" : [ "BPMN.STENCILS.GROUPS.BOUNDARYEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "BoundaryEventsMorph", "IntermediateEventOnActivityBoundary", "all" ] + }, { + "type" : "node", + "id" : "CatchTimerEvent", + "title" : "BPMN.STENCILS.CATCHTIMEREVENT.TITLE", + "description" : "BPMN.STENCILS.CATCHTIMEREVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \n \n \n \n \n \t\n\t\n \n", + "icon" : "catching/timer.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATECATCHINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "timercycledefinitionpackage", "timerdatedefinitionpackage", "timerdurationdefinitionpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "sequence_end", "CatchEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "CatchSignalEvent", + "title" : "BPMN.STENCILS.CATCHSIGNALEVENT.TITLE", + "description" : "BPMN.STENCILS.CATCHSIGNALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \n \n \n\t\n\t\n \n", + "icon" : "catching/signal.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATECATCHINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "signalrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "sequence_end", "CatchEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "CatchMessageEvent", + "title" : "BPMN.STENCILS.CATCHMESSAGEEVENT.TITLE", + "description" : "BPMN.STENCILS.CATCHMESSAGEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \t\n \n \n \n\t\n\t\t\n\t\n\t\n\t\n \n", + "icon" : "catching/message.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATECATCHINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "messagerefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "sequence_end", "CatchEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "CatchConditionalEvent", + "title" : "BPMN.STENCILS.CATCHCONDITIONALEVENT.TITLE", + "description" : "BPMN.STENCILS.CATCHCONDITIONALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \t\n \n \n \n \n\t\n\t\n \n", + "icon" : "catching/conditional.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATECATCHINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "conditionaleventpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "sequence_start", "sequence_end", "CatchEventsMorph", "all" ] + }, { + "type" : "node", + "id" : "ThrowNoneEvent", + "title" : "BPMN.STENCILS.THROWNONEEVENT.TITLE", + "description" : "BPMN.STENCILS.THROWNONEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "throwing/none.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATETHROWINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ThrowEventsMorph", "sequence_start", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "ThrowSignalEvent", + "title" : "BPMN.STENCILS.THROWSIGNALEVENT.TITLE", + "description" : "BPMN.STENCILS.THROWSIGNALEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "throwing/signal.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATETHROWINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "signalrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ThrowEventsMorph", "sequence_start", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "ThrowEscalationEvent", + "title" : "BPMN.STENCILS.THROWESCALATIONEVENT.TITLE", + "description" : "BPMN.STENCILS.THROWESCALATIONEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "throwing/escalation.png", + "groups" : [ "BPMN.STENCILS.GROUPS.INTERMEDIATETHROWINGEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "escalationrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ThrowEventsMorph", "sequence_start", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "EndNoneEvent", + "title" : "BPMN.STENCILS.ENDNONEEVENT.TITLE", + "description" : "BPMN.STENCILS.ENDNONEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n\t\n \n", + "icon" : "endevent/none.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ENDEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "EndEventsMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "EndErrorEvent", + "title" : "BPMN.STENCILS.ENDERROREVENT.TITLE", + "description" : "BPMN.STENCILS.ENDERROREVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "endevent/error.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ENDEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "errorrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "EndEventsMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "EndEscalationEvent", + "title" : "BPMN.STENCILS.ENDESCALATIONEVENT.TITLE", + "description" : "BPMN.STENCILS.ENDESCALATIONEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "endevent/escalation.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ENDEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "escalationrefpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "EndEventsMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "EndCancelEvent", + "title" : "BPMN.STENCILS.ENDCANCELEVENT.TITLE", + "description" : "BPMN.STENCILS.ENDCANCELEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n\t\n \n", + "icon" : "endevent/cancel.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ENDEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "EndEventsMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "EndTerminateEvent", + "title" : "BPMN.STENCILS.ENDTERMINATEEVENT.TITLE", + "description" : "BPMN.STENCILS.ENDTERMINATEEVENT.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n\t\n \n", + "icon" : "endevent/terminate.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ENDEVENTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "executionlistenerspackage", "terminateAllpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "EndEventsMorph", "sequence_end", "all" ] + }, { + "type" : "node", + "id" : "Pool", + "title" : "BPMN.STENCILS.POOL.TITLE", + "description" : "BPMN.STENCILS.POOL.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \n \n \n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n\t \t\n \t\n \n \n\t\n\t\n\t\n\t\n \n \n \n", + "icon" : "swimlane/pool.png", + "groups" : [ "BPMN.STENCILS.GROUPS.SWIMLANES" ], + "layout" : [ { + "type" : "layout.bpmn2_0.pool" + } ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "process_idpackage", "isexecutablepackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "canContainArtifacts", "all" ] + }, { + "type" : "node", + "id" : "Lane", + "title" : "BPMN.STENCILS.LANE.TITLE", + "description" : "BPMN.STENCILS.LANE.DESCRIPTION", + "view" : "\n\n \n \n \n \n\t\t\n\t\t\t\n\t\t\t\n\t\t\n\t\n\t\n \t\t\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n \n\t\n \n", + "icon" : "swimlane/lane.png", + "groups" : [ "BPMN.STENCILS.GROUPS.SWIMLANES" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "PoolChild", "canContainArtifacts", "all" ] + }, { + "type" : "edge", + "id" : "SequenceFlow", + "title" : "BPMN.STENCILS.SEQUENCEFLOW.TITLE", + "description" : "BPMN.STENCILS.SEQUENCEFLOW.DESCRIPTION", + "view" : "\r\n\r\n\t\r\n\t \t\r\n\t \t\t\r\n\t\t\t\r\n\t \t\r\n\t \t\r\n\t \t\t\r\n\t \t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n", + "icon" : "connector/sequenceflow.png", + "groups" : [ "BPMN.STENCILS.GROUPS.CONNECTINGOBJECTS" ], + "layout" : [ { + "type" : "layout.bpmn2_0.sequenceflow" + } ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "conditionsequenceflowpackage", "executionlistenerspackage", "defaultflowpackage", "skipexpressionpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ConnectingObjectsMorph", "all" ] + }, { + "type" : "edge", + "id" : "MessageFlow", + "title" : "BPMN.STENCILS.MESSAGEFLOW.TITLE", + "description" : "BPMN.STENCILS.MESSAGEFLOW.DESCRIPTION", + "view" : "\r\n\r\n\t\r\n\t\t\r\n\t \t\t\r\n\t \t\t\r\n\t \t\r\n\r\n\t \t\r\n\t \t\t\r\n\t \t\r\n\t\r\n\t\r\n\t \r\n\t\t\r\n\t\r\n", + "icon" : "connector/messageflow.png", + "groups" : [ "BPMN.STENCILS.GROUPS.CONNECTINGOBJECTS" ], + "layout" : [ { + "type" : "layout.bpmn2_0.sequenceflow" + } ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ConnectingObjectsMorph", "all" ] + }, { + "type" : "edge", + "id" : "Association", + "title" : "BPMN.STENCILS.ASSOCIATION.TITLE", + "description" : "BPMN.STENCILS.ASSOCIATION.DESCRIPTION", + "view" : "\r\n\r\n\t\r\n\t \r\n\t\t\r\n\t\r\n", + "icon" : "connector/association.undirected.png", + "groups" : [ "BPMN.STENCILS.GROUPS.CONNECTINGOBJECTS" ], + "layout" : [ { + "type" : "layout.bpmn2_0.sequenceflow" + } ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ConnectingObjectsMorph", "all" ] + }, { + "type" : "edge", + "id" : "DataAssociation", + "title" : "BPMN.STENCILS.DATAASSOCIATION.TITLE", + "description" : "BPMN.STENCILS.DATAASSOCIATION.DESCRIPTION", + "view" : "\r\n\r\n\t\r\n\t \t\r\n\t \t\t\r\n\t \t\r\n\t\r\n\t\r\n\t \r\n\t\t\r\n\t\r\n", + "icon" : "connector/association.unidirectional.png", + "groups" : [ "BPMN.STENCILS.GROUPS.CONNECTINGOBJECTS" ], + "layout" : [ { + "type" : "layout.bpmn2_0.sequenceflow" + } ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "ConnectingObjectsMorph", "all" ] + }, { + "type" : "node", + "id" : "TextAnnotation", + "title" : "BPMN.STENCILS.TEXTANNOTATION.TITLE", + "description" : "BPMN.STENCILS.TEXTANNOTATION.DESCRIPTION", + "view" : "\n\n \n \n \t\n \n \n \n \n \n \n\t\n \n", + "icon" : "artifact/text.annotation.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ARTIFACTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "textpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "all" ] + }, { + "type" : "node", + "id" : "DataStore", + "title" : "BPMN.STENCILS.DATASTORE.TITLE", + "description" : "BPMN.STENCILS.DATASTORE.DESCRIPTION", + "view" : "\r\n\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t \t\r\n\t\t\r\n\t\t\t \r\n\t\r\n\r\n", + "icon" : "dataobject/data.store.png", + "groups" : [ "BPMN.STENCILS.GROUPS.ARTIFACTS" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "all" ] + }, { + "type" : "node", + "id" : "AdhocSubProcess", + "title" : "BPMN.STENCILS.ADHOCSUBPROCESS.TITLE", + "description" : "BPMN.STENCILS.ADHOCSUBPROCESS.DESCRIPTION", + "view" : "\n\n \n \n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \t\n \n \n \n\t\n\t\n\t\n\t\n\t~\n \n", + "icon" : "activity/adhoc.subprocess.png", + "groups" : [ "BPMN.STENCILS.GROUPS.STRUCTURAL" ], + "propertyPackages" : [ "overrideidpackage", "namepackage", "documentationpackage", "completionconditionpackage", "orderingpackage", "cancelremaininginstancespackage" ], + "hiddenPropertyPackages" : [ ], + "roles" : [ "Activity", "sequence_start", "sequence_end", "all" ] + } ], + "rules" : { + "cardinalityRules" : [ { + "role" : "Startevents_all", + "incomingEdges" : [ { + "role" : "SequenceFlow", + "maximum" : 0 + } ] + }, { + "role" : "Endevents_all", + "outgoingEdges" : [ { + "role" : "SequenceFlow", + "maximum" : 0 + } ] + } ], + "connectionRules" : [ { + "role" : "SequenceFlow", + "connects" : [ { + "from" : "sequence_start", + "to" : [ "sequence_end" ] + } ] + }, { + "role" : "Association", + "connects" : [ { + "from" : "sequence_start", + "to" : [ "TextAnnotation" ] + }, { + "from" : "sequence_end", + "to" : [ "TextAnnotation" ] + }, { + "from" : "TextAnnotation", + "to" : [ "sequence_end" ] + }, { + "from" : "BoundaryCompensationEvent", + "to" : [ "sequence_end" ] + }, { + "from" : "TextAnnotation", + "to" : [ "sequence_start" ] + }, { + "from" : "BoundaryCompensationEvent", + "to" : [ "sequence_start" ] + } ] + }, { + "role" : "DataAssociation", + "connects" : [ { + "from" : "sequence_start", + "to" : [ "DataStore" ] + }, { + "from" : "sequence_end", + "to" : [ "DataStore" ] + }, { + "from" : "DataStore", + "to" : [ "sequence_end" ] + }, { + "from" : "DataStore", + "to" : [ "sequence_start" ] + } ] + }, { + "role" : "IntermediateEventOnActivityBoundary", + "connects" : [ { + "from" : "Activity", + "to" : [ "IntermediateEventOnActivityBoundary" ] + } ] + } ], + "containmentRules" : [ { + "role" : "BPMNDiagram", + "contains" : [ "all" ] + }, { + "role" : "SubProcess", + "contains" : [ "sequence_start", "sequence_end", "from_task_event", "to_task_event", "EventSubProcess", "TextAnnotation", "DataStore" ] + }, { + "role" : "AdhocSubProcess", + "contains" : [ "sequence_start", "sequence_end", "from_task_event", "to_task_event", "TextAnnotation", "DataStore" ] + }, { + "role" : "EventSubProcess", + "contains" : [ "sequence_start", "sequence_end", "from_task_event", "to_task_event", "TextAnnotation", "DataStore" ] + }, { + "role" : "Pool", + "contains" : [ "Lane" ] + }, { + "role" : "Lane", + "contains" : [ "sequence_start", "sequence_end", "EventSubProcess", "TextAnnotation", "DataStore" ] + } ], + "morphingRules" : [ { + "role" : "ActivitiesMorph", + "baseMorphs" : [ "UserTask" ], + "preserveBounds" : true + }, { + "role" : "GatewaysMorph", + "baseMorphs" : [ "ExclusiveGateway" ] + }, { + "role" : "StartEventsMorph", + "baseMorphs" : [ "StartNoneEvent" ] + }, { + "role" : "EndEventsMorph", + "baseMorphs" : [ "StartNoneEvent" ] + }, { + "role" : "CatchEventsMorph", + "baseMorphs" : [ "CatchTimerEvent" ] + }, { + "role" : "ThrowEventsMorph", + "baseMorphs" : [ "ThrowNoneEvent" ] + }, { + "role" : "BoundaryEventsMorph", + "baseMorphs" : [ "ThrowNoneEvent" ] + }, { + "role" : "BoundaryCompensationEvent", + "baseMorphs" : [ "BoundaryCompensationEvent" ] + }, { + "role" : "TextAnnotation", + "baseMorphs" : [ "TextAnnotation" ] + }, { + "role" : "DataStore", + "baseMorphs" : [ "DataStore" ] + } ] + } +} diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/adhoc.subprocess.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/adhoc.subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..bf50968ac183c188e0c1a3e12ea4acc521f6b915 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xj(fT|hE&{2`t$$4J+o>6*o7fx*uS3FfG@Q-&ezHxT{gD%HivbW)ou<7neWm7ndZ=kn1|!VAa^c7a}4O z+c3pY;QsE<5B_DT6gn#Ww~b?N=yGbjqNVcBR^ck=5ry8T4mnOIxV;?SaBb-n^k{cH zn&!l7>wSUSp?9uF&V@EufbeJYD@<);T3K0RZiEZ2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4x@XHPV2-p&roj9JG%-*R-NJ%=$=-fa5=0?3XOLWx0{HU^me944$rjF6*2UngCcma%=zq literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/event.subprocess.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/event.subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..db72fee2e91e47f3dcd60727031d9aae6eaf8e36 GIT binary patch literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4oc9xz-oTla#E zVdl>be_0CRuTPzH?wbD2Npq&B-b|1d3{(}p{bJ)1A;GI=yZG!Zm1@Mc7(B`piF<4m zbHT)P(_!9vw*AQ)($ikn&YI~O#M);#aZbPCUaPhg2J4fO3>Bs4^6QSt{F>2lAR6d2 N22WQ%mvv4FO#l&tVW0p2 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/expanded.subprocess.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/expanded.subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..085343c84e98d902680df5575d5e4ed1ca3604ec GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4I>W+Y*bM3I@G1- zZPLKP@UCw97Ums(MZGC2x9$^SDET2Mc%0|$yXf@12`zIrt2~_k)8Mr19Qg@u-p0~$ z?k)vd2`PV;eYXA)?NIzZSM1e2wl6}SVxGHa+Nv8%on&H&seNu9ay*L5=+A;ZK$kIi My85}Sb4q9e0D3oGY5)KL literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.business.rule.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.business.rule.png new file mode 100644 index 0000000000000000000000000000000000000000..7b3f3b671b0a8ff132b56b458550df699484efe4 GIT binary patch literal 209 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4w?GgtC@!$G<@3_2IlN7AIaJlz8 z_xpZ_dqh?7Ja67wdjWV7$MKK@EaRNJXRRFqcY$r^T%&mGbUL%1=bb5Zv)Mef2OuI3 zf$zDV0xW><`_oyLZCGpHIOoo{+wIHMYW1gc?&26AilQ}OyC{grdw?WKR)G^hSwz-U z^)_%ASn+*-dKb{^^-91(u0PajwQsFfYZY*XNmXk(4B%9fB!k_Cs)}>&2XGWffY-p{ zKC@F}%u*PJj|;#$(AXz5xxSQ2rL!jg_wNIS0VGM1>jpqoU;Srj2Pm3t0Y?l#rBWFH z&j6hWyvWZxBGRbW>!*R0yf!N$4@C8E#yPhLq`*z!oiXNCmSrDBWGRZGM*!V!cP35K zE#SDSE}PMIaU4HS)ATKH&RRPN!*B=K0A>nL5Cp$ebs0cJu8aWy%H{GLuo(owr+hw7 zfnyW4m%vwGeh(l`(@Vg5p+)4gs#Zrm#+Vu~1g6FSp68teu8GL~JS?i}1Jx0aRn;3J uvZ<<9QPqEL=UlJdZZC}1`u)Bs?tcI@I?dC0000Iakn literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.decision.png new file mode 100644 index 0000000000000000000000000000000000000000..0351fee8a4a147e3e54c9ddbfcd9dddc25fe693d GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt@+JY5_^ zEP9V#HuPdn6k&PbfAN@8N7zBPX%$T+Nr~xi8FP}?rR1v19k}GQp-WsqOgngGLSnKD z_xa=F`tQrtuRYq=E}ZkHFt1VCX8DJP_kGvbs8t+QzSrFUv1$2( z-#5-G<~(Mw?s5!Pic1Xop|ZtA*w}mS>Vpi27x6l0hh4wMHT#E-p!g4teWLoOyLOhX zJhVb($FVIRGBY{@!y>K=@72EIYvU??UVO*l)DOlo4{a)x_j#FSbRU#{)_UGKd#!@@ vo!@u+_3ST+^IcA8NWOdSQ0|gn>3V;J literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.http.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.http.png new file mode 100644 index 0000000000000000000000000000000000000000..ffba8de117c51945335082019349be32dacc78a4 GIT binary patch literal 1267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z81_tJ3nIRD+5xzcF$@#f@i7EL>sd^Q;1whpd3^o;3KxS@gNuokUZcbjY zRfVk*ScMgk4HDK@QUEI{$+lIB@C{IK&M!(;Fx4~BGf=YQQczH^DN0GR3UYCSY6tRc zl`=|73as??%gf94%8m8%i_-NCEiEne4UF`SjC6r2bc-wVN)jt{^NN)rhQQ2mNi9w; z$}A|!%+FH*nVXoDUs__Tqy(}E4xsMLEr45;R}A$P(0}?Bi3R$GdItK~G?iqgA)JSz z3nYV6TWUon4s9SAh&FIwK-_2p3{flJ{FKbJN|(fvR68RBLsMM?V_jpz5JL+q17j;g za~pj$H3%PqbvqZOCYIzEh2-bw*ac)(q~_#;xC+L4#t@yz@<>`izOeEy%1i|YFDMZ0 z3~lr=#L(3{=jRp_r4|>1)SE)pBa5M{4@xc0&nX2NADWk0VrK-^f+mcvD-t1ZXAaYY zEQqcl0-FY8K_m^JXs`l@Q-n)qZfYLbFNS6|`dB54=o-U3d7J^$R?dD?) z6mdQNSY1VG;tLTgUMa!OL-H$FT2~xle^KJ}I#|R@v|eH2i;g~lj}g{}CuP&rj0LSD zji1lke17h4iPOIVCkp%x++%sdiOtNQ*+J_;)Pc(hJ~AG%G3o)I1+J{v!59|9FJHRS z_rSeZjXxO6BMwgwO4)Kp>&rv7XPe$u_}Q`XsY>J?G^^ZuzT#8gx$g;53nEYF?=}_p z%!-eT5B{PY?6SNRln4WvVW_^4+wgGn%2?42r7v@UHx3vIVCg!0Kr9^jsO4v literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.manual.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.manual.png new file mode 100644 index 0000000000000000000000000000000000000000..8dc32983d825edfaf5ab40d3721db2f3ba3e3b02 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4~W4%O$Rt<}ImZm|i(={y#2- zlPaFu_DwEh)M0E`@^oMOjS7L|g+8Ao4(wu|<83v)BsFbqWNM_H<#W3z2NBoXX=TP& zf|g&3oR)fd8>{hY_DR~F<@*xS*2R8bhkf9F1oky=NAP!X7rn`mQ-Qd@D;qIvJB z8{0?{Oh(&qVn`o!Bn0aqz*B@F|Ye8u7ft%R@SO?b4>`j`c-#hVY3rJEN#|1Nc4s>&R>`Qujbab>-tyVpN zYm>t;{9tA;fgG@R3V9F6nOV^}_fC?I1>!g^NE!t;Bn_F_%t^MH%}5%`Fr#rCKL$`3 zhP{%$0xjp<^-`&{m5F`^ZfE>2Ns`43Ft=D}*UdLZd-*2!WRh9hAZj!1fu<=)TD&9%&I zFuSh>{r&ydvTa|e)oLrvW^)x70xnCMk~9T$0jt1+TCMi0*=)WBdVsPsvof#`4AkrO zLXsrg-uq!-v%?0P-uvMsNw(|tdI1;!_RTDjnK3>-{wQ;y2a0C4EU6CYuaB%x(tY3w z5J;LWm&;2svtuh~ZiGL!J2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4toV*9CakC_wr6HrFYDv7tik$#`TEASoEr+)seO61`C-gsmL1=`x44DB m<@FJJ^T^C1{^k4n$Lveu+-&7fWxfHrn8DN4&t;ucLK6TfN^xBP literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.script.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.script.png new file mode 100644 index 0000000000000000000000000000000000000000..674e4b89f0a97f1dff8637ffceec66f19ef68624 GIT binary patch literal 300 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4a{Eo zn0Wfbr!@=JnKtO0{=~L}g+tG7(JHmrEvr_U?~zU{`O9d}kixL)7mHZuJoo!-Upp3F p=WqC4$8N&;OzOt*rrE#F>6e=rtPQ{1&j@rhgQu&X%Q~loCIAlOZjJx| literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.send.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.send.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebe452eef430ca1a28af78cf7d8616e7a7a4451 GIT binary patch literal 440 zcmV;p0Z0CcP)>LL}bzk%xotj;|nA;JT|jkBLL7dvz_;T_=lua)xvu} ztl(Z-004dG+@6^SCnTk+7R)?w&g}v8>xZ-7*pf5@J5}A*`7@<7jWK?R$P&Oy4T?w) zz=Nu;z4ue++*{p6E%+j$EXMfG%+CPk0PbhASqA(J8Ni5{?_!LPB9fWeYZHNpvJk>C z&+}~s1HdSybVw;30F0`;d7kIn5Wb8E^u;0q!SBvR4$v$*P3!q4)vNS=qE%%l!=8WeG)5T!qOI6X0WbCbj%| z;Qo;i4C?@+Fm2+Tdp#bHe*kp5-4~5U;{tdbHq)$07*qoM6N<$f}+0Zod5s; literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.shell.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.shell.png new file mode 100644 index 0000000000000000000000000000000000000000..53226b1e91833e777b6dd811db8da22efae83b6e GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4-TS=8=P}GLLbv{SD$X3a>m0w5SU$IxRUPxelF{r5}E+Iym)v3 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.user.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/list/type.user.png new file mode 100644 index 0000000000000000000000000000000000000000..60562a0ae228c519d3f4571f48a892d42b546165 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4T86MDA{A z7f5m3=B<1q>csyXp~y1zzD?_EKL5YJr_tO===X^qXBKJng?x>3S;pY-$+BzF>{YAm zwxuu5b#`$H6=z6OIj(Y?A#K$z0YOftHCx3Q)aE5jwmGlg%rHrPUwWw(FH^|Zgp6nx zzGeo7*NO}$w<{cw*lfIoF@lw`P-Z<_(3;6AmAp)+HvM5S_|EX`?#=fM&+n|zzp%_D z<<%VNw?As9Zq_l*oE0~54|BmAPX>nfN=3J~y-mJs5^v9t{noO9eNsAe_wCF$hM4Q6 we^VG5o_x~p-n*-N8pDz6&Gnw&{+_%4+dsu>tF_WLU=T8Ry85}Sb4q9e0E_6JHvj+t literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/subprocess.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/activity/subprocess.png new file mode 100644 index 0000000000000000000000000000000000000000..329b24ca9a8b24864dc214684eeda04b490a5741 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR42?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4YHW%tNf9 zW5?}#4X;(Mt8P70qtCF-+_V2o&Djfr8~d8gbAr7#=GM*BFaG)ZW31mn%^TcRE^9Vl uxbfEDl*-DR_p;WW_jI3rg`s52Ir)%tAp*012^Ij|!QkoY=d#Wzp$PzP>0M<2 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/artifact/text.annotation.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/artifact/text.annotation.png new file mode 100644 index 0000000000000000000000000000000000000000..ab870a29537b0b696880f5f3c0129c50c1aabfa9 GIT binary patch literal 367 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/error.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/error.png new file mode 100644 index 0000000000000000000000000000000000000000..27603c4c86986f6f5b1a4a5b813ed68ddb8eec67 GIT binary patch literal 698 zcmV;r0!96aP)x!jk~$GbD!tA z=iKuglSFl8S=Mf54WI>Bp29Q0jHF_Cc=&Y{9~KT~X7zggh?z|TUBFsk2hb(yrlh52 zHkmN?k0%K;v)vvwTm|+3*MaZAbKpJj2AD{k+P^l&7*_zD zz?!t508XWn27sTy;nd=Z1zwuS$`7v0vxP#Z3Os~G6L8FOyqgqW@i18 z+$2%2*Dp#sYG(aKQQWBr5M%5C?$fmPTQl1s>71E8D2n2804U4y8SqikzC6#{ssipl z2FwEYfF+X7OZw*SLy%?xn!^-h9FR09={7J`Y42X(Eb!aRj=TGi64CxM&UKmwtEKP^ g&<>2c`|&FNFLL7VV$&j+9{>OV07*qoM6N<$f>UQZpa1{> literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/escalation.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/escalation.png new file mode 100644 index 0000000000000000000000000000000000000000..08dd1429d59d03e859e17f2ceda5ba2cbbccc754 GIT binary patch literal 3336 zcmV+j4fpbiP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0006rNkl|q75yzagmCN1cWA=?sO$I z;4Zpx*tyifX>Z z4V;fy0&V+VzJ>Qu#sFT8q{ryPU3`WQv4=mjNYIUcqP#n3@95|_H8C;qQ?*)MURztM zmP)02Jv}|gbGh7esADYG>v2kT;YU;gWv3O@|YpapXW{(sKg@v7+ooQSRjQ6pZ2~^kd zIeKEC+vvc>Y&P4>=kp)e>-F63?ry2sY<>~=zr$u5n)oGD&tfE;b{%P&rsZ0#w$f-c zhH)4#1j;HNwVe1TUJ1+A0_8fU(2sBMQOs*3@-nEk1nPlt6IUWQg5P4mmv9iXSdH8g z+A{n8LJ_?YIEvQ;aTE7&JMiW4Y*_r^et`oh#84aIyw2ED{EMB4<>Ktge**w?)}V)= SiHFPp0000_1Svv7N(G^VD2mefyp}*Ia8G3;6#N1yc!G2^6yT4->*yq6Ap|3>cJ|--XJ%(+ z4X7?5gbmxJq-I)@G?O#~su<%%-9B3?wq2IxuI&l11{_OjNooPdz?$tzvhfuUkZtFA zKDK=$%d*~JF!-u#q}%PT&*$?~;M-_4+5#}3vMhIjSJ#nNiS5T#RUJCd^9|b*NjK9) z1m3P7Jpe*FUILp9+a+*fyD#Yo=-K{URn=jgoU*(l=}6N3#3?c@Dm_gR&VU`@pe)ON zjob$gfF0Xs37$%7Ws;h<&zHtA#m^jX%`tS=xWD zGH7TqAnj#qLkL^8-${CI`=cZQw}1~Jgu7Xm{YY5b_N<}Blywq#+jb9l5@UQ>3-l?3 z@ZI)%;51kvb{iCQpff^ n+b@R0;cF7{%E40p_B;OqTC)QV^had)00000NkvXXu0mjfF=Fmq literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/signal.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/catching/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..19ea91858e1f1c91156e76a78b0a7755d1396875 GIT binary patch literal 627 zcmV-(0*w8MP)dix-joVSMp1M~av^C)(iMOPfQF0cSpzr(pBp1e*7bOe;Q54N2{j}d_J}CW3l58Z6NQTCCdRgskQ55e0oXzL+yZL;62jI-w zsL(;G zJkN8gjKTeaJO=>Bae5?g(=@%_Di>**UX#3a9H$2WmRT9xZ&|b3?LGl8Bze3ISIRyH zFto8v06!kaNb-%OuK@V31Xe`ym84IST9kw+iVh{cc3rnU7z~QX=;3f^*6Z~*lAqHw zegEhxZ_D3SndLQ-WEh5hNvD!V0G8!=ZNr)*-;z8ZkH;TmLH_SK{{ew55NEsU{ABb@?P)^WOJnc<+0Z zgfhC_?jgw-KqEf@um-S}Gs**+k4gefT8cC{>T;)0Z%aa6> zjH2ir$(k|dNt&ix>_M;ByXU>1Ncy!{EKVfJ0D!f2K(ZEwVe2X~0HkTU4a2ZSvSzIv z005&XIwZL=#vENo27ow@9|QPKa^tpNA7ew)gTDY0JJ1^oO9c5w>u_j zD|x3!dtQ40;FY9XK@i*l@Oih}HI~ce&phQEz_SW~2FViuEEkY;2H<|~e$BG%Q8`ZX z4S;V3SL1iduD09l+xwCXE(LP>Z-C?r03S)N0eq>~>mU04{@v0KPXVkexKvpaz}s?x z`F#E!z)|5_Yah;Lvmevxw76;l`1D_6ERYN8LejBu&TU8zz4wzONv`V&03b;c00000 LNkvXXu0mjfshaW4 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/association.undirected.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/association.undirected.png new file mode 100644 index 0000000000000000000000000000000000000000..f7954dce42305c445aef3fc5a0b2c7c3de6b004f GIT binary patch literal 413 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4U&3S%?H-dpd)1FqB%kj+BQ95nF&5jo<&x=~!1ki}6doW47)0d-u(KjaRQ)^>^*^=?*S=Gk$*4FTTEIsm|$VnX~M8 zD+8igyjFI0+!4I!EFT*#9ep7x-r(~gOY_awb}2GuGcCQcuR~|%&(sx_z7tY!h6=E> z=iZ(dm2KZXi!mYS`qwEl=QG+!CEq(XgE8T8_Pa&;CPi;W*YZwN0R|<5r>mdKI;Vst E0Dya?kN^Mx literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/association.unidirectional.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/association.unidirectional.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9be868d08efc8876b7039161b6db935f62d259 GIT binary patch literal 3032 zcmV;}3n%o6P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z00034Nkly=y1VIsPt;9R| zC<;LX5{-+=CfZCSpmBExzTzv+%z0-{qFk+G51%+eXQY5=9LLy26;n9G0vgo<4KmE* z60capDe7oe3R*wIGH&pNdvuT$X|RnNjxdQUydgz5$q{d0CNSzTbs9Z9=ON6-rrUTx z3r##mvlND1VGBFh59UtT&f@=5e>q5Sfa{pviuX%AEGV_O@gn9h`k!Dh2P<)^i{MKK zCJ(JX!V=EWz#Tq9+|IL|U=ypj#rwdv3o%zB<4<@gyRg24F-$}_(lX+H4zghGp<6}_ a-va=UOi%*TwY}y50000KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z00048Nkl#RrjZBQ3)Wpne5>fC0 ze1c95M0^nwF%mWq#9c7(AA7a$%z903BJ0k!6;)DI=hV5k|g%kt%Nnbmdu7$@+lP3mTz=b@^q7-Nj%@wmZVTtcsnL57Ee!C+BURV<2P7q@U8 zZ8mTmJ9v`k`C>F0y}}KgLFX`s>lmft@({vS2;m&Q;1}X5g9~_ud-#cOc!56llEHyH zY~llMrnEhL#S%x*N!;2$#2a{yb!?~P?@90*3xve?O|X$fckmW587vathb~THmd1LJ z`0JFgo08*!O_gQ&ayp%ce!t(~5w74A@?^RaYfaOv&*$@OGMPjSQZLP_vHwC*6!&|* zUOgNR-{3Yb;%M97)xj~G#cBM&JA6*3I~3jYNZ#XPDy(iRhCc%U&HZRG)o6B&00000 LNkvXXu0mjfl>OB5 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/sequenceflow.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/connector/sequenceflow.png new file mode 100644 index 0000000000000000000000000000000000000000..d757a24405b663ff6c7432b8fd66455169f2b293 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4rjid%bTNf8i5*AgAEn&J$TRpDB{(zh2?QZC=V- zSy(uh++%hWh#VMgLwe{*RkDi&eRM_~o{@3{Q z0>fjR&H literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/dataobject/data.store.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/dataobject/data.store.png new file mode 100644 index 0000000000000000000000000000000000000000..922f66f708b86ba3e38a90de2040ece9d05f5228 GIT binary patch literal 3184 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 WT7M%~IriZI00002?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4$h?Za;hN`RR?# u+P?*i;stC5&o)0k9JS%d4Udx2I>yQg)|@LcyOscrW$<+Mb6Mw<&;$Ubh(s0u literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/cancel.png new file mode 100644 index 0000000000000000000000000000000000000000..a4302bf88bfe9f8471042ef3e37694970de9872e GIT binary patch literal 910 zcmV;919AL`P)VGd000McNliru-vtX5MFU`FXJ^&L#l`Oy78V`@Kwn=U$z(DV07#OAMllT2z`Cvn`}_M} zc6D|60DJ&70CiCm{X`;hWLehu^(-L-06<+6EX#HhLN;r)ni`EpHw8iXd3bo3Jvut_ zwzjs~s@3YFgM)(*&+{+J4;%QItPy+a4bs9p!MRW@cvIOD2;m zO-)Uw9LMDx#~}bfFE204=jZ3Y$+Fy<$z(px=kw9s-Q7ILaq87BrD@v3jg5^TRaO0^ zy}kXpq9|WjmX!qnWHOmg0r(RW6W>lxPu~xPLOuXr6vfx7s>Wqm{)}bWe+eOeEEfB9 zZEY=S7)C*oq}TKF^Exz5dm%}Z>-&BH0NvW!`iy1SO8~wg2>UF{9$(=%ilRIKfbQ<@ zC$cR6-Ou@;iIF7S$adFX3Q51NdFGeDfM|*pF1puIF z`X9qEBF)Xs-L&hv7k34#R4TW6-}m7-&P|H)JP*}s^%8AuZMmxxLICKNmX>FPkjpC_ z_BoC_2HB2LKR{$DfL#SPF;3NhY062X=OLJ}H$-^w7}IX|Y&*RW6qqMN#sK zqKpC9t=H=xdY;#z>$*BOH@CmNz5QjSQh96J_A9KctjLC8{1pfUPN$}(-cP5~U&Z6` z9Z8ZJZ`5`Dp=p}GPfkvLplO<|s;Y0A<~NOlZW<|@&5n$R4Ual(#gpQ zdB@5u%Wk@^8|mrkDY~xv{m94&cX)W{<@5Qd=Xq15Qi%wH@WU-D-wabM77M0Qsh7RI zy|=<7%d$T(Fz|M8aPXZl(Vpi)6h#2Q>gwt-&-0H9g#xi{``*&h(o!y$`~2+ejA9t( kUN9K^={nA}S`7g3AKq>r_Y}*bn*aa+07*qoM6N<$g6qAjX8-^I literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/error.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/error.png new file mode 100644 index 0000000000000000000000000000000000000000..3e310a73b4a7d23e61f2a80e29e57bad1e8718f9 GIT binary patch literal 757 zcmV?woGV0Z5rl$*E+Zrqq;wZT-9&IvNN(W9g`i~9U0SMOB1FX`L~xY`x-g^!JGFrXKh_TJBT zNF0Fo{t9p=lHND7&w-E3%;x9kFXeeYY-S$=o02wqdV0pa_um3&baZquw%rSCrfGV% zEX#F3z#mmreOMI5Zq%p0R;x9us;Wzxs;cU!bIzTQ$tLN`s;WMX$pG~&Bjg9RGevq^z>2(x;#Qj@~H}!h`grvP@HlFACPr!qSohr-nXP`fXuw-UE z9dZXeiEM`@odJFw8XEc$AW4#OAjIHdfDpnjz|rVicam1(=XXg>=iE1wlam2pc6Rm| zkau;t=A1hK9E(LCy0R>9OKO|hV>7$gZnw9(MXai7g7?dXnJr100aD;?S(ekTD2gp$ zB80FisnOThx8l9;v`A4DuYj3YaSiw++EYbQY^4C(+uOGW1_sUn7b5s1%d$1#k(srf zb1P={MiTM(?lu~Y8vyFQM(_RCl5X*SvAW+Da1%HJ?CkFD-dtQX)4931o$mN|Yj^t$$N)2W00000NkvXXu0mjfju>Dl literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/escalation.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/endevent/escalation.png new file mode 100644 index 0000000000000000000000000000000000000000..3a4a724bd0948c0d60e53505b5eb24e5c1842f49 GIT binary patch literal 3185 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/eventbased.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/eventbased.png new file mode 100644 index 0000000000000000000000000000000000000000..7aa78b7186eefed78043a9c42d5b0a761888b372 GIT binary patch literal 492 zcmVSmS1&4N|+Fbu;X08cXT z-anH(m?e=cVg`%IHOV6p+3)xJ_vu~>z$M8G5!nMU%)$!EU)ao!opV<~5G?n4y|=>Y z76H77$S%qAOyaWIs=7KD48{Py%q%I+I+;v90BEDp7^~_k(%YG8z@K>@%xt|VsMTsM z08gDx$EG5tvy8m=k5LrWN!|k3E(!qbnAuGfMRo7}BY;sH$K6sy=UmIoUP<0f)fU-E zl4L0i!~0UiT&V0OIwTiF#E}#cac1@|A}4vcB*;tBsGk6kJNB^nE=q!;1OTewN2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4#|^;P`aR=xhX+SiCZv|Va8I0 z^ac-`@^i9tirEEcE>}=f&6{PovT=lXdwBs_}>-Op$foxPo* zZ0^Qo`s-G`@^A@ekTkx2CWiS$M@CfW)s6Ex*M_ZTasV3r{0<|-C!6iZW`u|CWoJ;T z%D?^Xpr!i5nw+(NSvJVmu)hE65vqPSDpdX6?~4~=g|lt~&8?i*-`O#vviZJT1-EhX zGhV^Kj(w~f^iOY+Fu5pEynNO6Rlg*>Dijy3-C+hD`Kbm|I2o24@pRzfJni_=)q!Q_kGb^>5&5^y#UI>s9~kxwp00i_>zopr08P=d AmH+?% literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/inclusive.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/inclusive.png new file mode 100644 index 0000000000000000000000000000000000000000..13e84f633bc517f7dc483cf37ed8c3980c7b086a GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4jnIb+#=PAB~fjPKs>`2mo2J`bQ|J03MJbT z#jQ`yDXz~+kNn2Dz+Q&${KBiNR_$YWa&D)%;*rb}r{r77=NY(^e$8n48m-;rZaQc-C6@pjD*J%xrlf6v() Y%)hjA!=>mCz|dvzboFyt=akR{0Be`5RR910 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/parallel.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/gateway/parallel.png new file mode 100644 index 0000000000000000000000000000000000000000..ef82f48737b83912c5a042e90549ec8773410e55 GIT binary patch literal 329 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4|lnl(#2 z-^lJzHN0%1>!7am_}Vr#1`kci_kRyterK_JCH1~dbLk4@oV!b=oGIHLR?qle;&D=9 zeP;giJEyDvUsxrZxMEv@s%7(c!B-a2?#=$J?wk#5tDB-W$@xEAwqTOU{?GhBm39RL TohoPq`iQ~P)z4*}Q$iB}c07G} literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/conditional.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/conditional.png new file mode 100644 index 0000000000000000000000000000000000000000..fe56892c36fe8c6b5c6a7fe274c02984da1103ec GIT binary patch literal 3134 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 Y0DT^2x!jk~$GbD!tA z=iKuglSFl8S=Mf54WI>Bp29Q0jHF_Cc=&Y{9~KT~X7zggh?z|TUBFsk2hb(yrlh52 zHkmN?k0%K;v)vvwTm|+3*MaZAbKpJj2AD{k+P^l&7*_zD zz?!t508XWn27sTy;nd=Z1zwuS$`7v0vxP#Z3Os~G6L8FOyqgqW@i18 z+$2%2*Dp#sYG(aKQQWBr5M%5C?$fmPTQl1s>71E8D2n2804U4y8SqikzC6#{ssipl z2FwEYfF+X7OZw*SLy%?xn!^-h9FR09={7J`Y42X(Eb!aRj=TGi64CxM&UKmwtEKP^ g&<>2c`|&FNFLL7VV$&j+9{>OV07*qoM6N<$f>UQZpa1{> literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/escalation.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/escalation.png new file mode 100644 index 0000000000000000000000000000000000000000..e19c715ac71601d26b2ca19e54a9dd30d9f4adcf GIT binary patch literal 3212 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/none.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/none.png new file mode 100644 index 0000000000000000000000000000000000000000..8b51f188c67b12bb1584925443c30540838dc16e GIT binary patch literal 450 zcmV;z0X_bSP)N82~Rw)gOdvn_zSu73c75W?54>z?(7QcA;8 z%F6c3X0!QX+d-0IjB{X6Rn`69U`gt_?zyU}dteY_oJ$gQUEc!R5W=T_!Ea3R)Ar{8 zG`5%5!ly}WFM$|zOnP@Me5ReGaga0ue!Z9OnNhgtyr7_CLGIoQ_RK!$*s{rgJU)^1 zJJ@~#W+|oNwPZ?Z2+VA+L(cgCEJ`V>wrwwF(zb0VrL2HO&iU}+Ds$RKfEeT4_BY#0 sNxRec_JK`+8L(Kd*WcZPd~}^(0hW8fflBbtcK`qY07*qoM6N<$g6RXvH~;_u literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/signal.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..828a260b602fcc09fed6ada9c77d8f8c77421f28 GIT binary patch literal 3201 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/timer.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/startevent/timer.png new file mode 100644 index 0000000000000000000000000000000000000000..adb275f4e91a42d1202157b5da038036310928ca GIT binary patch literal 573 zcmV-D0>b@?P)^WOJnc<+0Z zgfhC_?jgw-KqEf@um-S}Gs**+k4gefT8cC{>T;)0Z%aa6> zjH2ir$(k|dNt&ix>_M;ByXU>1Ncy!{EKVfJ0D!f2K(ZEwVe2X~0HkTU4a2ZSvSzIv z005&XIwZL=#vENo27ow@9|QPKa^tpNA7ew)gTDY0JJ1^oO9c5w>u_j zD|x3!dtQ40;FY9XK@i*l@Oih}HI~ce&phQEz_SW~2FViuEEkY;2H<|~e$BG%Q8`ZX z4S;V3SL1iduD09l+xwCXE(LP>Z-C?r03S)N0eq>~>mU04{@v0KPXVkexKvpaz}s?x z`F#E!z)|5_Yah;Lvmevxw76;l`1D_6ERYN8LejBu&TU8zz4wzONv`V&03b;c00000 LNkvXXu0mjfshaW4 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/swimlane/lane.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/swimlane/lane.png new file mode 100644 index 0000000000000000000000000000000000000000..f0e7a823bfc279536b4fd273c5569293895ae4d6 GIT binary patch literal 187 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4E*@+V;{%5!2apRTX;p{AYk*>z@ YZwjCKM~f}Xfo3pxy85}Sb4q9e04&ru8vp2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4421KEP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0004|NklHKCL^VoqDYaYm1Jo_Sy}i4Y_U;Z zHWp;%tx-eSh%t$fC?xW-G#A4dVO;mxoU7X{_sm+@d6VWdOi#}YYP2OIGu{T0kYM}e;><1?ON zb21=eHEJL%Uq$FK6a^k*8E%K-&L}>P)A=qM^hbxju&EUo#e=3SEQ}Tx5}reNo6KxU zUvJi(EJfuv_=J5yI)^Kmjpw+VOsv4ogzYsZ8aWunB#z=b&SC~O#p~hhzCHiO#c1$% zKrM|+aVAJh@D6h#?4z6>k{J{?&DgV>WVuRd}|%ho>Qc;j42s1 hfiHP(%gWV10{{`kbGK_P_!a;F002ovPDHLkV1mr)_Zt8J literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/none.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/none.png new file mode 100644 index 0000000000000000000000000000000000000000..7be082ead0f3d993abc3a029306e2405c1327346 GIT binary patch literal 582 zcmV-M0=fN(P)FNiO__p2z1T2)njmh^izo4t`F0|3ss5y@s8#}_0U*4jeSnB+Oh zb4g=sZ9%dTFiq#&2mqKQ$tlUXG3F)7hWGxPr0YD-@1M-(lH`rG_O+xxRaO0v^vaOT zB#q0m+g= zqzTDk6h$p-?SSOXA(2{)gD8qxB!`lwl!PqHt|YyUpz|IU%CG- UaOb0x?*IS*07*qoM6N<$g3Gi16951J literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/signal.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/bpmn2.0/icons/throwing/signal.png new file mode 100644 index 0000000000000000000000000000000000000000..c5979fbfa5fa0bbe98f38dba4b6e038e39cbce4d GIT binary patch literal 747 zcmVcBAHq$VKDRVY4b)#t3?Ms zxLm$-?&Uk@qa-w9aB$EkSpd)-7XYjPSdml=!?4`gZ}kI777B$Ck_(brB#i^e0LVxh zm()UXA@1P;0g?=YU`|rMnPtN;9Bpc9`ckP>ewf)FfXy%rN6joNsXqvUxw;4?p-?D{ zNa|0g)4gkJYiTnJNv@jNR1`(uNR9zGD(PBBN5|)ljg5CCXN$$+GX_E6lUy*fY!pRD z0K6snvQnwsPo+}tC2j5O>FMcv zsZ=Ttpo`>{WHOlv!|*nMJ0!<^-`|upK{9Xgq!-uM*DnHSZ*Fc5hlYll0X*Cvl-W}N z@I0>wptD>qX8J#nRD)YR`F#HB)YQ~Z0P~W%NG=2D zwuV=#lC}p1295!^i$fs!B$vxI0jNl-)$bFXot?dszLQ)7ATtX{<_-%0IG#)XRgk8&oQl`bf??=a$UuF@QDzuj6Vnv&YW4C6cpsG7#@V dBmQ@te*@$jHU6@4@HhYf002ovPDHLkV1l7MKcWBt literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/casefileitem.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/casefileitem.png new file mode 100644 index 0000000000000000000000000000000000000000..5c42a8f8a9b38539a803aa8321942604855e5cc4 GIT binary patch literal 2937 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/casetask.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/casetask.png new file mode 100644 index 0000000000000000000000000000000000000000..68be8d60547c3e95647e35c4bd3f4a4948ad38c6 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ydu{YLn>}1CoEt!Ff;qt&nvuk zW{PEunb0AYT$NK>n-4SOvq@*2ywE%%@Qj&Bpo624VzOSbXlIV2}PR$0OO zG+-BBmVk_M=hbP`rpak(X<4zEE9mO#?%TAfNbE$Kiu$621=?H-@3B0-a^*_Rlp`)> dUNQv?405ZUf7p?`u@LBR22WQ%mvv4FO#tE1Qj-7x literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/collapsed.planfragment.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/collapsed.planfragment.png new file mode 100644 index 0000000000000000000000000000000000000000..68e6ec2f9df461c191c2b8bce57c2076dc5a65d1 GIT binary patch literal 629 zcmV-*0*d{KP)E))u%)9LgN02F1ZRB98^+j6=5$uNu?P1CLbSds4c06eQyDj$jHb~c+)5Cn8C zcDo&QyIpb|=T1?SHGn4vJuF30*6nuttng1U9*=3i-@hgzK-07<$8qldi*Sh5YPGg) z`zf;7?6BYOKZHTOUXKjJ_zEI=^B@8d1wlZPB>lXYPN#Z4p9cVhVTi?If&0R;EJ%_B zS(Xuop#%UiSqKrg^=~PJh&9Dx@r!h>5@QTP2yo8fx-K~95JG@4cCvRk9A2Mw5>>iy zO+?gaG_Ef)nM?rSQIhWaKIZc|mdhmo#Ix`FCr)a$TIHxaQ6<-P&)!A!J#rFt2b0O< z#dfUBnsvGMy P00000NkvXXu0mjfv(XGa literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/decisiontask.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/decisiontask.png new file mode 100644 index 0000000000000000000000000000000000000000..0351fee8a4a147e3e54c9ddbfcd9dddc25fe693d GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt@+JY5_^ zEP9V#HuPdn6k&PbfAN@8N7zBPX%$T+Nr~xi8FP}?rR1v19k}GQp-WsqOgngGLSnKD z_xa=F`tQrtuRYq=E}ZkHFt1VCX8DJP_kGvbs8t+QzSrFUv1$2( z-#5-G<~(Mw?s5!Pic1Xop|ZtA*w}mS>Vpi27x6l0hh4wMHT#E-p!g4teWLoOyLOhX zJhVb($FVIRGBY{@!y>K=@72EIYvU??UVO*l)DOlo4{a)x_j#FSbRU#{)_UGKd#!@@ vo!@u+_3ST+^IcA8NWOdSQ0|gn>3V;J literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/expanded.planfragment.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/expanded.planfragment.png new file mode 100644 index 0000000000000000000000000000000000000000..c68cd0a80238b1d6ff9bcbc5c97254ad73527ee4 GIT binary patch literal 386 zcmV-|0e$|7P)3tRf{ z-@gw}pFaKn^XJe1*ueMi-~XRFb?SdXLBS7BPR@@&eI_si#6SWE4jlMT3b=Xm=Ko*6 zekFrV067h0@_#bGt5>f+>gnk@Gl+?aT{v^*3^``}KYjZ2e_$BhWdH_P<$p2(DC`&+ z8UHfezkk2uKLr39gAA0I@gEo_Hz+m)lzu2Sq@|^01p_-f`wxo4getLf{rdIb&!0b& zWysmHXF=)Y9s?H_*Bn@ieg6D8QJP`uE?&I&31~i^DVm02yACUwbomRsaA107*qoM6N<$g3Uapp8x;= literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/httptask.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/httptask.png new file mode 100644 index 0000000000000000000000000000000000000000..ffba8de117c51945335082019349be32dacc78a4 GIT binary patch literal 1267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0WW zg+Z8+Vb&Z81_tJ3nIRD+5xzcF$@#f@i7EL>sd^Q;1whpd3^o;3KxS@gNuokUZcbjY zRfVk*ScMgk4HDK@QUEI{$+lIB@C{IK&M!(;Fx4~BGf=YQQczH^DN0GR3UYCSY6tRc zl`=|73as??%gf94%8m8%i_-NCEiEne4UF`SjC6r2bc-wVN)jt{^NN)rhQQ2mNi9w; z$}A|!%+FH*nVXoDUs__Tqy(}E4xsMLEr45;R}A$P(0}?Bi3R$GdItK~G?iqgA)JSz z3nYV6TWUon4s9SAh&FIwK-_2p3{flJ{FKbJN|(fvR68RBLsMM?V_jpz5JL+q17j;g za~pj$H3%PqbvqZOCYIzEh2-bw*ac)(q~_#;xC+L4#t@yz@<>`izOeEy%1i|YFDMZ0 z3~lr=#L(3{=jRp_r4|>1)SE)pBa5M{4@xc0&nX2NADWk0VrK-^f+mcvD-t1ZXAaYY zEQqcl0-FY8K_m^JXs`l@Q-n)qZfYLbFNS6|`dB54=o-U3d7J^$R?dD?) z6mdQNSY1VG;tLTgUMa!OL-H$FT2~xle^KJ}I#|R@v|eH2i;g~lj}g{}CuP&rj0LSD zji1lke17h4iPOIVCkp%x++%sdiOtNQ*+J_;)Pc(hJ~AG%G3o)I1+J{v!59|9FJHRS z_rSeZjXxO6BMwgwO4)Kp>&rv7XPe$u_}Q`XsY>J?G^^ZuzT#8gx$g;53nEYF?=}_p z%!-eT5B{PY?6SNRln4WvVW_^4+wgGn%2?42r7v@UHx3vIVCg!0Kr9^jsO4v literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/humantask.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/humantask.png new file mode 100644 index 0000000000000000000000000000000000000000..f19f6ef41f96a62c2ff63c471d710c0d34dfb1b0 GIT binary patch literal 3015 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 JPDHLkV1i?9m8bv! literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/milestone.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/milestone.png new file mode 100644 index 0000000000000000000000000000000000000000..6c2e106b7163bad5c42f09d1a5856f1d29a26484 GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zKpodXn9)gNb_Gz7y~NYkmHjTGJU^Gh+|4fGK%rHhE{-7KMl=YlGo4&VjR2*PS&ousTtbE%$)io`Q^GlZSm)jbG z-Z}=a64qIyKHKOkAeb#GJb7lB?bCezm;e7eZ9O2X Ye{HVqnRy=UKvy$(y85}Sb4q9e09LzdK>z>% literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/processtask.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/processtask.png new file mode 100644 index 0000000000000000000000000000000000000000..ff9130bf5d0311b52a470da7529f4613dbced090 GIT binary patch literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`x}GkMAr-fh6C_we82_I<5W(xI z%J|r{MZ!Va+2dl*!g)z&mplq7**~GHU6_I4pq9a-?wJ1tK#dHZu6{1-oD!M2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4a{Eo zn0Wfbr!@=JnKtO0{=~L}g+tG7(JHmrEvr_U?~zU{`O9d}kixL)7mHZuJoo!-Upp3F p=WqC4$8N&;OzOt*rrE#F>6e=rtPQ{1&j@rhgQu&X%Q~loCIAlOZjJx| literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/servicetask.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/servicetask.png new file mode 100644 index 0000000000000000000000000000000000000000..8035fb984d9755f8befddfba0ca29928d16161bd GIT binary patch literal 530 zcmV+t0`2{YP)b8E^u;0q!SBvR4$v$*P3!q4)vNS=qE%%l!=8WeG)5T!qOI6X0WbCbj%| z;Qo;i4C?@+Fm2+Tdp#bHe*kp5-4~5U;{tdbHq)$07*qoM6N<$f}+0Zod5s; literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/task.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/task.png new file mode 100644 index 0000000000000000000000000000000000000000..40c8f70211f226436f34b17ed42082808692ceb8 GIT binary patch literal 2990 zcmV;f3sLlmP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0002lNklr#7A`=t3%6k7F052A zYEa=tBF1asDN=-&1X~AAbTgh*vBDmF>DBtxIMugZcvM2^f6eVOpmz40lHXAQJ!^lBA&S+SOwqsz&q+H kvR_9;+Y1VeV3~nqyPW_07*qoM6N<$f_@B$6#xJL literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/timereventlistener.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/activity/timereventlistener.png new file mode 100644 index 0000000000000000000000000000000000000000..adb275f4e91a42d1202157b5da038036310928ca GIT binary patch literal 573 zcmV-D0>b@?P)^WOJnc<+0Z zgfhC_?jgw-KqEf@um-S}Gs**+k4gefT8cC{>T;)0Z%aa6> zjH2ir$(k|dNt&ix>_M;ByXU>1Ncy!{EKVfJ0D!f2K(ZEwVe2X~0HkTU4a2ZSvSzIv z005&XIwZL=#vENo27ow@9|QPKa^tpNA7ew)gTDY0JJ1^oO9c5w>u_j zD|x3!dtQ40;FY9XK@i*l@Oih}HI~ce&phQEz_SW~2FViuEEkY;2H<|~e$BG%Q8`ZX z4S;V3SL1iduD09l+xwCXE(LP>Z-C?r03S)N0eq>~>mU04{@v0KPXVkexKvpaz}s?x z`F#E!z)|5_Yah;Lvmevxw76;l`1D_6ERYN8LejBu&TU8zz4wzONv`V&03b;c00000 LNkvXXu0mjfshaW4 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/connection/connector.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/connection/connector.png new file mode 100644 index 0000000000000000000000000000000000000000..34462c3d7a733bfe6b2bd99e60f3ffe353c76775 GIT binary patch literal 2988 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 iA^zeg*0SV*{0#tG3@+FTp2Pb90000@86d#I z!g4P+H#a?PL=00000NkvXXu0mjf3G!!g literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/collapsed.stage.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/collapsed.stage.png new file mode 100644 index 0000000000000000000000000000000000000000..1c2c21c67007b808e4a97bb93858dc27979a88c9 GIT binary patch literal 625 zcmV-%0*?KOP)gyMY>-4%MKn*M^qu_H3})=#Jyg{%|O$^PjJ%Qx`;pQvml$sQ{3V z;+Vg`s5=AX9LISZ3$)oOK@PN%yf0+wYx6pO{(a=H8z;H2epDaB%OXIa(*N~vHnnfw>v zq{(C=N~s_Li2Ugb0E@+fFbuh+TrP)g+W;gI2{=MxmCNN1kM|V)en0jDlDxK3uh+vE z!)!LgbzNq&8O9ilF_cQBcmAu8Y&MJ5np7%9x7#I^N};tzYmH@D@BHc-BnSdL&tpEH z1H_}_I9Gd=R7&lq)9J0qv0P82LNo_Mr%zzp9dhH z&!e@Dw<97n8V!H5**u3~_@V%|+wIe6H2T(Vx4#2l*6TH%=i&Q4uIu9aKAz_R5JeIF ze*f2KH2SgKZl7YRoW0_^ySsnh6Wg|b^7kv2%l~A53vkSTJ+J!>_#Fw7YCcac00000 LNkvXXu0mjfM`08j literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/expanded.stage.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/containers/expanded.stage.png new file mode 100644 index 0000000000000000000000000000000000000000..01535249653b47e152cc4006e170445d3cabbc28 GIT binary patch literal 252 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 VHCaiM%79K}@O1TaS?83{1OVlqVJ!dv literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/tables/planningtable.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/cmmn1.1/icons/tables/planningtable.png new file mode 100644 index 0000000000000000000000000000000000000000..80ed1f9b344faa2ac7380b4b9eb703f782de4fd0 GIT binary patch literal 476 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 P?E;kLHRS4KEkgeXtz233 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_checkbox.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_checkbox.png new file mode 100644 index 0000000000000000000000000000000000000000..463c9a2747683cb05695d2ae5ec6af703fe38f41 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4=z%BmB7a?00Gh0`Eg(OYaBdt>&MY`;1{L%dSj$Y^P36qwHygJs{Sd)0~ zIL{f5=Q7?&TRZ->9<&mPdL8-sN~!K7Hipnp#)P%LhmOsdc&<-jX-|>G_rTaIju`^S z9`5kJrfU77UD!47$C-nX%njSJCj?z8>-}GSCq6K?jHTgi-sAi4pQqQcUq79@q`2Uk xLd&uQ2Eltx*KTPpRby<}r1Mv)^S}Kv{SWta#3N#hT!D^f@O1TaS?83{1OU$acryS1 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_choices.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_choices.png new file mode 100644 index 0000000000000000000000000000000000000000..45b779bcd7b216eabc2a1408388042f610f7f6ec GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E zL4Lvi|1(@a#S1i$!N$|YF{I+woIXQ71_KVJ#{c%a+7^c1^eXuvB#^-=-yrncNn#RX wWb)OMoEaBNjOVF3L@1fubK4mEm&1TzbvGk3lhlSYKyw&8UHx3vIVCg!07Vf%@&Et; literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_combo.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_combo.png new file mode 100644 index 0000000000000000000000000000000000000000..aba156d817d23fb494c06449351fa72ad95fa9b7 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4Z` z6iPSHzL+IQ9<+8Fiou}Z4(txReK0>JHF@ZP19#@kocl9_suFX)nCZjgz0MaiJ>M_W zL{<6vo~!3gs8+8Sjc)P%DTl)k=g4d0@g0NyP$~ePH^Fs#?DzZRg6sA&26@f%CJg#R z3_1AzG{04b^2rB4+JZ5HF@lKDYPD&%9YiEy zx7&+igNVsi03ad&*!DF+utrsBHe0M#OC0AWNumm>X$vMbI5}@Nn@koF!)momlEf^m zAck$*1VIqZBsBw#SYlAG*9pT-G_=$-pCn@tAFwQo?RFcz$dSBWY7oP+tRxP@kVc~p zK(pCmy2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4lnOExHWRnv! zZ$8>P|HoXz=QWvYV^wWC4E0{AELBNh&2v8fM3?POKLW!!PC{xWt~$(69BGaT2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4!>igU;U~&f8LzN znacyu%*_>PU911-^>5)g6=wlKHTm^^SIWz+E}U}6NOcIw6Pd{4xOh9`@3{$$-!}E! zf5qSb{lgX`3!C>z7IlSHd+*+HR&nOAW-jM+VTzJGt?;4R;+34WcSlM_EJMS=7dJZ( z*8NU+<|HZ5Ig`8besorX-ZJhl+k0;BmR_?p>TI`Ht!&|+mY;J}3|IB?F3D`VmB#wF suIpErXymko8)Kd4J)d@P|Nmq1uh<@|n9U8m1Pnh0Pgg&ebxsLQ0IX4;!~g&Q literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_header.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_header.png new file mode 100644 index 0000000000000000000000000000000000000000..d15165f4be9dca17a7058422e6a334be90794ff9 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4B$alzq$2C4ctSyddrSrsH1xIC+k0-o2ajuDlS!nu;10u6eW_2npIi;PyY2PII z-^U$8KW-?#%ckVu<>{^2!J*W2RrhRGsOoc>MV7Mu?Y{c{&re@sJn;9|tt*X!dlcOo zj(`64)aXm{imhVK_Ii>fzxf(|+6HIqzM1n|`aj!h*Qn+Hy;m3NPpWR=Hzopr0E@h2`v3p{ literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_help.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_help.png new file mode 100644 index 0000000000000000000000000000000000000000..a481373874c78080dc79ff6d015c0ef75664db07 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E(;F6(&$;aXDWW+34W*J?{ViUQ?HsjSSK6`6N5@XUBzKo-O>tNr^>5=&tp# z;|`{60X4NY4;35|u0CchB-Kiv$D9G}gkkCy&Si-OAwU>gTe~DWM4f8zq#L literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_hint.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_hint.png new file mode 100644 index 0000000000000000000000000000000000000000..457dbbf2276e70fa94dfed6d73f1a8456b7c8adf GIT binary patch literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EG|Lu}>cd1Nox$KMQ&v(qzsm=t7%QfZ8-rH+ZlO=r@NM=gcWlLY*X;Pmfb7HkY zc8t{BJthsgGBaCL>vCl7?lGQna>6#Cq5YmNjv*DdV)`Tb4m)r-_s%>sYsv3>zvpi@ zSiB;%_enoHQ_rcbK6;;@9^rcDGKtAEp-%l9S7@W>o-mf0)CCG(^pZ-#XHIaR{Dsp{ zAm{2<(@k49EAR^3G<7a%h&B;2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4)OXc?Iy=9lHT7pn z`puag3atH0UdD5*NR6Ciq`{!k_2}A$@Bca`JpZY>c5B3S(QCK1%P}O(OTYO&wk>hO zvP_q3-Kgx3_uRumOII<^j0`CVxNgd@;C;1#;FKWs-RnyodJOuMJ2-N0*KKXrcs=Lv zwp@mW%vp9~7Izs18#^wP#+D@YI7Uu0I2NPbqI!?f*!$QS&-N*Q{~Oyfo@1ZuG(Bxy Q6wpHqp00i_>zopr0KuDjhX4Qo literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_item.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_item.png new file mode 100644 index 0000000000000000000000000000000000000000..26e1dba2c5c94b1a08d80eed4d558c3039468320 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{ENI}7YHJg!%hoSN!!*$-Y9e;t!7(8A5 KT-G@yGywo~zAWbe literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_itemset.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_itemset.png new file mode 100644 index 0000000000000000000000000000000000000000..3f5170700e666867cbccf60c8b9a229f1efba7a2 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E2?DzAWz!U#WAGfR#JisGmnWN0~1Fl3kL^J&q4-9Hiq;Q3~RGhn!AC@7(8A5 KT-G@yGywppqb&~r literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_label.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_label.png new file mode 100644 index 0000000000000000000000000000000000000000..d20cd3c387f2bbe3687c1422b4d480105f0d6880 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUfZd~z?Faq)=OI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i<5db&7>nLvDke3bO;(d42?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4)$dsMxr`E7gT z9W?QXtWDm|dcgmdKI;Vst E0379X4gdfE literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_output.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_output.png new file mode 100644 index 0000000000000000000000000000000000000000..b50cd8f46846049549a47f874a454e541724fcfc GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E}_o1RyuIv$bl0FPn|i!6ngN~xl>0@oM;kwkeHOv ikoE9b8n;6OBZI(QuG&1dxk*5?7(8A5T-G@yGywpyvtZ-^ literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_paragraph.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_paragraph.png new file mode 100644 index 0000000000000000000000000000000000000000..2caf4c1249005fe6ae14c516304c3cdab0450728 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4vnVo*2R;z_1N$Mzy5=|r$axfSK zV+_mX5~I<`T(8$3`~5zX&*$go5->p!I`Me?O4Br3GQZ!CNF*W~hH*6>k2?T)n3nM}HTK3}xeY85Qq(ZKC?XH%(^3;?fh zIv$$$n0`(%{hZ>Vd5_mO9RLuE#bi+wvkrspcB_U$AppSR;~z(}7N;l*cDtSGFd!m_ z=o~obwzo$EQ51)>*$e=XPG38O7PnX|APB#!_viC|DTz;I;_v(^5rZV!Yi;Ii@{{4rI zjm^~5R8&+WbYH!}YQ&CZMbaXB(Dsggh{qf`Hs#Rz~ScR=AS=* z{r&r|tE;E5uvk$^NnKsz^OvtXcI?`|eLEi?-@`{wl9N+^{P>}%simf-cKPx(CPpTH ze*WpxXHS_j{mGMO+1WYD$|}`0bw$OczkmP!_3QWi1&cB>a~?l_mYA4$>oXP+SJrqU0rKxYR<~SA}lQY z>C+dWk8-zr0KLZGSrX(I4CGP;Fz|594+R=J#nZ(xq~cc6hY!H;OXT1@BA3z7$T*i@ z=)(0U$>pU2)6Ckn5)2cbObD8k^7Q$ah8YVFoyb1&BypwQa&FVZ*P5i4#QHn)X0>tm zOWbgf3|-MMd8TrQ{({B4q7%}ue46m}!-h@8ZMP1oJXBlsMltI|4%1fG6Z0kp9(0}% yct zA*FQNjX-GKl3o1#10nr|aflO~bso45t?WqhLlV~MLa7_uq|j#31D8AZ&YhVvcg_fs zcn+jztp<=ezdWUFIZ!nP|Kf#V>O6dZ1dWvyV z*SFAYHUR+DY84lavnk4xEV9{Id_De>zQX4E)@VYO<*`mb1tBD;nv&`O0CKt9SOJ+l z2x!uN3(dA1yjWXX{XDmrMLvIm$G%X=V}9usip2sJmgi6^6|uN7k8-(;rPm9nR4Pz4 d1>(Q|#-CP09NK4u0QCR>002ovPDHLkV1hg#2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4z{}1H%C~fLpyY}cZj?M`(o+oam zBqS!@NNl_7J44dY!o~N!qQb9z{ihTd6wZI1-*&z9uF{gsUqQztcn&ip`%I{}U}(tP zbzrV6gTq{rO>a1|byuxw+G_S9A#&PT$Ga94_J@88mOfT!X%H~~Tm3)gz`Sgo5Kc|i zB~vs)e(rU;UTSmRxP8IaXWMckvt^%jcHHNxVG=BKatUmo^5?&CEaRG;D}^uZ;Hd+8 OhQZU-&t;ucLK6TX?|xta literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_select.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_select.png new file mode 100644 index 0000000000000000000000000000000000000000..568c6cb858609af44685f0d98e3a488a56bc83a2 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{E_CVE6e}@ literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_select1.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_select1.png new file mode 100644 index 0000000000000000000000000000000000000000..4bbb9385cd9b02d4b5e3e6b6f78575273346d9b4 GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EgTe~ HDWM4f=Y=hk literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_separator.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_separator.png new file mode 100644 index 0000000000000000000000000000000000000000..c46362be5f86a81475f0f2534d0eec5e76720c9c GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4w3x@Dul^hhdFJc|xKuFgP?YGCXeJWZ64?w>Qur22WQ%mvv4FO#t+2XtMwS literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_switch.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_switch.png new file mode 100644 index 0000000000000000000000000000000000000000..3d818beb262983104d7c10b17feec1880541caf1 GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{Eo?*O5}P*f{QB)jZf?<)Yq$UZ|IZo9Jrn2whms(_U?7(gz;LK~ zqYKciHcuDFkcwML8@8t>FeGwt9{HBhz^HcUh;oJ+TNsz&GSBt88YF6!H^Vs$x zy6~e{fx^v2DQgd%(CvE@BmdKI;Vst0PnL9CIA2c literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_textarea.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_textarea.png new file mode 100644 index 0000000000000000000000000000000000000000..125fd8bcf3384f540bf31fbe2907866519f63f51 GIT binary patch literal 419 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4gP=?fp7;KO;jr-@|s##v8x@W$<+M Kb6Mw<&;$VRUZ^Ml literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_trigger.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_trigger.png new file mode 100644 index 0000000000000000000000000000000000000000..df1e2c53b12d0e78587d4ab3114cff139c630210 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EM@T1 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_upload.png b/zbf-admin/src/main/resources/static/designer/editor-app/stencilsets/xforms/icons/new_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc01398441add3c03cb725600f4c7e234310c31 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl;=8&~`zjDUQ}64!{5 z;QX|b^2DN42FH~Aq*MjZ+{EJ9J-as3Yje{TSJ2?+^TuU>U= zw%WaGo|2NRl9JM@l@n&pXc83U+r4{tM|*KvYM8OH_NrB@IyyQ81qI)|duMEHoR*g6 z;^K1m?%mK3kMgqAySI10dvof{skJj_&I}C=EiW$@6%{>m=FGNj+hk>Bj~zRgh99IF!uPCFX8G`6fzK<@WtjlNm@YSx=e znrElDI2Jdrv7D{3_2HUJynTxl`VM_D`D1bEUs+gYbN0CteHm81x7j(*`&fj%vRt>D z+2qx%9|8|;^y--XRK;R?kMb2v4HsD18dUN^)umOA{pzXoveZR-dn4Ca`ZSKCAf!TLh&!)NlE-O~EzTM;Wnor86NXB@v zibaAOXThRf$-9{(Y?Nf`JH@V>&J>Qho?>&Zs55c0<-t4DP$uRytTIjb;T_&Sv(VL3oBZU(TA6cA`D3nR*sbAc4_nS^uj{x8Q>YfK# z%Rl!2X5-VcT4NHvLr`2>X34E%Gv91HEGcSx=k(`bWwSSd(H4^zwO8-iS=PC`cE^6{ znb$Vi`7Qp@6s>oE+7~OMwW+h-{NgGuJG^yG|7DFc`Q|aFe_8Z8MQgNe&5=$Ic(d(Y iOj+yYd9~sR3|sOKA3UFUd>$|fF?hQAxvX= minLength && !item.enabled) { + $scope.safeApply(function () { + item.enabled = true; + }); + } else if (elements.length == 0 && item.enabled) { + $scope.safeApply(function () { + item.enabled = false; + }); + } + } + } + }); + + }); + + }]); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/editor-app/tour.js b/zbf-admin/src/main/resources/static/designer/editor-app/tour.js new file mode 100644 index 0000000..0f29024 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/editor-app/tour.js @@ -0,0 +1,201 @@ +/* Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var FLOWABLE_EDITOR_TOUR = { + + /* + * General 'getting started' tutorial for the Editor. + */ + gettingStarted: function($scope, $translate, $q, useLocalStorage) { + var userName; + if ($scope.account.firstName) { + userName = $scope.account.firstName; + } else { + userName = $scope.account.fullname; + } + + $q.all([ + $translate('TOUR.WELCOME-TITLE', {userName: userName}), $translate('TOUR.WELCOME-CONTENT'), + $translate('TOUR.PALETTE-TITLE'), $translate('TOUR.PALETTE-CONTENT'), + $translate('TOUR.CANVAS-TITLE'), $translate('TOUR.CANVAS-CONTENT'), + $translate('TOUR.DRAGDROP-TITLE'), $translate('TOUR.DRAGDROP-CONTENT'), + $translate('TOUR.PROPERTIES-TITLE'), $translate('TOUR.PROPERTIES-CONTENT'), + $translate('TOUR.TOOLBAR-TITLE'), $translate('TOUR.TOOLBAR-CONTENT'), + $translate('TOUR.END-TITLE'), $translate('TOUR.END-CONTENT') + ]).then(function(translations) { + + // We're using a hack here due to https://github.com/sorich87/bootstrap-tour/issues/85: + // when clicking next in the tour, it always sets the 'display' css property to 'none' + // The hack is simple: before the next step is shown, we reset the 'display' property to 'block' + + var tourStepDomElements = ['body', '#paletteHelpWrapper', '#canvasHelpWrapper', '#propertiesHelpWrapper', '#editor-header']; + + var tour = new Tour({ + name: 'activitiEditorTour', + storage: (useLocalStorage ? window.localStorage : false), + container: 'body', + backdrop: true, + keyboard: true, + steps: [ + { + orphan: true, + title: translations[0], + content: translations[1], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 300), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + }, + { + element: tourStepDomElements[1], + title: translations[2], + content: translations[3], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 400, 'images/tour/open-group.gif'), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[1]) + }, + { + element: tourStepDomElements[2], + title: translations[4], + content: translations[5], + placement: 'left', + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[2]) + }, + { + orphan: true, + title: translations[6], + content: translations[7], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 720, 'images/tour/tour-dnd.gif'), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + }, + { + element: tourStepDomElements[3], + title: translations[8], + content: translations[9], + placement: 'top', + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 400), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[3]) + }, + { + element: tourStepDomElements[4], + title: translations[10], + content: translations[11], + placement: 'bottom', + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, true, false, 400), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[4]) + }, + { + orphan: true, + title: translations[12], + content: translations[13], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, false, true, 400), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + } + ], + + onEnd: FLOWABLE_EDITOR_TOUR._buildOnEndFunction(tourStepDomElements) + }); + + tour.init(); + tour.start(); + }) + }, + + /* + * Tutorial showing how to use the bendpoint functionality for sequenceflow + */ + sequenceFlowBendpoint: function($scope, $translate, $q, useLocalStorage) { + + $q.all([ + $translate('FEATURE-TOUR.BENDPOINT.TITLE'), $translate('FEATURE-TOUR.BENDPOINT.DESCRIPTION') + ]).then(function(translations) { + + // We're using a hack here due to https://github.com/sorich87/bootstrap-tour/issues/85: + // when clicking next in the tour, it always sets the 'display' css property to 'none' + // The hack is simple: before the next step is shown, we reset the 'display' property to 'block' + + var tourStepDomElements = ['body']; + + var tour = new Tour({ + name: 'bendpointTour', + storage: (useLocalStorage ? window.localStorage : false), + container: 'body', + backdrop: true, + keyboard: true, + steps: [ + { + orphan: true, + title: translations[0], + content: translations[1], + template: FLOWABLE_EDITOR_TOUR._buildStepTemplate(false, false, true, 500, 'images/tour/sequenceflow-bendpoint.gif'), + onNext: FLOWABLE_EDITOR_TOUR._buildOnNextFunction(tourStepDomElements[0]) + } + ], + + onEnd: FLOWABLE_EDITOR_TOUR._buildOnEndFunction(tourStepDomElements) + }); + + tour.init(); + tour.start(); + }) + }, + + + + _buildStepTemplate : function (addPrevButton, addNextButton, addEndTourButton, optionalForcedWidth, image) { + + var width = 200; + if (optionalForcedWidth) { + width = optionalForcedWidth; + } + + var template = + '
' + + '
' + + '

' + + '
' + + '
'; + if (image) { + template = template + '
'; + } + if (addPrevButton) { + template = template + ''; + } + if (addNextButton) { + template = template + ''; + } + if (addEndTourButton) { + template = template + ''; + } + + template = template + '
' + '' + '
'; + return template; + }, + + _buildOnNextFunction: function(selector) { + return function () { + jQuery(selector).each(function (i, obj) { + obj.style.display = 'block'; + }) + }; + }, + + _buildOnEndFunction: function(selectors) { + return function () { + for (var elementsToResetIndex = 0; elementsToResetIndex < selectors.length; elementsToResetIndex++) { + jQuery(selectors[elementsToResetIndex]).each(function (i, obj) { + obj.style.display = 'block'; + }); + } + } + } + +}; diff --git a/zbf-admin/src/main/resources/static/designer/favicon.ico b/zbf-admin/src/main/resources/static/designer/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cf1ae80fdcbe086b054a925b355458dcbeede9e3 GIT binary patch literal 102134 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/fonts/TitilliumWeb-Regular.ttf b/zbf-admin/src/main/resources/static/designer/fonts/TitilliumWeb-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6da821935dc29725c445ee8b469a2242c508c481 GIT binary patch literal 63752 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 D2bv~K literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.eot b/zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..74c04811b424a38cd5c5abf43b7747d396158dd7 GIT binary patch literal 4160 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.ttf b/zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34f143ff7d6fed9f797a97a9b8f5985fbd04c155 GIT binary patch literal 6896 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.woff b/zbf-admin/src/main/resources/static/designer/fonts/cherokee-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..c210f615339b1bad4db8af25ce817f335e5565da GIT binary patch literal 4816 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/fonts/glyphicons-halflings-regular.ttf b/zbf-admin/src/main/resources/static/designer/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a498ef4e7c8b556fc36f580c5ff524025bb11c84 GIT binary patch literal 41236 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%0Dt965W&Ju+|y^E^FA zPP8Wn|EJ%ftZLjCitBgWi>w6w*#0~Kje_rFS$t3DgEDi22Sd9^3T)psi+YpGd}5&| zxuVkEvI*}HM)f925N^&i&_lUwW4{peKDwb|((mmav+#>(l&mdb02D;k#;wEEKj3yp zbdR?<@X^EjOuXH1*oT8}oxtX&=DW%8pagiK`IIH>uS9TgkQw9F192cfuJ3|M?~ZoF z-kS&+lSqroTI2_$u#uZJ;k59aiHS)n!EGi=P0^_lHKQe(-`*MIz&-lNGIqu zwxaNFblB@K%A+KQDOi! zW0c-6e11ApPf&8SRb-LpisRsVu25HI_c$~Z_u^>KT-kU5o^CtBSZ=Z%`vcMcJ%Nn8 z)8;p1WmE@<^fEz_^bX06om1U3t5VV!`k|KWQgnNm-JJ zVat>c#QF#<04!aL2D~BxRiD_B!Dx`BtV7+gn3vvV8EOw8>O%0!L47Eo;{Diys=X6{ zz5O>mbO|rP)9|pRO{BrmxiTa&4PdKrtN~0=>waN6>t95kdi&X^SBN$jk6l`#1jXsG zY8oS*HXtd79%HG}fi?TJES9X;DTCroDZV4UTjA%tF#t5AeE*G+XggL^w$`x(Q>2*0 zIs%2?WThfIwq;DtEVqXaeRfya;!rNA29xq=|28Ve5~xc?j0UC$5sbm_6`XL*ZxKwh zWd4@-%^~=@wB(%588G)WcRq{tP8cX1hQw7Rn6>de{xk3`+`5>ECJ_`+cdDb@WS#8` z5dHk`L0Q+J)2=MyC5gN5IKg8-`$VJ^;UsO?p6P|-%$+n?M}koep3fbk^dNc zMrj;*zZ;e96u#MYtL{8hMq|&=!UF0Xmmh1R=M|(hOF9s;Qsh#c|EE3!8CR4Z)!?_C zpb+0xdklMbjYm2z(*8p%BX-o1wnIE^GzlkShyqNmd)LaYR&dS3x1kt*=01Ana~b6P z_SbtlHQ9M7n#s?9-mbx`uoq#5e)aP!EzVEm`0X9OX_N~kv_^S42Dq8^j9_-VWhF_$y1JFNXqn4D93!zNIQB(8N zYjOg}fV&lbzdxN?bGeBaHQp>j3r2uOeeXiQ6_9;RO(XKOPIfp5KZyIK8WtP$-OyBtZQ&d3uJ+pY6x~d|3 zD^K!?{KegwmU2`=Qi-e!qq@|etH15;>ax}Q@}x}u(Xj==$Aof9_$G?dv?dy&Qwojp7V0N+u^es?PNk^ zTB(`ZIr{2uS1^~{ot7dnWlbb`Aq5a%DboTKr3!LQOJOJ)hdbipV}nuxm>tvGA{38O zjPS1UT9E4xx8ySeArnm}J$k5zAa?QgtL=CMT03lkvdbj&HwQI}O z=H|+Yu8_3!Sr!|`Y{F?4hX& zQqF_{(62O6RD%=H&x6%b`!!e)ahs_m!UIwbMO04xbVuPZA^+xF44Ir)goyYs(s=`1 zM0dx3Kil>6DLKDd9zFm<#HBr&X@<~I(;M0+5ey>AqSUHsfH@z^)H&}!kHnu<4ica; z3)CBG9g+5i=vJ#1X#^xuX3a%b?AL7+gOxU2+zFXdU`_U+GLQ=G>J&1%6anlj{dgY_ zPrJb?XUDsxr`y)Ad>pC*{Mfv{SuAsM;QI^jeW@~3|$A4 z>R^V!mKcKc-_M^H0)5pURzi#|3K`u8XMcB>f7MqDS2z6NcQy8Lae!~!+%z+?GMUWE z^>e)nlAA6yisC;YdUmqOn6(XN-O`bISHq+N>G56CJFf_mRH=&GsJ@C#_#SUy*#BC>y(g%{WOONmi9cdIeN6~hQ(xT{{KY7J zeK4oIl2NV&x3ywRI!Gd|a+Ru}q+hnBkz2PB92R{Y)?^Cl;dF*ou`n!ka9?FGFS6G`7LJq9Tu*!wb`~yHqcj&laC2QlTu<~#km=sYG=>aE3LMMjj zY(*=j^(-HgWfUrYuEBsDJ?^<&?CG&Y688-miEMast~#!{AjA1J#x<~Ox0(O z@B(rKu14va+}Jz|X#nLlOw!{ZJ8n3SB53OnaQr4a>>W>JQ-!dXI)#yzv4-EZC~ZCC zcLZY$p|L~_F9_btT64fle+ne}_43XaOCV)TYdpl}@d~CT0^`&9cAu|BKl{}K{T~Lf z3n`S0Umy)aA!U>JO-fObN=reSh<^@Skrpq}F(&o43H7}jdo-lFs-nrvQssnhv7?B! zsj^)*2He>B!Q}9^ zMEasV%8ZW8OaRcB*fm7W0z^@iW`8}Kag(x`)BuJKs^&xQ7?5E*q=-nNTI26^*DNqe zwLMZ-z8qXS9IQkHP7+(F^PYZ<$V zGYEOJNuo>WN(ppTX^!WDew$wnNfr!0fN@?#3zc{gj9D@X!k?*Yf3AvNUz@h6G70QgqNvRqj<4{GdNwH3Yyf-#8PU-K{GA&Iu zI$qf1I-+|q$)jj_SZ;VnOsnfmHPAQku*Cyx4=o_PYu7Q5Mr&26#kdm9qT#7qehpCeZaujLA%aKuon57FItNBd1)=lic(4dJX4WEgpWiykD4b!;8#=QK*a`Q=wkNk_x^fNu8ZAJt2 z06j9Rbp8u3(uWl2rawrBCSRlZpz1G}Z zj}J@8P56yx%?wq-rI||>yde4wvl$e`LA0oFC|r4)?oJNe8q!#ZaoY)l&>;RW6es6Q z+BvS7=E;wqY%4s0i@A2C2gnDy{ceg={JpkpI~r2Ox^qgTU7MCMVZ@>Be~W7Q(KU~k zBr-IO8@s9h5myQa>jyytA?KB=8!rk$X(1fWoZIUQkj@0R#Job0G(A0~;_4n)4s?t^ z_I`zp60S>Q0;hf{q31sM*XZUox~JjhBzJIe@(!Eef3zM)q%8@}6wmtC$w-kpV9=C_ ztX9VqvFeH`+Hyh-~^r?q}I0(9a#Mp)A}69ix+Y=6a)kEBIwlyqksr;Ndfs& ztMFA(^gpqBW?>`R8l%Cfh_UOd(>7y_Rf7FFN`&7-2%n5o;RB@Udql{nOcwNrVYAZ_ zf8_zg=7NP^rp1J{pXqQpwLWmy9?*;bV`w=Sh~3p$oQW*@9_;jFQM!rF$*JLl<@!E@ z1(U_(oRV>_+S@l)RN2%>pm?o>YD^9MQF$4jv|TCQSAAP+|upTsoB=>s1H-@@u4RZSPZ(SO9tLs1(_3W8OC%57DmJ&>1_X%ZM0$GC_3J zh%~y~U*Z?G3F3BfczfvI7nIxB!?2YY(rmuqos@raWoPf#gZg-X;~1b%ahje_!#^=# z!b(FCp)`j21qBU*lgG`2EKfQxF{S>T@`k=$ozmPSTj;qE!4apGgw955HI}6X5AI8c z8-LiDW6%(6+No)I0l36KxK>3AqioQqLGn63&@H}fX5eUIuV@Lx-2fSA)yI2Ph5%}z zz65H0mi+k%=se?=2pUup5fw$VR?+0HPfg1o!Rv66wnVerI%C8}-p{#C%`u}1&*gD~ zVswVLDOA#jf|(SrAS3MZjJGO$&v4~p0_3lK=m4RUMpI@?i&2x;NYtsI2Lo9Zm;&%; z1yoKR1wE>E!^Gr?8*5s_0!RIPU??Jk)}oHGsdQKinY3d5IV#}b+mYS)Ur2M%&}FfzT1J@-OQiVF(z{Ic7#WGZN1{M|3E;ma!$+pM@R$(Rlzr zsN@>t#;HU2iIo%QWKEc}PNH&N%);3;Sn~O`vUHD69L-G}2hd8*+V4C^-2I!Nq(65k zE*+`QnF#hbM+k}P^~tuqE~tXq2O_V1c_xn&m5j8ACXcKT<#nR6%4>=hbEGTE_!;@| zAOm8gg(OHDJ_@%MG6CE?T?n&G?HtYB@?ypaq{(i~1wnpRkw!~=MX`)~IWlGZd=xQ@ zaZHi1P)r&aOa&B+x;oCHH6rURyb1BNm8NLY8e5qejX(w9k~v-PxYGc9O010F2;>eI z1kTp+R0=d3|2%~-4GwanzNC(Z0((50J0do@!7%T1-xAt9Dp?io*Ghj?UkvxU>%PBu zor4lffpW&p_-zNp1mNVCiiI;KEqbwUk8=vSY7tGXY^4fYjYnBgdMU(X*#h@@$gjUx zQ)F&d#-!R5$mc}D-fqNd8%S9vC{(8j-^YFYZ*L{Jivm2g=pZIr9uy1WZqcWJuaD zc0PgGVrBTY2&3~28ZJYnuOUYKm zW2(u>0{HOH77GG^{(x(QuU00Nvlf&7-0fEE+b*rW_HbHpRJ>1hL;RAubeE=t%KBKp zSRTEC>+@HA#L5I=w~&tCNHbMsj)sy{90gHz_ku>7om5~ z=Ax-JU#j>q-BI`9`oWI*!ni>&`E*<&*IiREp{d{{4sA`N& zbpELkp0-UjO<#o?VXb8uN|YJ-7^r)_vi~9R&zmP3)Gsw^;F}cY;H5+lg#BCjUVy$4 z2^!vUDu+D&$8NdBX*tmaLlvIuQCi!mXB$MG+S#>q81sU}5dwG4B66ye|1f@KhCnJv zoZMCbQ}}D8oV6&KR4ijXqf2WFJt!s|xNzA}Rm?MF{8itXg)>>VYBJvW>(JY*~VJhikh+;ivoS3{mP@X!6P|vAs5elIo9EY zVKjAoR?&qYYBP~Eo#9Scr;Pz9h&?`{DDxzE&lvs0&ohmyWY|AUpMY%bO`d^wW`qkr z4c8vn7!zc}4;h>XPZ1szgIpETIvftNEQp3BM1vKqergE-ac9e^ThnDq>aPZaLiAqK zF|vn0(-60?x(4f*aS>`P(Ghr-V%*RImDic7Xd{7q?FpHIeXxAKz~HC1Mml#GL5#Wv zWqx`)l+>J^Jj;2qb{;9sUvpxnRyzSDRdZ13;n&FHYv&USu3%4e9~1fZ^sp<@S~j6W zhGTQ$^B{!0^rAB_j0&*kVU@I6*`eK%Xcp#-d89VrqXQwyrv7&wAF8tmT+O z$eBJ|JPKIgzP}+rlauu^+dJodcQRSNO946hhmXAB`7x}xNTLbUO~FcGywZ`nob(5} z;eX9F>XDN?)eR;DQT_M6mYqEWE3_9wiBXNj6(475!Wf~Jy!JMUY8ZmiLz>mRl=l=N z(!>>|-Zfc9bjc#hefyG6x=Yw|xz*x+~QS>5eu&lM{TOZ9I=^Icj&O2J>7}Ll&?eipJmkST1-*_Y($&=oQ8h z2fjzSz;7hV5EYy4Mj}sQ>7$TkR=p&XWZx!~jtJc|%Telf6eS$uW;Pvc*J90;Z)7OJ z;n{2Y`#E(J`d$t=KW&BVBm+K}J=+j17=?Nk3h~&=nL084IRiXk!UH0G57#4iFvzY~ zphot38=9-fN2nf7bW2Mft{2J~Ge+0cLw@dr{$my3+LVJf8bub3RvM;*Y+j61RSMK= zvWX10@4>Y^va>MF5@99c*#R1LaqphI>Gx}@_U@nH zo;Uf*KlQ8*y{>qq#RRNkQ0Wdg!j{WNM7&LS5jy5|w58n2$0Qv;=7vIW++9W$FQ~fw zYOS%8{&j1eqd7+b%?mBdl&6OYi|6fY>|X9#-uo~ynp+2G2Iw_P^saqITD6;LZOd^Y zAp3-1EuBS&KfT0CLomiSVnCFG_g@+3Ov3W@3W?Roi-H_GM^}-}7i+2Gx=5Z`BA!`Z z6U=kZGwVH%th6IFg?W}IG3vC3s}Qw?ZE&Nbfa;4iroR6^gGsJ`Wtxy{MgA?J4~G(> z`H2pF{3NcEP2QmRyMGGQ@Gy=x?DD&l57W<3oFS>Ko)3e_2HfpAjCRV;e_aNpz6kh` z?MGYC2Eec$KGp1RF=TyVbZ8l!!Fo~HcJxS$T}(1!i+2h}ydX&iIMQO*LJJ{nx>Q|@ z7vud@w?7EgP{zLY^OsV0*=4z`rX;L>bMw;F`PM$!66&kbK>nvA$^qiE}?>4=2{c4V_Tx>pL~e z0TiH8RY?$?znO0iD?6WAOW^QfHuV9^BVpq_@YEge;_~aTadE?#&Mf9BOJE_>GDh?ck`! zGi=}?+lDEn_B+E11aLIN#0!R}@kf{n0)EMzHExB;*}w-FJzLCeafWR=p)+_9C%dY} zxyXnz-!qgpSe?Gl5W!d09B0eF)m=X;y)7*^3%gHhEe2g>vhtS1`o-{zFYuoc9H_6M@T`K`Uz)T%32(* znerj=(#Ne5&xvgC;zP6pJ6 zcS;z!B!jxi`?e8HZ}HlE!qqC}yiR=mNou)(5jHgf%~e?60c8uWS1C$Dm1f&h+#dz( zVh73BWE41EwP{V&EEr!pIZ-8mFpwew8f=E_-4ElDBXZqgmMJ&LUgK62TuOQ=X`y)F z^G25yZ{YI&N2?vZruliZD8?H1{hqJ6)=Zbr80a>$=-8d zH4A(yfk4nE1MV}AY^Qz5C-co)K(Mx4E!OAz%=Z=5{Bcc<_hAgS|mE* zmtv|LD{sMK{xwWd0~jXPyh~5anCinc|6cO`RBHS+nd6AbP}e0MUe~5B`58!_2G5d` zzg5Lm;qbuncr7wElEC-uE9chZ)xwaF$UzXYub}*EiPY0db714eGrBY`0T(~V1QxR> z98;5~R!P%FZlcf+WaUM{iHnC4E&-O(R-!^z4^$FvLTJ%Mr53g>0WO#_rdlUjgF7rj z{Bs&`FoU-OAGS~No?(|8JuH@lHkKR=OP@pqJQxqEd3->iblyymdH#I!X7q#8s0825J-r43H1U{7=CjF zgy?W8dx|7ZrP{nhz&uQWzJzE{$RryH7XFKL8=D!R?g!Kh=q$?1I42fMdA)K2pN(Bx zFF^?(w4@^`{PDkdklP;Wl=;DJFcRb+7}E1?D#_@f5jlv{bDU=YRlC7h**{{9xeyC; z-eYS%Q%6 zNMM?E#r!QUEaJ7VuSl$W2C)xn+8f^o>(M8*_f_6iA~YbQX3&c3VIJ!v$|-@DeiOy0 zeGXC*-X{;$q#yOAX`5{b`u7RV+|Htv+D>FC-0(wd*DzlJ&;=)iXbjSz{1*i+C2&CU zPoNLp+HAB!TkC=qeq*@N+%}jdnd*x~FrYb``R#+kR6fh39TYtfFPy#s%D0pJZ%6wO zkHdsx22$6Q0*iIhw}67w{hCJk`tR*}zC(&T*Ku1kYV)H8TTa3OBvPeN5GzT3QhP3ZDX^x2t=sUA{Ml%Nq8*V zCliW-xytVh>hF!;ls*3L7Dl4HI=d4+L%EECD}nob3BMi3M{SeqOt9F3&>40QJJi@4 zmUOo5XJ6Q$s9o2VEsZPCSqv4&)aVtKBBdU#DhlcK=rtD?vl5cZNZ6UEKJovTS9Cqf z2$;Tc^c%U_bmvc1LadW&{AjZ7$N*e}%A=uV&bNbucr$_alfwT2+uUr-cXD`+hz#6_ zqBH;rlBSVat|?Fo2moEejiI~N=b8ivWBZj#wHSEh<#Jz_#E#@#B~5gl=-wHO1)3q& zw8+rIJ5hPFsw6wapwOsQ)5}wJy%wIQ7zz{>SSup=%^@N$Se0gHaeqNC9Uw~U8KncO z$=#571kl=xXkvjwJ8bu;L>h?n4u-#4V0uJv?BBFLp%621w_Gp@vZS7V)rQ zdR;65)8Lw#zgMhvCZyEX{sMdJ_TG#T5S`D;0GXsPfV;j=QAenJP5lxmmmVy4WEeZB zyl{UW+Kp9y`Ko7UKZNYRl4sm&E7LF`_2@Q-JoLryP_Mb8F6_uIEu4#T5l8j6JtfgE z6V&pP&O4rNB|wYMe(S>R6RsV%o5i~L!aXUv*F+#AaiQgLFp_eF>quUWG{~2gdcL)_ ziJfaw0lB50CPRHonv}G@B5Y}~wfc7C4s@MVh1HAeP_)wH^z;U^D_MRyIq^^e6uwi# zlfra0pCC|24Qrozx0iJ4sOfMl8?^Ix2UPI9Y}MKPn9uf$5iawxVMW|n%vDi zn10|=Rdfo7-&s}4=)hfpLk`Boc7YvX`$}jd#wQ4v7wo{=_4A2>g;T26Y?|_0>SMH1 zNj(wb{)t0)$OOiNg)gKC%=)t~oU)N01biM}E>cEm9|;Me13ZD5CU6O2HE8pJjltA& zG#;G5y4a{v&1r`S#{&Xq>Y&oqCKXSJ7|&*Meh!D*oxzL~@^^m8v*8*xH+{*>?M)MXxAF~rIu zHAWS**g6S~2-up&4qQbYOgUQU*O5R)PU++7k^wXkTQdRKIFgTw2&naejVHJ;0$iN+ zx?&NjpMB;6l8AUgVEp~>Ka50|4M-z|pxnKbV7CeyIUcS`>Q_IJg3PX(#B;%E!D*(f zd?ii8r!94TQXU3{QHlLp)P2|N+^IlsLn-QbzW}C)KBc5H8okI69KS-i7?70&)P~1t z;xg7uR*6tkx@#82P*9ah)}>HauIc}9NxoJT<564qHohORS@DpMhVyiEE^(n2V|l9eUdz?UprQ4HAPE=-Lu1Yg+Laegz%uW zH-zkwq8zamquF1m`c{ImqD%SVme^D&$t7Yc!X>r(lhbfLG)g)F(A zHQf2m6JzF;s$O7cE7>QPx7F34fglB2wqewf%brdeS&^pC-j_eSJ8QM)*r&8X0UKZe zso?XDz465)P*Pm~P_6d-Q%4Iw4}SSMlH z;;uv;9_8Imu&zCtsmasPE{1KMv2bynJEK7haqLF!i{Q;i$o$@h8JTJA0LcTnh=O{~ z9Gxptb$C=vR>cY}1kfB%@vUv7z%=V&=olD0;N)vhNSh%95+p;>9RdH#qh0uGaZX{0f90$$#Mi5 zP=K=uO!Wr#@`do-YfTbr5)=!%oga6n@_EDDeJl^<*?mU!sPiJ<+rSQyZZjZAit3J(X3WA*nCzDX+jHHptAiofN<+qOrV}a{8Ebi zJ`|&R1+A+;&}4d#1mKP?lVPBoCQwoG1}z}MuD4>5x@=j>6FwqVO(Hdytp~+&SMT^L~J!wM>s)crkuF zZDLXcr)GF>XG@ZVI1yz&2&AflmHl;TudIY=Co8g!u5$ZlBe6!@m{=djXE*(l*qc-QXMWkt?V;S7yr5 zVi>XfDP;$%s9pZjF<2G{X^7lT>7Ab%%9NZrD!`G!Gy@dObHgBdcxLa;?w}hO4?7Kn zT|9Cld5JJw778Zz4BRk9PefVx;;yz3~PfFbkr<+ zJxT!znFlr`Xh$t=_-ebTdv6`xJknY*MKh-eR8hNAK({NXJx*BCT5~s%L+^BQP1imL z^#nwG3)WT@DYbE#JN%arxsItNO!~p-H zsGIzND1u;FJy`^KdE`r_PUNZ<$Uw}56TSXLiHwz-W|1BN>;MZ2>^#EyaHJyp$xIPO zGnF;Ae`h^?*fSQK_5JtiF=~M?YoMKBXAZ@HA-JUbl1OG=oT32z<4WSDN85<$MvNh` zWa^Mib;Oh5cOY|B%ZW}Z$|LPIq;e4L-Re?@xd0JKsdBSzkyAY62dr=fSo7%9Q#=00OD4-|qB05?ygVEiC!-OBT6f6I`@4hY zdXCL>T!R?6fal|b8Ye}d7tl0Y-iEaX*f`O`%sBhCW3URo{g>3=3uvD+;-dwaQw|iK z7~nkuYhb%@BB1ch+gV$ugI0(LM+;ndVSKtkrfivsdXWRD&!i2F^O7t?MeI|*7t91s znaQBVfVgCYP8$w(@LB?)_jbs?t+MZ)3*vE9Qx)!Pi`CgExDaJUbhMO7jx-<=xkLWm zB^jWIN!QOoa+ix3h@*dlte4RnCI>$Ttd| zh0w*kyU1FDN~ti><=0649+P6={q*dSu@KZf~5L!%33QSelHquw5e z^ZhLwrB(RW_L&i?6`<27+9;$L#q?QF*}Vk=V+_(w^QwF) z8U@3P$2p-S&{gg@biRW|gm~}Qgk{jhWhD$VSnwX-2xzo^g}VZG5e(1-9bmjr-~byL zj2Bqz>?Ifo#;vo>dVELGr^x$};C}BcfkV5lLsVOtGr~E?K9hY!NJeC(nO_L$+ftWsSi^ST5N!Q?wLIe;5&u zteQDOvb}(T1p&g9PC!zs6G!DBO%*a&0l~N3q?@pSeBF%s5@Cq;Lz4@b7isMlRQ1^{0C5}wUAK&2u`5Zi_qQ>Bkv}?&O8#80Bbi!qLBk+4BG^Y8l*J_=Wz6B6GTTH zsgF?z&O`aMO!}jFjpAcq=zkefQ4Lc*W!J|3E8x3<{cUY^%u2Q!QQ8~76I6tHt1P&OPk4lyyy&jtoyz%7f_Z}qz2L!x1Yp(}H)cb|Vv2vW*a(89 zL`ic7H2y(*{s+jx1W-9pWX@p5jMcVa>Kf5PGMbV=;n*G|Q>cxz{d_rwgct1OwW#12 zCTQ3aCDsM`3&168_;}Q$G88`15y5~GvNs;)I8V!ok-D>1|a@O&8*+^FnKuW2sRY{s~|~E zQUvmt3B?GA^HPHGuOdO>)Rvpb^Rk47k+4PKiIzy)7$$i!T0Bwa@TUjE5aKAU2PO)J ziS60C7?v=cG+YuP45Vq?MQ|IEKzBN@O`ViqhY7_hbbO2f0I7B?U=Ns}V!?emUhCBb zn!sl=bYWwt32wqN3#4&$=pgKnUi8lm58q>1o&w_IAvj?H7xQd?FfYLI$?@_llbA(t zz{?P3Ck!x)em#?F+z9NP!eQ18(VWj>4bBo?=4&p_3E0pwuyfzQ-ecDr9jwONknYxE zW}m#!T=1pUS*A8N6al_6jCpeBg`0%nBr9%+irl;{HS*zPHJj5XC;+o4?aPUGDWGdY zF6XEbm%r|$gkck-@Is~*) zIahmhSwi$Kn%$Bq0<)@}B7%{~T8Awm;F!tcnO^|>{5+AE{Fvq<&ZmLmh4Gu|8}%C^ zDj}l@w}DylArczwQT3wnBRS^-!%qcZmB$OOim z_(+wH(0jW|TV18gDxvH-iDfnl_(_*wj~&5ZF|f9@!c?KPg)?nuNvbh1eQ%Y7u3x)v%b<*Ng5830I=Jv`qzXu~l&Z*a8Syas;1nyd`vEm6AUTR`aU_ScKylw%0pa{t zz-D3>dEN=%EE!#h>(pRc&4av}{%x044mp)};#IqL;1nQYA{?LO2u;8nnm@m^X~C8Q z*cEm`95SS6FlTox19pFlh%@n-?Ix--+*D_SWoqcr`%Sp?Z2CToVok;3leJj5T1L7( zcd1G3r7k&0YHf?n;$v=Z4s(zc-{-f404gaX&$qJ-^27o&*4XyImuB|>T`!G;1Z z#o^9Jk@JWHNo8FiIVsSXGgRa^Cn3O=B&J2bfy@B>p5OjpkwFADm?zdY@=rfYw}^r3 z<^Z!{`II4JeVyMz7kZHEkaw|49Ce7~g&3=?e>V4b`vOJj$0;umjs=B;f|$rU+~*1b z5^|6Mla%Q_cS%Y=Fdz|f)F*p^0e(sVyoxc@0`uTdmLS?c%A4-r0)&`!;o%7$jNBRM zfohrwBm#jM{w_-b&rc1&A-d#*D0RfQlrc|Z4TIMu31{77Ym=8NAh~k9MvCYqJ-~aA z7p5+xE5PG`KtY^=28I3-tG665l#?Z)wTdPv2LoWe0^7X?0oS2{&r#$tG)8|J$9;zw z;xC>nyClm34;2T#>H^qs!A*(*aGBcz3C~J4VTVhQ&)`?`KfWHJ?m7e-Fe9=a2skro zpTX0skk$CmmU|}ZMq3Sp(p9BWkPnrrp!KbZapKcVa!L>7Vc%hQBglqZ_}qL7!%7%e zDS>`c9-sP4;R}_Y1`<02A4M-gnxV*oilOy#3;16#t#YSlC#1|5cnPtlQf!A(ZB`^` z_BO~ZYgUk5^pp_Dazq1@A1Qe*U|=PXakK3TyY4pa|3$ol>Ypk@Or!vdFiMYx(uqCB z!d0eb(My)qK~qA|GLXRiT6R?L)Fb2YCe z88aLzw^`p-?HAZh$G6;@O4>Xr25R6~;DZo!miMtzPoZF*!rh}>5-e{l-bGd{V}EWR zDJ`WC9+wFr7KI+&(@!xA6EDnTD#1WL4YwCrdW2tp%56c1tl0fA8;4XGa#G}hUo`SQ}^oU{0}aafn>=V^hA z)3VJoOsn=~79%tD&F)cbW@8;qkTd|S)k@r1nkZk*Zg{L9Q~9o=qO&=v>2qWm-9irh zV08&!DU5bX0g<6i|5m1KBsAKW3J+`6{wp)K#mB{4L3OrpG2v{C91(oBuq~|?laF`C z^6jITk4|4Psew)AsyB+kWn_f$c(y5d9|0u1BrvC0dc+=@HTrS6T&*P>O+;agSsFJT z=*UQ^5+ct`f5aXjgv}LIux3u?w?afcowS_$JFSsJgbyZ{ioioJu0AEbE#-qa%e|V= zY+@y7XsaSs2~#DZe0eWcIRa2QZ{Xwfr^S9-*I4t8J};deMk*U}QIgz~&dYH^i>0<$ zh%dh?&_xnV(>$BR@l~n_Q8JIRp>n!&a3~cS>v*^m3X)~0c`@mR3KMj z7%2xf$x3Ik4x!pV03|%|5?l43GVo*ObwV7Bi>4`d8cOjc36ZG{5*LR?nMZB1NAhd?0-9oBfF&;{byf`uJYZ%N(4-U!p6iK#M7+;21Da1CW zyFh?rU2&fH+-MMDMgR+6^adnMm|)`dqJPGz6 z(22hMIPV#w*fBW!2>RPOrkV9l@00F}HWF1iX>fo>rEGj>e*ju(An}NukjjS-g+Q4z zVUnxw=gcp@lnX1PNkrirBAlkkv|FJ@6&Dmh+|~TZuGkOmcrVL*;>GZl`~U>(jN?d9 zX)m~D*B=Q~S-TG>R%o+fhcU>o9Hko5ei+xk7jNHCNQ2B49Ov$uxG|g+qOZX3= zwvxj1eB3%pk2p0uyLB*O;K50G`;e|A^K3S2sU>_7UN2})04;K=8D!&ZBy8~~s9V(o zhG)h-G<|JQNh?_zGdX%=ZG@^6(;J+SCC&Wfh-~caT$qm)U-uBH-4=|x2E3>_Df=`F zlt>~`4t2j5pZpFkl<6Nj(p*lgl`Z}F5prMT62xS?iSV~yk2PmX_-L^!pL|7(; z?3wbLFk+J|-V7i~;0+10KLyGslmZQ9Qjr*$h75~D9EFqxg4G|szaIhR{;`DWajA!E zeb0dhs@gk>E<8|6Ck6#@uoig*R^UV;_G6LDqp&1y%AN!EAA~)H-5eTJ9Y2B9_=OGR26vZLz>62%|04rDWcK1U#&k*t|I=5NzZ(r+TR*7(E2efJbzl zh&KS0oa9XZK!imAVQEHU<~}SzXfG-{vsg*sbVsUWfIAj9fVC$uKd_d%EO0ZAVSbjK z7^FMv-nrk%9@v=^0Uu*<7x!;e0jr8~u1A#-!58oY+dnvJxA1D~Jtpkc36JxTO!j}b ztH9+W0ziW|pa}#PUP;M6f0PQu%eKpsajq8Y<~A^gis4AXW+Ge*+1pd`6fo&Dq}CF6!x0_vNCZ%c z`>F?w)J#0RDTuo~J>>n2y6Bj$9dXIKL5+?`mF~rcR0xwtezH3;C8^U>pfBm}@QP!q zqQaSwj#)&`47yw}bGGor)7b!Zgg{q3rd&||p_;Qs;b22VcQb|$m4-TgdrFi+Dqeko z+PjKtOlJySr;f^`f~mH*?a{Qr=yB_gDP{$iXnIH?g>Y~$oG4pBM5vYpKasuQpTS;x zJQLk+BUOuM5|j^6V>aI(>tU2SWoLBK@T{j&#Po`g?ePjEdh%`~5l!7?}o;@CX z13%>CTEH7ojy?kt{M)1sRYCU_b04n5KV-m%(~$GK>JSQeVx6@Q5+ARoV5#W5Kj<%Z zyHp@;W}c0%^S2T?AskCi)5z!T zODFKqwRM#Qu-K%!)RfBe&NVIpIBe#b=>m~IiZPJBfRx$OAqNQLT(+rUIGB`D4&y2D zXu(#wvB#FWg(Pix2n*C!gFqxf!x@Ey8#r!Jg$i4y{hRfG{iX(GTE69a6pJPvbH!0? zgY5^sj}+jRxdA+|4oj-~{zJr zb2a=@rM49|01j9Yn(%ZIR#lcJ)HI#P+ZOs^tP`1PJaTtW5iBw%9+!#2&V~93VW{xh=>@9y zi-UdBJQZ&C*~IBzTjkXJ;}id$V`g;f-|tbp=PWeBFl z;%5cL+wO#FP{oAb!w6@fR{hj zD@a0+lAV?Zw}Ir9ur){jAa^f##JKheYFipud_pMjh-SKSy9;@{+X}8^)3al3MCu5v z&(`Bsp{;2NbMyAyWdQ_<(9rq(V4g zF~DkvG0UY*u|F;nfpOBLPMDDdsE|l6NO*0yxdo??+=EMdG6yt$#3vwL*?}f;@S|_| zOp_Je@2LSGPJn^L&3$YoR>CNXXpHs!lcENzsq+~DQaT1*;>^kM;1$m(F901nNo0z& zc8X3(KM(u_zdivZcu4wEGuM%mk=T~7PZ8lgJXCI!3YZXrhk|vY!{$WlqCN#7g#=OT zNPMc>XYRQBaT}!AuwsAjy(BWh$SCILIj1sg(%= z9MzqyIrlD1-(urlsfrpD2AnRBDFO-vjJ9;qn>2w2MUWaiEP$Mt27uF)rviZSN$@~u ztTKVfBM6~^xXc5tKqHaumR619;lbFMGAF3O4b8nJ`q>`TL7Q4v ze?)W&-CnTdsT0Ewjz$En>Oi|fRRjYrY*58Ky4v)sfs;#Fj+LJJR3}g)AQcDCL4$kL zY?5d3jQvC~rrl`OlsZ-Qz5wne1VG$qd!4`}uET`N z?aXYp8J%F7dU!S@9r&#bNHx3!NG3luUimtrZ9W(*!i>!?JrM&ZngV6dGafEOn6LGJ z7pwUPFBk&GN5y=Yd_7MEn(<5W?UOMHG-Y2p3v}$kd9N0pasT?F1oI_8aC;@E7JGLP z0d^yBpP?o>=@Bk7-;AZtYN z6jOWg5U*c|h5JHAc81|T3S7f%7K zwnRw}Yt>*IJG?E{Gj4RQ#U@SkY9WFed?$)gu}uuXB7wdq_kA663zrP@3B;G9Hw>-1 zYb?mlH5rcG-cnf9z$ls60+1$Vi@B5>!qBh~6=4ksMxttlHi^dzbG)unVjORp_l*z4 z$|*-qf_%b=57>j|8BkkDS5#HRcF|7=gIaN0SBvZ*6Z=RbFhbEntS|bcvJT@OR8|Er zq8RD}Oo53ysg>Q2Cc0uPgRF6;h?ouKK#D@)vk^30AM8d0uLA%$(>`E0#qs0il(=zJ zV(s$OX<#lGlFVg36D?D=69S=yMl|ojv4YVf^LK{Z$dS-}YK+l(!fpY3_=3DJ8I&3; z5J0U}J-5zAt~y?~q%LT&ZB1K!w3X=lYlR*{iGV)~4abl*y{^m%Sf{C)_zNcO015I2 z3~-2WWl#a9B^IDoBpyIcN^tc)n>=lSV{8bUD(tjy^(ZK6`d~oCg#k!V0<}LYbq>^& zB4Conc!K={=QOl52o|Iz8Jqtf22FLkM%j(JJ^Wr?Hub<4OR7akFE+*P4%827SR#rt zM`Haf!bqJ&wjdNVhz;t2(sKeDax#Zx5(&~*jJ>ziVYC@%3E~qk`(797FXm#H8W-`UVu0g zVtL0y<#zMn8bDSRBXFGuN06`*kNCI^umH$Fa4;O9@n3NvU(o_@z@!x2-u!)c8hU1- zWJ8c3pj|67@Tyms4&7JyLSe-oPITZJS%*JCokqcvpl$*MwL6vU&Oi`>{UW&+Gt4{5 zviHlSg4YDgTx6VPkCA5Sng1sBuhS`JZty7ZBG!BxW=g``w?55x=|1xfagL+!9(u7^Qnb!3PCSQ~{v^tVo9FfeRz`=fpXmz9JeUG#@Bp*o4*i zp)I|9`9P8$(hf3P?$nqJ#^e0X{D!$W9t~xVZImY=Jqr1xJv$J}91hf2`)%WjE!OLz z&K|Na-Es`O1C9jJ2UHwdvH;2gh`9hD3t|soM8qL1ClTS1v`B&PQUKENB0~jw&yckV zliggRmC#?@h+#+zdO#D0Vf=$316lsy#o-5LtP^vjiO;RTYB!T@5~lCk3y86xf)kBm zGV{wBlZk_VW`i#w2J{wsv=(-G+HCcs1Uy+ENr1D_kO+y_KL*XO-jP4S?M42k( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/fonts/lato-bold-webfont.ttf b/zbf-admin/src/main/resources/static/designer/fonts/lato-bold-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..87107fc54ff9763d7a03f2f882d0c3c640a1f161 GIT binary patch literal 58344 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 + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.js b/zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.js new file mode 100644 index 0000000..8cd592d --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.js @@ -0,0 +1,2137 @@ +/** + * @license AngularJS v1.3.13 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) {'use strict'; + +/* jshint maxlen: false */ + +/** + * @ngdoc module + * @name ngAnimate + * @description + * + * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives. + * + *
+ * + * # Usage + * + * To see animations in action, all that is required is to define the appropriate CSS classes + * or to register a JavaScript animation via the `myModule.animation()` function. The directives that support animation automatically are: + * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation + * by using the `$animate` service. + * + * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives: + * + * | Directive | Supported Animations | + * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------| + * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move | + * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave | + * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave | + * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave | + * | {@link ng.directive:ngIf#animations ngIf} | enter and leave | + * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) | + * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) | + * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) | + * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) | + * | {@link module:ngMessages#animations ngMessage} | enter and leave | + * + * You can find out more information about animations upon visiting each directive page. + * + * Below is an example of how to apply animations to a directive that supports animation hooks: + * + * ```html + * + * + * + * + * ``` + * + * Keep in mind that, by default, if an animation is running, any child elements cannot be animated + * until the parent element's animation has completed. This blocking feature can be overridden by + * placing the `ng-animate-children` attribute on a parent container tag. + * + * ```html + *
+ *
+ *
+ * ... + *
+ *
+ *
+ * ``` + * + * When the `on` expression value changes and an animation is triggered then each of the elements within + * will all animate without the block being applied to child elements. + * + * ## Are animations run when the application starts? + * No they are not. When an application is bootstrapped Angular will disable animations from running to avoid + * a frenzy of animations from being triggered as soon as the browser has rendered the screen. For this to work, + * Angular will wait for two digest cycles until enabling animations. From there on, any animation-triggering + * layout changes in the application will trigger animations as normal. + * + * In addition, upon bootstrap, if the routing system or any directives or load remote data (via $http) then Angular + * will automatically extend the wait time to enable animations once **all** of the outbound HTTP requests + * are complete. + * + * ## CSS-defined Animations + * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes + * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported + * and can be used to play along with this naming structure. + * + * The following code below demonstrates how to perform animations using **CSS transitions** with Angular: + * + * ```html + * + * + *
+ *
+ *
+ * ``` + * + * The following code below demonstrates how to perform animations using **CSS animations** with Angular: + * + * ```html + * + * + *
+ *
+ *
+ * ``` + * + * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing. + * + * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add + * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically + * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be + * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end + * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element + * has no CSS transition/animation classes applied to it. + * + * ### Structural transition animations + * + * Structural transitions (such as enter, leave and move) will always apply a `0s none` transition + * value to force the browser into rendering the styles defined in the setup (`.ng-enter`, `.ng-leave` + * or `.ng-move`) class. This means that any active transition animations operating on the element + * will be cut off to make way for the enter, leave or move animation. + * + * ### Class-based transition animations + * + * Class-based transitions refer to transition animations that are triggered when a CSS class is + * added to or removed from the element (via `$animate.addClass`, `$animate.removeClass`, + * `$animate.setClass`, or by directives such as `ngClass`, `ngModel` and `form`). + * They are different when compared to structural animations since they **do not cancel existing + * animations** nor do they **block successive transitions** from rendering on the same element. + * This distinction allows for **multiple class-based transitions** to be performed on the same element. + * + * In addition to ngAnimate supporting the default (natural) functionality of class-based transition + * animations, ngAnimate also decorates the element with starting and ending CSS classes to aid the + * developer in further styling the element throughout the transition animation. Earlier versions + * of ngAnimate may have caused natural CSS transitions to break and not render properly due to + * $animate temporarily blocking transitions using `0s none` in order to allow the setup CSS class + * (the `-add` or `-remove` class) to be applied without triggering an animation. However, as of + * **version 1.3**, this workaround has been removed with ngAnimate and all non-ngAnimate CSS + * class transitions are compatible with ngAnimate. + * + * There is, however, one special case when dealing with class-based transitions in ngAnimate. + * When rendering class-based transitions that make use of the setup and active CSS classes + * (e.g. `.fade-add` and `.fade-add-active` for when `.fade` is added) be sure to define + * the transition value **on the active CSS class** and not the setup class. + * + * ```css + * .fade-add { + * /* remember to place a 0s transition here + * to ensure that the styles are applied instantly + * even if the element already has a transition style */ + * transition:0s linear all; + * + * /* starting CSS styles */ + * opacity:1; + * } + * .fade-add.fade-add-active { + * /* this will be the length of the animation */ + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * The setup CSS class (in this case `.fade-add`) also has a transition style property, however, it + * has a duration of zero. This may not be required, however, incase the browser is unable to render + * the styling present in this CSS class instantly then it could be that the browser is attempting + * to perform an unnecessary transition. + * + * This workaround, however, does not apply to standard class-based transitions that are rendered + * when a CSS class containing a transition is applied to an element: + * + * ```css + * /* this works as expected */ + * .fade { + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * Please keep this in mind when coding the CSS markup that will be used within class-based transitions. + * Also, try not to mix the two class-based animation flavors together since the CSS code may become + * overly complex. + * + * + * ### Preventing Collisions With Third Party Libraries + * + * Some third-party frameworks place animation duration defaults across many element or className + * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which + * is expecting actual animations on these elements and has to wait for their completion. + * + * You can prevent this unwanted behavior by using a prefix on all your animation classes: + * + * ```css + * /* prefixed with animate- */ + * .animate-fade-add.animate-fade-add-active { + * transition:1s linear all; + * opacity:0; + * } + * ``` + * + * You then configure `$animate` to enforce this prefix: + * + * ```js + * $animateProvider.classNameFilter(/animate-/); + * ``` + *

OSg+O7v1uMt)8fRG^AH!_jP8S)SYDEQAVV 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 Z(}8g#H;8Bh09+V9mH+?&R0uEI004T*CYAsI literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.eot b/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..b294f6c349351ecfd771e3a515676f99d1fbee37 GIT binary patch literal 28222 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 WeR)}BM`fQQW#SktZW^AOnHGSvj@q99 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.svg b/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.svg new file mode 100644 index 0000000..96737af --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.svg @@ -0,0 +1,4241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.ttf b/zbf-admin/src/main/resources/static/designer/fonts/lato-regular-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0768020a579a5dfc15587aef34da5ba750f2f334 GIT binary patch literal 57528 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 DGaFlowable Forum " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Bend point tutorial", + "DESCRIPTION" : "When you are connecting process steps with each other using sequence flow (those arrows between process steps), you might find that these sequence flow cross each other or you would like to arrange them differently. To do this, you can add or remove a bend point to or from a sequence flow.

As shown below in the picture, you first click the 'add bendpoint' and then click on a sequence flow to add it. Note that the sequence flow will show you a subtle indication in green to show the bendpoint can be added there.

Removing a bendpoint again follows a similar pattern: click the 'remove bendpoint' button and click on the bend point to remove it again." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Save", + "ACTION.SAVE-AND-CLOSE" : "Save and close editor", + "ACTION.SEND" : "Send", + "ACTION.CANCEL" : "Cancel", + "ACTION.SELECT" : "Select", + "ACTION.ADD" : "Add", + "ACTION.REMOVE" : "Remove", + "ACTION.MOVE.UP" : "Move entry up", + "ACTION.MOVE.DOWN" : "Move entry down", + + "TOOLBAR.ACTION.CLOSE" : "Close the editor and go back to the overview page", + "TOOLBAR.ACTION.SAVE" : "Save the model", + "TOOLBAR.ACTION.VALIDATE" : "Validate the model", + "TOOLBAR.ACTION.CUT" : "Cut (select one or more elements in your business process)", + "TOOLBAR.ACTION.COPY" : "Copy (select one or more elements in your business process)", + "TOOLBAR.ACTION.PASTE" : "Paste", + "TOOLBAR.ACTION.DELETE" : "Delete the selected element", + "TOOLBAR.ACTION.UNDO" : "Undo", + "TOOLBAR.ACTION.REDO" : "Redo", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom in", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom out", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom to actual size", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom to fit", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Add bend-point to the selected sequence flow", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Remove bend-point from the selected sequence flow", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Align model horizontal", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Align model vertical", + "TOOLBAR.ACTION.SAMESIZE" : "Same size", + "TOOLBAR.ACTION.HELP": "Start the guided tour", + "TOOLBAR.ACTION.FEEDBACK": "Provide feedback", + + "FORM_TOOLBAR.ACTION.SAVE" : "Save the model", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Save the app definition", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Delete the element from the model", + "BUTTON.ACTION.MORPH.TOOLTIP": "Change the element type", + + "ELEMENT.AUTHOR" : "Author", + "ELEMENT.DATE_CREATED" : "Date created", + + "PROPERTY.REMOVED" : "removed", + "PROPERTY.EMPTY" : "No value", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Change value for ", + + "PROPERTY.FEEDBACK.TITLE" : "Please fill-in your feedback", + + "PROPERTY.ASSIGNMENT.TITLE" : "Assignment", + "PROPERTY.ASSIGNMENT.TYPE" : "Type", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Identity store", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Fixed values", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Assignee", + "PROPERTY.ASSIGNMENT.MATCHING" : "Use ↑ and ↓ to select and press Enter to confirm or use the mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Enter an assignee", + "PROPERTY.ASSIGNMENT.EMPTY" : "No assignment selected", + "PROPERTY.ASSIGNMENT.NONE" : "None ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Search user", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Search group", + "PROPERTY.ASSIGNMENT.SEARCH": "Search: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Assignee {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} Candidate users", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Candidate users", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} Candidate groups", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Candidate groups", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "User {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "User {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Field {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Process initiator", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Assignment", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "No candidate users selected...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "No candidate groups selected...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Assigned to process initiator", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Assigned to single user", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Candidate users", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Candidate groups", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Allow process initiator to complete task", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} execution listeners", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No execution listeners configured", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Event", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Class", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "No execution listener selected", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.FIELDS" : "{{length}} fields", + "PROPERTY.FIELDS.EMPTY" : "No fields selected", + "PROPERTY.FIELDS.NAME" : "Name", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.FIELDS.STRING" : "String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implementation", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "No data objects configured", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "Enter an id", + "PROPERTY.DATAPROPERTIES.NAME" : "Name", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.DATAPROPERTIES.TYPE" : "Type", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "Enter a value (optional)", + "PROPERTY.DATAPROPERTIES.VALUE" : "Default Value", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} form properties", + "PROPERTY.FORMPROPERTIES.EMPTY" : "No form properties selected", + "PROPERTY.FORMPROPERTIES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Enter an id", + "PROPERTY.FORMPROPERTIES.NAME" : "Name", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.FORMPROPERTIES.TYPE" : "Type", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Date pattern", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Enter date pattern", + "PROPERTY.FORMPROPERTIES.VALUES" : "Values", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "No enum value selected", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Name", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Enter id of a value", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Enter name of a value", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expression", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Enter a variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Enter a default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Required", + "PROPERTY.FORMPROPERTIES.READABLE" : "Readable", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Writable", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} in-parameters", + "PROPERTY.INPARAMETERS.EMPTY" : "No in-parameters configured", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} out-parameters", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No out-parameters configured", + + "PROPERTY.PARAMETER.SOURCE" : "Source", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Enter a source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Source expression", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Enter a source expression", + "PROPERTY.PARAMETER.TARGET" : "Target", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Enter a target", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "Target expression", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "Enter a target expression", + "PROPERTY.PARAMETER.EMPTY" : "No parameter selected", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.PROCESSREFERENCE.TITLE" : "Process reference", + "PROPERTY.PROCESSREFERENCE.ERROR.PROCESS" : "There was an error loading the processes. Try again later", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "Loading processes...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "This folder contains no processes", + + "PROPERTY.FORMREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.FORMREFERENCE.TITLE" : "Form reference", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Reference to a form", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "There was an error loading the forms. Try again later", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Loading forms...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "This folder contains no forms", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} task listeners", + "PROPERTY.TASKLISTENERS.EMPTY" : "No task listeners configured", + "PROPERTY.TASKLISTENERS.EVENT" : "Event", + "PROPERTY.TASKLISTENERS.CLASS" : "Class", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} event listeners", + "PROPERTY.EVENTLISTENERS.EMPTY" : "No event listeners configured", + "PROPERTY.EVENTLISTENERS.EVENTS": "Events", + "PROPERTY.EVENTLISTENERS.RETHROW": "Rethrow event?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Class", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Entity type", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Enter an entity type", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Rethrow event type", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Error code", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Enter an error code", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Message name", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Enter a message name", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Signal name", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Enter a signal name", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "No event listener selected", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} signal definitions", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "No signal definitions configured", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Process Instance", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Id", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Name", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Scope", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} message definitions", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "No message definitions configured", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Name", + + "PROPERTY.ESCALATIONDEFINITIONS.DISPLAY" : "{{length}} escalation definitions", + "PROPERTY.ESCALATIONDEFINITIONS.EMPTY" : "No escalation definitions configured", + "PROPERTY.ESCALATIONDEFINITIONS.ID" : "Id", + "PROPERTY.ESCALATIONDEFINITIONS.NAME" : "Name", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "No sequence flow order determined", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Sequence flow order set", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "No outgoing sequence flow found.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Set the order in which the sequence flow need to be evaluated:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Sequence flow to {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "Sequence flow condition", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Condition expression", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "No condition set", + + "PROPERTY.DUEDATE.EMPTY" : "No due date", + "PROPERTY.DUEDATE.DEFINED" : "Due date defined", + "PROPERTY.DUEDATE.TITLE" : "Due date", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Due date expression", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "No due date", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Expression definition", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Fixed duration after task creation", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Based on field", + + "MODEL.SAVE.TITLE" : "Save model", + "MODEL.VALIDATE.TITLE" : "Validation results", + "MODEL.NAME" : "Name", + "MODEL.KEY" : "Key", + "MODEL.DESCRIPTION" : "Description", + "MODEL.SAVE.NEWVERSION" : "Save this as a new version? This means you can always go back to a previous version", + "MODEL.SAVE.COMMENT" : "Comment", + "MODEL.SAVE.SAVING" : "Saving model", + "MODEL.LASTMODIFIEDDATE" : "Last saved", + "MODEL.SAVE.ERROR": "Unexpected error: could not save model", + "MODEL.VALIDATIONERRORS": "Note that the model contains validation errors. This means that the model can not be deployed on the Flowable Engine in its current state.", + "MODEL.CONFLICT.WRITE": "Could not save model: '{{userFullName}}' has made changes to this model", + "MODEL.CONFLICT.WRITE.OPTIONS": "Select an option to resolve this conflict:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Overwrite other model", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Discard my changes", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Save as new model", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Create new version", + "MODEL.CONFLICT.SAVEAS" : "Save as:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "An activity is about to be executed as a compensation for another activity. The event targets the activity that is about to be executed for compensation", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "An activity has been completed successfully", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "An activity has received an error event. Dispatched before the actual error has been received by the activity", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "A new membership has been created", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "A single membership has been deleted", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "All memberships in the related group have been deleted. No individual events will be dispatched due to possible performance reasons", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "A task as been assigned. This is thrown alongside with an ENTITY_UPDATED event", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "A task has been completed. Dispatched before the task entity is deleted", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "When a BPMN Error was thrown, but was not caught within in the process", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "A new variable has been created", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "An existing variable has been deleted", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "An existing variable has been updated", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Decision table reference", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "There was an error loading the decision tables. Try again later", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Loading decision tables...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "This folder contains no decision tables", + + "PROPERTY.CASEREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.CASEREFERENCE.TITLE" : "Case model reference", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "There was an error loading the case models. Try again later", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "Loading case models...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "This folder contains no case models" +} diff --git a/zbf-admin/src/main/resources/static/designer/i18n/en.json b/zbf-admin/src/main/resources/static/designer/i18n/en.json new file mode 100644 index 0000000..dc71be1 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/i18n/en.json @@ -0,0 +1,2616 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable Editor", + "NAVIGATION" : { + "PROCESSES": "Processes", + "CASEMODELS": "Case models", + "FORMS": "Forms", + "DECISION-TABLES": "Decision Tables", + "APPS": "Apps" + }, + "TITLE": { + "SELECT-GROUP" :"Select group", + "MATCHING-GROUPS": "Matching groups", + "FILTER": "Filter", + "HISTORY": "History" + }, + "ACTION": { + "LOGOUT": "Sign out", + "RETURN-TO-LIST": "Show all definitions", + "CANCEL": "Cancel", + "CLOSE": "Close", + "EDIT": "Edit", + "SAVE": "Save", + "OPEN": "Open", + "OK": "Ok", + "CONFIRM": "Confirm", + "CONFIRM-AND-CLOSE": "Confirm and close", + "NEW-FORM": "New form", + "CREATE-FORM": "Create form", + "NEW-DECISION-TABLE": "New Decision Table", + "CREATE-DECISION-TABLE": "Create Decision Table" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "Use ↑ and ↓ to select and press Enter to confirm", + "PEOPLE-NO-MATCHING-RESULTS": "No matching users were found", + "GROUP-NO-MATCHING-RESULTS": "No matching groups were found", + "GROUP-SOURCE-TYPE": "Group source", + "GROUP-SOURCE-SEARCH-OPTION": "Group search", + "GROUP-SOURCE-FIELD-OPTION": "Form field" + }, + "OTHERS" : { + "PROCESS" : "Process", + "PROCESS_NAVIGATOR" : "Process Navigator", + "NO_STRUCTURAL_ELEMENTS_USED" : "No structural elements used." + } + }, + + "BPMN" : { + "TITLE": "Process editor", + "DESCRIPTION" : "BPMN process editor", + "PROPERTYPACKAGES" : { + "PROCESS_IDPACKAGE" : { + "PROCESS_ID" : { + "TITLE" : "Process identifier", + "DESCRIPTION" : "Unique identifier of the process definition." + } + }, + "OVERRIDEIDPACKAGE" : { + "OVERRIDEID" : { + "TITLE" : "Id", + "DESCRIPTION" : "Unique identifier of the element." + } + }, + "NAMEPACKAGE" : { + "NAME" : { + "TITLE" : "Name", + "DESCRIPTION" : "The descriptive name of the BPMN element." + } + }, + "DOCUMENTATIONPACKAGE" : { + "DOCUMENTATION" : { + "TITLE" : "Documentation", + "DESCRIPTION" : "The descriptive name of the BPMN element." + } + }, + "CATEGORYPACKAGE" : { + "CATEGORYDEFINITION" : { + "TITLE" : "Category", + "DESCRIPTION" : "Category of the BPMN element." + } + }, + "PROCESS_AUTHORPACKAGE" : { + "PROCESS_AUTHOR" : { + "TITLE" : "Process author", + "DESCRIPTION" : "Author of the process definition." + } + }, + "PROCESS_VERSIONPACKAGE" : { + "PROCESS_VERSION" : { + "TITLE" : "Process version string (documentation only)", + "DESCRIPTION" : "Version identifier for documentation purpose." + } + }, + "PROCESS_HISTORYLEVELPACKAGE" : { + "PROCESS_HISTORYLEVEL" : { + "TITLE" : "Set a specific history level for this process definition", + "DESCRIPTION" : "Set a specific history level for this process definition" + } + }, + "ISEXECUTABLEPACKAGE" : { + "ISEXECUTABLE" : { + "TITLE" : "Is executable", + "DESCRIPTION" : "Is the process executable?" + } + }, + "PROCESS_POTENTIALSTARTERUSERPACKAGE" : { + "PROCESS_POTENTIALSTARTERUSER" : { + "TITLE" : "Potential starter user", + "DESCRIPTION" : "Which user, can start the process?" + } + }, + "PROCESS_POTENTIALSTARTERGROUPPACKAGE" : { + "PROCESS_POTENTIALSTARTERGROUP" : { + "TITLE" : "Potential starter group", + "DESCRIPTION" : "Which group, can start the process?" + } + }, + "PROCESS_NAMESPACEPACKAGE" : { + "PROCESS_NAMESPACE" : { + "TITLE" : "Target namespace", + "DESCRIPTION" : "Target namespace for the process definition." + } + }, + "PROCESS_ISEAGEREXECUTIONFETCHPACKAGE" : { + "ISEAGEREXECUTIONFETCH" : { + "TITLE" : "Eager execution fetching", + "DESCRIPTION" : "Enable eager execution fetching for this process definition?" + } + }, + "ASYNCHRONOUSDEFINITIONPACKAGE" : { + "ASYNCHRONOUSDEFINITION" : { + "TITLE" : "Asynchronous", + "DESCRIPTION" : "Define the activity as asynchronous." + } + }, + "DATAPROPERTIESPACKAGE" : { + "DATAPROPERTIES" : { + "TITLE" : "Data Objects", + "DESCRIPTION" : "Definition of the data object properties" + } + }, + "EXCLUSIVEDEFINITIONPACKAGE" : { + "EXCLUSIVEDEFINITION" : { + "TITLE" : "Exclusive", + "DESCRIPTION" : "Define the activity as exclusive." + } + }, + "EXECUTIONLISTENERSPACKAGE" : { + "EXECUTIONLISTENERS" : { + "TITLE" : "Execution listeners", + "DESCRIPTION" : "Listeners for an activity, process, sequence flow, start and end event." + } + }, + "TASKLISTENERSPACKAGE" : { + "TASKLISTENERS" : { + "TITLE" : "Task listeners", + "DESCRIPTION" : "Listeners for a user task" + } + }, + "EVENTLISTENERSPACKAGE" : { + "EVENTLISTENERS" : { + "TITLE" : "Event listeners", + "DESCRIPTION" : "Listeners for any event happening in the Flowable Engine. It's also possible to rethrow the event as a signal, message or error event" + } + }, + "USERTASKASSIGNMENTPACKAGE" : { + "USERTASKASSIGNMENT" : { + "TITLE" : "Assignments", + "DESCRIPTION" : "Assignment definition for the user task" + } + }, + "FORMPROPERTIESPACKAGE" : { + "FORMPROPERTIES" : { + "TITLE" : "Form properties", + "DESCRIPTION" : "Definition of the form with a list of form properties" + } + }, + "FORMKEYDEFINITIONPACKAGE" : { + "FORMKEYDEFINITION" : { + "TITLE" : "Form key", + "DESCRIPTION" : "Form key that provides a reference to a form." + } + }, + "FORMFIELDVALIDATIONPACKAGE" : { + "FORMFIELDVALIDATION" : { + "TITLE" : "Validate form fields", + "DESCRIPTION" : "Validate form fields on the form submission. (allowed values are 'true', 'false' or expression)" + } + }, + "DUEDATEDEFINITIONPACKAGE" : { + "DUEDATEDEFINITION" : { + "TITLE" : "Due date", + "DESCRIPTION" : "Due date of the user task." + } + }, + "PRIORITYDEFINITIONPACKAGE" : { + "PRIORITYDEFINITION" : { + "TITLE" : "Priority", + "DESCRIPTION" : "Priority of the user task." + } + }, + "SERVICETASKCLASSPACKAGE" : { + "SERVICETASKCLASS" : { + "TITLE" : "Class", + "DESCRIPTION" : "Class that implements the service task logic." + } + }, + "SERVICETASKEXPRESSIONPACKAGE" : { + "SERVICETASKEXPRESSION" : { + "TITLE" : "Expression", + "DESCRIPTION" : "Service task logic defined with an expression." + } + }, + "SERVICETASKDELEGATEEXPRESSIONPACKAGE" : { + "SERVICETASKDELEGATEEXPRESSION" : { + "TITLE" : "Delegate expression", + "DESCRIPTION" : "Service task logic defined with a delegate expression." + } + }, + "SERVICETASKFIELDSPACKAGE" : { + "SERVICETASKFIELDS" : { + "TITLE" : "Class fields", + "DESCRIPTION" : "Field extensions" + } + }, + "SERVICETASKRESULTVARIABLEPACKAGE" : { + "SERVICETASKRESULTVARIABLE" : { + "TITLE" : "Result variable name", + "DESCRIPTION" : "Process variable name to store the service task result." + } + }, + "SERVICETASKRESULTVARIABLEPACKAGE" : { + "SERVICETASKUSELOCALSCOPEFORRESULTVARIABLE" : { + "TITLE" : "Use local scope for result variable", + "DESCRIPTION" : "Flag that marks that the used resultVariable needs to be saved as a local variable" + } + }, + "SERVICETASKTRIGGERABLEPACKAGE" : { + "SERVICETASKTRIGGERABLE" : { + "TITLE" : "Set service task to be triggerable", + "DESCRIPTION" : "Sets the service task to be triggerable" + } + }, + "SCRIPTFORMATPACKAGE" : { + "SCRIPTFORMAT" : { + "TITLE" : "Script format", + "DESCRIPTION" : "Script format of the script task." + } + }, + "SCRIPTTEXTPACKAGE" : { + "SCRIPTTEXT" : { + "TITLE" : "Script", + "DESCRIPTION" : "Script text of the script task." + } + }, + "SCRIPTAUTOSTOREVARIABLESPACKAGE" : { + "SCRIPTAUTOSTOREVARIABLES" : { + "TITLE" : "Auto Store Variables", + "DESCRIPTION" : "Automatically store all script variables to the process." + } + }, + "SHELLCOMMANDPACKAGE" : { + "SHELLCOMMAND" : { + "TITLE" : "Command", + "DESCRIPTION" : "Shell task command" + } + }, + "SHELLARG1PACKAGE" : { + "SHELLARG1" : { + "TITLE" : "Argument 1", + "DESCRIPTION" : "Shell commnad arg 1" + } + }, + "SHELLARG2PACKAGE" : { + "SHELLARG2" : { + "TITLE" : "Argument 2", + "DESCRIPTION" : "Shell commnad arg 2" + } + }, + "SHELLARG3PACKAGE" : { + "SHELLARG3" : { + "TITLE" : "Argument 3", + "DESCRIPTION" : "Shell commnad arg 3" + } + }, + "SHELLARG4PACKAGE" : { + "SHELLARG4" : { + "TITLE" : "Argument 4", + "DESCRIPTION" : "Shell commnad arg 4" + } + }, + "SHELLARG5PACKAGE" : { + "SHELLARG5" : { + "TITLE" : "Argument 5", + "DESCRIPTION" : "Shell commnad arg 5" + } + }, + "SHELLWAITPACKAGE" : { + "SHELLWAIT" : { + "TITLE" : "Wait", + "DESCRIPTION" : "Flag to wait for shell command execution end" + } + }, + "SHELLOUTPUTVARIABLEPACKAGE" : { + "SHELLOUTPUTVARIABLE" : { + "TITLE" : "Output variable", + "DESCRIPTION" : "Variable to store shell commnad output" + } + }, + "SHELLERRORCODEVARIABLEPACKAGE" : { + "SHELLERRORCODEVARIABLE" : { + "TITLE" : "Error code variable", + "DESCRIPTION" : "Variable to store shell commnad error code" + } + }, + "SHELLREDIRECTERRORPACKAGE" : { + "SHELLREDIRECTERROR" : { + "TITLE" : "Redirect error", + "DESCRIPTION" : "If true merge error output with standard output" + } + }, + "SHELLCLEANENVPACKAGE" : { + "SHELLCLEANENV" : { + "TITLE" : "Clean env", + "DESCRIPTION" : "Clean shell execution environment" + } + }, + "SHELLDIRECTORYPACKAGE" : { + "SHELLDIRECTORY" : { + "TITLE" : "Directory", + "DESCRIPTION" : "Shell process working directory" + } + }, + "RULETASK_RULESPACKAGE" : { + "RULETASK_RULES" : { + "TITLE" : "Rules", + "DESCRIPTION" : "Rules of the rule task." + } + }, + "RULETASK_VARIABLES_INPUTPACKAGE" : { + "RULETASK_VARIABLES_INPUT" : { + "TITLE" : "Input variables", + "DESCRIPTION" : "Input variables of the rule task." + } + }, + "RULETASK_EXCLUDEPACKAGE" : { + "RULETASK_EXCLUDE" : { + "TITLE" : "Exclude", + "DESCRIPTION" : "Use the rules property as exclusion." + } + }, + "RULETASK_RESULTPACKAGE" : { + "RULETASK_RESULT" : { + "TITLE" : "Result variable", + "DESCRIPTION" : "Result variable of the rule task." + } + }, + "MAILTASKHEADERSPACKAGE" : { + "MAILTASKHEADERS" : { + "TITLE" : "Headers", + "DESCRIPTION" : "Line separated Mail headers (For example - X-Attribute: value)." + } + }, + "MAILTASKTOPACKAGE" : { + "MAILTASKTO" : { + "TITLE" : "To", + "DESCRIPTION" : "The recipients if the e-mail. Multiple recipients are defined in a comma-separated list." + } + }, + "MAILTASKFROMPACKAGE" : { + "MAILTASKFROM" : { + "TITLE" : "From", + "DESCRIPTION" : "The sender e-mail address. If not provided, the default configured from address is used." + } + }, + "MAILTASKSUBJECTPACKAGE" : { + "MAILTASKSUBJECT" : { + "TITLE" : "Subject", + "DESCRIPTION" : "The subject of the e-mail." + } + }, + "MAILTASKCCPACKAGE" : { + "MAILTASKCC" : { + "TITLE" : "Cc", + "DESCRIPTION" : "The cc's of the e-mail. Multiple recipients are defined in a comma-separated list" + } + }, + "MAILTASKBCCPACKAGE" : { + "MAILTASKBCC" : { + "TITLE" : "Bcc", + "DESCRIPTION" : "The bcc's of the e-mail. Multiple recipients are defined in a comma-separated list" + } + }, + "MAILTASKTEXTPACKAGE" : { + "MAILTASKTEXT" : { + "TITLE" : "Text", + "DESCRIPTION" : "The content of the e-mail, in case one needs to send plain none-rich e-mails. Can be used in combination with html, for e-mail clients that don't support rich content. The client will then fall back to this text-only alternative." + } + }, + "MAILTASKHTMLPACKAGE" : { + "MAILTASKHTML" : { + "TITLE" : "Html", + "DESCRIPTION" : "A piece of HTML that is the content of the e-mail." + } + }, + "MAILTASKCHARSETPACKAGE" : { + "MAILTASKCHARSET" : { + "TITLE" : "Charset", + "DESCRIPTION" : "Allows to change the charset of the email, which is necessary for many non-English languages. " + } + }, + "HTTPTASKREQUESTMETHODPACKAGE" : { + "HTTPTASKREQUESTMETHOD" : { + "TITLE" : "Request method", + "DESCRIPTION" : "Request method (For example - GET,POST,PUT etc)." + } + }, + "HTTPTASKREQUESTURLPACKAGE" : { + "HTTPTASKREQUESTURL" : { + "TITLE" : "Request URL", + "DESCRIPTION" : "Request URL (For example - http://flowable.org)." + } + }, + "HTTPTASKREQUESTHEADERSPACKAGE" : { + "HTTPTASKREQUESTHEADERS" : { + "TITLE" : "Request headers", + "DESCRIPTION" : "Line separated HTTP request headers (For example - Content-Type: application/json)." + } + }, + "HTTPTASKREQUESTBODYPACKAGE" : { + "HTTPTASKREQUESTBODYPACKAGE" : { + "TITLE" : "Request body", + "DESCRIPTION" : "Request body (For example- ${sampleBody})." + } + }, + "HTTPTASKREQUESTBODYENCODINGPACKAGE" : { + "HTTPTASKREQUESTBODYENCODING" : { + "TITLE" : "Request body encoding", + "DESCRIPTION" : "Request body encoding (For example- UTF-8)." + } + }, + "HTTPTASKREQUESTTIMEOUTPACKAGE" : { + "HTTPTASKREQUESTTIMEOUT" : { + "TITLE" : "Request timeout", + "DESCRIPTION" : "Timeout in milliseconds for the request (For example - 5000)." + } + }, + "HTTPTASKDISALLOWREDIRECTSPACKAGE" : { + "HTTPTASKDISALLOWREDIRECTS" : { + "TITLE" : "Disallow redirects", + "DESCRIPTION" : "Flag to disallow HTTP redirects." + } + }, + "HTTPTASKFAILSTATUSCODESPACKAGE" : { + "HTTPTASKFAILSTATUSCODES" : { + "TITLE" : "Fail status codes", + "DESCRIPTION" : "Comma separated list of HTTP response status codes to retry, for example 400,5XX." + } + }, + "HTTPTASKHANDLESTATUSCODESPACKAGE" : { + "HTTPTASKHANDLESTATUSCODES" : { + "TITLE" : "Handle status codes", + "DESCRIPTION" : "Comma separated list of HTTP response status codes to ignore, for example 404,3XX." + } + }, + "HTTPTASKIGNOREEXCEPTIONPACKAGE" : { + "HTTPTASKIGNOREEXCEPTION" : { + "TITLE" : "Ignore exception", + "DESCRIPTION" : "Flag to ignore exceptions." + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENTPACKAGE" : { + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENT" : { + "TITLE" : "Save response as a transient variable", + "DESCRIPTION" : "Flag indicating to store the response variable(s) transient" + } + }, + "HTTPTASKSAVERESPONSEASJSONPACKAGE" : { + "HTTPTASKSAVERESPONSEASJSON" : { + "TITLE" : "Save response as JSON", + "DESCRIPTION" : "Flag indicating to store the response variable as a JSON variable instead of a String" + } + }, + "SKIPEXPRESSIONPACKAGE" : { + "SKIPEXPRESSION" : { + "TITLE" : "Skip expression", + "DESCRIPTION" : "Skip an expression execution associated with task or association or not." + } + }, + "HTTPTASKRESPONSEVARIABLENAMEPACKAGE" : { + "HTTPTASKRESPONSEVARIABLENAME" : { + "TITLE" : "Response variable name", + "DESCRIPTION" : "Define the variable name to store the http response." + } + }, + "HTTPTASKSAVEREQUESTVARIABLESPACKAGE" : { + "HTTPTASKSAVEREQUESTVARIABLES" : { + "TITLE" : "Save request variables", + "DESCRIPTION" : "Flag to save request variables." + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSPACKAGE" : { + "HTTPTASKSAVERESPONSEPARAMETERS" : { + "TITLE" : "Save response status, headers", + "DESCRIPTION" : "Flag to save response status, headers etc." + } + }, + "HTTPTASKRESULTVARIABLEPREFIXPACKAGE" : { + "HTTPTASKRESULTVARIABLEPREFIX" : { + "TITLE" : "Result variable prefix", + "DESCRIPTION" : "Prefix for the execution variable names." + } + }, + "CALLACTIVITYCALLEDELEMENTPACKAGE" : { + "CALLACTIVITYCALLEDELEMENT" : { + "TITLE" : "Called element", + "DESCRIPTION" : "Process reference." + } + }, + "CALLACTIVITYCALLEDELEMENTTYPEPACKAGE" : { + "CALLACTIVITYCALLEDELEMENTTYPE" : { + "TITLE" : "Called element type", + "DESCRIPTION" : "Type of the used process reference." + } + }, + "CALLACTIVITYINPARAMETERSPACKAGE" : { + "CALLACTIVITYINPARAMETERS" : { + "TITLE" : "In parameters", + "DESCRIPTION" : "Definition of the input parameters" + } + }, + "CALLACTIVITYOUTPARAMETERSPACKAGE" : { + "CALLACTIVITYOUTPARAMETERS" : { + "TITLE" : "Out parameters", + "DESCRIPTION" : "Definition of the output parameters" + } + }, + "CALLACTIVITYINHERITVARIABLESPACKAGE" : { + "CALLACTIVITYINHERITVARIABLES" : { + "TITLE" : "Inherit variables in sub process", + "DESCRIPTION" : "Inherit parent process variables in the sub process." + } + }, + "CALLACTIVITYSAMEDEPLOYMENTPACKAGE" : { + "CALLACTIVITYSAMEDEPLOYMENT" : { + "TITLE" : "Start the referenced process from the same deployment.", + "DESCRIPTION" : "Use the referenced process from the same deployment." + } + }, + "CALLACTIVITYFALLBACKTODEFAULTTENANTPACKAGE" : { + "CALLACTIVITYFALLBACKTODEFAULTTENANT" : { + "TITLE" : "Fallback to default tenant", + "DESCRIPTION" : "Look for the definition by key in the default tenant when current tenant search fails." + } + }, + "CALLACTIVITYPROCESSINSTANCENAMEPACKAGE" : { + "CALLACTIVITYPROCESSINSTANCENAME" : { + "TITLE" : "Process instance name", + "DESCRIPTION" : "An expression that resolves to the name of the child process instance" + } + }, + "CALLACTIVITYINHERITBUSINESSKEYPACKAGE" : { + "CALLACTIVITYINHERITBUSINESSKEY" : { + "TITLE" : "Inherit business key", + "DESCRIPTION" : "Inherit the business key from the parent process." + } + }, + "CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERSPACKAGE" : { + "CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERS" : { + "TITLE" : "Use local scope for out parameters", + "DESCRIPTION" : "Use local variable scope for out parameters." + } + }, + "CALLACTIVITYBUSINESSKEYPACKAGE" : { + "CALLACTIVITYBUSINESSKEY" : { + "TITLE" : "Business key expression", + "DESCRIPTION" : "An expression that resolves to a business key for the child process instance" + } + }, + "CALLACTIVITYCOMPLETEASYNCPACKAGE" : { + "CALLACTIVITYCOMPLETEASYNC" : { + "TITLE" : "Complete asynchronously", + "DESCRIPTION" : "If set, the child process ending and completing the call activity is done asynchronously. Useful when using parallel multi instance with a called process definition that has async tasks." + } + }, + "CAMELTASKCAMELCONTEXTPACKAGE" : { + "CAMELTASKCAMELCONTEXT" : { + "TITLE" : "Camel context", + "DESCRIPTION" : "An optional camel context definition, if left empty the default is used." + } + }, + "MULETASKENDPOINTURLPACKAGE" : { + "MULETASKENDPOINTURL" : { + "TITLE" : "Endpoint url", + "DESCRIPTION" : "A required endpoint url to sent the message to Mule." + } + }, + "MULETASKLANGUAGEPACKAGE" : { + "MULETASKLANGUAGE" : { + "TITLE" : "Language", + "DESCRIPTION" : "A required definition for the language to resolve the payload expression, like juel." + } + }, + "MULETASKPAYLOADEXPRESSIONPACKAGE" : { + "MULETASKPAYLOADEXPRESSION" : { + "TITLE" : "Payload expression", + "DESCRIPTION" : "A required definition for the payload of the message sent to Mule." + } + }, + "MULETASKRESULTVARIABLEPACKAGE" : { + "MULETASKRESULTVARIABLE" : { + "TITLE" : "Result variable", + "DESCRIPTION" : "An optional result variable for the payload returned." + } + }, + "CONDITIONSEQUENCEFLOWPACKAGE" : { + "CONDITIONSEQUENCEFLOWPACKAGE" : { + "TITLE" : "Flow condition", + "DESCRIPTION" : "The condition of the sequence flow" + } + }, + "DEFAULTFLOWPACKAGE" : { + "DEFAULTFLOW" : { + "TITLE" : "Default flow", + "DESCRIPTION" : "Define the sequence flow as default" + } + }, + "CONDITIONALFLOWPACKAGE" : { + "CONDITIONALFLOW" : { + "TITLE" : "Conditional flow", + "DESCRIPTION" : "Define the sequence flow with a condition" + } + }, + "TIMERCYCLEDEFINITIONPACKAGE" : { + "TIMERCYCLEDEFINITION" : { + "TITLE" : "Time cycle (e.g. R3/PT10H)", + "DESCRIPTION" : "Define the timer with a ISO-8601 cycle." + } + }, + "TIMERDATEDEFINITIONPACKAGE" : { + "TIMERDATEDEFINITION" : { + "TITLE" : "Time date in ISO-8601", + "DESCRIPTION" : "Define the timer with a ISO-8601 date definition." + } + }, + "TIMERDURATIONDEFINITIONPACKAGE" : { + "TIMERDURATIONDEFINITION" : { + "TITLE" : "Time duration (e.g. PT5M)", + "DESCRIPTION" : "Define the timer with a ISO-8601 duration." + } + }, + "TIMERENDDATEDEFINITIONPACKAGE" : { + "TIMERENDDATEDEFINITION" : { + "TITLE" : "Time End Date in ISO-8601", + "DESCRIPTION" : "Define the timer with a ISO-8601 duration." + } + }, + "MESSAGEREFPACKAGE" : { + "MESSAGEREF" : { + "TITLE" : "Message reference", + "DESCRIPTION" : "Define the message name." + } + }, + "SIGNALREFPACKAGE" : { + "SIGNALREF" : { + "TITLE" : "Signal reference", + "DESCRIPTION" : "Define the signal name." + } + }, + "ERRORREFPACKAGE" : { + "ERRORREF" : { + "TITLE" : "Error reference", + "DESCRIPTION" : "Define the error name." + } + }, + "ESCALATIONREFPACKAGE" : { + "ESCALATIONREF" : { + "TITLE" : "Escalation reference", + "DESCRIPTION" : "Define the escalation name." + } + }, + "CONDITIONALEVENTPACKAGE" : { + "CONDITION" : { + "TITLE" : "Condition expression", + "DESCRIPTION" : "Define the condition expression for the conditional event." + } + }, + "CANCELACTIVITYPACKAGE" : { + "CANCELACTIVITY" : { + "TITLE" : "Cancel activity", + "DESCRIPTION" : "Should the activity be cancelled" + } + }, + "INITIATORPACKAGE" : { + "INITIATOR" : { + "TITLE" : "Initiator", + "DESCRIPTION" : "Initiator of the process." + } + }, + "TEXTPACKAGE" : { + "TEXT" : { + "TITLE" : "Text", + "DESCRIPTION" : "The text of the text annotation." + } + }, + "MULTIINSTANCE_TYPEPACKAGE" : { + "MULTIINSTANCE_TYPE" : { + "TITLE" : "Multi-instance type", + "DESCRIPTION" : "Repeated activity execution (parallel or sequential) can be displayed through different loop types" + } + }, + "MULTIINSTANCE_CARDINALITYPACKAGE" : { + "MULTIINSTANCE_CARDINALITY" : { + "TITLE" : "Cardinality (Multi-instance)", + "DESCRIPTION" : "Define the cardinality of multi instance." + } + }, + "MULTIINSTANCE_COLLECTIONPACKAGE" : { + "MULTIINSTANCE_COLLECTION" : { + "TITLE" : "Collection (Multi-instance)", + "DESCRIPTION" : "Define the collection for the multi instance." + } + }, + "MULTIINSTANCE_VARIABLEPACKAGE" : { + "MULTIINSTANCE_VARIABLE" : { + "TITLE" : "Element variable (Multi-instance)", + "DESCRIPTION" : "Define the element variable for the multi instance." + } + }, + "MULTIINSTANCE_CONDITIONPACKAGE" : { + "MULTIINSTANCE_CONDITION" : { + "TITLE" : "Completion condition (Multi-instance)", + "DESCRIPTION" : "Define the completion condition for the multi instance." + } + }, + "ISFORCOMPENSATIONPACKAGE" : { + "ISFORCOMPENSATION" : { + "TITLE" : "Is for compensation", + "DESCRIPTION" : "A flag that identifies whether this activity is intended for the purposes of compensation." + } + }, + "SEQUENCEFLOWORDERPACKAGE" : { + "SEQUENCEFLOWORDER" : { + "TITLE" : "Flow order", + "DESCRIPTION" : "Order outgoing sequence flows." + } + }, + "SIGNALDEFINITIONSPACKAGE" : { + "SIGNALDEFINITIONS" : { + "TITLE" : "Signal definitions", + "DESCRIPTION" : "Signal definitions" + } + }, + "MESSAGEDEFINITIONSPACKAGE" : { + "MESSAGEDEFINITIONS" : { + "TITLE" : "Message definitions", + "DESCRIPTION" : "Message definitions" + } + }, + "ESCALATIONDEFINITIONSPACKAGE" : { + "ESCALATIONDEFINITIONS" : { + "TITLE" : "Escalation definitions", + "DESCRIPTION" : "Escalation definitions" + } + }, + "ISTRANSACTIONPACKAGE" : { + "ISTRANSACTION" : { + "TITLE" : "Is a transaction sub process", + "DESCRIPTION" : "A flag that identifies whether this sub process is of type transaction." + } + }, + "FORMREFERENCEPACKAGE" : { + "FORMREFERENCE" : { + "TITLE" : "Form reference", + "DESCRIPTION" : "Reference to a form" + } + }, + "TERMINATEALLPACKAGE" : { + "TERMINATEALL" : { + "TITLE" : "Terminate all", + "DESCRIPTION" : "Enable to terminate the process instance" + } + }, + "DECISIONTASKDECISIONTABLEREFERENCEPACKAGE" : { + "DECISIONTASKDECISIONTABLEREFERENCE" : { + "TITLE" : "Decision table reference", + "DESCRIPTION" : "Set the decision table reference" + } + }, + "DECISIONTASKTHROWERRORONNOHITSPACKAGE" : { + "DECISIONTASKTHROWERRORONNOHITS" : { + "TITLE" : "Throw error if no rules were hit", + "DESCRIPTION" : "Should an error be thrown if no rules of the decision table were hit and consequently no result was found." + } + }, + "DECISIONTASKFALLBACKTODEFAULTTENANTPACKAGE" : { + "DECISIONTASKFALLBACKTODEFAULTTENANT" : { + "TITLE" : "Fallback to default tenant", + "DESCRIPTION" : "Find decision definition without tenant when previous attemps to find it with tenant failed." + } + }, + "INTERRUPTINGPACKAGE" : { + "INTERRUPTING" : { + "TITLE" : "Interrupting", + "DESCRIPTION" : "Should all parent executions be terminated?" + } + }, + "COMPLETIONCONDITIONPACKAGE" : { + "COMPLETIONCONDITION" : { + "TITLE" : "Completion condition", + "DESCRIPTION" : "The completion condition for the adhoc sub process" + } + }, + "ORDERINGPACKAGE" : { + "ORDERING" : { + "TITLE" : "Ordering", + "DESCRIPTION" : "The ordering for the adhoc sub process" + } + }, + "CANCELREMAININGINSTANCESPACKAGE" : { + "CANCELREMAININGINSTANCES" : { + "TITLE" : "Cancel remaining instances", + "DESCRIPTION" : "Cancel the remaining instances for the adhoc sub process?" + } + } + + }, + "STENCILS" : { + "GROUPS" : { + "STARTEVENTS" : "Start Events", + "ENDEVENTS" : "End Events", + "DIAGRAM" : "Diagram", + "ACTIVITIES" : "Activities", + "STRUCTURAL" : "Structural", + "GATEWAYS" : "Gateways", + "BOUNDARYEVENTS" : "Boundary Events", + "INTERMEDIATECATCHINGEVENTS" : "Intermediate Catching Events", + "INTERMEDIATETHROWINGEVENTS" : "Intermediate Throwing Events", + "SWIMLANES" : "Swimlanes", + "CONNECTINGOBJECTS" : "Connecting Objects", + "ARTIFACTS" : "Artifacts" + }, + "BPMNDIAGRAM" : { + "TITLE" : "BPMN-Diagram", + "DESCRIPTION" : "A BPMN 2.0 diagram." + }, + "STARTNONEEVENT" : { + "TITLE" : "Start event", + "DESCRIPTION" : "A start event without a specific trigger" + }, + "STARTTIMEREVENT" : { + "TITLE" : "Start timer event", + "DESCRIPTION" : "A start event with a timer trigger" + }, + "STARTSIGNALEVENT" : { + "TITLE" : "Start signal event", + "DESCRIPTION" : "A start event with a signal trigger" + }, + "STARTMESSAGEEVENT" : { + "TITLE" : "Start message event", + "DESCRIPTION" : "A start event with a message trigger" + }, + "STARTCONDITIONALEVENT" : { + "TITLE" : "Start conditional event", + "DESCRIPTION" : "A start event that evaluates a conditional event" + }, + "STARTERROREVENT" : { + "TITLE" : "Start error event", + "DESCRIPTION" : "A start event that catches a thrown BPMN error" + }, + "STARTESCALATIONEVENT" : { + "TITLE" : "Start escalation event", + "DESCRIPTION" : "A start event that catches a thrown BPMN escalation" + }, + "USERTASK" : { + "TITLE" : "User task", + "DESCRIPTION" : "A manual task assigned to a specific person" + }, + "SERVICETASK" : { + "TITLE" : "Service task", + "DESCRIPTION" : "An automatic task with service logic" + }, + "SCRIPTTASK" : { + "TITLE" : "Script task", + "DESCRIPTION" : "An automatic task with script logic" + }, + "BUSINESSRULE" : { + "TITLE" : "Business rule task", + "DESCRIPTION" : "An automatic task with rule logic" + }, + "RECEIVETASK" : { + "TITLE" : "Receive task", + "DESCRIPTION" : "An task that waits for a signal" + }, + "MANUALTASK" : { + "TITLE" : "Manual task", + "DESCRIPTION" : "An automatic task with no logic" + }, + "MAILTASK" : { + "TITLE" : "Mail task", + "DESCRIPTION" : "An mail task" + }, + "CAMELTASK" : { + "TITLE" : "Camel task", + "DESCRIPTION" : "An task that sends a message to Camel" + }, + "HTTPTASK" : { + "TITLE" : "Http task", + "DESCRIPTION" : "A HTTP task" + }, + "MULETASK" : { + "TITLE" : "Mule task", + "DESCRIPTION" : "An task that sends a message to Mule" + }, + "SENDTASK" : { + "TITLE" : "Send task", + "DESCRIPTION" : "An task that sends a message" + }, + "DECISIONTASK" : { + "TITLE" : "Decision task", + "DESCRIPTION" : "Task to use the Flowable DMN rule engine" + }, + "SHELLTASK" : { + "TITLE" : "Shell task", + "DESCRIPTION" : "An automatic task with shell batch logic" + }, + "SUBPROCESS" : { + "TITLE" : "Sub process", + "DESCRIPTION" : "A sub process scope" + }, + "COLLAPSEDSUBPROCESS" : { + "TITLE" : "Collapsed Sub process", + "DESCRIPTION" : "A sub process scope" + }, + "EVENTSUBPROCESS" : { + "TITLE" : "Event sub process", + "DESCRIPTION" : "A event sub process scope" + }, + "CALLACTIVITY" : { + "TITLE" : "Call activity", + "DESCRIPTION" : "A call activity" + }, + "EXCLUSIVEGATEWAY" : { + "TITLE" : "Exclusive gateway", + "DESCRIPTION" : "A choice gateway" + }, + "PARALLELGATEWAY" : { + "TITLE" : "Parallel gateway", + "DESCRIPTION" : "A parallel gateway" + }, + "INCLUSIVEGATEWAY" : { + "TITLE" : "Inclusive gateway", + "DESCRIPTION" : "An inclusive gateway" + }, + "EVENTGATEWAY" : { + "TITLE" : "Event gateway", + "DESCRIPTION" : "An event gateway" + }, + "BOUNDARYCONDITIONALEVENT" : { + "TITLE" : "Boundary conditional event", + "DESCRIPTION" : "A boundary event that evaluates a conditional event" + }, + "BOUNDARYERROREVENT" : { + "TITLE" : "Boundary error event", + "DESCRIPTION" : "A boundary event that catches a BPMN error" + }, + "BOUNDARYESCALATIONEVENT" : { + "TITLE" : "Boundary escalation event", + "DESCRIPTION" : "A boundary event that catches a BPMN escalation" + }, + "BOUNDARYTIMEREVENT" : { + "TITLE" : "Boundary timer event", + "DESCRIPTION" : "A boundary event with a timer trigger" + }, + "BOUNDARYSIGNALEVENT" : { + "TITLE" : "Boundary signal event", + "DESCRIPTION" : "A boundary event with a signal trigger" + }, + "BOUNDARYMESSAGEEVENT" : { + "TITLE" : "Boundary message event", + "DESCRIPTION" : "A boundary event with a message trigger" + }, + "BOUNDARYCANCELEVENT" : { + "TITLE" : "Boundary cancel event", + "DESCRIPTION" : "A boundary cancel event" + }, + "BOUNDARYCOMPENSATIONEVENT" : { + "TITLE" : "Boundary compensation event", + "DESCRIPTION" : "A boundary compensation event" + }, + "CATCHTIMEREVENT" : { + "TITLE" : "Intermediate timer catching event", + "DESCRIPTION" : "An intermediate catching event with a timer trigger" + }, + "CATCHSIGNALEVENT" : { + "TITLE" : "Intermediate signal catching event", + "DESCRIPTION" : "An intermediate catching event with a signal trigger" + }, + "CATCHMESSAGEEVENT" : { + "TITLE" : "Intermediate message catching event", + "DESCRIPTION" : "An intermediate catching event with a message trigger" + }, + "CATCHCONDITIONALEVENT" : { + "TITLE" : "Intermediate conditional catching event", + "DESCRIPTION" : "An intermediate catching event with a conditional trigger" + }, + "THROWNONEEVENT" : { + "TITLE" : "Intermediate none throwing event", + "DESCRIPTION" : "An intermediate event without a specific trigger" + }, + "THROWSIGNALEVENT" : { + "TITLE" : "Intermediate signal throwing event", + "DESCRIPTION" : "An intermediate event with a signal trigger" + }, + "THROWESCALATIONEVENT" : { + "TITLE" : "Intermediate escalation throwing event", + "DESCRIPTION" : "An intermediate event with an escalation trigger" + }, + "ENDNONEEVENT" : { + "TITLE" : "End event", + "DESCRIPTION" : "An end event without a specific trigger" + }, + "ENDERROREVENT" : { + "TITLE" : "End error event", + "DESCRIPTION" : "An end event that throws an error event" + }, + "ENDESCALATIONEVENT" : { + "TITLE" : "End escalation event", + "DESCRIPTION" : "An end event that throws an escalation event" + }, + "ENDCANCELEVENT" : { + "TITLE" : "End cancel event", + "DESCRIPTION" : "A cancel end event" + }, + "ENDTERMINATEEVENT" : { + "TITLE" : "End terminate event", + "DESCRIPTION" : "A terminate end event" + }, + "POOL" : { + "TITLE" : "Pool", + "DESCRIPTION" : "A pool to stucture the process definition" + }, + "LANE" : { + "TITLE" : "Lane", + "DESCRIPTION" : "A lane to stucture the process definition" + }, + "SEQUENCEFLOW" : { + "TITLE" : "Sequence flow", + "DESCRIPTION" : "Sequence flow defines the execution order of activities." + }, + "MESSAGEFLOW" : { + "TITLE" : "Message flow", + "DESCRIPTION" : "Message flow to connect elements in different pools." + }, + "ASSOCIATION" : { + "TITLE" : "Association", + "DESCRIPTION" : "Associates a text annotation with an element." + }, + "DATAASSOCIATION" : { + "TITLE" : "DataAssociation", + "DESCRIPTION" : "Associates a data element with an activity." + }, + "TEXTANNOTATION" : { + "TITLE" : "Text annotation", + "DESCRIPTION" : "Annotates elements with description text." + }, + "DATASTORE" : { + "TITLE" : "Data store", + "DESCRIPTION" : "Reference to a data store." + }, + "ADHOCSUBPROCESS" : { + "TITLE" : "Adhoc sub process", + "DESCRIPTION" : "An adhoc sub process" + } + } + }, + + "CMMN" : { + "TITLE": "CMMN editor", + "DESCRIPTION": "CMMN case editor", + "PROPERTYPACKAGES": { + "CASE_IDPACKAGE": { + "CASE_ID": { + "TITLE": "Case identifier", + "DESCRIPTION": "Unique identifier of the case definition." + } + }, + "OVERRIDEIDPACKAGE": { + "OVERRIDEID": { + "TITLE": "Id", + "DESCRIPTION": "Unique identifier of the element." + } + }, + "NAMEPACKAGE": { + "NAME": { + "TITLE": "Name", + "DESCRIPTION": "The descriptive name of the CMMN element." + } + }, + "DOCUMENTATIONPACKAGE": { + "DOCUMENTATION": { + "TITLE": "Documentation", + "DESCRIPTION": "The descriptive name of the CMMN element." + } + }, + "BLOCKINGPACKAGE": { + "ISBLOCKING": { + "TITLE": "Blocking", + "DESCRIPTION": "Boolean property, default true. If false the task will automatically complete the task after executing any associated logic" + }, + "ISBLOCKINGEXPRESSION": { + "TITLE": "Blocking expression", + "DESCRIPTION": "An expression to control at runtime whether this task is blocking or not. When set, the value of the blocking property is ignored." + } + }, + "CASE_INITIATORVARIABLENAMEPACKAGE": { + "CASE_INITIATORVARIABLENAME": { + "TITLE": "Initiator variable name", + "DESCRIPTION": "Sets the variable name to be used for the case initiator value." + } + }, + "CASE_AUTHORPACKAGE": { + "CASE_AUTHOR": { + "TITLE": "Case author", + "DESCRIPTION": "Author of the case definition." + } + }, + "CASE_VERSIONPACKAGE": { + "CASE_VERSION": { + "TITLE": "Case version string (documentation only)", + "DESCRIPTION": "Version identifier for documentation purpose." + } + }, + "CASE_NAMESPACEPACKAGE": { + "CASE_NAMESPACE": { + "TITLE": "Target namespace", + "DESCRIPTION": "Target namespace for the case definition." + } + }, + "USERTASKASSIGNMENTPACKAGE": { + "USERTASKASSIGNMENT": { + "TITLE": "Assignments", + "DESCRIPTION": "Assignment definition for the user task" + } + }, + "TASKLISTENERSPACKAGE": { + "TASKLISTENERS": { + "TITLE": "Task listeners", + "DESCRIPTION": "Listeners for a human task" + } + }, + "FORMPROPERTIESPACKAGE": { + "FORMPROPERTIES": { + "TITLE": "Form properties", + "DESCRIPTION": "Definition of the form with a list of form properties" + } + }, + "FORMKEYDEFINITIONPACKAGE": { + "FORMKEYDEFINITION": { + "TITLE": "Form key", + "DESCRIPTION": "Form key that provides a reference to a form." + } + }, + "FORMFIELDVALIDATIONPACKAGE": { + "FORMFIELDVALIDATION": { + "TITLE": "Validate form fields", + "DESCRIPTION": "Validate form fields on the form submission. (allowed values are 'true', 'false' or expression)" + } + }, + "DUEDATEDEFINITIONPACKAGE": { + "DUEDATEDEFINITION": { + "TITLE": "Due date", + "DESCRIPTION": "Due date of the user task." + } + }, + "PRIORITYDEFINITIONPACKAGE": { + "PRIORITYDEFINITION": { + "TITLE": "Priority", + "DESCRIPTION": "Priority of the user task." + } + }, + "SERVICETASKCLASSPACKAGE": { + "SERVICETASKCLASS": { + "TITLE": "Class", + "DESCRIPTION": "Class that implements the service task logic." + } + }, + "SERVICETASKEXPRESSIONPACKAGE": { + "SERVICETASKEXPRESSION": { + "TITLE": "Expression", + "DESCRIPTION": "Service task logic defined with an expression." + } + }, + "SERVICETASKDELEGATEEXPRESSIONPACKAGE": { + "SERVICETASKDELEGATEEXPRESSION": { + "TITLE": "Delegate expression", + "DESCRIPTION": "Service task logic defined with a delegate expression." + } + }, + "SERVICETASKFIELDSPACKAGE": { + "SERVICETASKFIELDS": { + "TITLE": "Class fields", + "DESCRIPTION": "Field extensions" + } + }, + "SERVICETASKRESULTVARIABLEPACKAGE": { + "SERVICETASKRESULTVARIABLE": { + "TITLE": "Result variable name", + "DESCRIPTION": "Process variable name to store the service task result." + } + }, + "ASYNCPACKAGE": { + "ISASYNC": { + "TITLE": "Asynchronous", + "DESCRIPTION": "Indicates if the task needs to be executed asynchronously." + }, + "ISEXCLUSIVE": { + "TITLE": "Exclusive", + "DESCRIPTION": "Indicates if an asynchronous task must be executed exclusively" + } + }, + "MAILTASKHEADERSPACKAGE": { + "MAILTASKHEADERS": { + "TITLE": "Headers", + "DESCRIPTION": "Line separated Mail headers (For example - X-Attribute: value)." + } + }, + "MAILTASKTOPACKAGE": { + "MAILTASKTO": { + "TITLE": "To", + "DESCRIPTION": "The recipients if the e-mail. Multiple recipients are defined in a comma-separated list." + } + }, + "MAILTASKFROMPACKAGE": { + "MAILTASKFROM": { + "TITLE": "From", + "DESCRIPTION": "The sender e-mail address. If not provided, the default configured from address is used." + } + }, + "MAILTASKSUBJECTPACKAGE": { + "MAILTASKSUBJECT": { + "TITLE": "Subject", + "DESCRIPTION": "The subject of the e-mail." + } + }, + "MAILTASKCCPACKAGE": { + "MAILTASKCC": { + "TITLE": "Cc", + "DESCRIPTION": "The cc's of the e-mail. Multiple recipients are defined in a comma-separated list" + } + }, + "MAILTASKBCCPACKAGE": { + "MAILTASKBCC": { + "TITLE": "Bcc", + "DESCRIPTION": "The bcc's of the e-mail. Multiple recipients are defined in a comma-separated list" + } + }, + "MAILTASKTEXTPACKAGE": { + "MAILTASKTEXT": { + "TITLE": "Text", + "DESCRIPTION": "The content of the e-mail, in case one needs to send plain none-rich e-mails. Can be used in combination with html, for e-mail clients that don't support rich content. The client will then fall back to this text-only alternative." + } + }, + "MAILTASKHTMLPACKAGE": { + "MAILTASKHTML": { + "TITLE": "Html", + "DESCRIPTION": "A piece of HTML that is the content of the e-mail." + } + }, + "MAILTASKCHARSETPACKAGE": { + "MAILTASKCHARSET": { + "TITLE": "Charset", + "DESCRIPTION": "Allows to change the charset of the email, which is necessary for many non-English languages. " + } + }, + "TEXTPACKAGE": { + "TEXT": { + "TITLE": "TEXT", + "DESCRIPTION": "The text of the text annotation." + } + }, + "FORMREFERENCEPACKAGE": { + "FORMREFERENCE": { + "TITLE": "Form reference", + "DESCRIPTION": "Reference to a form" + } + }, + "DECISIONTASKDECISIONTABLEREFERENCEPACKAGE": { + "DECISIONTASKDECISIONTABLEREFERENCE": { + "TITLE": "Decision table reference", + "DESCRIPTION": "Set the decision table reference" + } + }, + "DECISIONTASKTHROWERRORONNOHITSPACKAGE": { + "DECISIONTASKTHROWERRORONNOHITS": { + "TITLE": "Throw error if no rules were hit", + "DESCRIPTION": "Should an error be thrown if no rules of the decision table were hit and consequently no result was found." + } + }, + "DECISIONTASKFALLBACKTODEFAULTTENANTPACKAGE": { + "DECISIONTASKFALLBACKTODEFAULTTENANT": { + "TITLE": "Fallback to default tenant", + "DESCRIPTION": "Find decision definition without tenant when previous attemps to find it with tenant failed." + } + }, + "HTTPTASKREQUESTMETHODPACKAGE": { + "HTTPTASKREQUESTMETHOD": { + "TITLE": "Request method", + "DESCRIPTION": "Request method (For example - GET,POST,PUT etc)." + } + }, + "HTTPTASKREQUESTURLPACKAGE": { + "HTTPTASKREQUESTURL": { + "TITLE": "Request URL", + "DESCRIPTION": "Request URL (For example - http://flowable.org)" + } + }, + "HTTPTASKREQUESTHEADERSPACKAGE": { + "HTTPTASKREQUESTHEADERS": { + "TITLE": "Request headers", + "DESCRIPTION": "Line separated HTTP request headers (For example - Content-Type: application/json)." + } + }, + "HTTPTASKREQUESTBODYPACKAGE": { + "HTTPTASKREQUESTBODY": { + "TITLE": "Request body", + "DESCRIPTION": "Request body (For example- ${sampleBody})." + } + }, + "HTTPTASKREQUESTBODYENCODINGPACKAGE": { + "HTTPTASKREQUESTBODYENCODING": { + "TITLE": "Request body encoding", + "DESCRIPTION": "Request body encoding (For example- UTF-8)." + } + }, + "HTTPTASKREQUESTTIMEOUTPACKAGE": { + "HTTPTASKREQUESTTIMEOUT": { + "TITLE": "Request timeout", + "DESCRIPTION": "Timeout in milliseconds for the request (For example - 5000)." + } + }, + "HTTPTASKDISALLOWREDIRECTSPACKAGE": { + "HTTPTASKDISALLOWREDIRECTS": { + "TITLE": "Disallow redirects", + "DESCRIPTION": "Flag to disallow HTTP redirects." + } + }, + "HTTPTASKFAILSTATUSCODESPACKAGE": { + "HTTPTASKFAILSTATUSCODES": { + "TITLE": "Fail status codes", + "DESCRIPTION": "Comma separated list of HTTP response status codes to retry, for example 400,5XX." + } + }, + "HTTPTASKHANDLESTATUSCODESPACKAGE": { + "HTTPTASKHANDLESTATUSCODES": { + "TITLE": "Handle status codes", + "DESCRIPTION": "Comma separated list of HTTP response status codes to ignore, for example 404,3XX." + } + }, + "HTTPTASKIGNOREEXCEPTIONPACKAGE": { + "HTTPTASKIGNOREEXCEPTION": { + "TITLE": "Ignore exception", + "DESCRIPTION": "Flag to ignore exceptions." + } + }, + "HTTPTASKRESPONSEVARIABLENAMEPACKAGE": { + "HTTPTASKRESPONSEVARIABLENAME": { + "TITLE": "Response variable name", + "DESCRIPTION": "Define the variable name to store the http response." + } + }, + "HTTPTASKSAVEREQUESTVARIABLESPACKAGE": { + "HTTPTASKSAVEREQUESTVARIABLES": { + "TITLE": "Save request variables", + "DESCRIPTION": "Flag to save request variables." + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSPACKAGE": { + "HTTPTASKSAVERESPONSEPARAMETERS": { + "TITLE": "Save response status, headers", + "DESCRIPTION": "Flag to save response status, headers etc." + } + }, + "HTTPTASKRESULTVARIABLEPREFIXPACKAGE": { + "HTTPTASKRESULTVARIABLEPREFIX": { + "TITLE": "Result variable prefix", + "DESCRIPTION": "Prefix for the execution variable names." + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENTPACKAGE": { + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENT": { + "TITLE": "Save response as a transient variable", + "DESCRIPTION": "Flag indicating to store the response variable(s) transient" + } + }, + "HTTPTASKSAVERESPONSEASJSONPACKAGE": { + "HTTPTASKSAVERESPONSEASJSON": { + "TITLE": "Save response as JSON", + "DESCRIPTION": "Flag indicating to store the response variable as a JSON variable instead of a String" + } + }, + "CASETASKCASEREFERENCEPACKAGE": { + "CASETASKCASEREFERENCE": { + "TITLE": "Case reference", + "DESCRIPTION": "Set the case reference" + } + }, + "PROCESSTASKPROCESSREFERENCEPACKAGE": { + "PROCESSTASKPROCESSREFERENCE": { + "TITLE": "Process reference", + "DESCRIPTION": "Set the process reference" + } + }, + "FALLBACKTODEFAULTTENANTPACKAGE": { + "FALLBACKTODEFAULTTENANT": { + "TITLE": "Fallback to default tenant", + "DESCRIPTION": "Use default tenant as a fallback when definition is not found by key in the specified tenant" + } + }, + "PROCESSTASKINPARAMETERSPACKAGE": { + "PROCESSTASKINPARAMETERS": { + "TITLE": "In parameters", + "DESCRIPTION": "Definition of the input parameters" + } + }, + "PROCESSTASKOUTPARAMETERSPACKAGE": { + "PROCESSTASKOUTPARAMETERS": { + "TITLE": "Out parameters", + "DESCRIPTION": "Definition of the output parameters" + } + }, + "TIMEREXPRESSIONPACKAGE": { + "TIMEREXPRESSION": { + "TITLE": "Timer Expression", + "DESCRIPTION": "An ISO-8601 string or an expression that resolves to either an ISO-8601 string or a java.util.Date" + } + }, + "TIMERSTARTTRIGGERPACKAGE": { + "TIMERSTARTTRIGGERSOURCEREF": { + "TITLE": "Start trigger plan item", + "DESCRIPTION": "A reference to the plan item for which the configured standard event needs to happen to start the timer (optional)" + }, + "TRANSITIONEVENT": { + "TITLE": "Start trigger transition event", + "DESCRIPTION": "The type of the transition event. Only used when the start trigger plan item is set" + } + }, + "DECISIONTASKDECISIONREFERENCEPACKAGE": { + "DECISIONTASKDECISIONREFERENCE": { + "TITLE": "Decision reference", + "DESCRIPTION": "Set the decision reference" + } + }, + "IFPARTCONDITIONPACKAGE": { + "IFPARTCONDITION": { + "TITLE": "Condition", + "DESCRIPTION": "" + } + }, + "TRIGGERMODEPACKAGE": { + "TRIGGERMODE": { + "TITLE": "Trigger mode", + "DESCRIPTION": "Determines if the sentry conditions are evaluated with memory (default) of without (on-event). The default means that the parts (on- and ifparts) of a sentry being satisfied will be stored. Subsequent evaluations will use the stored parts when the sentry is re-evaluated. Using 'on-event', all parts are evaluated and if all are true the sentry is satisfied. If not, all results are discarded and not stored." + } + }, + "AUTOCOMPLETEPACKAGE": { + "AUTOCOMPLETEENABLED": { + "TITLE": "Auto complete", + "DESCRIPTION": "Flag indicating that the stage will automatically complete, once all required children are in an end state and no other children are active." + }, + "AUTOCOMPLETECONDITION": { + "TITLE": "Auto complete condition", + "DESCRIPTION": "An expression that is resolved to if the stage can automatically complere." + } + }, + "REQUIREDRULEPACKAGE": { + "REQUIREDENABLED": { + "TITLE": "Required", + "DESCRIPTION": "Flag indicating if the stage, task or milestone is required when determining the parent stage completion. By default false." + }, + "REQUIREDRULECONDITION": { + "TITLE": "Required Rule", + "DESCRIPTION": "An expression that is resolved to determine if the stage, task or milestone is required when determining the parent stage completion." + } + }, + "REPETITIONRULEPACKAGE": { + "REPETITIONENABLED": { + "TITLE": "Repetition", + "DESCRIPTION": "Flag indicating if repetition is enabled" + }, + "REPETITIONRULECONDITION": { + "TITLE": "Repetition Rule", + "DESCRIPTION": "An expression that is resolved to determine if new instances of the planitem need to be created" + }, + "REPETITIONCOUNTERVARIABLENAME": { + "TITLE": "Repetition counter variable", + "DESCRIPTION": "The name of the local variable which stores the instance counter of the repetition. Default value is 'repetitionCounter'." + } + }, + "MANUALACTIVATIONRULEPACKAGE": { + "MANUALACTIVATIONENABLED": { + "TITLE": "Manual activation", + "DESCRIPTION": "Flag indicating if the task or stage needs to be manually activated. False by default." + }, + "MANUALACTIVATIONRULECONDITION": { + "TITLE": "Manual activation Rule", + "DESCRIPTION": "An expression that is resolved to determine if the stage or task needs to be manually activated." + } + }, + "COMPLETIONNEUTRALRULEPACKAGE": { + "COMPLETIONNEUTRALENABLED": { + "TITLE": "Completion neutral", + "DESCRIPTION": "Flag indicating if the plan item is completion neutral. False by default." + }, + "COMPLETIONNEUTRALRULECONDITION": { + "TITLE": "Completion neutral Rule", + "DESCRIPTION": "An expression that is resolved to determine if the plan item is completion neutral." + } + }, + "PLANITEMLIFECYCLELISTENERSPACKAGE": { + "PLANITEMLIFECYCLELISTENERS": { + "TITLE": "Lifecycle listeners", + "DESCRIPTION": "Listeners for lifecycle events of a plan item" + } + }, + "DISPLAYORDERPACKAGE": { + "DISPLAYORDER": { + "TITLE": "Display order", + "DESCRIPTION": "A number value indicating the order compared to other stages when getting or showing a stage overview." + } + }, + "INCLUDEINSTAGEOVERVIEWPACKAGE": { + "INCLUDEINSTAGEOVERVIEW": { + "TITLE": "Include in overview", + "DESCRIPTION": "Indicates if this stage should be considered for the stage overview" + } + }, + "SCRIPTFORMATPACKAGE": { + "SCRIPTFORMAT": { + "TITLE": "Script format", + "DESCRIPTION": "Script format of the script task (JavaScript, groovy, etc)." + } + }, + "SCRIPTTEXTPACKAGE": { + "SCRIPTTEXT": { + "TITLE": "Script", + "DESCRIPTION": "Script text of the script task." + } + }, + "TRANSITIONEVENTPACKAGE": { + "TRANSITIONEVENT": { + "TITLE": "Transition event type", + "DESCRIPTION": "The type of the transition event" + } + }, + "AVAILABLECONDITIONPACKAGE": { + "AVAILABLECONDITION": { + "TITLE": "Available condition", + "DESCRIPTION": "An optional condition expression on an event listener to indicate to determine when it becomes available." + } + } + }, + "STENCILS" : { + "GROUPS" : { + "DIAGRAM" : "Diagram", + "CONTAINERS" : "Containers", + "ACTIVITIES" : "Activities", + "EVENTLISTENERS" : "Event Listeners", + "SENTRIES" : "Sentries", + "CONNECTORS" : "Connectors" + }, + "CMMNDIAGRAM" : { + "TITLE" : "CMMN-Diagram", + "DESCRIPTION" : "A CMMN 2.0 diagram." + }, + "CASEPLANMODEL" : { + "TITLE" : "Case plan model", + "DESCRIPTION" : "A case plan model" + }, + "STAGE" : { + "TITLE" : "Stage", + "DESCRIPTION" : "A stage" + }, + "TASK" : { + "TITLE" : "Task", + "DESCRIPTION" : "A manual task" + }, + "HUMANTASK" : { + "TITLE" : "Human task", + "DESCRIPTION" : "A manual task assigned to a specific person" + }, + "SERVICETASK" : { + "TITLE" : "Service task", + "DESCRIPTION" : "An automatic task with service logic" + }, + "DECISIONTASK" : { + "TITLE" : "Decision task", + "DESCRIPTION" : "Task to invoke a DMN decision" + }, + "HTTPTASK" : { + "TITLE" : "Http task", + "DESCRIPTION" : "A HTTP task" + }, + "SCRIPTTASK" : { + "TITLE" : "Script task", + "DESCRIPTION" : "An automatic task with script logic" + }, + "MILESTONE" : { + "TITLE" : "Milestone", + "DESCRIPTION" : "A milestone" + }, + "CASETASK" : { + "TITLE" : "Case task", + "DESCRIPTION" : "A reference to a case definition to start a new instance" + }, + "PROCESSTASK" : { + "TITLE" : "Process task", + "DESCRIPTION" : "A reference to a process definition to start a new instance" + }, + "EVENTLISTENER" : { + "TITLE" : "Event listener", + "DESCRIPTION" : "A generic eventlistener" + }, + "TIMEREVENTLISTENER" : { + "TITLE" : "Timer event listener", + "DESCRIPTION" : "An eventlistener with a timer trigger" + }, + "USEREVENTLISTENER" : { + "TITLE" : "User event listener", + "DESCRIPTION" : "An listener for user events" + }, + "ENTRYCRITERION" : { + "TITLE" : "Entry criterion", + "DESCRIPTION" : "A sentry that defines an entry criterion" + }, + "EXITCRITERION" : { + "TITLE" : "Exit criterion", + "DESCRIPTION" : "A sentry that defines an exit criterion" + }, + "ASSOCIATION" : { + "TITLE" : "Association", + "DESCRIPTION" : "Associates a sentry with a plan item." + } + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "You have unsaved changes", + "DESCRIPTION": "What do you want to do with your unsaved changes?", + "ACTION": { + "SAVE": "Save changes", + "DISCARD": "Discard changes", + "CONTINUE": "Continue editing" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "Business Process Models", + "SEARCH-PLACEHOLDER": "Search", + "ACTION" : { + "CREATE": "Create Process", + "IMPORT": "Import Process" + }, + + "FILTER" : { + "PROCESSES": "Process models", + "PROCESSES-COUNT": "There are {{total}} process models", + "PROCESSES-ONE": "There is one process model", + "PROCESSES-EMPTY": "There is no process model created yet. You can design process models, user forms and then bundle them up into a process app. The first step is to create a process model:", + "PROCESSES-BPMN-HINT": "Create a BPMN model using the BPMN Visual Editor.", + "PROCESSES-BPMN-IMPORT-HINT": "You can also import existing BPMN models.", + "FILTER-TEXT": ", matching \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "There are no process models matching \"{{filterText}}\"", + "RECENT": "Recent", + "RECENT-COUNT": "{{total}} recently used models", + "RECENT-ONE": "One recently used models", + "RECENT-EMPTY": "No recently used models" + }, + + "SORT": { + "MODIFIED-ASC": "Oldest", + "MODIFIED-DESC": "Last modified", + "NAME-ASC": "Name, A-Z", + "NAME-DESC": "Name, Z-A" + } + }, + + "CASE-LIST" : { + "TITLE" : "Case Models", + "SEARCH-PLACEHOLDER": "Search", + "ACTION" : { + "CREATE": "Create Case", + "IMPORT": "Import Case" + }, + + "FILTER" : { + "CASES": "Case models", + "CASES-COUNT": "There are {{total}} case models", + "CASES-ONE": "There is one case model", + "CASES-EMPTY": "There is no case model created yet. You can design case models, user forms and then bundle them up into an app definition. The first step is to create a case model:", + "CASES-CMMN-HINT": "Create a CMMN model using the CMMN Visual Editor.", + "CASES-CMMN-IMPORT-HINT": "You can also import existing CMMN models.", + "FILTER-TEXT": ", matching \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "There are no case models matching \"{{filterText}}\"", + "RECENT": "Recent", + "RECENT-COUNT": "{{total}} recently used models", + "RECENT-ONE": "One recently used models", + "RECENT-EMPTY": "No recently used models" + }, + + "SORT": { + "MODIFIED-ASC": "Oldest", + "MODIFIED-DESC": "Last modified", + "NAME-ASC": "Name, A-Z", + "NAME-DESC": "Name, Z-A" + } + }, + + "FORMS-LIST" : { + "TITLE" : "Forms", + "SEARCH-PLACEHOLDER": "Search", + "ACTION" : { + "CREATE": "Create Form", + "CREATE-INLINE": "Create a new form now!", + "SHOW-MORE": "Show more..." + }, + + "FILTER" : { + "FORMS": "Forms", + "FORMS-COUNT": "There are {{total}} forms", + "FORMS-ONE": "There is one form", + "FORMS-EMPTY": "There are no forms. To add one, click Create Form.", + "FILTER-TEXT": ", matching \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "There is no form matching \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Oldest", + "MODIFIED-DESC": "Last modified", + "NAME-ASC": "Name, A-Z", + "NAME-DESC": "Name, Z-A" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "Decision Tables", + "SEARCH-PLACEHOLDER": "Search", + "ACTION": { + "CREATE": "Create Decision Table", + "IMPORT": "Import Decision Table", + "CREATE-INLINE": "Create a new decision table now!", + "SHOW-MORE": "Show more..." + }, + + "FILTER": { + "DECISION-TABLES": "Decision tables", + "DECISION-TABLES-COUNT": "There are {{total}} decision tables", + "DECISION-TABLES-ONE": "There is one decision table", + "DECISION-TABLES-EMPTY": "There are no decision tables. To add one, click Create Decision Table.", + "FILTER-TEXT": ", matching \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "There are no decision table matching \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Oldest", + "MODIFIED-DESC": "Last modified", + "NAME-ASC": "Name, A-Z", + "NAME-DESC": "Name, Z-A" + } + }, + + "APPS-LIST" : { + "TITLE" : "App definitions", + "SEARCH-PLACEHOLDER": "Search", + "ACTION" : { + "CREATE": "Create App", + "IMPORT": "Import App", + "SHOW-MORE": "Show more..." + }, + + "FILTER" : { + "APPS": "App definitions", + "APPS-COUNT": "There are {{total}} app definitions", + "APPS-ONE": "There is one app definition", + "APPS-EMPTY": "There are no app definitions. To add one, click Create App Definition.", + "FILTER-TEXT": ", matching \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "There are no app definitions matching \"{{filterText}}\"", + + "NO-APPS": "You can create an App definition by publishing a bundle of Process Models.", + "NO-APPS-CALL-TO-ACTION": "You can create an App definition now.", + "NO-APPS-NOTE": "Remember to Publish it when you are ready to use it." + }, + + "SORT": { + "MODIFIED-ASC": "Oldest", + "MODIFIED-DESC": "Last modified", + "NAME-ASC": "Name, A-Z", + "NAME-DESC": "Name, Z-A" + } + }, + "PROCESS": { + "NAME": "Model name", + "KEY": "Model key", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Version comment", + "ACTION": { + "DETAILS": "Show details", + "EDIT": "Modify model properties", + "DUPLICATE": "Duplicate this model", + "EXPORT_BPMN20": "Export to BPMN 2.0", + "DELETE": "Delete this model", + "CREATE-CONFIRM": "Create new model", + "DUPLICATE-CONFIRM": "Duplicate the model", + "OPEN-IN-EDITOR": "Visual Editor", + "EDIT-CONFIRM": "Save", + "DELETE-CONFIRM": "Delete process model", + "USE-AS-NEW-VERSION": "Use as new version", + "FAVORITE": "Favorite this model" + + }, + "DETAILS": { + "HISTORY-TITLE": "History", + "LAST-UPDATED-BY": "Last updated by {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}", + "NO-DESCRIPTION": "This model has no description. Modify the model properties to add one" + }, + + "POPUP": { + "CREATE-TITLE": "Create a new business process model", + "DUPLICATE-TITLE": "Duplicate the business process model", + "CREATE-DESCRIPTION": "You need to give a name for the new model and you may want to add a description at the same time.", + "DUPLICATE-DESCRIPTION": "You can change the name for the new model and you may want to change the description at the same time.", + "EDIT-DESCRIPTION": "Change any of the model properties below and then press Save to update the model.", + "DELETE-DESCRIPTION": "Are you sure you want to delete the process model \"{{name}}\"?", + "EDIT-TITLE":"Edit model details", + "DELETE-TITLE": "Delete model", + "DELETE-LOADING-RELATIONS": "Checking model usage...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "This model cannot be deleted, because another model is using it:", + "DELETE-RELATIONS-DESCRIPTION": "This model cannot be deleted, because it is used by other models:", + "DELETE-PROCESS-RELATION": "Process model", + "DELETE-FORM-RELATION": "Form model", + "DELETE-APP-RELATION": "App model", + "IMPORT-DESCRIPTION": "Please browse for or drop a BPMN XML definition with an .bpmn or .bpmn20.xml extension", + "IMPORT-TITLE": "Import a process model", + "USE-AS-NEW-TITLE": "Use as new version", + "USE-AS-NEW-DESCRIPTION": "Are you sure you want to use version {{version}} to create a new version of \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Could not fully restore the app model to the chosen version: some referenced models are missing due to being deleted in the past. Please update the app model accordingly. Missing models:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Model '{{name}}' with internal id {{id}}, created by {{createdBy}}", + "SHARED-WITH": "Shared with", + "PERMISSION": "Permission", + "ACTIONS": "Actions", + "IMPORT": { + "DROPZONE": "Drop a .bpmn or .bpmn20.xml BPMN XML file", + "CANCEL-UPLOAD": "Cancel the upload", + "ERROR": "Error while processing the BPMN XML file", + "NO-DROP": "Drag and drop not supported" + } + }, + "ALERT": { + "EDIT-CONFIRM": "Model updated" + }, + "ERROR": { + "NOT-FOUND": "The requested model does not exist" + } + }, + + "SUBPROCESS": { + "NAME": "Sub process name", + "DESCRIPTION": "Description", + "ACTION": { + "CREATE-CONFIRM": "Create new sub process" + }, + "POPUP": { + "CREATE-TITLE": "Create a new sub process", + "CREATE-DESCRIPTION": "You need to give a name for the new sub process and you may want to add a description at the same time." + } + }, + + "CASE": { + "NAME": "Model name", + "KEY": "Model key", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Version comment", + "ACTION": { + "DETAILS": "Show details", + "EDIT": "Modify model properties", + "DUPLICATE": "Duplicate this model", + "EXPORT_CMMN": "Export to CMMN 1.1", + "DELETE": "Delete this model", + "CREATE-CONFIRM": "Create new model", + "DUPLICATE-CONFIRM": "Duplicate the model", + "OPEN-IN-EDITOR": "Visual Editor", + "EDIT-CONFIRM": "Save", + "DELETE-CONFIRM": "Delete case model", + "USE-AS-NEW-VERSION": "Use as new version", + "FAVORITE": "Favorite this model" + }, + "DETAILS": { + "HISTORY-TITLE": "History", + "LAST-UPDATED-BY": "Last updated by {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}", + "NO-DESCRIPTION": "This model has no description. Modify the model properties to add one" + }, + + "POPUP": { + "CREATE-TITLE": "Create a new case model", + "DUPLICATE-TITLE": "Duplicate the case model", + "CREATE-DESCRIPTION": "You need to give a name for the new model and you may want to add a description at the same time.", + "DUPLICATE-DESCRIPTION": "You can change the name for the new model and you may want to change the description at the same time.", + "EDIT-DESCRIPTION": "Change any of the model properties below and then press Save to update the model.", + "DELETE-DESCRIPTION": "Are you sure you want to delete the process model \"{{name}}\"?", + "EDIT-TITLE":"Edit model details", + "DELETE-TITLE": "Delete model", + "DELETE-LOADING-RELATIONS": "Checking model usage...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "This model cannot be deleted, because another model is using it:", + "DELETE-RELATIONS-DESCRIPTION": "This model cannot be deleted, because it is used by other models:", + "DELETE-PROCESS-RELATION": "Case model", + "DELETE-FORM-RELATION": "Form model", + "DELETE-APP-RELATION": "App model", + "IMPORT-DESCRIPTION": "Please browse for or drop a CMMN XML definition with an .cmmn or .cmmn.xml extension", + "IMPORT-TITLE": "Import a case model", + "USE-AS-NEW-TITLE": "Use as new version", + "USE-AS-NEW-DESCRIPTION": "Are you sure you want to use version {{version}} to create a new version of \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Could not fully restore the app model to the chosen version: some referenced models are missing due to being deleted in the past. Please update the app model accordingly. Missing models:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Model '{{name}}' with internal id {{id}}, created by {{createdBy}}", + "SHARED-WITH": "Shared with", + "PERMISSION": "Permission", + "ACTIONS": "Actions", + "IMPORT": { + "DROPZONE": "Drop a .cmmn or .cmmn.xml CMMN XML file", + "CANCEL-UPLOAD": "Cancel the upload", + "ERROR": "Error while processing the CMMN XML file", + "NO-DROP": "Drag and drop not supported" + } + }, + "ALERT": { + "EDIT-CONFIRM": "Model updated" + }, + "ERROR": { + "NOT-FOUND": "The requested model does not exist" + } + }, + + "FORM": { + "NAME": "Form name", + "KEY": "Form key", + "DESCRIPTION": "Description", + "ACTION": { + "DETAILS": "Show details", + "EDIT": "Modify model properties", + "DELETE": "Delete this form", + "CREATE-CONFIRM": "Create new form", + "DUPLICATE": "Duplicate this form", + "DUPLICATE-CONFIRM": "Duplicate the form", + "OPEN-IN-EDITOR": "Form Editor", + "EDIT-CONFIRM": "Save", + "DELETE-CONFIRM": "Delete form", + "USE-AS-NEW-VERSION": "Use as new version" + + }, + "DETAILS": { + "HISTORY-TITLE": "History", + "LAST-UPDATED-BY": "Last updated by {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}" + }, + + "POPUP": { + "CREATE-TITLE": "Create a new form", + "DUPLICATE-TITLE": "Duplicate form", + "CREATE-DESCRIPTION": "You need to give a name for the new form and you may want to add a description at the same time.", + "DUPLICATE-DESCRIPTION": "You need to give a name for the new form and you may want to add a description at the same time.", + "SAVE-FORM-TITLE": "Save form", + "EDIT-DESCRIPTION": "Change any of the form properties below and then press Save to update the form.", + "DELETE-DESCRIPTION": "Are you sure you want to delete the form \"{{name}}\"?", + "EDIT-TITLE":"Edit form details", + "DELETE-TITLE": "Delete form", + "USE-AS-NEW-TITLE": "Use as new version", + "USE-AS-NEW-VERSION": "Use as new version", + "USE-AS-NEW-DESCRIPTION": "Are you sure you want to use version {{version}} to create a new version of \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Could not fully restore the app model to the chosen version: some referenced models are missing due to being deleted in the past. Please update the app model accordingly. Missing models:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Model '{{name}}' with internal id {{id}}, created by {{createdBy}}" + } + }, + + "DECISION-TABLE": { + "NAME": "Decision Table name", + "KEY": "Decision Table key", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Version comment", + "HIT-POLICY": "Hit Policy:", + "ACTION": { + "DETAILS": "Show details", + "EDIT": "Modify model properties", + "SHARE": "Share this decision table", + "DELETE": "Delete this decision table", + "ADD-COMMENT": "+ Add comment", + "CREATE-CONFIRM": "Create new decision table", + "OPEN-IN-EDITOR": "Decision Table Editor", + "EXPORT": "Export decision table", + "DELETE-CONFIRM": "Delete decision table", + "USE-AS-NEW-VERSION": "Use as new version", + "FAVORITE": "Favorite this decision table", + "DUPLICATE": "Duplicate this decision table" + }, + "DETAILS": { + "HISTORY-TITLE": "History", + "COMMENTS-TITLE": "Comments", + "LAST-UPDATED-BY": "Last updated by {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}" + }, + "HIT-POLICIES": { + "FIRST": "First", + "ANY": "Any", + "UNIQUE": "Unique", + "PRIORITY": "Priority", + "RULE ORDER": "Rule Order", + "OUTPUT ORDER": "Output Order", + "COLLECT": "Collect" + }, + "COLLECT-OPERATORS": { + "SUM": "Sum", + "MIN": "Min", + "MAX": "Max", + "COUNT": "Count" + }, + "POPUP": { + "CREATE-TITLE": "Create a new decision table", + "CREATE-DESCRIPTION": "You need to give a name for the new decision table and you may want to add a description at the same time.", + "SAVE-DESCRIPTION": "You need to give a name and a unique key for the new decision table and you may want to add a description at the same time.", + "DUPLICATE-TITLE": "Duplicate decision table", + "DUPLICATE-DESCRIPTION": "You need to give a name for the new decision table and you may want to add a description at the same time.", + "DELETE-TITLE": "Delete decision table", + "DELETE-DESCRIPTION": "Are you sure you want to delete the decision table \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "Save decision table", + "IMPORT-DESCRIPTION": "Please browse for or drop a DMN XML definition with an .dmn or .dmn.xml extension", + "IMPORT-TITLE": "Import a DMN model", + "IMPORT": { + "DROPZONE": "Drop a .dmn or .dmn.xml DMN XML file", + "CANCEL-UPLOAD": "Cancel the upload", + "ERROR": "Error while processing the DMN XML file", + "NO-DROP": "Drag and drop not supported" + }, + "USE-AS-NEW-TITLE": "Use as new version", + "USE-AS-NEW-VERSION": "Use as new version", + "USE-AS-NEW-DESCRIPTION": "Are you sure you want to use version {{version}} to create a new version of \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Could not fully restore the app model to the chosen version: some referenced models are missing due to being deleted in the past. Please update the app model accordingly. Missing models:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Model '{{name}}' with internal id {{id}}, created by {{createdBy}}" + }, + "ALERT": { + "FAVORITE-CONFIRM": "This decision table is now favorited", + "UN-FAVORITE-CONFIRM": "This decision table is no longer favorited" + } + }, + + "APP": { + "NAME": "App definition name", + "KEY": "App definition key", + "DESCRIPTION": "Description", + "ICON": "Icon", + "THEME": "Theme", + "GROUPS-ACCESS": "Groups access, separated by commas", + "USERS-ACCESS": "Users access, separated by commas", + "ACTION": { + "DETAILS": "Show details", + "EDIT": "Modify app definition properties", + "DUPLICATE": "Duplicate this application", + "SHARE": "Share this app definition", + "DELETE": "Delete this app definition", + "CREATE-CONFIRM": "Create new app definition", + "DUPLICATE-CONFIRM": "Duplicate the app definition", + "DELETE-CONFIRM": "Delete app definition", + "USE-AS-NEW-VERSION": "Use as new version", + "OPEN-IN-EDITOR": "App Editor", + "PUBLISH": "Publish", + "PUBLISH-CONFIRM": "Publish app definition", + "SELECT-ICON": "Change icon...", + "SELECT-THEME": "Change theme...", + "EDIT-MODELS": "Edit included models", + "EXPORT-ZIP": "Export app definition as a zip file", + "EXPORT-BAR": "Export app definition as a deployable bar file" + + }, + "DETAILS": { + "TITLE": "App definition details: {{name}}", + "HISTORY-TITLE": "History", + "MODELS-TITLE": "Models included in the app definition", + "LAST-UPDATED-BY": "Last updated by {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}", + "NO-DESCRIPTION": "This app definition has no description. Modify the app definition properties to add one", + "NO-MODELS-SELECTED": "No models are selected for this app" + }, + "TITLE": { + "SELECT-ICON": "Select app icon", + "SELECT-THEME": "Select app colors", + "PREVIEW": "Preview" + + }, + "POPUP": { + "CREATE-TITLE": "Create a new app definition", + "DUPLICATE-TITLE": "Duplicate an app definition", + "SAVE-APP-TITLE": "Save app definition", + "SAVE-APP-SAVE-SUCCESS": "Saved app definition", + "CREATE-DESCRIPTION": "You need to give a name for the new app definition and you may want to add a description at the same time.", + "DUPLICATE-DESCRIPTION": "You can give a name for the new app definition and you may want to change the description at the same time.", + "PUBLISH-TITLE": "Publish app definition", + "PUBLISH-DESCRIPTION": "Are you sure you want to publish the app definition \"{{name}}\"? Note that this app definition will be versioned and the workflow app will be updated if existing already.", + "PUBLISH-FIELD": "Publish? Note that if publish is enabled, this app definition will be versioned and the workflow app will be updated if existing already.", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "Your process model \"{{modelInAppName}}\" has the same identifier \"{{processDefinitionKey}}\" as the existing deployed process \"{{conflictingModelName}}\" of the app \"{{conflictingAppName}}\". Please change this \"id\" property of the process model to something different.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "Following process models are already used in another app. Is this ok?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "App", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "Invalid app: duplicate process identifiers found (change the \"id\" property of the offending process models):", + "DELETE-TITLE": "Delete app definition", + "DELETE-DESCRIPTION": "Are you sure you want to delete the app definition \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "Are you sure you want to delete the app definition \"{{name}}\"? Note that this app definition has been deployed to the task landing page and by confirming, the app will be removed from the task app landing page.", + "DELETE-CASCADE-FALSE": "Only delete the current version of this app definition (v{{version}})", + "DELETE-CASCADE-TRUE": "Also delete all previous versions of this app definition", + "HAS-CUSTOM-STENCILITEM" : "Model \"{{modelName}}\" uses a stencil with custom stencil items. It is not possible to use this model in an app definition.", + "HAS-VALIDATIONERROR" : "Model \"{{modelName}}\" has validation errors and cannot be added to an app definition. Open the model in the editor to see more details about the validation error(s).", + "IMPORT-DESCRIPTION":"Please browse for or drop a app definition with a .zip extension", + "IMPORT-TITLE":"Import an app definition model", + "IMPORT": { + "DROPZONE": "Drop a .zip app definition file", + "CANCEL-UPLOAD": "Cancel the upload", + "RENEWIDM-IDS": "Renew the user and group identifiers when importing step and BPMN models. This is often required when importing the app definition into a different Flowable environment. It will try to link the human steps and user tasks to the right user and group in this target environment.", + "ERROR": "Error while processing the app definition file", + "NO-DROP": "Drag and drop not supported" + }, + "INCLUDE-MODELS-TITLE": "Models included in the app definition" + }, + "ALERT": { + "DELETE-CONFIRM": "App definition deleted", + "PUBLISH-CONFIRM": "The app definition has been published", + "PUBLISH-ERROR": "Could not publish app definition. Please check the validity of the referenced process models" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "Add another person" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "Text", + "MULTILINE-TEXT": "Multiline text", + "PASSWORD": "Password", + "NUMBER": "Number", + "CHECKBOX": "Checkbox", + "DATE": "Date", + "DROPDOWN": "Dropdown", + "RADIO": "Radio buttons", + "PEOPLE": "People", + "GROUP-OF-PEOPLE": "Group of people", + "UPLOAD": "Upload", + "EXPRESSION": "Expression", + "DECIMAL": "Decimal", + "HYPERLINK": "Hyperlink", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS": { + "GENERAL": "General", + "OPTIONS": "Options", + "UPLOAD-OPTIONS": "Upload options", + "ADVANCED-OPTIONS":"Advanced" + }, + "VERSION": "Version {{version}}", + "LAST-UPDATED": "Last updated by {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "Design", + "OUTCOME": "Outcomes" + }, + "POPUP": { + "EDIT-TITLE": "Edit field '{{name}}'", + "EXPRESSION-TITLE": "Edit expression" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(No expression value)", + "EXPRESSION-HELP": "You can also display values previously submitted in any form, as part of the text, by referencing them using a notation as follows ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "You can use an expression to dynamically populate options for example by referencing a variable like this ${optionsVariable}. The expression needs to result in either a java object (java.util.List with Option objects) or its json representation." + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "Select group..", + "PERSON": "Select person.." + }, + "COMPONENT": { + "LABEL": "Label:", + "OVERRIDEID": "Override id?", + "ID": "Id:", + "PLACEHOLDER": "Placeholder:", + "OPTIONS": "Options", + "RADIO-BUTTON-DEFAULT": "Option 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "Please choose one...", + "DROPDOWN-EMPTY-VALUE-HELP": "This is the 'empty value' option. Selecting this at runtime is the taken to mean 'no value' or 'empty'. This is allowed for optional fields, but not allowed for required fields.", + "OPTIONS-EXPRESSION": "Options expression:", + "OPTIONS-EXPRESSION-ENABLED": "Enable options expression", + "REQUIRED": "Required", + "READONLY": "Read-only", + "EXPRESSION": "Expression", + "ADD-OPTION": "+ Add a new option", + "UPLOAD-ALLOW-MULTIPLE": "Allow uploading multiple files", + "SIZE": "Size", + "MAX-LENGTH":"Maximum length:", + "MIN-LENGTH":"Minimum length:", + "PASSWORD-UNMASK-OPTION": "password masking/unmasking option", + "HYPERLINK-URL": "Hyperlink URL", + "REGEX-PATTERN":"Regex standard", + "MASK":{ + "TITLE":"Input mask", + "EXAMPLES":{ + "TITLE":"Examples:", + "NUMBER":"Any number", + "LETTER":"Any letter", + "NUMBERORLETTER":"Any letter or number", + "OPTIONAL":"Make mask optional (not valid)", + "PHONE":"Phone" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "You can define multiple outcomes for this task. When completing a task, the users selects one of the available outcomes, which can be used in eg. a condition further on in the process.", + "NO-OUTCOMES-OPTION": "Don't use custom outcomes, only show a 'Complete' button.", + "OUTCOMES-OPTION": "Use custom outcomes for this form.", + "POSSIBLE-OUTCOMES": "Possible outcomes", + "NEW-OUTCOME-PLACEHOLDER": "Enter new outcome", + "ADD": "Add outcome", + "REMOVE": "Remove" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "Undefined" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "Edit input column", + "INPUT-DESCRIPTION": "Select input variable as input for the column", + "OUTPUT-TITLE": "Edit output column", + "OUTPUT-DESCRIPTION": "Select an existing output variable or create a new one", + "EXPRESSION-LABEL": "Column label:", + "EXPRESSION-PLACEHOLDER": "Enter an optional label", + "EXPRESSION-VARIABLE-NAME": "Variable name:", + "EXPRESSION-VARIABLE-TYPE": "Variable type:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "Enter a variable name", + "OUTPUT-NEW-VARIABLE-ID": "Variable ID:", + "OUTPUT-NEW-VARIABLE-TYPE": "Variable type:", + "COMPLEX-EXPRESSION-LABEL": "Complex expression:", + "ALLOWED-VALUES": "Allowed values (optional):", + "OUTPUT-VALUES": "Output values ", + "OUTPUT-VALUES-OPTIONAL": "(optional):", + "OUTPUT-VALUES-NOT-OPTIONAL": "(drag rows for priority / output order):" + } + }, + "BUTTON-ACTIONS-LABEL": "Actions", + "BUTTON-ADD-INPUT-LABEL": "Add input", + "BUTTON-ADD-OUTPUT-LABEL": "Add output", + "BUTTON-ADD-RULE-LABEL": "Add rule", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "Move up", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "Move down", + "BUTTON-REMOVE-RULE-LABEL": "Remove rule", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "All input and output expressions must reference a form field or variable.", + "SAVE-CONFIRM": "Saved decision table '{{name}}'" + } + }, + + "TOUR": { + "WELCOME-TITLE": "Welcome, {{userName}}", + "WELCOME-CONTENT": "This a short tour of the Flowable editor. The next few steps will guide you through the different sections of the application to get you started. Press the ESC key to stop at any time." , + "PALETTE-TITLE": "The Palette", + "PALETTE-CONTENT": "All the available constructs to create a business process can be found here. They are arranged in logical groups. To open a group simply click on it:", + "CANVAS-TITLE": "The Canvas", + "CANVAS-CONTENT": "This is the work space on which you create your business process. Drag elements from the palette on the left and drop them on this canvas to start modeling.", + "DRAGDROP-TITLE": "Drag and Drop Example", + "DRAGDROP-CONTENT": "Here is an example how you get started with modeling:", + "PROPERTIES-TITLE": "Properties", + "PROPERTIES-CONTENT": "Here you can configure the properties of a business process construct. Simply select the item on the canvas and its properties will be shown. Click on the property if you want to edit it", + "TOOLBAR-TITLE": "The Toolbar", + "TOOLBAR-CONTENT": "All the actions can be found here: saving or validating a model, copy and pasting parts of a process, and so on. Hover over the buttons to get a description for an action.", + "END-TITLE": "The End", + "END-CONTENT": "That's it! You can now start modeling your processes. If you have any questions, feel free to ask them on the Flowable Forum " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Bend point tutorial", + "DESCRIPTION" : "When you are connecting process steps with each other using sequence flow (those arrows between process steps), you might find that these sequence flow cross each other or you would like to arrange them differently. To do this, you can add or remove a bend point to or from a sequence flow.

As shown below in the picture, you first click the 'add bendpoint' and then click on a sequence flow to add it. Note that the sequence flow will show you a subtle indication in green to show the bendpoint can be added there.

Removing a bendpoint again follows a similar pattern: click the 'remove bendpoint' button and click on the bend point to remove it again." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Save", + "ACTION.SAVE-AND-CLOSE" : "Save and close editor", + "ACTION.SEND" : "Send", + "ACTION.CANCEL" : "Cancel", + "ACTION.SELECT" : "Select", + "ACTION.ADD" : "Add", + "ACTION.REMOVE" : "Remove", + "ACTION.MOVE.UP" : "Move entry up", + "ACTION.MOVE.DOWN" : "Move entry down", + + "TOOLBAR.ACTION.CLOSE" : "Close the editor and go back to the overview page", + "TOOLBAR.ACTION.SAVE" : "Save the model", + "TOOLBAR.ACTION.VALIDATE" : "Validate the model", + "TOOLBAR.ACTION.CUT" : "Cut (select one or more elements in your business process)", + "TOOLBAR.ACTION.COPY" : "Copy (select one or more elements in your business process)", + "TOOLBAR.ACTION.PASTE" : "Paste", + "TOOLBAR.ACTION.DELETE" : "Delete the selected element", + "TOOLBAR.ACTION.UNDO" : "Undo", + "TOOLBAR.ACTION.REDO" : "Redo", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom in", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom out", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom to actual size", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom to fit", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Add bend-point to the selected sequence flow", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Remove bend-point from the selected sequence flow", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Align model horizontal", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Align model vertical", + "TOOLBAR.ACTION.SAMESIZE" : "Same size", + "TOOLBAR.ACTION.HELP": "Start the guided tour", + "TOOLBAR.ACTION.FEEDBACK": "Provide feedback", + + "FORM_TOOLBAR.ACTION.SAVE" : "Save the model", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Save the app definition", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Delete the element from the model", + "BUTTON.ACTION.MORPH.TOOLTIP": "Change the element type", + + "ELEMENT.AUTHOR" : "Author", + "ELEMENT.DATE_CREATED" : "Date created", + + "PROPERTY.REMOVED" : "removed", + "PROPERTY.EMPTY" : "No value", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Change value for ", + + "PROPERTY.FEEDBACK.TITLE" : "Please fill-in your feedback", + + "PROPERTY.ASSIGNMENT.TITLE" : "Assignment", + "PROPERTY.ASSIGNMENT.TYPE" : "Type", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Identity store", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Fixed values", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Assignee", + "PROPERTY.ASSIGNMENT.MATCHING" : "Use ↑ and ↓ to select and press Enter to confirm or use the mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Enter an assignee", + "PROPERTY.ASSIGNMENT.EMPTY" : "No assignment selected", + "PROPERTY.ASSIGNMENT.NONE" : "None ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Search user", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Search group", + "PROPERTY.ASSIGNMENT.SEARCH": "Search: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Assignee {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} Candidate users", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Candidate users", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} Candidate groups", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Candidate groups", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "User {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "User {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Field {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Process initiator", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Assignment", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "No candidate users selected...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "No candidate groups selected...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Assigned to process initiator", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Assigned to single user", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Candidate users", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Candidate groups", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Allow process initiator to complete task", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} execution listeners", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No execution listeners configured", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Event", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Class", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "No execution listener selected", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.FIELDS" : "{{length}} fields", + "PROPERTY.FIELDS.EMPTY" : "No fields selected", + "PROPERTY.FIELDS.NAME" : "Name", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.FIELDS.STRING" : "String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implementation", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "No data objects configured", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "Enter an id", + "PROPERTY.DATAPROPERTIES.NAME" : "Name", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.DATAPROPERTIES.TYPE" : "Type", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "Enter a value (optional)", + "PROPERTY.DATAPROPERTIES.VALUE" : "Default Value", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} form properties", + "PROPERTY.FORMPROPERTIES.EMPTY" : "No form properties selected", + "PROPERTY.FORMPROPERTIES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Enter an id", + "PROPERTY.FORMPROPERTIES.NAME" : "Name", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.FORMPROPERTIES.TYPE" : "Type", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Date pattern", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Enter date pattern", + "PROPERTY.FORMPROPERTIES.VALUES" : "Values", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "No enum value selected", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Name", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Enter id of a value", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Enter name of a value", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expression", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Enter a variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Enter a default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Required", + "PROPERTY.FORMPROPERTIES.READABLE" : "Readable", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Writable", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} in-parameters", + "PROPERTY.INPARAMETERS.EMPTY" : "No in-parameters configured", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} out-parameters", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No out-parameters configured", + + "PROPERTY.PARAMETER.SOURCE" : "Source", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Enter a source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Source expression", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Enter a source expression", + "PROPERTY.PARAMETER.TARGET" : "Target", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Enter a target", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "Target expression", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "Enter a target expression", + "PROPERTY.PARAMETER.EMPTY" : "No parameter selected", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.PROCESSREFERENCE.TITLE" : "Process reference", + "PROPERTY.PROCESSREFERENCE.ERROR.PROCESS" : "There was an error loading the processes. Try again later", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "Loading processes...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "This folder contains no processes", + + "PROPERTY.FORMREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.FORMREFERENCE.TITLE" : "Form reference", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Reference to a form", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "There was an error loading the forms. Try again later", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Loading forms...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "This folder contains no forms", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} task listeners", + "PROPERTY.TASKLISTENERS.EMPTY" : "No task listeners configured", + "PROPERTY.TASKLISTENERS.EVENT" : "Event", + "PROPERTY.TASKLISTENERS.CLASS" : "Class", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} event listeners", + "PROPERTY.EVENTLISTENERS.EMPTY" : "No event listeners configured", + "PROPERTY.EVENTLISTENERS.EVENTS": "Events", + "PROPERTY.EVENTLISTENERS.RETHROW": "Rethrow event?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Class", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Entity type", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Enter an entity type", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Rethrow event type", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Error code", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Enter an error code", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Message name", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Enter a message name", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Signal name", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Enter a signal name", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "No event listener selected", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} signal definitions", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "No signal definitions configured", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Process Instance", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Id", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Name", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Scope", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} message definitions", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "No message definitions configured", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Name", + + "PROPERTY.ESCALATIONDEFINITIONS.DISPLAY" : "{{length}} escalation definitions", + "PROPERTY.ESCALATIONDEFINITIONS.EMPTY" : "No escalation definitions configured", + "PROPERTY.ESCALATIONDEFINITIONS.ID" : "Id", + "PROPERTY.ESCALATIONDEFINITIONS.NAME" : "Name", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "No sequence flow order determined", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Sequence flow order set", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "No outgoing sequence flow found.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Set the order in which the sequence flow need to be evaluated:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Sequence flow to {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "Sequence flow condition", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Condition expression", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "No condition set", + + "PROPERTY.DUEDATE.EMPTY" : "No due date", + "PROPERTY.DUEDATE.DEFINED" : "Due date defined", + "PROPERTY.DUEDATE.TITLE" : "Due date", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Due date expression", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "No due date", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Expression definition", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Fixed duration after task creation", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Based on field", + + "MODEL.SAVE.TITLE" : "Save model", + "MODEL.VALIDATE.TITLE" : "Validation results", + "MODEL.NAME" : "Name", + "MODEL.KEY" : "Key", + "MODEL.DESCRIPTION" : "Description", + "MODEL.SAVE.NEWVERSION" : "Save this as a new version? This means you can always go back to a previous version", + "MODEL.SAVE.COMMENT" : "Comment", + "MODEL.SAVE.SAVING" : "Saving model", + "MODEL.LASTMODIFIEDDATE" : "Last saved", + "MODEL.SAVE.ERROR": "Unexpected error: could not save model", + "MODEL.VALIDATIONERRORS": "Note that the model contains validation errors. This means that the model can not be deployed on the Flowable Engine in its current state.", + "MODEL.CONFLICT.WRITE": "Could not save model: '{{userFullName}}' has made changes to this model", + "MODEL.CONFLICT.WRITE.OPTIONS": "Select an option to resolve this conflict:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Overwrite other model", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Discard my changes", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Save as new model", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Create new version", + "MODEL.CONFLICT.SAVEAS" : "Save as:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "An activity is about to be executed as a compensation for another activity. The event targets the activity that is about to be executed for compensation", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "An activity has been completed successfully", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "An activity has received an error event. Dispatched before the actual error has been received by the activity", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "A new membership has been created", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "A single membership has been deleted", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "All memberships in the related group have been deleted. No individual events will be dispatched due to possible performance reasons", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "A task as been assigned. This is thrown alongside with an ENTITY_UPDATED event", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "A task has been completed. Dispatched before the task entity is deleted", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "When a BPMN Error was thrown, but was not caught within in the process", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "A new variable has been created", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "An existing variable has been deleted", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "An existing variable has been updated", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Decision table reference", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "There was an error loading the decision tables. Try again later", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Loading decision tables...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "This folder contains no decision tables", + + "PROPERTY.CASEREFERENCE.EMPTY" : "No reference selected", + "PROPERTY.CASEREFERENCE.TITLE" : "Case model reference", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "There was an error loading the case models. Try again later", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "Loading case models...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "This folder contains no case models" +} diff --git a/zbf-admin/src/main/resources/static/designer/i18n/es.json b/zbf-admin/src/main/resources/static/designer/i18n/es.json new file mode 100644 index 0000000..55f3f62 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/i18n/es.json @@ -0,0 +1,872 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable Editor", + "NAVIGATION" : { + "PROCESSES": "Procesos", + "FORMS": "Formularios", + "DECISION-TABLES": "Tablas de decisión", + "APPS": "Aplicaciones" + }, + "TITLE": { + "SELECT-GROUP" :"Selecciona el grupo", + "MATCHING-GROUPS": "Grupos coincidentes", + "FILTER": "Filtro", + "HISTORY": "Historial" + }, + "ACTION": { + "LOGOUT": "Salir", + "RETURN-TO-LIST": "Mostrar todas las definiciones", + "CANCEL": "Cancelar", + "CLOSE": "Cerrar", + "EDIT": "Editar", + "SAVE": "Guardar", + "OPEN": "Abrir", + "OK": "Ok", + "CONFIRM": "Confirmar", + "CONFIRM-AND-CLOSE": "Confirmar y cerrar", + "NEW-FORM": "Nuevo formulario", + "CREATE-FORM": "Crear formulario", + "NEW-DECISION-TABLE": "Nueva tabla de decisión", + "CREATE-DECISION-TABLE": "Crear tabla de decisión" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "Usa ↑ y ↓ para seleccionar y presiona Enter para confirmar", + "PEOPLE-NO-MATCHING-RESULTS": "No se encontraron usuarios similares", + "GROUP-NO-MATCHING-RESULTS": "No se encontraron grupos similares", + "GROUP-SOURCE-TYPE": "Group source", + "GROUP-SOURCE-SEARCH-OPTION": "Busqueda de grupo", + "GROUP-SOURCE-FIELD-OPTION": "Campo de formulario" + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "Tienes cambios sin guardar", + "DESCRIPTION": "Que deseas realizar con los cambios sin guardar?", + "ACTION": { + "SAVE": "Guardar cambios", + "DISCARD": "Descartar cambios", + "CONTINUE": "Continiar edición" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "Modelos de procesos de negocio", + "SEARCH-PLACEHOLDER": "Buscar", + "ACTION" : { + "CREATE": "Crear Proceso", + "IMPORT": "Importar Proceso" + }, + + "FILTER" : { + "PROCESSES": "Modelo de proceso", + "PROCESSES-COUNT": "Existen {{total}} modelos de proceso", + "PROCESSES-ONE": "Existe un modelo de proceso", + "PROCESSES-EMPTY": "Aun no existe un modelo de proceso creado. puedes diseñar tus propios modelos, formularios y despues incluirlos en una aplicación. El primer paso es crear un modelo de proceso:", + "PROCESSES-BPMN-HINT": "Crear un modelo BPMN usando el editor visual BPMN.", + "PROCESSES-BPMN-IMPORT-HINT": "Tambien puede importar modelos BPMN existentes.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "No existen modelos de proceso parecidos a \"{{filterText}}\"", + "RECENT": "Reciente", + "RECENT-COUNT": "{{total}} modelos usados recientemente", + "RECENT-ONE": "Existe un modelo usado recientemente", + "RECENT-EMPTY": "No existen modelos usados recientemente" + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + + "FORMS-LIST" : { + "TITLE" : "Formularios", + "SEARCH-PLACEHOLDER": "Busqueda", + "ACTION" : { + "CREATE": "Crear formulario", + "CREATE-INLINE": "Crear un nuevo formulario ahora!", + "SHOW-MORE": "Mostrar más..." + }, + + "FILTER" : { + "FORMS": "Formularios", + "FORMS-COUNT": "Existen {{total}} formularios", + "FORMS-ONE": "Existe un formulario", + "FORMS-EMPTY": "No existen formularios. Para agregar uno da click en Crear formulario.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "No existe un formulario parecido a \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "Tablas de decision", + "SEARCH-PLACEHOLDER": "Busqueda", + "ACTION": { + "CREATE": "Crear tabla de decision", + "IMPORT": "Importar tabla de decision", + "CREATE-INLINE": "Crear una tabla de decision ahora!", + "SHOW-MORE": "Mostrar más..." + }, + + "FILTER": { + "DECISION-TABLES": "Tablas de decision", + "DECISION-TABLES-COUNT": "Existen {{total}} tablas de decision", + "DECISION-TABLES-ONE": "Existe una tabla de decision", + "DECISION-TABLES-EMPTY": "No existen tablas de decision. Para agregar una da click en Crear tabla de decision.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "no existen tablas de decision parecidas a \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + + "APPS-LIST" : { + "TITLE" : "Aplicaciones", + "SEARCH-PLACEHOLDER": "Busqueda", + "ACTION" : { + "CREATE": "Crear App", + "IMPORT": "Importar App", + "SHOW-MORE": "Mostrar mas..." + }, + + "FILTER" : { + "APPS": "Aplicaciones", + "APPS-COUNT": "Existen {{total}} aplicaciones", + "APPS-ONE": "Existe una aplicacion", + "APPS-EMPTY": "No existen aplicaciones. Para agregar una da click en Crear App.", + "FILTER-TEXT": ", parecido a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "No existen aplicaciones parecidas a \"{{filterText}}\"", + + "NO-APPS": "Puedes crear una aplicacion publicando un conjunto de Modelos de Proceso.", + "NO-APPS-CALL-TO-ACTION": "Puedes crear una aplicacion ahora.", + "NO-APPS-NOTE": "Recuerda publicar cuando estes listo para usar la aplicacion." + }, + + "SORT": { + "MODIFIED-ASC": "Antiguo", + "MODIFIED-DESC": "Ultimo modificado", + "NAME-ASC": "Nombre, A-Z", + "NAME-DESC": "Nombre, Z-A" + } + }, + "PROCESS": { + "NAME": "Nombre del modelo", + "KEY": "Identificador del modelo", + "DESCRIPTION": "Descripcion", + "VERSION-COMMENT": "Comentario de version", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modificar propiedades del modelo", + "DUPLICATE": "Duplicar este modelo", + "EXPORT_BPMN20": "Exportar a BPMN 2.0", + "DELETE": "Borrar este modelo", + "CREATE-CONFIRM": "Crear nuevo modelo", + "DUPLICATE-CONFIRM": "Duplicar el modelo", + "OPEN-IN-EDITOR": "Editor visual", + "EDIT-CONFIRM": "Guardar", + "DELETE-CONFIRM": "Borrar modelo de proceso", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "FAVORITE": "Hacer modelo favorito" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historial", + "LAST-UPDATED-BY": "Ultima actualizacion por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}", + "NO-DESCRIPTION": "Este modelo no tiene descripcion. Modifica las propiedades del modelo para agregar una" + }, + + "POPUP": { + "CREATE-TITLE": "Crear un nuevo modelo de proceso de negocio", + "DUPLICATE-TITLE": "Duplicar modelo de proceso de negocio", + "CREATE-DESCRIPTION": "Necesitas dar un nombre para el nuevo modelo y es recomendable que agregues una descripción al mismo tiempo.", + "DUPLICATE-DESCRIPTION": "Puedes cambiar el nombre del modelo y es recomendable que cambies la descripción al mismo tiempo.", + "EDIT-DESCRIPTION": "Cambia cualquiera de las propiedades del modelo y despues presiona Guardar para actualizar el modelo.", + "DELETE-DESCRIPTION": "Estas seguro que deseas borral el modelo de proceso de negocio \"{{name}}\"?", + "EDIT-TITLE":"Editar los detalles del modelo", + "DELETE-TITLE": "Borrar modelo", + "DELETE-LOADING-RELATIONS": "Verificando el uso del modelo...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "Este modelo no puede ser eliminado porque esta siendo utilizado por otro modelo:", + "DELETE-RELATIONS-DESCRIPTION": "Este modelo no puede ser eliminado porque esta siendo utilizado por otros modelos:", + "DELETE-PROCESS-RELATION": "Modelo de proceso", + "DELETE-FORM-RELATION": "Formulario de modelo", + "DELETE-APP-RELATION": "Modelo de App", + "IMPORT-DESCRIPTION": "Busca o arrastra una definicion BPMN XML con la extension .bpmn o .bpmn20.xml", + "IMPORT-TITLE": "Importar un modelo de proceso", + "USE-AS-NEW-TITLE": "Usar como nueva version", + "USE-AS-NEW-DESCRIPTION": "Estas seguro que deseas utilizar la version {{version}} para crear una nueva version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "No se pudo restaurar a la version seleccionada: Algunos modelos no se encuentran debido a que fueron borrados. Por favor actualiza el modelo de la aplicacion. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modelo '{{name}}' con el id {{id}}, creado por {{createdBy}}", + "SHARED-WITH": "Compartido con", + "PERMISSION": "Permiso", + "ACTIONS": "Acciones", + "IMPORT": { + "DROPZONE": "Arrastra un archivo .bpmn or .bpmn20.xml BPMN XML", + "CANCEL-UPLOAD": "Cancelar la carga de archivo", + "ERROR": "Error al procesar el archivo BPMN XML", + "NO-DROP": "Arrastrar y soltar no soportado" + } + }, + "ALERT": { + "EDIT-CONFIRM": "Modelo actualizado" + }, + "ERROR": { + "NOT-FOUND": "El modelo solicitado no existe" + } + }, + + "SUBPROCESS": { + "NAME": "Nombre del Sub proceso", + "DESCRIPTION": "Descripcion", + "ACTION": { + "CREATE-CONFIRM": "Crear nuevo sub proceso" + }, + "POPUP": { + "CREATE-TITLE": "Crear nuevo sub proceso", + "CREATE-DESCRIPTION": "Necesitas proporcionar un nombre para el nuevo sub proceso y es recomendable agregar una descripcion al mismo tiempo." + } + }, + + "FORM": { + "NAME": "Nombre del formulario", + "KEY": "identificador del formulario", + "DESCRIPTION": "Descripcion", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modicar propiedades del modelo", + "DELETE": "Borrar este formulario", + "CREATE-CONFIRM": "Crear nuevo formulario", + "DUPLICATE-CONFIRM": "Duplicar el formulario", + "OPEN-IN-EDITOR": "Editor de formulario", + "EDIT-CONFIRM": "Guardar", + "DELETE-CONFIRM": "Borrar formulario", + "USE-AS-NEW-VERSION": "Usar como nueva version" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historial", + "LAST-UPDATED-BY": "Ultima actualizacion por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}" + }, + + "POPUP": { + "CREATE-TITLE": "Crear nuevo formulario", + "DUPLICATE-TITLE": "Duplicar formulario", + "CREATE-DESCRIPTION": "Necesitas proporcionar un nombre para el nuevo formulario y es recomendable agregar una descripcion al mismo tiempo.", + "DUPLICATE-DESCRIPTION": "Necesitas proporcionar un nombre para el nuevo formulario y es recomendable agregar una descripcion al mismo tiempo.", + "SAVE-FORM-TITLE": "Guardar formulario", + "EDIT-DESCRIPTION": "Cambia cualquiera de las propiedades debajo y despues presiona Guardar para actualizar el formulario.", + "DELETE-DESCRIPTION": "Estas seguro de borrar el formulario \"{{name}}\"?", + "EDIT-TITLE":"Editar detalles de formulario", + "DELETE-TITLE": "Borrar formulario", + "USE-AS-NEW-TITLE": "Usar como nueva version", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "USE-AS-NEW-DESCRIPTION": "Estas seguro que quieres utilizar la version {{version}} para crear una nueva version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "No se pudo restaurar completamente a la version seleccionada: Algunos modelos referenciados fueron borrados. Por favor actualiza el modelo. Moodelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modelo '{{name}}' con identificador {{id}}, creado por {{createdBy}}" + } + }, + + "DECISION-TABLE": { + "NAME": "Nombre de la Tabla de decision", + "KEY": "Identificador de la Tabla de decision", + "DESCRIPTION": "Descripcion", + "VERSION-COMMENT": "Comentario de version", + "HIT-POLICY": "Reglas de aciertos:", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modificar propiedades del modelo", + "SHARE": "Compartir esta tabla de decision", + "DELETE": "Borrar esta tabla de decision", + "ADD-COMMENT": "+ Agregar comentario", + "CREATE-CONFIRM": "Crear nueva tabla de decision", + "OPEN-IN-EDITOR": "Editor de tabla de decision", + "EXPORT": "Exportar tabla de decision", + "DELETE-CONFIRM": "Borrar tabla de decision", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "FAVORITE": "Maracar como favorita esta tabla de decision", + "DUPLICATE": "Duplicar esta tabla de decision" + }, + "DETAILS": { + "HISTORY-TITLE": "Historial", + "COMMENTS-TITLE": "Comentarios", + "LAST-UPDATED-BY": "Ultimavez actualizado por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}" + }, + "HIT-POLICIES": { + "FIRST": "Primero (Single pass)", + "ANY": "Cualquiera (Single pass)" + }, + "POPUP": { + "CREATE-TITLE": "Crear nueva tabla de decision", + "CREATE-DESCRIPTION": "Es necesario dar un nombre par a la tabla de decision, es recomendable proporcionar una descripcion al mismo tiempo.", + "DUPLICATE-TITLE": "Duplicar tabla de decision", + "DUPLICATE-DESCRIPTION": "Puedes dar un nombre para la nueba tabla de decision es recomendable proporcionar una descripcion al mismo tiempo.", + "SAVE-DESCRIPTION": "Es necesario proporcionar un nombre y un identificador unico para la tabla de decision, es recomendable proporcionar una descripcion al mismo tiempo", + "DELETE-TITLE": "Borrar tabla de decision", + "DELETE-DESCRIPTION": "Estas Seguro que deseas borrar esta tabla de decision \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "Guardar tabla de decision", + "IMPORT-DESCRIPTION": "Busca o arrastra una definicion DMN XML con una extension .dmn o .dmn.xml", + "IMPORT-TITLE": "Importar un modelo DMN", + "IMPORT": { + "DROPZONE": "Arrastra un archivo.dmn o .dmn.xml DMN XML", + "CANCEL-UPLOAD": "Cancelar la carga", + "ERROR": "Error cuando se procesaba el archivo DMN XML", + "NO-DROP": "Arrastrar y soltar no soportado" + }, + "USE-AS-NEW-TITLE": "Usar como nueva version", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "USE-AS-NEW-DESCRIPTION": "Estas seguro que quieres utilizar la version {{version}} tpara crear una nueva version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "No se pudo restaurar completamente a la version seleccionada: Algunos modelos referenciados fueron borrados. Por favor actualiza el modelo. Moodelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modelo '{{name}}' con identificador {{id}}, creado por {{createdBy}}" + }, + "ALERT": { + "FAVORITE-CONFIRM": "Esta tabla de decision es ahora favorita", + "UN-FAVORITE-CONFIRM": "Esta tabla de decision ya no es favorita" + } + }, + + "APP": { + "NAME": "Nombre de la App", + "KEY": "Identificador de la App", + "DESCRIPTION": "Descripcion", + "ICON": "Icono", + "THEME": "Tema", + "GROUPS-ACCESS": "Acceso a grupos, separado por comas", + "USERS-ACCESS": "Acceso a usuarios, separado por comas", + "ACTION": { + "DETAILS": "Mostrar detalles", + "EDIT": "Modificar propiedades de la App", + "DUPLICATE": "Duplicar esta App", + "SHARE": "Compartir esta App", + "DELETE": "Borrar esta App", + "CREATE-CONFIRM": "Crear nueva App", + "DUPLICATE-CONFIRM": "Duplicar App", + "DELETE-CONFIRM": "Borrar App", + "USE-AS-NEW-VERSION": "Usar como nueva version", + "OPEN-IN-EDITOR": "Editor de App", + "PUBLISH": "Publicar", + "PUBLISH-CONFIRM": "Publicar App", + "SELECT-ICON": "Cambiar icono...", + "SELECT-THEME": "Cambiar tema...", + "EDIT-MODELS": "Editar modelos incluidos", + "EXPORT-ZIP": "Exportar App como archivo zip", + "EXPORT-BAR": "Exportar App como archivo deployable bar" + + }, + "DETAILS": { + "TITLE": "Detalles de la App: {{name}}", + "HISTORY-TITLE": "Historial", + "MODELS-TITLE": "Modelos incluidos en la App", + "LAST-UPDATED-BY": "Ultima modificacion por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Creado por {{createdBy}}", + "NO-DESCRIPTION": "Esta App no tiene descripcion. Modifica las propiedades de la App para agregar una", + "NO-MODELS-SELECTED": "No hay modelos seleccionados para esta App" + }, + "TITLE": { + "SELECT-ICON": "Seleccionar icono de la App", + "SELECT-THEME": "Seleccionar tema de la App", + "PREVIEW": "Vista previa" + + }, + "POPUP": { + "CREATE-TITLE": "Crear nueva App", + "DUPLICATE-TITLE": "Duplicar App", + "SAVE-APP-TITLE": "Guardar App", + "SAVE-APP-SAVE-SUCCESS": "App guardada", + "CREATE-DESCRIPTION": "Necesitas dar un nombre para la nueva App es recomendable proporcionar una descripcion al mismo tiempo", + "DUPLICATE-DESCRIPTION": "Puedes dar un nombre para la nueba App es recomendable proporcionar una descripcion al mismo tiempo", + "PUBLISH-TITLE": "Publicar App", + "PUBLISH-DESCRIPTION": "Estas seguro que deseas publicar la App \"{{name}}\"? Esta App sera versionada y actualizada en la App de workflow si ya existe.", + "PUBLISH-FIELD": "Publicar? Esta App sera versionada y actualizada en la App de workflow si ya existe.", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "Tu modelo de proceso \"{{modelInAppName}}\" tiene el mismo identificador \"{{processDefinitionKey}}\" que el proceso existente deployado \"{{conflictingModelName}}\" de la App \"{{conflictingAppName}}\". Por favor cambia el \"id\" del modelo de proceso a algo diferente.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "Los siguientes modelos de proceso ya son utilizados en otra App. Esto es correcto?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "App", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "App invalida: se encontraron identificadores de proceso duplicados (cambia el \"id\" identificador de los procesos que tienen este detalle):", + "DELETE-TITLE": "Borrar App", + "DELETE-DESCRIPTION": "Estas seguro que deseas borrar la App \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "Estas seguro que deseas borrar la App \"{{name}}\"? Esta App se ha publicado en la vista de aplicaciones si confirmas, el acceso a la App sera removido.", + "DELETE-CASCADE-FALSE": "Borrar solo la version actual de la App (v{{version}})", + "DELETE-CASCADE-TRUE": "Borrar tambien las versiones anteriores de esta App", + "HAS-CUSTOM-STENCILITEM" : "Modelo \"{{modelName}}\" uses a stencil with custom stencil items. It is not possible to use this model in an App.", + "HAS-VALIDATIONERROR" : "Model \"{{modelName}}\" has validation errors and cannot be added to an App. Open the model in the editor to see more details about the validation error(s).", + "IMPORT-DESCRIPTION":"Por favor busca o arrastra una App con una extension .zip", + "IMPORT-TITLE":"Importar una App", + "IMPORT": { + "DROPZONE": "Arrastra un archivo de App .zip", + "CANCEL-UPLOAD": "Cancelar la carga", + "RENEWIDM-IDS": "Renueva los identificadores de grupo y de usuario cuando importes los modelos BPMN. Esto es comunmente requerido cuando importas la App en un ambiente de Flowable diferente. Se intentara ligar los pasos humanos y las tareas de usuario al usuario y grupo de usuarios correctos en este ambiente.", + "ERROR": "Error mientras se procesaba el archivo de la App", + "NO-DROP": "Arrastrar y soltar no soportado" + }, + "INCLUDE-MODELS-TITLE": "Modelos incluidos en la App" + }, + "ALERT": { + "DELETE-CONFIRM": "App Borrada", + "PUBLISH-CONFIRM": "La App ha sido publicada", + "PUBLISH-ERROR": "No se pude publicar la App. Por favor revisa que los modelos de proceso incluidos sean correctos" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "Agregar otra persona" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "Texto", + "PASSWORD": "Contraseña", + "MULTILINE-TEXT": "Texto en varias lineas", + "NUMBER": "Numero", + "CHECKBOX": "Checkbox", + "DATE": "Fecha", + "DROPDOWN": "Lista", + "RADIO": "Radio buttons", + "PEOPLE": "Personas", + "GROUP-OF-PEOPLE": "Grupo de personas", + "UPLOAD": "Upload", + "EXPRESSION": "Expresion", + "HYPERLINK": "Hipervínculo", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS": { + "GENERAL": "General", + "OPTIONS": "Opciones", + "UPLOAD-OPTIONS": "Opciones Upload", + "ADVANCED-OPTIONS":"Avanzado" + }, + "VERSION": "Version {{version}}", + "LAST-UPDATED": "Ultima vez actualizado por {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "Diseño", + "OUTCOME": "Resultado" + }, + "POPUP": { + "EDIT-TITLE": "Editar campo '{{name}}'", + "EXPRESSION-TITLE": "Editar expresion" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(No expression value)", + "EXPRESSION-HELP": "Tambien puedes mostrar valores enviados anteriormente en cualquier formulario, como parte del texto, referenciandolo utilizando una notacion como la siguiente ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "Puede usar una expresión para completar dinámicamente las opciones, por ejemplo, haciendo referencia a una variable como esta ${optionsVariable}. La expresión debe dar como resultado un objeto java (java.util.List con objetos Option) o su representación json." + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "Selecciona el grupo..", + "PERSON": "Selecciona persona..." + }, + "COMPONENT": { + "LABEL": "Etiqueta:", + "OVERRIDEID": "Sobreescribir identificador?", + "ID": "Identificador:", + "PLACEHOLDER": "Placeholder:", + "OPTIONS": "Opciones", + "RADIO-BUTTON-DEFAULT": "Opcion 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "Por favor elige uno...", + "DROPDOWN-EMPTY-VALUE-HELP": "Este es la opcion 'valor vacio'. Seleccionar esto en tiempo de ejecucion es igual a 'no valor' o 'vacio'. Esto esta permitido para campos opcionales, pero no para campos requeridos.", + "OPTIONS-EXPRESSION": "Expresión de opciones:", + "OPTIONS-EXPRESSION-ENABLED": "Habilitar expresión de opciones", + "REQUIRED": "Requerido", + "EXPRESSION": "Expresion", + "ADD-OPTION": "+ Agregar nueva opcion", + "UPLOAD-ALLOW-MULTIPLE": "Permitir subir varios archivos", + "MAX-LENGTH":"Longitud máxima:", + "MIN-LENGTH":"Longitud mínima:", + "PASSWORD-UNMASK-OPTION": "Opción de enmascaramiento/desenmascaramiento de contraseña", + "HYPERLINK-URL": "URL hiperlink", + "REGEX-PATTERN":"Estándar Regex", + "MASK":{ + "TITLE":"Máscara de entrada", + "EXAMPLES":{ + "TITLE":"Ejemplos:", + "NUMBER":"Cualquier número", + "LETTER":"Cualquier letra", + "NUMBERORLETTER":"Cualquier letra o número", + "OPTIONAL":"La máscara opcional (no valida)", + "PHONE":"Teléfono" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "Puedes definir multiples resultados para esta tarea. Cuando se este completando la tarea, el usuario selecciona uno de los resultados disponibles, que pueden ser utilizados por ejemplo eg. una condicion utilizada mas adelante en el proceso.", + "NO-OUTCOMES-OPTION": "Don't use custom outcomes, only show a 'Complete' button.", + "OUTCOMES-OPTION": "Usar resultados propios para este formulario.", + "POSSIBLE-OUTCOMES": "Posibles resultados", + "NEW-OUTCOME-PLACEHOLDER": "Introduce un nuevo resultado", + "ADD": "Agregar resultado", + "REMOVE": "Eliminar" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "Indefinido" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "Editar columna de entrada", + "INPUT-DESCRIPTION": "Seleccionar variable de entrada como ebtrada para la columna", + "OUTPUT-TITLE": "Editar columna de salida", + "OUTPUT-DESCRIPTION": "Selecionar una variable de salida existente o crear una nueva", + "EXPRESSION-LABEL": "Etiqueta de columna:", + "EXPRESSION-PLACEHOLDER": "Ingresar una etiqueta opcional", + "EXPRESSION-VARIABLE-NAME": "Nombre de variable:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "Ingresar nombre de variable", + "OUTPUT-NEW-VARIABLE-ID": "Identificador de variable:", + "OUTPUT-NEW-VARIABLE-TYPE": "Tipo de variable:" + } + }, + "BUTTON-ADD-INPUT-LABEL": "Agregar entrada", + "BUTTON-ADD-OUTPUT-LABEL": "Agregar salida", + "BUTTON-ADD-RULE-LABEL": "Agregar regla", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "Mover arriba", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "Mover abajo", + "BUTTON-REMOVE-RULE-LABEL": "Eliminar regla", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "Todas las expresiones de entrada y salida deben referenciar un campo del formulario o una variable.", + "SAVE-CONFIRM": "Guardar tabla de decision '{{name}}'" + } + }, + + "TOUR": { + "WELCOME-TITLE": "Bienvenido, {{userName}}", + "WELCOME-CONTENT": "Esta es una pequeña guia del Editor Flowable. Los siguientes pasos te guiaran a traves de diferentes secciones de la aplicacion.Presion ESC para detener la guia en cualquier momento." , + "PALETTE-TITLE": "Barra de dibujo", + "PALETTE-CONTENT": "Todos los simbolos necesarios para crear un proceso de negocio pueden ser encontrados aqui. Se encuentran agrupados de manera logica. Para abrir un grupo simplemente da click en el:", + "CANVAS-TITLE": "El area de trabajo", + "CANVAS-CONTENT": "En este espacio crea tu proceso de negocio. Arrastra elementos desde la barra de dibujoe en la izquierda y sueltalos en esta area para empezar a modelar.", + "DRAGDROP-TITLE": "Ejemplo arrastrar y soltar", + "DRAGDROP-CONTENT": "aqui esta un ejemplo de como comenzar a modelar:", + "PROPERTIES-TITLE": "Propiedades", + "PROPERTIES-CONTENT": "Aqui puedes configurar las propuedades de un proceso de negocios. Simplemente selecciona un elemento en el area de trabajo y sus propiedades serán mostradas. Da click en la propiedad si deseas editarla", + "TOOLBAR-TITLE": "Barra de herramientas", + "TOOLBAR-CONTENT": "Todas las acciones pueden ser encontradas aqui: guardar o validar un modelo, copiar y pegar partes del proceso, y continua. Pasa sobre los botnones para ver lo que realizan.", + "END-TITLE": "Fin", + "END-CONTENT": "Ahora puedes modelar tus procesos. Si tienes alguna duda, sientete libre de preguntar en Flowable Forum " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Tutorial punto de curva", + "DESCRIPTION" : "Cuando estas conectando un elemento con otro usando un flujo de secuencia (Esas flechas entre los pasos del proceso), encontraras que esos flujos de secuencia se crean de manera automatica, si deseas modificar la direccione de las flechas, puedes agregar o eliminar un punto de curva de un flujo de secuencia.
Como se muestra debajo en la figura, primero das click en el boton 'Agregar punto curva'y despues das click en el flujo de secuencia al que deseas agregarlo. El fluo de secuencia te indicará con un punto en verde que el punto curva puede ser agregado.
Para eliminar un punto curva, click en 'eliminar punto curva' y da click en el flujo de secuencia del cual deseas eliminar." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Guardar", + "ACTION.SAVE-AND-CLOSE" : "Guardar y cerrar el editor", + "ACTION.SEND" : "Enviar", + "ACTION.CANCEL" : "Cancelar", + "ACTION.SELECT" : "Seleccionar", + "ACTION.ADD" : "Agregar", + "ACTION.REMOVE" : "Eliminar", + "ACTION.MOVE.UP" : "Mover arriba", + "ACTION.MOVE.DOWN" : "Mover abajo", + + "TOOLBAR.ACTION.CLOSE" : "Cerrar el editor y volver a la pagina de previsualizacion", + "TOOLBAR.ACTION.SAVE" : "Guardar el modelo", + "TOOLBAR.ACTION.VALIDATE" : "Validar el modelo", + "TOOLBAR.ACTION.CUT" : "Cortar (seleciona uno o mas elementos en tu proceso de negocio)", + "TOOLBAR.ACTION.COPY" : "Copiar (seleciona uno o mas elementos en tu proceso de negocio)", + "TOOLBAR.ACTION.PASTE" : "Pegar", + "TOOLBAR.ACTION.DELETE" : "Borrar el elemento seleccionado", + "TOOLBAR.ACTION.UNDO" : "Deshacer", + "TOOLBAR.ACTION.REDO" : "Rehacer", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom in", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom out", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom a tamaño actual", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom para ajustar", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Agregar punto de curva al flujo de secuencia seleccionado", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Eliminar punto de curva al flujo de secuencia seleccionado", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Alinear modelo horizontalmente", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Alinear modelo verticalmente", + "TOOLBAR.ACTION.SAMESIZE" : "Mismo tamaño", + "TOOLBAR.ACTION.HELP": "Iniciar la visita guiada", + "TOOLBAR.ACTION.FEEDBACK": "Proveer retroalimentacion", + + "FORM_TOOLBAR.ACTION.SAVE" : "Guardar el modelo", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Guardar la App", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Borrar elemento del modelo", + "BUTTON.ACTION.MORPH.TOOLTIP": "Cambiar tipo del elemento", + + "ELEMENT.AUTHOR" : "Autor", + "ELEMENT.DATE_CREATED" : "Fecha de creacion", + + "PROPERTY.REMOVED" : "eliminado", + "PROPERTY.EMPTY" : "Sin valor", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Cambiar valor por", + + "PROPERTY.FEEDBACK.TITLE" : "Por favor proporciona tu retroalimentacion", + + "PROPERTY.ASSIGNMENT.TITLE" : "Asignacion", + "PROPERTY.ASSIGNMENT.TYPE" : "Tipo", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Almacen de identidad", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Valores arreglados", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Asignado", + "PROPERTY.ASSIGNMENT.MATCHING" : "Usa ↑ y ↓ para seleccionar y presiona Enter para confirmar o usa el mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Introduce un asignado", + "PROPERTY.ASSIGNMENT.EMPTY" : "No hay asignacion seleccionada", + "PROPERTY.ASSIGNMENT.NONE" : "Ninguno ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Buscar usuario", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Buscar grupo", + "PROPERTY.ASSIGNMENT.SEARCH": "Buscar: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Assignado {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} Usuarios candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Usuarios candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} Grupos candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Grupos candidatos", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "Usuario {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "Usuario {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Campo {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Iniciador del proceso", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Asignacion", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "No hay usuarios candidatos seleccionados...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "No hay grupos candidatos seleccionados...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Asignar al iniciador del proceso", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Asignar a un solo usuario", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Usuarios candidatos", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Grupos candidatos", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Permitir al iniciador del proceso completar la tarea", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} escuchadores de ejecucion", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No hay escuchadores de ejecucion configurados", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Evento", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Clase", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Introduce un nombre de clase", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expresion", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Expresion delegada", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Introduce una expresion delegada", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "No hay escuchadores de ejecucion seleccionados", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Nombre", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expresion", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "Valor cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "Cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementacion", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "No hay un campo seleccionado", + + "PROPERTY.FIELDS" : "{{length}} campos", + "PROPERTY.FIELDS.EMPTY" : "No hay campos seleccionados", + "PROPERTY.FIELDS.NAME" : "Nombre", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.FIELDS.EXPRESSION" : "Expresion", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Ingresa una expresion", + "PROPERTY.FIELDS.STRINGVALUE" : "Valor cadena", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.FIELDS.STRING" : "Cadena", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implementacion", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} propiedades del formulario", + "PROPERTY.FORMPROPERTIES.EMPTY" : "No hay propiedades del formulario seleccionadas", + "PROPERTY.FORMPROPERTIES.ID" : "Identificador", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Introduce un identificador", + "PROPERTY.FORMPROPERTIES.NAME" : "Nombre", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.FORMPROPERTIES.TYPE" : "Tipo", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Patron de fecha", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Introduce un patron de fecha", + "PROPERTY.FORMPROPERTIES.VALUES" : "Valores", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "Nose selecciono un valor enum", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Identificador", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Nombre", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Introdice el identificador del valor", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Introduce el nombre del valor", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expresion", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Introduce una variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Introduce una default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Requerido", + "PROPERTY.FORMPROPERTIES.READABLE" : "Leible", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Escribible", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} parametros de entrada", + "PROPERTY.INPARAMETERS.EMPTY" : "No hay parametros de entrada configurados", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} parametros de salida", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No hay parametros de salida configurados", + + "PROPERTY.PARAMETER.SOURCE" : "Fuente", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Introduce una fuente", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Expresion de fuente", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Expresion de fuente", + "PROPERTY.PARAMETER.TARGET" : "Objetivo", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Introduce un objetivo", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "Expresion de objetivo", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "Introduce un expresion de objetivo", + "PROPERTY.PARAMETER.EMPTY" : "No hay parametro seleccionado", + + "PROPERTY.SUBPROCESSREFERENCE.EMPTY" : "No hay referencia seleccionada", + "PROPERTY.SUBPROCESSREFERENCE.TITLE" : "Referencia a subproceso colapsado", + "PROPERTY.SUBPROCESSREFERENCE.ERROR.SUBPROCESS" : "Ocurrio un error cargando subprocesos. Intenta mas tarde", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.LOADING" : "Cargando subprocesos...", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.EMPTY" : "Este folder no contiene subprocesos", + + "PROPERTY.FORMREFERENCE.EMPTY" : "No hay referencia seleccionada", + "PROPERTY.FORMREFERENCE.TITLE" : "Referencia a formulario", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Referencia a formulario", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "Ocurrio un error cargando los formularios. Intenta mas tarde", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Cargando formularios...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "Este folder no contiene formularios", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} escuchadores de tarea", + "PROPERTY.TASKLISTENERS.EMPTY" : "No hay escuchadores de tarea configurados", + "PROPERTY.TASKLISTENERS.EVENT" : "Evento", + "PROPERTY.TASKLISTENERS.CLASS" : "Clase", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Introduce un nombre de clase", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expresion", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegar expresion", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Introduce una expresion de delegado", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "No hay escuchadores de tarea seleccionados", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Nombre", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Introduce un nombre", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expresion", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Introduce una expresion", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "Valor cadena", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "Cadena", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Introduce una cadena", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implementacion", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "No hay campo seleccionado", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} escuchadores de evento", + "PROPERTY.EVENTLISTENERS.EMPTY" : "No hay esuchadores de evento seleecionados", + "PROPERTY.EVENTLISTENERS.EVENTS": "Eventos", + "PROPERTY.EVENTLISTENERS.RETHROW": "Relanzar evento?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Clase", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Introduce un nombre de clase", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Expresion delegada", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Introduce una expresion de delegado", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Tipo de entidad", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Introduce un tipo de entidad", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Relanzar tipo de evento", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Codigo de error", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Introduce un codigo de error", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Nombre de mensaje", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Introduce un nombre de mensaje", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Nombre de señal", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Introduce un nombre de señal", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "No hay escuchador de evento seleccionado", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} definiciones de señal", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "No hay definiciones de señal", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Instancia de proceso", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Identificador", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Nombre", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Alcance", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} definiciones de mensaje", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "No hay definiciones de mensaje configuradas", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Identificador", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Nombre", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "No se definio el orden de los flujos de secuencia", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Orden de flujos de secuencia fijado", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "No se encontro un flujo de secuencia de salida.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Fijar el orden en el cual el flujo de secuencia necesita ser evaluado:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Flujo de secuencia a {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "Condicion del flujo de secuencia", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Expresion de la condicion", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "No hay condicion fijada", + + "PROPERTY.DUEDATE.EMPTY" : "No se definio fecha de vencimiento", + "PROPERTY.DUEDATE.DEFINED" : "Se definio fecha de vencimiento", + "PROPERTY.DUEDATE.TITLE" : "Fecha de vencimiento", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Expression de fecha de vencimiento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "No hay fecha de vencimiento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Definicion de expresion", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Duracion arreglada despues de la creacion de la tarea", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Basado en un campo", + + "MODEL.SAVE.TITLE" : "Guardar modelo", + "MODEL.VALIDATE.TITLE" : "Resultados de validacion", + "MODEL.NAME" : "Nombre", + "MODEL.KEY" : "Llave", + "MODEL.DESCRIPTION" : "Descripcion", + "MODEL.SAVE.NEWVERSION" : "Guardar como nueva version? Esto significa que siempre podras volver a una version anterior", + "MODEL.SAVE.COMMENT" : "Comentario", + "MODEL.SAVE.SAVING" : "Guardando modelo", + "MODEL.LASTMODIFIEDDATE" : "Ultimo guardado", + "MODEL.SAVE.ERROR": "Error inesperado: No se pudo guardar el modelo", + "MODEL.VALIDATIONERRORS": "El modelo tiene errores de validacion. El modelo no puede deployarse al Flowable Engine en el estado actual.", + "MODEL.CONFLICT.WRITE": "No se puede guardar el modelo: '{{userFullName}}' ha echo cambios a este modelo", + "MODEL.CONFLICT.WRITE.OPTIONS": "Selecciona una opcion para solucionar esto:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Sobreescribir el otro modelo", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Descartar mis cambios", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Guardar como nuevo modelo", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Crrear una nueva version", + "MODEL.CONFLICT.SAVEAS" : "Guardar como:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "Una actividad esta apunto de ser ejecutada como compensacion para otra actividad. Los eventos objetivo de la actividad que esta apunto de ser ejecutada para la compensacion", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "Una actividad se ha completado exitosamente", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "Una actividad ha recibido un mensaje de error. Enviado antes que el actual error haya sido recibido por la actividad", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "Una nueva membresia ha sido creada", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "Una sola membresia ha sido borrada", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "Todas las membresias relacionadas a un grupo han sido borradas. No se enviaran eventos individuales debido a razones de desempeño", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "Una tarea se ha asignado. Se lanzo junto al evento ENTITY_UPDATED", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "Una tarea ha sido completada. Antes que la entidad sea borrada", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "Cuando un error BPMN fue lanzado, pero no fue atrapado dentro del proceso", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "Una nueva variable se creo", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "Una variable existente fue borrada", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "Una variable existente fue actualizada", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "No hay referencia selecionada", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Tabla de decision referenciada", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "Ocurrio un error cargando la tabla de decisiones. Intenta mas tarde", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Cargando tabla de decisiones...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "Este folder no contiene tablas de decisiones" +} diff --git a/zbf-admin/src/main/resources/static/designer/i18n/fr.json b/zbf-admin/src/main/resources/static/designer/i18n/fr.json new file mode 100644 index 0000000..1ffa150 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/i18n/fr.json @@ -0,0 +1,1008 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable Editeur", + "NAVIGATION" : { + "PROCESSES": "Processus", + "CASEMODELS": "Modèle de cas", + "FORMS": "Formulaires", + "DECISION-TABLES": "Tables de décision", + "APPS": "Apps" + }, + "TITLE": { + "SELECT-GROUP" :"Sélectionner un groupe", + "MATCHING-GROUPS": "Groupes correspondants", + "FILTER": "Filtre", + "HISTORY": "Historique" + }, + "ACTION": { + "LOGOUT": "Déconnexion", + "RETURN-TO-LIST": "Afficher toutes les définitions", + "CANCEL": "Annuler", + "CLOSE": "Fermer", + "EDIT": "Editer", + "SAVE": "Sauver", + "OPEN": "Ouvrir", + "OK": "Ok", + "CONFIRM": "Confirmer", + "CONFIRM-AND-CLOSE": "Confirmer et fermer", + "NEW-FORM": "Nouveau formulaire", + "CREATE-FORM": "Créer un formulaire", + "NEW-DECISION-TABLE": "Nouvelle table de décision", + "CREATE-DECISION-TABLE": "Créer une table de décision" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "Utiliser ↑ et ↓ pour sélectionner et appuyer sur entrée pour confirmer ", + "PEOPLE-NO-MATCHING-RESULTS": "Aucun utilisateur correspondant n'a été trouvé", + "GROUP-NO-MATCHING-RESULTS": "Aucun groupe correspondant n'a été trouvé", + "GROUP-SOURCE-TYPE": "Groupe source", + "GROUP-SOURCE-SEARCH-OPTION": "Recherche de Groupe", + "GROUP-SOURCE-FIELD-OPTION": "Champ de formulaire" + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "Vous avez des modifications non enregistrées ", + "DESCRIPTION": "Que voulez vous faire des modifications non sauvegardées ?", + "ACTION": { + "SAVE": "Sauver", + "DISCARD": "Ignorer les changements", + "CONTINUE": "Continuer à éditer" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "Modèles de processus métiers", + "SEARCH-PLACEHOLDER": "Rechercher", + "ACTION" : { + "CREATE": "Créer un processus", + "IMPORT": "Importer un processus" + }, + + "FILTER" : { + "PROCESSES": "Modèles de processus", + "PROCESSES-COUNT": "Il y a {{total}} modèles de processus", + "PROCESSES-ONE": "Il y a un modèle de processus", + "PROCESSES-EMPTY": "Il n'y a pas de modèle de processus encore créé. Vous pouvez créer des modèles de processus, des formulaires et les grouper au sein d'une application. La première étpage consiste à créer ce modèle de processus:", + "PROCESSES-BPMN-HINT": "Créer un modèle BPMN en utilisant l'Editeur visuel BPMN.", + "PROCESSES-BPMN-IMPORT-HINT": "Vous pouvez aussi importer des modèles BPMN existants.", + "FILTER-TEXT": ", correspondant à \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de modèles de processus correspondant à \"{{filterText}}\"", + "RECENT": "Récent", + "RECENT-COUNT": "{{total}} modèles récemment utilisés", + "RECENT-ONE": "Un modèle récemment utilisé", + "RECENT-EMPTY": "Aucun modèle récemment utilisé" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "CASE-LIST" : { + "TITLE" : "Modèles de Cas", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION" : { + "CREATE": "Créer un Cas", + "IMPORT": "Importer un Cas" + }, + + "FILTER" : { + "CASES": "Modèles de Cas", + "CASES-COUNT": "Il y a {{total}} modèles de Cas", + "CASES-ONE": "Il y a un modèle de Cas", + "CASES-EMPTY": "Aucun modèle de cas n'a encore été créé. Vous pouvez créer un modèle de cas, des formulaires et les grouper au sein d'une définition d'App. La première étape consiste à créer ce modèle de Cas:", + "CASES-CMMN-HINT": "Créer un modèle CMMN en utilisant l'éditeur visuel CMMN.", + "CASES-CMMN-IMPORT-HINT": "Vous pouvez aussi importer un modèle CMMN existant.", + "FILTER-TEXT": ", correspondant à \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de modèle de cas correspondant à \"{{filterText}}\"", + "RECENT": "Récent", + "RECENT-COUNT": "{{total}}modèles récemment utilisés", + "RECENT-ONE": "Un modèle récemment utilisé", + "RECENT-EMPTY": "Aucun modèle récemment utilisé" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "FORMS-LIST" : { + "TITLE" : "Formulaires", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION" : { + "CREATE": "Créer un formulaire", + "CREATE-INLINE": "Créer un nouveau formulaire maintenant!", + "SHOW-MORE": "Voir plus..." + }, + + "FILTER" : { + "FORMS": "Formulaires", + "FORMS-COUNT": "Il y a {{total}} formulaires", + "FORMS-ONE": "Il y a un formulaire", + "FORMS-EMPTY": "Il n'y a pas formulaires. Pour en ajouter un, cliquer sur Créer formulaire.", + "FILTER-TEXT": ", correspondant \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de formulaires correspondant à \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "Tables de décision", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION": { + "CREATE": "Créer une table de décision", + "IMPORT": "Importer une table de décision", + "CREATE-INLINE": "Créer une nouvelle table de décision maintenant!", + "SHOW-MORE": "Voir plus..." + }, + + "FILTER": { + "DECISION-TABLES": "Table de décisions", + "DECISION-TABLES-COUNT": "Il y a {{total}} tables de décision", + "DECISION-TABLES-ONE": "Il y a une table de décision", + "DECISION-TABLES-EMPTY": "Il n'y a pas de table de décisions. Pour en ajouter une, cliquer sur Créer une table de décision.", + "FILTER-TEXT": ", correspondant \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de table de décision correpondants à \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + + "APPS-LIST" : { + "TITLE" : "Définitions d'App", + "SEARCH-PLACEHOLDER": "Recherche", + "ACTION" : { + "CREATE": "Créer une App", + "IMPORT": "Importer une App", + "SHOW-MORE": "Voir plus..." + }, + + "FILTER" : { + "APPS": "Définitions d'App", + "APPS-COUNT": "Il y a {{total}} définitions d'App", + "APPS-ONE": "Il y a une définition d'App", + "APPS-EMPTY": "Il n'y a pas de définitions d'App. Pour en ajouter une, cliquer sur Créer une Définition d'App .", + "FILTER-TEXT": ", correspondant à \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "Il n'y a pas de définitions d'App correpondant à \"{{filterText}}\"", + + "NO-APPS": "Vous pouvez créer une définition d'App en publiant un paquet de modèles de processus.", + "NO-APPS-CALL-TO-ACTION": "Vous pouvez créer une définition d'App maintenant.", + "NO-APPS-NOTE": "N'oubliez pas de Publier quand vous êtes prêt à l'utiliser." + }, + + "SORT": { + "MODIFIED-ASC": "Du plus vieux", + "MODIFIED-DESC": "Dernières modifications", + "NAME-ASC": "Nom, A-Z", + "NAME-DESC": "Nom, Z-A" + } + }, + "PROCESS": { + "NAME": "Nom du Modèle", + "KEY": "Clé du Modèle", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Commentaire de version", + "ACTION": { + "DETAILS": "Voir les détails", + "EDIT": "Modifier les propriétés du modèle", + "DUPLICATE": "Dupliquer le modèle", + "EXPORT_BPMN20": "Exporter en BPMN 2.0", + "DELETE": "Supprimer le modèle", + "CREATE-CONFIRM": "Créer un nouveau modèle", + "DUPLICATE-CONFIRM": "Dupliquer le modèle", + "OPEN-IN-EDITOR": "Editeur Visuel", + "EDIT-CONFIRM": "Sauvegarder", + "DELETE-CONFIRM": "Supprimer le modèle de processus", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "FAVORITE": "Mettre en favori ce modèle" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}", + "NO-DESCRIPTION": "Ce modèle n'a pas de description. Modifier les propriétés du modèle pour en ajouter un." + }, + + "POPUP": { + "CREATE-TITLE": "Créer un nouveau modèle de processus métier", + "DUPLICATE-TITLE": "Dupliquer un modèle de processus métier", + "CREATE-DESCRIPTION": "Vous devez donner un nom à ce modèle et en même temps vous devriez en profiter pour ajouter une description. ", + "DUPLICATE-DESCRIPTION": "Vous pouvez changer le nom du nouveau modèle et en même temps vous devriez en profiter pour ajouter une description.", + "EDIT-DESCRIPTION": "Modifier les propriétés ci-dessous et ensuite appuyer sur Sauvegarder pour mettre à jour le modèle.", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer le modèle de processus \"{{name}}\"?", + "EDIT-TITLE":"Modifier les détails du modèle", + "DELETE-TITLE": "Supprimer le modèle", + "DELETE-LOADING-RELATIONS": "Vérification des usages du modèle...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "Ce modèle ne peut être supprimé car un autre modèle l'utilise:", + "DELETE-RELATIONS-DESCRIPTION": "Ce modèle ne peut être supprimé car il est utilisé par d'autres modèles:", + "DELETE-PROCESS-RELATION": "Modèle de processus", + "DELETE-FORM-RELATION": "Modèle de formulaire", + "DELETE-APP-RELATION": "Modèle d'App", + "IMPORT-DESCRIPTION": "Veuillez naviguer vers ou déposer un fichier de défnition BPMN XML avec une extension en .bpmn ou .bpmn20.xml", + "IMPORT-TITLE": "Importer un modèle de processus", + "USE-AS-NEW-TITLE": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr de vouloir utiliser la version {{version}} pour créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle d'App dans la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}' avec un identifiant interne {{id}}, créé par {{createdBy}}", + "SHARED-WITH": "Partagé avec", + "PERMISSION": "Permission", + "ACTIONS": "Actions", + "IMPORT": { + "DROPZONE": "Déposer un fichier BPMN avec une extension en .bpmn ou .bpmn20.xml", + "CANCEL-UPLOAD": "Annuler l'envoi", + "ERROR": "Une erreur s'est produite lors du traitement du fichier BPMN XML", + "NO-DROP": "Glisser/déposer n'est pas supporté" + } + }, + "ALERT": { + "EDIT-CONFIRM": "Modèle mise à jour" + }, + "ERROR": { + "NOT-FOUND": "Le modèle demandé n'existe pas." + } + }, + + "SUBPROCESS": { + "NAME": "Nom du sous-processus", + "DESCRIPTION": "Description", + "ACTION": { + "CREATE-CONFIRM": "Créer un nouveau sous-processus" + }, + "POPUP": { + "CREATE-TITLE": "Créer un nouveau sous-processus", + "CREATE-DESCRIPTION": "Vous devez donner un nom au nouveau sous-processus et en même temps vous devriez ajouter une description." + } + }, + + "CASE": { + "NAME": "Nom du Modèle", + "KEY": "Clé du Modèle", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Commentaire de Version", + "ACTION": { + "DETAILS": "Voir les détails", + "EDIT": "Modifier les propriétés du modèle", + "DUPLICATE": "Dupliquer ce modèle", + "EXPORT_CMMN": "Exporter en CMMN 1.1", + "DELETE": "Supprimer ce modèle", + "CREATE-CONFIRM": "Créer un nouveau modèle", + "DUPLICATE-CONFIRM": "Dupliquer ce modèle", + "OPEN-IN-EDITOR": "Editeur Visuel", + "EDIT-CONFIRM": "Sauvegarder", + "DELETE-CONFIRM": "Supprimer ce modèle de Cas ", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "FAVORITE": "Mettre en favori ce modèle" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Created by {{createdBy}}", + "NO-DESCRIPTION": "Ce modèle n'a pas de description. Modifier les propriétés du modèle pour en ajouter un." + }, + + "POPUP": { + "CREATE-TITLE": "Créer un nouveau modèle de Cas ", + "DUPLICATE-TITLE": "Dupliquer le modèle de Cas ", + "CREATE-DESCRIPTION": "Vous devez donner un nom au nouveau modèle et en même temps vous devriez ajouter une description.", + "DUPLICATE-DESCRIPTION": "Vous pouvez changer le nom du nouveau modèle et en même temps vous devriez en profiter pour ajouter une description.", + "EDIT-DESCRIPTION": "Modifier les propriétés ci-dessous du modèle et appuyez sur Sauvegarder pour mettre à jour le modèle.", + "DELETE-DESCRIPTION": "Êtes-vous sûr de want to supprimer the modèle de processus \"{{name}}\"?", + "EDIT-TITLE":"Edit modèle details", + "DELETE-TITLE": "Supprimer modèle", + "DELETE-LOADING-RELATIONS": "Checking modèle usage...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "This modèle cannot be deleted, because another modèle is using it:", + "DELETE-RELATIONS-DESCRIPTION": "This modèle cannot be deleted, because it is used by other models:", + "DELETE-PROCESS-RELATION": "Cas modèle", + "DELETE-FORM-RELATION": "formulaire modèle", + "DELETE-APP-RELATION": "App modèle", + "IMPORT-DESCRIPTION": "Please browse for or drop a CMMN XML definition with an .cmmn or .cmmn.xml extension", + "IMPORT-TITLE": "Import a Cas modèle", + "USE-AS-NEW-TITLE": "Use as new version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr de vouloir utiliser la version {{version}} afin de créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle à la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}' avec l'identifiant interne {{id}}, créé par {{createdBy}}", + "SHARED-WITH": "Partagé avec", + "PERMISSION": "Permission", + "ACTIONS": "Actions", + "IMPORT": { + "DROPZONE": "Déposer un fichier CMMN XML avec une extension .cmmn ou .cmmn.xml ", + "CANCEL-UPLOAD": "Annuler l'envoi", + "ERROR": "Erreur durant le traitement du fichier CMMN XML ", + "NO-DROP": "Glisser/Déposer n'est pas supporté." + } + }, + "ALERT": { + "EDIT-CONFIRM": "Modèle mis à jour" + }, + "ERROR": { + "NOT-FOUND": "Le modèle demandé n'existe pas" + } + }, + + "FORM": { + "NAME": "Nom du formulaire", + "KEY": "Clé du formulaire", + "DESCRIPTION": "Description", + "ACTION": { + "DETAILS": "Afficher les détails", + "EDIT": "Modifier les propriétés du modèle", + "DELETE": "Supprimer le formulaire", + "CREATE-CONFIRM": "Créer un nouveau formulaire", + "DUPLICATE": "Dupliquer ce formulaire", + "DUPLICATE-CONFIRM": "Dupliquer le formulaire", + "OPEN-IN-EDITOR": "Editeur de formulaire", + "EDIT-CONFIRM": "Sauvegarder", + "DELETE-CONFIRM": "Supprimer le formulaire", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version" + + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}" + }, + + "POPUP": { + "CREATE-TITLE": "Créer un nouveau formulaire", + "DUPLICATE-TITLE": "Dupliquer le formulaire", + "CREATE-DESCRIPTION": "Vous devez donner un nom au nouveau formulaire et en même temps vous devriez ajouter une description.", + "DUPLICATE-DESCRIPTION": "Vous devez donner un nom au nouveau formulaire et en même temps vous devriez ajouter une description.", + "SAVE-FORM-TITLE": "Sauvegarder le formulaire", + "EDIT-DESCRIPTION": "Modifier les propriétés ci-dessous du formulaire et ensuite appuyer sur Sauvegarder pour mettre à jour le formulaire", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer le formulaire \"{{name}}\"?", + "EDIT-TITLE":"Editer les détails du formulaire", + "DELETE-TITLE": "Supprimer le formulaire", + "USE-AS-NEW-TITLE": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr d'utiliser la version {{version}} pour créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle à la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}'avec l'identifiant interne {{id}}, créé par {{createdBy}}" + } + }, + + "DECISION-TABLE": { + "NAME": "Nom de la table de décision", + "KEY": "Clé de la table de décision", + "DESCRIPTION": "Description", + "VERSION-COMMENT": "Commentaire de Version", + "HIT-POLICY": "Hit Policy:", + "ACTION": { + "DETAILS": "Afficher les détails", + "EDIT": "Modifier les propriétés du modèle", + "SHARE": "Partager cette table de décision", + "DELETE": "Supprimer cette table de décision", + "ADD-COMMENT": "+ Ajouter un commentaire", + "CREATE-CONFIRM": "Créer une nouvelle table de décision", + "OPEN-IN-EDITOR": "Editeur de table de décision", + "EXPORT": "Exporter la table de décision", + "DELETE-CONFIRM": "Supprimer la table de décision", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "FAVORITE": "Mettre en favori cette table de décision", + "DUPLICATE": "Dupliquer cette table de décision" + }, + "DETAILS": { + "HISTORY-TITLE": "Historique", + "COMMENTS-TITLE": "Commentaires", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}" + }, + "HIT-POLICIES": { + "FIRST": "Les premiers", + "ANY": "Tous", + "UNIQUE": "Unique", + "PRIORITY": "Priorité", + "RULE ORDER": "Ordre des règles", + "OUTPUT ORDER": "Ordre de résultats", + "COLLECT": "Collecte" + }, + "COLLECT-OPERATORS": { + "SUM": "Sum", + "MIN": "Min", + "MAX": "Max", + "COUNT": "Count" + }, + "POPUP": { + "CREATE-TITLE": "Créer une nouvelle table de décision", + "CREATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle table de décision et en même temps vous devriez ajouter une description.", + "SAVE-DESCRIPTION": "Vous devez donner un nom à la nouvelle table de décision ainsi qu'une clé unique et en même temps vous devriez ajouter une description.", + "DUPLICATE-TITLE": "Dupliquer la table de décision", + "DUPLICATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle table de décision et en même temps vous devriez ajouter une description.", + "DELETE-TITLE": "Supprimer la table de décision", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer la table de décision \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "Sauvegarder la table de décision", + "IMPORT-DESCRIPTION": "Veuillez naviguer vers ou déposer un fichier de définition DMN XML avec une extension en .dmn ou .dmn.xml", + "IMPORT-TITLE": "Importer un modèle DMN ", + "IMPORT": { + "DROPZONE": "Déposer un fichier DMN XML avec une extension en a .dmn ou .dmn.xml", + "CANCEL-UPLOAD": "Annuler l'envoi", + "ERROR": "Erreurr lors du tratiement du fichier DMN XML", + "NO-DROP": "Glisser/Déposer n'est pas supporté." + }, + "USE-AS-NEW-TITLE": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "USE-AS-NEW-DESCRIPTION": "Êtes-vous sûr de vouloir utiliser la version {{version}} pour créer une nouvelle version de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "Impossibilité de restaurer le modèle à la version choisie: certains modèles référencés sont manquants car précédemment supprimés. Veuillez mettre à jour votre modèle d'App en conséquence. Modèles manquants:", + "USE-AS-NEW-UNRESOLVED-MODEL": "Modèle '{{name}}' avec l'identifiant interne {{id}}, créé par {{createdBy}}" + }, + "ALERT": { + "FAVORITE-CONFIRM": "La table de décision est maintenant en favori", + "UN-FAVORITE-CONFIRM": "La table de décision n'est plus marqué en favori" + } + }, + + "APP": { + "NAME": "Nom de la définition d'App", + "KEY": "Clé de la définition d'App", + "DESCRIPTION": "Description", + "ICON": "Icône", + "THEME": "Thème", + "GROUPS-ACCESS": "Groupes avec accès, séparés par des virgules", + "USERS-ACCESS": "Utilisateurs avec access, séparés par des virgules", + "ACTION": { + "DETAILS": "Afficher les détails", + "EDIT": "Modifier les propriétés de la définition d'App", + "DUPLICATE": "Dupliquer la définition", + "SHARE": "Partagé la définition d'App", + "DELETE": "Supprimer la définition d'App", + "CREATE-CONFIRM": "Créer une nouvelle définition d'App", + "DUPLICATE-CONFIRM": "Dupliquer la définition d'App", + "DELETE-CONFIRM": "Supprimer la définition d'App", + "USE-AS-NEW-VERSION": "Utiliser en tant que nouvelle version", + "OPEN-IN-EDITOR": "Editeur d'App", + "PUBLISH": "Publier", + "PUBLISH-CONFIRM": "Publier la définition d'App", + "SELECT-ICON": "Changer l'icône...", + "SELECT-THEME": "Change le thème...", + "EDIT-MODELS": "Editer les modèles inclus", + "EXPORT-ZIP": "Exporter la définition d'App dans un fichier zip", + "EXPORT-BAR": "Exporter la définition d'App en tant que fichier bar deployable" + + }, + "DETAILS": { + "TITLE": "Détails de la définition d'App: {{name}}", + "HISTORY-TITLE": "Historique", + "MODELS-TITLE": "Modèles inclus dans la définition d'App", + "LAST-UPDATED-BY": "Dernière modification par {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY": "Créé par {{createdBy}}", + "NO-DESCRIPTION": "La définition d'App n'a pas de description. Modifier les propriétés de la définition d'App pour en ajouter une", + "NO-MODELS-SELECTED": "Aucun modèle n'a été sélectionné pour cette App" + }, + "TITLE": { + "SELECT-ICON": "Choisir une icône d'App", + "SELECT-THEME": "Choisir des couleurs d'App", + "PREVIEW": "Prévisualiser" + + }, + "POPUP": { + "CREATE-TITLE": "Créer une nouvelle définition d'App", + "DUPLICATE-TITLE": "Dupliquer une définition d'App", + "SAVE-APP-TITLE": "Sauvegarder la définition d'App", + "SAVE-APP-SAVE-SUCCESS": "La définition d'App a été sauvé", + "CREATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle définition d'App et en même temps vous devriez ajouter une description.", + "DUPLICATE-DESCRIPTION": "Vous devez donner un nom à la nouvelle définition d'App et en même temps vous devriez ajouter une description.", + "PUBLISH-TITLE": "Publier la définition d'App", + "PUBLISH-DESCRIPTION": "Êtes-vous sûr de vouloir publier la définition d'App \"{{name}}\"? A noter que cette définition d'App sera versionné et l'App de sera mise à jour s'il existe", + "PUBLISH-FIELD": "Publier? A noter que si la publication est activé,la définition d'App sera versionné et que l'App de workflow sera mis à jour s'il existe. .", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "Votre modèle de processus \"{{modelInAppName}}\" a le même identifiant \"{{processDefinitionKey}}\" que le processus déjà déployé \"{{conflictingModelName}}\" de l'App \"{{conflictingAppName}}\". Veuillez changer la valeur de la propriété \"id\" du modèle de processus.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "Les modèles de processus sont déjà utilisés dans d'autres applications. Est ce normal ?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "App", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "App invalide: Duplication trouvé des identifians de processus (modifier la propriété \"id\" des modèles de processus mise en cause):", + "DELETE-TITLE": "Supprimer la définition d'App", + "DELETE-DESCRIPTION": "Êtes-vous sûr de vouloir supprimer la définition d'App \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "Êtes-vous sûr de vouloir supprimer la définition d'App \"{{name}}\"? A noter que la définition d'App a été déployé sur la page d'accueil des tâches et en confirmant l'App sera supprimé des pages d'accueil.", + "DELETE-CASCADE-FALSE": "Supprimer uniquement la version courante de la définition d'App (v{{version}})", + "DELETE-CASCADE-TRUE": "Supprimer aussi toutes les versions précédentes de la définition d'App", + "HAS-CUSTOM-STENCILITEM" : "Modèle \"{{modelName}}\" utilise un stencil avec des objets personnalisés de stencil. Il n'est pas possible d'utiliser ce modèle dans une définition d'App.", + "HAS-VALIDATIONERROR" : "Modèle \"{{modelName}}\" a des erreurs de validations et ne peut être ajouté à une définition d'App. Ouvrez le modèle dans l'éditeur and vérifier les détails des erreurs.", + "IMPORT-DESCRIPTION":"Veuillez naviguer ou déposer une définition d'App avec une extension en .zip", + "IMPORT-TITLE":"Importer un modèle de définition d'App ", + "IMPORT": { + "DROPZONE": "Déposer un fichier de définition d'App en .zip", + "CANCEL-UPLOAD": "Annuler l'envoi", + "RENEWIDM-IDS": "Renouveler les identifiants d'utilisateur et de groupe lors de l'importation de modèles d'étapes et BPMN. Ceci est souvent requis lors de l'importation de la définition d'application dans un environnement Flowable différent. Il essaiera de lier les étapes humaines et les tâches utilisateur au bon utilisateur et groupe dans cet environnement cible.", + "ERROR": "Une erreur s'est produite lors du traitement du fichier", + "NO-DROP": "Glisser/Déposer n'est pas supporté." + }, + "INCLUDE-MODELS-TITLE": "Modèles inclus dans la définition d'App" + }, + "ALERT": { + "DELETE-CONFIRM": "La définition d'App a été supprimé", + "PUBLISH-CONFIRM": "La définition d'App a été publié", + "PUBLISH-ERROR": "Impossible de publier la définition d'App. Veuillez vérifier la validité des références de modèles de processus" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "Ajouter une autre personne" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "Texte", + "MULTILINE-TEXT": "Texte Multiligne", + "PASSWORD": "Mot de passe", + "NUMBER": "Nombre", + "CHECKBOX": "Case à cocher", + "DATE": "Date", + "DROPDOWN": "Liste déroulante", + "RADIO": "Boutton radio", + "PEOPLE": "Personnes", + "GROUP-OF-PEOPLE": "Groupes de personnes", + "UPLOAD": "Téléchargement", + "EXPRESSION": "Expression", + "DECIMAL": "Décimal", + "HYPERLINK": "Lien Hypertexte", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS": { + "GENERAL": "Général", + "OPTIONS": "Options", + "UPLOAD-OPTIONS": "Options de téléchargement", + "ADVANCED-OPTIONS":"Avancé" + }, + "VERSION": "Version {{version}}", + "LAST-UPDATED": "Dernière modification par {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "Conception", + "OUTCOME": "Résultats" + }, + "POPUP": { + "EDIT-TITLE": "Editer le champ '{{name}}'", + "EXPRESSION-TITLE": "Editer l'expression" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(Aucune valeur de l'expression)", + "EXPRESSION-HELP": "Vous pouvez également afficher les valeurs préalablement soumises dans tout formulaire, dans le cadre du texte, en utilisant une notation de référence comme ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "Vous pouvez utiliser une expression pour remplir dynamiquement des options, par exemple en référençant une variable telle que ${optionsVariable}. L'expression doit aboutir à un objet java (java.util.List avec des objets Option) ou à sa représentation json." + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "Sélectionner un groupe..", + "PERSON": "Sélectionner une personne.." + }, + "COMPONENT": { + "LABEL": "Libellé:", + "OVERRIDEID": "Surcharger l'identifiant?", + "ID": "Identifiant:", + "PLACEHOLDER": "Paramètre fictif:", + "OPTIONS": "Options", + "RADIO-BUTTON-DEFAULT": "Option 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "Veuillez en choisir un...", + "DROPDOWN-EMPTY-VALUE-HELP": "Ceci est l'option pour la 'valeur à vide'. Le sélectionner lors de l'utilisation signifie 'aucune valeur' ou 'vide'. Ceci est autorisé pour les champs optionnels mais pas pour les champs obligatoires.", + "OPTIONS-EXPRESSION": "Expression des options:", + "OPTIONS-EXPRESSION-ENABLED": "Activer l'expression des options", + "REQUIRED": "Requis", + "READONLY": "Lecture seul", + "EXPRESSION": "Expression", + "ADD-OPTION": "+ Ajouter une nouvelle option", + "UPLOAD-ALLOW-MULTIPLE": "Autoriser le téléchargement de plusieurs fichiers", + "SIZE": "Taille", + "MAX-LENGTH":"Longueur maximale:", + "MIN-LENGTH":"Longueur minimum:", + "PASSWORD-UNMASK-OPTION": "Option de masquage / démasquage de mot de passe", + "HYPERLINK-URL": "URL line hypertexte", + "REGEX-PATTERN":"Regex standard", + "MASK":{ + "TITLE":"Masque de saisie", + "EXAMPLES":{ + "TITLE":"Exemples:", + "NUMBER":"tous les nombres", + "LETTER":"toutes les lettres", + "NUMBERORLETTER":"N'importe quel nombre ou lettre", + "OPTIONAL":"Rendre le masque optionel (non valide)", + "PHONE":"Téléphone" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "Vous pouvez définir plusieurs résultats pour cette tâche. Une fois la tâche complété, les utilisateurs choisissent la variable de résultat qui pourra ensuite être utilisé en tant que tel dans le processus.", + "NO-OUTCOMES-OPTION": "Ne pas utiliser les résultats personnalisés, afficher uniquement le boutton 'Terminer'", + "OUTCOMES-OPTION": "Utiliser des résultats personnalisés pour ce formulaire.", + "POSSIBLE-OUTCOMES": "Résultats possibles", + "NEW-OUTCOME-PLACEHOLDER": "Entrer un nouveau résultat", + "ADD": "Ajouter un résultat", + "REMOVE": "Retirer" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "Indéfini" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "Modifier la colonne d'entrée", + "INPUT-DESCRIPTION": "Sélectionnez la variable d'entrée comme entrée pour la colonne", + "OUTPUT-TITLE": "Modifier la colonne de sortiee", + "OUTPUT-DESCRIPTION": "Sélectionnez une variable de sortie existante ou créez une nouvelle", + "EXPRESSION-LABEL": "Libellé de colonne:", + "EXPRESSION-PLACEHOLDER": "Entrer un libellé optionnel", + "EXPRESSION-VARIABLE-NAME": "Nom de variable:", + "EXPRESSION-VARIABLE-TYPE": "Type de variable:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "Entrer un nom de variable", + "OUTPUT-NEW-VARIABLE-ID": "Variable ID:", + "OUTPUT-NEW-VARIABLE-TYPE": "Type de variable:", + "COMPLEX-EXPRESSION-LABEL": "Expression complexe :", + "ALLOWED-VALUES": "Valeurs autorisées (optionel):", + "OUTPUT-VALUES": "Valeurs de résultats ", + "OUTPUT-VALUES-OPTIONAL": "(optionel):", + "OUTPUT-VALUES-NOT-OPTIONAL": "(drag rows for priority / output order):" + } + }, + "BUTTON-ACTIONS-LABEL": "Actions", + "BUTTON-ADD-INPUT-LABEL": "Ajouter une entrée", + "BUTTON-ADD-OUTPUT-LABEL": "Ajouter une sortie", + "BUTTON-ADD-RULE-LABEL": "Ajouter une règle", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "Déplacer vers le haut", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "Déplacer vers le bas", + "BUTTON-REMOVE-RULE-LABEL": "Retirer une règle", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "Toutes les expressions d'entrée et de sorties doivent référencer un champs de formulaire ou une variable.", + "SAVE-CONFIRM": "La table de décision '{{name}}' a été sauvegardée" + } + }, + + "TOUR": { + "WELCOME-TITLE": "Bienvenue, {{userName}}", + "WELCOME-CONTENT": "Ceci est une introduction à l'éditeur Flowable. Les prochaines étapes vous guideront dans les différentes sections de l'application pour vous aider à démarrer. Appuyez sur la touche ESC pour arrêter à tout moment." , + "PALETTE-TITLE": "La Palette", + "PALETTE-CONTENT": "Tous les éléments disponibles pour créer un processus métier peuvent être trouvées ici. Ils sont organisés dans des groupes logiques. Pour ouvrir un groupe, cliquez simplement dessus:", + "CANVAS-TITLE": "Le Canevas", + "CANVAS-CONTENT": "C'est l'espace de travail sur lequel vous créez votre processus métier. Faites glisser des éléments de la palette sur la gauche et déposez-les sur le canevas pour commencer la modélisation..", + "DRAGDROP-TITLE": "Exemple de glisser-déposer", + "DRAGDROP-CONTENT": "Voici un exemple de comment commencer avec la modélisation:", + "PROPERTIES-TITLE": "Propriétés", + "PROPERTIES-CONTENT": "Ici, vous pouvez configurer les propriétés des éléments constitutif de votre processus métier. Il suffit de sélectionner l'élément sur le canevas et ses propriétés seront affichées. Cliquez sur la propriété si vous souhaitez l'éditer", + "TOOLBAR-TITLE": "La Barre d'outils", + "TOOLBAR-CONTENT": "Toutes les actions peuvent être trouvées ici: sauvegarder ou valider un modèle, copier et coller des éléments d'un processus, etc. Survolez les boutons pour obtenir une description pour une action.", + "END-TITLE": "La Fin", + "END-CONTENT": "C'est tout! Vous pouvez maintenant commencer à modéliser vos processus. Si vous avez des questions, n'hésitez pas à les poser sur le Forum Flowable " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "Tutorial sur les points de courbure", + "DESCRIPTION" : "Lorsque vous connectez les étapes d'un processus l'une à l'autre en utilisant le flux de séquence (les flèches entre les étapes d'un processus), vous pourriez constater que ces flux de séquence se croisent ou que vous souhaitez les répartir différemment. Pour ce faire, vous pouvez ajouter ou supprimer un point de courbure vers ou à partir d'un flux de séquence.

Comme indiqué ci-dessous dans l'image, cliquez d'abord sur 'Ajouter un point de courbure', puis cliquez sur un flux de séquence pour ajoutez-le. Notez que le flux de séquence vous montrera une indication subtile en vert pour montrer que le point de flexion peut être ajouté là.

La suppression d'un point de courbure suit à nouveau un motif similaire: cliquez sur le bouton 'supprimer le point de courbure' et cliquez sur le bouton courber le point pour le retirer à nouveau." + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "Sauvegarder", + "ACTION.SAVE-AND-CLOSE" : "Sauvegarder et fermer l'éditeur", + "ACTION.SEND" : "Envoyer", + "ACTION.CANCEL" : "Annuler", + "ACTION.SELECT" : "Sélectionner", + "ACTION.ADD" : "Ajouter", + "ACTION.REMOVE" : "Retirer", + "ACTION.MOVE.UP" : "Déplacer l'entrée vers le haut", + "ACTION.MOVE.DOWN" : "Déplacer l'entrée vers le base", + + "TOOLBAR.ACTION.CLOSE" : "Fermer l'éditeur et revenir vers la page de vue d'ensemble", + "TOOLBAR.ACTION.SAVE" : "Sauvegarder le modèle", + "TOOLBAR.ACTION.VALIDATE" : "Valider le modèle", + "TOOLBAR.ACTION.CUT" : "Couper (sélectionner un ou plusieurs éléments dans votre processus métier)", + "TOOLBAR.ACTION.COPY" : "Copier (sélectionner un ou plusieurs éléments dans votre processus métier)", + "TOOLBAR.ACTION.PASTE" : "Coller", + "TOOLBAR.ACTION.DELETE" : "Supprimer l'élément sélectionné", + "TOOLBAR.ACTION.UNDO" : "Annuler", + "TOOLBAR.ACTION.REDO" : "Refaire", + "TOOLBAR.ACTION.ZOOMIN" : "Zoom avant", + "TOOLBAR.ACTION.ZOOMOUT" : "Zoom arrière", + "TOOLBAR.ACTION.ZOOMACTUAL" : "Zoom en taille réelle", + "TOOLBAR.ACTION.ZOOMFIT" : "Zoom pour s'adapter", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "Ajouter un point de courbure sur le flux de séquence sélectionné", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "Retirer un point de courbure sur le flux de séquence sélectionné", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "Aligner le modèle horizontalement", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "Aligner modèle verticalement", + "TOOLBAR.ACTION.SAMESIZE" : "Même taille", + "TOOLBAR.ACTION.HELP": "Démarrer la visite guidée", + "TOOLBAR.ACTION.FEEDBACK": "Faire un retour d'information", + + "FORM_TOOLBAR.ACTION.SAVE" : "Sauvegarder le modèle", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "Sauvegarder la définition d'App", + + "BUTTON.ACTION.DELETE.TOOLTIP": "Supprimer un élément from the modèle", + "BUTTON.ACTION.MORPH.TOOLTIP": "Changer un type d'élément", + + "ELEMENT.AUTHOR" : "Auteur", + "ELEMENT.DATE_CREATED" : "Date de creation", + + "PROPERTY.REMOVED" : "supprimé", + "PROPERTY.EMPTY" : "Aucune valeur", + "PROPERTY.PROPERTY.EDIT.TITLE" : "Changer la valeur pour ", + + "PROPERTY.FEEDBACK.TITLE" : "Veuillez ajouter vos commentaires", + + "PROPERTY.ASSIGNMENT.TITLE" : "Tâche", + "PROPERTY.ASSIGNMENT.TYPE" : "Type", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "Identity store", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "Valeurs fixées", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "Personne assignée", + "PROPERTY.ASSIGNMENT.MATCHING" : "Utiliser ↑ et ↓ pour sélectionner et appuyer sur Entrée pour confirmer ou utiliser la souris", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "Choisir une personne assignée", + "PROPERTY.ASSIGNMENT.EMPTY" : "Aucune personne assignée sélectionné", + "PROPERTY.ASSIGNMENT.NONE" : "Aucune ...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Recherche un utilisateur", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Recherche un groupe", + "PROPERTY.ASSIGNMENT.SEARCH": "Recherche: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "Personne assignée {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} utilisateurs candidats", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "Utilisateurs candidats", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} groupes candidats", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "Groupes candidats", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "Utilisateur {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "Utilisateur {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "Champs {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "Initiateur de processus", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "Tâche", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "Aucun utilisateur candidat sélectionné...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "Aucun groupe candidat sélectionné...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "Assigné à l'initiateur de processus", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "Assigné à un seul utilisateur", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "Utilisateurs candidats", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "Groupes candidats", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "Autoriser l'initiateur de processus à terminer la tâche", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} execution listeners", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "No execution listeners configured", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "Événement", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "Class", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "Entrer un classname", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Entrer une delegate expression", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "Aucun execution listener sélectionné", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "Nom", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "valeur de chaîne", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Entrer une valeur de chaîne", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Entrer une valeur de chaîne", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "Aucun champ sélectionné", + + "PROPERTY.FIELDS" : "{{length}} champs", + "PROPERTY.FIELDS.EMPTY" : "Aucun champ sélectionné", + "PROPERTY.FIELDS.NAME" : "Nom", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.FIELDS.STRINGVALUE" : "valeur de chaîne", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "Entrer a string value", + "PROPERTY.FIELDS.STRING" : "String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "Entrer a string", + "PROPERTY.FIELDS.IMPLEMENTATION" : "Implémentation", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "Aucun objet de données configuré", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "Entrer une id", + "PROPERTY.DATAPROPERTIES.NAME" : "Nom", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "Entrer a nom", + "PROPERTY.DATAPROPERTIES.TYPE" : "Type", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "Entrer une value (optionnel)", + "PROPERTY.DATAPROPERTIES.VALUE" : "Valeur par défaut", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} propriétés de formulaire", + "PROPERTY.FORMPROPERTIES.EMPTY" : "Aucune propriété du formulaire sélectionné", + "PROPERTY.FORMPROPERTIES.ID" : "Identifiant", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "Entrer un identifiant", + "PROPERTY.FORMPROPERTIES.NAME" : "Nom", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.FORMPROPERTIES.TYPE" : "Type", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "Pattern de Date", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "Entrer un Pattern de date", + "PROPERTY.FORMPROPERTIES.VALUES" : "Valeurs", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "Aucune valeur d'énumération sélectionné", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Identifiant", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "Nom", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "Entrer un identifiant pour la valeur", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "Entrer un nom pour la valeur", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "Expression", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "Variable", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "Entrer une variable", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Entrer une default", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "Requise", + "PROPERTY.FORMPROPERTIES.READABLE" : "Lecture", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "Ecriture", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}} paramètres d'entrée", + "PROPERTY.INPARAMETERS.EMPTY" : "Aucun paramètres d'entrée configuré", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}} paramètres de sortie", + "PROPERTY.OUTPARAMETERS.EMPTY" : "No paramètres de sortie configuré", + + "PROPERTY.PARAMETER.SOURCE" : "Source", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "Entrer une source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "Expression de source", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "Entrer une expression de source", + "PROPERTY.PARAMETER.TARGET" : "Cible (Target)", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "Entrer une Cible", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "Expression de cible", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "Entrer une expression de cible", + "PROPERTY.PARAMETER.EMPTY" : "Aucun paramètre sélectionné", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "Aucune référence sélectionnée", + "PROPERTY.PROCESSREFERENCE.TITLE" : "Référence de processus", + "PROPERTY.PROCESSREFERENCE.ERROR.SUBPROCESS" : "Une erreur a été rencontré lors du chargement des processus. Veuillez réessayer ultérieurement", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "Chargement des processus...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "Ce répertoire ne contient pas de processus", + + "PROPERTY.FORMREFERENCE.EMPTY" : "Aucune reference sélectionnée", + "PROPERTY.FORMREFERENCE.TITLE" : "Référence de formulaire", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "Référence vers un formulaire", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "Une erreur a été rencontré lors du chargement des formulaires. Veuillez réessayer ultérieurement", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "Chargement des formulaires...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "Ce répertoire ne contient pas de formulaires", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}} task listeners", + "PROPERTY.TASKLISTENERS.EMPTY" : "Aucun task listeners configuré", + "PROPERTY.TASKLISTENERS.EVENT" : "Événements", + "PROPERTY.TASKLISTENERS.CLASS" : "Class", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "Entrer un classname", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Entrer une delegate expression", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "Aucun task listener sélectionné", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "Nom", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "Entrer un nom", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Entrer une expression", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "valeur de chaîne", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Entrer une valeur de chaîne", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "Entrer a string", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "Implémentation", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "Aucun champ sélectionné", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} événement listeners", + "PROPERTY.EVENTLISTENERS.EMPTY" : "Aucun événement listeners configured", + "PROPERTY.EVENTLISTENERS.EVENTS": "Événements", + "PROPERTY.EVENTLISTENERS.RETHROW": "Renvoyer l'événement?", + "PROPERTY.EVENTLISTENERS.CLASS" : "Class", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "Entrer un classname", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Entrer une delegate expression", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "Type de l'entité", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "Entrer le type de l'entité ", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Renvoyer le type d'événement", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "Code d'erreur", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "Entrer un code d'erreur ", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "Nom du Message", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "Entrer le nom du message", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "Nom du Signal", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "Entrer le nom du signal", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "Aucun événement listener sélectionné", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} définitions de signal", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "Aucune définitions de signal configuré", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "Instance de processus ", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Identifiant", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "Nom", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Portée", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} definitions de message", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "Aucune définitions de message configuré", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Identifiant", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "Nom", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "Aucune ordre de flux de séquence défini", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "Ordre flux de séquence order défini", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "Aucun flux de séquence sortant trouvé.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "Définir l'ordre dans lequel le flux de séquence doit être évalué:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "Flux de séquence vers {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "condition du flux de séquence ", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "Condition expression", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "Aucune condition définie", + + "PROPERTY.DUEDATE.EMPTY" : "Aucune date d'échéance", + "PROPERTY.DUEDATE.DEFINED" : "Date d'échéance définie", + "PROPERTY.DUEDATE.TITLE" : "Date d'échéance", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "Expression de la Date d'échéance ", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "Aucune date d'échéance", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "Définition de l'expression ", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "Durée fixe après la création de la tâche", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "Basé sur le champ", + + "MODEL.SAVE.TITLE" : "Sauvegarder le modèle", + "MODEL.VALIDATE.TITLE" : "Validation des résultats", + "MODEL.NAME" : "Nom", + "MODEL.KEY" : "Clé", + "MODEL.DESCRIPTION" : "Description", + "MODEL.SAVE.NEWVERSION" : "Sauvegarder ceci en tant que nouvelle version? Cela signifie que vous pouvez toujours revenir à une version précédente", + "MODEL.SAVE.COMMENT" : "Commentaire", + "MODEL.SAVE.SAVING" : "Sauvegarder du modèle", + "MODEL.LASTMODIFIEDDATE" : "Dernière sauvegarde", + "MODEL.SAVE.ERROR": "Erreur innatendue: impossible de sauvegarder le modèle", + "MODEL.VALIDATIONERRORS": "Notez que le modèle contient des erreurs de validation. Cela signifie que le modèle ne peut pas être déployé sur le Moteur Flowable dans son état actuel.", + "MODEL.CONFLICT.WRITE": "Impossible de sauvegarder le modèle: '{{userFullName}}' a éffectué des changements à ce modèle", + "MODEL.CONFLICT.WRITE.OPTIONS": "Sélectionner une option pour résoudre ce conflit:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "Surcharger l'autre modèle", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "Ignorer mes modifications", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "Sauvegarder en tant que nouveau modèle", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "Créer une nouvelle version", + "MODEL.CONFLICT.SAVEAS" : "Sauvegarder en tant que:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "Une activité est sur le point d'être exécutée en compensation d'une autre activité. L'événement cible l'activité qui va être exécutée par compensation", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "Une activité a été terminée avec succès", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "Une activité a reçu un événement d'erreur. Expédié avant que l'erreur réelle n'ait été reçue par l'activité", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "Une nouvelle adhésion a été créée", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "Une seule adhésion a été supprimée", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "Toutes les adhésions au groupe concerné ont été supprimées. Aucun évènement individuel ne sera envoyé pour des raisons de performances", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "Une tâche a été assignée. Ceci est executé en même temps qu'un événement ENTITY_UPDATED", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "Une tâche a été effectuée. Déployé avant que l'entité de tâche ne soit supprimée", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "Lorsqu'une erreur BPMN a été lancée, mais elle n'a pas été prise dans le processus", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "Une nouvelle variable a été créé", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "Une variable existante a été supprimé", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "Une variable existante a été mis à jour", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "Aucune référence sélectionné", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "Référence de la table de décision", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "Une erreur s'est produite lors du chargement des tables de décision. Veuillez réessayer ultérieurement", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "Chargement des tables de décision...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "Ce répertoire ne contient pas de tables de décision", + + "PROPERTY.CASEREFERENCE.EMPTY" : "Aucune référence sélectionné", + "PROPERTY.CASEREFERENCE.TITLE" : "Réference du modèle de cas", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "Une erreur a été rencontré lors du chargement des modèles de cas. Veuillez réessayer ultérieurement", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "Chargement des modèles de cas...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "Ce répertoire ne contient pas de modèle de cas" +} diff --git a/zbf-admin/src/main/resources/static/designer/i18n/pt-BR.json b/zbf-admin/src/main/resources/static/designer/i18n/pt-BR.json new file mode 100644 index 0000000..e519db8 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/i18n/pt-BR.json @@ -0,0 +1,818 @@ +{ + "GENERAL":{ + "MAIN-TITLE":"Editor Flowable", + "NAVIGATION":{ + "PROCESSES":"Processos", + "FORMS":"Formulários", + "DECISION-TABLES":"Tabelas de Decisão", + "APPS":"Aplicativos" + }, + "TITLE":{ + "SELECT-GROUP":"Selecionar grupo", + "MATCHING-GROUPS":"Grupos correspondentes", + "FILTER":"Filtro", + "HISTORY":"Histórico" + }, + "ACTION":{ + "LOGOUT":"Sair", + "RETURN-TO-LIST":"Mostrar todas as definições", + "CANCEL":"Cancelar", + "CLOSE":"Fechar", + "EDIT":"Editar", + "SAVE":"Salvar", + "OPEN":"Abrir", + "OK":"Ok", + "CONFIRM":"Confirmar", + "CONFIRM-AND-CLOSE":"Confirmar e fechar", + "NEW-FORM":"Novo formulário", + "CREATE-FORM":"Criar formulário", + "NEW-DECISION-TABLE":"Nova tabela de decisão", + "CREATE-DECISION-TABLE":"Criar tabela de decisão" + }, + "MESSAGE":{ + "SELECT-GROUP-HELP":"Use ↑ e ↓ para selecionar e pressione Enter para confirmar", + "PEOPLE-NO-MATCHING-RESULTS":"Nenhum usuário correspondente foi encontrado", + "GROUP-NO-MATCHING-RESULTS":"Nenhum grupo correspondente foi encontrado", + "GROUP-SOURCE-TYPE":"Grupo de origem", + "GROUP-SOURCE-SEARCH-OPTION":"Pesquisa por grupo", + "GROUP-SOURCE-FIELD-OPTION":"Campo de formulário" + } + }, + "EDITOR":{ + "POPUP":{ + "UNSAVED-CHANGES":{ + "TITLE":"Você tem alterações não salvas", + "DESCRIPTION":"O que deseja fazer com as suas alterações não salvas?", + "ACTION":{ + "SAVE":"Salvar as alterações", + "DISCARD":"Descartar as alterações", + "CONTINUE":"Continuar editando" + } + } + } + }, + "PROCESS-LIST":{ + "TITLE":"Modelo de processo de negócios", + "SEARCH-PLACEHOLDER":"Pesquisar", + "ACTION":{ + "CREATE":"Criar processo", + "IMPORT":"Importar processo" + }, + "FILTER":{ + "PROCESSES":"Modelos de processo", + "PROCESSES-COUNT":"Existem {{total}} modelos de processos", + "PROCESSES-ONE":"Há um modelo de processo", + "PROCESSES-EMPTY":"Não há modelo de processo criado ainda. Você pode projetar modelos de processos, formulários de usuário e então empacotá-los em um aplicativo de processo. O primeiro passo é criar um modelo de processo:", + "PROCESSES-BPMN-HINT":"Crie um modelo BPMN usando o Editor Visual de BPMN.", + "PROCESSES-BPMN-IMPORT-HINT":"Você também pode importar modelos BPMN existentes.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há modelo de processo correspondente a \"{{filterText}}\"", + "RECENT":"Recente", + "RECENT-COUNT":"{{total}} modelos usados recentemente", + "RECENT-ONE":"Um modelo usado recentemente", + "RECENT-EMPTY":"Nenhum modelo usado recentemente" + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Modificado por último", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "FORMS-LIST":{ + "TITLE":"Formulários", + "SEARCH-PLACEHOLDER":"Pesquisar", + "ACTION":{ + "CREATE":"Criar formulário", + "CREATE-INLINE":"Crie um novo formulário agora!", + "SHOW-MORE":"Mostrar mais..." + }, + "FILTER":{ + "FORMS":"Formulários", + "FORMS-COUNT":"Existem {{total}} formulários", + "FORMS-ONE":"Existe um formulário", + "FORMS-EMPTY":"Não existem formulários. Para adicionar um, clique em criar formulário.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há formulário correspondente a \"{{filterText}}\"" + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Último Modificado", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "DECISION-TABLES-LIST":{ + "TITLE":"Tabelas de Decisão", + "SEARCH-PLACEHOLDER":"Busca", + "ACTION":{ + "CREATE":"Criar Tabela de Decisão", + "IMPORT":"Importar tabela de decisão", + "CREATE-INLINE":"Criar uma nova tabela de decisão agora!", + "SHOW-MORE":"Mostrar mais..." + }, + "FILTER":{ + "DECISION-TABLES":"Tabelas de decisão", + "DECISION-TABLES-COUNT":"Existem {{total}} tabelas de decisão", + "DECISION-TABLES-ONE":"Há uma tabela de decisão", + "DECISION-TABLES-EMPTY":"Não há tabela de decisão. Para adicionar uma, clique em criar tabela de decisão.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há tabela de decisão correspondente a \"{{filterText}}\"" + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Modificado por último", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "APPS-LIST":{ + "TITLE":"Definições de Aplicativo", + "SEARCH-PLACEHOLDER":"Pesquisar", + "ACTION":{ + "CREATE":"Criar Aplicativo", + "IMPORT":"Importar aplicativo", + "SHOW-MORE":"Mostrar mais..." + }, + "FILTER":{ + "APPS":"Definições de Aplicativo", + "APPS-COUNT":"Existem {{total}} definições de aplicativos", + "APPS-ONE":"Há uma definição de aplicativo", + "APPS-EMPTY":"Não há definições de aplicativo. Para adicionar uma, clique em criar definição de Aplicativo.", + "FILTER-TEXT":", correspondente a \"{{filterText}}\"", + "FILTER-TEXT-EMPTY":"Não há definições de aplicativo correspondentes a \"{{filterText}}\"", + "NO-APPS":"Você pode criar uma definição de Aplicativo, através da publicação de um pacote de modelos de processo.", + "NO-APPS-CALL-TO-ACTION":"Você pode criar uma definição de Aplicativo agora.", + "NO-APPS-NOTE":"Lembre-se de publicá-lo quando você estiver pronto para usá-lo." + }, + "SORT":{ + "MODIFIED-ASC":"Mais antigo", + "MODIFIED-DESC":"Modificado por último", + "NAME-ASC":"Nome, A-Z", + "NAME-DESC":"Nome, Z-A" + } + }, + "PROCESS":{ + "NAME":"Nome do modelo", + "KEY":"Chave do modelo", + "DESCRIPTION":"Descrição", + "VERSION-COMMENT":"Comentários da versão", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades do modelo", + "DUPLICATE":"Duplicar este modelo", + "EXPORT_BPMN20":"Exportar para BPMN 2.0", + "DELETE":"Excluir este modelo", + "CREATE-CONFIRM":"Criar novo modelo", + "DUPLICATE-CONFIRM":"Duplique o modelo", + "OPEN-IN-EDITOR":"Editor Visual", + "EDIT-CONFIRM":"Salvar", + "DELETE-CONFIRM":"Excluir o modelo de processo", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "FAVORITE":"Adicionar este modelo aos favoritos" + }, + "DETAILS":{ + "HISTORY-TITLE":"Histórico", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}", + "NO-DESCRIPTION":"Este modelo não tem descrição. Modifique as propriedades do modelo para adicionar uma" + }, + "POPUP":{ + "CREATE-TITLE":"Criar um novo modelo de processo de negócio", + "DUPLICATE-TITLE":"Duplicar o modelo de processo de negócio", + "CREATE-DESCRIPTION":"Você precisa dar um nome para o novo modelo e você pode querer também adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-DESCRIPTION":"Você pode alterar o nome para o novo modelo e você pode querer alterar a descrição ao mesmo tempo.", + "EDIT-DESCRIPTION":"Altere qualquer uma das propriedades modelo abaixo e em seguida pressione Salvar para atualizar o modelo.", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir o modelo de processo \"{{name}}\"?", + "EDIT-TITLE":"Editar detalhes do modelo", + "DELETE-TITLE":"Excluir o modelo", + "DELETE-LOADING-RELATIONS":"Verificar o uso de modelo...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE":"Este modelo não pode ser excluído, porque o outro modelo está a usá-lo:", + "DELETE-RELATIONS-DESCRIPTION":"Este modelo não pode ser excluído, porque ele é usado por outros modelos:", + "DELETE-PROCESS-RELATION":"Modelos de processo", + "DELETE-FORM-RELATION":"Modelo de formulário", + "DELETE-APP-RELATION":"Modelo de aplicativo", + "IMPORT-DESCRIPTION":"Por favor, procure ou arraste e solte uma definição de BPMN XML com um arquivo .bpmn ou .bpmn20.xml", + "IMPORT-TITLE":"Importar um modelo de processo", + "USE-AS-NEW-TITLE":"Use como nova versão", + "USE-AS-NEW-DESCRIPTION":"Tem certeza que quer usar a versão {{version}} para criar uma nova versão de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR":"Não foi possível restaurar completamente o modelo de aplicativo para a versão escolhida: alguns modelos referenciados estão ausentes poque foram excluído no passado. Por favor, atualize o modelo de aplicativo em conformidade. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL":"Modelo '{{name}}' com id interno {{id}}, criado por {{createdBy}}", + "SHARED-WITH":"Compartilhado com", + "PERMISSION":"Permissão", + "ACTIONS":"Ações", + "IMPORT":{ + "DROPZONE":"Arraste e solte um arquivo .bpmn ou bpmn20.xml", + "CANCEL-UPLOAD":"Cancelar o upload", + "ERROR":"Erro ao processar o arquivo XML BPMN", + "NO-DROP":"Arrastar e soltar não suportado" + } + }, + "ALERT":{ + "EDIT-CONFIRM":"Modelo atualizado" + }, + "ERROR":{ + "NOT-FOUND":"O modelo solicitado não existe" + } + }, + "SUBPROCESS":{ + "NAME":"Nome do subprocesso", + "DESCRIPTION":"Descrição", + "ACTION":{ + "CREATE-CONFIRM":"Criar novo subprocesso" + }, + "POPUP":{ + "CREATE-TITLE":"Criar um novo subprocesso", + "CREATE-DESCRIPTION":"Você precisa dar um nome para o novo subprocesso e você pode querer adicionar uma descrição ao mesmo tempo." + } + }, + "FORM":{ + "NAME":"Nome do formulário", + "KEY":"Chave do formulário", + "DESCRIPTION":"Descrição", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades do modelo", + "DELETE":"Excluir este formulário", + "CREATE-CONFIRM":"Criar novo formulário", + "DUPLICATE-CONFIRM":"Duplicar o formulário", + "OPEN-IN-EDITOR":"Editor de formulário", + "EDIT-CONFIRM":"Salvar", + "DELETE-CONFIRM":"Excluir Formulário", + "USE-AS-NEW-VERSION":"Usar como uma nova versão" + }, + "DETAILS":{ + "HISTORY-TITLE":"Histórico", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}" + }, + "POPUP":{ + "CREATE-TITLE":"Criar novo formulário", + "DUPLICATE-TITLE":"Duplicar o formulário", + "CREATE-DESCRIPTION":"Você precisa dar um nome para o novo formulário e você pode querer adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-DESCRIPTION":"Você precisa dar um nome para o novo formulário e você pode querer adicionar uma descrição ao mesmo tempo.", + "SAVE-FORM-TITLE":"Salvar formulário", + "EDIT-DESCRIPTION":"Altere qualquer uma das propriedades do formulário abaixo e em seguida pressione Salvar para atualizar o formulário.", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir o formulário \"{{name}}\"?", + "EDIT-TITLE":"Editar detalhes do formulário", + "DELETE-TITLE":"Excluir Formulário", + "USE-AS-NEW-TITLE":"Usar como uma nova versão", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "USE-AS-NEW-DESCRIPTION":"Tem certeza que quer usar a versão {{version}} para criar uma nova versão de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR":"Não foi possível restaurar completamente o modelo de aplicativo para a versão escolhida: alguns modelos referenciados estão ausentes poque foram excluído no passado. Por favor, atualize o modelo de aplicativo em conformidade. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL":"Modelo '{{name}}' com id interno {{id}}, criado por {{createdBy}}" + } + }, + "DECISION-TABLE":{ + "NAME":"Nome da tabela de decisão", + "KEY":"Chave de tabela de decisão", + "DESCRIPTION":"Descrição", + "VERSION-COMMENT":"Comentários da versão", + "HIT-POLICY":"Acertar política:", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades do modelo", + "SHARE":"Compartilhar esta tabela de decisão", + "DELETE":"Excluir esta tabela de decisão", + "ADD-COMMENT":"+ Adicionar comentário", + "CREATE-CONFIRM":"Criar nova tabela de decisão", + "OPEN-IN-EDITOR":"Editor de tabela de decisão", + "EXPORT":"Exportar tabela de decisão", + "DELETE-CONFIRM":"Excluir a tabela de decisão", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "FAVORITE":"Adicionar esta tabela de decisão aos favoritos", + "DUPLICATE":"Duplicar esta tabela de decisão" + }, + "DETAILS":{ + "HISTORY-TITLE":"Histórico", + "COMMENTS-TITLE":"Comentários", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}" + }, + "HIT-POLICIES":{ + "FIRST":"Primeiro (passagem única)", + "ANY":"Qualquer (passagem única)" + }, + "POPUP":{ + "CREATE-TITLE":"Criar uma nova tabela de decisão", + "CREATE-DESCRIPTION":"Você precisa dar um nome para a nova tabela de decisão, e você pode querer adicionar uma descrição ao mesmo tempo.", + "SAVE-DESCRIPTION":"Você precisa dar um nome e uma chave exclusiva para a nova tabela de decisão, e você pode querer adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-TITLE":"Duplicar uma tabela de decisão", + "DUPLICATE-DESCRIPTION":"Você pode dar um nome para a tabela de decisão, e pode querer alterar a descrição ao mesmo tempo.", + "DELETE-TITLE":"Excluir a tabela de decisão", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir a tabela de decisão \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE":"Salvar a tabela de decisão", + "IMPORT-DESCRIPTION":"Por favor, procure ou arraste e solte uma definição de DMN XML com uma extensão .dmn ou .dmn.xml", + "IMPORT-TITLE":"Importar um modelo DMN", + "IMPORT":{ + "DROPZONE":"Arraste e solte um arquivo DMN XML com extensão .dmn ou .dmn.xml", + "CANCEL-UPLOAD":"Cancelar o carregamento", + "ERROR":"Erro ao processar o arquivo XML DMN", + "NO-DROP":"Arrastar e soltar não suportado" + }, + "USE-AS-NEW-TITLE":"Usar como uma nova versão", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "USE-AS-NEW-DESCRIPTION":"Tem certeza que quer usar a versão {{version}} para criar uma nova versão de \"{{name}}\"?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR":"Não foi possível restaurar completamente o modelo de aplicativo para a versão escolhida: alguns modelos referenciados estão ausentes poque foram excluído no passado. Por favor, atualize o modelo de aplicativo em conformidade. Modelos faltantes:", + "USE-AS-NEW-UNRESOLVED-MODEL":"Modelo '{{name}}' com id interno {{id}}, criado por {{createdBy}}" + }, + "ALERT":{ + "FAVORITE-CONFIRM":"Esta tabela de decisão agora está adicionada aos favoritos", + "UN-FAVORITE-CONFIRM":"Esta tabela de decisão já não está mais nos favoritos" + } + }, + "APP":{ + "NAME":"Nome de definição do Aplicativo", + "KEY":"Chave de definição do aplicativo", + "DESCRIPTION":"Descrição", + "ICON":"Ícone", + "THEME":"Tema", + "GROUPS-ACCESS":"Acesso de grupos, separado por vírgulas", + "USERS-ACCESS":"Acesso de usuários, separado por vírgulas", + "ACTION":{ + "DETAILS":"Mostrar detalhes", + "EDIT":"Modificar propriedades de definição do aplicativo", + "DUPLICATE":"Duplique esta aplicação", + "SHARE":"Compartilhar esta definição de aplicativo", + "DELETE":"Excluir esta definição de aplicativo", + "CREATE-CONFIRM":"Criar nova definição de aplicativo", + "DUPLICATE-CONFIRM":"Duplicar a definição de aplicativo", + "DELETE-CONFIRM":"Excluir a definição de aplicativo", + "USE-AS-NEW-VERSION":"Usar como uma nova versão", + "OPEN-IN-EDITOR":"Editor de Aplicativo", + "PUBLISH":"Publicar", + "PUBLISH-CONFIRM":"Publicar a definição de aplicativo", + "SELECT-ICON":"Mudar ícone...", + "SELECT-THEME":"Alterar tema...", + "EDIT-MODELS":"Editar modelos incluídos", + "EXPORT-ZIP":"Exportar definição de aplicativo como um arquivo zip", + "EXPORT-BAR":"Exportar definição de aplicativo como um arquivo de implantação bar" + }, + "DETAILS":{ + "TITLE":"Detalhes da definição do aplicativo: {{name}}", + "HISTORY-TITLE":"Histórico", + "MODELS-TITLE":"Modelos incluídos na definição do aplicativo", + "LAST-UPDATED-BY":"Última atualização feita por {{lastUpdatedBy}} - {{lastUpdated | dateformat}}", + "CREATED-BY":"Criado por {{createdBy}}", + "NO-DESCRIPTION":"Esta definição de aplicativo não tem descrição. Modifique as propriedades de definição do aplicativo para adicionar uma", + "NO-MODELS-SELECTED":"Não há modelos selecionados para este aplicativo" + }, + "TITLE":{ + "SELECT-ICON":"Selecione o ícone para o aplicativo", + "SELECT-THEME":"Selecione as cores para o aplicativo", + "PREVIEW":"Visualizar" + }, + "POPUP":{ + "CREATE-TITLE":"Criar uma nova definição de aplicativo", + "DUPLICATE-TITLE":"Duplicar uma definição de aplicativo", + "SAVE-APP-TITLE":"Salvar a definição de aplicativo", + "SAVE-APP-SAVE-SUCCESS":"Definição de aplicativo salva", + "CREATE-DESCRIPTION":"Você precisa dar um nome para a nova definição do aplicativo, e você pode querer também adicionar uma descrição ao mesmo tempo.", + "DUPLICATE-DESCRIPTION":"Você pode dar um nome para a nova definição de aplicativo, e pode querer alterar a descrição ao mesmo tempo.", + "PUBLISH-TITLE":"Publicar a definição de aplicativo", + "PUBLISH-DESCRIPTION":"Tem certeza que deseja publicar a definição do aplicativo \"{{name}}\"? Note que esta definição de aplicativo será versionada e o aplicativo de worflow será atualizado se existente.", + "PUBLISH-FIELD":"Publicar? Observe que, se a publicação estiver habilitado, esta definição de aplicativo será versionada e o aplicativo de workflow será atualizado se já existente.", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT":"Seu modelo de processo \"{{modelInAppName}}\" tem o mesmo identificador de \"{{processDefinitionKey}}\" com o processo previamente implantado \"{{conflictingModelName}}\" do aplicativo \"{{conflictingAppName}}\". Por favor, altere a propriedade \"id\" do modelo de processo para algo diferente.", + "PUBLISH-ERROR-PROCESS-ALREADY-USED":"Os seguintes modelos de processos já são utilizados em outro aplicativo. Isto está correto?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP":"Aplicativo", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS":"Aplicativo inválido: identificadores de processo duplicados foram encontrados (altere a propriedade de \"id\" dos modelos de processo com id duplicados):", + "DELETE-TITLE":"Excluir a definição de aplicativo", + "DELETE-DESCRIPTION":"Tem certeza que deseja excluir a definição do aplicativo \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME":"Tem certeza que deseja excluir a definição do aplicativo \"{{name}}\"? Note que esta definição de aplicativo foi implantada como uma tarefa de página inicial, o aplicativo será removido da página inicial.", + "DELETE-CASCADE-FALSE":"Somente apagar a versão atual desta definição de aplicativo (v{{version}})", + "DELETE-CASCADE-TRUE":"Também excluir todas as versões anteriores desta definição de aplicativo", + "HAS-CUSTOM-STENCILITEM":"O modelo \"{{modelName}}\" usa um estêncil com itens de estêncil personalizado. Não é possível usar este modelo em uma definição de aplicativo.", + "HAS-VALIDATIONERROR":"O modelo \"{{modelName}}\" tem erros de validação e não pode ser adicionado a uma definição de aplicativo. Abra o modelo no editor para ver mais detalhes sobre o(s) erro(s) de validação.", + "IMPORT-DESCRIPTION":"Por favor, procure ou arraste e solte uma definição de aplicativo com a extensão .zip", + "IMPORT-TITLE":"Importar um modelo de definição de aplicativo", + "IMPORT":{ + "DROPZONE":"Arraste e solte um arquivo de definição de aplicativo .zip", + "CANCEL-UPLOAD":"Cancelar o carregamento", + "RENEWIDM-IDS":"Renove os identificadores de usuário e grupo ao importar os passos e modelos BPMN. Isso é muitas vezes necessário ao importar a definição de aplicativo em um ambiente Flowable diferente. Isto vai tentar vincular o etapas humanas e tarefas de usuário para usuário e grupo correto no ambiente de destino.", + "ERROR":"Erro ao processar o arquivo de definição de aplicativo", + "NO-DROP":"Arrastar e soltar não suportado" + }, + "INCLUDE-MODELS-TITLE":"Modelos incluídos na definição do aplicativo" + }, + "ALERT":{ + "DELETE-CONFIRM":"Definição de Aplicativo excluída", + "PUBLISH-CONFIRM":"A definição de aplicativo foi publicada", + "PUBLISH-ERROR":"Não foi possível publicar a definição de aplicativo. Por favor, verifique a validade dos modelos de processos referenciados" + } + }, + "SHARE-INFO":{ + "ACTION":{ + "ADD":"Adicionar outra pessoa" + } + }, + "FORM-BUILDER":{ + "PALLETTE":{ + "TEXT":"Texto", + "PASSWORD": "Senha", + "MULTILINE-TEXT":"Texto de multilinhas", + "NUMBER":"Número", + "CHECKBOX":"Caixa de seleção", + "DATE":"Data", + "DROPDOWN":"Seleção simples", + "RADIO":"Botões de opção", + "PEOPLE":"Pessoas", + "GROUP-OF-PEOPLE":"Grupo de pessoas", + "UPLOAD":"Carregar", + "EXPRESSION":"Expressão", + "DECIMAL":"Decimal", + "HYPERLINK":"Hiperlink", + "SPACER": "Spacer", + "HORIZONTAL-LINE": "Horizontal line", + "HEADLINE": "Headline", + "HEADLINE-WITH-LINE":"Headline" + }, + "TABS":{ + "GENERAL":"Geral", + "OPTIONS":"Opções", + "UPLOAD-OPTIONS":"Opções de carregamento", + "ADVANCED-OPTIONS":"Avançado" + }, + "VERSION":"Versão {{version}}", + "LAST-UPDATED":"Última atualização feita por {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE":{ + "DESIGN":"Desenho", + "OUTCOME":"Resultados" + }, + "POPUP":{ + "EDIT-TITLE":"Editar o campo '{{name}}'", + "EXPRESSION-TITLE":"Editar expressão" + }, + "MESSAGE":{ + "EMPTY-EXPRESSION":"(Nenhuma expressão)", + "EXPRESSION-HELP":"Você também pode exibir valores anteriormente apresentados sob qualquer formulário, como parte do texto, referenciando-os usando uma notação como segue ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "Você pode usar uma expressão para preencher dinamicamente opções, por exemplo, fazendo referência a uma variável como esta ${optionsVariable}. A expressão precisa resultar em um objeto java (java.util.List com objetos Option) ou sua representação json." + }, + "LABEL":{ + "FUNCTIONAL-GROUP":"Selecione o grupo..", + "PERSON":"Selecione a pessoa.." + }, + "COMPONENT":{ + "LABEL":"Rótulo:", + "OVERRIDEID":"Substituir o id?", + "ID":"Id:", + "PLACEHOLDER":"Marcador:", + "OPTIONS":"Opções", + "RADIO-BUTTON-DEFAULT":"Opção 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION":"Por favor, escolha uma...", + "DROPDOWN-EMPTY-VALUE-HELP":"Esta é a opção 'valor vazio'. Selecionar isto em tempo de execução significa dizer 'sem valor' ou 'vazio'. Isto é permitido para campos opcionais, mas não permitido para campos obrigatórios.", + "OPTIONS-EXPRESSION": "Expressão de opções:", + "OPTIONS-EXPRESSION-ENABLED": "Ativar expressão de opções", + "REQUIRED":"Obrigatório", + "READONLY":"Somente leitura", + "EXPRESSION":"Expressão", + "ADD-OPTION":"+ Adicionar uma nova opção", + "UPLOAD-ALLOW-MULTIPLE":"Permitir o upload de vários arquivos", + "MAX-LENGTH":"Comprimento máximo:", + "MIN-LENGTH":"Comprimento mínimo:", + "PASSWORD-UNMASK-OPTION": "opção de mascaramento/desmascarar senha", + "HYPERLINK-URL": "URL de hiperlink", + "REGEX-PATTERN":"Padrão Regex", + "MASK":{ + "TITLE":"Máscara de entrada", + "EXAMPLES":{ + "TITLE":"Exemplos:", + "NUMBER":"Qualquer número", + "LETTER":"Qualquer letra", + "NUMBERORLETTER":"Qualquer letra ou número", + "OPTIONAL":"Torna a máscara opcional (não valida)", + "PHONE":"Dinheiro" + } + } + }, + "OUTCOMES":{ + "DESCRIPTION":"Você pode definir várias saídas para esta tarefa. Quando concluir uma tarefa, os usuários seleciona uma das saídas disponíveis, que podem ser usados em, por exemplo, em uma condição futura no processo.", + "NO-OUTCOMES-OPTION":"Não use as saídas personalizados, apenas mostre um botão 'Completar'.", + "OUTCOMES-OPTION":"Use saídas personalizados para este formulário.", + "POSSIBLE-OUTCOMES":"Saídas possíveis", + "NEW-OUTCOME-PLACEHOLDER":"Insira uma nova saída", + "ADD":"Adicionar saída", + "REMOVE":"Excluir" + } + }, + "DECISION-TABLE-EDITOR":{ + "EMPTY-MESSAGES":{ + "NO-VARIABLE-SELECTED":"Indefinido" + }, + "POPUP":{ + "EXPRESSION-EDITOR":{ + "INPUT-TITLE":"Editar a coluna de entrada", + "INPUT-DESCRIPTION":"Selecione a variável de entrada como entrada para a coluna", + "OUTPUT-TITLE":"Editar a coluna de saída", + "OUTPUT-DESCRIPTION":"Selecione uma variável de saída existente ou crie uma nova", + "EXPRESSION-LABEL":"Rótulo de coluna:", + "EXPRESSION-PLACEHOLDER":"Digite um rótulo opcional", + "EXPRESSION-VARIABLE-NAME":"Nome da variável:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER":"Entre com um nome de variável", + "OUTPUT-NEW-VARIABLE-ID":"ID da variável:", + "OUTPUT-NEW-VARIABLE-TYPE":"Tipo da variável:" + } + }, + "BUTTON-ADD-INPUT-LABEL":"Adicionar entrada", + "BUTTON-ADD-OUTPUT-LABEL":"Adicionar saída", + "BUTTON-ADD-RULE-LABEL":"Adicionar regra", + "BUTTON-MOVE-RULE-UPWARDS-LABEL":"Mover para cima", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL":"Mover para baixo", + "BUTTON-REMOVE-RULE-LABEL":"Excluir Regra", + "ALERT":{ + "EXPRESSION-VARIABLE-REQUIRED-ERROR":"Todas as expressões de entrada e saídas devem fazer referência a uma variável ou o campo do formulário.", + "SAVE-CONFIRM":"Tabela de decisão '{{name}}' salva" + } + }, + "TOUR":{ + "WELCOME-TITLE":"Bem-vindo, {{userName}}", + "WELCOME-CONTENT":"Esta uma pequena turnê do editor Flowable. Os próximos passos irão guiá-lo através de diferentes seções do aplicativo. Pressione a tecla ESC para parar a turnê a qualquer momento.", + "PALETTE-TITLE":"A paleta", + "PALETTE-CONTENT":"Todas as construções disponíveis para criar um processo de negócios podem ser encontradas aqui. Elas estão organizadas em grupos lógicos. Para abrir um grupo simplesmente clicar nele:", + "CANVAS-TITLE":"O Canvas", + "CANVAS-CONTENT":"Este é o espaço de trabalho no qual você cria seu processo de negócios. Arraste os elementos da paleta da esquerda e solte-os sobre esta tela para iniciar a modelagem.", + "DRAGDROP-TITLE":"Exemplo de arrastar e soltar", + "DRAGDROP-CONTENT":"Aqui está um exemplo de como você deve iniciar com a modelagem:", + "PROPERTIES-TITLE":"Propriedades", + "PROPERTIES-CONTENT":"Aqui você pode configurar as propriedades de uma construção de processo de negócios. Basta selecionar o item na tela e suas propriedades serão mostradas. Clique na propriedade se você quiser editá-la", + "TOOLBAR-TITLE":"A barra de ferramentas", + "TOOLBAR-CONTENT":"Todas as ações podem ser encontradas aqui: salvar ou validar um modelo, copiar e colar partes de um processo e assim por diante. Passe o mouse sobre os botões para obter uma descrição de uma ação.", + "END-TITLE":"Fim", + "END-CONTENT":"É isso! Agora você pode começar a modelagem de seus processos. Se você tiver alguma dúvida, não hesite em perguntar em Fórum Flowable " + }, + "FEATURE-TOUR":{ + "BENDPOINT":{ + "TITLE":"Tutorial de ponto curva", + "DESCRIPTION":"Quando você estiver se conectando as etapas do processo com o as outras usando o fluxo de sequência (as setas entre as etapas do processo), você pode achar que esses fluxo de sequência se cruzam, ou gostaria de organizá-los de forma diferente. Para fazer isso, você pode adicionar ou remover um ponto de curva para/de um fluxo de sequência.

Como mostrado abaixo na foto, primeiro, clique o 'Adicionar ponto de curva' e, em seguida, clique em um fluxo de sequência para adicioná-lo. Observe que o fluxo de sequência irá mostrar-lhe uma indicação sutil em verde para mostrar o ponto de curva pode ser adicionado lá.

Remover um ponto de curva novo segue um padrão semelhante: clique no botão 'remover ponto de curva' e clique em ponto de curva para removê-lo novamente." + } + }, + "ACTION.OK":"Ok", + "ACTION.SAVE":"Salvar", + "ACTION.SAVE-AND-CLOSE":"Salve e feche o editor", + "ACTION.SEND":"Enviar", + "ACTION.CANCEL":"Cancelar", + "ACTION.SELECT":"Selecione", + "ACTION.ADD":"Adicionar", + "ACTION.REMOVE":"Excluir", + "ACTION.MOVE.UP":"Mover a entrada para cima", + "ACTION.MOVE.DOWN":"Mover a entrada para baixo", + "TOOLBAR.ACTION.CLOSE":"Fechar o editor e voltar para a página de visão geral", + "TOOLBAR.ACTION.SAVE":"Salvar o modelo", + "TOOLBAR.ACTION.VALIDATE":"Validar o modelo", + "TOOLBAR.ACTION.CUT":"Recortar (selecione um ou mais elementos em seu processo de negócios)", + "TOOLBAR.ACTION.COPY":"Copiar (selecione um ou mais elementos em seu processo de negócios)", + "TOOLBAR.ACTION.PASTE":"Colar", + "TOOLBAR.ACTION.DELETE":"Excluir o elemento selecionado", + "TOOLBAR.ACTION.UNDO":"Desfazer", + "TOOLBAR.ACTION.REDO":"Refazer", + "TOOLBAR.ACTION.ZOOMIN":"Aumentar Zoom", + "TOOLBAR.ACTION.ZOOMOUT":"Diminuir o zoom", + "TOOLBAR.ACTION.ZOOMACTUAL":"Voltar para o tamanho real", + "TOOLBAR.ACTION.ZOOMFIT":"Enquadrar", + "TOOLBAR.ACTION.BENDPOINT.ADD":"Adicionar ponto de curva ao fluxo de sequência selecionado", + "TOOLBAR.ACTION.BENDPOINT.REMOVE":"Remover ponto de curva do fluxo de sequência selecionado", + "TOOLBAR.ACTION.ALIGNHORIZONTAL":"Alinhar o modelo horizontalmente", + "TOOLBAR.ACTION.ALIGNVERTICAL":"Alinhar o modelo verticalmente", + "TOOLBAR.ACTION.SAMESIZE":"Mesmo tamanho", + "TOOLBAR.ACTION.HELP":"Iniciar uma visita guiada", + "TOOLBAR.ACTION.FEEDBACK":"Fornecer feedback", + "FORM_TOOLBAR.ACTION.SAVE":"Salvar o modelo", + "APP_DEFINITION_TOOLBAR.ACTION.SAVE":"Salvar a definição de aplicativo", + "BUTTON.ACTION.DELETE.TOOLTIP":"Excluir o elemento do modelo", + "BUTTON.ACTION.MORPH.TOOLTIP":"Alterar o tipo do elemento", + "ELEMENT.AUTHOR":"Autor", + "ELEMENT.DATE_CREATED":"Data de criação", + "PROPERTY.REMOVED":"removido", + "PROPERTY.EMPTY":"Nenhum valor", + "PROPERTY.PROPERTY.EDIT.TITLE":"Altere o valor para ", + "PROPERTY.FEEDBACK.TITLE":"Por favor, nos envie seu feedback", + "PROPERTY.ASSIGNMENT.TITLE":"Atribuição", + "PROPERTY.ASSIGNMENT.TYPE":"Tipo", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE":"Identidades", + "PROPERTY.ASSIGNMENT.TYPE.STATIC":"Valores fixos", + "PROPERTY.ASSIGNMENT.ASSIGNEE":"Responsável", + "PROPERTY.ASSIGNMENT.MATCHING":"Use ↑ e ↓ para selecionar e pressione Enter para confirmar ou use o mouse", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER":"Insira um candidato", + "PROPERTY.ASSIGNMENT.EMPTY":"Nenhuma atribuição selecionada", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY":"Designado {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY":"{{length}} Usuários candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS":"Usuários candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY":"{{length}} Grupos candidatos", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS":"Grupos de candidatos", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY":"Usuário {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY":"Usuário {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY":"Campo {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY":"Iniciador do processo", + "PROPERTY.ASSIGNMENT.IDM.TYPE":"Atribuição", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS":"Nenhum usuário candidato selecionado...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS":"Nenhum grupo candidato selecionados...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR":"Atribuído ao iniciador do processo", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER":"Atribuído a um único usuário", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS":"Usuários candidatos", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS":"Grupos de candidatos", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE":"Permitir que o iniciador do processo complete a tarefa", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY":"{{length}} ouvintes da execução", + "PROPERTY.EXECUTIONLISTENERS.EMPTY":"Nenhum ouvinte de execução configurado", + "PROPERTY.EXECUTIONLISTENERS.EVENT":"Evento", + "PROPERTY.EXECUTIONLISTENERS.CLASS":"Classe", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER":"Digite um nome de classe", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION":"Expressão", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION":"Expressão de atribuição", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER":"Insira uma expressão de atribuição", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED":"Nenhum ouvinte de execução selecionado", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME":"Nome", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION":"Expressão", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE":"Valor da string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER":"Insira um valor da string", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING":"String", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER":"Entre com o texto", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION":"Implementação", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY":"Nenhum campo selecionado", + "PROPERTY.FIELDS":"{{length}} campos", + "PROPERTY.FIELDS.EMPTY":"Nenhum campo selecionado", + "PROPERTY.ASSIGNMENT.NONE" : "Nenhum...", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "Pesquisar usuário", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "Pesquisar grupo", + "PROPERTY.ASSIGNMENT.SEARCH": "Pesquisa: ", + "PROPERTY.FIELDS.NAME":"Nome", + "PROPERTY.FIELDS.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.FIELDS.EXPRESSION":"Expressão", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.FIELDS.STRINGVALUE":"Valor da string", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER":"Insira um valor da string", + "PROPERTY.FIELDS.STRING":"String", + "PROPERTY.FIELDS.STRING.PLACEHOLDER":"Entre com o texto", + "PROPERTY.FIELDS.IMPLEMENTATION":"Implementação", + "PROPERTY.FORMPROPERTIES.VALUE":"{{length}} propriedades de formulário", + "PROPERTY.FORMPROPERTIES.EMPTY":"Não há propriedades de formulário selecionadas", + "PROPERTY.FORMPROPERTIES.ID":"Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER":"Entre com um id", + "PROPERTY.FORMPROPERTIES.NAME":"Nome", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.FORMPROPERTIES.TYPE":"Tipo", + "PROPERTY.FORMPROPERTIES.DATEPATTERN":"Padrão de data", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER":"Digite um padrão de data", + "PROPERTY.FORMPROPERTIES.VALUES":"Valores", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY":"Nenhum valor válido (enum) foi selecionado", + "PROPERTY.FORMPROPERTIES.VALUES.ID":"Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME":"Nome", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER":"Digite o id de um valor", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER":"Digite o nome do valor", + "PROPERTY.FORMPROPERTIES.EXPRESSION":"Expressão", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.FORMPROPERTIES.VARIABLE":"Variável", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER":"Insira uma variável", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "default", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "Insira uma default", + "PROPERTY.FORMPROPERTIES.REQUIRED":"Obrigatório", + "PROPERTY.FORMPROPERTIES.READABLE":"Possibilita Leitura", + "PROPERTY.FORMPROPERTIES.WRITABLE":"Possibilita Escrita", + "PROPERTY.INPARAMETERS.VALUE":"{{length}} parâmetros de entrada", + "PROPERTY.INPARAMETERS.EMPTY":"Nenhum parâmetro de entrada configurado", + "PROPERTY.OUTPARAMETERS.VALUE":"{{length}} parâmetros de saída", + "PROPERTY.OUTPARAMETERS.EMPTY":"Nenhum parâmetro de saída configurado", + "PROPERTY.PARAMETER.SOURCE":"Origem", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER":"Insira uma origem", + "PROPERTY.PARAMETER.SOURCEEXPRESSION":"Expressão de origem", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER":"Insira uma expressão de origem", + "PROPERTY.PARAMETER.TARGET":"Destino", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER":"Insira um destino", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "Expressão de destino", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "Insira uma expressão de destino", + "PROPERTY.PARAMETER.EMPTY":"Nenhum parâmetro selecionado", + "PROPERTY.SUBPROCESSREFERENCE.EMPTY":"Nenhuma referência selecionada", + "PROPERTY.SUBPROCESSREFERENCE.TITLE":"Referência de subprocesso recolhida", + "PROPERTY.SUBPROCESSREFERENCE.ERROR.SUBPROCESS":"Houve um erro ao carregar os subprocessos. Tente novamente mais tarde", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.LOADING":"Carregando subprocessos...", + "PROPERTY.SUBPROCESSREFERENCE.SUBPROCESS.EMPTY":"Esta pasta não contém subprocessos", + "PROPERTY.FORMREFERENCE.EMPTY":"Nenhuma referência selecionada", + "PROPERTY.FORMREFERENCE.TITLE":"Formulário de referência", + "PROPERTY.FORMREFERENCE.DESCRIPTION":"Referência a um formulário", + "PROPERTY.FORMREFERENCE.ERROR.FORM":"Houve um erro ao carregar o formulário. Tente novamente mais tarde", + "PROPERTY.FORMREFERENCE.FORM.LOADING":"Carregando formulários...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY":"Esta pasta não contém formulários", + "PROPERTY.TASKLISTENERS.VALUE":"{{length}} ouvintes de tarefa", + "PROPERTY.TASKLISTENERS.EMPTY":"Nenhum ouvintes tarefa configurado", + "PROPERTY.TASKLISTENERS.EVENT":"Evento", + "PROPERTY.TASKLISTENERS.CLASS":"Classe", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER":"Digite um nome de classe", + "PROPERTY.TASKLISTENERS.EXPRESSION":"Expressão", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION":"Expressão de atribuição", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER":"Insira uma expressão de atribuição", + "PROPERTY.TASKLISTENERS.UNSELECTED":"Nenhum ouvinte de tarefas selecionado", + "PROPERTY.TASKLISTENERS.FIELDS.NAME":"Nome", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER":"Digite um nome", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION":"Expressão", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER":"Insira uma expressão", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE":"Valor da string", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER":"Insira um valor da string", + "PROPERTY.TASKLISTENERS.FIELDS.STRING":"String", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER":"Entre com o texto", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION":"Implementação", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY":"Nenhum campo selecionado", + "PROPERTY.EVENTLISTENERS.DISPLAY":"{{length}} ouvintes de evento", + "PROPERTY.EVENTLISTENERS.EMPTY":"Nenhum ouvintes de evento configurado", + "PROPERTY.EVENTLISTENERS.EVENTS":"Eventos", + "PROPERTY.EVENTLISTENERS.RETHROW":"Relançar o evento?", + "PROPERTY.EVENTLISTENERS.CLASS":"Classe", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER":"Digite um nome de classe", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION":"Expressão de atribuição", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER":"Insira uma expressão de atribuição", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE":"Tipo de entidade", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER":"Entre com um tipo de entidade", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE":"Relançar o tipo de evento", + "PROPERTY.EVENTLISTENERS.ERRORCODE":"Código de erro", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER":"Entre com um código de erro", + "PROPERTY.EVENTLISTENERS.MESSAGENAME":"Nome da mensagem", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER":"Entre com um nome de mensagem", + "PROPERTY.EVENTLISTENERS.SIGNALNAME":"Nome do sinal", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER":"Entre com o nome do sinal", + "PROPERTY.EVENTLISTENERS.UNSELECTED":"Nenhum ouvinte de evento selecionado", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}} lifecycle listeners", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "No lifecycle listeners configured", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "Event", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "Source state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "Target state", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "Class", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "Enter a classname", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "Delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "Enter a delegate expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "No task listener selected", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "Name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "Enter a name", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "Expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "Enter an expression", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "String value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "Enter a string value", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "String", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "Enter a string", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "Implementation", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "No Field selected", + "PROPERTY.SIGNALDEFINITIONS.DISPLAY":"{{length}} definições de sinal", + "PROPERTY.SIGNALDEFINITIONS.EMPTY":"Nenhuma definição de sinal configurada", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL":"Global", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE":"Instâncias de processos", + "PROPERTY.SIGNALDEFINITIONS.ID":"Id", + "PROPERTY.SIGNALDEFINITIONS.NAME":"Nome", + "PROPERTY.SIGNALDEFINITIONS.SCOPE":"Escopo", + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY":"{{length}} definições de mensagem", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY":"Nenhuma definição de mensagem configurada", + "PROPERTY.MESSAGEDEFINITIONS.ID":"Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME":"Nome", + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY":"Nenhuma ordem de fluxo de sequência determinada", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY":"Conjunto de ordem de fluxo de sequência", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND":"Não foi encontrado nenhum fluxo de sequência de saída.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION":"Defina a ordem em que o fluxo de sequência precisa ser analisado:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE":"Fluxo de sequência para {{targetType}} {{targetTitle}}", + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE":"Condição de fluxo de sequência", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC":"Expressão de condição", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY":"Nenhum conjunto de condição", + "PROPERTY.DUEDATE.EMPTY":"Sem data de vencimento", + "PROPERTY.DUEDATE.DEFINED":"Data de vencimento definida", + "PROPERTY.DUEDATE.TITLE":"Data de vencimento", + "PROPERTY.DUEDATE.EXPRESSION-LABEL":"Expressões de data de vencimento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE":"Sem data de vencimento", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION":"Definição de expressão", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC":"Duração fixa após a criação da tarefa", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD":"Com base no campo", + "MODEL.SAVE.TITLE":"Salvar modelo", + "MODEL.VALIDATE.TITLE":"Resultados de validação", + "MODEL.NAME":"Nome", + "MODEL.KEY":"Chave", + "MODEL.DESCRIPTION":"Descrição", + "MODEL.SAVE.NEWVERSION":"Salvar como uma nova versão? Isto significa que você pode sempre voltar para uma versão anterior", + "MODEL.SAVE.COMMENT":"Comentário", + "MODEL.SAVE.SAVING":"Salvando modelo", + "MODEL.LASTMODIFIEDDATE":"Salvo pela última vez em", + "MODEL.SAVE.ERROR":"Erro inesperado: não foi possível salvar o modelo", + "MODEL.VALIDATIONERRORS":"Observe que o modelo contem erros de validação. Isto significa que o modelo não pode ser implantado no motor Flowable em seu estado atual.", + "MODEL.CONFLICT.WRITE":"Não foi possível salvar modelo: '{{userFullName}}' há mudanças para este modelo", + "MODEL.CONFLICT.WRITE.OPTIONS":"Selecione uma opção para resolver este conflito:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE":"Substituir outro modelo", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES":"Descartar minhas alterações", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS":"Salvar como novo modelo", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION":"Criar uma nova versão", + "MODEL.CONFLICT.SAVEAS":"Salvar como:", + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP":"Uma atividade está prestes a ser executado como uma compensação para outra atividade. O evento destina-se a atividade que está prestes a ser executado para compensação", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP":"Uma atividade foi concluída com sucesso", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP":"Uma atividade recebeu um evento de erro. Expedido antes que o erro real tenha sido recebido pela atividade", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP":"Um nova subscrição foi criada", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP":"Um único subscrição foi removida", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP":"Todas as subscrições no grupo relacionado foram excluídas. Nenhum evento individual será despachados por razões de desempenho", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP":"Uma tarefa foi atribuída. Isto é lançado como um evento ENTITY_UPDATED", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP":"Uma tarefa foi concluída. Expedida antes da entidade tarefa ser excluída", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP":"Quando um erro de BPMN foi acionado, mas não foi detectado dentro do processo", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP":"Foi criada uma nova variável", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP":"Uma variável existente foi excluída", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP":"Uma variável existente foi atualizada", + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY":"Nenhuma referência selecionada", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE":"Referência de tabela de decisão", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM":"Houve um erro ao carregar as tabelas de decisão. Tente novamente mais tarde", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING":"Carregando tabelas de decisão...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY":"Esta pasta não contém tabelas de decisão" +} diff --git a/zbf-admin/src/main/resources/static/designer/i18n/zh-CN.json b/zbf-admin/src/main/resources/static/designer/i18n/zh-CN.json new file mode 100644 index 0000000..0415bc3 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/i18n/zh-CN.json @@ -0,0 +1,2736 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable编辑器", + "NAVIGATION" : { + "PROCESSES": "流程", + "CASEMODELS": "案例模型", + "FORMS": "表单", + "DECISION-TABLES": "决策表", + "APPS": "应用程序" + }, + "TITLE": { + "SELECT-GROUP" :"选择组", + "MATCHING-GROUPS": "匹配组", + "FILTER": "过滤", + "HISTORY": "历史" + }, + "ACTION": { + "LOGOUT": "退出", + "DASHBOARD": "Dashboard", + "RETURN-TO-LIST": "显示所有定义", + "CANCEL": "取消", + "CLOSE": "关闭", + "EDIT": "编辑", + "SAVE": "保存", + "OPEN": "打开", + "OK": "Ok", + "CONFIRM": "确认", + "CONFIRM-AND-CLOSE": "确认并且关闭", + "NEW-FORM": "新表单", + "CREATE-FORM": "创建表单", + "NEW-DECISION-TABLE": "新决策表", + "CREATE-DECISION-TABLE": "创建决策表" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "使用 ↑ 和 ↓ 选择并按回车确认", + "PEOPLE-NO-MATCHING-RESULTS": "没有找到匹配的用户", + "GROUP-NO-MATCHING-RESULTS": "没有找到匹配的组", + "GROUP-SOURCE-TYPE": "组源", + "GROUP-SOURCE-SEARCH-OPTION": "组搜索", + "GROUP-SOURCE-FIELD-OPTION": "表单字段" + }, + "OTHERS" : { + "PROCESS" : "流程", + "PROCESS_NAVIGATOR" : "流程导航", + "NO_STRUCTURAL_ELEMENTS_USED" : "未使用结构元素。" + } + }, + + "BPMN" : { + "TITLE": "BPMN 2.0标准工具", + "DESCRIPTION" : "BPMN流程编辑器", + "PROPERTYPACKAGES" : { + "PROCESS_IDPACKAGE" : { + "PROCESS_ID" : { + "TITLE" : "流程标识", + "DESCRIPTION" : "进程定义的唯一标识符。" + } + }, + "OVERRIDEIDPACKAGE" : { + "OVERRIDEID" : { + "TITLE" : "主键ID", + "DESCRIPTION" : "元素的唯一标识" + } + }, + "NAMEPACKAGE" : { + "NAME" : { + "TITLE" : "名称", + "DESCRIPTION" : "BPMN元素的描述名称." + } + }, + "DOCUMENTATIONPACKAGE" : { + "DOCUMENTATION" : { + "TITLE" : "描述信息", + "DESCRIPTION" : "BPMN元素的描述信息" + } + }, + "CATEGORYPACKAGE" : { + "CATEGORYDEFINITION" : { + "TITLE" : "分类", + "DESCRIPTION" : "BPMN元素的分类." + } + }, + "PROCESS_AUTHORPACKAGE" : { + "PROCESS_AUTHOR" : { + "TITLE" : "流程作者", + "DESCRIPTION" : "流程定义的作者." + } + }, + "PROCESS_VERSIONPACKAGE" : { + "PROCESS_VERSION" : { + "TITLE" : "流程版本字符串(仅备注)", + "DESCRIPTION" : "文档的目的为版本标识" + } + }, + "PROCESS_HISTORYLEVELPACKAGE" : { + "PROCESS_HISTORYLEVEL" : { + "TITLE" : "为此流程定义设置特定的历史级别", + "DESCRIPTION" : "为此流程定义设置特定的历史级别" + } + }, + "ISEXECUTABLEPACKAGE" : { + "ISEXECUTABLE" : { + "TITLE" : "是否可执行", + "DESCRIPTION" : "这个流程是可执行的吗?" + } + }, + "PROCESS_POTENTIALSTARTERUSERPACKAGE" : { + "PROCESS_POTENTIALSTARTERUSER" : { + "TITLE" : "流程启动者", + "DESCRIPTION" : "哪个用户,可以启动流程?" + } + }, + "PROCESS_POTENTIALSTARTERGROUPPACKAGE" : { + "PROCESS_POTENTIALSTARTERGROUP" : { + "TITLE" : "流程启动者组", + "DESCRIPTION" : "哪个组,可以启动流程?" + } + }, + "PROCESS_NAMESPACEPACKAGE" : { + "PROCESS_NAMESPACE" : { + "TITLE" : "目标命名空间", + "DESCRIPTION" : "流程定义的目标命名空间" + } + }, + "PROCESS_ISEAGEREXECUTIONFETCHPACKAGE" : { + "ISEAGEREXECUTIONFETCH" : { + "TITLE" : "即时执行抓取", + "DESCRIPTION" : "是否为该流程定义启用即时执行抓取" + } + }, + "ASYNCHRONOUSDEFINITIONPACKAGE" : { + "ASYNCHRONOUSDEFINITION" : { + "TITLE" : "异步", + "DESCRIPTION" : "定义异步的活动" + } + }, + "DATAPROPERTIESPACKAGE" : { + "DATAPROPERTIES" : { + "TITLE" : "数据对象", + "DESCRIPTION" : "数据对象属性的定义" + } + }, + "EXCLUSIVEDEFINITIONPACKAGE" : { + "EXCLUSIVEDEFINITION" : { + "TITLE" : "独占任务", + "DESCRIPTION" : "定义排它的活动" + } + }, + "EXECUTIONLISTENERSPACKAGE" : { + "EXECUTIONLISTENERS" : { + "TITLE" : "执行监听器", + "DESCRIPTION" : "活动、流程、流程跳转,开始、结事事件的监听器" + } + }, + "TASKLISTENERSPACKAGE" : { + "TASKLISTENERS" : { + "TITLE" : "任务监听器", + "DESCRIPTION" : "人工任务的监听器" + } + }, + "EVENTLISTENERSPACKAGE" : { + "EVENTLISTENERS" : { + "TITLE" : "事件监听器", + "DESCRIPTION" : "监听Flowable引擎的任何发生的事件. 同样可能是任何抛出的信号、信息、出错的事件。" + } + }, + "USERTASKASSIGNMENTPACKAGE" : { + "USERTASKASSIGNMENT" : { + "TITLE" : "分配用户", + "DESCRIPTION" : "分配任务给用户" + } + }, + "FORMPROPERTIESPACKAGE" : { + "FORMPROPERTIES" : { + "TITLE" : "动态表单属性", + "DESCRIPTION" : "定义带有属性列表的表单" + } + }, + "FORMKEYDEFINITIONPACKAGE" : { + "FORMKEYDEFINITION" : { + "TITLE" : "表单的标识", + "DESCRIPTION" : "表单的Key(指向关联的表单)" + } + }, + "FORMFIELDVALIDATIONPACKAGE" : { + "FORMFIELDVALIDATION" : { + "TITLE" : "验证表单字段", + "DESCRIPTION" : "验证表单提交上的表单字段。(允许的值是“true”、“false”或表达式)" + } + }, + "DUEDATEDEFINITIONPACKAGE" : { + "DUEDATEDEFINITION" : { + "TITLE" : "到期时间", + "DESCRIPTION" : "用户任务到期时间" + } + }, + "PRIORITYDEFINITIONPACKAGE" : { + "PRIORITYDEFINITION" : { + "TITLE" : "优先级", + "DESCRIPTION" : "用户任务的优先级" + } + }, + "SERVICETASKCLASSPACKAGE" : { + "SERVICETASKCLASS" : { + "TITLE" : "类", + "DESCRIPTION" : "实现服务任务逻辑的类" + } + }, + "SERVICETASKEXPRESSIONPACKAGE" : { + "SERVICETASKEXPRESSION" : { + "TITLE" : "表达式", + "DESCRIPTION" : "定义服务任务逻辑的表达式" + } + }, + "SERVICETASKDELEGATEEXPRESSIONPACKAGE" : { + "SERVICETASKDELEGATEEXPRESSION" : { + "TITLE" : "委托表达式", + "DESCRIPTION" : "通过代理表达式定义任务服务逻辑" + } + }, + "SERVICETASKFIELDSPACKAGE" : { + "SERVICETASKFIELDS" : { + "TITLE" : "类中的字段", + "DESCRIPTION" : "字段扩展" + } + }, + "SERVICETASKRESULTVARIABLEPACKAGE" : { + "SERVICETASKRESULTVARIABLE" : { + "TITLE" : "结果变量名", + "DESCRIPTION" : "流程变量存储服务任务的执行结果" + } + }, + "SERVICETASKRESULTVARIABLEPACKAGE" : { + "SERVICETASKUSELOCALSCOPEFORRESULTVARIABLE" : { + "TITLE" : "对结果变量使用局部作用域", + "DESCRIPTION" : "标记需要将使用的结果变量保存为局部变量" + } + }, + "SERVICETASKTRIGGERABLEPACKAGE" : { + "SERVICETASKTRIGGERABLE" : { + "TITLE" : "将服务任务设置为可触发的", + "DESCRIPTION" : "将服务任务设置为可触发的" + } + }, + "SERVICETASKSTORERESULTVARIABLETRANSIENTPACKAGE" : { + "SERVICETASKSTORERESULTVARIABLETRANSIENT" : { + "TITLE" : "使結果變量瞬變", + "DESCRIPTION" : "指示存储結果變量变量瞬态的标志" + } + }, + "SCRIPTFORMATPACKAGE" : { + "SCRIPTFORMAT" : { + "TITLE" : "脚本格式", + "DESCRIPTION" : "脚本任务的脚本格式化" + } + }, + "SCRIPTTEXTPACKAGE" : { + "SCRIPTTEXT" : { + "TITLE" : "脚本", + "DESCRIPTION" : "脚本任务的脚本文本" + } + }, + "SCRIPTAUTOSTOREVARIABLESPACKAGE" : { + "SCRIPTAUTOSTOREVARIABLES" : { + "TITLE" : "自动存储变量", + "DESCRIPTION" : "自动存储流程的所有脚本变量" + } + }, + "SHELLCOMMANDPACKAGE" : { + "SHELLCOMMAND" : { + "TITLE" : "命令", + "DESCRIPTION" : "Shell任务命令" + } + }, + "SHELLARG1PACKAGE" : { + "SHELLARG1" : { + "TITLE" : "参数1", + "DESCRIPTION" : "Shell 命令的参数1" + } + }, + "SHELLARG2PACKAGE" : { + "SHELLARG2" : { + "TITLE" : "参数2", + "DESCRIPTION" : "Shell 命令的参数2" + } + }, + "SHELLARG3PACKAGE" : { + "SHELLARG3" : { + "TITLE" : "参数3", + "DESCRIPTION" : "Shell 命令的参数3" + } + }, + "SHELLARG4PACKAGE" : { + "SHELLARG4" : { + "TITLE" : "参数4", + "DESCRIPTION" : "Shell 命令的参数4" + } + }, + "SHELLARG5PACKAGE" : { + "SHELLARG5" : { + "TITLE" : "参数5", + "DESCRIPTION" : "Shell 命令的参数5" + } + }, + "SHELLWAITPACKAGE" : { + "SHELLWAIT" : { + "TITLE" : "等待", + "DESCRIPTION" : "等待shell命令执行结束的标志" + } + }, + "SHELLOUTPUTVARIABLEPACKAGE" : { + "SHELLOUTPUTVARIABLE" : { + "TITLE" : "输出变量", + "DESCRIPTION" : "存储shell 命令的输出变量" + } + }, + "SHELLERRORCODEVARIABLEPACKAGE" : { + "SHELLERRORCODEVARIABLE" : { + "TITLE" : "错误代码变量", + "DESCRIPTION" : "存储shell 命令错误代码的变量" + } + }, + "SHELLREDIRECTERRORPACKAGE" : { + "SHELLREDIRECTERROR" : { + "TITLE" : "重定向错误", + "DESCRIPTION" : "当设置为true,使用标准输出合并错误输出" + } + }, + "SHELLCLEANENVPACKAGE" : { + "SHELLCLEANENV" : { + "TITLE" : "清除环境变量", + "DESCRIPTION" : "清理shell执行环境" + } + }, + "SHELLDIRECTORYPACKAGE" : { + "SHELLDIRECTORY" : { + "TITLE" : "Shell目录", + "DESCRIPTION" : "Shell 进程工作目录" + } + }, + "RULETASK_RULESPACKAGE" : { + "RULETASK_RULES" : { + "TITLE" : "规则", + "DESCRIPTION" : "规则任务的规则" + } + }, + "RULETASK_VARIABLES_INPUTPACKAGE" : { + "RULETASK_VARIABLES_INPUT" : { + "TITLE" : "输入变量", + "DESCRIPTION" : "规则任务的输入变量" + } + }, + "RULETASK_EXCLUDEPACKAGE" : { + "RULETASK_EXCLUDE" : { + "TITLE" : "排除", + "DESCRIPTION" : "使用作为排它性的规则属性" + } + }, + "RULETASK_RESULTPACKAGE" : { + "RULETASK_RESULT" : { + "TITLE" : "结果变量", + "DESCRIPTION" : "规则任务的结果变量" + } + }, + "MAILTASKHEADERSPACKAGE" : { + "MAILTASKHEADERS" : { + "TITLE" : "邮件头", + "DESCRIPTION" : "行分隔邮件头(例如-x-attribute:value)。" + } + }, + "MAILTASKTOPACKAGE" : { + "MAILTASKTO" : { + "TITLE" : "接收人", + "DESCRIPTION" : "接收者,格式为邮件。多个接收者请用逗号分割的列表来定义" + } + }, + "MAILTASKFROMPACKAGE" : { + "MAILTASKFROM" : { + "TITLE" : "发件人", + "DESCRIPTION" : "发送者的邮箱.若不提供,默认将使用配置中的来源地址." + } + }, + "MAILTASKSUBJECTPACKAGE" : { + "MAILTASKSUBJECT" : { + "TITLE" : "主题", + "DESCRIPTION" : "Email中的主题" + } + }, + "MAILTASKCCPACKAGE" : { + "MAILTASKCC" : { + "TITLE" : "抄送", + "DESCRIPTION" : "抄送的Email地址,多个接收者请用逗号分隔开。" + } + }, + "MAILTASKBCCPACKAGE" : { + "MAILTASKBCC" : { + "TITLE" : "密送", + "DESCRIPTION" : "密送的Email地址. 多个接收者请用逗号分隔开" + } + }, + "MAILTASKTEXTPACKAGE" : { + "MAILTASKTEXT" : { + "TITLE" : "正文", + "DESCRIPTION" : "Email中的内容, 案例一需要发送纯文件的邮件. 可使用Html格式的邮件进行发送,若邮件的接收的客户端不支持这种格式,客户端可转为纯文本的邮件" + } + }, + "MAILTASKHTMLPACKAGE" : { + "MAILTASKHTML" : { + "TITLE" : "Html", + "DESCRIPTION" : "HTML中的一片段作为邮件的内容." + } + }, + "MAILTASKCHARSETPACKAGE" : { + "MAILTASKCHARSET" : { + "TITLE" : "字符集", + "DESCRIPTION" : "对于很多非英语语言来说,允许更改邮件的编码设置是必要的 " + } + }, + "HTTPTASKREQUESTMETHODPACKAGE" : { + "HTTPTASKREQUESTMETHOD" : { + "TITLE" : "请求方法", + "DESCRIPTION" : "请求方法(例如 - GET,POST,PUT等)。" + } + }, + "HTTPTASKREQUESTURLPACKAGE" : { + "HTTPTASKREQUESTURL" : { + "TITLE" : "请求 URL", + "DESCRIPTION" : "请求URL(例如 - http://flowable.org)。" + } + }, + "HTTPTASKREQUESTHEADERSPACKAGE" : { + "HTTPTASKREQUESTHEADERS" : { + "TITLE" : "请求头", + "DESCRIPTION" : "行分隔的HTTP请求标头(例如 - Content-Type:application/json)。" + } + }, + "HTTPTASKREQUESTBODYPACKAGE" : { + "HTTPTASKREQUESTBODYPACKAGE" : { + "TITLE" : "请求体", + "DESCRIPTION" : "请求正文(例如 - ${sampleBody})。" + } + }, + "HTTPTASKREQUESTBODYENCODINGPACKAGE" : { + "HTTPTASKREQUESTBODYENCODING" : { + "TITLE" : "请求体编码", + "DESCRIPTION" : "请求正文编码(例如-UTF-8)。" + } + }, + "HTTPTASKREQUESTTIMEOUTPACKAGE" : { + "HTTPTASKREQUESTTIMEOUT" : { + "TITLE" : "请求超时时间(ms)", + "DESCRIPTION" : "请求超时(以毫秒为单位)(例如 - 5000)。" + } + }, + "HTTPTASKDISALLOWREDIRECTSPACKAGE" : { + "HTTPTASKDISALLOWREDIRECTS" : { + "TITLE" : "不允许重定向", + "DESCRIPTION" : "不允许HTTP重定向的标记。" + } + }, + "HTTPTASKFAILSTATUSCODESPACKAGE" : { + "HTTPTASKFAILSTATUSCODES" : { + "TITLE" : "失败时状态码", + "DESCRIPTION" : "逗号分隔的HTTP响应状态代码列表以重试,例如400,5XX。" + } + }, + "HTTPTASKHANDLESTATUSCODESPACKAGE" : { + "HTTPTASKHANDLESTATUSCODES" : { + "TITLE" : "处理状态码", + "DESCRIPTION" : "要忽略的逗号分隔的HTTP响应状态代码列表,例如404,3XX。" + } + }, + "HTTPTASKIGNOREEXCEPTIONPACKAGE" : { + "HTTPTASKIGNOREEXCEPTION" : { + "TITLE" : "忽略异常", + "DESCRIPTION" : "标记以忽略异常。" + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENTPACKAGE" : { + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENT" : { + "TITLE" : "将响应保存为瞬态变量", + "DESCRIPTION" : "指示存储响应变量瞬态的标志" + } + }, + "HTTPTASKSAVERESPONSEASJSONPACKAGE" : { + "HTTPTASKSAVERESPONSEASJSON" : { + "TITLE" : "将响应保存为JSON", + "DESCRIPTION" : "指示将响应变量存储为JSON变量而不是String的标志" + } + }, + "HTTPTASKPARALLELINSAMETRANSACTIONPACKAGE" : { + "HTTPTASKPARALLELINSAMETRANSACTION" : { + "TITLE" : "Execute parallel in same transaction", + "DESCRIPTION" : "Flag indicating that the Http call should be done parallel in the same transaction. This means that when using parallel gateways multiple http tasks are executed in the same time in the same transaction and thus the entire execution of the process is faster." + } + }, + "SKIPEXPRESSIONPACKAGE" : { + "SKIPEXPRESSION" : { + "TITLE" : "跳过表达式", + "DESCRIPTION" : "跳过与任务或关联关联的表达式执行与否。" + } + }, + "HTTPTASKRESPONSEVARIABLENAMEPACKAGE" : { + "HTTPTASKRESPONSEVARIABLENAME" : { + "TITLE" : "响应变量名", + "DESCRIPTION" : "定义变量名称以存储http响应。" + } + }, + "HTTPTASKSAVEREQUESTVARIABLESPACKAGE" : { + "HTTPTASKSAVEREQUESTVARIABLES" : { + "TITLE" : "保存请求变量", + "DESCRIPTION" : "用于保存请求变量的标志。" + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSPACKAGE" : { + "HTTPTASKSAVERESPONSEPARAMETERS" : { + "TITLE" : "保存响应状态、头", + "DESCRIPTION" : "用于保存响应状态,标题等的标志" + } + }, + "HTTPTASKRESULTVARIABLEPREFIXPACKAGE" : { + "HTTPTASKRESULTVARIABLEPREFIX" : { + "TITLE" : "结果变量的前缀", + "DESCRIPTION" : "执行变量名称的前缀。" + } + }, + "CALLACTIVITYCALLEDELEMENTPACKAGE" : { + "CALLACTIVITYCALLEDELEMENT" : { + "TITLE" : "被调用元素", + "DESCRIPTION" : "流程引用" + } + }, + "CALLACTIVITYCALLEDELEMENTTYPEPACKAGE" : { + "CALLACTIVITYCALLEDELEMENTTYPE" : { + "TITLE" : "被调用元素类型", + "DESCRIPTION" : "使用流程参考的类型。." + } + }, + "CALLACTIVITYINPARAMETERSPACKAGE" : { + "CALLACTIVITYINPARAMETERS" : { + "TITLE" : "输入参数", + "DESCRIPTION" : "定义输入参数" + } + }, + "CALLACTIVITYOUTPARAMETERSPACKAGE" : { + "CALLACTIVITYOUTPARAMETERS" : { + "TITLE" : "输出参数", + "DESCRIPTION" : "输出参数的定义" + } + }, + "CALLACTIVITYINHERITVARIABLESPACKAGE" : { + "CALLACTIVITYINHERITVARIABLES" : { + "TITLE" : "在子流程中继承变量", + "DESCRIPTION" : "在子流程中继承父流程变量。" + } + }, + "CALLACTIVITYSAMEDEPLOYMENTPACKAGE" : { + "CALLACTIVITYSAMEDEPLOYMENT" : { + "TITLE" : "从相同的部署中启动引用的流程", + "DESCRIPTION" : "使用同一部署中引用的流程。" + } + }, + "CALLACTIVITYFALLBACKTODEFAULTTENANTPACKAGE" : { + "CALLACTIVITYFALLBACKTODEFAULTTENANT" : { + "TITLE" : "回退到默认租户", + "DESCRIPTION" : "当前租户搜索失败时,在默认租户中按键查找定义。" + } + }, + "CALLACTIVITYPROCESSINSTANCENAMEPACKAGE" : { + "CALLACTIVITYPROCESSINSTANCENAME" : { + "TITLE" : "流程实例名称", + "DESCRIPTION" : "解析为子流程实例名称的表达式" + } + }, + "CALLACTIVITYINHERITBUSINESSKEYPACKAGE" : { + "CALLACTIVITYINHERITBUSINESSKEY" : { + "TITLE" : "继承业务键", + "DESCRIPTION" : "从父流程继承业务键。" + } + }, + "CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERSPACKAGE" : { + "CALLACTIVITYUSELOCALSCOPEFOROUTPARAMETERS" : { + "TITLE" : "对输出参数使用局部作用域", + "DESCRIPTION" : "对输出参数使用局部变量范围。" + } + }, + "CALLACTIVITYBUSINESSKEYPACKAGE" : { + "CALLACTIVITYBUSINESSKEY" : { + "TITLE" : "业务键表达式", + "DESCRIPTION" : "解析为子流程实例的业务键的表达式" + } + }, + "CALLACTIVITYCOMPLETEASYNCPACKAGE" : { + "CALLACTIVITYCOMPLETEASYNC" : { + "TITLE" : "完成异步", + "DESCRIPTION" : "如果设置,则子流程结束并完成调用活动是异步完成的。将并行多实例与具有异步任务的被调用流程定义一起使用时非常有用。" + } + }, + "CAMELTASKCAMELCONTEXTPACKAGE" : { + "CAMELTASKCAMELCONTEXT" : { + "TITLE" : "驼峰内容", + "DESCRIPTION" : "可选的Camel 上下文定义,若为空,则使用系统缺省的." + } + }, + "MULETASKENDPOINTURLPACKAGE" : { + "MULETASKENDPOINTURL" : { + "TITLE" : "终端url", + "DESCRIPTION" : "发送消息到Mule的必须的端点URL" + } + }, + "MULETASKLANGUAGEPACKAGE" : { + "MULETASKLANGUAGE" : { + "TITLE" : "语言", + "DESCRIPTION" : "必须的语言定义来解析装载的表达式,如JUEL." + } + }, + "MULETASKPAYLOADEXPRESSIONPACKAGE" : { + "MULETASKPAYLOADEXPRESSION" : { + "TITLE" : "有效载荷表达式", + "DESCRIPTION" : "发送至Mule的必须执行的消息定义" + } + }, + "MULETASKRESULTVARIABLEPACKAGE" : { + "MULETASKRESULTVARIABLE" : { + "TITLE" : "返回变量", + "DESCRIPTION" : "可选的装载返回的结果的变量" + } + }, + "CONDITIONSEQUENCEFLOWPACKAGE" : { + "CONDITIONSEQUENCEFLOWPACKAGE" : { + "TITLE" : "流条件", + "DESCRIPTION" : "流程跳线的条件定义" + } + }, + "DEFAULTFLOWPACKAGE" : { + "DEFAULTFLOW" : { + "TITLE" : "默认流", + "DESCRIPTION" : "将序列流定义为默认值" + } + }, + "CONDITIONALFLOWPACKAGE" : { + "CONDITIONALFLOW" : { + "TITLE" : "条件流", + "DESCRIPTION" : "用条件定义序列流" + } + }, + "TIMERCYCLEDEFINITIONPACKAGE" : { + "TIMERCYCLEDEFINITION" : { + "TITLE" : "循环时间(例:R3/PT10H)", + "DESCRIPTION" : "定义ISO-8601时间周期" + } + }, + "TIMERDATEDEFINITIONPACKAGE" : { + "TIMERDATEDEFINITION" : { + "TITLE" : "开始时间(ISO-8601)", + "DESCRIPTION" : "定义(ISO-8601格式标准)的定时器." + } + }, + "TIMERDURATIONDEFINITIONPACKAGE" : { + "TIMERDURATIONDEFINITION" : { + "TITLE" : "持续时间(例:PT5M)", + "DESCRIPTION" : "定义(ISO-8601)持续的定时器" + } + }, + "TIMERENDDATEDEFINITIONPACKAGE" : { + "TIMERENDDATEDEFINITION" : { + "TITLE" : "结束时间(ISO-8601)", + "DESCRIPTION" : "定义带(ISO-8601 duration)定时器." + } + }, + "MESSAGEREFPACKAGE" : { + "MESSAGEREF" : { + "TITLE" : "消息引用", + "DESCRIPTION" : "定义消息的名字。" + } + }, + "SIGNALREFPACKAGE" : { + "SIGNALREF" : { + "TITLE" : "信号引用", + "DESCRIPTION" : "定义信号的名称" + } + }, + "ERRORREFPACKAGE" : { + "ERRORREF" : { + "TITLE" : "错误引用", + "DESCRIPTION" : "定义错误名称" + } + }, + "ESCALATIONREFPACKAGE" : { + "ESCALATIONREF" : { + "TITLE" : "升级引用", + "DESCRIPTION" : "定义升级名称" + } + }, + "CONDITIONALEVENTPACKAGE" : { + "CONDITION" : { + "TITLE" : "条件表达式", + "DESCRIPTION" : "定义条件表达式." + } + }, + "CANCELACTIVITYPACKAGE" : { + "CANCELACTIVITY" : { + "TITLE" : "取消活动", + "DESCRIPTION" : "活动是否应取消?" + } + }, + "INITIATORPACKAGE" : { + "INITIATOR" : { + "TITLE" : "发起人", + "DESCRIPTION" : "流程的发起方。" + } + }, + "TEXTPACKAGE" : { + "TEXT" : { + "TITLE" : "文本", + "DESCRIPTION" : "文本批注的文本。" + } + }, + "MULTIINSTANCE_TYPEPACKAGE" : { + "MULTIINSTANCE_TYPE" : { + "TITLE" : "多实例类型", + "DESCRIPTION" : "重复的活动执行(并行或顺序)可以通过不同的循环类型显示。" + } + }, + "MULTIINSTANCE_CARDINALITYPACKAGE" : { + "MULTIINSTANCE_CARDINALITY" : { + "TITLE" : "基数(多实例)", + "DESCRIPTION" : "定义多实例的基数" + } + }, + "MULTIINSTANCE_COLLECTIONPACKAGE" : { + "MULTIINSTANCE_COLLECTION" : { + "TITLE" : "集合(多实例)", + "DESCRIPTION" : "定义多实例的集合" + } + }, + "MULTIINSTANCE_VARIABLEPACKAGE" : { + "MULTIINSTANCE_VARIABLE" : { + "TITLE" : "元素变量(多实例)", + "DESCRIPTION" : "为多实例定义变量元素" + } + }, + "MULTIINSTANCE_CONDITIONPACKAGE" : { + "MULTIINSTANCE_CONDITION" : { + "TITLE" : "完成条件(多实例)", + "DESCRIPTION" : "定义多实例的完成条件" + } + }, + "ISFORCOMPENSATIONPACKAGE" : { + "ISFORCOMPENSATION" : { + "TITLE" : "是否为补偿", + "DESCRIPTION" : "标识此活动是否用于补偿的标志。" + } + }, + "SEQUENCEFLOWORDERPACKAGE" : { + "SEQUENCEFLOWORDER" : { + "TITLE" : "流顺序", + "DESCRIPTION" : "流程走向的顺序" + } + }, + "SIGNALDEFINITIONSPACKAGE" : { + "SIGNALDEFINITIONS" : { + "TITLE" : "信号定义", + "DESCRIPTION" : "信号定义" + } + }, + "MESSAGEDEFINITIONSPACKAGE" : { + "MESSAGEDEFINITIONS" : { + "TITLE" : "消息定义", + "DESCRIPTION" : "消息定义" + } + }, + "ESCALATIONDEFINITIONSPACKAGE" : { + "ESCALATIONDEFINITIONS" : { + "TITLE" : "升级的定义", + "DESCRIPTION" : "升级的定义" + } + }, + + "EVENTREGISTRYPACKAGE" : { + "EVENTKEY" : { + "TITLE" : "事件key", + "DESCRIPTION" : "事件key定义" + }, + "EVENTNAME" : { + "TITLE" : "事件名称", + "DESCRIPTION" : "事件名称定义" + }, + "EVENTINPARAMETERS" : { + "TITLE" : "事件载体映射", + "DESCRIPTION" : "将流程变量映射到事件有效载体的属性" + }, + "EVENTOUTPARAMETERS" : { + "TITLE" : "从事件有效载体映射到流程", + "DESCRIPTION" : "将事件有效载体的属性映射到流程变量" + }, + "EVENTCORRELATIONPARAMETERS" : { + "TITLE" : "相关参数", + "DESCRIPTION" : "相关参数定义" + }, + "CHANNELKEY" : { + "TITLE" : "通道key", + "DESCRIPTION" : "通道key定义" + }, + "CHANNELNAME" : { + "TITLE" : "通道名称", + "DESCRIPTION" : "通道名称定义" + }, + "CHANNELTYPE" : { + "TITLE" : "通道类型", + "DESCRIPTION" : "通道类型定义" + }, + "CHANNELDESTINATION" : { + "TITLE" : "通道目的地", + "DESCRIPTION" : "通道目的地定义" + }, + "TRIGGEREVENTKEY" : { + "TITLE" : "触发事件key", + "DESCRIPTION" : "触发事件key定义" + }, + "TRIGGEREVENTNAME" : { + "TITLE" : "触发事件名称", + "DESCRIPTION" : "触发事件名称定义" + }, + "TRIGGERCHANNELKEY" : { + "TITLE" : "触发管道key", + "DESCRIPTION" : "触发管道key定义" + }, + "TRIGGERCHANNELNAME" : { + "TITLE" : "触发管道名称", + "DESCRIPTION" : "触发管道名称" + }, + "TRIGGERCHANNELTYPE" : { + "TITLE" : "触发通道类型", + "DESCRIPTION" : "触发通道类型定义" + }, + "TRIGGERCHANNELDESTINATION" : { + "TITLE" : "触发通道目的地", + "DESCRIPTION" : "触发通道目的地定义" + }, + "KEYDETECTIONFIXEDVALUE" : { + "TITLE" : "事件key固定值", + "DESCRIPTION" : "事件key固定值定义" + }, + "KEYDETECTIONJSONFIELD" : { + "TITLE" : "事件key json 字段", + "DESCRIPTION" : "事件key json 字段" + }, + "KEYDETECTIONJSONPOINTER" : { + "TITLE" : "事件key json 指针", + "DESCRIPTION" : "事件key json 指针" + } + }, + "ISTRANSACTIONPACKAGE" : { + "ISTRANSACTION" : { + "TITLE" : "是事务子流程", + "DESCRIPTION" : "标识此子流程是否为事务类型的标志。" + } + }, + "FORMREFERENCEPACKAGE" : { + "FORMREFERENCE" : { + "TITLE" : "表单引用", + "DESCRIPTION" : "关联到一个表单" + } + }, + "TERMINATEALLPACKAGE" : { + "TERMINATEALL" : { + "TITLE" : "终止所有", + "DESCRIPTION" : "启用以终止流程实例" + } + }, + "DECISIONTASKDECISIONTABLEREFERENCEPACKAGE" : { + "DECISIONTASKDECISIONTABLEREFERENCE" : { + "TITLE" : "决策表参考", + "DESCRIPTION" : "设置决策表引用" + } + }, + "DECISIONTASKTHROWERRORONNOHITSPACKAGE" : { + "DECISIONTASKTHROWERRORONNOHITS" : { + "TITLE" : "如果未命中任何规则,则引发错误", + "DESCRIPTION" : "如果未命中决策表的规则,因而找不到结果,则应引发错误。" + } + }, + "DECISIONTASKFALLBACKTODEFAULTTENANTPACKAGE" : { + "DECISIONTASKFALLBACKTODEFAULTTENANT" : { + "TITLE" : "回退到默认租户", + "DESCRIPTION" : "当上一次尝试用租户查找决策定义失败时,查找不带租户的决策定义。" + } + }, + "INTERRUPTINGPACKAGE" : { + "INTERRUPTING" : { + "TITLE" : "中断", + "DESCRIPTION" : "是否应终止所有父级执行?" + } + }, + "COMPLETIONCONDITIONPACKAGE" : { + "COMPLETIONCONDITION" : { + "TITLE" : "完成条件", + "DESCRIPTION" : "自组网子流程的完成条件" + } + }, + "ORDERINGPACKAGE" : { + "ORDERING" : { + "TITLE" : "排序", + "DESCRIPTION" : "自组网子流程的排序" + } + }, + "CANCELREMAININGINSTANCESPACKAGE" : { + "CANCELREMAININGINSTANCES" : { + "TITLE" : "取消剩余的实例", + "DESCRIPTION" : "取消自组网子流程的剩余实例?" + } + } + + }, + "STENCILS" : { + "GROUPS" : { + "STARTEVENTS" : "启动事件", + "ENDEVENTS" : "结束事件", + "DIAGRAM" : "图解", + "ACTIVITIES" : "活动", + "STRUCTURAL" : "结构", + "GATEWAYS" : "网关", + "BOUNDARYEVENTS" : "边界事件", + "INTERMEDIATECATCHINGEVENTS" : "中间捕捉事件", + "INTERMEDIATETHROWINGEVENTS" : "中间抛出事件", + "SWIMLANES" : "泳道", + "CONNECTINGOBJECTS" : "连接对象", + "ARTIFACTS" : "工件" + }, + "BPMNDIAGRAM" : { + "TITLE" : "BPMN流程图", + "DESCRIPTION" : "BPMN 2.0 流程图." + }, + "STARTNONEEVENT" : { + "TITLE" : "空启动事件", + "DESCRIPTION" : "无特定触发器的启动事件" + }, + "STARTTIMEREVENT" : { + "TITLE" : "定时器启动事件", + "DESCRIPTION" : "带定时器触发的启动事件" + }, + "STARTSIGNALEVENT" : { + "TITLE" : "信号启动事件", + "DESCRIPTION" : "通过信号触发启动事件" + }, + "STARTMESSAGEEVENT" : { + "TITLE" : "消息启动事件", + "DESCRIPTION" : "通过消息触发启动事件" + }, + "STARTCONDITIONALEVENT" : { + "TITLE" : "条件启动事件", + "DESCRIPTION" : "通过条件触发启动事件" + }, + "STARTERROREVENT" : { + "TITLE" : "异常启动事件", + "DESCRIPTION" : "用于捕获BPMN抛出的异常启动事件" + }, + "STARTESCALATIONEVENT" : { + "TITLE" : "升级开始事件", + "DESCRIPTION" : "捕获抛出的BPMN升级的启动事件" + }, + "STARTEVENTREGISTRYEVENT" : { + "TITLE" : "注册开始事件", + "DESCRIPTION" : "注册开始事件" + }, + + "USERTASK" : { + "TITLE" : "用户任务", + "DESCRIPTION" : "分配给特定人的任务" + }, + "SERVICETASK" : { + "TITLE" : "服务任务", + "DESCRIPTION" : "带有服务逻辑的自动任务" + }, + "SCRIPTTASK" : { + "TITLE" : "脚本任务", + "DESCRIPTION" : "带有脚本逻辑的自动任务" + }, + "BUSINESSRULE" : { + "TITLE" : "业务规则任务", + "DESCRIPTION" : "带有业务规则的自动任务" + }, + "RECEIVETASK" : { + "TITLE" : "接收任务", + "DESCRIPTION" : "等待接收信号来触发的任务" + }, + "MANUALTASK" : { + "TITLE" : "手动任务", + "DESCRIPTION" : "不带任何逻辑的自动任务" + }, + "MAILTASK" : { + "TITLE" : "邮件任务", + "DESCRIPTION" : "邮件任务" + }, + "CAMELTASK" : { + "TITLE" : "驼峰任务", + "DESCRIPTION" : "发送消息给Camel容器的任务" + }, + "HTTPTASK" : { + "TITLE" : "Http任务", + "DESCRIPTION" : "Http任务" + }, + "MULETASK" : { + "TITLE" : "Mule任务", + "DESCRIPTION" : "An task that sends a message to Mule" + }, + "SENDTASK" : { + "TITLE" : "发送任务", + "DESCRIPTION" : "发送消息的任务" + }, + "DECISIONTASK" : { + "TITLE" : "决策任务", + "DESCRIPTION" : "使用Flowable DMN规则引擎的任务" + }, + "SHELLTASK" : { + "TITLE" : "Shell任务", + "DESCRIPTION" : "具有shell批处理逻辑的自动任务" + }, + "SUBPROCESS" : { + "TITLE" : "子流程", + "DESCRIPTION" : "子流程范围" + }, + "SENDEVENTTASK" : { + "TITLE" : "事件发送任务", + "DESCRIPTION" : "事件发送任务" + }, + + "COLLAPSEDSUBPROCESS" : { + "TITLE" : "折叠子流程", + "DESCRIPTION" : "子流程范围" + }, + "EVENTSUBPROCESS" : { + "TITLE" : "事件子流程", + "DESCRIPTION" : "事件子流程范围" + }, + "CALLACTIVITY" : { + "TITLE" : "调用活动", + "DESCRIPTION" : "一个调用活动" + }, + "EXCLUSIVEGATEWAY" : { + "TITLE" : "排他网关", + "DESCRIPTION" : "一个选择的网关" + }, + "PARALLELGATEWAY" : { + "TITLE" : "并行网关", + "DESCRIPTION" : "一个并行的网关" + }, + "INCLUSIVEGATEWAY" : { + "TITLE" : "包容网关", + "DESCRIPTION" : "一个包容性网关" + }, + "EVENTGATEWAY" : { + "TITLE" : "事件网关", + "DESCRIPTION" : "一个事件网关" + }, + "BOUNDARYCONDITIONALEVENT" : { + "TITLE" : "边界条件事件", + "DESCRIPTION" : "捕获指定条件的边界事件" + }, + "BOUNDARYERROREVENT" : { + "TITLE" : "边界错误事件", + "DESCRIPTION" : "捕捉bpmn错误的边界事件" + }, + "BOUNDARYESCALATIONEVENT" : { + "TITLE" : "边界升级事件", + "DESCRIPTION" : "捕获BPMN升级的边界事件" + }, + "BOUNDARYTIMEREVENT" : { + "TITLE" : "边界计时器事件", + "DESCRIPTION" : "具有计时器触发器的边界事件" + }, + "BOUNDARYSIGNALEVENT" : { + "TITLE" : "边界信号事件", + "DESCRIPTION" : "一个信号触发的边界事件" + }, + "BOUNDARYMESSAGEEVENT" : { + "TITLE" : "边界消息事件", + "DESCRIPTION" : "一个边界消息事件" + }, + "BOUNDARYCANCELEVENT" : { + "TITLE" : "边界取消事件", + "DESCRIPTION" : "一个边界取消事件" + }, + "BOUNDARYEVENTREGISTRYEVENT" : { + "TITLE" : "边界注册事件", + "DESCRIPTION" : "边界注册事件" + }, + "BOUNDARYCOMPENSATIONEVENT" : { + "TITLE" : "边界补偿事件", + "DESCRIPTION" : "边界补偿事件" + }, + "CATCHTIMEREVENT" : { + "TITLE" : "中间计时器捕获事件", + "DESCRIPTION" : "使用计时器触发器的中间捕获事件" + }, + "CATCHSIGNALEVENT" : { + "TITLE" : "中间信号捕获事件", + "DESCRIPTION" : "带有信号触发器的中间捕获事件" + }, + "CATCHMESSAGEEVENT" : { + "TITLE" : "中间消息捕获事件", + "DESCRIPTION" : "带有消息触发器的中间捕获事件" + }, + "CATCHCONDITIONALEVENT" : { + "TITLE" : "中间条件捕获事件", + "DESCRIPTION" : "带有条件触发器的中间捕获事件" + }, + "THROWNONEEVENT" : { + "TITLE" : "中间无抛出事件", + "DESCRIPTION" : "没有特定触发器的中间事件" + }, + "THROWSIGNALEVENT" : { + "TITLE" : "中间信号抛出事件", + "DESCRIPTION" : "带有信号触发器的中间事件" + }, + "THROWESCALATIONEVENT" : { + "TITLE" : "中间升级抛出事件", + "DESCRIPTION" : "具有升级触发器的中间事件" + }, + "ENDNONEEVENT" : { + "TITLE" : "结束事件", + "DESCRIPTION" : "没有特定触发器的结束事件" + }, + "ENDERROREVENT" : { + "TITLE" : "结束错误事件", + "DESCRIPTION" : "引发错误事件的结束事件" + }, + "ENDESCALATIONEVENT" : { + "TITLE" : "结束升级事件", + "DESCRIPTION" : "抛出升级事件的结束时间" + }, + "ENDCANCELEVENT" : { + "TITLE" : "结束取消事件", + "DESCRIPTION" : "取消结束事件" + }, + "ENDTERMINATEEVENT" : { + "TITLE" : "结束终止事件", + "DESCRIPTION" : "终止结束事件" + }, + "POOL" : { + "TITLE" : "池", + "DESCRIPTION" : "用于构造流程定义的池" + }, + "LANE" : { + "TITLE" : "泳道", + "DESCRIPTION" : "构建流程定义的泳道" + }, + "SEQUENCEFLOW" : { + "TITLE" : "顺序流", + "DESCRIPTION" : "序列流定义了活动的执行顺序。" + }, + "MESSAGEFLOW" : { + "TITLE" : "消息流", + "DESCRIPTION" : "用于连接不同池中的元素的消息流。" + }, + "ASSOCIATION" : { + "TITLE" : "关联", + "DESCRIPTION" : "将文本注释与元素关联。" + }, + "DATAASSOCIATION" : { + "TITLE" : "数据关联", + "DESCRIPTION" : "将数据元素与活动关联。" + }, + "TEXTANNOTATION" : { + "TITLE" : "文本注释", + "DESCRIPTION" : "用描述文本注释元素。" + }, + "DATASTORE" : { + "TITLE" : "数据存储", + "DESCRIPTION" : "对数据存储的引用。" + }, + "ADHOCSUBPROCESS" : { + "TITLE" : "自组网子流程", + "DESCRIPTION" : "自组网子流程" + } + } + }, + + "CMMN" : { + "TITLE": "CMMN编辑器", + "DESCRIPTION": "CMMN案例编辑器", + "PROPERTYPACKAGES": { + "CASE_IDPACKAGE": { + "CASE_ID": { + "TITLE": "案例标识符", + "DESCRIPTION": "案例定义的唯一标识符。" + } + }, + "OVERRIDEIDPACKAGE": { + "OVERRIDEID": { + "TITLE": "主键Id", + "DESCRIPTION": "元素的唯一标识符" + } + }, + "NAMEPACKAGE": { + "NAME": { + "TITLE": "案例名称", + "DESCRIPTION": "CMMN元素的描述性名称。" + } + }, + "DOCUMENTATIONPACKAGE": { + "DOCUMENTATION": { + "TITLE": "描述文档", + "DESCRIPTION": "CMMN元素的描述性名称。" + } + }, + "BLOCKINGPACKAGE": { + "ISBLOCKING": { + "TITLE": "阻塞", + "DESCRIPTION": "布尔属性,默认为true。如果为false,则任务将在执行任何关联逻辑后自动完成任务" + }, + "ISBLOCKINGEXPRESSION": { + "TITLE": "阻塞表达式", + "DESCRIPTION": "在运行时控制此任务是否阻塞的表达式。设置后,将忽略阻塞属性的值。" + } + }, + "CASE_INITIATORVARIABLENAMEPACKAGE": { + "CASE_INITIATORVARIABLENAME": { + "TITLE": "启动器变量名称", + "DESCRIPTION": "设置要用于案例启动程序值的变量名称。" + } + }, + "CASE_AUTHORPACKAGE": { + "CASE_AUTHOR": { + "TITLE": "案例作者", + "DESCRIPTION": "案例定义的作者" + } + }, + "CASE_VERSIONPACKAGE": { + "CASE_VERSION": { + "TITLE": "案例版本字符串(仅文档)", + "DESCRIPTION": "版本标识符用于文档目的。" + } + }, + "CASE_NAMESPACEPACKAGE": { + "CASE_NAMESPACE": { + "TITLE": "目标命名空间", + "DESCRIPTION": "案例定义的目标名称空间。" + } + }, + "USERTASKASSIGNMENTPACKAGE": { + "USERTASKASSIGNMENT": { + "TITLE": "分配任务", + "DESCRIPTION": "用户任务的分配定义" + } + }, + "TASKLISTENERSPACKAGE": { + "TASKLISTENERS": { + "TITLE": "任务监听器", + "DESCRIPTION": "人工任务的监听器" + } + }, + "FORMPROPERTIESPACKAGE": { + "FORMPROPERTIES": { + "TITLE": "表单属性", + "DESCRIPTION": "具有表单属性列表的表单定义" + } + }, + "FORMKEYDEFINITIONPACKAGE": { + "FORMKEYDEFINITION": { + "TITLE": "表单键", + "DESCRIPTION": "提供对表单的引用的表单键。" + } + }, + "FORMFIELDVALIDATIONPACKAGE": { + "FORMFIELDVALIDATION": { + "TITLE": "验证表单字段", + "DESCRIPTION": "在表单提交时验证表单字段。(允许值为“true”、“false”或表达式)" + } + }, + "DUEDATEDEFINITIONPACKAGE": { + "DUEDATEDEFINITION": { + "TITLE": "到期日", + "DESCRIPTION": "用户任务的截止日期" + } + }, + "PRIORITYDEFINITIONPACKAGE": { + "PRIORITYDEFINITION": { + "TITLE": "优先级", + "DESCRIPTION": "用户任务的优先级。" + } + }, + "SERVICETASKCLASSPACKAGE": { + "SERVICETASKCLASS": { + "TITLE": "类", + "DESCRIPTION": "实现服务任务逻辑的类。" + } + }, + "SERVICETASKEXPRESSIONPACKAGE": { + "SERVICETASKEXPRESSION": { + "TITLE": "表达式", + "DESCRIPTION": "用表达式定义的服务任务逻辑。" + } + }, + "SERVICETASKDELEGATEEXPRESSIONPACKAGE": { + "SERVICETASKDELEGATEEXPRESSION": { + "TITLE": "委托表达式", + "DESCRIPTION": "用委托表达式定义的服务任务逻辑。" + } + }, + "SERVICETASKFIELDSPACKAGE": { + "SERVICETASKFIELDS": { + "TITLE": "类字段", + "DESCRIPTION": "字段扩展" + } + }, + "SERVICETASKRESULTVARIABLEPACKAGE": { + "SERVICETASKRESULTVARIABLE": { + "TITLE": "结果变量名称", + "DESCRIPTION": "存储服务任务结果的进程变量名。" + } + }, + "ASYNCPACKAGE": { + "ISASYNC": { + "TITLE": "异步", + "DESCRIPTION": "指示是否需要异步执行任务。" + }, + "ISEXCLUSIVE": { + "TITLE": "独占", + "DESCRIPTION": "指示是否必须以独占方式执行异步任务" + } + }, + "MAILTASKHEADERSPACKAGE": { + "MAILTASKHEADERS": { + "TITLE": "报头", + "DESCRIPTION": "行分隔邮件头(例如 - X-Attribute: value)" + } + }, + "MAILTASKTOPACKAGE": { + "MAILTASKTO": { + "TITLE": "接收者", + "DESCRIPTION": "如果是电子邮件,则为收件人。在逗号分隔的列表中定义了多个收件人。" + } + }, + "MAILTASKFROMPACKAGE": { + "MAILTASKFROM": { + "TITLE": "发件者", + "DESCRIPTION": "发件人电子邮件地址。如果未提供,则使用从地址配置的默认值。" + } + }, + "MAILTASKSUBJECTPACKAGE": { + "MAILTASKSUBJECT": { + "TITLE": "主题", + "DESCRIPTION": "电子邮件的主题。" + } + }, + "MAILTASKCCPACKAGE": { + "MAILTASKCC": { + "TITLE": "抄送", + "DESCRIPTION": "电子邮件的抄送。在逗号分隔的列表中定义了多个收件人" + } + }, + "MAILTASKBCCPACKAGE": { + "MAILTASKBCC": { + "TITLE": "密送", + "DESCRIPTION": "电子邮件的密件抄送。在逗号分隔的列表中定义了多个收件人" + } + }, + "MAILTASKTEXTPACKAGE": { + "MAILTASKTEXT": { + "TITLE": "文本", + "DESCRIPTION": "电子邮件的内容,以防需要发送不丰富的普通电子邮件。可与HTML结合使用,用于不支持丰富内容的电子邮件客户端。然后,客户机将返回到此文本唯一的备选方案。" + } + }, + "MAILTASKHTMLPACKAGE": { + "MAILTASKHTML": { + "TITLE": "Html", + "DESCRIPTION": "一段HTML,它是电子邮件的内容。" + } + }, + "MAILTASKCHARSETPACKAGE": { + "MAILTASKCHARSET": { + "TITLE": "字符集", + "DESCRIPTION": "允许更改电子邮件的字符集,这对于许多非英语语言是必需的。" + } + }, + "TEXTPACKAGE": { + "TEXT": { + "TITLE": "文本", + "DESCRIPTION": "文本批注的文本。" + } + }, + "FORMREFERENCEPACKAGE": { + "FORMREFERENCE": { + "TITLE": "表单引用", + "DESCRIPTION": "一个表单的引用" + } + }, + "DECISIONTASKDECISIONTABLEREFERENCEPACKAGE": { + "DECISIONTASKDECISIONTABLEREFERENCE": { + "TITLE": "决策表参考", + "DESCRIPTION": "设置决策表引用" + } + }, + "DECISIONTASKTHROWERRORONNOHITSPACKAGE": { + "DECISIONTASKTHROWERRORONNOHITS": { + "TITLE": "如果未命中任何规则,则抛出错误", + "DESCRIPTION": "如果未命中决策表的规则,因而找不到结果,则应抛出错误。" + } + }, + "DECISIONTASKFALLBACKTODEFAULTTENANTPACKAGE": { + "DECISIONTASKFALLBACKTODEFAULTTENANT": { + "TITLE": "回退到默认租户", + "DESCRIPTION": "当上一次尝试用租户查找决策定义失败时,查找不带租户的决策定义。" + } + }, + "HTTPTASKREQUESTMETHODPACKAGE": { + "HTTPTASKREQUESTMETHOD": { + "TITLE": "请求方法", + "DESCRIPTION": "请求方法(例如GET、POST、PUT等)。" + } + }, + "HTTPTASKREQUESTURLPACKAGE": { + "HTTPTASKREQUESTURL": { + "TITLE": "请求URL", + "DESCRIPTION": "请求URL(例如-http://flowable.org)。" + } + }, + "HTTPTASKREQUESTHEADERSPACKAGE": { + "HTTPTASKREQUESTHEADERS": { + "TITLE": "请求头", + "DESCRIPTION": "行分隔的HTTP请求头(例如-content-type:application/json)。" + } + }, + "HTTPTASKREQUESTBODYPACKAGE": { + "HTTPTASKREQUESTBODY": { + "TITLE": "请求正文", + "DESCRIPTION": "请求主体(例如-$samplebody)。" + } + }, + "HTTPTASKREQUESTBODYENCODINGPACKAGE": { + "HTTPTASKREQUESTBODYENCODING": { + "TITLE": "请求正文编码", + "DESCRIPTION": "Request body encoding (For example- UTF-8)." + } + }, + "HTTPTASKREQUESTTIMEOUTPACKAGE": { + "HTTPTASKREQUESTTIMEOUT": { + "TITLE": "请求超时(ms)", + "DESCRIPTION": "请求超时(毫秒)(例如-5000)。" + } + }, + "HTTPTASKDISALLOWREDIRECTSPACKAGE": { + "HTTPTASKDISALLOWREDIRECTS": { + "TITLE": "不允许重定向", + "DESCRIPTION": "禁止HTTP重定向的标志。" + } + }, + "HTTPTASKFAILSTATUSCODESPACKAGE": { + "HTTPTASKFAILSTATUSCODES": { + "TITLE": "故障状态代码", + "DESCRIPTION": "以逗号分隔的要重试的HTTP响应状态代码列表,例如400,5xx。" + } + }, + "HTTPTASKHANDLESTATUSCODESPACKAGE": { + "HTTPTASKHANDLESTATUSCODES": { + "TITLE": "处理状态代码", + "DESCRIPTION": "要忽略的HTTP响应状态代码的逗号分隔列表,例如404、3xx。" + } + }, + "HTTPTASKIGNOREEXCEPTIONPACKAGE": { + "HTTPTASKIGNOREEXCEPTION": { + "TITLE": "忽略异常", + "DESCRIPTION": "忽略异常的标志。" + } + }, + "HTTPTASKRESPONSEVARIABLENAMEPACKAGE": { + "HTTPTASKRESPONSEVARIABLENAME": { + "TITLE": "响应变量名", + "DESCRIPTION": "定义存储HTTP响应的变量名。" + } + }, + "HTTPTASKSAVEREQUESTVARIABLESPACKAGE": { + "HTTPTASKSAVEREQUESTVARIABLES": { + "TITLE": "保存请求变量", + "DESCRIPTION": "保存请求变量的标志。" + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSPACKAGE": { + "HTTPTASKSAVERESPONSEPARAMETERS": { + "TITLE": "保存响应状态,标题", + "DESCRIPTION": "保存响应状态、标题等的标志。" + } + }, + "HTTPTASKRESULTVARIABLEPREFIXPACKAGE": { + "HTTPTASKRESULTVARIABLEPREFIX": { + "TITLE": "结果变量前缀", + "DESCRIPTION": "执行变量名称的前缀。" + } + }, + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENTPACKAGE": { + "HTTPTASKSAVERESPONSEPARAMETERSTRANSIENT": { + "TITLE": "使結果變量瞬态變的", + "DESCRIPTION": "指示存储响应变量瞬态的标志" + } + }, + "HTTPTASKSAVERESPONSEASJSONPACKAGE": { + "HTTPTASKSAVERESPONSEASJSON": { + "TITLE": "将响应另存为JSON", + "DESCRIPTION": "指示将响应变量存储为JSON变量而不是字符串的标志" + } + }, + "HTTPTASKPARALLELINSAMETRANSACTIONPACKAGE" : { + "HTTPTASKPARALLELINSAMETRANSACTION" : { + "TITLE" : "Execute parallel in same transaction", + "DESCRIPTION" : "Flag indicating that the Http call should be done parallel in the same transaction. This means that multiple http tasks are executed in the same time in the same transaction and thus the entire execution of the case is faster." + } + }, + "CASETASKCASEREFERENCEPACKAGE": { + "CASETASKCASEREFERENCE": { + "TITLE": "案例参考", + "DESCRIPTION": "设置案例参考" + } + }, + "PROCESSTASKPROCESSREFERENCEPACKAGE": { + "PROCESSTASKPROCESSREFERENCE": { + "TITLE": "工艺参考", + "DESCRIPTION": "设置进程引用" + } + }, + "FALLBACKTODEFAULTTENANTPACKAGE": { + "FALLBACKTODEFAULTTENANT": { + "TITLE": "回退到默认租户", + "DESCRIPTION": "当指定租户中的键找不到定义时,使用默认租户作为回退" + } + }, + "PROCESSTASKINPARAMETERSPACKAGE": { + "PROCESSTASKINPARAMETERS": { + "TITLE": "在参数中", + "DESCRIPTION": "输入参数的定义" + } + }, + "PROCESSTASKOUTPARAMETERSPACKAGE": { + "PROCESSTASKOUTPARAMETERS": { + "TITLE": "输出参数", + "DESCRIPTION": "输出参数的定义" + } + }, + "TIMEREXPRESSIONPACKAGE": { + "TIMEREXPRESSION": { + "TITLE": "计时器表达式", + "DESCRIPTION": "一个iso-8601字符串或表达式,它解析为iso-8601字符串或java.util.Date。" + } + }, + "TIMERSTARTTRIGGERPACKAGE": { + "TIMERSTARTTRIGGERSOURCEREF": { + "TITLE": "启动触发计划项", + "DESCRIPTION": "对计划项的引用,为其配置的标准事件需要发生才能启动计时器(可选)" + }, + "TRANSITIONEVENT": { + "TITLE": "启动触发器转换事件", + "DESCRIPTION": "过渡事件的类型. 仅在设置开始触发计划项时使用" + } + }, + "DECISIONTASKDECISIONREFERENCEPACKAGE": { + "DECISIONTASKDECISIONREFERENCE": { + "TITLE": "决策参考", + "DESCRIPTION": "设置决策参考" + } + }, + "IFPARTCONDITIONPACKAGE": { + "IFPARTCONDITION": { + "TITLE": "条件", + "DESCRIPTION": "" + } + }, + "TRIGGERMODEPACKAGE": { + "TRIGGERMODE": { + "TITLE": "触发模式", + "DESCRIPTION": "确定是否使用内存(默认)为without(on event)评估哨兵条件。默认值意味着满足的哨兵部分(on和ifparts)将被存储。当重新评估哨兵时,后续评估将使用存储的部分。使用“on event”,对所有部分进行评估,如果所有部分均为真,则哨兵满意。否则,所有结果都将被丢弃而不存储。" + } + }, + "AUTOCOMPLETEPACKAGE": { + "AUTOCOMPLETEENABLED": { + "TITLE": "自动完成", + "DESCRIPTION": "当所有必需的子级都处于结束状态且没有其他子级处于活动状态时,指示阶段将自动完成的标志。" + }, + "AUTOCOMPLETECONDITION": { + "TITLE": "自动完成条件", + "DESCRIPTION": "如果阶段可以自动完成,则解析为的表达式。" + } + }, + "REQUIREDRULEPACKAGE": { + "REQUIREDENABLED": { + "TITLE": "必须的", + "DESCRIPTION": "指示在确定父阶段完成时是否需要阶段、任务或里程碑的标志。默认为false。" + }, + "REQUIREDRULECONDITION": { + "TITLE": "必需规则", + "DESCRIPTION": "在确定父阶段完成时,决定阶段、任务或里程碑是否需要的表达式。" + } + }, + "REPETITIONRULEPACKAGE": { + "REPETITIONENABLED": { + "TITLE": "重复", + "DESCRIPTION": "指示是否启用重复的标志" + }, + "REPETITIONRULECONDITION": { + "TITLE": "重复规则", + "DESCRIPTION": "用于确定是否需要创建计划的新实例的表达式。" + }, + "REPETITIONCOUNTERVARIABLENAME": { + "TITLE": "重复计数器变量", + "DESCRIPTION": "存储重复实例计数器的局部变量的名称。默认值为“repetitionCounter”。" + } + }, + "MANUALACTIVATIONRULEPACKAGE": { + "MANUALACTIVATIONENABLED": { + "TITLE": "手动激活", + "DESCRIPTION": "指示任务或阶段是否需要手动激活的标志。默认为false。" + }, + "MANUALACTIVATIONRULECONDITION": { + "TITLE": "手动激活规则", + "DESCRIPTION": "一种表达式,用于确定阶段或任务是否需要手动激活。" + } + }, + "COMPLETIONNEUTRALRULEPACKAGE": { + "COMPLETIONNEUTRALENABLED": { + "TITLE": "完成中性", + "DESCRIPTION": "指示计划项是否处于非完成状态的标志。默认为false。" + }, + "COMPLETIONNEUTRALRULECONDITION": { + "TITLE": "完成中性规则", + "DESCRIPTION": "用于确定计划项是否为非完成状态的表达式。" + } + }, + "PLANITEMLIFECYCLELISTENERSPACKAGE": { + "PLANITEMLIFECYCLELISTENERS": { + "TITLE": "生命周期监听器", + "DESCRIPTION": "计划项生命周期事件的监听器" + } + }, + "DISPLAYORDERPACKAGE": { + "DISPLAYORDER": { + "TITLE": "显示顺序", + "DESCRIPTION": "表示获取或显示阶段概述时与其他阶段相比的顺序的数值。" + } + }, + "INCLUDEINSTAGEOVERVIEWPACKAGE": { + "INCLUDEINSTAGEOVERVIEW": { + "TITLE": "包括在概述中", + "DESCRIPTION": "指示是否应为阶段概述考虑此阶段" + } + }, + "MILESTONEVARIABLEPACKAGE" : { + "MILESTONEVARIABLE": { + "TITLE": "Milestone variable", + "DESCRIPTION": "If set, a variable with this name and boolean value true will be created when this milestone is reached" + } + }, + "SCRIPTFORMATPACKAGE": { + "SCRIPTFORMAT": { + "TITLE": "脚本格式", + "DESCRIPTION": "脚本任务的脚本格式(javascript、groovy等)。" + } + }, + "SCRIPTTEXTPACKAGE": { + "SCRIPTTEXT": { + "TITLE": "脚本", + "DESCRIPTION": "脚本任务的脚本文本。" + } + }, + "TRANSITIONEVENTPACKAGE": { + "TRANSITIONEVENT": { + "TITLE": "过渡事件类型", + "DESCRIPTION": "过渡事件类型" + } + }, + "AVAILABLECONDITIONPACKAGE": { + "AVAILABLECONDITION": { + "TITLE": "可用条件", + "DESCRIPTION": "事件监听器上的可选条件表达式,用于指示何时可用。" + } + }, + "SERVICETASKSTORERESULTVARIABLETRANSIENTPACKAGE" : { + "SERVICETASKSTORERESULTVARIABLETRANSIENT" : { + "TITLE" : "使結果變量瞬變", + "DESCRIPTION" : "指示存储結果變量变量瞬态的标志" + } + } + }, + "STENCILS" : { + "GROUPS" : { + "DIAGRAM" : "图解", + "CONTAINERS" : "容器", + "ACTIVITIES" : "活动", + "EVENTLISTENERS" : "事件监听器", + "SENTRIES" : "哨兵", + "CONNECTORS" : "连接器" + }, + "CMMNDIAGRAM" : { + "TITLE" : "CMMN-图", + "DESCRIPTION" : "CMMN 2.0 图表。" + }, + "CASEPLANMODEL" : { + "TITLE" : "案例计划模型", + "DESCRIPTION" : "案例计划模型" + }, + "STAGE" : { + "TITLE" : "阶段", + "DESCRIPTION" : "阶段" + }, + "TASK" : { + "TITLE" : "任务", + "DESCRIPTION" : "手动任务" + }, + "HUMANTASK" : { + "TITLE" : "人工任务", + "DESCRIPTION" : "分配给特定人员的手动任务" + }, + "SERVICETASK" : { + "TITLE" : "服务任务", + "DESCRIPTION" : "具有服务逻辑的自动任务" + }, + "DECISIONTASK" : { + "TITLE" : "决策任务", + "DESCRIPTION" : "调用DMN决策的任务" + }, + "HTTPTASK" : { + "TITLE" : "HTTP任务", + "DESCRIPTION" : "一个HTTP任务" + }, + "SCRIPTTASK" : { + "TITLE" : "脚本任务", + "DESCRIPTION" : "具有脚本逻辑的自动任务" + }, + "MILESTONE" : { + "TITLE" : "里程碑", + "DESCRIPTION" : "里程碑" + }, + "CASETASK" : { + "TITLE" : "案例任务", + "DESCRIPTION" : "引用案例定义以启动新实例" + }, + "PROCESSTASK" : { + "TITLE" : "流程任务", + "DESCRIPTION" : "对流程定义的引用以启动新实例" + }, + "EVENTLISTENER" : { + "TITLE" : "事件监听器", + "DESCRIPTION" : "通用事件监听器" + }, + "TIMEREVENTLISTENER" : { + "TITLE" : "计时器事件监听器", + "DESCRIPTION" : "带有计时器触发器的事件监听器" + }, + "USEREVENTLISTENER" : { + "TITLE" : "用户事件监听器", + "DESCRIPTION" : "用户事件的监听器" + }, + "ENTRYCRITERION" : { + "TITLE" : "进入准则", + "DESCRIPTION" : "定义进入标准的哨兵" + }, + "EXITCRITERION" : { + "TITLE" : "退出准则", + "DESCRIPTION" : "定义出口标准的哨兵" + }, + "ASSOCIATION" : { + "TITLE" : "关联", + "DESCRIPTION" : "将哨兵与计划项目联系起来" + } + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "您有未保存的更改", + "DESCRIPTION": "您想如何处理未保存的更改?", + "ACTION": { + "SAVE": "保存更改", + "DISCARD": "放弃更改", + "CONTINUE": "继续编辑" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "业务流程模型", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建流程", + "IMPORT": "导入流程" + }, + + "FILTER" : { + "PROCESSES": "流程模型", + "PROCESSES-COUNT": "一共有 {{total}}个流程模型", + "PROCESSES-ONE": "有一个流程模型", + "PROCESSES-EMPTY": "目前还没有创建流程模型。您可以设计流程模型、用户表单,然后将它们捆绑到app中。第一步是创建流程模型:", + "PROCESSES-BPMN-HINT": "使用BPMN可视化编辑器创建BPMN模型.", + "PROCESSES-BPMN-IMPORT-HINT": "还可以导入现有的BPMN模型。", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到流程模型 \"{{filterText}}\"", + "RECENT": "最近", + "RECENT-COUNT": "{{total}} 最近使用的模型", + "RECENT-ONE": "最近使用的模型", + "RECENT-EMPTY": "最近没有使用模型" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "CASE-LIST" : { + "TITLE" : "案例模型", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建案例", + "IMPORT": "导入案例" + }, + + "FILTER" : { + "CASES": "案例模型", + "CASES-COUNT": "一共有 {{total}}个案例模型", + "CASES-ONE": "有一个case模型", + "CASES-EMPTY": "目前还没有创建案例模型。您可以设计实例模型、用户表单,然后将它们捆绑到app应用程序定义中。第一步是创建一个案例模型。:", + "CASES-CMMN-HINT": "使用CMMN可视化编辑器创建CMMN模型.", + "CASES-CMMN-IMPORT-HINT": "还可以导入现有CMMN模型。", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到case模型 \"{{filterText}}\"", + "RECENT": "最近", + "RECENT-COUNT": "{{total}} 最近使用的模型", + "RECENT-ONE": "最近使用的模型", + "RECENT-EMPTY": "最近没有使用模型" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "FORMS-LIST" : { + "TITLE" : "表单", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建表单", + "CREATE-INLINE": "现在创建一个新表单!", + "SHOW-MORE": "显示更多..." + }, + + "FILTER" : { + "FORMS": "表单", + "FORMS-COUNT": "一共有{{total}} 个表单", + "FORMS-ONE": "有一个表单", + "FORMS-EMPTY": "没有表单。若要添加一个,请单击创建表单 ", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到表单 \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "DECISIONS-LIST": { + "TITLE": "决策表", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION": { + "CREATE": "创建决策表", + "IMPORT": "导入决策表", + "CREATE-INLINE": "现在创建一个新的决策表!", + "SHOW-MORE": "显示更多..." + }, + + "FILTER": { + "DECISION-TABLES": "决策表", + "DECISION-TABLES-COUNT": "一共有 {{total}} 个决策表", + "DECISION-TABLES-ONE": "有一个决策表", + "DECISION-TABLES-EMPTY": "没有决策表。若要添加一个,请单击创建决策表 ", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到决策表 \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "APPS-LIST" : { + "TITLE" : "应用程序定义", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建应用程序", + "IMPORT": "导入应用程序", + "SHOW-MORE": "显示更多..." + }, + + "FILTER" : { + "APPS": "应用程序定义", + "APPS-COUNT": "一共有 {{total}}个应用程序定义", + "APPS-ONE": "有一个app定义", + "APPS-EMPTY": "没有应用程序定义。若要添加一个,请单击创建应用程序定义", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到应用程序定义 \"{{filterText}}\"", + + "NO-APPS": " 您可以通过发布一批流程模型来创建应用程序定义", + "NO-APPS-CALL-TO-ACTION": "现在可以创建一个应用程序定义 ", + "NO-APPS-NOTE": "当你准备好使用它时,记得要发布它。" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + "PROCESS": { + "NAME": "模型名称", + "KEY": "模型key", + "DESCRIPTION": "描述", + "VERSION-COMMENT": "版本注释", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DUPLICATE": "复制这个模型", + "EXPORT_BPMN20": "导出到BPMN2", + "DELETE": "删除这个模型", + "CREATE-CONFIRM": "创建新模型", + "DUPLICATE-CONFIRM": "复制这个模型", + "OPEN-IN-EDITOR": "可视化编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除流程模型", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个模型" + + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个模型没有描述信息,可以通过修改模型来添加一个描述" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的业务流程模型", + "DUPLICATE-TITLE": "复制这个业务流程模型", + "CREATE-DESCRIPTION": "您需要为新模型命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您可以更改新模型的名称,并且此时您可以更改描述信息。", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新模型。", + "DELETE-DESCRIPTION": "确实要删除进程模型吗? \"{{name}}\"?", + "EDIT-TITLE":"编辑模型详细信息", + "DELETE-TITLE": "删除模型", + "DELETE-LOADING-RELATIONS": "检查模型使用...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-RELATIONS-DESCRIPTION": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-PROCESS-RELATION": "流程模型", + "DELETE-FORM-RELATION": "表单模型", + "DELETE-APP-RELATION": "App模型", + "IMPORT-DESCRIPTION": "请浏览或拖拽.bpmn或.bpmn20.xml扩展名的BPMN XML定义", + "IMPORT-TITLE": "导入一个流程模型", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建", + "SHARED-WITH": "分享", + "PERMISSION": "许可", + "ACTIONS": "动作", + "IMPORT": { + "DROPZONE": "拖拽一个 .bpmn 或者 .bpmn20.xml BPMN XML 文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理BPMN XML文件时出错", + "NO-DROP": "不支持拖放" + } + }, + "ALERT": { + "EDIT-CONFIRM": "模型被更新" + }, + "ERROR": { + "NOT-FOUND": "所请求的模型不存在" + } + }, + + "SUBPROCESS": { + "NAME": "子流程名称", + "DESCRIPTION": "描述信息", + "ACTION": { + "CREATE-CONFIRM": "创建一个子流程" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的子流程", + "CREATE-DESCRIPTION": "您需要为新的子流程命名,并且您可能希望同时添加描述。" + } + }, + + "CASE": { + "NAME": "模型名称", + "KEY": "模型key", + "DESCRIPTION": "描述信息", + "VERSION-COMMENT": "版本注释", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DUPLICATE": "复制这个模型", + "EXPORT_CMMN": "导出到CMMN1.1", + "DELETE": "删除这个模型", + "CREATE-CONFIRM": "创建新模型", + "DUPLICATE-CONFIRM": "复制这个模型", + "OPEN-IN-EDITOR": "可视化编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除case模型", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个模型" + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被 {{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个模型没有描述信息,可以通过修改模型来添加一个描述" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的案例模型", + "DUPLICATE-TITLE": "复制这个案例模型", + "CREATE-DESCRIPTION": "您需要为新模型命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您可以更改新模型的名称,并且此时您可以更改描述信息。", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新模型。", + "DELETE-DESCRIPTION": "确实要删除进程流程吗 \"{{name}}\"?", + "EDIT-TITLE":"编辑模型详细信", + "DELETE-TITLE": "删除模型", + "DELETE-LOADING-RELATIONS": "检查模型使用...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-RELATIONS-DESCRIPTION": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-PROCESS-RELATION": "案例模型", + "DELETE-FORM-RELATION": "表单模型", + "DELETE-APP-RELATION": "应用程序模型", + "IMPORT-DESCRIPTION": "请浏览或拖拽.cmmn 或者.cmmn.xml 扩展名的CMMN XML", + "IMPORT-TITLE": "导入一个案例模型", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新应用程序模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建", + "SHARED-WITH": "分享", + "PERMISSION": "许可", + "ACTIONS": "动作", + "IMPORT": { + "DROPZONE": "拖拽一个 .cmmn or .cmmn.xml CMMN XML文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理CMMN XML文件时出错", + "NO-DROP": "不支持拖放" + } + }, + "ALERT": { + "EDIT-CONFIRM": "模型被更新" + }, + "ERROR": { + "NOT-FOUND": "所请求的模型不存在" + } + }, + + "FORM": { + "NAME": "表单名称", + "KEY": "表单key", + "DESCRIPTION": "描述", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DELETE": "复制这个表单", + "CREATE-CONFIRM": "创建新表单", + "DUPLICATE": "复制这个表单", + "DUPLICATE-CONFIRM": "复制这个表单", + "OPEN-IN-EDITOR": "表单编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除表单", + "USE-AS-NEW-VERSION": "作为新版本使用" + + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的表单", + "DUPLICATE-TITLE": "复制这个表单", + "CREATE-DESCRIPTION": "您需要为新表单命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您需要为新表单命名,并且您可以在这个操作中添加描述信息。", + "SAVE-FORM-TITLE": "保存表单", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新表单。", + "DELETE-DESCRIPTION": "确实要删除表单 \"{{name}}\"?", + "EDIT-TITLE":"编辑表单详细信息", + "DELETE-TITLE": "删除表单", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-VERSION": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建" + } + }, + + "DECISION-TABLE": { + "NAME": "决策表 名称", + "KEY": "决策表 key", + "DESCRIPTION": "描述", + "VERSION-COMMENT": "版本注释", + "HIT-POLICY": "命中策略:", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "SHARE": "分享决策表", + "DELETE": "删除决策表", + "ADD-COMMENT": "+ 添加评论", + "CREATE-CONFIRM": "创建新的决策表", + "OPEN-IN-EDITOR": "决策表编辑器", + "EXPORT": "Export 决策表", + "DELETE-CONFIRM": "删除决策表", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个决策表", + "DUPLICATE": "复制这个决策表" + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "COMMENTS-TITLE": "评论", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建" + }, + "HIT-POLICIES": { + "FIRST": "第一个", + "ANY": "任何", + "UNIQUE": "唯一", + "PRIORITY": "优先级", + "RULE ORDER": "规则顺序", + "OUTPUT ORDER": "输出顺序", + "COLLECT": "采集" + }, + "COLLECT-OPERATORS": { + "SUM": "和", + "MIN": "最小", + "MAX": "最大", + "COUNT": "总数" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的决策表", + "CREATE-DESCRIPTION": "您需要为新决策表命名,并且您可以在这个操作中添加描述信息。", + "SAVE-DESCRIPTION": "您可以更改新决策表的名称,并且此时您可以更改描述信息。", + "DUPLICATE-TITLE": "复制决策表", + "DUPLICATE-DESCRIPTION": "您需要为新决策表命名,并且您可以在这个操作中添加描述信息。", + "DELETE-TITLE": "删除决策表", + "DELETE-DESCRIPTION": "确实要删除决策表 \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "保存决策表", + "IMPORT-DESCRIPTION": "请浏览或拖拽.dmn or .dmn.xml扩展名的的 DMN XML文件", + "IMPORT-TITLE": "导入DMN模型", + "IMPORT": { + "DROPZONE": "拖拽一个 .dmn or .dmn.xml DMN XML文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理DMN XML文件时出错", + "NO-DROP": "不支持拖放" + }, + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-VERSION": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建" + }, + "ALERT": { + "FAVORITE-CONFIRM": "喜欢这个决策表", + "UN-FAVORITE-CONFIRM": "这个决策表不再流行了" + } + }, + + "APP": { + "NAME": "应用程序定义名称", + "KEY": "应用程序定义key", + "DESCRIPTION": "描述", + "ICON": "图标", + "THEME": "主题", + "GROUPS-ACCESS": "组访问,用逗号分隔", + "USERS-ACCESS": "用户访问,用逗号分隔", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改应用程序定义属性", + "DUPLICATE": "复制这个应用", + "SHARE": "分享应用程序定义", + "DELETE": "删除应用程序定义", + "CREATE-CONFIRM": "创建新的应用程序定义", + "DUPLICATE-CONFIRM": "复制这个应用程序定义", + "DELETE-CONFIRM": "删除应用程序定义", + "USE-AS-NEW-VERSION": "作为新版本使用", + "OPEN-IN-EDITOR": "应用程序编辑器", + "PUBLISH": "发布", + "PUBLISH-CONFIRM": "发布应用程序定义", + "SELECT-ICON": "修改图标...", + "SELECT-THEME": "修改主题...", + "EDIT-MODELS": "编辑包含的模型", + "EXPORT-ZIP": "将app定义导出为zip文件", + "EXPORT-BAR": "将app定义导出为可部署的bar文件" + + }, + "DETAILS": { + "TITLE": "App定义详细信息: {{name}}", + "HISTORY-TITLE": "历史", + "MODELS-TITLE": "app定义中包含的模型", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个应用程序定义没有描述信息,可以通过修改应用程序定义来添加一个描述", + "NO-MODELS-SELECTED": "没有为这个应用程序选择模型" + }, + "TITLE": { + "SELECT-ICON": "选择应用图标", + "SELECT-THEME": "选择应用主题", + "PREVIEW": "预览" + + }, + "POPUP": { + "CREATE-TITLE": "创建新的应用程序定义", + "DUPLICATE-TITLE": "复制一个应用程序定义", + "SAVE-APP-TITLE": "保存应用程序定义", + "SAVE-APP-SAVE-SUCCESS": "保存的应用程序定义", + "CREATE-DESCRIPTION": "您需要为新的应用程序定义命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您需要为新的应用程序定义命名,并且您可以在这个操作中添加描述信息。", + "PUBLISH-TITLE": "发布应用程序定义", + "PUBLISH-DESCRIPTION": "您确定要发布应用程序定义 \"{{name}}\"? 注意这个应用程序定义将版本化,如果已经存在,则将更新工作流应用程序。", + "PUBLISH-FIELD": "发布?请注意,如果启用了发布,则将版本化此应用程序定义,如果已经存在,则将更新工作流应用程序。", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "你的流程模型 \"{{modelInAppName}}\"具有相同的标识符\"{{processDefinitionKey}}\"作为已经存在的部署流程\"{{conflictingModelName}}\" ,关于这个应用程序 \"{{conflictingAppName}}\". 请修改这个 \"id\"流程模型的属性。", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "下面的流程模型已经在另一个应用程序中使用了。这样行吗?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "应用程序", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "无效的应用程序: 找到重复的流程标识符 (修改这个非法的流程模型 \"id\"属性):", + "DELETE-TITLE": "删除应用程序定义", + "DELETE-DESCRIPTION": "确实要删除应用程序定义 \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "确实要删应用程序定义 \"{{name}}\"? 注意,这个应用程序定义已经部署到任务landing页面,并且通过确认,该应用程序将从任务应用程序landing页面中删除。", + "DELETE-CASCADE-FALSE": "只删除当前版本的应用程序定义 (v{{version}})", + "DELETE-CASCADE-TRUE": "也删除所有以前的版本应用程序定义", + "HAS-CUSTOM-STENCILITEM" : "模型 \"{{modelName}}\" 使用带有自定义模板项目的模板. 在这个模型中使用这个模型是不可能的.", + "HAS-VALIDATIONERROR" : "模型 \"{{modelName}}\" 有验证错误,不能添加到应用程序定义.在编辑器中打开模型以查看关于验证错误的更多细节。", + "IMPORT-DESCRIPTION":"请使用.zip扩展的应用程序定义浏览或拖拽一个", + "IMPORT-TITLE":"导入应用程序定义模型", + "IMPORT": { + "DROPZONE": "扩拽一个.zip 应用程序定义文件", + "CANCEL-UPLOAD": "取消上传", + "RENEWIDM-IDS": "Renew the user and group identifiers when importing step and BPMN models. This is often required when importing the 应用程序定义 into a different Flowable environment. It will try to link the human steps and user tasks to the right user and group in this target environment.", + "ERROR": "处理应用程序定义文件时出错", + "NO-DROP": "不支持拖放" + }, + "INCLUDE-MODELS-TITLE": "包含在应用程序定义中的模型" + }, + "ALERT": { + "DELETE-CONFIRM": "应用程序定义删除了", + "PUBLISH-CONFIRM": "应用程序定义已经被发布了", + "PUBLISH-ERROR": "不能发布应用程序定义. 请检查引用的流程模型的有效性。" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "添加另一个人" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "文本", + "MULTILINE-TEXT": "多行文本", + "PASSWORD": "密码", + "NUMBER": "数字", + "CHECKBOX": "多选", + "DATE": "日期", + "DROPDOWN": "下拉", + "RADIO": "单选按钮", + "PEOPLE": "选择人", + "GROUP-OF-PEOPLE": "选择组", + "UPLOAD": "上传文件", + "EXPRESSION": "表达式", + "DECIMAL": "小数", + "HYPERLINK": "超链接", + "SPACER": "垫片", + "HORIZONTAL-LINE": "横线", + "HEADLINE": "标题", + "HEADLINE-WITH-LINE":"标题和线" + }, + "TABS": { + "GENERAL": "一般", + "OPTIONS": "选项", + "UPLOAD-OPTIONS": "上传选项", + "ADVANCED-OPTIONS":"高级" + }, + "VERSION": "版本 {{version}}", + "LAST-UPDATED": "最后更新的 {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "设计", + "OUTCOME": "结果" + }, + "POPUP": { + "EDIT-TITLE": "编辑字段 '{{name}}'", + "EXPRESSION-TITLE": "编辑表达式" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(没有表达值)", + "EXPRESSION-HELP": "您还可以使用如下的符号来引用先前以任何形式提交的值,作为文本的一部分 ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "可以使用表达式来动态填充选项,例如通过引用这样的变量 ${optionsVariable}. 这个表达式需要产生一个java对象(java.util)。带有选项对象的列表)或其json表示。" + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "选择组..", + "PERSON": "选择人.." + }, + "COMPONENT": { + "LABEL": "标签:", + "OVERRIDEID": "覆盖id?", + "ID": "Id:", + "PLACEHOLDER": "默认值:", + "OPTIONS": "选项", + "RADIO-BUTTON-DEFAULT": "选项 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "请选择一个...", + "DROPDOWN-EMPTY-VALUE-HELP": " 这是‘空值’选项。在运行时选择它意味着‘没有值’或’空’。这允许用于可选字段,但不允许用于必需字段。", + "OPTIONS-EXPRESSION": "选择表达:", + "OPTIONS-EXPRESSION-ENABLED": "启用选项表达", + "REQUIRED": "必填", + "READONLY": "只读", + "EXPRESSION": "表达式", + "ADD-OPTION": "+ 添加一个新选项", + "UPLOAD-ALLOW-MULTIPLE": "允许上传多个文件", + "SIZE": "大小", + "MAX-LENGTH":"最大长度:", + "MIN-LENGTH":"最小长度:", + "PASSWORD-UNMASK-OPTION": "密码屏蔽/揭露选项", + "HYPERLINK-URL": "超链接地址", + "REGEX-PATTERN":"正则表达式的标准", + "MASK":{ + "TITLE":"输入掩码", + "EXAMPLES":{ + "TITLE":"例子:", + "NUMBER":"任何数字", + "LETTER":"任何字母", + "NUMBERORLETTER":"任何字母或数字", + "OPTIONAL":"使蒙版可选(无效)", + "PHONE":"电话" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "您可以为这个任务定义多个结果。在完成一个任务时,用户选择一个可用的结果,可在后续的流程中使用结果变量", + "NO-OUTCOMES-OPTION": "不要使用自定义结果,只显示'完成'按钮。", + "OUTCOMES-OPTION": "使用此表单的定制结果。", + "POSSIBLE-OUTCOMES": "可能的结果", + "NEW-OUTCOME-PLACEHOLDER": "输入新的结果", + "ADD": "添加结果", + "REMOVE": "移除" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "未定义" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "编辑输入列", + "INPUT-DESCRIPTION": "选择输入变量作为列的输入", + "OUTPUT-TITLE": "编辑输出列", + "OUTPUT-DESCRIPTION": "选择一个现有的输出变量或创建一个新的变量", + "EXPRESSION-LABEL": "列标签:", + "EXPRESSION-PLACEHOLDER": "输入可选标签", + "EXPRESSION-VARIABLE-NAME": "变量名称:", + "EXPRESSION-VARIABLE-TYPE": "变量类型:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "输入变量名", + "OUTPUT-NEW-VARIABLE-ID": "变量ID:", + "OUTPUT-NEW-VARIABLE-TYPE": "变量类型:", + "COMPLEX-EXPRESSION-LABEL": "复杂表达式:", + "ALLOWED-VALUES": "允许值(可选):", + "OUTPUT-VALUES": "输出值", + "OUTPUT-VALUES-OPTIONAL": "(可选):", + "OUTPUT-VALUES-NOT-OPTIONAL": "(为优先级/输出顺序拖动行):" + } + }, + "BUTTON-ACTIONS-LABEL": "动作", + "BUTTON-ADD-INPUT-LABEL": "添加输入", + "BUTTON-ADD-OUTPUT-LABEL": "添加输出", + "BUTTON-ADD-RULE-LABEL": "添加规则", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "向上移动", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "向下移动", + "BUTTON-REMOVE-RULE-LABEL": "移除规则", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "所有输入和输出表达式都必须引用表单字段或变量。", + "SAVE-CONFIRM": "保存决策表'{{name}}'" + } + }, + + "TOUR": { + "WELCOME-TITLE": "欢迎, {{userName}}", + "WELCOME-CONTENT": "这是一个短暂的flowable编辑器. 接下来的几个步骤将指导您通过应用程序的不同部分来启动。按ESC键随时停止。" , + "PALETTE-TITLE": "调色板", + "PALETTE-CONTENT": "在这里可以找到创建业务流程的所有可用构成。它们是按逻辑组排列的。只需点击它就可以打开一组:", + "CANVAS-TITLE": "画布", + "CANVAS-CONTENT": "这是创建业务流程的工作空间。从左侧的调色板中拖动元素,并将它们放在画布上以开始建模", + "DRAGDROP-TITLE": "拖放示例", + "DRAGDROP-CONTENT": "下面是一个如何开始建模的例子:", + "PROPERTIES-TITLE": "属性", + "PROPERTIES-CONTENT": "在这里您可以配置业务流程构造的属性。只需选择画布上的项目,它的属性就会显示出来。如果要编辑该属性,请单击该属性。", + "TOOLBAR-TITLE": "工具栏", + "TOOLBAR-CONTENT": "可以在这里找到所有的动作:保存或验证模型, 复制和粘贴一个流程的部分, 等等. 在按钮上悬停以此获得对动作的描述信息.", + "END-TITLE": "终点", + "END-CONTENT": "就是这样!现在可以开始建模过程。如果你有任何问题,可以问他们。 Flowable论坛 " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "教程", + "DESCRIPTION" : "当使用连线流将流程按照步骤彼此连接的时候,您可能会发现,这些连线彼此交叉,或者您希望以不同的方式排列它们。这样做, 可以向连线添加或移除一个弯曲点。

如下图所示,你首先应该点击 '添加弯曲点' 然后单击连线添加它。注意,连线将在绿色中显示一个微妙的指示,以显示可以在那里添加弯曲点。

删除一个弯曲点再次遵循类似的模式: 点击 '移除弯曲点' 按钮 ,然后点击弯曲点再次移除。" + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "保存", + "ACTION.SAVE-AND-CLOSE" : "保存和关闭编辑器", + "ACTION.SEND" : "发送", + "ACTION.CANCEL" : "取消", + "ACTION.SELECT" : "选择", + "ACTION.ADD" : "添加", + "ACTION.REMOVE" : "移除", + "ACTION.MOVE.UP" : "移动入口", + "ACTION.MOVE.DOWN" : "向下移动", + + "TOOLBAR.ACTION.CLOSE" : "关闭编辑器并返回到概览页面", + "TOOLBAR.ACTION.SAVE" : "保存模型", + "TOOLBAR.ACTION.VALIDATE" : "验证模型", + "TOOLBAR.ACTION.CUT" : "剪切 (在业务流程中选择一个或多个元素)", + "TOOLBAR.ACTION.COPY" : "拷贝 (在业务流程中选择一个或多个元素)", + "TOOLBAR.ACTION.PASTE" : "粘贴", + "TOOLBAR.ACTION.DELETE" : "删除选定元素", + "TOOLBAR.ACTION.UNDO" : "撤消", + "TOOLBAR.ACTION.REDO" : "重做", + "TOOLBAR.ACTION.ZOOMIN" : "放大", + "TOOLBAR.ACTION.ZOOMOUT" : "缩小", + "TOOLBAR.ACTION.ZOOMACTUAL" : "缩放到实际尺寸", + "TOOLBAR.ACTION.ZOOMFIT" : "缩放到适当大小", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "向选定的连线添加弯曲点", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "向选定的连线移除弯曲点", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "水平对齐", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "垂直对齐", + "TOOLBAR.ACTION.SAMESIZE" : "相同大小", + "TOOLBAR.ACTION.HELP": "开始导游", + "TOOLBAR.ACTION.FEEDBACK": "提供反馈", + + "FORM_TOOLBAR.ACTION.SAVE" : "保存模型", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "保存应用程序定义", + + "BUTTON.ACTION.DELETE.TOOLTIP": "从模型中删除元素", + "BUTTON.ACTION.MORPH.TOOLTIP": "更改元素类型", + + "ELEMENT.AUTHOR" : "作者", + "ELEMENT.DATE_CREATED" : "创建日期", + + "PROPERTY.REMOVED" : "移除", + "PROPERTY.EMPTY" : "空值", + "PROPERTY.PROPERTY.EDIT.TITLE" : "更改值为", + + "PROPERTY.FEEDBACK.TITLE" : "请填写您的反馈意见", + + "PROPERTY.ASSIGNMENT.TITLE" : "分配", + "PROPERTY.ASSIGNMENT.TYPE" : "类型", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "身份存储", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "固定值", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "分配", + "PROPERTY.ASSIGNMENT.MATCHING" : "使用 ↑ 和 ↓选择并按Enter确认或使用鼠标", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "输入分配人", + "PROPERTY.ASSIGNMENT.EMPTY" : "没有选择分配人", + "PROPERTY.ASSIGNMENT.NONE" : "未分配经办人", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "搜索用户", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "搜索组", + "PROPERTY.ASSIGNMENT.SEARCH": "搜索: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "分配人 {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} 候选用户", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "候选用户", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} 候选组", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "候选组", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "用户 {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "用户 {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "字段 {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "流程发起人", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "分配", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "没有选择候选人...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "没有选择候选组...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "分配给流程发起人", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "分配给单个用户", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "候选用户", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "候选组", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "允许流程发起人完成任务", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} 执行监听器", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "没有配置执行监听器", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "事件", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "类", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "表达式", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "没有选择执行监听器", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "字符串", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "未选择字段", + + "PROPERTY.FIELDS" : "{{length}} 字段", + "PROPERTY.FIELDS.EMPTY" : "未选择字段", + "PROPERTY.FIELDS.NAME" : "名称", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.FIELDS.STRING" : "字符串", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.FIELDS.IMPLEMENTATION" : "实现", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} 数据对象", + "PROPERTY.DATAPROPERTIES.EMPTY" : "没有配置数据对象", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "输入一个id", + "PROPERTY.DATAPROPERTIES.NAME" : "名称", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.DATAPROPERTIES.TYPE" : "类型", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "输入一个值 (可选)", + "PROPERTY.DATAPROPERTIES.VALUE" : "默认值", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} 表单属性", + "PROPERTY.FORMPROPERTIES.EMPTY" : "没有选择表单属性", + "PROPERTY.FORMPROPERTIES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "输入一个id", + "PROPERTY.FORMPROPERTIES.NAME" : "名称", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.FORMPROPERTIES.TYPE" : "类型", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "日期格式", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "输入日期格式", + "PROPERTY.FORMPROPERTIES.VALUES" : "值", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "未选择枚举值", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "名称", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "输入id值", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "输入名称值", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "表达式", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "变量", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "输入一个变量", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "默认值", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "输入一个默认值", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "必须的", + "PROPERTY.FORMPROPERTIES.READABLE" : "可读的", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "可写的", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}}个输入参数", + "PROPERTY.INPARAMETERS.EMPTY" : "没有配置输入参数", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}}个输出参数", + "PROPERTY.OUTPARAMETERS.EMPTY" : "没有配置输出参数", + + "PROPERTY.PARAMETER.SOURCE" : "源", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "输入一个源", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "源表达式", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "输入一个源表达式", + "PROPERTY.PARAMETER.TARGET" : "目标", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "输入一个目标", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "目标表达式", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "输入一个目标表达式", + "PROPERTY.PARAMETER.EMPTY" : "没有选择参数", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.PROCESSREFERENCE.TITLE" : "流程参考", + "PROPERTY.PROCESSREFERENCE.ERROR.PROCESS" : "加载流程出错。稍后再试一次", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "加载流程...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "此文件夹不包含流程", + + "PROPERTY.FORMREFERENCE.EMPTY" : "没有选择参考", + "PROPERTY.FORMREFERENCE.TITLE" : "表单引用", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "引用表单", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "加载表单出错。稍后再试一次", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "加载表单...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "此文件夹不包含表单", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}}任务监听器", + "PROPERTY.TASKLISTENERS.EMPTY" : "没有配置任务监听器", + "PROPERTY.TASKLISTENERS.EVENT" : "事件", + "PROPERTY.TASKLISTENERS.CLASS" : "类", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "表达式", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "没有选择任务监听器", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "字符串", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "没有选择字段", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} 事件监听器", + "PROPERTY.EVENTLISTENERS.EMPTY" : "没有配置事件监听器", + "PROPERTY.EVENTLISTENERS.EVENTS": "事件", + "PROPERTY.EVENTLISTENERS.RETHROW": "Rethrow event?", + "PROPERTY.EVENTLISTENERS.CLASS" : "类", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "实体类型", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "输入一个实体类型", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Rethrow event type", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "错误码", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "输入一个错误码", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "消息名称", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "输入一个消息名称", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "信号名称", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "输入信号名称", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "没有选择事件监听器", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}}个生命周期侦听器", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "未配置生命周期侦听器", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "事件", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "源状态", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "目标状态", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "类", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "未选择任务监听器", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "字符值", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符值", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "字符", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符值", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "没有选中字段", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} 信号定义", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "没有配置信号定义", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "全局", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "流程实例", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Id", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "名称", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Scope", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} 消息定义", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "没有配置消息定义", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "名称", + + "PROPERTY.ESCALATIONDEFINITIONS.DISPLAY" : "{{length}} 个升级定义", + "PROPERTY.ESCALATIONDEFINITIONS.EMPTY" : "没有配置升级定义", + "PROPERTY.ESCALATIONDEFINITIONS.ID" : "Id", + "PROPERTY.ESCALATIONDEFINITIONS.NAME" : "名称", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "没有确定连线的顺序", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "设置连线的顺序", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "没有发现流出连线.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "设置需要评估连线的顺序:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "连线到 {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "连线条件", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "条件表达式", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "没有设置条件", + + "PROPERTY.DUEDATE.EMPTY" : "没有到期", + "PROPERTY.DUEDATE.DEFINED" : "定义到期日", + "PROPERTY.DUEDATE.TITLE" : "到期日", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "到期日表达式", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "没有到期日", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "表达式定义", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "任务创建后的固定持续时间", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "基于字段", + + "MODEL.SAVE.TITLE" : "保存模型", + "MODEL.VALIDATE.TITLE" : "验证结果", + "MODEL.NAME" : "名称", + "MODEL.KEY" : "Key", + "MODEL.DESCRIPTION" : "描述", + "MODEL.SAVE.NEWVERSION" : "将此保存为新版本?这意味着你可以回到以前的版本。", + "MODEL.SAVE.COMMENT" : "评论", + "MODEL.SAVE.SAVING" : "正在保存模型", + "MODEL.LASTMODIFIEDDATE" : "最后保存", + "MODEL.SAVE.ERROR": "Unexpected error: 不能保存模型", + "MODEL.VALIDATIONERRORS": " 注意,模型包含验证错误。这意味着该模型在当前状态下不能部署在Flowable引擎上。", + "MODEL.CONFLICT.WRITE": "不能保存模型: '{{userFullName}}'对该模型进行了更改", + "MODEL.CONFLICT.WRITE.OPTIONS": "选择一个选项来解决此冲突:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "覆盖其他模型", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "放弃我的改变", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "保存为新模型", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "创建新版本", + "MODEL.CONFLICT.SAVEAS" : "另存为:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "一项活动将作为对另一活动的补偿而被执行。事件针对即将执行的活动进行补偿。", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "一项活动已圆满完成。", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "活动已接收到错误事件。在活动接收到实际错误之前发送", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "创建了新的membership", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "单个membership已被删除", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "相关组中的所有成员已被删除。由于可能的原因,个别事件不会被派遣。", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "一个任务已经被分配人了。这将抛出一个实体更新事件", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "一个任务已经被完成。在删除任务实体之前调度", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "当BPMN错误被抛出,但未在流程中捕获时", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "已经创建了一个新的变量", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "已删除现有变量", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "已更新现有变量", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "决策表引用", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "加载决策表出现错误. 稍后再试一次", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "加载决策表...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "此文件夹不包含任何决策表", + + "PROPERTY.CASEREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.CASEREFERENCE.TITLE" : "案例型引用", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "加载案例模型时出错。稍后再试一次", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "加载案例模型...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "此文件夹不包含任何案例模型" +} diff --git a/zbf-admin/src/main/resources/static/designer/i18n/zh-TW.json b/zbf-admin/src/main/resources/static/designer/i18n/zh-TW.json new file mode 100644 index 0000000..ffcc5f5 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/i18n/zh-TW.json @@ -0,0 +1,1006 @@ +{ + "GENERAL" : { + "MAIN-TITLE": "Flowable编辑器", + "NAVIGATION" : { + "PROCESSES": "流程", + "CASEMODELS": "案例模型", + "FORMS": "表单", + "DECISION-TABLES": "决策表", + "APPS": "应用程序" + }, + "TITLE": { + "SELECT-GROUP" :"选择组", + "MATCHING-GROUPS": "匹配组", + "FILTER": "过滤", + "HISTORY": "历史" + }, + "ACTION": { + "LOGOUT": "退出", + "RETURN-TO-LIST": "显示所有定义", + "CANCEL": "取消", + "CLOSE": "关闭", + "EDIT": "编辑", + "SAVE": "保存", + "OPEN": "打开", + "OK": "Ok", + "CONFIRM": "确认", + "CONFIRM-AND-CLOSE": "确认并且关闭", + "NEW-FORM": "新表单", + "CREATE-FORM": "创建表单", + "NEW-DECISION-TABLE": "新决策表", + "CREATE-DECISION-TABLE": "创建决策表" + }, + "MESSAGE": { + "SELECT-GROUP-HELP": "使用 ↑ 和 ↓ 选择并按回车确认", + "PEOPLE-NO-MATCHING-RESULTS": "没有找到匹配的用户", + "GROUP-NO-MATCHING-RESULTS": "没有找到匹配的组", + "GROUP-SOURCE-TYPE": "组源", + "GROUP-SOURCE-SEARCH-OPTION": "组搜索", + "GROUP-SOURCE-FIELD-OPTION": "表单字段" + } + }, + + "EDITOR": { + "POPUP": { + "UNSAVED-CHANGES": { + "TITLE": "您有未保存的更改", + "DESCRIPTION": "您想如何处理未保存的更改?", + "ACTION": { + "SAVE": "保存更改", + "DISCARD": "放弃更改", + "CONTINUE": "继续编辑" + } + } + } + }, + + "PROCESS-LIST" : { + "TITLE" : "业务流程模型", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建流程", + "IMPORT": "导入流程" + }, + + "FILTER" : { + "PROCESSES": "流程模型", + "PROCESSES-COUNT": "一共有 {{total}}个流程模型", + "PROCESSES-ONE": "有一个流程模型", + "PROCESSES-EMPTY": "目前还没有创建流程模型。您可以设计流程模型、用户表单,然后将它们捆绑到app中。第一步是创建流程模型:", + "PROCESSES-BPMN-HINT": "使用BPMN可视化编辑器创建BPMN模型.", + "PROCESSES-BPMN-IMPORT-HINT": "还可以导入现有的BPMN模型。", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到流程模型 \"{{filterText}}\"", + "RECENT": "最近", + "RECENT-COUNT": "{{total}} 最近使用的模型", + "RECENT-ONE": "最近使用的模型", + "RECENT-EMPTY": "最近没有使用模型" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "CASE-LIST" : { + "TITLE" : "案例模型", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建案例", + "IMPORT": "导入案例" + }, + + "FILTER" : { + "CASES": "案例模型", + "CASES-COUNT": "一共有 {{total}}个案例模型", + "CASES-ONE": "有一个case模型", + "CASES-EMPTY": "目前还没有创建案例模型。您可以设计实例模型、用户表单,然后将它们捆绑到app应用程序定义中。第一步是创建一个案例模型。:", + "CASES-CMMN-HINT": "使用CMMN可视化编辑器创建CMMN模型.", + "CASES-CMMN-IMPORT-HINT": "还可以导入现有CMMN模型。", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到case模型 \"{{filterText}}\"", + "RECENT": "最近", + "RECENT-COUNT": "{{total}} 最近使用的模型", + "RECENT-ONE": "最近使用的模型", + "RECENT-EMPTY": "最近没有使用模型" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "FORMS-LIST" : { + "TITLE" : "表单", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建表单", + "CREATE-INLINE": "现在创建一个新表单!", + "SHOW-MORE": "显示更多..." + }, + + "FILTER" : { + "FORMS": "表单", + "FORMS-COUNT": "一共有{{total}} 个表单", + "FORMS-ONE": "有一个表单", + "FORMS-EMPTY": "没有表单。若要添加一个,请单击创建表单 ", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到表单 \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "DECISION-TABLES-LIST": { + "TITLE": "决策表", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION": { + "CREATE": "创建决策表", + "IMPORT": "导入决策表", + "CREATE-INLINE": "现在创建一个新的决策表!", + "SHOW-MORE": "显示更多..." + }, + + "FILTER": { + "DECISION-TABLES": "决策表", + "DECISION-TABLES-COUNT": "一共有 {{total}} 个决策表", + "DECISION-TABLES-ONE": "有一个决策表", + "DECISION-TABLES-EMPTY": "没有决策表。若要添加一个,请单击创建决策表 ", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到决策表 \"{{filterText}}\"" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + + "APPS-LIST" : { + "TITLE" : "应用程序定义", + "SEARCH-PLACEHOLDER": "搜索", + "ACTION" : { + "CREATE": "创建应用程序", + "IMPORT": "导入应用程序", + "SHOW-MORE": "显示更多..." + }, + + "FILTER" : { + "APPS": "应用程序定义", + "APPS-COUNT": "一共有 {{total}}个应用程序定义", + "APPS-ONE": "有一个app定义", + "APPS-EMPTY": "没有应用程序定义。若要添加一个,请单击创建应用程序定义", + "FILTER-TEXT": ", 匹配 \"{{filterText}}\"", + "FILTER-TEXT-EMPTY": "没有匹配到应用程序定义 \"{{filterText}}\"", + + "NO-APPS": " 您可以通过发布一批流程模型来创建应用程序定义", + "NO-APPS-CALL-TO-ACTION": "现在可以创建一个应用程序定义 ", + "NO-APPS-NOTE": "当你准备好使用它时,记得要发布它。" + }, + + "SORT": { + "MODIFIED-ASC": "按照修改时间升序", + "MODIFIED-DESC": "按照修改时间降序", + "NAME-ASC": "按照名称升序", + "NAME-DESC": "按照名称降序" + } + }, + "PROCESS": { + "NAME": "模型名称", + "KEY": "模型key", + "DESCRIPTION": "描述", + "VERSION-COMMENT": "版本注释", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DUPLICATE": "复制这个模型", + "EXPORT_BPMN20": "导出到BPMN2", + "DELETE": "删除这个模型", + "CREATE-CONFIRM": "创建新模型", + "DUPLICATE-CONFIRM": "复制这个模型", + "OPEN-IN-EDITOR": "可视化编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除流程模型", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个模型" + + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个模型没有描述信息,可以通过修改模型来添加一个描述" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的业务流程模型", + "DUPLICATE-TITLE": "复制这个业务流程模型", + "CREATE-DESCRIPTION": "您需要为新模型命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您可以更改新模型的名称,并且此时您可以更改描述信息。", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新模型。", + "DELETE-DESCRIPTION": "确实要删除进程模型吗? \"{{name}}\"?", + "EDIT-TITLE":"编辑模型详细信息", + "DELETE-TITLE": "删除模型", + "DELETE-LOADING-RELATIONS": "检查模型使用...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-RELATIONS-DESCRIPTION": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-PROCESS-RELATION": "流程模型", + "DELETE-FORM-RELATION": "表单模型", + "DELETE-APP-RELATION": "App模型", + "IMPORT-DESCRIPTION": "请浏览或拖拽.bpmn或.bpmn20.xml扩展名的BPMN XML定义", + "IMPORT-TITLE": "导入一个流程模型", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建", + "SHARED-WITH": "分享", + "PERMISSION": "许可", + "ACTIONS": "动作", + "IMPORT": { + "DROPZONE": "拖拽一个 .bpmn 或者 .bpmn20.xml BPMN XML 文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理BPMN XML文件时出错", + "NO-DROP": "不支持拖放" + } + }, + "ALERT": { + "EDIT-CONFIRM": "模型被更新" + }, + "ERROR": { + "NOT-FOUND": "所请求的模型不存在" + } + }, + + "SUBPROCESS": { + "NAME": "子流程名称", + "DESCRIPTION": "描述信息", + "ACTION": { + "CREATE-CONFIRM": "创建一个子流程" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的子流程", + "CREATE-DESCRIPTION": "您需要为新的子流程命名,并且您可能希望同时添加描述。" + } + }, + + "CASE": { + "NAME": "模型名称", + "KEY": "模型key", + "DESCRIPTION": "描述信息", + "VERSION-COMMENT": "版本注释", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DUPLICATE": "复制这个模型", + "EXPORT_CMMN": "导出到CMMN1.1", + "DELETE": "删除这个模型", + "CREATE-CONFIRM": "创建新模型", + "DUPLICATE-CONFIRM": "复制这个模型", + "OPEN-IN-EDITOR": "可视化编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除case模型", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个模型" + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被 {{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个模型没有描述信息,可以通过修改模型来添加一个描述" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的案例模型", + "DUPLICATE-TITLE": "复制这个案例模型", + "CREATE-DESCRIPTION": "您需要为新模型命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您可以更改新模型的名称,并且此时您可以更改描述信息。", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新模型。", + "DELETE-DESCRIPTION": "确实要删除进程流程吗 \"{{name}}\"?", + "EDIT-TITLE":"编辑模型详细信", + "DELETE-TITLE": "删除模型", + "DELETE-LOADING-RELATIONS": "检查模型使用...", + "DELETE-RELATIONS-DESCRIPTION-SINGLE": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-RELATIONS-DESCRIPTION": "无法删除此模型,因为另一个模型正在使用它:", + "DELETE-PROCESS-RELATION": "案例模型", + "DELETE-FORM-RELATION": "表单模型", + "DELETE-APP-RELATION": "应用程序模型", + "IMPORT-DESCRIPTION": "请浏览或拖拽.cmmn 或者.cmmn.xml 扩展名的CMMN XML", + "IMPORT-TITLE": "导入一个案例模型", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新应用程序模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建", + "SHARED-WITH": "分享", + "PERMISSION": "许可", + "ACTIONS": "动作", + "IMPORT": { + "DROPZONE": "拖拽一个 .cmmn or .cmmn.xml CMMN XML文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理CMMN XML文件时出错", + "NO-DROP": "不支持拖放" + } + }, + "ALERT": { + "EDIT-CONFIRM": "模型被更新" + }, + "ERROR": { + "NOT-FOUND": "所请求的模型不存在" + } + }, + + "FORM": { + "NAME": "表单名称", + "KEY": "表单key", + "DESCRIPTION": "描述", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "DELETE": "复制这个表单", + "CREATE-CONFIRM": "创建新表单", + "DUPLICATE": "复制这个表单", + "DUPLICATE-CONFIRM": "复制这个表单", + "OPEN-IN-EDITOR": "表单编辑器", + "EDIT-CONFIRM": "保存", + "DELETE-CONFIRM": "删除表单", + "USE-AS-NEW-VERSION": "作为新版本使用" + + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建" + }, + + "POPUP": { + "CREATE-TITLE": "创建一个新的表单", + "DUPLICATE-TITLE": "复制这个表单", + "CREATE-DESCRIPTION": "您需要为新表单命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您需要为新表单命名,并且您可以在这个操作中添加描述信息。", + "SAVE-FORM-TITLE": "保存表单", + "EDIT-DESCRIPTION": "更改下面的任何模型属性,然后按下保存去更新表单。", + "DELETE-DESCRIPTION": "确实要删除表单 \"{{name}}\"?", + "EDIT-TITLE":"编辑表单详细信息", + "DELETE-TITLE": "删除表单", + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-VERSION": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建" + } + }, + + "DECISION-TABLE": { + "NAME": "决策表 名称", + "KEY": "决策表 key", + "DESCRIPTION": "描述", + "VERSION-COMMENT": "版本注释", + "HIT-POLICY": "命中策略:", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改模型属性", + "SHARE": "分享决策表", + "DELETE": "删除决策表", + "ADD-COMMENT": "+ 添加评论", + "CREATE-CONFIRM": "创建新的决策表", + "OPEN-IN-EDITOR": "决策表编辑器", + "EXPORT": "Export 决策表", + "DELETE-CONFIRM": "删除决策表", + "USE-AS-NEW-VERSION": "作为新版本使用", + "FAVORITE": "喜欢这个决策表", + "DUPLICATE": "复制这个决策表" + }, + "DETAILS": { + "HISTORY-TITLE": "历史", + "COMMENTS-TITLE": "评论", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建" + }, + "HIT-POLICIES": { + "FIRST": "First", + "ANY": "Any", + "UNIQUE": "Unique", + "PRIORITY": "Priority", + "RULE ORDER": "Rule Order", + "OUTPUT ORDER": "Output Order", + "COLLECT": "Collect" + }, + "COLLECT-OPERATORS": { + "SUM": "和", + "MIN": "最小", + "MAX": "最大", + "COUNT": "总数" + }, + "POPUP": { + "CREATE-TITLE": "创建一个新的决策表", + "CREATE-DESCRIPTION": "您需要为新决策表命名,并且您可以在这个操作中添加描述信息。", + "SAVE-DESCRIPTION": "您可以更改新决策表的名称,并且此时您可以更改描述信息。", + "DUPLICATE-TITLE": "复制决策表", + "DUPLICATE-DESCRIPTION": "您需要为新决策表命名,并且您可以在这个操作中添加描述信息。", + "DELETE-TITLE": "删除决策表", + "DELETE-DESCRIPTION": "确实要删除决策表 \"{{name}}\"?", + "SAVE-DECISION-TABLE-TITLE": "保存决策表", + "IMPORT-DESCRIPTION": "请浏览或拖拽.dmn or .dmn.xml扩展名的的 DMN XML文件", + "IMPORT-TITLE": "导入DMN模型", + "IMPORT": { + "DROPZONE": "拖拽一个 .dmn or .dmn.xml DMN XML文件", + "CANCEL-UPLOAD": "取消上传", + "ERROR": "处理DMN XML文件时出错", + "NO-DROP": "不支持拖放" + }, + "USE-AS-NEW-TITLE": "作为一个新版本使用", + "USE-AS-NEW-VERSION": "作为一个新版本使用", + "USE-AS-NEW-DESCRIPTION": "您确定要使用 {{version}}版本 去创建一个关于 \"{{name}}\"的新版本?", + "USE-AS-NEW-UNRESOLVED-MODELS-ERROR": "无法完全恢复app模型到所选择的版本:由于一些引用的模型过去被删除而丢失。请相应地更新app模型。缺失模型:", + "USE-AS-NEW-UNRESOLVED-MODEL": "模型 '{{name}}' 内部id {{id}}, 被 {{createdBy}}创建" + }, + "ALERT": { + "FAVORITE-CONFIRM": "喜欢这个决策表", + "UN-FAVORITE-CONFIRM": "这个决策表不再流行了" + } + }, + + "APP": { + "NAME": "应用程序定义名称", + "KEY": "应用程序定义key", + "DESCRIPTION": "描述", + "ICON": "图标", + "THEME": "主题", + "GROUPS-ACCESS": "组访问,用逗号分隔", + "USERS-ACCESS": "用户访问,用逗号分隔", + "ACTION": { + "DETAILS": "显示详细信息", + "EDIT": "修改应用程序定义属性", + "DUPLICATE": "复制这个应用", + "SHARE": "分享应用程序定义", + "DELETE": "删除应用程序定义", + "CREATE-CONFIRM": "创建新的应用程序定义", + "DUPLICATE-CONFIRM": "复制这个应用程序定义", + "DELETE-CONFIRM": "删除应用程序定义", + "USE-AS-NEW-VERSION": "作为新版本使用", + "OPEN-IN-EDITOR": "应用程序编辑器", + "PUBLISH": "发布", + "PUBLISH-CONFIRM": "发布应用程序定义", + "SELECT-ICON": "修改图标...", + "SELECT-THEME": "修改主题...", + "EDIT-MODELS": "编辑包含的模型", + "EXPORT-ZIP": "将app定义导出为zip文件", + "EXPORT-BAR": "将app定义导出为可部署的bar文件" + + }, + "DETAILS": { + "TITLE": "App定义详细信息: {{name}}", + "HISTORY-TITLE": "历史", + "MODELS-TITLE": "app定义中包含的模型", + "LAST-UPDATED-BY": "最后被{{lastUpdatedBy}} - {{lastUpdated | dateformat}}更新", + "CREATED-BY": "被{{createdBy}}创建", + "NO-DESCRIPTION": "这个应用程序定义没有描述信息,可以通过修改应用程序定义来添加一个描述", + "NO-MODELS-SELECTED": "没有为这个应用程序选择模型" + }, + "TITLE": { + "SELECT-ICON": "选择应用图标", + "SELECT-THEME": "选择应用主题", + "PREVIEW": "预览" + + }, + "POPUP": { + "CREATE-TITLE": "创建新的应用程序定义", + "DUPLICATE-TITLE": "复制一个应用程序定义", + "SAVE-APP-TITLE": "保存应用程序定义", + "SAVE-APP-SAVE-SUCCESS": "保存的应用程序定义", + "CREATE-DESCRIPTION": "您需要为新的应用程序定义命名,并且您可以在这个操作中添加描述信息。", + "DUPLICATE-DESCRIPTION": "您需要为新的应用程序定义命名,并且您可以在这个操作中添加描述信息。", + "PUBLISH-TITLE": "发布应用程序定义", + "PUBLISH-DESCRIPTION": "您确定要发布应用程序定义 \"{{name}}\"? 注意这个应用程序定义将版本化,如果已经存在,则将更新工作流应用程序。", + "PUBLISH-FIELD": "发布?请注意,如果启用了发布,则将版本化此应用程序定义,如果已经存在,则将更新工作流应用程序。", + "PUBLISH-ERROR-PROCDEF-KEY-CONFLICT": "你的流程模型 \"{{modelInAppName}}\"具有相同的标识符\"{{processDefinitionKey}}\"作为已经存在的部署流程\"{{conflictingModelName}}\" ,关于这个应用程序 \"{{conflictingAppName}}\". 请修改这个 \"id\"流程模型的属性。", + "PUBLISH-ERROR-PROCESS-ALREADY-USED": "下面的流程模型已经在另一个应用程序中使用了。这样行吗?", + "PUBLISH-ERROR-PROCESS-ALREADY-USED-APP": "应用程序", + "PUBLISH-ERROR-PROCDEF-DUPLICATE-KEYS": "无效的应用程序: 找到重复的流程标识符 (修改这个非法的流程模型 \"id\"属性):", + "DELETE-TITLE": "删除应用程序定义", + "DELETE-DESCRIPTION": "确实要删除应用程序定义 \"{{name}}\"?", + "DELETE-DESCRIPTION-WITH-RUNTIME": "确实要删应用程序定义 \"{{name}}\"? 注意,这个应用程序定义已经部署到任务landing页面,并且通过确认,该应用程序将从任务应用程序landing页面中删除。", + "DELETE-CASCADE-FALSE": "只删除当前版本的应用程序定义 (v{{version}})", + "DELETE-CASCADE-TRUE": "也删除所有以前的版本应用程序定义", + "HAS-CUSTOM-STENCILITEM" : "模型 \"{{modelName}}\" 使用带有自定义模板项目的模板. 在这个模型中使用这个模型是不可能的.", + "HAS-VALIDATIONERROR" : "模型 \"{{modelName}}\" 有验证错误,不能添加到应用程序定义.在编辑器中打开模型以查看关于验证错误的更多细节。", + "IMPORT-DESCRIPTION":"请使用.zip扩展的应用程序定义浏览或拖拽一个", + "IMPORT-TITLE":"导入应用程序定义模型", + "IMPORT": { + "DROPZONE": "扩拽一个.zip 应用程序定义文件", + "CANCEL-UPLOAD": "取消上传", + "RENEWIDM-IDS": "Renew the user and group identifiers when importing step and BPMN models. This is often required when importing the 应用程序定义 into a different Flowable environment. It will try to link the human steps and user tasks to the right user and group in this target environment.", + "ERROR": "处理应用程序定义文件时出错", + "NO-DROP": "不支持拖放" + }, + "INCLUDE-MODELS-TITLE": "包含在应用程序定义中的模型" + }, + "ALERT": { + "DELETE-CONFIRM": "应用程序定义删除了", + "PUBLISH-CONFIRM": "应用程序定义已经被发布了", + "PUBLISH-ERROR": "不能发布应用程序定义. 请检查引用的流程模型的有效性。" + } + }, + + "SHARE-INFO": { + "ACTION": { + "ADD": "添加另一个人" + } + }, + + "FORM-BUILDER": { + "PALLETTE": { + "TEXT": "文本", + "MULTILINE-TEXT": "多行文本", + "PASSWORD": "密码", + "NUMBER": "数字", + "CHECKBOX": "多选", + "DATE": "日期", + "DROPDOWN": "下拉", + "RADIO": "单选按钮", + "PEOPLE": "选择人", + "GROUP-OF-PEOPLE": "选择组", + "UPLOAD": "上传文件", + "EXPRESSION": "表达式", + "DECIMAL": "小数", + "HYPERLINK": "超链接", + "SPACER": "垫片", + "HORIZONTAL-LINE": "横线", + "HEADLINE": "标题", + "HEADLINE-WITH-LINE":"标题和线" + }, + "TABS": { + "GENERAL": "一般", + "OPTIONS": "选项", + "UPLOAD-OPTIONS": "上传选项", + "ADVANCED-OPTIONS":"高级" + }, + "VERSION": "版本 {{version}}", + "LAST-UPDATED": "最后更新的 {{lastUpdatedBy}}, {{lastUpdated | dateformat}}", + "TITLE": { + "DESIGN": "设计", + "OUTCOME": "结果" + }, + "POPUP": { + "EDIT-TITLE": "编辑字段 '{{name}}'", + "EXPRESSION-TITLE": "编辑表达式" + }, + "MESSAGE": { + "EMPTY-EXPRESSION": "(没有表达值)", + "EXPRESSION-HELP": "您还可以使用如下的符号来引用先前以任何形式提交的值,作为文本的一部分 ${myFieldId}.", + "OPTIONS-EXPRESSION-HELP": "可以使用表达式来动态填充选项,例如通过引用这样的变量 ${optionsVariable}. 这个表达式需要产生一个java对象(java.util)。带有选项对象的列表)或其json表示。" + }, + "LABEL" : { + "FUNCTIONAL-GROUP": "选择组..", + "PERSON": "选择人.." + }, + "COMPONENT": { + "LABEL": "标签:", + "OVERRIDEID": "覆盖id?", + "ID": "Id:", + "PLACEHOLDER": "默认值:", + "OPTIONS": "选项", + "RADIO-BUTTON-DEFAULT": "选项 1", + "DROPDOWN-DEFAULT-EMPTY-SELECTION": "请选择一个...", + "DROPDOWN-EMPTY-VALUE-HELP": " 这是‘空值’选项。在运行时选择它意味着‘没有值’或’空’。这允许用于可选字段,但不允许用于必需字段。", + "OPTIONS-EXPRESSION": "选择表达:", + "OPTIONS-EXPRESSION-ENABLED": "启用选项表达", + "REQUIRED": "必填", + "READONLY": "只读", + "EXPRESSION": "表达式", + "ADD-OPTION": "+ 添加一个新选项", + "UPLOAD-ALLOW-MULTIPLE": "允许上传多个文件", + "SIZE": "大小", + "MAX-LENGTH":"最大长度:", + "MIN-LENGTH":"最小长度:", + "PASSWORD-UNMASK-OPTION": "密码屏蔽/揭露选项", + "HYPERLINK-URL": "超链接地址", + "REGEX-PATTERN":"正则表达式的标准", + "MASK":{ + "TITLE":"输入掩码", + "EXAMPLES":{ + "TITLE":"例子:", + "NUMBER":"任何数字", + "LETTER":"任何字母", + "NUMBERORLETTER":"任何字母或数字", + "OPTIONAL":"使蒙版可选(无效)", + "PHONE":"电话" + } + } + }, + "OUTCOMES": { + "DESCRIPTION": "您可以为这个任务定义多个结果。在完成一个任务时,用户选择一个可用的结果,可以在eg中使用。在这个过程中进一步的条件。", + "NO-OUTCOMES-OPTION": "不要使用自定义结果,只显示'完成'按钮。", + "OUTCOMES-OPTION": "使用此表单的定制结果。", + "POSSIBLE-OUTCOMES": "可能的出线", + "NEW-OUTCOME-PLACEHOLDER": "输入新的出线", + "ADD": "添加出线", + "REMOVE": "移除" + } + }, + + "DECISION-TABLE-EDITOR": { + "EMPTY-MESSAGES": { + "NO-VARIABLE-SELECTED": "未定义" + }, + "POPUP": { + "EXPRESSION-EDITOR": { + "INPUT-TITLE": "编辑输入列", + "INPUT-DESCRIPTION": "选择输入变量作为列的输入", + "OUTPUT-TITLE": "编辑输出列", + "OUTPUT-DESCRIPTION": "选择一个现有的输出变量或创建一个新的变量", + "EXPRESSION-LABEL": "列标签:", + "EXPRESSION-PLACEHOLDER": "输入可选标签", + "EXPRESSION-VARIABLE-NAME": "变量名称:", + "EXPRESSION-VARIABLE-TYPE": "变量类型:", + "EXPRESSION-VARIABLE-NAME-PLACEHOLDER": "输入变量名", + "OUTPUT-NEW-VARIABLE-ID": "变量ID:", + "OUTPUT-NEW-VARIABLE-TYPE": "变量类型:", + "COMPLEX-EXPRESSION-LABEL": "复杂表达式:", + "ALLOWED-VALUES": "允许值(可选):", + "OUTPUT-VALUES": "输出值", + "OUTPUT-VALUES-OPTIONAL": "(可选):", + "OUTPUT-VALUES-NOT-OPTIONAL": "(为优先级/输出顺序拖动行):" + } + }, + "BUTTON-ACTIONS-LABEL": "动作", + "BUTTON-ADD-INPUT-LABEL": "添加输入", + "BUTTON-ADD-OUTPUT-LABEL": "添加输出", + "BUTTON-ADD-RULE-LABEL": "添加规则", + "BUTTON-MOVE-RULE-UPWARDS-LABEL": "向上移动", + "BUTTON-MOVE-RULE-DOWNWARDS-LABEL": "向下移动", + "BUTTON-REMOVE-RULE-LABEL": "移除规则", + "ALERT": { + "EXPRESSION-VARIABLE-REQUIRED-ERROR": "所有输入和输出表达式都必须引用表单字段或变量。", + "SAVE-CONFIRM": "保存决策表'{{name}}'" + } + }, + + "TOUR": { + "WELCOME-TITLE": "欢迎, {{userName}}", + "WELCOME-CONTENT": "这是一个短暂的flowable编辑器. 接下来的几个步骤将指导您通过应用程序的不同部分来启动。按ESC键随时停止。" , + "PALETTE-TITLE": "调色板", + "PALETTE-CONTENT": "在这里可以找到创建业务流程的所有可用构成。它们是按逻辑组排列的。只需点击它就可以打开一组:", + "CANVAS-TITLE": "画布", + "CANVAS-CONTENT": "这是创建业务流程的工作空间。从左侧的调色板中拖动元素,并将它们放在画布上以开始建模", + "DRAGDROP-TITLE": "拖放示例", + "DRAGDROP-CONTENT": "下面是一个如何开始建模的例子:", + "PROPERTIES-TITLE": "属性", + "PROPERTIES-CONTENT": "在这里您可以配置业务流程构造的属性。只需选择画布上的项目,它的属性就会显示出来。如果要编辑该属性,请单击该属性。", + "TOOLBAR-TITLE": "工具栏", + "TOOLBAR-CONTENT": "可以在这里找到所有的动作:保存或验证模型, 复制和粘贴一个流程的部分, 等等. 在按钮上悬停以此获得对动作的描述信息.", + "END-TITLE": "终点", + "END-CONTENT": "就是这样!现在可以开始建模过程。如果你有任何问题,可以问他们。 Flowable论坛 " + }, + + "FEATURE-TOUR" : { + "BENDPOINT" : { + "TITLE": "教程", + "DESCRIPTION" : "当使用连线流将流程按照步骤彼此连接的时候,您可能会发现,这些连线彼此交叉,或者您希望以不同的方式排列它们。这样做, 可以向连线添加或移除一个弯曲点。

如下图所示,你首先应该点击 '添加弯曲点' 然后单击连线添加它。注意,连线将在绿色中显示一个微妙的指示,以显示可以在那里添加弯曲点。

删除一个弯曲点再次遵循类似的模式: 点击 '移除弯曲点' 按钮 ,然后点击弯曲点再次移除。" + } + }, + + "ACTION.OK" : "Ok", + "ACTION.SAVE" : "保存", + "ACTION.SAVE-AND-CLOSE" : "保存和关闭编辑器", + "ACTION.SEND" : "发送", + "ACTION.CANCEL" : "取消", + "ACTION.SELECT" : "选择", + "ACTION.ADD" : "添加", + "ACTION.REMOVE" : "移除", + "ACTION.MOVE.UP" : "移动入口", + "ACTION.MOVE.DOWN" : "向下移动", + + "TOOLBAR.ACTION.CLOSE" : "关闭编辑器并返回到概览页面", + "TOOLBAR.ACTION.SAVE" : "保存模型", + "TOOLBAR.ACTION.VALIDATE" : "验证模型", + "TOOLBAR.ACTION.CUT" : "剪切 (在业务流程中选择一个或多个元素)", + "TOOLBAR.ACTION.COPY" : "拷贝 (在业务流程中选择一个或多个元素)", + "TOOLBAR.ACTION.PASTE" : "粘贴", + "TOOLBAR.ACTION.DELETE" : "删除选定元素", + "TOOLBAR.ACTION.UNDO" : "撤消", + "TOOLBAR.ACTION.REDO" : "重做", + "TOOLBAR.ACTION.ZOOMIN" : "放大", + "TOOLBAR.ACTION.ZOOMOUT" : "缩小", + "TOOLBAR.ACTION.ZOOMACTUAL" : "缩放到实际尺寸", + "TOOLBAR.ACTION.ZOOMFIT" : "缩放到适当大小", + "TOOLBAR.ACTION.BENDPOINT.ADD" : "向选定的连线添加弯曲点", + "TOOLBAR.ACTION.BENDPOINT.REMOVE" : "向选定的连线移除弯曲点", + "TOOLBAR.ACTION.ALIGNHORIZONTAL" : "水平对齐", + "TOOLBAR.ACTION.ALIGNVERTICAL" : "垂直对齐", + "TOOLBAR.ACTION.SAMESIZE" : "相同大小", + "TOOLBAR.ACTION.HELP": "开始导游", + "TOOLBAR.ACTION.FEEDBACK": "提供反馈", + + "FORM_TOOLBAR.ACTION.SAVE" : "保存模型", + + "APP_DEFINITION_TOOLBAR.ACTION.SAVE" : "保存应用程序定义", + + "BUTTON.ACTION.DELETE.TOOLTIP": "从模型中删除元素", + "BUTTON.ACTION.MORPH.TOOLTIP": "更改元素类型", + + "ELEMENT.AUTHOR" : "作者", + "ELEMENT.DATE_CREATED" : "创建日期", + + "PROPERTY.REMOVED" : "移除", + "PROPERTY.EMPTY" : "空值", + "PROPERTY.PROPERTY.EDIT.TITLE" : "更改值为", + + "PROPERTY.FEEDBACK.TITLE" : "请填写您的反馈意见", + + "PROPERTY.ASSIGNMENT.TITLE" : "分配", + "PROPERTY.ASSIGNMENT.TYPE" : "类型", + "PROPERTY.ASSIGNMENT.TYPE.IDENTITYSTORE" : "身份存储", + "PROPERTY.ASSIGNMENT.TYPE.STATIC" : "固定值", + "PROPERTY.ASSIGNMENT.ASSIGNEE" : "分配", + "PROPERTY.ASSIGNMENT.MATCHING" : "使用 ↑ 和 ↓选择并按Enter确认或使用鼠标", + "PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER" : "输入分配人", + "PROPERTY.ASSIGNMENT.EMPTY" : "没有选择分配人", + "PROPERTY.ASSIGNMENT.NONE" : "未分配经办人", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHUSER": "搜索用户", + "PROPERTY.ASSIGNMENT.PLACEHOLDER-SEARCHGROUP": "搜索组", + "PROPERTY.ASSIGNMENT.SEARCH": "搜索: ", + "PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY" : "分配人 {{assignee}}", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY" : "{{length}} 候选用户", + "PROPERTY.ASSIGNMENT.CANDIDATE_USERS" : "候选用户", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY" : "{{length}} 候选组", + "PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS" : "候选组", + "PROPERTY.ASSIGNMENT.USER_IDM_DISPLAY": "用户 {{firstName}} {{lastName}}", + "PROPERTY.ASSIGNMENT.USER_IDM_EMAIL_DISPLAY": "用户 {{email}}", + "PROPERTY.ASSIGNMENT.USER_IDM_FIELD_DISPLAY": "字段 {{name}}", + "PROPERTY.ASSIGNMENT.IDM_EMPTY" : "流程发起人", + "PROPERTY.ASSIGNMENT.IDM.TYPE" : "分配", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_USERS" : "没有选择候选人...", + "PROPERTY.ASSIGNMENT.IDM.NO_CANDIDATE_GROUPS" : "没有选择候选组...", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.INITIATOR" : "分配给流程发起人", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USER" : "分配给单个用户", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.USERS" : "候选用户", + "PROPERTY.ASSIGNMENT.IDM.DROPDOWN.GROUPS" : "候选组", + "PROPERTY.ASSIGNMENT.INITIATOR-CAN-COMPLETE" : "允许流程发起人完成任务", + "PROPERTY.EXECUTIONLISTENERS.DISPLAY" : "{{length}} 执行监听器", + "PROPERTY.EXECUTIONLISTENERS.EMPTY" : "没有配置执行监听器", + "PROPERTY.EXECUTIONLISTENERS.EVENT" : "事件", + "PROPERTY.EXECUTIONLISTENERS.CLASS" : "类", + "PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION" : "表达式", + "PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.EXECUTIONLISTENERS.UNSELECTED" : "没有选择执行监听器", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING" : "字符串", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY" : "未选择字段", + + "PROPERTY.FIELDS" : "{{length}} 字段", + "PROPERTY.FIELDS.EMPTY" : "未选择字段", + "PROPERTY.FIELDS.NAME" : "名称", + "PROPERTY.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.FIELDS.STRING" : "字符串", + "PROPERTY.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.FIELDS.IMPLEMENTATION" : "实现", + + "PROPERTY.DATAPROPERTIES.VALUES" : "{{length}} data objects", + "PROPERTY.DATAPROPERTIES.EMPTY" : "没有配置data objects", + "PROPERTY.DATAPROPERTIES.ID" : "Id", + "PROPERTY.DATAPROPERTIES.ID.PLACEHOLDER" : "输入一个id", + "PROPERTY.DATAPROPERTIES.NAME" : "名称", + "PROPERTY.DATAPROPERTIES.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.DATAPROPERTIES.TYPE" : "类型", + "PROPERTY.DATAPROPERTIES.VALUE.PLACEHOLDER" : "输入一个值 (可选)", + "PROPERTY.DATAPROPERTIES.VALUE" : "默认值", + + "PROPERTY.FORMPROPERTIES.VALUE" : "{{length}} 表单属性", + "PROPERTY.FORMPROPERTIES.EMPTY" : "没有选择表单属性", + "PROPERTY.FORMPROPERTIES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.ID.PLACEHOLDER" : "输入一个id", + "PROPERTY.FORMPROPERTIES.NAME" : "名称", + "PROPERTY.FORMPROPERTIES.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.FORMPROPERTIES.TYPE" : "类型", + "PROPERTY.FORMPROPERTIES.DATEPATTERN" : "日期格式", + "PROPERTY.FORMPROPERTIES.DATEPATTERN.PLACEHOLDER" : "输入日期格式", + "PROPERTY.FORMPROPERTIES.VALUES" : "值", + "PROPERTY.FORMPROPERTIES.ENUMVALUES.EMPTY" : "未选择枚举值", + "PROPERTY.FORMPROPERTIES.VALUES.ID" : "Id", + "PROPERTY.FORMPROPERTIES.VALUES.NAME" : "名称", + "PROPERTY.FORMPROPERTIES.VALUES.ID.PLACEHOLDER" : "输入id值", + "PROPERTY.FORMPROPERTIES.VALUES.NAME.PLACEHOLDER" : "输入名称值", + "PROPERTY.FORMPROPERTIES.EXPRESSION" : "表达式", + "PROPERTY.FORMPROPERTIES.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.FORMPROPERTIES.VARIABLE" : "变量", + "PROPERTY.FORMPROPERTIES.VARIABLE.PLACEHOLDER" : "输入一个变量", + "PROPERTY.FORMPROPERTIES.DEFAULT" : "默认值", + "PROPERTY.FORMPROPERTIES.DEFAULT.PLACEHOLDER" : "输入一个默认值", + "PROPERTY.FORMPROPERTIES.REQUIRED" : "必须的", + "PROPERTY.FORMPROPERTIES.READABLE" : "可读的", + "PROPERTY.FORMPROPERTIES.WRITABLE" : "可写的", + + "PROPERTY.INPARAMETERS.VALUE" : "{{length}}个输入参数", + "PROPERTY.INPARAMETERS.EMPTY" : "没有配置输入参数", + + "PROPERTY.OUTPARAMETERS.VALUE" : "{{length}}个输出参数", + "PROPERTY.OUTPARAMETERS.EMPTY" : "没有配置输出参数", + + "PROPERTY.PARAMETER.SOURCE" : "源", + "PROPERTY.PARAMETER.SOURCE.PLACEHOLDER" : "输入一个源", + "PROPERTY.PARAMETER.SOURCEEXPRESSION" : "源表达式", + "PROPERTY.PARAMETER.SOURCEEXPRESSION.PLACEHOLDER" : "输入一个源表达式", + "PROPERTY.PARAMETER.TARGET" : "目标", + "PROPERTY.PARAMETER.TARGET.PLACEHOLDER" : "输入一个目标", + "PROPERTY.PARAMETER.TARGETEXPRESSION" : "目标表达式", + "PROPERTY.PARAMETER.TARGETEXPRESSION.PLACEHOLDER" : "输入一个目标表达式", + "PROPERTY.PARAMETER.EMPTY" : "没有选择参数", + + "PROPERTY.PROCESSREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.PROCESSREFERENCE.TITLE" : "流程参考", + "PROPERTY.PROCESSREFERENCE.ERROR.PROCESS" : "加载流程出错。稍后再试一次", + "PROPERTY.PROCESSREFERENCE.PROCESS.LOADING" : "加载流程...", + "PROPERTY.PROCESSREFERENCE.PROCESS.EMPTY" : "此文件夹不包含流程", + + "PROPERTY.FORMREFERENCE.EMPTY" : "没有选择参考", + "PROPERTY.FORMREFERENCE.TITLE" : "表单引用", + "PROPERTY.FORMREFERENCE.DESCRIPTION" : "引用表单", + "PROPERTY.FORMREFERENCE.ERROR.FORM" : "加载表单出错。稍后再试一次", + "PROPERTY.FORMREFERENCE.FORM.LOADING" : "加载表单...", + "PROPERTY.FORMREFERENCE.FORM.EMPTY" : "此文件夹不包含表单", + + "PROPERTY.TASKLISTENERS.VALUE" : "{{length}}任务监听器", + "PROPERTY.TASKLISTENERS.EMPTY" : "没有配置任务监听器", + "PROPERTY.TASKLISTENERS.EVENT" : "事件", + "PROPERTY.TASKLISTENERS.CLASS" : "类", + "PROPERTY.TASKLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.TASKLISTENERS.EXPRESSION" : "表达式", + "PROPERTY.TASKLISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.TASKLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.TASKLISTENERS.UNSELECTED" : "没有选择任务监听器", + "PROPERTY.TASKLISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.TASKLISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.TASKLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE" : "字符串值", + "PROPERTY.TASKLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符串值", + "PROPERTY.TASKLISTENERS.FIELDS.STRING" : "字符串", + "PROPERTY.TASKLISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符串", + "PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.TASKLISTENERS.FIELDS.EMPTY" : "没有选择字段", + + "PROPERTY.EVENTLISTENERS.DISPLAY" : "{{length}} 事件监听器", + "PROPERTY.EVENTLISTENERS.EMPTY" : "没有配置事件监听器", + "PROPERTY.EVENTLISTENERS.EVENTS": "事件", + "PROPERTY.EVENTLISTENERS.RETHROW": "Rethrow event?", + "PROPERTY.EVENTLISTENERS.CLASS" : "类", + "PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE" : "实体类型", + "PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER" : "输入一个实体类型", + "PROPERTY.EVENTLISTENERS.RETHROWTYPE": "Rethrow event type", + "PROPERTY.EVENTLISTENERS.ERRORCODE" : "错误码", + "PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER" : "输入一个错误码", + "PROPERTY.EVENTLISTENERS.MESSAGENAME" : "消息名称", + "PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER" : "输入一个消息名称", + "PROPERTY.EVENTLISTENERS.SIGNALNAME" : "信号名称", + "PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER" : "输入信号名称", + "PROPERTY.EVENTLISTENERS.UNSELECTED" : "没有选择事件监听器", + + "PROPERTY.PLANITEMLIFECYCLELISTENERS.VALUE" : "{{length}}个生命周期侦听器", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EMPTY" : "未配置生命周期侦听器", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EVENT" : "事件", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.SOURCE_STATE" : "源状态", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.TARGET_STATE" : "目标状态", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS" : "类", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.CLASS.PLACEHOLDER" : "输入一个类名", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION" : "表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION" : "委托表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.DELEGATEEXPRESSION.PLACEHOLDER" : "输入一个委托表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.UNSELECTED" : "未选择任务监听器", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME" : "名称", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.NAME.PLACEHOLDER" : "输入一个名称", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION" : "表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EXPRESSION.PLACEHOLDER" : "输入一个表达式", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE" : "字符值", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER" : "输入一个字符值", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING" : "字符", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.STRING.PLACEHOLDER" : "输入一个字符值", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.IMPLEMENTATION" : "实现", + "PROPERTY.PLANITEMLIFECYCLELISTENERS.FIELDS.EMPTY" : "没有选中字段", + + "PROPERTY.SIGNALDEFINITIONS.DISPLAY" : "{{length}} 信号定义", + "PROPERTY.SIGNALDEFINITIONS.EMPTY" : "没有配置信号定义", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-GLOBAL": "全局", + "PROPERTY.SIGNALDEFINITIONS.SCOPE-PROCESSINSTANCE": "流程实例", + "PROPERTY.SIGNALDEFINITIONS.ID" : "Id", + "PROPERTY.SIGNALDEFINITIONS.NAME" : "名称", + "PROPERTY.SIGNALDEFINITIONS.SCOPE" : "Scope", + + "PROPERTY.MESSAGEDEFINITIONS.DISPLAY" : "{{length}} 消息定义", + "PROPERTY.MESSAGEDEFINITIONS.EMPTY" : "没有配置消息定义", + "PROPERTY.MESSAGEDEFINITIONS.ID" : "Id", + "PROPERTY.MESSAGEDEFINITIONS.NAME" : "名称", + + "PROPERTY.SEQUENCEFLOW.ORDER.EMPTY" : "没有确定连线的顺序", + "PROPERTY.SEQUENCEFLOW.ORDER.NOT.EMPTY" : "设置连线的顺序", + "PROPERTY.SEQUENCEFLOW.ORDER.NO.OUTGOING.SEQUENCEFLOW.FOUND" : "没有发现流出连线.", + "PROPERTY.SEQUENCEFLOW.ORDER.DESCRIPTION" : "设置需要评估连线的顺序:", + "PROPERTY.SEQUENCEFLOW.ORDER.SEQUENCEFLOW.VALUE" : "连线到 {{targetType}} {{targetTitle}}", + + "PROPERTY.SEQUENCEFLOW.CONDITION.TITLE" : "连线条件", + "PROPERTY.SEQUENCEFLOW.CONDITION.STATIC" : "条件表达式", + "PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY": "没有设置条件", + + "PROPERTY.DUEDATE.EMPTY" : "没有到期", + "PROPERTY.DUEDATE.DEFINED" : "定义到期日", + "PROPERTY.DUEDATE.TITLE" : "到期日", + "PROPERTY.DUEDATE.EXPRESSION-LABEL" : "到期日表达式", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.NO-DUEDATE" : "没有到期日", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.EXPRESSION" : "表达式定义", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.STATIC" : "任务创建后的固定持续时间", + "PROPERTY.DUEDATE.TASK-DUE-DATE-OPTIONS.FIELD" : "基于字段", + + "MODEL.SAVE.TITLE" : "保存模型", + "MODEL.VALIDATE.TITLE" : "验证结果", + "MODEL.NAME" : "名称", + "MODEL.KEY" : "Key", + "MODEL.DESCRIPTION" : "描述", + "MODEL.SAVE.NEWVERSION" : "将此保存为新版本?这意味着你可以回到以前的版本。", + "MODEL.SAVE.COMMENT" : "评论", + "MODEL.SAVE.SAVING" : "正在保存模型", + "MODEL.LASTMODIFIEDDATE" : "最后保存", + "MODEL.SAVE.ERROR": "Unexpected error: 不能保存模型", + "MODEL.VALIDATIONERRORS": " 注意,模型包含验证错误。这意味着该模型在当前状态下不能部署在Flowable引擎上。", + "MODEL.CONFLICT.WRITE": "不能保存模型: '{{userFullName}}'对该模型进行了更改", + "MODEL.CONFLICT.WRITE.OPTIONS": "选择一个选项来解决此冲突:", + "MODEL.CONFLICT.WRITE.OPTION.OVERWRITE": "覆盖其他模型", + "MODEL.CONFLICT.WRITE.OPTION.DISCARDCHANGES": "放弃我的改变", + "MODEL.CONFLICT.WRITE.OPTION.SAVEAS": "保存为新模型", + "MODEL.CONFLICT.WRITE.OPTION.NEWVERSION": "创建新版本", + "MODEL.CONFLICT.SAVEAS" : "另存为:", + + "EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP": "一项活动将作为对另一活动的补偿而被执行。事件针对即将执行的活动进行补偿。", + "EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP": "一项活动已圆满完成。", + "EVENT_TYPE.ACTIVITY.ERROR.RECEIVED.TOOLTIP": "活动已接收到错误事件。在活动接收到实际错误之前发送", + "EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP": "创建了新的membership", + "EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP": "单个membership已被删除", + "EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP": "相关组中的所有成员已被删除。由于可能的原因,个别事件不会被派遣。", + "EVENT_TYPE.TASK.ASSIGNED.TOOLTIP": "一个任务已经被分配人了。这将抛出一个实体更新事件", + "EVENT_TYPE.TASK.COMPLETED.TOOLTIP": "一个任务已经被完成。在删除任务实体之前调度", + "EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP": "当BPMN错误被抛出,但未在流程中捕获时", + "EVENT_TYPE.VARIABLE.CREATED.TOOLTIP": "已经创建了一个新的变量", + "EVENT_TYPE.VARIABLE.DELETED.TOOLTIP": "已删除现有变量", + "EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP": "已更新现有变量", + + "PROPERTY.DECISIONTABLEREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.DECISIONTABLEREFERENCE.TITLE" : "决策表引用", + "PROPERTY.DECISIONTABLEREFERENCE.ERROR.FORM" : "加载决策表出现错误. 稍后再试一次", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.LOADING" : "加载决策表...", + "PROPERTY.DECISIONTABLEREFERENCE.DECISIONTABLE.EMPTY" : "此文件夹不包含任何决策表", + + "PROPERTY.CASEREFERENCE.EMPTY" : "没有选择引用", + "PROPERTY.CASEREFERENCE.TITLE" : "案例型引用", + "PROPERTY.CASEREFERENCE.ERROR.FORM" : "加载案例模型时出错。稍后再试一次", + "PROPERTY.CASEREFERENCE.CASE.LOADING" : "加载案例模型...", + "PROPERTY.CASEREFERENCE.CASE.EMPTY" : "此文件夹不包含任何案例模型" +} diff --git a/zbf-admin/src/main/resources/static/designer/images/android-chrome-192x192.png b/zbf-admin/src/main/resources/static/designer/images/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a85b6e756d6c8930b96b377f3d289b23159609 GIT binary patch literal 4310 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/favicon-32x32.png b/zbf-admin/src/main/resources/static/designer/images/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5e2cd3d5fcf27d8b569deabc8a4a3aa8dd5922 GIT binary patch literal 996 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-G$+Qd;gjJKpuOE zr>`sfLuN)%Mk{TtZ&5(`PEQxd5RccnkXq?r6k6lBrNA)@)M#7BQ!3 zx>3VZlli{f>%12~;cR+vEH(N4v98NE7&$Ka@^AJmOGxM5zcVAJK%G5T=H}d37Ke_i zch$#t&zKeemPsgLTCh%Q-Q#x;46fz(Uc7d%>$JD3*rb`q_}C`?{Cs)R%y5C;+JrOC z?me?uY)c*ozFVy`>*@nrc3p9H@5mXMPtyWJg3mpBTPt31XiX-&)Mg&#&QF@0*FIh- z{CsKptpbI%xfh)3)_t}qbXL1NZR1t59aZOE^o70q;mm8IDyvz&Nx3m0?&K}abFQjP zxBevbi-^^5dS)*^cfG!st?8m4f53zw_FXTOE@@?7c@^e&$@^lG?2IylL&kPODm}-| zMONo6ZL9XtJJ&KPVTx7dLqT)nh!@L`vc#X;uNs-LXsP=uNu#66AMPAc(eQqw`bRHz zho&P3Q{lzhJHCA8svLSfc?qgZW-RC}vyXqgXp@MHju0Pn?wn7&aj^?3zuw+5S@N#; zv`1Gr^4d%-+nmF5`uSF+nFiBOHvC|BUA%MAtLg7|Yu);ruqACT2{eHrWbAldc19!@#PXr?)FK#IZ0 zz|dURz*yJ7FvQ5v%D~Xd)Iu9b8W=E%s~<9nO2EgL$TNVYM_Sjs*s41pu}>8 zf};Gi%$!t(lFEWqh0KDIWCn(cIgdZ_a1@4VXq@stea7=?5CgL^w_Y;0u(GiCWD#az z1(ybs!zs+ln?n>%-?(z($eANDN7zp{cr5VJV|XPlSn|oqbSlsa22WQ%mvv4FO#t&t Bn&1Ec literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/flowable-logo.png b/zbf-admin/src/main/resources/static/designer/images/flowable-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cf49ee74068e34a945478f47e9de7b011e8d7dfa GIT binary patch literal 11874 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/flowable-logo@2x.png b/zbf-admin/src/main/resources/static/designer/images/flowable-logo@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..13938c0edba10919ca89817038c7203ac731389d GIT binary patch literal 25782 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/amountfield-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/amountfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1f4b7c7d3cb2bf67ca81e920055d32f2c220c06c GIT binary patch literal 3174 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 M07*qoM6N<$f^@3i#Q*>R literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/booleanfield-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/booleanfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8933752fb4ac3206945e15fa1bec78374fa0c0a1 GIT binary patch literal 694 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 M07*qoM6N<$f^@3i#Q*>R literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/dropdownfield-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/dropdownfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c76a2413062b0e4b7cc71cd50c497cd45dd39637 GIT binary patch literal 492 zcmV8b&mn&ZguBcAevtdPJ4Qrs8Sa$c z2>b^DQNF}+yytmdAHa@f=5wCsgYkI$1OTkvZi`l{H2{!U23Ipo)3h(5D3V09X*d8R zVHi#X5uFwdhKOXAWjE95^xX!r)9HvX3{Mzi*8n(U?2Jh%b1WC*o!0v3Cle{9&H+Gc zeYuW^QtB4KAppbiQ3)?A%yCdW>!xIJ=VjOkh-yQx*E=@GY}XCuoWG4mqlr}kB6=;# zWUJCOC!+3O!hxD!ptXJg&;>C63lpi<;HsXMd|v6mX?o9TAa1k)hNzWqeoAIqrAuN-s-2O6p{cHcp{{{th@pv;f_?Qgd=aTm@r2V~9>bV(99f^K%P|Qj3d0>P?~Qk;Tx}2c;J0=ahns56#Ogu`_~dK@&#T6^W3yGl%Ix z7DU$&flULlAd&`9G+2SdDZ(W)H#HCJ7h|9;SS8RkI_Kx)7X=q2CZ~eJ3#-F2kp2@7ah=JU|>4z>Eaj?!TEHWb@miT zk+$!Xdc{Tdxa2U2X--*iu_FQqHO$0bZHoNEc&+J&vdahdh~460xvqlTH?>+T+_||A zI&o(8G#x7~uf6whw!Zr5GkT0SS&Ry17{9N4KIikrPvgk_)-c$=`)_L#L zb3AtAgf$`B$2@D6nr?U$e86?`yVf~3uboe;42v&hD*N>RLN3$GO)WB;zszO%FT5#w z_QPWsjGHv7d`|0biugTMO+;w;SSCX9l z*TDY%w@jVc4XQl8@xh!+(v3g;%zY@c^=QZ4TQcUynEjJ??p<(T9;2MYvtK^9+I;ON z#S4DdW7+X5_jaSk$)62(ovS+Hf>yN0Y%Hi*S6H)-S?)`Z-Cic1EUznnOWZoniy9|I br+=`ou)FwXk&DGeP&MP}>gTe~DWM4fljxl6 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/group-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/group-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..31703862797b8b9b5de4a02f4e7e9b6685feea9d GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq zgi1h|@m`vI1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWIZto-U3d z5v^~h9~3-fz{BD%^{T5^z_!HZ$@IGIi+Asw=o$L( z=Z#QX28NhziqGeCW^5D)y}EPjH9iIg>S~nz0ZyX_d5yo>?ihcFcQIG0ieTtCA$`EoNrHh&P;Ay u(b047cNIfNwZc2b_2U1T%DL}2|6pZ#m1x|1?0YBB-YWr^}8>&oDE+S@lj&>O&?}irp0^`r3~CNf4x#t zQhIfP_5a`B=2EOB-AqATi!N$Nlpa{Y%(k7`?VyGPD>EO%6*nmr7qcsjKsy;cUHx3v IIVCg!0QB%h5&!@I literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/headline-with-line-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/headline-with-line-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce7e9b68d1d3ea4f27cb09b4347f60249845da83 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_r*vAk26?e?l#Bv_ewBsv2{1O*Fw z8XFxMJy&EN?GiPAlHvH@o)s}l~G&^&FbHWwI#e4~h!SS&!E-tdW z9_+9G@3y!hFVMlu(L{=MF`q=~fd^#=G$ekQCAzpA*?cj^;8jDQ0T-JP14ECmjP!IS Re|ezo44$rjF6*2UngH4ANnrp0 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/horizontal-line-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/horizontal-line-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..910a352ee6fbe3d3daf398a255e9976722c58625 GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_r*vAk26?e?o&hR9%K%h0c@&*Q-&({Zm z6t7V61UA9P8x;xAU?egSL4k2-44E1PLUT~EPa1_yf^cXtbQX$(fi5agvTwN=4uvdA z*wGj$!N(us3NR@UTi7<3H597>fk4nqaujMe&V3n|jWE!IY&HW0hbJT?z!H!!fO!Cp zaBy&dTid{GY^-DoD;Af|CULCjER&^4KFououp*gM2Ac}dA@X@i5kMRp1BJ>1{r4=d zlg9Wj5S_K0l`KCvhs1y*VAk+YL2PQ&$L0MGCHH(5qj0F7!Q`GLY_S+iYedT`it+)- z)F>{F#HL_vtP!?W)(9(W2RvdM${K+}*rMU9G#@iuq+OX55*uLR0U!qJPvuZzX!0Qh z2}3TCEBz}_c@`)?CY2&9ue^v@1RDN-w$*x9fW}}_SS-0-wy;J0O51AvZVC&CiIYzs zM5nT`Hp|E=^J<)Tr1_U`zuFIU3fArj2ng8AWWLrtefqSm?^P)#uU$|i5X8NX&=1&Pxb{F< zb+!F=ELN0dtK~XY(2f!W#F9zLI6 zp`xmKHJJG{+xX>dVtGkP$)Selt_@w?ewCm)KF!m|2V;Xq8xba(Odb3Q1bqw=DOCUo zt&J=O^A}FGY2BS)W1g9jt8Hj_nC9#2>zACoP-EKL{cyc`swCk`aq+nFc+!JrLbTJ- zhgG+3O@pd0TtD7omT|U2EUv?q?i_*)fZMG)wVw2n7c-u8118lO|G?hgqG>8uQEVO&gPBwNhA(CUuYiut-C!v^qR;7s%qco zyEZ>XR9H`okAM5DxVU&ry0@@zLKJA*2+GOHA>U74Tiem?bNfP>=*WTZ<|;U$p?#tH zf7|c7s`l!8b#--3OFUM|FvF-w8cihraI%P(^^eaklMDyWnbtu`z9Fuo z2h(*_qvX&Tyx`18g-a50-Cm*Trsq1ky6fL6W`d{hSAgfjx7yeCniTx3XKdVm^qz4C zQa!<-;c#Z_UAx=B@gBXx>Bxu(bNg(|7MI2aat!=&TzjK{(YzV26Pw|q&&zaBnTsB} zQC(eq`EhM<;o}#TQXv=~KK^B7)U#6FoBY{8ixgx$NhdfsxV-3B4T9stvjL8c#6AA~ zNz(W8T_%rodR~KH?t=<08ZgSMs_+eYp^zSugBF4X!a>l|&8<#Z!{ z+BnkOocG52y;}eF9mfC>^SIGQl7AM>4LBeqR_0$YMwOP9MsRvBQ9S;vE1B?6quDl- z&-L&7E^Kb+31l}IL@mvHTUE`DA1Wq#US_@N0d@$ zboq4h#G6bV|7Ki$ASN}qP;0wRZ+k%1*JPr3ie0v%Ie}!?mr__*2mos-Syc6>F=+n0V$akMlFd~^L|T927mt;bIc&7rhA zjHU?%RkBxd#ZXghXGncuOS;k;H?8*0>({RuU7j%y@wnJNrE8b%(DXnVNR{D9F(^xzcTnK3-!`_&z`)bngt+QC#4>IYIvsa T7g5hH`Ok`%n=h{1CH&aGD(=7g literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/multi-line-textfield-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/multi-line-textfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..76e992a591368313bedb0b4f69ff5a4c514e5f15 GIT binary patch literal 489 zcmV->$%v|wrGiY;a{wR& zh~v1Vs#ib@sCdqN0d7R(y3^^rNfbpTRUH6j&%x_@6_Hw)oV*O6s$-xhBJVyDRW$@o zMPwf+tLjzA=e47%;GCQI2v1e7*Y}FW;wXV=g?!h%=bW2FQS{?uu-3{p0i1Ia zV@wY?2P$7(kY2m0MnE6vCw}W%E%8PhcDvm!Fak!2_o~eQfgE51z!+nIIWSMWSB2{v zB4StkCE)cTZUAh%?|;+ZdjmN@4v+(60WeMc(GGLdtZ4|`0~bIwj^kV4VYys-8JB_} z5a0}`0*J_+7-MR{BfBrh5;zI0wF96540jkl1RB=bfvgUv&1Um>u~;1XOfD1(&+T^m fDP7CIpN>BOJT-dt-h8S$00000NkvXXu0mjf-CW1V literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/numberfield-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/numberfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8edac39865cecd4fae3ea5bba8826b0c171bfc13 GIT binary patch literal 521 zcmV+k0`~ohP)DqY)ai6&v)LQ~h-)S;VmP1A`?A$)DQ4a_IRL~_ z6x~T?zHkpLGpjUBZzq$dUSMVo078g2Ywg~qXQ5O;k|f^>jn;aj0=%cd zyMUDxEaiOmQ$Vrb?FH?;y>2y>04zRdA_P`*Uc@i`Rri1#p|h5hQjY*m;9)xk@I+ec zn3-?tAS?qj$3Yl|&y7ao5Ww-4`G;wmUQ>QE@^&cQUCnj^d<*yhEZ(mhM9LnY00000 LNkvXXu0mjfr25pb literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/password-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/password-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a8d098186e4ea607345fa7705a5203f0bb72beae GIT binary patch literal 1021 zcmV|VJRM@UvO>^Jj%^M1eYee=DYk1!a>T6-M8tg04N zb)1=1MD8-PFCwK{t#)&ug#8lp`TXH1ioPMDd=gJY766>8)oQ=>lb8D;<#M@~L}Vcr z{|mrJQ4~GDxw*MN48t@LJqO@J0Dm&`G&5I>F~|DJ-LnGueEx7et1$pqUDrM1`~G?- z?&Rd;zH~bM6%m~Ta9>1T=v9eSFN1N}#{gUng5V7RYOS47)eA&4B_a+pFRJRLYPEU| zz^pL_M0Apw=KvIv1QM6PT6?@%cGq>!08nGhMG?73M3-FGJs3sN0TKC3RX?%TehNU- z>GW9XZ0ElSH zb=_Ot_!}D=w?t$L06foI1psCqAKCyjKL!9RD=YWoTVvgJK$FMJPXNID{QTeXZFgt` z4+H-j*wqOqCMMiWCi6LfHvwcvAtEAmBKo#oufMmpw$^Bk?dk)u_&cKzZi1OT0Ovf< z1Az012Cy@80GJMfpfU;r#+Yd$x=loHwHxU44rBpfRN??otyUM}VWvIy$X~)oZlKqn zQCH-0xmN*PVP*yJb`S*Dhsm>-3S4340|1@`@a3>c_F|y5$3Oni4KQ=LITjIrlm@nd zosO9FpsHSLx%@tfTPzmS@vzYz+hssR?gBtIn|&rJ>Gt+^NmcKt>K)g0zf0nVVR$GW z{?Q)WwF{Wp2k^9roB;4^x1`I<%MSqLl7yRZ9OspISZ#P0G<+&au5VRw-dTGqEi4W0A9D&s^d6k zE0s!p5M^s^MpfsC=rs{pPo+|)J38!^z!-Ckh<*UDPekq!(PdS=;d$O_%lF=YP%IYH zVHh5Y*Ze$oX1?w?&WWX^rTKvj06;F6dp17Z97*DJgNT$e2W!yIYTFU}vk90hBtec{~0ArSNh9q3m>400000NkvXXu0mjf@fFN2eu~3mkcyGc& z(85B&pF%9fLP0A{ZD|lB7>EdBAp{bWoxp-!P|`>WjiOd+AP|3IklkVCSm-W`zWGUZ zWi33_@a}o{etYk{d908`E9JDb`hS3b0iZ3-;CWsjfJ-C~h)5^Nj{qhd#~GcPnwn4A ztF@jGkwYY3O;1nv**u9IFvi>@`IO{I0J}+U0k99iwJ3__wALq*_KQddfK4LO8Rv-w z&|04Za5*7=yNEn6#vDt6NK@w)k4E3p8%T&}&Vt7~tTUmzj}tIy?f`LFEWaY%z4#0LjMy7OLwaatgo>081o?>(*pM`DG3Ek*J2Bykh#W2!i_a1OQk4ks3*sGs zU6#;Y-}lcqQXI&38-BMfk_;Lx4y1ITzrTNf6h+Tt!rxri-99-v`Lz*%*be0L`Hm=x zhU4M@I>Io#WsKR-bO5dOQKeJ~fb|Zq(-{DBp67WYB5MJtjbLza(3zQ;IZpB_fZQ5# zy&*XghT&+bRC>Q^0AtJz0N2-0_;-aQi>~XAEG{mN&(6*!zO3~laGOvZ09+9%L{app zySw{fnzRs@+)$)HvEeH4kZ1m=E TKN}{t00000NkvXXu0mjfE_G7m literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/readonly-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/readonly-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0b11705b1c777bbefa74087d39215a456e0fd874 GIT binary patch literal 497 zcmV4-jijhOzBgB zNe~E!NvTwt3xc2u%p}Zwj^p^S(P%sZNTE;&bGh6hu$3@)G>$r*PBqNu^V)l#HXL9p zilVE~d%rU%IPbmgcDv`zX7eoxVzF2ZqbS-Ckz+uK$gXIuWBQlz##+0U1b8%zG1tH< z;1nN|@R|mEgrzbc!^{Q3?~2BlJz(XJS+~~OgVEw-?!dtGi*0HG#+YMZbIe{R)>{21 z0wS{SoVysOky7eqT=jkT0aj9kO~Ma0YAx^W}2+2)K04 zCGu2ON(rzI%mawXsc5a2fIHGZ4hJkNYi*nU%s-?Ee*iYEwQc$QF{xB4i*X#!CP@y0 n;Hg%t-4E9?{TWRK{=L9E##w9VEe&ln00000NkvXXu0mjfE3?*# literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/readonly-text-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/readonly-text-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cc9f19c8943a973407285677e9e9c2d427efb38 GIT binary patch literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzmSQK*5Dp-y;YjHK@;M7UB8wRq zgi1h|@m`vI1yE43#5JNMI6tkVJh3R1p}f3YFEcN@I61K(RWH9NefB#WDWIZNo-U3d z5v^~hALKo(z~lOM{ke;dMjS!nOSGCNSYC2`6DQOeHzDbg5bJ(n^&cI}^AE1_vUR+E z*|vdQVbSev9Ex`seWv-ks4Smy&zF(G=ggliIZO{6U6wICuVfND`P#QkS?Q)!!*;ct z!UIeVs>dwkA2qOs)(T#%;bqrhh}g&UXHt~^pQDXY{yh&J)~fRr9!PiOPCnOkX{O%h q1trg<_}(lnY5SZ0gt3kP1LNO6i2@pe2VVnS&EVVGd000McNliru;sg;2D+U<(TbTd=0bfZ( zK~z}7?bbg}R6!I4@E>p4EX0Jw2t=W=vD?BgVBwe0X=vzWTTA^6w6r9**UsLCb_)^% z2_&vc!ygH(ECideA}E-Pr3x*|*|EoI&eUgABLZ=oMy1&8>JUPK%Xi*y*)F^{LX#_Ry@95!)+<81oX zeXrnSZn;Jls1G@B4v#Z$WfV2Ajkh?!#U1!P{J?5n?`I$)F7Oj?(8&UW#J}SmenrHe zkxjysQXPxQVTl~aWa;FK{nCIUGX`a=;2!y z-;0QDne%F84Yb?st7fwaU-25}_<(j<@e0+myfRQd%O3>(0we!Y(h}oIX8-^I07*qo IM6N<$f&(nW(EtDd literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/form-builder/textfield-icon.png b/zbf-admin/src/main/resources/static/designer/images/form-builder/textfield-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..92526b2f2e7b1f14f1f9a432b81c083c85541763 GIT binary patch literal 434 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 Ux2a*LX7{U#G`wn1p=Tfd4=mNw)Bpeg literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/line.png b/zbf-admin/src/main/resources/static/designer/images/line.png new file mode 100644 index 0000000000000000000000000000000000000000..31a2b968c2d0ce5cffdfdd6059ba4fc0db0acb12 GIT binary patch literal 147 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 + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/zbf-admin/src/main/resources/static/designer/images/tour/open-group.gif b/zbf-admin/src/main/resources/static/designer/images/tour/open-group.gif new file mode 100644 index 0000000000000000000000000000000000000000..e78b4966713c73ca2dbc00a1cf97519d82c99ee8 GIT binary patch literal 44216 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 literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/tour/sequenceflow-bendpoint.gif b/zbf-admin/src/main/resources/static/designer/images/tour/sequenceflow-bendpoint.gif new file mode 100644 index 0000000000000000000000000000000000000000..b088c86e47c0893e82cd751ce3d184414bd6ace8 GIT binary patch literal 74199 zcmeFZcT`hrxAuJ}B#?v_s&qq@E+8l%XlP0|AWDaTpa>SghKL$^6Y0J8-jQBH?+S=W z6GIUJK~X_LRKDf*Is5GMJm;Ko#`ykt-*Mi(91hfE4CH35i+RoKH|J@cQ;JG~dqh?B1X|me_Pjl~a09q_32A7nYiOL-*3s3|(~1OZUlgPkAYW&o2M`Ei3fg(AUF*? z&IFM;AifZ!l!A;3bXFB#PPIU8jaY7tbV035VVz=8Jt*!5<$a)P05m)Wt)rm*Idk_* z?(UcT-7kfDCdGOtWqK#&`leL+rnJhNbt_s3Rc$6UWXmTV#JVn*=H4qUeHsJPx`Q)k zhi5IG&Do5+wjX(YgFJA*bJ%f=a``#s*2IG6%fB)# z#U&&sC$7PnKW#^?A*Jo#E=N6Y16%}QaG?Z6V)Ie85b5m1OLt95c?`TN>Xw2|< z%IKu;)SE{$%TcdZ5?-$+Q`T}`%oI$_7Eiuv>FjCf9IBp~Z+g9yv-qxPX}xlJqh{rO z+x&9<>WAjFO-hU3JUMi+JLXM)^2SVSdwYA=z|*0jq5fxM10&C$j!!;^uBlhk)6;#g zmtM}zPrY93SzH}hUh7={IQaha_`8ki`8RWKR;M;LM>n^oK7X0p-ubxnY<_;8^7h@r z>c+cw@7}C$zWKbp_+{tq&bN&(JL|i9+v}9A&6Us4wfFt!&!4|;jQ^J|)IQKd^JrIO zwELo1#I5=&GCKpYg1RZ%m08`P97mjI`zo`0!*LoRJUUf5{n4Uli>&&qatGsOE)1mT zRObyRE8bX}?XS*%_9)hUwm_|>U^H7hdaloCl{k{AldUV&SX0=Zf3{lOam}P)qTHn6 zd1T#6f6aBC=F5-c$12F}er;UR{)%oB z-HgJSM7;(%M^;z#(c6-2Rh`2r(Vlb3GN)HclrTvrq!bj|Uz9{Q@}Z7@8J%LfU^X|r zr%Css*70l!Z;I%(G1^eU79+y0(J~^H+y4YX`CLf!Jr~>JtcGo_alr@sG~u)JJ6v;Z z`E{)}%H12AFKX`?e)QV)_GF$8Kk=Z|eZN~Q=AimVHV-(d9bI7i@N29bMQ!g~Z-(F6 zM^k=vMlJ`U7iu~Wr%seo>&2ye$)R}lNG~#cX>CLaeuoV?1da8F>=wfmmz@^b+ z)wnxe+Fd!x74w4Lt>Du@l)iMKE|03n6Z-&-i40$!g!)eyksIGhrm?0M8yw?pEkt7( z?t4`&i9K8)i1?q9{iu8B=EUWD|*YkDQfx^HU!bWfhpvkFBO;d=gvZxwo({^OCu|KEzI4 zt!E^MDVCEfmcc^0U$dajha(nSTqcgFeB+3Ddm~?FbwD^?zAz-$I16J_qi1L-75(yo zKaOFxbpa!iAip}0Wxh)z!BCzeN5g0_>ikaaDTXyixLnAtOQLYAsPz1*I)A?S5Le7~ zF{3vTSE?qn0xySZ-w(yKXucwA9Mba?D63_^KsVRJ`|x{-5l>qd25SPF?~f{|@m%d! zAX{iOl%WJ}(0{pTDH+kkX{3YGNXh76^2o7&Z=TW|^~&O$v|B$;jr7v*pl+l3_@LY| z-Ou!qN2mH(lvl`pxabFCYcZ_c$nL0A{0l!8&V0$h^PqKj&HeV`ewZ_ltHySx*iF*c zPZIZc46283$nW-=s0zM$(i+D!x->7I{0YP7+T0OLmgn}DjJ9iHE7jGZ8kwxXDPf9@;HRz__q^HL(ml*(Am+xv)I$gp!pu2Z*x z`0SB^CEdzoRrytVXSH^0P=t>@gZ@QX{|~E$1(Vk)dJutYK87O_mjK^z+#< zd7@aLHNoa!*A%H1eV&-XznY=b{FxRTu3jX<|B*Uv(vE&Ww2-z4dk3qIS)Yw*6WM;x z=A4pIAY$&TE4LbzsBdPhXwK^4wn?pr5q=jXr(Q6b!DxcFEB*OW8NPAq#vPKkg_A4d zz-FHA=o(cMA~8akFZX_bmG!WQLeR{s-h|Vc9Z|;eH29hi%p}6%!I=V`B%RM};|M>+ z-ojyFRYHvRt_X9m{Xo{0&nd-Ti$5SNXQ`n>HN5K7&qhdG`A~mOb$^ypAlC#t ztLAKSqu)Qr*kDe_TxlfR;REy03h#qg$km=Aqq(&ubj&tP$fTdo12QEr8)XI0?Hd^q zqoW2_5|qYUSkL+CHEJ3a5s?L&AK6F*t5ZxIlLb6SD@~B=5=s3}>6zbDhG-R{nv{7T zTMLBP=-L^buTMVK>_hG3?JaR$LdrC!L-Goz@uHAZ?u-5DiQ1x-B*>V2sG_!M-O6bd6UTG6`p%U#Bv_stHVm{(Ef}W%cA%_u;D-1y?J0>h!ujLO zi13(1HIX>tgNq*-Rz%@{SH7E~O1-m9pazC5A>y}608DeT@)KT6L_DMKyW37={!w~RG9 zpF4D#I-yR7NqzsRLJ75mM~5*}O^uAvinyS%xPHX@lqAB8#`Cd3R{<{Qlx6?Gh69KW0xyjSqkP`s^k`<#o< zcCh1O?n?{7+6xiZ6h~Van_gdC>(}8AUN8CQPP3ytr_>R{j_UWFz15ho42{=Vv{3DX z(w8=^Vp@{!nJ*73Wb8-z8hUl;eY&mBApH^jNJB|paQ~#%3w1*_o#Yv|oAipIW1fj8 zQ?*{*O5G;o9N!`H_X0}VcT>F|aAmTXObgXE6fLgt=g`ROXaz8{2N%7|JCdrc$rv`e z4|mSJG1Iu^<~gCIDZrAsV)F2DPAK_jddZpD4W+hAV=dCJi)pOaZy)~l>~qSpsSaq8h)#pFXl*A_0oY0M~WPDBz~{B!cl*$4hL2b5;8 z@Fa?4-fr#PpLcSur;egj_@m}qP^_CF+ITW7`w(m&J?4|>gFkt6BE8{kUR##`tnkrW z4I!rI%MT0>9sId{VCaWA%fpZet)3P&I2wy72LO%(2oeAkAQ%C^&U7Fu{vp%H2j35Q zZ`|?bNMK2lL9^nik@eK207PQZKnBprU^o+e#Or-HSCEhk;ibUJE5Ky}sgyv<#KN4( zJ}Q&GClXk)v7o#H1(N}(>ZAiWYSA5E{YgJV59Xu_fY?C+JSNKBw|oTVSmAeO(%)vs zpFI=JF9SOkW{yDVcfjry1e6o0S@!X0Uyk6YKEI?2BnuX;=N@p`0~THZ>?_dG93fc=-q~c- zL7b1l7$%1V!vS>mPDq6r->p7aMx77x-na9EeIBNuqC`0|a{_*1Q}Z-|ndijv-qlHrV& zQ;L>1k3M=gT5&%yTDc)wWh(l_ZZw`VMqMdJ(>&(X-5Bk}7~O^#{iztk-53IAtg%w8 ziFxe#yRl}8u@()nR#UMyyRk&hID4fy2lKd#cjKHAro_ytG()yqgfgnHZIru&*8A&zX?9 zi3;6BMNcKB?IvcdCM4;Q;-}(ED^QWd#FILhq+tKt#Q4yRBy}B3=w_0~-6Y)xRN3WZ zch2PKDoh{=Y37P5rbL(YC*KH8XiG$Ph^3elQdBw7Il(E{SCgZdQ-;M-0*NW%_|)q< z$*CPFQ~SY4zs=~z)zqtnDbaFi!@JSpGN~(xacg2?>tZP<#Zo^u#0gG{Z3iR21_$pZ z#_cJI1(4GMHq&9^89-bt1DEy`jX@=4TvEzFB&E`DWingDv5JfNN2L0L81AG@d(NzK zG6t!f7C^?F(8&_`7Rw)kVo**qC!t0gGNicTSe>(eT+S3Pik9@uw$jOzZOk@{Kpx-C z#uvr1>gKH9%{iKsV;!8MC6-HYjx|w^F}27&o0zNCpKF1MwF$|zEy_8Q6l15Hr++t3 zAtcYTFi&MQ?}}%P>sq!WSH7i1zI#aiZA_l0a_;@cd;_I?C9wh$ChK8HZlFcM#iRo3 z{eglI=NLcF=*VvchHEj=x`n=L1@<9@-bIBHYlSI|g`r$UXYLltUoOf~jxG?7E>0?v znJOyB6qV`b$B7qLheTI=i)!#J7H=q)S}kt&j3PHib#j#mnU{zKm-KK&4TzW2HkOop zD@nwZKCmbr*Nqu=j+*i;#mK_u; z-&~8>nvVQxQBIp!&fQ=BEhOS+QY37z9H~@s;Bp0`I2?7aY$K@x*HFQVu4J$bXO@U$ zJ6`$8qY_(K$+2h2<5EsPQ~86dsz|p=AT;veOoZ6Is;H`}J?ARP!HNm4>cdkQmwixO zsaq|vi@Hok@{(X26z|lcYGF=vFrJzZ)acUIJmDJAtxWe?3QLk2O z2=5}#-+N-_@+8os)hqC+Du z5}xo7sZEP(crxk8D!G_V2dXwx-%4J zL2Omssn3PNY_YAIF7e?JHOmrpUtQv3^_mT4+B`WMCtRq%NRZvp zP543N_fWFCSaVlsD}#Rg_)P1}@%EdmEqK~ijw|s?v^8&M+HWwA|DO8h9gO*V=VkNuiF@suDREqnU_2>Z z-^^PrNY#czF+x{bL{z#jCw6cU$z~~W(#>twkK&HZ!W3qs0(YC8QhEf<5`#lKFJhw; z8xoyWdYx2~tYs!DJ@Vy}H!qMNn9POl0h`z=M{Tg^L*?)NUyQIArm8d6n*``;CHTUkY?%?N4e zrY#qCwtwrk0G)?d`}M}s-|GwvD)$8FN4I{*kW~ie*Ltp7U2*#psh#%|YfXo|2$PU9rx?lPSZQNvO}X{cE$C!@HSl`h`h6-IEr1${|^* z7Q=+WAXGAVycmm71YNpqt#W#EC@qCx}S2VjNH|IemIfZI--Vu6KRWu zd(R@J!=j8{iSd)4_ZvUc8jynEkeS)In|}5?WN%k8B;$TsUOit zl?)46jLa5~VM0*PPprqr42K`!M)Q-y`DJF?p3L6eN7eMJV?GZKOAowSa-RFr2a|hc zn@~F2q$;MnCll&28yz;cniO?;b8g3pddoUoGwemw!Yc#j*Nnce&h5VDb9v2JO!+j4 z)M^P2&Zwg)tU+D720uZe{ICqqK$_^x2NT;~w1l(0dr8fS@lc#UZ#iG=KF={X!&r^- zNSoj8I-l{tT8%|wzZe6~Twrn!@=HwjGA>*~4 z{c=2ay~^+liI%rsb8jEKe|wd0#plF|pUp}@*>e2;yEm-T%K|#fG?(Ar;aiP*T&FiU z-w$7nehhQwZAzS5P5Zf;!MB$Bb8%vDWhm(t;aYadYE#MFTG`LF*5s9wX%iPK-W2<+ zMn8T2SpirV&do^;fivT&oHk@aC85&N%$#L7Qu6i0QJhWANDE&Py~ zl3r4{{#nF&X7Q(`h+$MIe)HsOA@0Ll+^;qn1)H_n#0y*IE_1h*%!wI%*ixn6HhK+H z`!K^t+~z8r`&_?mb+SnM?qqPwq{I~L?1vea8=5d>!X|rZT22MsZlk zn{hVsS-h0N=j*$>TYcZ;b*QaLyW_my^bPj(3nwt1-|X~vY7dsT*w&S$SGI-MwqL*2 z{j9V%ozhf3-q`m2bHaDziSO35KU}1K5cGZ&`~2uB`Vqa~@uS&u$eru!)5GD3mkSq8 z{#*~+)0%2rc@|#O6jMF>a~JhfbGPYJTX>XyOqtjIPJQ2LG&a~$kUP5A8Fzc{Ka6q@%JB+v+GeQR&wE zrK#unorF+!Edh)16{8%TSZT-Uaj~(};p#tfEMBagE0NOh_ndz5&a~om-NKN?#JYLS zG&+~u=UKBtFsNaJ}keQ`Ffqw z?$3D0W_HJIsXzAcrMcPN8!Mx^XYy@ceY>?j_2hav5BA?Plrg{q*Z?>9m7yTfXgXFl z6wg6+Zf+WxV^j*N3^EG8!W01^J_RK~Ir%^Hlw+zVR8>`h>M5XQ1oTXSl{4o21>krK zINy`fJ97-Le)6=Ax~8UZRecmO<`w1@75|Pf zs;a8$>+7LlqPMrVs~?IQ{>U0e$A1M4)32tcrl6o<^7X>_yZ5sT%fEAk#kKdpbA(Ty zKK(zK7eL?ZzpsBf0VqRpspkj+cz?08adcLFuDCGo13+H~CuG+dDq~esL9x?i@0e7>JzldC_1{`}%Xg8PL58b2QC z4B^YTA~Wn+?0#xOmR%?<#wUm^a`HnAFO3z0m#k~IADuS#{l;E<9~>inVMv=rvGs^!>H2fja2#kvPt8PHKCnOq;jg4jPU4PY$fq#g`93&clD8>e)7*G)T zw`ly+!}9lE|9S$DblBFrGEpG_w-K|rkq@GW?0tmV9$>V^24@#dekx_Eh@)b4$tTVW}M%4$DHJ@wm(>KgHuFPL=jBLjjPI5>}-!5cEVs#A(vv>!}znqZ2|) zq)e>=s`JAkK~-k1-KMf~YbF@HmT_wMt-q^f2`WNb;Y9^w~5 z-1?YvI~pe>DuTc>;Uh$z_@1=;Lfp$`BE!hjqMoB+~Cjsb8C2ue!{!N6%4I12|h zaNr0BE^y!qq|AVnBan0flI{ZPCxM1G&^QOwF9P*j0Ph8iZUW~A`T$q~pbrG~ft(eP zGZP2S06?V3B{AS|5Ze|GC^!MNXi8%1yp&3M`Mzt%gdFU>eRB*)w1%{YpZR_^Uv2;-pY)>P>^%Ew!~<# z#d5gm8oB&Zf79iW*1J7*_n+suyzIC=(cuHYBLLC?2vz|xI1r}VU%Ypz;)Gvjh1K0!_DN$!9_TB`|Umv_F)4ejnHI(6}<)qPXT>OUdQe0iY*P_Idb; z#mBNMQHPh~jy(@I9*sZSU2=IfTjyQj*{vG$K+X=MReChKWmD4(UR3!UHYOhYpOY9rYq)kclzs&#HHTmj-LE?y(ORfYv;S3 ztaLZ6_tk87S8ok8Z+ACu4>s-&P8Isk){&kL=MGI2jXbM-@x0*0%ewBBrqT7*$@Ti# z&HB%SVV_<;{xR?=NTWujcH%FWA{=*x%0D z-zwVQE7{+w{PC&z=a1^2Kbj!^gxu5LIWXMU*Vj8d+V^w}5_yP1c?n&Az$d+%-Q9bG z!+V1-zYa`%?;hVDoZjl5+v%SAJ}|SeJojd0W21xex$n)7{*})iE1&z;_j)(>2e#jL zeEQt+@oV4KUhn7c1ACu4zU}q={5i0+v_x56gD{o#^>qkS+1lFL+uMWmVGqqy|7@BL z>@&mhDDrfx_rKs7LEi|l1UFy*5H{NC4a$Q?+N;63 z^4D!7Dw?=SIqufZAQlOmq58_j-UvaxH2sFEH-kZfja>l^)o-6=XoS9}8_hl8l6|(= zX1MXzMIXuST#b#!+Krid+pjKS$E_9mzg{fWDpA&B-89w!8wP1Pe+r##FkdAnyWjFknXM%!ww5^z>2P z05ar5JG0Me0PLm@qm0x}X0Dj^1052zmdr98`X(zNu?C7|!2oN8Pq>UKStBozD&dnp zidMm!14k-UYt|ovS8MqqnCEckUs#4LTK`Ezl(0K{NH%aLN?s9Hsau+3Y zkePsEKSUf9E%<7~U@=6PO7M?_h=}h5Uo$~?AM_PU=YcO!9JeQjaxHMm;l&4oMwjh}uMoVYeF0%W7MQs)@}VO%_*Lc~OYrf-9?3D< zkNLH093S&wLZ}1+SB(AFu1d1>_LiRXiEHbmXM9SUha3+OX0sVi%-r6)T3F7p=z0X_ z8tF>?MrM(L3@`S=3|fuc>y~$2pMDpv_O0_wMNo^kw~`;ghsax7jlSV9liAo(C0O=@ z@?I1rgd08?p$>{>2A#Cub2^$G;YV6H`pxM_)UnI^Qb(sQ zE^3rWcEye^%fKk76_|rJyd_UOj5k0$XPqQO-tTa>>lXt#Y+(`yQxt~| zDmqD<#i-G&iy~qK{M6Y_>D^Nl)P@`|ZKT^Yj_V{T;kf$TdH~CwN%ck)0A>Jj?Wkx?cR=awI-h&Z{%fS}b;kC!XVHIwh8+A*3}uP23Hzu$n5QPzW_75VmkO7b_9dyfpufCth8qZ5Ri5xg688XCIBqh8}#!Ul!9 zH*Sn!%eHc5tPS*(+R+9?I7?&@LI^h>l=f{aA5ULI2-F?V;@U3IHYhTV9~jS$I_tFC zM{_LCGt7nH%OyWtbiQujMVaSzF_FI5tXFrUDrvjK@xHTGzV5kV8@5u{uwtvXx-T2E zUYO#=^G&8K&ehp$my_sAh%|bW9b8{3f(%OR4-8KB2(XveHodZ$8VGB(_)?WHTypW) z;M7ykFVz|JrB0_MESi_kmB$#AI-3qoPc(jcQV~{q<&xgabp7=CCwcTqHrbvtbKkzy zk?G4^9bKlMV~nee-fXzW56&(tAE@tEct4VtJiBJ`wQ+K|>~`JYtM{H?n<(_<9^Ks5 zi*T356@zlmmxFU(8o#z|hLwB0)qDMIqOQ4Ztn}K(;On2?zP15|&HEpdZGUj>kWq#e zJ_m*<)W>()v5zbKnDi;LhC3Y`Pb&hB4b3A>cRFzll|iTV7nqZGxfz4{x_sM4nevQo_pj!19R=u$$zrBjR!3m&)sZV@Mu|pP+h%0P+f@A zbr}5zr+aaXa^uCqy_bs*CYQW@egAZ%k!iUh#jUZ~MNmsCzp(Jneimd+qiYBLiN_6{ z{l()ZzFteBtU<>0Pb3%OadQUe3!c3#7d>3(Rd;`vvAg-Lanj zU+uB>=d**OFMf5$rhawD+GpND0PfR;cOCCO4!r+7@#a0m;6lE4W_bg$zRy2yPkq{k z7+lB$|JgNz=-Z_)yZ=VteuJ85TmR2+w@@)>iblLB{LR|xqjWR=nYE2vC@^@04gSsA zif~@#dQthCwQa5!8$EFNH*0(7+2P=$!#uhWYnzb4@oLs*DJU|Zkgc1lyN!yHvT2pE z7mHwF5!UJWqnI-n)>mxb!c3IR)Y*>~sp^^%^EGX1DHZL%i@CjSZv~_LGFKJ}L%BM^ z{O*Y1qh*#`We0?gIuA__{ZY&vds*S#6>8_LFHp=r*yXtPqR8^>QRk_kFiu(bcXPu{ zbsuJrT;Y+u@4>eILf4AVG}Y_2V{@(Bewra~J-uKTQrfiC>$t<)XDyoh<%V;2T-Wo% z?%7(6V!OB3+ZjvmH#OgX^|rb=kg@K^UN;d4^o!+d!%-Zs`;W2QAA4nL^I-L3e8NK( z;XKWQ6+>C`0bCtpr!B9G)#Gk%D<#Y@++BzH-F>n(UV}H<2Bb(5dB^ zcTXQuKgCf^&dSw1s=LI_VmhHT818TteKx-JTsvCGxGTb!&A(YLRI(vbE|jiWtkBw? z=ple+)e+?n5ab+SjuWdUCFI8(i^}zTd^}F>6pMi$6FNNKLp(0cDr$cccm1qu-{ruP zA!F3R>Ih>IPrZ(Fj^W$`V*`?p5ptno*H5ut(!99ce&L{FuxzP$MPt{Y>!ItD!JH?$ zGBnCA1k4m9wzmrRKTgk)U1aX94St)?qDmWS&gpIzVwtwSa?yOMwr1m6h-*E~bvbQW zEqY1#-il?o>&j_!g66zsj+JBLcqd>ogGK#&`mlfGmI%d#CBrei=Q{*2~&ot{Zgbc1iACJ9ebTA=3Gcm~5!-fuw(VQb1Y82htZ<%_BV(KErH)1DAyjuWHi1Y}8OJi0wI z%(a0fwC2RyAand>B?ie9jG$M+;fQ5f4kMi}v#*Z_S?!s;SWn@_O2m<{c7sOFdMz#&` znZpzK=NrPjdXDIUC-wXvnVy9*$xgAlvte#DRKf}pkN|@xQON+n;pDwf*ohOZ_qqDu z(IYmA{?qi1Xl;@o>NQ6$_kkKRa3?JB+QWc>6CA)f09}diar9_`4Hp%W{cT+T$$&9_ zubD6;9O^)45ZSR6z5*9AwM|q2RZUE`l$$8_-kXn72L=v=t8|e+{xA+)5F5Qo#FETS z1OTGKSU{EFZT|Cm(zuns!a)=c#?*&5X?}CeH*uf)fFv$50g%LRcMX|GWTeV^98zgX ztRzUqWVS8kb04aJU1T4puO@a%;xjTC9LT9LUMt@=wa-L;b5AFJr>8sbO1f~(2~kZF zJAJwj{*Ep%Sl}vyH19V;YSxxqBHG}ReFhwBmHR2Z_Q)GlC+QSZHsM(^j(|Z$c%00~rved%7B#1bQ8Dxf-c;Klp zHBlOs1b>vMt8cy;Qo>?>KzvfpprPcAM3}+gF@EFdsT9gaxK69fl-< znEs>*rGs{w0_T4fbGM%alBj?#3C{Rg8&8$i-RW{JYx4QGIO%M&AlKt|!3R<(_1A-Z z(Zp(rI z=PB6*kU$9f6$oIkf8>SSeC%A@jE5v>4lB?~$;0K3(<+_h5fJ<%GE@+PMzEAr#AN0E z5g96L01X46a~2p_03$1)X9rB|fSDt(bVi>e0_&TAcpY4DhjPSYY8od`YeQw>p9!Lg zg%wm2S~)lpi9{DSH*lQ<+k0XVi+<%pSr6jJEPvY);}2W`iSy;u@rO@% zRah!sA1XGt6f&Sa;_48Wbmq>f=`kd-<8Wn1T1dRYU~&9~wpJa_4`vBfcVAA-$h|+G z|1kQ-gwl6m+D6v%8HPVipNuX`sa<+Alm$o#bE%+xTWOZ#dW;urIc#@fBxWS@?cR0X z?9LC{hgBj7@FkMhbo8r$7Z+}~kUOY!IYt4TrHcZ;`vw`5WXrDk#fO%GCldkXpd>&A zJVrXqnLMdk?n>7XNsQc>NCY^=0fSzN&_1ZojetI%xG0kvmRqE9o(bzg$hw+<%s?=~ zuo+#^1o6yy6lcn99kt((I;FiD$F}#1$>y! z)b3tHYsrw?=@OlVuxhko2o0pnDY`@ivxpVmSB+kk^*;a=zf#d(0to;uEiDfZuYjPS zq@<+$(PPTW$A2jwBzw-DYU=9H@aY*NVa`ad}VNFa|~nIyry+o@3W0$4>?4W9sd7InWJ*Q~B!Do*w0pvpym1c&m!52enM zGk+On>)Q#?P^v)^pF1>^diHH#I^Gw9?o(hXvB$I^=^V2VMyf%fCESIh69N!#9=#M7^da07bq~I zA_2J5y$BQ_!u=0Yo2_hTng;rmAFm%k;V6L+K>F#ZXl19Sce6a$#Q*U9%!uYP+ySGc z>J6ro>ffD+jox(66$H%iKPabfESy9wDM(#tcYDs1!nhxq_4V>WLH6-eGW1p+R9qOd z$y3+tWStMH2#^vCntBi*A4a)zX6EKPidDXX4F6{EGM$m%ECWY-n1F@f|M7$D%fR}L z;>&jV`F2eLbA8F zzjEcuty{Ms{rD{skV2%Urb3h7kT5_!CP)+-8XCH~x*#za8yka^;CJ1#yz%kxNB@6v zYybV8|Fb6mNy~B6e>U$viu3>q6|i@?grN&EB(t8xS-!$>v}S5Hb-5XXF}5LeG?>}*n~;NhtH zB$XNBS|FlUl{x4hb0_T8!B%*iD(t8(BbLEwQ?co&4;{65&WXazcH%e>tD=Nrs&OYA z9E4@;Kdq{PQ==Go2xq)<18L|#nO2Y~u-#amD>$4b_jeiyhWK+|MmI!Cu!F<@|McU( z5|6)?OX;B{Ru1tQtpmGKqNrTrKfm2uc0ys!b19wo9;;o(XH zKZ&$aB-U#T_V9{q^7g?xyy@Wk)Tc=80NDgTA|GUN#}`g>6MfMP5OJjG62^gZWYF$S zRVT>3vXJ-C9^!Soph<`oHpl`Cs`(p>}}ke`+ZH zCZk|6lgK_) zfL%y?guHCPfEJ;9G6Ew}(?iWp4n=+d{YizRKt}!$iJnFpg$U*+lYG@#A~sy{PSijc zy}U&xcMQ{@-QR~%U_OBeILo7${+Nt2=|NDNae%+W8}5wE@>};-CoIdus~s7djwOL6Yp zIcU+IuJbvYTaLGM4Sp}$bMd$ibu1ut0kHri0+0zn0RWu<3<59$z#ITe0IUJ<6WkB= zt`Ivkmqnb2ap>gwv|=H}Xg=KV*p`_akJLc0B$hW)0t{buq% zZKi{ApYic=sQ3nP~$T2boxc1j;+EM#mH>?R|DIH6J^BCZj?c&pn z@Sy%{z0!urx{T-9&_Kr=gcURmfC5jg8XCLN^A};N}vfmhBPB)PC;du2F`^ zM^2Wg>}v~DT0vMGwPHR@(08lP@WINys9TFl5SCUz@y^K7y~R(<&pK^MWH^HV{cBqq z{@34c;m*pBBG`5ndJcN+rS^8>&w8CF+Mz@^Iv9{jY7}38Rd0&7sFl$On<0^dgH1)# zBNffZ=a3n6_XpkveUfNugJyWJ(#3M1s&9ft#Hy~-fAfXM2&}aI6Na0eH{!y`< z$4H~h&fqgx6PtSs*0Nf@hPPK8qX_~xwI1=ufG#!u6wZsb23s6(MzOL)4%V{)85*(f zBDeh+U&dlJ(;mUpY*4CQXeZ(svrCsA2f|M+1oI!&O$c@TNi4{@`*B4uJ7GasI5zc* z!o_swfF#r8m+hCGZEo7!d0XVMu|M@Ty<$Rm<(B`1u4z`8dr`4PcmPp7r>#{>>`^?s zOI#kyx1tiW^Z*h(?b&TMI8a?Vm6!M;U|SQI3t3GC9lIwv!(oIjaXI@AVcVZ6lf9ao_P?su`Txb1x;y1{Gqbc~Fe>)GOgcHNNqAImBxp#8Q1N$_xnUP2Xs932dW(L|k1!@^s9RBf;EU`@ zpDy%NRRtB3Ul>M_^*kpPy0^kFgG$^LMvECaBn20b1ZgsCcldU@1|IMu_tkywam65*oU@^t##c~zD-#>$q^YGd8e*}P#W7rP>ezr$Sd#Xs zABhoW*N7wc=5U!Px96u#2gc$WAzVA`vc86eNF{4c4oWLRy?WD^PaDFuRTo$S{sXR^ zb81C}-vGu)y%sIVA)ihkY=81K=a|dbbN*GUOXpQr)9yq)C)iqR<9~A~&?+$?*$wI; z>jDj*LRkn@t^CeHpqTZ@kt2VNLm=w{#UWR(Ui}@1`2NA(Li0^fvG6-5{cT-3J39vk z2L76b{N2v{Z+=4l{nGzECxF`gZC$94NDR9PPLu!xX!v0nJVz##1|uijgM%;+>!9J1 zK4nG8RQE>EN(S-NXOd{>sd_baa?2n}A3rA!&dWMJ7VS4}nJMQ!Zyx0eUWg z!r@$@oC9#lZxV_8AQT+ssi*LJpQ3{yf@Twm`~g(Qj{uwn0Y??f%O_Ofbi{`S<%kqX z*md`&^1-MG8R8=(RyB@N~t&Fvr(E{CR##NwbxXwSpbGo-OERZw8oK3p7t zBPcfiZ8Bh&*M{clCwdPY$GhU2ef+7hHnvL@nRkcj2TXOpVt=z1f52!Dp`nB}u=)pU zar*RW$Xong;{6K{b8&$l`MY=T{@e2H|G@P_%eNu4U;Gcc|9IcjpX;@MGy4#&@ARB< z^ABJj+NwQM?KWNO`FpW8G$08Ll0z%CA@%sZLmS$k-O|zmt;_xs&xh7!LrDH_0Ke+( z#(%XI`%m-HyY!FU*MHr2y|}mtHBg{LcJU9;{;xZ(x4%QSuv z`Wy3Q&0PI#Wi7bE+E^iDvBit245DwTUX$T>Ol`rWx5MC16>iy5iv(IsE0XKZ!fg62 znz>gxZrAl29yorX{~nKGeb|D}7o<#Bkr~v8wS2 z<RC|R{(eCky9nPBN;U@Y8>qr3`1Br*gV8t;(Msq z+;#5y`5y-;B-F=4Df+DSZ!_G!@iVd9r^82T(qe(Xtshb>fsdeukA&USgLKrK|1nA{ zn1^|Z-&$p^D(5^+!K59MkRPK^wc^IgCf`uZl6#2 z&lO46zf986kk^Z%rtme1<~As4Jc z-P{`bJ#4BqqXd=I8@0t>W^EACTF!DY$HOI_=*7b`NpLw)l6)3i4C7=N=?)a0Dg^#8 zo^@XRep^SNX+J(W!}iAI>H$|Y42hM+^S4jC-`-0OCS5~*K_Gfnkt}v9V zc?p_`o!8#!g$?kwkq&Fok9+Luk$;vgOV3B<7%|w}Ce5CfPZh<(50lwwRsxUjg#{uB zBmWFt6V-O;@lRh zeokD15=b~!;XAG2GFWQ8=CO_E?91apJl4j6p4M3|ak&TV6pWc7);qZ5U2Axf)-?58 z4~%+yVuIte?lr3$p?PofXKYXF-|M-tr{!(IT_5HsL(h+!2R^?& zDQ(OkHL&_2m?y-hqUlDNDJjVsebuA1TXVdep)x5@&^_h4oNo-a?5IoG|?( zWvQ^;VSOuabfHZ5dc}r_-dq28!n92PT?I9*(($zQol4htl`j8q!qj(tmFvCUyNxaH zeomNPi$co^x8fqNS8e^!d+*BUhO=Sb6+BU_Sjn&N;Do8#R@4c5#W@zvf>yn0FL85^ z{hhjF1p(ei+T+BdCs2AciqDZK=MNgv=#$?9@TLZ%#rAiN3fI5f5jNmj{6ms~EvR82Bv9=b(IOE2~cj3dS+w#qYu5^#TjQ-+w zYvzd#t5RNL{izh%Qx%u8r~Bu2kE>1=nK!o?Ue-u>X*0>WakzcprADHr+9RH@;f|MP ztCBWda^O6#Tc&O+iSk{`?=UQwI}a0F7#j1)66Sk`e-#>_|YFE z7?yw4aEJOmy}pRX(8AM~b|`(g&~xzn43{|#sU*x8NHAY0V!u3Ns_8nIaiG3LV*N97 zH~pdPu7y&?%g=1XTyJHlBeq%uBa4sGaT_#l@Yr+4Z>q|>Qxm9Nz2n=gD;xr;yP6h%Jm;|-c!|tv8T+mPu1myiPBoZB&nl1!<={Ktu{#1Lzo7Kd=Mw4ZO}n-OI8gxUNq|3rs&VTbpt?U z8I@eS@_g*Wcjqoi#w%=agyqEtUW#-1VC~H)3m)2R{=RoJj?R}X3ew-!y&^r6B}I3y zzlN$iYE+tceEz;ix?A?@D{tJ5+VD~8AG7TbOs8M1CPW=T_5>BqSiatK$3rxV`_Sbv znHeMNjokaH-m~6D9D4S=N@8DG`juB_u6`p%Jb24L;rQ`|(dQQblMatGe^gu$(*N;( zTg%rFos;EPrM`SBJ)D1Jo6#qIiG%)IxZciuxc%kHx=J2PYS2mUhOfk?1Nzy1Uv+@Z zwF5iDqq{!$%>yv3BTp1tb*!eqV+uhQ3xHLU$T{-U8sL zE>idyfk=jQMD)0m-|*cSb)^_%`GW!8knVecl#=l=z9VF();6RoH z;izu>F}|LVErg7a(xbFz_A=C{DcwviW#^y@JN&@0S4Brwh`8((al{2@nl{C^UUR{X z-9FyH(F5+nS%(0lA4(I_%%FgWkp2McQPXw4p9Lw2UTHzo=&3`5B zw_zfz#KOHM*Wvk|{8x8S4}9_>H=j^_m#^uG#L~7DJj)-y>upxTA*rJ;g>~g-gOO}Mh&!S{mCk^CJZqx}6FbjGo7(V`_uxk=!L_G3zubs-=E~(x? z>E6J{J6#O5L*6>2DU*>Qxu^77P8s%|>V!+bMN269C8n+==20bP`XMVv3pK4zJ->U* z^J$5_eyO8tsZ&&`b8@iJy%KxZG({@XNVLpT^tchV%qObMH?PdEr7U2yEU=|aG$Lp` z0aQG55O+1)H&Xn*tW?f5SL8#%&aBfbdQVR!i68h(Lj1yyP6mfT9B}$s4p<9-Ij^9V znB+eFwXif`ZEd|&8rV*?`?WgI0FddCdvkV2+y-DAfOoL+?&L9N_E){d?Ck85Cr>W* z78@EGu3T9ZwSr8CJ9qAkjg3L318f>DsZTAhlKk&ag_oZI09X#N`|EOmNxY(|<-$Nw zES7^)Py;_-`%@20p@VLWh=F=wWnW1@^}rk?$$D?Su5-%L;OK>>bWEPg!5fYm#lAOB zS?j;Pie+AWzCt*vs%CKWw?)2hZ- zeMAxJYMKatoN>z@RD|KA2f~_D50|-#H6P^Jnjw}xKo4acI)mBBYi9W?t5wfiB0k*F9xOA?Dt z8r{7L5oU7#U|ReDTGv1B$Y*t zDLWCfz_9WWK&!Ax(tiLXAzLsQd8(pP#obRfgB-Ihp_ojm(bylH8HXS5^)hW|8&j*3 z2?-uL$dOHq!AS+YR zT+?Wnrs2d~xSMkO6u_k-uO2`qtJHPA<40Cu`Qn1>E}GxZyS!2)gMGFtA>rA)o*$?xyCszV$dt-Z4-}dXQ?09l%#YHvyg62K8nkML#0rLZF0^^#L zEx8i|r$mKUENmCjDp_^SM(TDphGR>??jb$yl2zxnX-ceNQ#{VO$7E+!0dWYKn^HHn zqbC}P-8FQ1&$%_voi0cCqbBz?j`}Ls-oYmbyl5K9RlfZ3VX`!xar*$ueB^QFGq*Nm z&Pr2F0!R4w_kFTjW}Di|B|r1`C1^-#fldZ`m?ks3TfaLQ=waw|I^?ZD-%?muxa3=4B^mmb zwzf9didv$jK;QE0*)ynWxa?S#Vg1i}0?^f%{k5xUkHc{(<q{ajGKZ{ ziZ3!IDWiF8O0?$Tu$3_!A}84jUocQ3=(Rl5+pNY(OSCYBgfe_Z~?C246~rNTnC0~d@w6shUoMd zD-m5=a`M?ODxEAu3zi0=bkJ6udZ3AQN+h7R6(^D}OgWirjYCp5?4M(73rGgO70)*R zpaINrmE3Z2Wt)l=5=&Kd$BG7%D{GGKB-t6Cs*F;uyW^pqW$d+@T^x@i(JSifB&mo- z^#t18?EA-jUZ5wFUGANqE<41Je1>&tMF`fPC~U%UsGg-ge(*)YXJ*#T4R`0W>iES> zHun?EccSiYSlsQ3;GH>>3$-+$s4?$_-X<>GK=A)6h~?bJA>=ndEBf^rmsVV-9!WiK*Hw8*)6V7c*S8yPyBcV16!hJvweg|)nWJ@Vx-SQ-FnX%H zEqH|-7y6y0D*yZg)j(dzhm5md3J#G2c81cNtJ?cWo5OL-9%Yf|Djt9r$5U9PcuN}2Zl6+gx>-14Zy_D9Oo+l zT~1DaIH4u-BpeTg9nGb7CQNXCbwV(~S$0ByPW=6!_EgZ{IQ)&j`6+cgJZIX@E3fps z)UkwuC8Sj+rs7vE`WrY^&S%kUTT4UXvrwDb7Nw3irV)tv0=-a10=Jy~%-0@B&OB*) z>c(y2BS_A4(as$HY&>g=UTxqdVe@`x(izg)=mD0K%5Zs5N+@e{W6gMyVq-G(BI70U ztlfwt#xT@ms5FA_p;_JTI9IL!5n|y8eHX4lwox)muf80Yg5*(^91l|^G)NAw$x%Cs zaO3hb2{4mB^41b7Sb_8wTLZ~mA>Jb<&r7NwqvdaXH1X;EX)}Jzu zxaymFXWMv=$lJQ7Ul=$}+nQUNE0x`&K=CchjmZg$ner*XbSf(rM23d%IEmc9la-0i z#m$%=L|T_36gVpLalIl@F2N<84go{NT3JOt#_K zTr0v4QVd>!J}1kTd1bb;hL8l?VhTB=whB#8t!b?htuawZ9h)U+P4~>U;Bx20FDs{Ju&^KPvz)Ighi9;G zU}N~o%c63@!L2WlhC`P)EZnICIjewq3Q3OD+9@v8VT?rVQ9DPjT48vuQ?@{DHG$yE z4867`>D`-7F*)j;enA_o`i2a>HCC| z{Q*^K+!F7H&UU%KZ)|xlvFGBH0#SFM{;EyHa4+xP$kEHMn|0@c4}a2~KdZlG&zzdQ z?V2}Cp9gE+D*G7ipLeZE_||{h*)r<>_=oq#Y04#B-`^`&3Iw|nn3oMd3skNo;;Q!E zF!=hcXB~0ksj2`4|IsG(J2nQ1t4)t21e0<46Lho|9p!2x^_b%k=w6?u)AkvlkdfI4 z$r8lrx1-4$CIELwPz=F?^)k{&j#y6Bmvrn#lDa4nxnz`Thc$*G zL+w=;o}m=@No)ieVcl>2iNj$4w`H{{qgzf|5&!7ct1PpNj)TcZtM0wcd4HPsj2G&{ zk#3<@myRr5`gY%v$&;o`y^L^Vj>je9kUndI}N!_Z8f?Mn_>Eto`3)dgaY} zlo#X!6l!=<)gyXrwiMeRBR!(yj_GE&QGDexP>29ld%utV+uX~kWm>1LuKT&(Iv)6` z^bX0he|r?4x`UmijO%U?C$Q6**QHt@Vue`;3TzY#`9i-& zmyvOmg8P2&bn0&mj_F2(CE?`_khZShEpmw$JSCGpX;VEj*Bq3YvQ`s0j>(yFkPepP zX)h-_HL_*V!-vG5`&#DaEYL5%IYrTGAs)Y?RTdMSC~_jqAu)9#O|_uhIQsLDCALAv zRh*r`mP9O+iL2nb$YN~wb4oeX(UCuqvyxp&dzZ90}hi#L_|bJMpgpkd4O1qQZ_o|ZS_pq?w#)An-msa z=;7T3K+n&F`3C@TadByBX^^=2YqkuhJm3!Jql_ z!iZ)4-$pDb?f_yP6>XL%tO+BQkRrxm-j$;DO0^~lToMkI?iE91#$l48pxg-EI3C00 z0*kS4N&U!`9tr%u^9T&Pr80S@r+%k(&brvHuOv?}RE1>vjsIo)zn~hm99O-yA)^5< zj17L=E3nV0e6Wg7Mt8jL-sIgD2W5R1sxc$(N+O?FYO+%qAya{fwj|ZYCGj2;@DH3l zS7%u)q$fN<3O1eYKjCnme>T!fP(fTT^o4a@Q*wzPM zKYjdY%szGbvLWIL`bdV4V>)%go!_OE+jzv~ylgbB?Vwgy`GeGzo(cIowRoS&MrsP0 zBJmQD0GVnLsQb`(K?x~|o60q59O^r=y9to5hX5AmArYS{1DcdKDI)a^{uP|TO==KjnR)fc*o4XRsM z=fSf)_tBIyRX3Y4##d;kVBxcv!J_RW;0gCDpbTvN?AIw-e+!LOQrN zzHns;K6eV~LRs~%GS1jbqvNCuE^R{|IF?GZ63-|@SgZ8idqWn<5PxecQ=&%1>OZ(Y zzXP>}e)i_!q~ExVyUgRG|d+p8d?SC_O^J$1qO8kumAug zs17+fLC}VX4O7dCii*a@M!0sUv$OO1_3N;{IXpbP)H_>FE&t5$wft;E#k@irw2=I_v;HNhqJDyin^#vWVFu4vGZK< zDV^n=jwk4-x_5)DG8--)xqLL)I5wd%P|voUDvcUNh;{kxhxOJ3wlF=f9OWW_&Jer1 zRja?5j7}9*vt`nZYb^=bsROrZAJrcZh^Ew_SGYdial2+)Q~Lf@OWOd{;AeypTNE6r z5&CK2(7czzHCS45baaFfn~#rAR8&+UfP{OH?Y1q&%jZx?C=Ah-O#Qu+)8WI1Gcq!u za8OM`;y*O_-#X>X@!8*8sO4|}WG8^{0vNKet_Ga}EnJjnNsKX$XA{wl1Trx(Skh|0 z`#B-TF{uJ;gT)Dt+7U#Qb+TN=d^?&5><_r~yop8UtlD%=Z7&~vW3HCoXvZgqr`<(s zk0OmmHFpl?Qcmb!Cp389Lg?v44JU?^an-`QF8GUgRIG{O8dJAfMJCkaA}id<1X3)H z+t}ucDbv^l*MM4^HEqdY#c@e!4PXWtCGki>pT_HnIaBe-FyqK!x^#O&tJumNf~mr1 zy-~TEPDTY$iiz~Uv@2J_((yxR-iu2~f2|k8g`+SN+p}j6H0{cq$hML&27{5Bnz}S0 z_eVt-x@|Zix0q-R_Ce1LSub#5AXK}#7#jOyTzxl1g%_^7k`rSX1G5iT$xF@i>52v&8emzZ~daMTbpchK9 zF-OY0u2Tw>HDcmg=pn8|OX=6+ze=%*1^SUmW2_u83dun4+)pVspZga=pWGre1xD6- z#9(jNZkJM**u86PIOlO7^~|L9tB1Qghc@iHwQ{aMR$FVBNHcl;c%U`?PD&%wwXf;a z%}rMjSdj1Fzbce;f81eMVtv+X$1Ja-S-nMpmzy5CY@hf;0R~UlW zlkL6_$jxkv#;nO1*#AVYobMo;!bgc%UY{9ioam!^$ru6k;i3d$dikvbq=d+#BrdLx zLMfaQGh4xHo-9Nv=2+r(6Mifmk;daPN6yfBl_M2pzIs7AOzif;1GFHG?vXkA%(B$@ z%ZesZbU%V*j1{rnD<7_&zLOf-C#}(n7B-zIz?$WW6lRC=PSF7;joymh5=b{L2n+Qs z^W)~2BL~^Bl_)YdjdsmoTXuC#V@0SFLYR=XpWSj(xf&TI$kvJ-IeC&6il>M~jh*G5 z$C5=e^D2KFgH_`-$>XPvRJvA0<|AjHRbRwL`B$*8ViMJddn>Ezy!3m0YwB00xSieo zy`{STgnre|y5S9~GdaEHV=s4}&Lg~RZuX$wPr1U@v7+U)$At2Mv90VuJ|dB>e$5}+ zd|J~M?(Pk|I&W@DyLfWcCYY9kO|5KWzgLRDd}(11>DX;Xo`lCo+GPwm~E*Q9nN zs4-t3t3F5hTH}7NXFJ!6H}1T(ZYz2;Z(`2pD?iN->sx!VK{IJ&ig54XO90>33p*OB?q(6L>_-;gRSK8cgz}WFUnZeh_ z&y4KRvmpa2?Vw*oqv_4AvXuPj|_`@R%LjCkmM&HZX$?R*%VNX(p zZajLNZxg66ogZ=FQ)j8OTI4KdGwpmnbH^((+A8SA=MJt@sZrB8mFX8A&aQcOA*oLG z!IxIXkHCo1_PfuuAGKbr)SVi9DtZ28zJr0@``qJhr{9F=1Wqla>^tZ^f53m8{)g-n zK?)xOQm)E=N_^;ysCi+smWFHyf{f0y&mXw*2kW5?gM#0*4?2-pr6YAW_FL%#v?Q6a zPJ04zu+kB$YN^cSR~swFA&s~A*vcC<7bm0T!DeSk5v;6@S52M7uMptDqlxaTl9Ek` ztUUIafkV;AVv`>SEIUYoA&KU;GQ7u?Ius-aldR)p_)c1ODmm3@b57j4D!2NG>Z&;s z`>@NGQ3^oovJiL@3n5B25Z})ujURCSgl5BZ$Ji zoFry8LwTCqk(t2}ygK?!y|+BKWnUbPtkc}Vh8~>}#5N}=o|Cg&DHTW06?uE)DPtO4 zKP6aa$fwxj=;I*l$-p%C=Uvkp-*iCvc)Po%^vG=m1rZA4eR+WXL`LE?w_;$>fg$LACwVa-*1e_6F8b~zS?KrhZ4;ulEu{l z)-6i0S?67>=2b;YSYA;hFAd5x&^Pe7nzNHZF;;qZd+KLp9BZN4*PG__`=Ct2Yyc&h zj%9_So>!MyUWmHES?;LV=Y=;ZmCw)E>cBjJEDP_789;j3+42VOFhN#jwDR7qolI45 z`n;K1r|XnT$fZ+PURd8673vPI2W+J2^@kpCQsnnl*!ed3#x3>Y#JK|YmNxL!T(9H#C?{}Vl9;5|`swRBhLuIHLAzjffbpi_a_Q8283NdF!}K|=9T zDa}aLUU+{#QBy{A(clM+n6gM?@e^;;|C= zaQqQc9F_;E740(bi3Xy|lD70ZVbYRN9kCur$|5vY+n73VG+L;icv2Csoa4 zUhI6k!!jKuM1*k?+3pk%n}!6LJi#bkf0B}IeMg0XGEJ+I`$(VIRJ#_Xiw6LKLIw75 z8QM6?qR^^t`ebXN?PwHkHPUi!0x^W&FH52_S%?RKIF<%2v;ldIv2`qrZ?*H~Zb@K#^fr&(EWmHAZ#-P~* z)pW_ji0)no#U1^hHf#FUa}fD8==3)`TR60252PJaf{NCJVn-S+A_#YBKRfQbf$scd z*HNKu>G_}LpZ1=xInFh{cVYJSS^uURM*BY8pJ*SmG$k=FeR?}{t7_ZLE0@1~n7d~{ zB3`}n?aRlvH-$7@q8&be`{WE~1w_qgjCB%;6YJUFaDFUTBibWQZoOrZh2Yk1y981D zUxi~1fGr^7FEyG!`sA=lzO?BOMjGkq>Bo*8`=bXAac8Lq4m&D;^uS?V22LX_M;-s< zm0te!Kg$U~a9IVxg@{6;F?@dkmn>b6n2uP!#fEv^_Ksvp6DS-rB-@>-&9$q0Q2z29 z_kt}tHk{|JW;KUw%S=R3@qooZV+)m?)t~1)-d4;j?iEjBP#z50*#vndGmKFj`BIMM zbE0ePM?`b=>3|V43xrI+JYjQ}#Sr+EV0lRlB;@zyZtLnd@bPC1o%jFobhC6!ERH8D z<;UeM-l5Mf-Lu(srM@Y;aN)J40*kr7_3LNOHE?s_C+8dn;`17)lf^sy@E~46*EJTY zF-&7bTSab*<#(MSp}(84CKKh3`94ZgDl31KtkyW}886Puq@vXC`aVw6ec~$%6MbFQ zE>SjJnZr__Eo3u{XYY8Va!bz0W?EfoARQg++3l5Ot?$dsUgt>=O5hA3lpep5WK|aF zQ+UBW&#$e^=S22pf}%(0jSJ2NdtBdp6{b%1C~iLR{lX?@OqY+>@%Y)?f$XF!X1=G4 zjM#RrhYfRw(qolzJIj=I^(tEx9#F9_FU|{}$tfK&^{W&+)9Yu>pa0{t%Ep^7^;Fjj zxHl*jH{Fn9L?Ks=KDVxWl{{N3U+SDu+g%oJjP83gT5a8nRef2nZtVZEZn&%?ph9f1^#?Lh9GT(Sgkm=`FU#M5VuR#a1*g0)$>u?cX z!ELA&{Tf&T76C<$lxud)4cCxzuxmpVaC%V`U_;EFVR}YR%2@C`)aO;X>i;25lYtMPVk&f~;*r}PxmVbF+eTWb)3+%Rd_^WS7 zg38<4K=JqF^KYU~i2g9@gz|;UQRklp!Fr!P9(K{rcTZ*1DJ+tJv)Mk!2Ij>XZczxz)6E$nO;`G#zRLC{Ajp-nL)4Iu(9n0Y?Ird@cdwx(m4hlA&%g8simonq@g*4 zsT0~DwpvSoWXU8m81H50sNU?&Dpe@iHJ>L7f>O7)R1Y1?pim__Xr7< z3bdSF=w>XsYf7M;)x4K=wyZ&(=_h-+Yl)iM%IcMGm2Sw<;d}Cxz<>HCP$8&mB(J6; zOVC7oVoUg>Z5ke5u0=3XR#4oHgMl0^G z=f23+-)H{}fy8hPtT5CG8g0XDrxe;=I5!>p>rRTQESPW6f*%=U38Ls={NN*UDkli2o;e~DlOdybEIg8z-giVocD3)b)$&%k zTK;YIx_sX2Ppsm3|Fy!Qw5>?Sf!Dn@*cV_BfJi3MRBoM8)R7@&3;`s@m@_7TM5CJn zjG!7`b&c#|oE^-`n(#Bl;CYp(w26S&B*S}azp4bk?q#rZ5tV{juXo8LJsDE%q6u59@`EPK`ptwJ5x<-8ti|spj7rwKM}a0B)ED!c2~Qqke_yko zBXb2bVNL(QU*}JTfgZGBiRDoGzv^}@zwf`s3E*pgwc?MCU z;@pzD!ivU|Rn1FbHI$}bVp6oU_AZTy{ZZC_^z0?1Qcb^@Tc(`p|&0sTFnmh+8&`}GBDeG( zTX}7BE41>~YkeKPu!D8|=A9A9VSrt%@kdX_r)J=^*yG=gewobhzr9S$Km0SE0RG`m z8bd7;&WWyaaq*QdGGPcR_|}q(CQah_NxlOb9x5tC2(wR z_nU4xuW*;$^L$`|2$KQ;T#k~MvgYNT26vOT3S_A&A`x*U}?|p3a%sJKd80-}lWt|R+1X3hwU?>qt~%DU+#1?wO&$K1 zt_57~4rBH1Z@(UskOWt4CT12u>88wMIfbXn^2-~bfKzGJnI#RUikiB!wY6s(n$Mj( zSAXGBb93{Bt8EF_29tXRv##IH9~>^ZGgf~0e%0{!<@T=gW0MyjPFUccU`(*a^^OvKO(+{Sfjl7&2pL+v` z=N`|#g7QuKQFH?`7@gG|MfFL>QWy~deS3yaW-7VeTIP+ zWQYq|=PMm)CnpPQ29kK}PFcib)BWH{I@&mMQDc$_YU3<~%Mey(YT6S2Ms$ftn^a zMVB!G^&x zp{(nu>b4u=pC%JTaln#1R1_A^4yvVV$t7kCw7lOBD)30-MvH2#iFPT2yvUc=Z1rlN zB*#hG^!g4WuU`G}!&R5mB?|aSbTkK;GZFluJ$zDVvtb5`K`BA71e^hhj@Yg{!{kH& zDg)y$4$zF9L?tZBIP&8|VMH~L89)X!cF}q64-}=$?G0hkHvzJ_vvQ3cgUjH}Orem7 zZieR(?dnzSqCDOF#zZTX&0WG&Tk<1Y-fAA7Y=2>L{IR+Ht4vWF`%M`+jx}|$sINtz z3WZkd2FKglZ4faQz}=sVFL<3M-H8#RWMf5mX|(uQLsOM!C7F-NCaBRKG<^>kprcB& zMwR?B_+8+hXs!T#W_fjTUKfW*hYDL9QLtabtEzdAS%UDTvLgw?O;1!_)OHB^zo_e0 zsCsd(f6en3=Lgiqmb!$l@M@`jfMpE_|4!pu4#LAgiuCuVBn3|ed z+gMs!T2t*H&{C;X2(<2AJ`idB1A}*kgoT8JE@3SQjR$*@z`k@4oe^~aQq+!t*c^~l z01g*JxP`C^p_CqXXbDFlhC&1_DJ?C6YpW}(VA2M$69Okh&Engm5FjBgw)b5B4HpM* zFM{IeA}B&Qyz}DK*iRsY5IFJl`5!3wbYT$%mo+#4uYu;@^A{m}?q~*{W(n*QGH(Og=&aRf4*1xNwLShtLYO$l9Upl$12iZ5jcLHb%Cbu$r%X9n!m9fHU6( zL8j9YSfEy3dx2uc5H~pJh{%v5z`>CXYpRKWjOKMBeH`BGeflU)P_z+Gi?;+wr=iM* z;`1m>g}Rg4z+N;ttHG(ol`wy7l8qqJGJDyhGa;LMr;a*i&tbCxC&%KWQL5h2K)7bDb!#O549mKiW% zel7eahX*|JYkh}l_q*RbwD!#yuGxMKFL>qbtrg~;C5C(o<{3&t+~U2T-@SO;cXA`7 zl@A%ddH(R`)pZYk0IU++rYGpjbp5SMDY1wkvrq_A1%53CV80=VnB*dYtklM88E|PC ziOb4Kuhy2=GgMx+TFU_9h7m%?6d0IF>XHfO8-b}kuyOz!HUm3%cE@eN(F3@612;dy zCK{jxf$gEdCkpsQ$x$rUnOZ<(F|l3$7ff+;bKbVy-OJlyN0^g;#G<%HNGJ%RgV0zI zkp%Xpfbb(=cP`j}#MqAx=tlt~55yONgmREn0aDL{v}TZb1!TAJ74}dWC%hZS1MBVv zH;jf~d=z>45e(ZP+(4{3T~YA|%49b5=3Ti}%jzz>FVQxePJ?p2+e0r-BG_6@S0DbTR4TQ?YF}W0KXK zOUSvFb;X@2!Yi#Ww3$t0E14!FE(Kr;Nv0Rxc&B7#kfRqSjL(-{KcO4;eh%S<=TUaA zHx)seTBM({JgTy#SF0ku(2kAk-I2!$X^=7wm#w{rL)EU#(gr zd0^KCjr-^oy3LcJUt6`M_rBRRQy==x{grEU^8Cfbl5F7w9N%Xem^qd6P3 zQ5*6Pp-^XyGq zMl@p4(vfV{JRbZ!=7j3x0ff`G_)VMbbi<#&Y|_0?j78-(`cZ_R+N(};JX~vb+(x4( z%VE7iH)!QQQ$v4M??DQob7{T2eQTq{etuqSd5kd%?^Mfnre5B$mBmfTD&e)+MwT<< z7ms*RcWtA_5#*_wn8|p8iq?F`HL=}OR4TiCTs)tmX^#r9Lr$0q5-xl-Bmbp#HU|Si zahORj27>JD>`>HPMphPzn(ONuEH3S!FreP|* z$=Su#&28H@8qB8QW*6U}h_LYRh<*FvGH?(c2lk~cB5=$JaHwJtb&s`2#~+4B8y_DJ zkv2Uu>&THKi)nGyVpO-76gMTEdI-g$!{naWbi{y*-6njB3k5 zoU%A1_(vY?P$~Yg2yXe-*xrl&4aSr4t>;hQJV|C`3R~Bg51z8zp|qv9zT(zt{bK6^ z>xRlZQa@q5q3YgQTGIv)EK@xqwHk>Q0gqqYlU%8S4k;=+G*)Be$Bz$Y-Q1{g<7LT;qBVjVQ-;5vw#6_Aj4UQ;N5=a<#Ic#RmAqJ1CXJ6rE znM7An1R6bZ-2m@NsNBcSjqE^pih*eS4v8sB>SUjdCGEPn8IjLe?!_@Os%1`0aLvNb zGGg4N_aroN-|O{{jX#VF_U_;=_Wb<$0hwypTsNk_hp0vYz<<(_tI-sIC*jJ%RF zEl9^5fFNL-GZEV+y~7yGYdA-apY`Y#BPs;YirH6r(PCm{-aJ8ZYakJ5ZnZ|=QxU&X z-G+fW3?XIU&bpsfJcvHBva;&x>V}4f6bc0@+t}ONySce}dU`@+fpt2FDNDcsQKO)s z0B(y~0uG26aA6c&gaDCZXlMw+#B%uc|6&Boula8}0f;^Zzc=T889>aptn)Nu`?;~V z?vzEk6y^6S9^BabQ)2+4PrlX9AaaWWAWA>&vGbjFI^89D+qhuyKH97NY{kg_jF&m_X36oG=)gQ=wR>EbW{xBv7B{Kr_a zm~j3aR{klq_*Yor-Hrw_&8CUcFxNXN#o3F`+>Fpst)I3)mw zFp~vS0WsImVLF*|n@t>ebuW&tWb+~cjm0!Uu-WAz2WYGq>k~pqye?h<;hrVVLGA=3 zRpT-VK}XA;Rs^yvQ93+w0Kp)m^&CWZku{8QH;)+*>6LHV82u7aF|RZx=dHPjTwX+_ z+|@`9tP;s7w}>&^F2=8`(Z9MK2~Y^q52K^CNGzU9oVsCD{t%AyoI^Ql0ugdtOe+z; zt#WeT0Q1*CA{S1pDnp*ne=3kz28Vz8E-t^|Pj&+MH~&!}@e>>*Z2>8!D_$5GE*w0$ zox;whPYtH=79}7hRx6d$i%>YO6_`+6W)X^xK=BI$nn$b^ml)AOSjS+3P9lY$;?C@iDeWD17Z2Z^X(8)^mNJe^XhS2-1;P9B2&&h zmlLlrQyUqKLmFvr)ulC?^ma)o%-!imv@tl4Kd|QXRuJDJqNx>W9TAJfg{|{(0W=bQ zv^uP7)6XEGNw#SU#t0#70>XxgICpJe{c9iS zE>5EN2vQE=B#3y^fx)6)ESfKzSlxs|YHKC%}q!4tBtSX6i4PoM#gz=?2pqJPwIVY7MV1 zLc-dmMBo7VQfb13tP~dg)AE0ANZt!~qw+2?|Nn^hWn^Sv_flJ18@3QkOiXNTZ5T|pxZb4hy4S)A|&7y_rXtifP@4g z!N~GC<|Gy+sijt%(Q0yt3vWOgo>+AI>|C%VP(;IV5fpCM5B$~=5Z09jusL8TTn^nn zofD^ypGy4c_W7tUgXun4U_@wJV6kHQa0FUS+5{rz5VU-8R@D%~7$XTSKar+^MN46l z`Cl+7_Zbp0qybV!%{W?w%h5%Z8jCvRr>7Q~ag2$@0xZ&!^Yg?A2ChjZ*XBKG1QSYZ6+`8Atwi0i*T1ZY%RiV${rgxhEVNbgE25LaH+u-Z#(V#*oln3qosV)b5kIBi&5IBm9iXdv7J9`!a2V^NMH6EAv2}_N~<(a`h zk#YRHKMMW}@cvul=W@uhMA(@lftYS|q>D5?6)8=j2m8`vIQT_PwQ^YJy z#)#D}cv3L29G#5XP6ne$vVDxFw>y;)5r?kZYtv1VHi;n<)Yw{TGZ>_eg$dr`z%|1x zt^>KEo38e_V_WPhYtvw9s)h$)1*xRFN;lT=l7?Dp^S%KyG%Wv595|DK2JFIerp=u6 zPzoQroL6@SoE74&=ZR9Ee`J;_yt3HlcreA|m*QVEhy?sV@F$gtfWg42AP5F>;^NZM za3n}oQ&SUSz>+5L7H;k(4A{DH;}Q()a&w0m;OFNT9v%)O1jvRe_=y2aD#1`>a!Dl^ ziUSY+)Cc|!z!DJwg2Bm?CyR@V|A->sfZ-ps&?PWfZZ7`2Ti~DT^T7t;c6@4)Gz!ll zhE;J_%7{HgBpQX&EbR~-DFl))l>cRR64`-!cX!x#{i1(eX1#;4$i4sB@oy4z1&0nCgOxXY$Pli~~k(8pOPn-+ZM6&^TYaq`Z|6O+&U@0G_vE^URl0^Xt_^E;kLY)gnDmZW z_l-GRzrS_hq36IupP`AJwbKSa|WwaenINlG5#ym-CO`e|-A!^NUYk-o2QB zq6{z*S@`mGdB*pDw$13k-yCt;4TnIH~f1Fkqi>eCj3?RV=N=)=uf&KU#aym zb^rg>-g!qgwe5NQq>w^06d{CSK)UoUpauk_8$l&vArT~i3K5YmB%y`gt4J>a1(6zx z0!j&jiin7)Gy#DtAnK(n!+me&tvh$k{5Su+HTTc+-#Ndv_C9NW_O~p4aKBmFnV}lM z8J|5QXIgMPb*)R}w8G0G=oQTVji(i7p!Uh9A607ocDDL>-O(M+jPkd&B=|EId=kj9 z@EWq^cB|%cN3+k>v3Q2=%D^M@t*v->hcY@n?5adUj{n@{hIk(PIHhd$+0;a`)MM_O znq+9+;gi3($7;ZS18WVSjdky`tG@QM7rp)Dmf*< z@l9Hc!Nq#}1Y(>lUt%;OemWxsGuRX!d)%?RG*e{^?P`70xDcA2bp&e?beuc=;~l(` zIw(Pa`&Aylc+R;`)>tW`wBX6%!Os?FhkoQ|7@h;dc?1i>Y1~$*z?8fwiFx^w6gv+E zaMsW~*#=YJTj=ali%q+6C<~JYwP5X1Q}Xa#HH%R{8?aN{1~Q9eqjQ)pdk+3uzmf!v zHo!F3f%p8E1h!)T{US1^sfeMaP+$@iHSK#4oNhdo0p^=$AF`bCeUGh17^0^57q=|M zjXR4n3&V~4QBKKAAmm)W{zp;L<892s1LpU@71U`V`>~2Qj z5D_qe3A8+Tdcohr=9{;l6jlE@wy;v;6rR>H-z+9Mpx$SFv!OW|VHzvZhW#;EX*YNY zE_tX86f39P0YLC#e7gA5yKfgCEyq_G z^Et6FMZ}xG=JhH2UX6w{0t`nobfQC#U^r)bj;SkZ(Pib<$ z7g5CO$sn-uAa-ls?%on*oYRlD`?H#9-@^qOWGvr4`gNmTf6SW`ss44v%Z<)0nGFG+ z0`*avHl@ZlSSwnmZnyoWCeyytPG7ebm~Bv1{9=3My?$y%lVjecDmR|cV(|2l8*T|7 zdOQhRHb#jl$%|vZ4CY7rXH-x~Y3y+@f<68WT`Ith1G!IdNqqOcjDymL% z5uQGaS3GZqF?QM&DkwR~p+H){lV7n_MAdq;z)%!8hqOT#3PWp5(p$wr#;8@TF2Ob-xh}p}_#%4S||=%kY7&$0eaIf2ALOd@o_`-ni|~di9}8 zNP==Wa#(BRI1E8T)H{x#Y}cN)i&fYf-H?{nMOs+CxR;`Jj(Q+=wkPb$Y66$&mGBh2 zWuxS&B>iMsB)Y~}+0#q5$~Z@fEGY0bUQM>yq(dd5sRz+h0=6}=i~TmLsvWZ;Ei7MD zp@wU;)3+xbyk`NH{z|9ZD###M&R7tD2%ccdEoAQWA$Mcjn~q7hF3_-wJob{V#x#2Q z=@{?@k=^38;f_d+K3Tec5{M$j?-#xxEK7dU$}M{%Ien327<>36>;60v;IKLtopdTI z7>5)>RG6Qz97=i&6qg&$3th3JT}MtacxnLb5;HYpgj^;Gks+V~sMP6#;tNym{8H&B zd(AcD%w^Ib$;_eid2`tT$#T9uLT4(6OoQMpm1icT-b`L=2zHW@<>GrL%Jlf%@7$~h z;Q(tSI^kC774112vT4U3Fh`_y_J%B1x z&IfVZzLI*!zI;X{qg#p0DUe!6>8Z;EDPQR_Mm^*SS4!r)?jZ?D&!2Hot5QbT5rYKY z?vA`ve0Z0A?PtpS*N-!r8kD0cQC1(OG3zY0O|^Gs|A#sK_2$9&YM*kekBg4$Eu+t? zeVh6}E(fl+PVzkP@3k8Lmb2bAZ}TAVZ7ZK3YyHvJ_y@tCttPg{)*o*?e-N_XKk;j8 zy&d@FWe2yO1dDETAZ%;s!UK~qgN;s9LQS}w^%Up%jVI_AHIcdlQ@lYNPqDlY87Hi# z`R{CW$=g1RaTu5uYTf8oOL!PZw*G{9ztN-j;$ec{z$c0Ajb0pYZBmr=jFjjm+uXJ` zC39d#)?l*_pHQ1tZau4be)AdOMQujYz^qEpW&eo0f^B)$AQqJT7^8ylCm?nSB`l%(b*_4 z3a8&6!RyS6BQ98--$WSVJW36g+!d|#<8ozhRg?yM@RSC=IX$jv=frbWpw$mUBrb;)0@iN`sPz1I0wQ+U_oA~~q< z>0_O$_PaAAzn~8@M{Da|FU{Pl+a7%s;@A2~*~|a!cHi>jrj~^&FOTo76Jx)0JEC(} zXk5*cFu2AOf#pvTnz_Bap{#_1DmTRJ+op9M>-D(bUybi)eKPX}3+7_KIfk{d&34`P z_1UOUBm#^y8k@o%yQg>b!>%>x0Rv-$9g^9E5q&m*q+0D9sJ zn#X<&g?;!@e*EIX5wiE2s_O5|w*iZ|as9VZN8M_6S&JZ4OE~)H@Ap-k7eH#pWA=j( zfx){=UOKIb@e+jhBPr-@_zi2 zk?oPMR!TcliL8yDed^y*cc*4G+n>G&{S{fP`jgwfeM|W9(KUrH(ET4mwx!p$cM+Uw zR8SVMqqNq^YfYqnYi-{tG;5Czpn&;MlRqJ-j%|qQF8`-vyIWDA1{5gnZRo+d5HO00 zAcQCkN*oysfQ^!n8=(T`V7?&_z75hYoC;9`W9))N=1E7Wp#pBerA#+THt7ToEUE`^ zpaSp!UBQhcM+t>ez?+{#po89_YgA2h(h*#UxSQL`XJ4}p2(|2XpC42TAHspBE=`3L zM-gqYTp9=?u}Mbj;aktqz4Z9&8Z z|7bCt$XSQTTqen#5ONJ2BLa)^HjgS}ko*WCfvgzexu_C!bj>I+e4ZXjh!x0S=&~6t zSwtg3NYX~EfLSzz2xOSY@nl4MBO;$|5cBkaf{nO+Ix$!MBZirhOjbl?Ry@y045WrJ zK1!@bFg~$~O$4Bs<$NQO_OmB8_Or8J2HBF~+Nl>F1b3@vd-gEmaI#@Pd*aT|#~DV_ zVZ!mRH=F?^N5Y!th&*@{?YzuR>M-+suNP&~m~Wq+N?Zyo8>Hk z6mlkVtwS)^ah zYlQe`CD~+nJuCC^KqR*bnSC%zbDx7MvEv__d5yTHUY$#ROz?crk(3^c-?x@} zX)aT#F^gXVY|o0z(aUmdq#P{(kL$XmRY*!rroemB^7S$_r zYVs{+p-@!V;dicqe!x^VX;vg+R+o5!8ud#)pnEh=*|z|J$%p9BYb)|NFp_eVLSENw zrb7PaLIl#1c$5M-&lPgG`Wp~wLUSSVfkb|cV-8QnrLj+R--R}{JI0BoNt_YExfcPzh-DLZ8ej?pE0kI_XDX$m+nHGs*; zVa8N41J=iw30ur0Oht-Exw3qjiX(}p$joV}5ZnmS;bi7+g*GXK7dlp!1y(Y1DoZh? z=LsYyj3jgvQmcQj-tk_eK3!CgwoJYwS5Rh=UQx)I_Nax~<#?YOaF3mH|5?lZfwBAb zV-=?Y_ng(`r{;@;w?c4^OirC*glpNUM(PFqQiHK#V&%Q_=3sk_nIfeG-ctpetD0yj z$8mBfJ}a`V40G`y8hovQ%~eBT4^|h;lF9y}i^b5S2gn|X?AQYneIl@3^&Mjt=m$l$ zTn=H^IK-UZw|xa-StU3J*?;HsFUwL%%X|@!e6_}c%6B!G+K0qQ%AXw*)V62QuOmfFo8YKS5R~)2@yt712lWoXsYEF7dtkHIWG&AWrGhTR{S%%gM)+rRqeW`W!Qt0dm^a4>&v}V z!he#<$w%S;8+iN|X8adg{F^KOzgZ^#ejmCAIgkGpazeD-sQ(E$F=@<)fA}QDy}AEL zMvOgpa?ew(G2NA+=1jL%s4KH!Xn8GuXkL|hnQv%h@)cR{*3XR+5=5(Y&|a0x>;>r% zsTF6+&;=gP8B;Vc*a41U1xh|0sS|t}BQCmT46k$hq*1R(RlZn;g1XLQo4lU1cz`s~ zY#MXospN3AcufHo_L#v(MsSS+3_7;fZ23KnHVxuXIS||?vIMDtN-!EMJJdP{f~<}` zuSrv%xmV5Oy=TBETA8RN`Qkh3feW;=s)o?c!mlg2ofdTb5i0Id7^M0{Vo;$DfA^5-#)D9W&6h^x;rM;wy+$y!OHx_Ru~pWjZ?^l_%NKB*(Gu=aBJSdW*`|#ysZ$`! zB=~+T6~`eV$WaQm%Q%~5Bq2S?EJm8N*rzXXFz0dco{MfA2JU?_q2g%@No8eHyI5N0 zrb3NeU?xWJw=(Vch05E_LiP8GH6Dr-~_qOj{S~}TUlI~I+ z3C+*-HeIQW8yx6g5UqT!8}wzc!%!~#yD?X+m`^X-!g}=;C(rG{9&6ntO(SSH;GK9% zb*3IC&i+gu;l8eng1w_D4-Ly70M@|5U0+g6MdXtj&RpwN(lJ77_5ASgY1)m~7=vF_ z8+~ORe?{0iB#Po^#HWSZI1}mA-I$9p>ga%Ek*hc7a=ofMJ{Lr(Y|WQsdTuQ+Gk=|% z@$ozTo?O$bvi+t0t!L{}ltcL|2#?S5_DU8RyYsb6*lTB%E%#vO8ynuEYY$fgHeO$c z-F`cD>(J5LMp-LA4X1xsR>7~2AIjR85K3??X}4 zV;To8i-x|-Rc+)1^C6_vUUq@bhCGa|D!GgU{-Jj^+1r4XkRU-2-yi03+kOv;Y7A literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/images/tour/tour-dnd.gif b/zbf-admin/src/main/resources/static/designer/images/tour/tour-dnd.gif new file mode 100644 index 0000000000000000000000000000000000000000..24fb73bf11bd5c59a604409f20db749d38bd3610 GIT binary patch literal 81854 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 Ofd9Li^>HFWoBj>oAb literal 0 HcmV?d00001 diff --git a/zbf-admin/src/main/resources/static/designer/index.html b/zbf-admin/src/main/resources/static/designer/index.html new file mode 100644 index 0000000..035e241 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/index.html @@ -0,0 +1,277 @@ + + + + + + + + + + Flowable Modeler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ * + * ### CSS Staggering Animations + * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a + * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be + * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for + * the animation. The style property expected within the stagger class can either be a **transition-delay** or an + * **animation-delay** property (or both if your animation contains both transitions and keyframe animations). + * + * ```css + * .my-animation.ng-enter { + * /* standard transition code */ + * -webkit-transition: 1s linear all; + * transition: 1s linear all; + * opacity:0; + * } + * .my-animation.ng-enter-stagger { + * /* this will have a 100ms delay between each successive leave animation */ + * -webkit-transition-delay: 0.1s; + * transition-delay: 0.1s; + * + * /* in case the stagger doesn't work then these two values + * must be set to 0 to avoid an accidental CSS inheritance */ + * -webkit-transition-duration: 0s; + * transition-duration: 0s; + * } + * .my-animation.ng-enter.ng-enter-active { + * /* standard transition styles */ + * opacity:1; + * } + * ``` + * + * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations + * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this + * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation + * will also be reset if more than 10ms has passed after the last animation has been fired. + * + * The following code will issue the **ng-leave-stagger** event on the element provided: + * + * ```js + * var kids = parent.children(); + * + * $animate.leave(kids[0]); //stagger index=0 + * $animate.leave(kids[1]); //stagger index=1 + * $animate.leave(kids[2]); //stagger index=2 + * $animate.leave(kids[3]); //stagger index=3 + * $animate.leave(kids[4]); //stagger index=4 + * + * $timeout(function() { + * //stagger has reset itself + * $animate.leave(kids[5]); //stagger index=0 + * $animate.leave(kids[6]); //stagger index=1 + * }, 100, false); + * ``` + * + * Stagger animations are currently only supported within CSS-defined animations. + * + * ## JavaScript-defined Animations + * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not + * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module. + * + * ```js + * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application. + * var ngModule = angular.module('YourApp', ['ngAnimate']); + * ngModule.animation('.my-crazy-animation', function() { + * return { + * enter: function(element, done) { + * //run the animation here and call done when the animation is complete + * return function(cancelled) { + * //this (optional) function will be called when the animation + * //completes or when the animation is cancelled (the cancelled + * //flag will be set to true if cancelled). + * }; + * }, + * leave: function(element, done) { }, + * move: function(element, done) { }, + * + * //animation that can be triggered before the class is added + * beforeAddClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is added + * addClass: function(element, className, done) { }, + * + * //animation that can be triggered before the class is removed + * beforeRemoveClass: function(element, className, done) { }, + * + * //animation that can be triggered after the class is removed + * removeClass: function(element, className, done) { } + * }; + * }); + * ``` + * + * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run + * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits + * the element's CSS class attribute value and then run the matching animation event function (if found). + * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will + * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported). + * + * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned. + * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run, + * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation + * or transition code that is defined via a stylesheet). + * + * + * ### Applying Directive-specific Styles to an Animation + * In some cases a directive or service may want to provide `$animate` with extra details that the animation will + * include into its animation. Let's say for example we wanted to render an animation that animates an element + * towards the mouse coordinates as to where the user clicked last. By collecting the X/Y coordinates of the click + * (via the event parameter) we can set the `top` and `left` styles into an object and pass that into our function + * call to `$animate.addClass`. + * + * ```js + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { + * to: { + * left : e.client.x + 'px', + * top : e.client.y + 'px' + * } + * }): + * }); + * ``` + * + * Now when the animation runs, and a transition or keyframe animation is picked up, then the animation itself will + * also include and transition the styling of the `left` and `top` properties into its running animation. If we want + * to provide some starting animation values then we can do so by placing the starting animations styles into an object + * called `from` in the same object as the `to` animations. + * + * ```js + * canvas.on('click', function(e) { + * $animate.addClass(element, 'on', { + * from: { + * position: 'absolute', + * left: '0px', + * top: '0px' + * }, + * to: { + * left : e.client.x + 'px', + * top : e.client.y + 'px' + * } + * }): + * }); + * ``` + * + * Once the animation is complete or cancelled then the union of both the before and after styles are applied to the + * element. If `ngAnimate` is not present then the styles will be applied immediately. + * + */ + +angular.module('ngAnimate', ['ng']) + + /** + * @ngdoc provider + * @name $animateProvider + * @description + * + * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module. + * When an animation is triggered, the $animate service will query the $animate service to find any animations that match + * the provided name value. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * + */ + .directive('ngAnimateChildren', function() { + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + return function(scope, element, attrs) { + var val = attrs.ngAnimateChildren; + if (angular.isString(val) && val.length === 0) { //empty attribute + element.data(NG_ANIMATE_CHILDREN, true); + } else { + scope.$watch(val, function(value) { + element.data(NG_ANIMATE_CHILDREN, !!value); + }); + } + }; + }) + + //this private service is only used within CSS-enabled animations + //IE8 + IE9 do not support rAF natively, but that is fine since they + //also don't support transitions and keyframes which means that the code + //below will never be used by the two browsers. + .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) { + var bod = $document[0].body; + return function(fn) { + //the returned function acts as the cancellation function + return $$rAF(function() { + //the line below will force the browser to perform a repaint + //so that all the animated elements within the animation frame + //will be properly updated and drawn on screen. This is + //required to perform multi-class CSS based animations with + //Firefox. DO NOT REMOVE THIS LINE. + var a = bod.offsetWidth + 1; + fn(); + }); + }; + }]) + + .config(['$provide', '$animateProvider', function($provide, $animateProvider) { + var noop = angular.noop; + var forEach = angular.forEach; + var selectors = $animateProvider.$$selectors; + var isArray = angular.isArray; + var isString = angular.isString; + var isObject = angular.isObject; + + var ELEMENT_NODE = 1; + var NG_ANIMATE_STATE = '$$ngAnimateState'; + var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren'; + var NG_ANIMATE_CLASS_NAME = 'ng-animate'; + var rootAnimateState = {running: true}; + + function extractElementNode(element) { + for (var i = 0; i < element.length; i++) { + var elm = element[i]; + if (elm.nodeType == ELEMENT_NODE) { + return elm; + } + } + } + + function prepareElement(element) { + return element && angular.element(element); + } + + function stripCommentsFromElement(element) { + return angular.element(extractElementNode(element)); + } + + function isMatchingElement(elm1, elm2) { + return extractElementNode(elm1) == extractElementNode(elm2); + } + var $$jqLite; + $provide.decorator('$animate', + ['$delegate', '$$q', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document', '$templateRequest', '$$jqLite', + function($delegate, $$q, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document, $templateRequest, $$$jqLite) { + + $$jqLite = $$$jqLite; + $rootElement.data(NG_ANIMATE_STATE, rootAnimateState); + + // Wait until all directive and route-related templates are downloaded and + // compiled. The $templateRequest.totalPendingRequests variable keeps track of + // all of the remote templates being currently downloaded. If there are no + // templates currently downloading then the watcher will still fire anyway. + var deregisterWatch = $rootScope.$watch( + function() { return $templateRequest.totalPendingRequests; }, + function(val, oldVal) { + if (val !== 0) return; + deregisterWatch(); + + // Now that all templates have been downloaded, $animate will wait until + // the post digest queue is empty before enabling animations. By having two + // calls to $postDigest calls we can ensure that the flag is enabled at the + // very end of the post digest queue. Since all of the animations in $animate + // use $postDigest, it's important that the code below executes at the end. + // This basically means that the page is fully downloaded and compiled before + // any animations are triggered. + $rootScope.$$postDigest(function() { + $rootScope.$$postDigest(function() { + rootAnimateState.running = false; + }); + }); + } + ); + + var globalAnimationCounter = 0; + var classNameFilter = $animateProvider.classNameFilter(); + var isAnimatableClassName = !classNameFilter + ? function() { return true; } + : function(className) { + return classNameFilter.test(className); + }; + + function classBasedAnimationsBlocked(element, setter) { + var data = element.data(NG_ANIMATE_STATE) || {}; + if (setter) { + data.running = true; + data.structural = true; + element.data(NG_ANIMATE_STATE, data); + } + return data.disabled || (data.running && data.structural); + } + + function runAnimationPostDigest(fn) { + var cancelFn, defer = $$q.defer(); + defer.promise.$$cancelFn = function() { + cancelFn && cancelFn(); + }; + $rootScope.$$postDigest(function() { + cancelFn = fn(function() { + defer.resolve(); + }); + }); + return defer.promise; + } + + function parseAnimateOptions(options) { + // some plugin code may still be passing in the callback + // function as the last param for the $animate methods so + // it's best to only allow string or array values for now + if (isObject(options)) { + if (options.tempClasses && isString(options.tempClasses)) { + options.tempClasses = options.tempClasses.split(/\s+/); + } + return options; + } + } + + function resolveElementClasses(element, cache, runningAnimations) { + runningAnimations = runningAnimations || {}; + + var lookup = {}; + forEach(runningAnimations, function(data, selector) { + forEach(selector.split(' '), function(s) { + lookup[s]=data; + }); + }); + + var hasClasses = Object.create(null); + forEach((element.attr('class') || '').split(/\s+/), function(className) { + hasClasses[className] = true; + }); + + var toAdd = [], toRemove = []; + forEach((cache && cache.classes) || [], function(status, className) { + var hasClass = hasClasses[className]; + var matchingAnimation = lookup[className] || {}; + + // When addClass and removeClass is called then $animate will check to + // see if addClass and removeClass cancel each other out. When there are + // more calls to removeClass than addClass then the count falls below 0 + // and then the removeClass animation will be allowed. Otherwise if the + // count is above 0 then that means an addClass animation will commence. + // Once an animation is allowed then the code will also check to see if + // there exists any on-going animation that is already adding or remvoing + // the matching CSS class. + if (status === false) { + //does it have the class or will it have the class + if (hasClass || matchingAnimation.event == 'addClass') { + toRemove.push(className); + } + } else if (status === true) { + //is the class missing or will it be removed? + if (!hasClass || matchingAnimation.event == 'removeClass') { + toAdd.push(className); + } + } + }); + + return (toAdd.length + toRemove.length) > 0 && [toAdd.join(' '), toRemove.join(' ')]; + } + + function lookup(name) { + if (name) { + var matches = [], + flagMap = {}, + classes = name.substr(1).split('.'); + + //the empty string value is the default animation + //operation which performs CSS transition and keyframe + //animations sniffing. This is always included for each + //element animation procedure if the browser supports + //transitions and/or keyframe animations. The default + //animation is added to the top of the list to prevent + //any previous animations from affecting the element styling + //prior to the element being animated. + if ($sniffer.transitions || $sniffer.animations) { + matches.push($injector.get(selectors[''])); + } + + for (var i=0; i < classes.length; i++) { + var klass = classes[i], + selectorFactoryName = selectors[klass]; + if (selectorFactoryName && !flagMap[klass]) { + matches.push($injector.get(selectorFactoryName)); + flagMap[klass] = true; + } + } + return matches; + } + } + + function animationRunner(element, animationEvent, className, options) { + //transcluded directives may sometimes fire an animation using only comment nodes + //best to catch this early on to prevent any animation operations from occurring + var node = element[0]; + if (!node) { + return; + } + + if (options) { + options.to = options.to || {}; + options.from = options.from || {}; + } + + var classNameAdd; + var classNameRemove; + if (isArray(className)) { + classNameAdd = className[0]; + classNameRemove = className[1]; + if (!classNameAdd) { + className = classNameRemove; + animationEvent = 'removeClass'; + } else if (!classNameRemove) { + className = classNameAdd; + animationEvent = 'addClass'; + } else { + className = classNameAdd + ' ' + classNameRemove; + } + } + + var isSetClassOperation = animationEvent == 'setClass'; + var isClassBased = isSetClassOperation + || animationEvent == 'addClass' + || animationEvent == 'removeClass' + || animationEvent == 'animate'; + + var currentClassName = element.attr('class'); + var classes = currentClassName + ' ' + className; + if (!isAnimatableClassName(classes)) { + return; + } + + var beforeComplete = noop, + beforeCancel = [], + before = [], + afterComplete = noop, + afterCancel = [], + after = []; + + var animationLookup = (' ' + classes).replace(/\s+/g,'.'); + forEach(lookup(animationLookup), function(animationFactory) { + var created = registerAnimation(animationFactory, animationEvent); + if (!created && isSetClassOperation) { + registerAnimation(animationFactory, 'addClass'); + registerAnimation(animationFactory, 'removeClass'); + } + }); + + function registerAnimation(animationFactory, event) { + var afterFn = animationFactory[event]; + var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)]; + if (afterFn || beforeFn) { + if (event == 'leave') { + beforeFn = afterFn; + //when set as null then animation knows to skip this phase + afterFn = null; + } + after.push({ + event: event, fn: afterFn + }); + before.push({ + event: event, fn: beforeFn + }); + return true; + } + } + + function run(fns, cancellations, allCompleteFn) { + var animations = []; + forEach(fns, function(animation) { + animation.fn && animations.push(animation); + }); + + var count = 0; + function afterAnimationComplete(index) { + if (cancellations) { + (cancellations[index] || noop)(); + if (++count < animations.length) return; + cancellations = null; + } + allCompleteFn(); + } + + //The code below adds directly to the array in order to work with + //both sync and async animations. Sync animations are when the done() + //operation is called right away. DO NOT REFACTOR! + forEach(animations, function(animation, index) { + var progress = function() { + afterAnimationComplete(index); + }; + switch (animation.event) { + case 'setClass': + cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress, options)); + break; + case 'animate': + cancellations.push(animation.fn(element, className, options.from, options.to, progress)); + break; + case 'addClass': + cancellations.push(animation.fn(element, classNameAdd || className, progress, options)); + break; + case 'removeClass': + cancellations.push(animation.fn(element, classNameRemove || className, progress, options)); + break; + default: + cancellations.push(animation.fn(element, progress, options)); + break; + } + }); + + if (cancellations && cancellations.length === 0) { + allCompleteFn(); + } + } + + return { + node: node, + event: animationEvent, + className: className, + isClassBased: isClassBased, + isSetClassOperation: isSetClassOperation, + applyStyles: function() { + if (options) { + element.css(angular.extend(options.from || {}, options.to || {})); + } + }, + before: function(allCompleteFn) { + beforeComplete = allCompleteFn; + run(before, beforeCancel, function() { + beforeComplete = noop; + allCompleteFn(); + }); + }, + after: function(allCompleteFn) { + afterComplete = allCompleteFn; + run(after, afterCancel, function() { + afterComplete = noop; + allCompleteFn(); + }); + }, + cancel: function() { + if (beforeCancel) { + forEach(beforeCancel, function(cancelFn) { + (cancelFn || noop)(true); + }); + beforeComplete(true); + } + if (afterCancel) { + forEach(afterCancel, function(cancelFn) { + (cancelFn || noop)(true); + }); + afterComplete(true); + } + } + }; + } + + /** + * @ngdoc service + * @name $animate + * @kind object + * + * @description + * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations. + * When any of these operations are run, the $animate service + * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object) + * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run. + * + * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives + * will work out of the box without any extra configuration. + * + * Requires the {@link ngAnimate `ngAnimate`} module to be installed. + * + * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application. + * ## Callback Promises + * With AngularJS 1.3, each of the animation methods, on the `$animate` service, return a promise when called. The + * promise itself is then resolved once the animation has completed itself, has been cancelled or has been + * skipped due to animations being disabled. (Note that even if the animation is cancelled it will still + * call the resolve function of the animation.) + * + * ```js + * $animate.enter(element, container).then(function() { + * //...this is called once the animation is complete... + * }); + * ``` + * + * Also note that, due to the nature of the callback promise, if any Angular-specific code (like changing the scope, + * location of the page, etc...) is executed within the callback promise then be sure to wrap the code using + * `$scope.$apply(...)`; + * + * ```js + * $animate.leave(element).then(function() { + * $scope.$apply(function() { + * $location.path('/new-page'); + * }); + * }); + * ``` + * + * An animation can also be cancelled by calling the `$animate.cancel(promise)` method with the provided + * promise that was returned when the animation was started. + * + * ```js + * var promise = $animate.addClass(element, 'super-long-animation'); + * promise.then(function() { + * //this will still be called even if cancelled + * }); + * + * element.on('click', function() { + * //tooo lazy to wait for the animation to end + * $animate.cancel(promise); + * }); + * ``` + * + * (Keep in mind that the promise cancellation is unique to `$animate` since promises in + * general cannot be cancelled.) + * + */ + return { + /** + * @ngdoc method + * @name $animate#animate + * @kind function + * + * @description + * Performs an inline animation on the element which applies the provided `to` and `from` CSS styles to the element. + * If any detected CSS transition, keyframe or JavaScript matches the provided `className` value then the animation + * will take on the provided styles. For example, if a transition animation is set for the given className then the + * provided `from` and `to` styles will be applied alongside the given transition. If a JavaScript animation is + * detected then the provided styles will be given in as function paramters. + * + * ```js + * ngModule.animation('.my-inline-animation', function() { + * return { + * animate : function(element, className, from, to, done) { + * //styles + * } + * } + * }); + * ``` + * + * Below is a breakdown of each step that occurs during the `animate` animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| + * | 1. `$animate.animate(...)` is called | `class="my-animation"` | + * | 2. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 3. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 4. the `className` class value is added to the element | `class="my-animation ng-animate className"` | + * | 5. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate className"` | + * | 6. `$animate` blocks all CSS transitions on the element to ensure the `.className` class styling is applied right away| `class="my-animation ng-animate className"` | + * | 7. `$animate` applies the provided collection of `from` CSS styles to the element | `class="my-animation ng-animate className"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate className"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate className"` | + * | 10. the `className-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate className className-active"` | + * | 11. `$animate` applies the collection of `to` CSS styles to the element which are then handled by the transition | `class="my-animation ng-animate className className-active"` | + * | 12. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate className className-active"` | + * | 13. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 14. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the enter animation + * @param {object} from a collection of CSS styles that will be applied to the element at the start of the animation + * @param {object} to a collection of CSS styles that the element will animate towards + * @param {string=} className an optional CSS class that will be added to the element for the duration of the animation (the default class is `ng-inline-animate`) + * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + animate: function(element, from, to, className, options) { + className = className || 'ng-inline-animate'; + options = parseAnimateOptions(options) || {}; + options.from = to ? from : null; + options.to = to ? to : from; + + return runAnimationPostDigest(function(done) { + return performAnimation('animate', className, stripCommentsFromElement(element), null, null, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#enter + * @kind function + * + * @description + * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once + * the animation is started, the following CSS classes will be present on the element for the duration of the animation: + * + * Below is a breakdown of each step that occurs during enter animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| + * | 1. `$animate.enter(...)` is called | `class="my-animation"` | + * | 2. element is inserted into the `parentElement` element or beside the `afterElement` element | `class="my-animation"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 5. the `.ng-enter` class is added to the element | `class="my-animation ng-animate ng-enter"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-enter"` | + * | 7. `$animate` blocks all CSS transitions on the element to ensure the `.ng-enter` class styling is applied right away | `class="my-animation ng-animate ng-enter"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-enter"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-enter"` | + * | 10. the `.ng-enter-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-enter ng-enter-active"` | + * | 11. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-enter ng-enter-active"` | + * | 12. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 13. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the enter animation + * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation + * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation + * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + enter: function(element, parentElement, afterElement, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + parentElement = prepareElement(parentElement); + afterElement = prepareElement(afterElement); + + classBasedAnimationsBlocked(element, true); + $delegate.enter(element, parentElement, afterElement); + return runAnimationPostDigest(function(done) { + return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#leave + * @kind function + * + * @description + * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during leave animation: + * + * | Animation Step | What the element class attribute looks like | + * |-----------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------| + * | 1. `$animate.leave(...)` is called | `class="my-animation"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. the `.ng-leave` class is added to the element | `class="my-animation ng-animate ng-leave"` | + * | 5. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-leave"` | + * | 6. `$animate` blocks all CSS transitions on the element to ensure the `.ng-leave` class styling is applied right away | `class="my-animation ng-animate ng-leave"` | + * | 7. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-leave"` | + * | 8. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-leave"` | + * | 9. the `.ng-leave-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-leave ng-leave-active"` | + * | 10. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-leave ng-leave-active"` | + * | 11. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 12. The element is removed from the DOM | ... | + * | 13. The returned promise is resolved. | ... | + * + * @param {DOMElement} element the element that will be the focus of the leave animation + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + leave: function(element, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + + cancelChildAnimations(element); + classBasedAnimationsBlocked(element, true); + return runAnimationPostDigest(function(done) { + return performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() { + $delegate.leave(element); + }, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#move + * @kind function + * + * @description + * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or + * add the element directly after the afterElement element if present. Then the move animation will be run. Once + * the animation is started, the following CSS classes will be added for the duration of the animation: + * + * Below is a breakdown of each step that occurs during move animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------| + * | 1. `$animate.move(...)` is called | `class="my-animation"` | + * | 2. element is moved into the parentElement element or beside the afterElement element | `class="my-animation"` | + * | 3. `$animate` waits for the next digest to start the animation | `class="my-animation ng-animate"` | + * | 4. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 5. the `.ng-move` class is added to the element | `class="my-animation ng-animate ng-move"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate ng-move"` | + * | 7. `$animate` blocks all CSS transitions on the element to ensure the `.ng-move` class styling is applied right away | `class="my-animation ng-animate ng-move"` | + * | 8. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate ng-move"` | + * | 9. `$animate` removes the CSS transition block placed on the element | `class="my-animation ng-animate ng-move"` | + * | 10. the `.ng-move-active` class is added (this triggers the CSS transition/animation) | `class="my-animation ng-animate ng-move ng-move-active"` | + * | 11. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate ng-move ng-move-active"` | + * | 12. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 13. The returned promise is resolved. | `class="my-animation"` | + * + * @param {DOMElement} element the element that will be the focus of the move animation + * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation + * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + move: function(element, parentElement, afterElement, options) { + options = parseAnimateOptions(options); + element = angular.element(element); + parentElement = prepareElement(parentElement); + afterElement = prepareElement(afterElement); + + cancelChildAnimations(element); + classBasedAnimationsBlocked(element, true); + $delegate.move(element, parentElement, afterElement); + return runAnimationPostDigest(function(done) { + return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#addClass + * + * @description + * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class. + * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide + * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions + * or keyframes are defined on the -add-active or base CSS class). + * + * Below is a breakdown of each step that occurs during addClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |--------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| + * | 1. `$animate.addClass(element, 'super')` is called | `class="my-animation"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate"` | + * | 3. the `.super-add` class is added to the element | `class="my-animation ng-animate super-add"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate super-add"` | + * | 5. the `.super` and `.super-add-active` classes are added (this triggers the CSS transition/animation) | `class="my-animation ng-animate super super-add super-add-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate super super-add super-add-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate super super-add super-add-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation super"` | + * | 9. The super class is kept on the element | `class="my-animation super"` | + * | 10. The returned promise is resolved. | `class="my-animation super"` | + * + * @param {DOMElement} element the element that will be animated + * @param {string} className the CSS class that will be added to the element and then animated + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + addClass: function(element, className, options) { + return this.setClass(element, className, [], options); + }, + + /** + * @ngdoc method + * @name $animate#removeClass + * + * @description + * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value + * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in + * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if + * no CSS transitions or keyframes are defined on the -remove or base CSS classes). + * + * Below is a breakdown of each step that occurs during removeClass animation: + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| + * | 1. `$animate.removeClass(element, 'super')` is called | `class="my-animation super"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation super ng-animate"` | + * | 3. the `.super-remove` class is added to the element | `class="my-animation super ng-animate super-remove"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation super ng-animate super-remove"` | + * | 5. the `.super-remove-active` classes are added and `.super` is removed (this triggers the CSS transition/animation) | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate super-remove super-remove-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation"` | + * | 9. The returned promise is resolved. | `class="my-animation"` | + * + * + * @param {DOMElement} element the element that will be animated + * @param {string} className the CSS class that will be animated and then removed from the element + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + removeClass: function(element, className, options) { + return this.setClass(element, [], className, options); + }, + + /** + * + * @ngdoc method + * @name $animate#setClass + * + * @description Adds and/or removes the given CSS classes to and from the element. + * Once complete, the `done()` callback will be fired (if provided). + * + * | Animation Step | What the element class attribute looks like | + * |----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------| + * | 1. `$animate.setClass(element, 'on', 'off')` is called | `class="my-animation off"` | + * | 2. `$animate` runs the JavaScript-defined animations detected on the element | `class="my-animation ng-animate off"` | + * | 3. the `.on-add` and `.off-remove` classes are added to the element | `class="my-animation ng-animate on-add off-remove off"` | + * | 4. `$animate` waits for a single animation frame (this performs a reflow) | `class="my-animation ng-animate on-add off-remove off"` | + * | 5. the `.on`, `.on-add-active` and `.off-remove-active` classes are added and `.off` is removed (this triggers the CSS transition/animation) | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 6. `$animate` scans the element styles to get the CSS transition/animation duration and delay | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 7. `$animate` waits for the animation to complete (via events and timeout) | `class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active"` | + * | 8. The animation ends and all generated CSS classes are removed from the element | `class="my-animation on"` | + * | 9. The returned promise is resolved. | `class="my-animation on"` | + * + * @param {DOMElement} element the element which will have its CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * CSS classes have been set on the element + * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation + * @return {Promise} the animation callback promise + */ + setClass: function(element, add, remove, options) { + options = parseAnimateOptions(options); + + var STORAGE_KEY = '$$animateClasses'; + element = angular.element(element); + element = stripCommentsFromElement(element); + + if (classBasedAnimationsBlocked(element)) { + return $delegate.$$setClassImmediately(element, add, remove, options); + } + + // we're using a combined array for both the add and remove + // operations since the ORDER OF addClass and removeClass matters + var classes, cache = element.data(STORAGE_KEY); + var hasCache = !!cache; + if (!cache) { + cache = {}; + cache.classes = {}; + } + classes = cache.classes; + + add = isArray(add) ? add : add.split(' '); + forEach(add, function(c) { + if (c && c.length) { + classes[c] = true; + } + }); + + remove = isArray(remove) ? remove : remove.split(' '); + forEach(remove, function(c) { + if (c && c.length) { + classes[c] = false; + } + }); + + if (hasCache) { + if (options && cache.options) { + cache.options = angular.extend(cache.options || {}, options); + } + + //the digest cycle will combine all the animations into one function + return cache.promise; + } else { + element.data(STORAGE_KEY, cache = { + classes: classes, + options: options + }); + } + + return cache.promise = runAnimationPostDigest(function(done) { + var parentElement = element.parent(); + var elementNode = extractElementNode(element); + var parentNode = elementNode.parentNode; + // TODO(matsko): move this code into the animationsDisabled() function once #8092 is fixed + if (!parentNode || parentNode['$$NG_REMOVED'] || elementNode['$$NG_REMOVED']) { + done(); + return; + } + + var cache = element.data(STORAGE_KEY); + element.removeData(STORAGE_KEY); + + var state = element.data(NG_ANIMATE_STATE) || {}; + var classes = resolveElementClasses(element, cache, state.active); + return !classes + ? done() + : performAnimation('setClass', classes, element, parentElement, null, function() { + if (classes[0]) $delegate.$$addClassImmediately(element, classes[0]); + if (classes[1]) $delegate.$$removeClassImmediately(element, classes[1]); + }, cache.options, done); + }); + }, + + /** + * @ngdoc method + * @name $animate#cancel + * @kind function + * + * @param {Promise} animationPromise The animation promise that is returned when an animation is started. + * + * @description + * Cancels the provided animation. + */ + cancel: function(promise) { + promise.$$cancelFn(); + }, + + /** + * @ngdoc method + * @name $animate#enabled + * @kind function + * + * @param {boolean=} value If provided then set the animation on or off. + * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation + * @return {boolean} Current animation state. + * + * @description + * Globally enables/disables animations. + * + */ + enabled: function(value, element) { + switch (arguments.length) { + case 2: + if (value) { + cleanup(element); + } else { + var data = element.data(NG_ANIMATE_STATE) || {}; + data.disabled = true; + element.data(NG_ANIMATE_STATE, data); + } + break; + + case 1: + rootAnimateState.disabled = !value; + break; + + default: + value = !rootAnimateState.disabled; + break; + } + return !!value; + } + }; + + /* + all animations call this shared animation triggering function internally. + The animationEvent variable refers to the JavaScript animation event that will be triggered + and the className value is the name of the animation that will be applied within the + CSS code. Element, `parentElement` and `afterElement` are provided DOM elements for the animation + and the onComplete callback will be fired once the animation is fully complete. + */ + function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, options, doneCallback) { + var noopCancel = noop; + var runner = animationRunner(element, animationEvent, className, options); + if (!runner) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + closeAnimation(); + return noopCancel; + } + + animationEvent = runner.event; + className = runner.className; + var elementEvents = angular.element._data(runner.node); + elementEvents = elementEvents && elementEvents.events; + + if (!parentElement) { + parentElement = afterElement ? afterElement.parent() : element.parent(); + } + + //skip the animation if animations are disabled, a parent is already being animated, + //the element is not currently attached to the document body or then completely close + //the animation if any matching animations are not found at all. + //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found. + if (animationsDisabled(element, parentElement)) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + closeAnimation(); + return noopCancel; + } + + var ngAnimateState = element.data(NG_ANIMATE_STATE) || {}; + var runningAnimations = ngAnimateState.active || {}; + var totalActiveAnimations = ngAnimateState.totalActive || 0; + var lastAnimation = ngAnimateState.last; + var skipAnimation = false; + + if (totalActiveAnimations > 0) { + var animationsToCancel = []; + if (!runner.isClassBased) { + if (animationEvent == 'leave' && runningAnimations['ng-leave']) { + skipAnimation = true; + } else { + //cancel all animations when a structural animation takes place + for (var klass in runningAnimations) { + animationsToCancel.push(runningAnimations[klass]); + } + ngAnimateState = {}; + cleanup(element, true); + } + } else if (lastAnimation.event == 'setClass') { + animationsToCancel.push(lastAnimation); + cleanup(element, className); + } else if (runningAnimations[className]) { + var current = runningAnimations[className]; + if (current.event == animationEvent) { + skipAnimation = true; + } else { + animationsToCancel.push(current); + cleanup(element, className); + } + } + + if (animationsToCancel.length > 0) { + forEach(animationsToCancel, function(operation) { + operation.cancel(); + }); + } + } + + if (runner.isClassBased + && !runner.isSetClassOperation + && animationEvent != 'animate' + && !skipAnimation) { + skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR + } + + if (skipAnimation) { + fireDOMOperation(); + fireBeforeCallbackAsync(); + fireAfterCallbackAsync(); + fireDoneCallbackAsync(); + return noopCancel; + } + + runningAnimations = ngAnimateState.active || {}; + totalActiveAnimations = ngAnimateState.totalActive || 0; + + if (animationEvent == 'leave') { + //there's no need to ever remove the listener since the element + //will be removed (destroyed) after the leave animation ends or + //is cancelled midway + element.one('$destroy', function(e) { + var element = angular.element(this); + var state = element.data(NG_ANIMATE_STATE); + if (state) { + var activeLeaveAnimation = state.active['ng-leave']; + if (activeLeaveAnimation) { + activeLeaveAnimation.cancel(); + cleanup(element, 'ng-leave'); + } + } + }); + } + + //the ng-animate class does nothing, but it's here to allow for + //parent animations to find and cancel child animations when needed + $$jqLite.addClass(element, NG_ANIMATE_CLASS_NAME); + if (options && options.tempClasses) { + forEach(options.tempClasses, function(className) { + $$jqLite.addClass(element, className); + }); + } + + var localAnimationCount = globalAnimationCounter++; + totalActiveAnimations++; + runningAnimations[className] = runner; + + element.data(NG_ANIMATE_STATE, { + last: runner, + active: runningAnimations, + index: localAnimationCount, + totalActive: totalActiveAnimations + }); + + //first we run the before animations and when all of those are complete + //then we perform the DOM operation and run the next set of animations + fireBeforeCallbackAsync(); + runner.before(function(cancelled) { + var data = element.data(NG_ANIMATE_STATE); + cancelled = cancelled || + !data || !data.active[className] || + (runner.isClassBased && data.active[className].event != animationEvent); + + fireDOMOperation(); + if (cancelled === true) { + closeAnimation(); + } else { + fireAfterCallbackAsync(); + runner.after(closeAnimation); + } + }); + + return runner.cancel; + + function fireDOMCallback(animationPhase) { + var eventName = '$animate:' + animationPhase; + if (elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) { + $$asyncCallback(function() { + element.triggerHandler(eventName, { + event: animationEvent, + className: className + }); + }); + } + } + + function fireBeforeCallbackAsync() { + fireDOMCallback('before'); + } + + function fireAfterCallbackAsync() { + fireDOMCallback('after'); + } + + function fireDoneCallbackAsync() { + fireDOMCallback('close'); + doneCallback(); + } + + //it is less complicated to use a flag than managing and canceling + //timeouts containing multiple callbacks. + function fireDOMOperation() { + if (!fireDOMOperation.hasBeenRun) { + fireDOMOperation.hasBeenRun = true; + domOperation(); + } + } + + function closeAnimation() { + if (!closeAnimation.hasBeenRun) { + if (runner) { //the runner doesn't exist if it fails to instantiate + runner.applyStyles(); + } + + closeAnimation.hasBeenRun = true; + if (options && options.tempClasses) { + forEach(options.tempClasses, function(className) { + $$jqLite.removeClass(element, className); + }); + } + + var data = element.data(NG_ANIMATE_STATE); + if (data) { + + /* only structural animations wait for reflow before removing an + animation, but class-based animations don't. An example of this + failing would be when a parent HTML tag has a ng-class attribute + causing ALL directives below to skip animations during the digest */ + if (runner && runner.isClassBased) { + cleanup(element, className); + } else { + $$asyncCallback(function() { + var data = element.data(NG_ANIMATE_STATE) || {}; + if (localAnimationCount == data.index) { + cleanup(element, className, animationEvent); + } + }); + element.data(NG_ANIMATE_STATE, data); + } + } + fireDoneCallbackAsync(); + } + } + } + + function cancelChildAnimations(element) { + var node = extractElementNode(element); + if (node) { + var nodes = angular.isFunction(node.getElementsByClassName) ? + node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) : + node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME); + forEach(nodes, function(element) { + element = angular.element(element); + var data = element.data(NG_ANIMATE_STATE); + if (data && data.active) { + forEach(data.active, function(runner) { + runner.cancel(); + }); + } + }); + } + } + + function cleanup(element, className) { + if (isMatchingElement(element, $rootElement)) { + if (!rootAnimateState.disabled) { + rootAnimateState.running = false; + rootAnimateState.structural = false; + } + } else if (className) { + var data = element.data(NG_ANIMATE_STATE) || {}; + + var removeAnimations = className === true; + if (!removeAnimations && data.active && data.active[className]) { + data.totalActive--; + delete data.active[className]; + } + + if (removeAnimations || !data.totalActive) { + $$jqLite.removeClass(element, NG_ANIMATE_CLASS_NAME); + element.removeData(NG_ANIMATE_STATE); + } + } + } + + function animationsDisabled(element, parentElement) { + if (rootAnimateState.disabled) { + return true; + } + + if (isMatchingElement(element, $rootElement)) { + return rootAnimateState.running; + } + + var allowChildAnimations, parentRunningAnimation, hasParent; + do { + //the element did not reach the root element which means that it + //is not apart of the DOM. Therefore there is no reason to do + //any animations on it + if (parentElement.length === 0) break; + + var isRoot = isMatchingElement(parentElement, $rootElement); + var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {}); + if (state.disabled) { + return true; + } + + //no matter what, for an animation to work it must reach the root element + //this implies that the element is attached to the DOM when the animation is run + if (isRoot) { + hasParent = true; + } + + //once a flag is found that is strictly false then everything before + //it will be discarded and all child animations will be restricted + if (allowChildAnimations !== false) { + var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN); + if (angular.isDefined(animateChildrenFlag)) { + allowChildAnimations = animateChildrenFlag; + } + } + + parentRunningAnimation = parentRunningAnimation || + state.running || + (state.last && !state.last.isClassBased); + } + while (parentElement = parentElement.parent()); + + return !hasParent || (!allowChildAnimations && parentRunningAnimation); + } + }]); + + $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow', + function($window, $sniffer, $timeout, $$animateReflow) { + // Detect proper transitionend/animationend event names. + var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT; + + // If unprefixed events are not supported but webkit-prefixed are, use the latter. + // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them. + // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend` + // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`. + // Register both events in case `window.onanimationend` is not supported because of that, + // do the same for `transitionend` as Safari is likely to exhibit similar behavior. + // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit + // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition + if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) { + CSS_PREFIX = '-webkit-'; + TRANSITION_PROP = 'WebkitTransition'; + TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend'; + } else { + TRANSITION_PROP = 'transition'; + TRANSITIONEND_EVENT = 'transitionend'; + } + + if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) { + CSS_PREFIX = '-webkit-'; + ANIMATION_PROP = 'WebkitAnimation'; + ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend'; + } else { + ANIMATION_PROP = 'animation'; + ANIMATIONEND_EVENT = 'animationend'; + } + + var DURATION_KEY = 'Duration'; + var PROPERTY_KEY = 'Property'; + var DELAY_KEY = 'Delay'; + var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount'; + var ANIMATION_PLAYSTATE_KEY = 'PlayState'; + var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey'; + var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data'; + var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3; + var CLOSING_TIME_BUFFER = 1.5; + var ONE_SECOND = 1000; + + var lookupCache = {}; + var parentCounter = 0; + var animationReflowQueue = []; + var cancelAnimationReflow; + function clearCacheAfterReflow() { + if (!cancelAnimationReflow) { + cancelAnimationReflow = $$animateReflow(function() { + animationReflowQueue = []; + cancelAnimationReflow = null; + lookupCache = {}; + }); + } + } + + function afterReflow(element, callback) { + if (cancelAnimationReflow) { + cancelAnimationReflow(); + } + animationReflowQueue.push(callback); + cancelAnimationReflow = $$animateReflow(function() { + forEach(animationReflowQueue, function(fn) { + fn(); + }); + + animationReflowQueue = []; + cancelAnimationReflow = null; + lookupCache = {}; + }); + } + + var closingTimer = null; + var closingTimestamp = 0; + var animationElementQueue = []; + function animationCloseHandler(element, totalTime) { + var node = extractElementNode(element); + element = angular.element(node); + + //this item will be garbage collected by the closing + //animation timeout + animationElementQueue.push(element); + + //but it may not need to cancel out the existing timeout + //if the timestamp is less than the previous one + var futureTimestamp = Date.now() + totalTime; + if (futureTimestamp <= closingTimestamp) { + return; + } + + $timeout.cancel(closingTimer); + + closingTimestamp = futureTimestamp; + closingTimer = $timeout(function() { + closeAllAnimations(animationElementQueue); + animationElementQueue = []; + }, totalTime, false); + } + + function closeAllAnimations(elements) { + forEach(elements, function(element) { + var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (elementData) { + forEach(elementData.closeAnimationFns, function(fn) { + fn(); + }); + } + }); + } + + function getElementAnimationDetails(element, cacheKey) { + var data = cacheKey ? lookupCache[cacheKey] : null; + if (!data) { + var transitionDuration = 0; + var transitionDelay = 0; + var animationDuration = 0; + var animationDelay = 0; + + //we want all the styles defined before and after + forEach(element, function(element) { + if (element.nodeType == ELEMENT_NODE) { + var elementStyles = $window.getComputedStyle(element) || {}; + + var transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY]; + transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration); + + var transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY]; + transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay); + + var animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY]; + animationDelay = Math.max(parseMaxTime(elementStyles[ANIMATION_PROP + DELAY_KEY]), animationDelay); + + var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]); + + if (aDuration > 0) { + aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1; + } + animationDuration = Math.max(aDuration, animationDuration); + } + }); + data = { + total: 0, + transitionDelay: transitionDelay, + transitionDuration: transitionDuration, + animationDelay: animationDelay, + animationDuration: animationDuration + }; + if (cacheKey) { + lookupCache[cacheKey] = data; + } + } + return data; + } + + function parseMaxTime(str) { + var maxValue = 0; + var values = isString(str) ? + str.split(/\s*,\s*/) : + []; + forEach(values, function(value) { + maxValue = Math.max(parseFloat(value) || 0, maxValue); + }); + return maxValue; + } + + function getCacheKey(element) { + var parentElement = element.parent(); + var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY); + if (!parentID) { + parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter); + parentID = parentCounter; + } + return parentID + '-' + extractElementNode(element).getAttribute('class'); + } + + function animateSetup(animationEvent, element, className, styles) { + var structural = ['ng-enter','ng-leave','ng-move'].indexOf(className) >= 0; + + var cacheKey = getCacheKey(element); + var eventCacheKey = cacheKey + ' ' + className; + var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0; + + var stagger = {}; + if (itemIndex > 0) { + var staggerClassName = className + '-stagger'; + var staggerCacheKey = cacheKey + ' ' + staggerClassName; + var applyClasses = !lookupCache[staggerCacheKey]; + + applyClasses && $$jqLite.addClass(element, staggerClassName); + + stagger = getElementAnimationDetails(element, staggerCacheKey); + + applyClasses && $$jqLite.removeClass(element, staggerClassName); + } + + $$jqLite.addClass(element, className); + + var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {}; + var timings = getElementAnimationDetails(element, eventCacheKey); + var transitionDuration = timings.transitionDuration; + var animationDuration = timings.animationDuration; + + if (structural && transitionDuration === 0 && animationDuration === 0) { + $$jqLite.removeClass(element, className); + return false; + } + + var blockTransition = styles || (structural && transitionDuration > 0); + var blockAnimation = animationDuration > 0 && + stagger.animationDelay > 0 && + stagger.animationDuration === 0; + + var closeAnimationFns = formerData.closeAnimationFns || []; + element.data(NG_ANIMATE_CSS_DATA_KEY, { + stagger: stagger, + cacheKey: eventCacheKey, + running: formerData.running || 0, + itemIndex: itemIndex, + blockTransition: blockTransition, + closeAnimationFns: closeAnimationFns + }); + + var node = extractElementNode(element); + + if (blockTransition) { + blockTransitions(node, true); + if (styles) { + element.css(styles); + } + } + + if (blockAnimation) { + blockAnimations(node, true); + } + + return true; + } + + function animateRun(animationEvent, element, className, activeAnimationComplete, styles) { + var node = extractElementNode(element); + var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (node.getAttribute('class').indexOf(className) == -1 || !elementData) { + activeAnimationComplete(); + return; + } + + var activeClassName = ''; + var pendingClassName = ''; + forEach(className.split(' '), function(klass, i) { + var prefix = (i > 0 ? ' ' : '') + klass; + activeClassName += prefix + '-active'; + pendingClassName += prefix + '-pending'; + }); + + var style = ''; + var appliedStyles = []; + var itemIndex = elementData.itemIndex; + var stagger = elementData.stagger; + var staggerTime = 0; + if (itemIndex > 0) { + var transitionStaggerDelay = 0; + if (stagger.transitionDelay > 0 && stagger.transitionDuration === 0) { + transitionStaggerDelay = stagger.transitionDelay * itemIndex; + } + + var animationStaggerDelay = 0; + if (stagger.animationDelay > 0 && stagger.animationDuration === 0) { + animationStaggerDelay = stagger.animationDelay * itemIndex; + appliedStyles.push(CSS_PREFIX + 'animation-play-state'); + } + + staggerTime = Math.round(Math.max(transitionStaggerDelay, animationStaggerDelay) * 100) / 100; + } + + if (!staggerTime) { + $$jqLite.addClass(element, activeClassName); + if (elementData.blockTransition) { + blockTransitions(node, false); + } + } + + var eventCacheKey = elementData.cacheKey + ' ' + activeClassName; + var timings = getElementAnimationDetails(element, eventCacheKey); + var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration); + if (maxDuration === 0) { + $$jqLite.removeClass(element, activeClassName); + animateClose(element, className); + activeAnimationComplete(); + return; + } + + if (!staggerTime && styles && Object.keys(styles).length > 0) { + if (!timings.transitionDuration) { + element.css('transition', timings.animationDuration + 's linear all'); + appliedStyles.push('transition'); + } + element.css(styles); + } + + var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay); + var maxDelayTime = maxDelay * ONE_SECOND; + + if (appliedStyles.length > 0) { + //the element being animated may sometimes contain comment nodes in + //the jqLite object, so we're safe to use a single variable to house + //the styles since there is always only one element being animated + var oldStyle = node.getAttribute('style') || ''; + if (oldStyle.charAt(oldStyle.length - 1) !== ';') { + oldStyle += ';'; + } + node.setAttribute('style', oldStyle + ' ' + style); + } + + var startTime = Date.now(); + var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT; + var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER; + var totalTime = (staggerTime + animationTime) * ONE_SECOND; + + var staggerTimeout; + if (staggerTime > 0) { + $$jqLite.addClass(element, pendingClassName); + staggerTimeout = $timeout(function() { + staggerTimeout = null; + + if (timings.transitionDuration > 0) { + blockTransitions(node, false); + } + if (timings.animationDuration > 0) { + blockAnimations(node, false); + } + + $$jqLite.addClass(element, activeClassName); + $$jqLite.removeClass(element, pendingClassName); + + if (styles) { + if (timings.transitionDuration === 0) { + element.css('transition', timings.animationDuration + 's linear all'); + } + element.css(styles); + appliedStyles.push('transition'); + } + }, staggerTime * ONE_SECOND, false); + } + + element.on(css3AnimationEvents, onAnimationProgress); + elementData.closeAnimationFns.push(function() { + onEnd(); + activeAnimationComplete(); + }); + + elementData.running++; + animationCloseHandler(element, totalTime); + return onEnd; + + // This will automatically be called by $animate so + // there is no need to attach this internally to the + // timeout done method. + function onEnd() { + element.off(css3AnimationEvents, onAnimationProgress); + $$jqLite.removeClass(element, activeClassName); + $$jqLite.removeClass(element, pendingClassName); + if (staggerTimeout) { + $timeout.cancel(staggerTimeout); + } + animateClose(element, className); + var node = extractElementNode(element); + for (var i in appliedStyles) { + node.style.removeProperty(appliedStyles[i]); + } + } + + function onAnimationProgress(event) { + event.stopPropagation(); + var ev = event.originalEvent || event; + var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now(); + + /* Firefox (or possibly just Gecko) likes to not round values up + * when a ms measurement is used for the animation */ + var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES)); + + /* $manualTimeStamp is a mocked timeStamp value which is set + * within browserTrigger(). This is only here so that tests can + * mock animations properly. Real events fallback to event.timeStamp, + * or, if they don't, then a timeStamp is automatically created for them. + * We're checking to see if the timeStamp surpasses the expected delay, + * but we're using elapsedTime instead of the timeStamp on the 2nd + * pre-condition since animations sometimes close off early */ + if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) { + activeAnimationComplete(); + } + } + } + + function blockTransitions(node, bool) { + node.style[TRANSITION_PROP + PROPERTY_KEY] = bool ? 'none' : ''; + } + + function blockAnimations(node, bool) { + node.style[ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY] = bool ? 'paused' : ''; + } + + function animateBefore(animationEvent, element, className, styles) { + if (animateSetup(animationEvent, element, className, styles)) { + return function(cancelled) { + cancelled && animateClose(element, className); + }; + } + } + + function animateAfter(animationEvent, element, className, afterAnimationComplete, styles) { + if (element.data(NG_ANIMATE_CSS_DATA_KEY)) { + return animateRun(animationEvent, element, className, afterAnimationComplete, styles); + } else { + animateClose(element, className); + afterAnimationComplete(); + } + } + + function animate(animationEvent, element, className, animationComplete, options) { + //If the animateSetup function doesn't bother returning a + //cancellation function then it means that there is no animation + //to perform at all + var preReflowCancellation = animateBefore(animationEvent, element, className, options.from); + if (!preReflowCancellation) { + clearCacheAfterReflow(); + animationComplete(); + return; + } + + //There are two cancellation functions: one is before the first + //reflow animation and the second is during the active state + //animation. The first function will take care of removing the + //data from the element which will not make the 2nd animation + //happen in the first place + var cancel = preReflowCancellation; + afterReflow(element, function() { + //once the reflow is complete then we point cancel to + //the new cancellation function which will remove all of the + //animation properties from the active animation + cancel = animateAfter(animationEvent, element, className, animationComplete, options.to); + }); + + return function(cancelled) { + (cancel || noop)(cancelled); + }; + } + + function animateClose(element, className) { + $$jqLite.removeClass(element, className); + var data = element.data(NG_ANIMATE_CSS_DATA_KEY); + if (data) { + if (data.running) { + data.running--; + } + if (!data.running || data.running === 0) { + element.removeData(NG_ANIMATE_CSS_DATA_KEY); + } + } + } + + return { + animate: function(element, className, from, to, animationCompleted, options) { + options = options || {}; + options.from = from; + options.to = to; + return animate('animate', element, className, animationCompleted, options); + }, + + enter: function(element, animationCompleted, options) { + options = options || {}; + return animate('enter', element, 'ng-enter', animationCompleted, options); + }, + + leave: function(element, animationCompleted, options) { + options = options || {}; + return animate('leave', element, 'ng-leave', animationCompleted, options); + }, + + move: function(element, animationCompleted, options) { + options = options || {}; + return animate('move', element, 'ng-move', animationCompleted, options); + }, + + beforeSetClass: function(element, add, remove, animationCompleted, options) { + options = options || {}; + var className = suffixClasses(remove, '-remove') + ' ' + + suffixClasses(add, '-add'); + var cancellationMethod = animateBefore('setClass', element, className, options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + beforeAddClass: function(element, className, animationCompleted, options) { + options = options || {}; + var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + beforeRemoveClass: function(element, className, animationCompleted, options) { + options = options || {}; + var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), options.from); + if (cancellationMethod) { + afterReflow(element, animationCompleted); + return cancellationMethod; + } + clearCacheAfterReflow(); + animationCompleted(); + }, + + setClass: function(element, add, remove, animationCompleted, options) { + options = options || {}; + remove = suffixClasses(remove, '-remove'); + add = suffixClasses(add, '-add'); + var className = remove + ' ' + add; + return animateAfter('setClass', element, className, animationCompleted, options.to); + }, + + addClass: function(element, className, animationCompleted, options) { + options = options || {}; + return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted, options.to); + }, + + removeClass: function(element, className, animationCompleted, options) { + options = options || {}; + return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted, options.to); + } + }; + + function suffixClasses(classes, suffix) { + var className = ''; + classes = isArray(classes) ? classes : classes.split(/\s+/); + forEach(classes, function(klass, i) { + if (klass && klass.length > 0) { + className += (i > 0 ? ' ' : '') + klass + suffix; + } + }); + return className; + } + }]); + }]); + + +})(window, window.angular); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.min.js new file mode 100644 index 0000000..6ed98ee --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-animate_1.3.13/angular-animate.min.js @@ -0,0 +1,33 @@ +/* + AngularJS v1.3.13 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(N,f,W){'use strict';f.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(X,C,g){g=g.ngAnimateChildren;f.isString(g)&&0===g.length?C.data("$$ngAnimateChildren",!0):X.$watch(g,function(f){C.data("$$ngAnimateChildren",!!f)})}}).factory("$$animateReflow",["$$rAF","$document",function(f,C){return function(g){return f(function(){g()})}}]).config(["$provide","$animateProvider",function(X,C){function g(f){for(var n=0;n=C&&b>=x&&c()}var m=g(e);a=e.data("$$ngAnimateCSS3Data");if(-1!=m.getAttribute("class").indexOf(b)&&a){var k="",t="";n(b.split(" "),function(a, +b){var e=(0
+ * + * See {@link ngCookies.$cookies `$cookies`} and + * {@link ngCookies.$cookieStore `$cookieStore`} for usage. + */ + + +angular.module('ngCookies', ['ng']). + /** + * @ngdoc service + * @name $cookies + * + * @description + * Provides read/write access to browser's cookies. + * + * Only a simple Object is exposed and by adding or removing properties to/from this object, new + * cookies are created/deleted at the end of current $eval. + * The object's properties can only be strings. + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + * + * ```js + * angular.module('cookiesExample', ['ngCookies']) + * .controller('ExampleController', ['$cookies', function($cookies) { + * // Retrieving a cookie + * var favoriteCookie = $cookies.myFavorite; + * // Setting a cookie + * $cookies.myFavorite = 'oatmeal'; + * }]); + * ``` + */ + factory('$cookies', ['$rootScope', '$browser', function($rootScope, $browser) { + var cookies = {}, + lastCookies = {}, + lastBrowserCookies, + runEval = false, + copy = angular.copy, + isUndefined = angular.isUndefined; + + //creates a poller fn that copies all cookies from the $browser to service & inits the service + $browser.addPollFn(function() { + var currentCookies = $browser.cookies(); + if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl + lastBrowserCookies = currentCookies; + copy(currentCookies, lastCookies); + copy(currentCookies, cookies); + if (runEval) $rootScope.$apply(); + } + })(); + + runEval = true; + + //at the end of each eval, push cookies + //TODO: this should happen before the "delayed" watches fire, because if some cookies are not + // strings or browser refuses to store some cookies, we update the model in the push fn. + $rootScope.$watch(push); + + return cookies; + + + /** + * Pushes all the cookies from the service to the browser and verifies if all cookies were + * stored. + */ + function push() { + var name, + value, + browserCookies, + updated; + + //delete any cookies deleted in $cookies + for (name in lastCookies) { + if (isUndefined(cookies[name])) { + $browser.cookies(name, undefined); + } + } + + //update all cookies updated in $cookies + for (name in cookies) { + value = cookies[name]; + if (!angular.isString(value)) { + value = '' + value; + cookies[name] = value; + } + if (value !== lastCookies[name]) { + $browser.cookies(name, value); + updated = true; + } + } + + //verify what was actually stored + if (updated) { + updated = false; + browserCookies = $browser.cookies(); + + for (name in cookies) { + if (cookies[name] !== browserCookies[name]) { + //delete or reset all cookies that the browser dropped from $cookies + if (isUndefined(browserCookies[name])) { + delete cookies[name]; + } else { + cookies[name] = browserCookies[name]; + } + updated = true; + } + } + } + } + }]). + + + /** + * @ngdoc service + * @name $cookieStore + * @requires $cookies + * + * @description + * Provides a key-value (string-object) storage, that is backed by session cookies. + * Objects put or retrieved from this storage are automatically serialized or + * deserialized by angular's toJson/fromJson. + * + * Requires the {@link ngCookies `ngCookies`} module to be installed. + * + * @example + * + * ```js + * angular.module('cookieStoreExample', ['ngCookies']) + * .controller('ExampleController', ['$cookieStore', function($cookieStore) { + * // Put cookie + * $cookieStore.put('myFavorite','oatmeal'); + * // Get cookie + * var favoriteCookie = $cookieStore.get('myFavorite'); + * // Removing a cookie + * $cookieStore.remove('myFavorite'); + * }]); + * ``` + */ + factory('$cookieStore', ['$cookies', function($cookies) { + + return { + /** + * @ngdoc method + * @name $cookieStore#get + * + * @description + * Returns the value of given cookie key + * + * @param {string} key Id to use for lookup. + * @returns {Object} Deserialized cookie value. + */ + get: function(key) { + var value = $cookies[key]; + return value ? angular.fromJson(value) : value; + }, + + /** + * @ngdoc method + * @name $cookieStore#put + * + * @description + * Sets a value for given cookie key + * + * @param {string} key Id for the `value`. + * @param {Object} value Value to be stored. + */ + put: function(key, value) { + $cookies[key] = angular.toJson(value); + }, + + /** + * @ngdoc method + * @name $cookieStore#remove + * + * @description + * Remove given cookie + * + * @param {string} key Id of the key-value pair to delete. + */ + remove: function(key) { + delete $cookies[key]; + } + }; + + }]); + + +})(window, window.angular); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js new file mode 100644 index 0000000..2d81fd3 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js @@ -0,0 +1,8 @@ +/* + AngularJS v1.3.13 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(p,f,n){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(e,b){var c={},g={},h,k=!1,l=f.copy,m=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,l(a,g),l(a,c),k&&e.$apply())})();k=!0;e.$watch(function(){var a,d,e;for(a in g)m(c[a])&&b.cookies(a,n);for(a in c)d=c[a],f.isString(d)||(d=""+d,c[a]=d),d!==g[a]&&(b.cookies(a,d),e=!0);if(e)for(a in d=b.cookies(),c)c[a]!==d[a]&&(m(d[a])?delete c[a]:c[a]=d[a])});return c}]).factory("$cookieStore", +["$cookies",function(e){return{get:function(b){return(b=e[b])?f.fromJson(b):b},put:function(b,c){e[b]=f.toJson(c)},remove:function(b){delete e[b]}}}])})(window,window.angular); +//# sourceMappingURL=angular-cookies.min.js.map diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js.map b/zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js.map new file mode 100644 index 0000000..677960c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-cookies_1.3.13/angular-cookies.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-cookies.min.js", +"lineCount":7, +"mappings":"A;;;;;aAKC,SAAQ,CAACA,CAAD,CAASC,CAAT,CAAkBC,CAAlB,CAA6B,CAmBtCD,CAAAE,OAAA,CAAe,WAAf,CAA4B,CAAC,IAAD,CAA5B,CAAAC,QAAA,CA0BW,UA1BX,CA0BuB,CAAC,YAAD,CAAe,UAAf,CAA2B,QAAQ,CAACC,CAAD,CAAaC,CAAb,CAAuB,CAAA,IACvEC,EAAU,EAD6D,CAEvEC,EAAc,EAFyD,CAGvEC,CAHuE,CAIvEC,EAAU,CAAA,CAJ6D,CAKvEC,EAAOV,CAAAU,KALgE,CAMvEC,EAAcX,CAAAW,YAGlBN,EAAAO,UAAA,CAAmB,QAAQ,EAAG,CAC5B,IAAIC,EAAiBR,CAAAC,QAAA,EACjBE,EAAJ,EAA0BK,CAA1B,GACEL,CAGA,CAHqBK,CAGrB,CAFAH,CAAA,CAAKG,CAAL,CAAqBN,CAArB,CAEA,CADAG,CAAA,CAAKG,CAAL,CAAqBP,CAArB,CACA,CAAIG,CAAJ,EAAaL,CAAAU,OAAA,EAJf,CAF4B,CAA9B,CAAA,EAUAL,EAAA,CAAU,CAAA,CAKVL,EAAAW,OAAA,CASAC,QAAa,EAAG,CAAA,IACVC,CADU,CAEVC,CAFU,CAIVC,CAGJ,KAAKF,CAAL,GAAaV,EAAb,CACMI,CAAA,CAAYL,CAAA,CAAQW,CAAR,CAAZ,CAAJ,EACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBhB,CAAvB,CAKJ,KAAKgB,CAAL,GAAaX,EAAb,CACEY,CAKA,CALQZ,CAAA,CAAQW,CAAR,CAKR,CAJKjB,CAAAoB,SAAA,CAAiBF,CAAjB,CAIL,GAHEA,CACA,CADQ,EACR,CADaA,CACb,CAAAZ,CAAA,CAAQW,CAAR,CAAA,CAAgBC,CAElB,EAAIA,CAAJ,GAAcX,CAAA,CAAYU,CAAZ,CAAd,GACEZ,CAAAC,QAAA,CAAiBW,CAAjB,CAAuBC,CAAvB,CACA,CAAAC,CAAA,CAAU,CAAA,CAFZ,CAOF,IAAIA,CAAJ,CAIE,IAAKF,CAAL,GAFAI,EAEaf,CAFID,CAAAC,QAAA,EAEJA,CAAAA,CAAb,CACMA,CAAA,CAAQW,CAAR,CAAJ,GAAsBI,CAAA,CAAeJ,CAAf,CAAtB,GAEMN,CAAA,CAAYU,CAAA,CAAeJ,CAAf,CAAZ,CAAJ,CACE,OAAOX,CAAA,CAAQW,CAAR,CADT,CAGEX,CAAA,CAAQW,CAAR,CAHF,CAGkBI,CAAA,CAAeJ,CAAf,CALpB,CAhCU,CAThB,CAEA,OAAOX,EA1BoE,CAA1D,CA1BvB,CAAAH,QAAA,CAoIW,cApIX;AAoI2B,CAAC,UAAD,CAAa,QAAQ,CAACmB,CAAD,CAAW,CAErD,MAAO,CAWLC,IAAKA,QAAQ,CAACC,CAAD,CAAM,CAEjB,MAAO,CADHN,CACG,CADKI,CAAA,CAASE,CAAT,CACL,EAAQxB,CAAAyB,SAAA,CAAiBP,CAAjB,CAAR,CAAkCA,CAFxB,CAXd,CA0BLQ,IAAKA,QAAQ,CAACF,CAAD,CAAMN,CAAN,CAAa,CACxBI,CAAA,CAASE,CAAT,CAAA,CAAgBxB,CAAA2B,OAAA,CAAeT,CAAf,CADQ,CA1BrB,CAuCLU,OAAQA,QAAQ,CAACJ,CAAD,CAAM,CACpB,OAAOF,CAAA,CAASE,CAAT,CADa,CAvCjB,CAF8C,CAAhC,CApI3B,CAnBsC,CAArC,CAAD,CAwMGzB,MAxMH,CAwMWA,MAAAC,QAxMX;", +"sources":["angular-cookies.js"], +"names":["window","angular","undefined","module","factory","$rootScope","$browser","cookies","lastCookies","lastBrowserCookies","runEval","copy","isUndefined","addPollFn","currentCookies","$apply","$watch","push","name","value","updated","isString","browserCookies","$cookies","get","key","fromJson","put","toJson","remove"] +} diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js b/zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js new file mode 100644 index 0000000..e496fd4 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.js @@ -0,0 +1,501 @@ +/** + * angular-drag-and-drop-lists v1.2.0 + * + * Copyright (c) 2014 Marcel Juenemann mail@marcel-junemann.de + * https://github.com/marceljuenemann/angular-drag-and-drop-lists + * + * License: MIT + */ +angular.module('dndLists', []) + + /** + * Use the dnd-draggable attribute to make your element draggable + * + * Attributes: + * - dnd-draggable Required attribute. The value has to be an object that represents the data + * of the element. In case of a drag and drop operation the object will be + * serialized and unserialized on the receiving end. + * - dnd-selected Callback that is invoked when the element was clicked but not dragged. + * The original click event will be provided in the local event variable. + * - dnd-effect-allowed Use this attribute to limit the operations that can be performed. Options: + * - "move": The drag operation will move the element. This is the default. + * - "copy": The drag operation will copy the element. Shows a copy cursor. + * - "copyMove": The user can choose between copy and move by pressing the + * ctrl or shift key. *Not supported in IE:* In Internet Explorer this + * option will be the same as "copy". *Not fully supported in Chrome on + * Windows:* In the Windows version of Chrome the cursor will always be the + * move cursor. However, when the user drops an element and has the ctrl + * key pressed, we will perform a copy anyways. + * - HTML5 also specifies the "link" option, but this library does not + * actively support it yet, so use it at your own risk. + * - dnd-moved Callback that is invoked when the element was moved. Usually you will + * remove your element from the original list in this callback, since the + * directive is not doing that for you automatically. The original dragend + * event will be provided in the local event variable. + * - dnd-copied Same as dnd-moved, just that it is called when the element was copied + * instead of moved. The original dragend event will be provided in the local + * event variable. + * - dnd-dragstart Callback that is invoked when the element was dragged. The original + * dragstart event will be provided in the local event variable. + * - dnd-type Use this attribute if you have different kinds of items in your + * application and you want to limit which items can be dropped into which + * lists. Combine with dnd-allowed-types on the dnd-list(s). This attribute + * should evaluate to a string, although this restriction is not enforced. + * - dnd-disable-if You can use this attribute to dynamically disable the draggability of the + * element. This is useful if you have certain list items that you don't want + * to be draggable, or if you want to disable drag & drop completely without + * having two different code branches (e.g. only allow for admins). + * **Note**: If your element is not draggable, the user is probably able to + * select text or images inside of it. Since a selection is always draggable, + * this breaks your UI. You most likely want to disable user selection via + * CSS (see user-select). + * + * CSS classes: + * - dndDragging This class will be added to the element while the element is being + * dragged. It will affect both the element you see while dragging and the + * source element that stays at it's position. Do not try to hide the source + * element with this class, because that will abort the drag operation. + * - dndDraggingSource This class will be added to the element after the drag operation was + * started, meaning it only affects the original element that is still at + * it's source position, and not the "element" that the user is dragging with + * his mouse pointer. + */ + .directive('dndDraggable', ['$parse', '$timeout', 'dndDropEffectWorkaround', 'dndDragTypeWorkaround', + function($parse, $timeout, dndDropEffectWorkaround, dndDragTypeWorkaround) { + return function(scope, element, attr) { + // Set the HTML5 draggable attribute on the element + element.attr("draggable", "true"); + + // If the dnd-disable-if attribute is set, we have to watch that + if (attr.dndDisableIf) { + scope.$watch(attr.dndDisableIf, function(disabled) { + element.attr("draggable", !disabled); + }); + } + + /** + * When the drag operation is started we have to prepare the dataTransfer object, + * which is the primary way we communicate with the target element + */ + element.on('dragstart', function(event) { + event = event.originalEvent || event; + + // Serialize the data associated with this element. IE only supports the Text drag type + event.dataTransfer.setData("Text", angular.toJson(scope.$eval(attr.dndDraggable))); + + // Only allow actions specified in dnd-effect-allowed attribute + event.dataTransfer.effectAllowed = attr.dndEffectAllowed || "move"; + + // Add CSS classes. See documentation above + element.addClass("dndDragging"); + + // Workarounds for stupid browsers, see description below + dndDropEffectWorkaround.dropEffect = "none"; + dndDragTypeWorkaround.isDragging = true; + + // + // This code was originally placed after element.addClass. + // This timeout is invoked after the 'dragend' event in IE9 (at leats on slooow virtual box) + // and since this class is used to hide elements it seems like the element is gone, + // therefor make sure the dragging still is happening when adding this class + $timeout(function() { + // Flowable This code + if (dndDragTypeWorkaround.isDragging) { + element.addClass("dndDraggingSource"); + } + }, 0); + // + + // Save type of item in global state. Usually, this would go into the dataTransfer + // typename, but we have to use "Text" there to support IE + dndDragTypeWorkaround.dragType = attr.dndType ? scope.$eval(attr.dndType) : undefined; + + // Invoke callback + $parse(attr.dndDragstart)(scope, {event: event}); + + event.stopPropagation(); + }); + + /** + * The dragend event is triggered when the element was dropped or when the drag + * operation was aborted (e.g. hit escape button). Depending on the executed action + * we will invoke the callbacks specified with the dnd-moved or dnd-copied attribute. + */ + element.on('dragend', function(event) { + event = event.originalEvent || event; + + // Invoke callbacks. Usually we would use event.dataTransfer.dropEffect to determine + // the used effect, but Chrome has not implemented that field correctly. On Windows + // it always sets it to 'none', while Chrome on Linux sometimes sets it to something + // else when it's supposed to send 'none' (drag operation aborted). + var dropEffect = dndDropEffectWorkaround.dropEffect; + scope.$apply(function() { + switch (dropEffect) { + case "move": + $parse(attr.dndMoved)(scope, {event: event}); + break; + + case "copy": + $parse(attr.dndCopied)(scope, {event: event}); + break; + } + }); + + // Clean up + element.removeClass("dndDragging"); + element.removeClass("dndDraggingSource"); + dndDragTypeWorkaround.isDragging = false; + event.stopPropagation(); + }); + + /** + * When the element is clicked we invoke the callback function + * specified with the dnd-selected attribute. + */ + element.on('click', function(event) { + event = event.originalEvent || event; + + scope.$apply(function() { + $parse(attr.dndSelected)(scope, {event: event}); + }); + + event.stopPropagation(); + }); + + /** + * Workaround to make element draggable in IE9 + */ + element.on('selectstart', function() { + if (this.dragDrop) this.dragDrop(); + return false; + }); + }; + }]) + + /** + * Use the dnd-list attribute to make your list element a dropzone. Usually you will add a single + * li element as child with the ng-repeat directive. If you don't do that, we will not be able to + * position the dropped element correctly. If you want your list to be sortable, also add the + * dnd-draggable directive to your li element(s). Both the dnd-list and it's direct children must + * have position: relative CSS style, otherwise the positioning algorithm will not be able to + * determine the correct placeholder position in all browsers. + * + * Attributes: + * - dnd-list Required attribute. The value has to be the array in which the data of + * the dropped element should be inserted. + * - dnd-allowed-types Optional array of allowed item types. When used, only items that had a + * matching dnd-type attribute will be dropable. + * - dnd-disable-if Optional boolean expresssion. When it evaluates to true, no dropping + * into the list is possible. Note that this also disables rearranging + * items inside the list. + * - dnd-horizontal-list Optional boolean expresssion. When it evaluates to true, the positioning + * algorithm will use the left and right halfs of the list items instead of + * the upper and lower halfs. + * - dnd-dragover Optional expression that is invoked when an element is dragged over the + * list. If the expression is set, but does not return true, the element is + * not allowed to be dropped. The following variables will be available: + * - event: The original dragover event sent by the browser. + * - index: The position in the list at which the element would be dropped. + * - type: The dnd-type set on the dnd-draggable, or undefined if unset. + * - dnd-drop Optional expression that is invoked when an element is dropped over the + * list. If the expression is set, it must return the object that will be + * inserted into the list. If it returns false, the drop will be aborted + * and the event is propagated. The following variables will be available: + * - event: The original drop event sent by the browser. + * - index: The position in the list at which the element would be dropped. + * - item: The transferred object. + * - type: The dnd-type set on the dnd-draggable, or undefined if unset. + * - dnd-external-sources Optional boolean expression. When it evaluates to true, the list accepts + * drops from sources outside of the current browser tab. This allows to + * drag and drop accross different browser tabs. Note that this will allow + * to drop arbitrary text into the list, thus it is highly recommended to + * implement the dnd-drop callback to check the incoming element for + * sanity. Furthermore, the dnd-type of external sources can not be + * determined, therefore do not rely on restrictions of dnd-allowed-type. + * + * CSS classes: + * - dndPlaceholder When an element is dragged over the list, a new placeholder child + * element will be added. This element is of type li and has the class + * dndPlaceholder set. + * - dndDragover Will be added to the list while an element is dragged over the list. + */ + .directive('dndList', ['$parse', '$timeout', 'dndDropEffectWorkaround', 'dndDragTypeWorkaround', + function($parse, $timeout, dndDropEffectWorkaround, dndDragTypeWorkaround) { + return function(scope, element, attr) { + // While an element is dragged over the list, this placeholder element is inserted + // at the location where the element would be inserted after dropping + var placeholder = angular.element("
  • "); + var placeholderNode = placeholder[0]; + var listNode = element[0]; + + var horizontal = attr.dndHorizontalList && scope.$eval(attr.dndHorizontalList); + var externalSources = attr.dndExternalSources && scope.$eval(attr.dndExternalSources); + + /** + * The dragover event is triggered "every few hundred milliseconds" while an element + * is being dragged over our list, or over an child element. + */ + element.on('dragover', function(event) { + event = event.originalEvent || event; + + if (!isDropAllowed(event)) { + return true; + } + + // First of all, make sure that the placeholder is shown + // This is especially important if the list is empty + if (placeholderNode.parentNode != listNode) { + element.append(placeholder); + } + + if (event.target !== listNode) { + // Try to find the node direct directly below the list node. + var listItemNode = event.target; + while (listItemNode.parentNode !== listNode && listItemNode.parentNode) { + listItemNode = listItemNode.parentNode; + } + + if (listItemNode.parentNode === listNode && listItemNode !== placeholderNode) { + // If the mouse pointer is in the upper half of the child element, + // we place it before the child element, otherwise below it. + if (isMouseInFirstHalf(event, listItemNode)) { + listNode.insertBefore(placeholderNode, listItemNode); + } else { + listNode.insertBefore(placeholderNode, listItemNode.nextSibling); + } + } + } else { + // This branch is reached when we are dragging directly over the list element. + // Usually we wouldn't need to do anything here, but the IE does not fire it's + // events for the child element, only for the list directly. Therefore we repeat + // the positioning algorithm for IE here. + if (isMouseInFirstHalf(event, placeholderNode, true)) { + // Check if we should move the placeholder element one spot towards the top. + // Note that display none elements will have offsetTop and offsetHeight set to + // zero, therefore we need a special check for them. + while (placeholderNode.previousElementSibling + && (isMouseInFirstHalf(event, placeholderNode.previousElementSibling, true) + || placeholderNode.previousElementSibling.offsetHeight === 0)) { + listNode.insertBefore(placeholderNode, placeholderNode.previousElementSibling); + } + } else { + // Check if we should move the placeholder element one spot towards the bottom + while (placeholderNode.nextElementSibling && + !isMouseInFirstHalf(event, placeholderNode.nextElementSibling, true)) { + listNode.insertBefore(placeholderNode, + placeholderNode.nextElementSibling.nextElementSibling); + } + } + } + + // At this point we invoke the callback, which still can disallow the drop. + // We can't do this earlier because we want to pass the index of the placeholder. + if (attr.dndDragover && !invokeCallback(attr.dndDragover, event)) { + return stopDragover(); + } + + element.addClass("dndDragover"); + event.preventDefault(); + event.stopPropagation(); + return false; + }); + + /** + * When the element is dropped, we use the position of the placeholder element as the + * position where we insert the transferred data. This assumes that the list has exactly + * one child element per array element. + */ + element.on('drop', function(event) { + event = event.originalEvent || event; + + if (!isDropAllowed(event)) return true; + + // The default behavior in Firefox is to interpret the dropped element as URL and + // forward to it. We want to prevent that even if our drop is aborted. + event.preventDefault(); + + // Unserialize the data that was serialized in dragstart. According to the HTML5 specs, + // the "Text" drag type will be converted to text/plain, but IE does not do that. + var data = event.dataTransfer.getData("Text") || event.dataTransfer.getData("text/plain"); + var transferredObject; + try { + transferredObject = JSON.parse(data); + } catch(e) { + return stopDragover(); + } + + // Invoke the callback, which can transform the transferredObject and even abort the drop. + if (attr.dndDrop) { + transferredObject = invokeCallback(attr.dndDrop, event, transferredObject); + if (!transferredObject) { + return stopDragover(); + } + } + + // Retrieve the JSON array and insert the transferred object into it. + var targetArray = scope.$eval(attr.dndList); + scope.$apply(function() { + targetArray.splice(getPlaceholderIndex(), 0, transferredObject); + }); + + // Invoke the callback, after the transfered objrct is added to the new container. + if (attr.dndAfterDrop) { + invokeCallback(attr.dndAfterDrop, event, transferredObject); + } + // In Chrome on Windows the dropEffect will always be none... + // We have to determine the actual effect manually from the allowed effects + if (event.dataTransfer.dropEffect === "none") { + if (event.dataTransfer.effectAllowed === "copy" || + event.dataTransfer.effectAllowed === "move") { + dndDropEffectWorkaround.dropEffect = event.dataTransfer.effectAllowed; + } else { + dndDropEffectWorkaround.dropEffect = event.ctrlKey ? "copy" : "move"; + } + } else { + dndDropEffectWorkaround.dropEffect = event.dataTransfer.dropEffect; + } + + // Clean up + stopDragover(); + event.stopPropagation(); + return false; + }); + + /** + * We have to remove the placeholder when the element is no longer dragged over our list. The + * problem is that the dragleave event is not only fired when the element leaves our list, + * but also when it leaves a child element -- so practically it's fired all the time. As a + * workaround we wait a few milliseconds and then check if the dndDragover class was added + * again. If it is there, dragover must have been called in the meantime, i.e. the element + * is still dragging over the list. If you know a better way of doing this, please tell me! + */ + element.on('dragleave', function(event) { + event = event.originalEvent || event; + + element.removeClass("dndDragover"); + $timeout(function() { + if (!element.hasClass("dndDragover")) { + placeholder.remove(); + } + }, 100); + }); + + /** + * Checks whether the mouse pointer is in the first half of the given target element. + * + * In Chrome we can just use offsetY, but in Firefox we have to use layerY, which only + * works if the child element has position relative. In IE the events are only triggered + * on the listNode instead of the listNodeItem, therefore the mouse positions are + * relative to the parent element of targetNode. + */ + function isMouseInFirstHalf(event, targetNode, relativeToParent) { + var mousePointer = horizontal ? (event.offsetX || event.layerX) + : (event.offsetY || event.layerY); + var targetSize = horizontal ? targetNode.offsetWidth : targetNode.offsetHeight; + var targetPosition = horizontal ? targetNode.offsetLeft : targetNode.offsetTop; + targetPosition = relativeToParent ? targetPosition : 0; + return mousePointer < targetPosition + targetSize / 2; + } + + /** + * Flowable-patched version of isMouseInFirstHalf that uses page and bounding client rect + * instead of the offsetX and layerX properties to determine which half of target the mouse pointer is hovering + * this is more natural since th method now actually works like above, but it also adds some mild + * flickering when sorting inside the list, why its still not in use. + */ + function isMouseInFirstHalf_new(event, targetNode, relativeToParent) { + var targetNodeRect = targetNode.getBoundingClientRect(); + if (horizontal) { + return (event.pageX - targetNodeRect.left) < (targetNodeRect.width / 2); + } + else { + return (event.pageY - targetNodeRect.top) < (targetNodeRect.height / 2); + } + } + /** + * We use the position of the placeholder node to determine at which position of the array the + * object needs to be inserted + */ + function getPlaceholderIndex() { + return Array.prototype.indexOf.call(listNode.children, placeholderNode); + } + + /** + * Checks various conditions that must be fulfilled for a drop to be allowed + */ + function isDropAllowed(event) { + // Disallow drop from external source unless it's allowed explicitly. + if (!dndDragTypeWorkaround.isDragging && !externalSources) return false; + + // Check mimetype. Usually we would use a custom drag type instead of Text, but IE doesn't + // support that. + if (!hasTextMimetype(event.dataTransfer.types)) return false; + + // Now check the dnd-allowed-types against the type of the incoming element. For drops from + // external sources we don't know the type, so it will need to be checked via dnd-drop. + if (attr.dndAllowedTypes && dndDragTypeWorkaround.isDragging) { + var allowed = scope.$eval(attr.dndAllowedTypes); + if (angular.isArray(allowed) && allowed.indexOf(dndDragTypeWorkaround.dragType) === -1) { + return false; + } + } + + // Check whether droping is disabled completely + if (attr.dndDisableIf && scope.$eval(attr.dndDisableIf)) return false; + + return true; + } + + /** + * Small helper function that cleans up if we aborted a drop. + */ + function stopDragover() { + placeholder.remove(); + element.removeClass("dndDragover"); + return true; + } + + /** + * Invokes a callback with some interesting parameters and returns the callbacks return value. + */ + function invokeCallback(expression, event, item) { + return $parse(expression)(scope, { + event: event, + index: getPlaceholderIndex(), + item: item || undefined, + external: !dndDragTypeWorkaround.isDragging, + type: dndDragTypeWorkaround.isDragging ? dndDragTypeWorkaround.dragType : undefined + }); + } + + /** + * Check if the dataTransfer object contains a drag type that we can handle. In old versions + * of IE the types collection will not even be there, so we just assume a drop is possible. + */ + function hasTextMimetype(types) { + if (!types) return true; + for (var i = 0; i < types.length; i++) { + if (types[i] === "Text" || types[i] === "text/plain") return true; + } + + return false; + } + }; + }]) + + /** + * This workaround handles the fact that Internet Explorer does not support drag types other than + * "Text" and "URL". That means we can not know whether the data comes from one of our elements or + * is just some other data like a text selection. As a workaround we save the isDragging flag in + * here. When a dropover event occurs, we only allow the drop if we are already dragging, because + * that means the element is ours. + */ + .factory('dndDragTypeWorkaround', function(){ return {} }) + + /** + * Chrome on Windows does not set the dropEffect field, which we need in dragend to determine + * whether a drag operation was successful. Therefore we have to maintain it in this global + * variable. The bug report for that has been open for years: + * https://code.google.com/p/chromium/issues/detail?id=39399 + */ + .factory('dndDropEffectWorkaround', function(){ return {} }); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js new file mode 100644 index 0000000..d21e062 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-drag-and-drop-lists_1.2.0/angular-drag-and-drop-lists.min.js @@ -0,0 +1 @@ +angular.module("dndLists",[]).directive("dndDraggable",["$parse","$timeout","dndDropEffectWorkaround","dndDragTypeWorkaround",function(e,t,n,r){return function(i,s,o){s.attr("draggable","true");if(o.dndDisableIf){i.$watch(o.dndDisableIf,function(e){s.attr("draggable",!e)})}s.on("dragstart",function(u){u=u.originalEvent||u;u.dataTransfer.setData("Text",angular.toJson(i.$eval(o.dndDraggable)));u.dataTransfer.effectAllowed=o.dndEffectAllowed||"move";s.addClass("dndDragging");t(function(){s.addClass("dndDraggingSource")},0);n.dropEffect="none";r.isDragging=true;r.dragType=o.dndType?i.$eval(o.dndType):undefined;e(o.dndDragstart)(i,{event:u});u.stopPropagation()});s.on("dragend",function(t){t=t.originalEvent||t;var u=n.dropEffect;i.$apply(function(){switch(u){case"move":e(o.dndMoved)(i,{event:t});break;case"copy":e(o.dndCopied)(i,{event:t});break}});s.removeClass("dndDragging");s.removeClass("dndDraggingSource");r.isDragging=false;t.stopPropagation()});s.on("click",function(t){t=t.originalEvent||t;i.$apply(function(){e(o.dndSelected)(i,{event:t})});t.stopPropagation()});s.on("selectstart",function(){if(this.dragDrop)this.dragDrop();return false})}}]).directive("dndList",["$parse","$timeout","dndDropEffectWorkaround","dndDragTypeWorkaround",function(e,t,n,r){return function(i,s,o){function h(e,t,n){var r=l?e.offsetX||e.layerX:e.offsetY||e.layerY;var i=l?t.offsetWidth:t.offsetHeight;var s=l?t.offsetLeft:t.offsetTop;s=n?s:0;return r");var a=u[0];var f=s[0];var l=o.dndHorizontalList&&i.$eval(o.dndHorizontalList);var c=o.dndExternalSources&&i.$eval(o.dndExternalSources);s.on("dragover",function(e){e=e.originalEvent||e;if(!d(e))return true;if(a.parentNode!=f){s.append(u)}if(e.target!==f){var t=e.target;while(t.parentNode!==f&&t.parentNode){t=t.parentNode}if(t.parentNode===f&&t!==a){if(h(e,t)){f.insertBefore(a,t)}else{f.insertBefore(a,t.nextSibling)}}}else{if(h(e,a,true)){while(a.previousElementSibling&&(h(e,a.previousElementSibling,true)||a.previousElementSibling.offsetHeight===0)){f.insertBefore(a,a.previousElementSibling)}}else{while(a.nextElementSibling&&!h(e,a.nextElementSibling,true)){f.insertBefore(a,a.nextElementSibling.nextElementSibling)}}}if(o.dndDragover&&!m(o.dndDragover,e)){return v()}s.addClass("dndDragover");e.preventDefault();e.stopPropagation();return false});s.on("drop",function(e){e=e.originalEvent||e;if(!d(e))return true;e.preventDefault();var t=e.dataTransfer.getData("Text")||e.dataTransfer.getData("text/plain");var r;try{r=JSON.parse(t)}catch(s){return v()}if(o.dndDrop){r=m(o.dndDrop,e,r);if(!r){return v()}}var u=i.$eval(o.dndList);i.$apply(function(){u.splice(p(),0,r)});if(e.dataTransfer.dropEffect==="none"){if(e.dataTransfer.effectAllowed==="copy"||e.dataTransfer.effectAllowed==="move"){n.dropEffect=e.dataTransfer.effectAllowed}else{n.dropEffect=e.ctrlKey?"copy":"move"}}else{n.dropEffect=e.dataTransfer.dropEffect}v();e.stopPropagation();return false});s.on("dragleave",function(e){e=e.originalEvent||e;s.removeClass("dndDragover");t(function(){if(!s.hasClass("dndDragover")){u.remove()}},100)})}}]).factory("dndDragTypeWorkaround",function(){return{}}).factory("dndDropEffectWorkaround",function(){return{}}) diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.js b/zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.js new file mode 100644 index 0000000..20aee96 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.js @@ -0,0 +1,360 @@ +/** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Implementing Drag and Drop functionality in AngularJS is easier than ever. + * Demo: http://codef0rmer.github.com/angular-dragdrop/ + * + * @version 1.0.11 + * + * (c) 2013 Amit Gharat a.k.a codef0rmer - amitgharat.wordpress.com + */ + +(function (window, angular, $, undefined) { + 'use strict'; + + var jqyoui = angular.module('ngDragDrop', []).service('ngDragDropService', ['$timeout', '$parse', function($timeout, $parse) { + this.draggableScope = null; + this.droppableScope = null; + + this.callEventCallback = function (scope, callbackName, event, ui) { + if (!callbackName) return; + + var objExtract = extract(callbackName), + callback = objExtract.callback, + constructor = objExtract.constructor, + args = [event, ui].concat(objExtract.args); + + // call either $scoped method i.e. $scope.dropCallback or constructor's method i.e. this.dropCallback. + // Removing scope.$apply call that was performance intensive (especially onDrag) and does not require it + // always. So call it within the callback if needed. + return (scope[callback] || scope[constructor][callback]).apply(scope, args); + + function extract(callbackName) { + var atStartBracket = callbackName.indexOf('(') !== -1 ? callbackName.indexOf('(') : callbackName.length, + atEndBracket = callbackName.lastIndexOf(')') !== -1 ? callbackName.lastIndexOf(')') : callbackName.length, + args = callbackName.substring(atStartBracket + 1, atEndBracket), // matching function arguments inside brackets + constructor = callbackName.match(/^[^.]+.\s*/)[0].slice(0, -1); // matching a string upto a dot to check ctrl as syntax + constructor = scope[constructor] && typeof scope[constructor].constructor === 'function' ? constructor : null; + + return { + callback: callbackName.substring(constructor && constructor.length + 1 || 0, atStartBracket), + args: $.map(args && args.split(',') || [], function(item) { return [$parse(item)(scope)]; }), + constructor: constructor + } + } + }; + + this.invokeDrop = function ($draggable, $droppable, event, ui) { + var dragModel = '', + dropModel = '', + dragSettings = {}, + dropSettings = {}, + jqyoui_pos = null, + dragItem = {}, + dropItem = {}, + dragModelValue, + dropModelValue, + $droppableDraggable = null, + droppableScope = this.droppableScope, + draggableScope = this.draggableScope; + + dragModel = $draggable.ngattr('ng-model'); + dropModel = $droppable.ngattr('ng-model'); + dragModelValue = draggableScope.$eval(dragModel); + dropModelValue = droppableScope.$eval(dropModel); + + $droppableDraggable = $droppable.find('[jqyoui-draggable]:last,[data-jqyoui-draggable]:last'); + dropSettings = droppableScope.$eval($droppable.attr('jqyoui-droppable') || $droppable.attr('data-jqyoui-droppable')) || []; + dragSettings = draggableScope.$eval($draggable.attr('jqyoui-draggable') || $draggable.attr('data-jqyoui-draggable')) || []; + + // Helps pick up the right item + dragSettings.index = this.fixIndex(draggableScope, dragSettings, dragModelValue); + dropSettings.index = this.fixIndex(droppableScope, dropSettings, dropModelValue); + + jqyoui_pos = angular.isArray(dragModelValue) ? dragSettings.index : null; + dragItem = angular.isArray(dragModelValue) ? dragModelValue[jqyoui_pos] : dragModelValue; + + if (dragSettings.deepCopy) { + dragItem = angular.copy(dragItem); + } + + if (angular.isArray(dropModelValue) && dropSettings && dropSettings.index !== undefined) { + dropItem = dropModelValue[dropSettings.index]; + } else if (!angular.isArray(dropModelValue)) { + dropItem = dropModelValue; + } else { + dropItem = {}; + } + + if (dropSettings.deepCopy) { + dropItem = angular.copy(dropItem); + } + + if (dragSettings.animate === true) { + this.move($draggable, $droppableDraggable.length > 0 ? $droppableDraggable : $droppable, null, 'fast', dropSettings, null); + this.move($droppableDraggable.length > 0 && !dropSettings.multiple ? $droppableDraggable : [], $draggable.parent('[jqyoui-droppable],[data-jqyoui-droppable]'), jqyoui.startXY, 'fast', dropSettings, angular.bind(this, function() { + $timeout(angular.bind(this, function() { + // Do not move this into move() to avoid flickering issue + $draggable.css({'position': 'relative', 'left': '', 'top': ''}); + // Angular v1.2 uses ng-hide to hide an element not display property + // so we've to manually remove display:none set in this.move() + $droppableDraggable.css({'position': 'relative', 'left': '', 'top': '', 'display': $droppableDraggable.css('display') === 'none' ? '' : $droppableDraggable.css('display')}); + + this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable); + this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos); + this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui); + })); + })); + } else { + $timeout(angular.bind(this, function() { + this.mutateDraggable(draggableScope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable); + this.mutateDroppable(droppableScope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos); + this.callEventCallback(droppableScope, dropSettings.onDrop, event, ui); + })); + } + }; + + this.move = function($fromEl, $toEl, toPos, duration, dropSettings, callback) { + if ($fromEl.length === 0) { + if (callback) { + window.setTimeout(function() { + callback(); + }, 300); + } + return false; + } + + var zIndex = $fromEl.css('z-index'), + fromPos = $fromEl[dropSettings.containment || 'offset'](), + displayProperty = $toEl.css('display'), // sometimes `display` is other than `block` + hadNgHideCls = $toEl.hasClass('ng-hide'); + + if (toPos === null && $toEl.length > 0) { + if (($toEl.attr('jqyoui-draggable') || $toEl.attr('data-jqyoui-draggable')) !== undefined && $toEl.ngattr('ng-model') !== undefined && $toEl.is(':visible') && dropSettings && dropSettings.multiple) { + toPos = $toEl[dropSettings.containment || 'offset'](); + if (dropSettings.stack === false) { + toPos.left+= $toEl.outerWidth(true); + } else { + toPos.top+= $toEl.outerHeight(true); + } + } else { + // Angular v1.2 uses ng-hide to hide an element + // so we've to remove it in order to grab its position + if (hadNgHideCls) $toEl.removeClass('ng-hide'); + toPos = $toEl.css({'visibility': 'hidden', 'display': 'block'})[dropSettings.containment || 'offset'](); + $toEl.css({'visibility': '','display': displayProperty}); + } + } + + $fromEl.css({'position': 'absolute', 'z-index': 9999}) + .css(fromPos) + .animate(toPos, duration, function() { + // Angular v1.2 uses ng-hide to hide an element + // and as we remove it above, we've to put it back to + // hide the element (while swapping) if it was hidden already + // because we remove the display:none in this.invokeDrop() + if (hadNgHideCls) $toEl.addClass('ng-hide'); + $fromEl.css('z-index', zIndex); + if (callback) callback(); + }); + }; + + this.mutateDroppable = function(scope, dropSettings, dragSettings, dropModel, dragItem, jqyoui_pos) { + var dropModelValue = scope.$eval(dropModel); + + scope.dndDragItem = dragItem; + + if (angular.isArray(dropModelValue)) { + if (dropSettings && dropSettings.index >= 0) { + dropModelValue[dropSettings.index] = dragItem; + } else { + dropModelValue.push(dragItem); + } + if (dragSettings && dragSettings.placeholder === true) { + dropModelValue[dropModelValue.length - 1]['jqyoui_pos'] = jqyoui_pos; + } + } else { + $parse(dropModel + ' = dndDragItem')(scope); + if (dragSettings && dragSettings.placeholder === true) { + dropModelValue['jqyoui_pos'] = jqyoui_pos; + } + } + }; + + this.mutateDraggable = function(scope, dropSettings, dragSettings, dragModel, dropModel, dropItem, $draggable) { + var isEmpty = angular.equals(dropItem, {}) || !dropItem, + dragModelValue = scope.$eval(dragModel); + + scope.dndDropItem = dropItem; + + if (dragSettings && dragSettings.placeholder) { + if (dragSettings.placeholder != 'keep'){ + if (angular.isArray(dragModelValue) && dragSettings.index !== undefined) { + dragModelValue[dragSettings.index] = dropItem; + } else { + $parse(dragModel + ' = dndDropItem')(scope); + } + } + } else { + if (angular.isArray(dragModelValue)) { + if (isEmpty) { + if (dragSettings && ( dragSettings.placeholder !== true && dragSettings.placeholder !== 'keep' )) { + dragModelValue.splice(dragSettings.index, 1); + } + } else { + dragModelValue[dragSettings.index] = dropItem; + } + } else { + // Fix: LIST(object) to LIST(array) - model does not get updated using just scope[dragModel] = {...} + // P.S.: Could not figure out why it happened + $parse(dragModel + ' = dndDropItem')(scope); + if (scope.$parent) { + $parse(dragModel + ' = dndDropItem')(scope.$parent); + } + } + } + + $draggable.css({'z-index': '', 'left': '', 'top': ''}); + }; + + this.fixIndex = function(scope, settings, modelValue) { + if (settings.applyFilter && angular.isArray(modelValue) && modelValue.length > 0) { + var dragModelValueFiltered = scope[settings.applyFilter](), + lookup = dragModelValueFiltered[settings.index], + actualIndex = undefined; + + modelValue.forEach(function(item, i) { + if (angular.equals(item, lookup)) { + actualIndex = i; + } + }); + + return actualIndex; + } + + return settings.index; + }; + }]).directive('jqyouiDraggable', ['ngDragDropService', function(ngDragDropService) { + return { + require: '?jqyouiDroppable', + restrict: 'A', + link: function(scope, element, attrs) { + var dragSettings, jqyouiOptions, zIndex; + var updateDraggable = function(newValue, oldValue) { + if (newValue) { + dragSettings = scope.$eval(element.attr('jqyoui-draggable') || element.attr('data-jqyoui-draggable')) || {}; + jqyouiOptions = scope.$eval(attrs.jqyouiOptions) || {}; + element + .draggable({disabled: false}) + .draggable(jqyouiOptions) + .draggable({ + start: function(event, ui) { + ngDragDropService.draggableScope = scope; + zIndex = angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index'); + angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index', 9999); + jqyoui.startXY = angular.element(this)[dragSettings.containment || 'offset'](); + ngDragDropService.callEventCallback(scope, dragSettings.onStart, event, ui); + }, + stop: function(event, ui) { + angular.element(jqyouiOptions.helper ? ui.helper : this).css('z-index', zIndex); + ngDragDropService.callEventCallback(scope, dragSettings.onStop, event, ui); + }, + drag: function(event, ui) { + ngDragDropService.callEventCallback(scope, dragSettings.onDrag, event, ui); + } + }); + } else { + element.draggable({disabled: true}); + } + }; + scope.$watch(function() { return scope.$eval(attrs.drag); }, updateDraggable); + updateDraggable(); + + element.on('$destroy', function() { + element.draggable({disabled: true}).draggable('destroy'); + }); + } + }; + }]).directive('jqyouiDroppable', ['ngDragDropService', '$q', function(ngDragDropService, $q) { + return { + restrict: 'A', + priority: 1, + link: function(scope, element, attrs) { + var dropSettings; + var updateDroppable = function(newValue, oldValue) { + if (newValue) { + dropSettings = scope.$eval(angular.element(element).attr('jqyoui-droppable') || angular.element(element).attr('data-jqyoui-droppable')) || {}; + element + .droppable({disabled: false}) + .droppable(scope.$eval(attrs.jqyouiOptions) || {}) + .droppable({ + over: function(event, ui) { + ngDragDropService.callEventCallback(scope, dropSettings.onOver, event, ui); + }, + out: function(event, ui) { + ngDragDropService.callEventCallback(scope, dropSettings.onOut, event, ui); + }, + drop: function(event, ui) { + var beforeDropPromise = null; + + if (dropSettings.beforeDrop) { + beforeDropPromise = ngDragDropService.callEventCallback(scope, dropSettings.beforeDrop, event, ui); + } else { + beforeDropPromise = (function() { + var deferred = $q.defer(); + deferred.resolve(); + return deferred.promise; + })(); + } + + beforeDropPromise.then(angular.bind(this, function() { + if (angular.element(ui.draggable).ngattr('ng-model') && attrs.ngModel) { + ngDragDropService.droppableScope = scope; + ngDragDropService.invokeDrop(angular.element(ui.draggable), angular.element(this), event, ui); + } else { + ngDragDropService.callEventCallback(scope, dropSettings.onDrop, event, ui); + } + }), function() { + ui.draggable.css({left: '', top: ''}); + }); + } + }); + } else { + element.droppable({disabled: true}); + } + }; + + scope.$watch(function() { return scope.$eval(attrs.drop); }, updateDroppable); + updateDroppable(); + + element.on('$destroy', function() { + element.droppable({disabled: true}).droppable('destroy'); + }); + } + }; + }]); + + angular.element.prototype.ngattr = function(name, value) { + var element = angular.element(this).get(0); + + return element.getAttribute(name) || element.getAttribute('data-' + name); + }; +})(window, window.angular, window.jQuery); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js new file mode 100644 index 0000000..bfb1cf8 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-dragdrop_1.0.11/angular-dragdrop.min.js @@ -0,0 +1,29 @@ +/** + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** + * Implementing Drag and Drop functionality in AngularJS is easier than ever. + * Demo: http://codef0rmer.github.com/angular-dragdrop/ + * + * @version 1.0.11 + * + * (c) 2013 Amit Gharat a.k.a codef0rmer - amitgharat.wordpress.com + */ +(function(e,t,n,r){"use strict";var i=t.module("ngDragDrop",[]).service("ngDragDropService",["$timeout","$parse",function(s,o){this.draggableScope=null;this.droppableScope=null;this.callEventCallback=function(e,t,r,i){function l(t){var r=t.indexOf("(")!==-1?t.indexOf("("):t.length,i=t.lastIndexOf(")")!==-1?t.lastIndexOf(")"):t.length,s=t.substring(r+1,i),u=t.match(/^[^.]+.\s*/)[0].slice(0,-1);u=e[u]&&typeof e[u].constructor==="function"?u:null;return{callback:t.substring(u&&u.length+1||0,r),args:n.map(s&&s.split(",")||[],function(t){return[o(t)(e)]}),constructor:u}}if(!t)return;var s=l(t),u=s.callback,a=s.constructor,f=[r,i].concat(s.args);return(e[u]||e[a][u]).apply(e,f)};this.invokeDrop=function(e,n,o,u){var a="",f="",l={},c={},h=null,p={},d={},v,m,g=null,y=this.droppableScope,b=this.draggableScope;a=e.ngattr("ng-model");f=n.ngattr("ng-model");v=b.$eval(a);m=y.$eval(f);g=n.find("[jqyoui-draggable]:last,[data-jqyoui-draggable]:last");c=y.$eval(n.attr("jqyoui-droppable")||n.attr("data-jqyoui-droppable"))||[];l=b.$eval(e.attr("jqyoui-draggable")||e.attr("data-jqyoui-draggable"))||[];l.index=this.fixIndex(b,l,v);c.index=this.fixIndex(y,c,m);h=t.isArray(v)?l.index:null;p=t.isArray(v)?v[h]:v;if(l.deepCopy){p=t.copy(p)}if(t.isArray(m)&&c&&c.index!==r){d=m[c.index]}else if(!t.isArray(m)){d=m}else{d={}}if(c.deepCopy){d=t.copy(d)}if(l.animate===true){this.move(e,g.length>0?g:n,null,"fast",c,null);this.move(g.length>0&&!c.multiple?g:[],e.parent("[jqyoui-droppable],[data-jqyoui-droppable]"),i.startXY,"fast",c,t.bind(this,function(){s(t.bind(this,function(){e.css({position:"relative",left:"",top:""});g.css({position:"relative",left:"",top:"",display:g.css("display")==="none"?"":g.css("display")});this.mutateDraggable(b,c,l,a,f,d,e);this.mutateDroppable(y,c,l,f,p,h);this.callEventCallback(y,c.onDrop,o,u)}))}))}else{s(t.bind(this,function(){this.mutateDraggable(b,c,l,a,f,d,e);this.mutateDroppable(y,c,l,f,p,h);this.callEventCallback(y,c.onDrop,o,u)}))}};this.move=function(t,n,i,s,o,u){if(t.length===0){if(u){e.setTimeout(function(){u()},300)}return false}var a=t.css("z-index"),f=t[o.containment||"offset"](),l=n.css("display"),c=n.hasClass("ng-hide");if(i===null&&n.length>0){if((n.attr("jqyoui-draggable")||n.attr("data-jqyoui-draggable"))!==r&&n.ngattr("ng-model")!==r&&n.is(":visible")&&o&&o.multiple){i=n[o.containment||"offset"]();if(o.stack===false){i.left+=n.outerWidth(true)}else{i.top+=n.outerHeight(true)}}else{if(c)n.removeClass("ng-hide");i=n.css({visibility:"hidden",display:"block"})[o.containment||"offset"]();n.css({visibility:"",display:l})}}t.css({position:"absolute","z-index":9999}).css(f).animate(i,s,function(){if(c)n.addClass("ng-hide");t.css("z-index",a);if(u)u()})};this.mutateDroppable=function(e,n,r,i,s,u){var a=e.$eval(i);e.dndDragItem=s;if(t.isArray(a)){if(n&&n.index>=0){a[n.index]=s}else{a.push(s)}if(r&&r.placeholder===true){a[a.length-1]["jqyoui_pos"]=u}}else{o(i+" = dndDragItem")(e);if(r&&r.placeholder===true){a["jqyoui_pos"]=u}}};this.mutateDraggable=function(e,n,i,s,u,a,f){var l=t.equals(a,{})||!a,c=e.$eval(s);e.dndDropItem=a;if(i&&i.placeholder){if(i.placeholder!="keep"){if(t.isArray(c)&&i.index!==r){c[i.index]=a}else{o(s+" = dndDropItem")(e)}}}else{if(t.isArray(c)){if(l){if(i&&i.placeholder!==true&&i.placeholder!=="keep"){c.splice(i.index,1)}}else{c[i.index]=a}}else{o(s+" = dndDropItem")(e);if(e.$parent){o(s+" = dndDropItem")(e.$parent)}}}f.css({"z-index":"",left:"",top:""})};this.fixIndex=function(e,n,i){if(n.applyFilter&&t.isArray(i)&&i.length>0){var s=e[n.applyFilter](),o=s[n.index],u=r;i.forEach(function(e,n){if(t.equals(e,o)){u=n}});return u}return n.index}}]).directive("jqyouiDraggable",["ngDragDropService",function(e){return{require:"?jqyouiDroppable",restrict:"A",link:function(n,r,s){var o,u,a;var f=function(f,l){if(f){o=n.$eval(r.attr("jqyoui-draggable")||r.attr("data-jqyoui-draggable"))||{};u=n.$eval(s.jqyouiOptions)||{};r.draggable({disabled:false}).draggable(u).draggable({start:function(r,s){e.draggableScope=n;a=t.element(u.helper?s.helper:this).css("z-index");t.element(u.helper?s.helper:this).css("z-index",9999);i.startXY=t.element(this)[o.containment||"offset"]();e.callEventCallback(n,o.onStart,r,s)},stop:function(r,i){t.element(u.helper?i.helper:this).css("z-index",a);e.callEventCallback(n,o.onStop,r,i)},drag:function(t,r){e.callEventCallback(n,o.onDrag,t,r)}})}else{r.draggable({disabled:true})}};n.$watch(function(){return n.$eval(s.drag)},f);f();r.on("$destroy",function(){r.draggable({disabled:true}).draggable("destroy")})}}}]).directive("jqyouiDroppable",["ngDragDropService","$q",function(e,n){return{restrict:"A",priority:1,link:function(r,i,s){var o;var u=function(u,a){if(u){o=r.$eval(t.element(i).attr("jqyoui-droppable")||t.element(i).attr("data-jqyoui-droppable"))||{};i.droppable({disabled:false}).droppable(r.$eval(s.jqyouiOptions)||{}).droppable({over:function(t,n){e.callEventCallback(r,o.onOver,t,n)},out:function(t,n){e.callEventCallback(r,o.onOut,t,n)},drop:function(i,u){var a=null;if(o.beforeDrop){a=e.callEventCallback(r,o.beforeDrop,i,u)}else{a=function(){var e=n.defer();e.resolve();return e.promise}()}a.then(t.bind(this,function(){if(t.element(u.draggable).ngattr("ng-model")&&s.ngModel){e.droppableScope=r;e.invokeDrop(t.element(u.draggable),t.element(this),i,u)}else{e.callEventCallback(r,o.onDrop,i,u)}}),function(){u.draggable.css({left:"",top:""})})}})}else{i.droppable({disabled:true})}};r.$watch(function(){return r.$eval(s.drop)},u);u();i.on("$destroy",function(){i.droppable({disabled:true}).droppable("destroy")})}}}]);t.element.prototype.ngattr=function(e,n){var r=t.element(this).get(0);return r.getAttribute(e)||r.getAttribute("data-"+e)}})(window,window.angular,window.jQuery) \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.js b/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.js new file mode 100644 index 0000000..37b400c --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.js @@ -0,0 +1,2109 @@ +(function(angular) { + + 'use strict'; + + angular.module('gridster', []) + + .constant('gridsterConfig', { + columns: 6, // number of columns in the grid + pushing: true, // whether to push other items out of the way + floating: true, // whether to automatically float items up so they stack + swapping: false, // whether or not to have items switch places instead of push down if they are the same size + width: 'auto', // width of the grid. "auto" will expand the grid to its parent container + colWidth: 'auto', // width of grid columns. "auto" will divide the width of the grid evenly among the columns + rowHeight: 'match', // height of grid rows. 'match' will make it the same as the column width, a numeric value will be interpreted as pixels, '/2' is half the column width, '*5' is five times the column width, etc. + margins: [10, 10], // margins in between grid items + outerMargin: true, + isMobile: false, // toggle mobile view + mobileBreakPoint: 600, // width threshold to toggle mobile mode + mobileModeEnabled: true, // whether or not to toggle mobile mode when screen width is less than mobileBreakPoint + minColumns: 1, // minimum amount of columns the grid can scale down to + minRows: 1, // minimum amount of rows to show if the grid is empty + maxRows: 100, // maximum amount of rows in the grid + defaultSizeX: 2, // default width of an item in columns + defaultSizeY: 1, // default height of an item in rows + minSizeX: 1, // minimum column width of an item + maxSizeX: null, // maximum column width of an item + minSizeY: 1, // minumum row height of an item + maxSizeY: null, // maximum row height of an item + saveGridItemCalculatedHeightInMobile: false, // grid item height in mobile display. true- to use the calculated height by sizeY given + resizable: { // options to pass to resizable handler + enabled: true, + handles: ['s', 'e', 'n', 'w', 'se', 'ne', 'sw', 'nw'] + }, + draggable: { // options to pass to draggable handler + enabled: true, + scrollSensitivity: 20, // Distance in pixels from the edge of the viewport after which the viewport should scroll, relative to pointer + scrollSpeed: 15 // Speed at which the window should scroll once the mouse pointer gets within scrollSensitivity distance + } + }) + + .controller('GridsterCtrl', ['gridsterConfig', '$timeout', + function(gridsterConfig, $timeout) { + + var gridster = this; + + /** + * Create options from gridsterConfig constant + */ + angular.extend(this, gridsterConfig); + + this.resizable = angular.extend({}, gridsterConfig.resizable || {}); + this.draggable = angular.extend({}, gridsterConfig.draggable || {}); + + var flag = false; + this.layoutChanged = function() { + if (flag) { + return; + } + flag = true; + $timeout(function() { + flag = false; + if (gridster.loaded) { + gridster.floatItemsUp(); + } + gridster.updateHeight(gridster.movingItem ? gridster.movingItem.sizeY : 0); + }); + }; + + /** + * A positional array of the items in the grid + */ + this.grid = []; + + /** + * Clean up after yourself + */ + this.destroy = function() { + if (this.grid) { + this.grid.length = 0; + this.grid = null; + } + }; + + /** + * Overrides default options + * + * @param {object} options The options to override + */ + this.setOptions = function(options) { + if (!options) { + return; + } + + options = angular.extend({}, options); + + // all this to avoid using jQuery... + if (options.draggable) { + angular.extend(this.draggable, options.draggable); + delete(options.draggable); + } + if (options.resizable) { + angular.extend(this.resizable, options.resizable); + delete(options.resizable); + } + + angular.extend(this, options); + + if (!this.margins || this.margins.length !== 2) { + this.margins = [0, 0]; + } else { + for (var x = 0, l = this.margins.length; x < l; ++x) { + this.margins[x] = parseInt(this.margins[x], 10); + if (isNaN(this.margins[x])) { + this.margins[x] = 0; + } + } + } + }; + + /** + * Check if item can occupy a specified position in the grid + * + * @param {object} item The item in question + * @param {number} row The row index + * @param {number} column The column index + * @returns {boolean} True if if item fits + */ + this.canItemOccupy = function(item, row, column) { + return row > -1 && column > -1 && item.sizeX + column <= this.columns && item.sizeY + row <= this.maxRows; + }; + + /** + * Set the item in the first suitable position + * + * @param {object} item The item to insert + */ + this.autoSetItemPosition = function(item) { + // walk through each row and column looking for a place it will fit + for (var rowIndex = 0; rowIndex < this.maxRows; ++rowIndex) { + for (var colIndex = 0; colIndex < this.columns; ++colIndex) { + // only insert if position is not already taken and it can fit + var items = this.getItems(rowIndex, colIndex, item.sizeX, item.sizeY, item); + if (items.length === 0 && this.canItemOccupy(item, rowIndex, colIndex)) { + this.putItem(item, rowIndex, colIndex); + return; + } + } + } + throw new Error('Unable to place item!'); + }; + + /** + * Gets items at a specific coordinate + * + * @param {number} row + * @param {number} column + * @param {number} sizeX + * @param {number} sizeY + * @param {array} excludeItems An array of items to exclude from selection + * @returns {array} Items that match the criteria + */ + this.getItems = function(row, column, sizeX, sizeY, excludeItems) { + var items = []; + if (!sizeX || !sizeY) { + sizeX = sizeY = 1; + } + if (excludeItems && !(excludeItems instanceof Array)) { + excludeItems = [excludeItems]; + } + for (var h = 0; h < sizeY; ++h) { + for (var w = 0; w < sizeX; ++w) { + var item = this.getItem(row + h, column + w, excludeItems); + if (item && (!excludeItems || excludeItems.indexOf(item) === -1) && items.indexOf(item) === -1) { + items.push(item); + } + } + } + return items; + }; + + this.getBoundingBox = function(items) { + + if (items.length === 0) { + return null; + } + if (items.length === 1) { + return { + row: items[0].row, + col: items[0].col, + sizeY: items[0].sizeY, + sizeX: items[0].sizeX + }; + } + + var maxRow = 0; + var maxCol = 0; + var minRow = 9999; + var minCol = 9999; + + for (var i = 0, l = items.length; i < l; ++i) { + var item = items[i]; + minRow = Math.min(item.row, minRow); + minCol = Math.min(item.col, minCol); + maxRow = Math.max(item.row + item.sizeY, maxRow); + maxCol = Math.max(item.col + item.sizeX, maxCol); + } + + return { + row: minRow, + col: minCol, + sizeY: maxRow - minRow, + sizeX: maxCol - minCol + }; + }; + + + /** + * Removes an item from the grid + * + * @param {object} item + */ + this.removeItem = function(item) { + for (var rowIndex = 0, l = this.grid.length; rowIndex < l; ++rowIndex) { + var columns = this.grid[rowIndex]; + if (!columns) { + continue; + } + var index = columns.indexOf(item); + if (index !== -1) { + columns[index] = null; + break; + } + } + this.layoutChanged(); + }; + + /** + * Returns the item at a specified coordinate + * + * @param {number} row + * @param {number} column + * @param {array} excludeitems Items to exclude from selection + * @returns {object} The matched item or null + */ + this.getItem = function(row, column, excludeItems) { + if (excludeItems && !(excludeItems instanceof Array)) { + excludeItems = [excludeItems]; + } + var sizeY = 1; + while (row > -1) { + var sizeX = 1, + col = column; + while (col > -1) { + var items = this.grid[row]; + if (items) { + var item = items[col]; + if (item && (!excludeItems || excludeItems.indexOf(item) === -1) && item.sizeX >= sizeX && item.sizeY >= sizeY) { + return item; + } + } + ++sizeX; + --col; + } + --row; + ++sizeY; + } + return null; + }; + + /** + * Insert an array of items into the grid + * + * @param {array} items An array of items to insert + */ + this.putItems = function(items) { + for (var i = 0, l = items.length; i < l; ++i) { + this.putItem(items[i]); + } + }; + + /** + * Insert a single item into the grid + * + * @param {object} item The item to insert + * @param {number} row (Optional) Specifies the items row index + * @param {number} column (Optional) Specifies the items column index + * @param {array} ignoreItems + */ + this.putItem = function(item, row, column, ignoreItems) { + if (typeof row === 'undefined' || row === null) { + row = item.row; + column = item.col; + if (typeof row === 'undefined' || row === null) { + this.autoSetItemPosition(item); + return; + } + } + if (!this.canItemOccupy(item, row, column)) { + column = Math.min(this.columns - item.sizeX, Math.max(0, column)); + row = Math.min(this.maxRows - item.sizeY, Math.max(0, row)); + } + + if (item.oldRow !== null && typeof item.oldRow !== 'undefined') { + var samePosition = item.oldRow === row && item.oldColumn === column; + var inGrid = this.grid[row] && this.grid[row][column] === item; + if (samePosition && inGrid) { + item.row = row; + item.col = column; + return; + } else { + // remove from old position + var oldRow = this.grid[item.oldRow]; + if (oldRow && oldRow[item.oldColumn] === item) { + delete oldRow[item.oldColumn]; + } + } + } + + item.oldRow = item.row = row; + item.oldColumn = item.col = column; + + this.moveOverlappingItems(item, ignoreItems); + + if (!this.grid[row]) { + this.grid[row] = []; + } + this.grid[row][column] = item; + + if (this.movingItem === item) { + this.floatItemUp(item); + } + this.layoutChanged(); + }; + + /** + * Trade row and column if item1 with item2 + * + * @param {object} item1 + * @param {object} item2 + */ + this.swapItems = function(item1, item2) { + this.grid[item1.row][item1.col] = item2; + this.grid[item2.row][item2.col] = item1; + + var item1Row = item1.row; + var item1Col = item1.col; + item1.row = item2.row; + item1.col = item2.col; + item2.row = item1Row; + item2.col = item1Col; + }; + + /** + * Prevents items from being overlapped + * + * @param {object} item The item that should remain + * @param {array} ignoreItems + */ + this.moveOverlappingItems = function(item, ignoreItems) { + if (ignoreItems) { + if (ignoreItems.indexOf(item) === -1) { + ignoreItems = ignoreItems.slice(0); + ignoreItems.push(item); + } + } else { + ignoreItems = [item]; + } + var overlappingItems = this.getItems( + item.row, + item.col, + item.sizeX, + item.sizeY, + ignoreItems + ); + this.moveItemsDown(overlappingItems, item.row + item.sizeY, ignoreItems); + }; + + /** + * Moves an array of items to a specified row + * + * @param {array} items The items to move + * @param {number} newRow The target row + * @param {array} ignoreItems + */ + this.moveItemsDown = function(items, newRow, ignoreItems) { + if (!items || items.length === 0) { + return; + } + items.sort(function(a, b) { + return a.row - b.row; + }); + ignoreItems = ignoreItems ? ignoreItems.slice(0) : []; + var topRows = {}, + item, i, l; + // calculate the top rows in each column + for (i = 0, l = items.length; i < l; ++i) { + item = items[i]; + var topRow = topRows[item.col]; + if (typeof topRow === 'undefined' || item.row < topRow) { + topRows[item.col] = item.row; + } + } + // move each item down from the top row in its column to the row + for (i = 0, l = items.length; i < l; ++i) { + item = items[i]; + var rowsToMove = newRow - topRows[item.col]; + this.moveItemDown(item, item.row + rowsToMove, ignoreItems); + ignoreItems.push(item); + } + }; + + this.moveItemDown = function(item, newRow, ignoreItems) { + if (item.row >= newRow) { + return; + } + while (item.row < newRow) { + ++item.row; + this.moveOverlappingItems(item, ignoreItems); + } + this.putItem(item, item.row, item.col, ignoreItems); + }; + + /** + * Moves all items up as much as possible + */ + this.floatItemsUp = function() { + if (this.floating === false) { + return; + } + for (var rowIndex = 0, l = this.grid.length; rowIndex < l; ++rowIndex) { + var columns = this.grid[rowIndex]; + if (!columns) { + continue; + } + for (var colIndex = 0, len = columns.length; colIndex < len; ++colIndex) { + var item = columns[colIndex]; + if (item) { + this.floatItemUp(item); + } + } + } + }; + + /** + * Float an item up to the most suitable row + * + * @param {object} item The item to move + */ + this.floatItemUp = function(item) { + if (this.floating === false) { + return; + } + var colIndex = item.col, + sizeY = item.sizeY, + sizeX = item.sizeX, + bestRow = null, + bestColumn = null, + rowIndex = item.row - 1; + + while (rowIndex > -1) { + var items = this.getItems(rowIndex, colIndex, sizeX, sizeY, item); + if (items.length !== 0) { + break; + } + bestRow = rowIndex; + bestColumn = colIndex; + --rowIndex; + } + if (bestRow !== null) { + this.putItem(item, bestRow, bestColumn); + } + }; + + /** + * Update gridsters height + * + * @param {number} plus (Optional) Additional height to add + */ + this.updateHeight = function(plus) { + var maxHeight = this.minRows; + plus = plus || 0; + for (var rowIndex = this.grid.length; rowIndex >= 0; --rowIndex) { + var columns = this.grid[rowIndex]; + if (!columns) { + continue; + } + for (var colIndex = 0, len = columns.length; colIndex < len; ++colIndex) { + if (columns[colIndex]) { + maxHeight = Math.max(maxHeight, rowIndex + plus + columns[colIndex].sizeY); + } + } + } + this.gridHeight = this.maxRows - maxHeight > 0 ? Math.min(this.maxRows, maxHeight) : Math.max(this.maxRows, maxHeight); + }; + + /** + * Returns the number of rows that will fit in given amount of pixels + * + * @param {number} pixels + * @param {boolean} ceilOrFloor (Optional) Determines rounding method + */ + this.pixelsToRows = function(pixels, ceilOrFloor) { + if (ceilOrFloor === true) { + return Math.ceil(pixels / this.curRowHeight); + } else if (ceilOrFloor === false) { + return Math.floor(pixels / this.curRowHeight); + } + + return Math.round(pixels / this.curRowHeight); + }; + + /** + * Returns the number of columns that will fit in a given amount of pixels + * + * @param {number} pixels + * @param {boolean} ceilOrFloor (Optional) Determines rounding method + * @returns {number} The number of columns + */ + this.pixelsToColumns = function(pixels, ceilOrFloor) { + if (ceilOrFloor === true) { + return Math.ceil(pixels / this.curColWidth); + } else if (ceilOrFloor === false) { + return Math.floor(pixels / this.curColWidth); + } + + return Math.round(pixels / this.curColWidth); + }; + + // unified input handling + // adopted from a msdn blogs sample + this.unifiedInput = function(target, startEvent, moveEvent, endEvent) { + var lastXYById = {}; + + // Opera doesn't have Object.keys so we use this wrapper + var numberOfKeys = function(theObject) { + if (Object.keys) { + return Object.keys(theObject).length; + } + + var n = 0, + key; + for (key in theObject) { + ++n; + } + + return n; + }; + + // this calculates the delta needed to convert pageX/Y to offsetX/Y because offsetX/Y don't exist in the TouchEvent object or in Firefox's MouseEvent object + var computeDocumentToElementDelta = function(theElement) { + var elementLeft = 0; + var elementTop = 0; + var oldIEUserAgent = navigator.userAgent.match(/\bMSIE\b/); + + for (var offsetElement = theElement; offsetElement != null; offsetElement = offsetElement.offsetParent) { + // the following is a major hack for versions of IE less than 8 to avoid an apparent problem on the IEBlog with double-counting the offsets + // this may not be a general solution to IE7's problem with offsetLeft/offsetParent + if (oldIEUserAgent && + (!document.documentMode || document.documentMode < 8) && + offsetElement.currentStyle.position === 'relative' && offsetElement.offsetParent && offsetElement.offsetParent.currentStyle.position === 'relative' && offsetElement.offsetLeft === offsetElement.offsetParent.offsetLeft) { + // add only the top + elementTop += offsetElement.offsetTop; + } else { + elementLeft += offsetElement.offsetLeft; + elementTop += offsetElement.offsetTop; + } + } + + return { + x: elementLeft, + y: elementTop + }; + }; + + // cache the delta from the document to our event target (reinitialized each mousedown/MSPointerDown/touchstart) + var documentToTargetDelta = computeDocumentToElementDelta(target); + + // common event handler for the mouse/pointer/touch models and their down/start, move, up/end, and cancel events + var doEvent = function(theEvtObj) { + + if (theEvtObj.type === 'mousemove' && numberOfKeys(lastXYById) === 0) { + return; + } + + var prevent = true; + + var pointerList = theEvtObj.changedTouches ? theEvtObj.changedTouches : [theEvtObj]; + for (var i = 0; i < pointerList.length; ++i) { + var pointerObj = pointerList[i]; + var pointerId = (typeof pointerObj.identifier !== 'undefined') ? pointerObj.identifier : (typeof pointerObj.pointerId !== 'undefined') ? pointerObj.pointerId : 1; + + // use the pageX/Y coordinates to compute target-relative coordinates when we have them (in ie < 9, we need to do a little work to put them there) + if (typeof pointerObj.pageX === 'undefined') { + // initialize assuming our source element is our target + pointerObj.pageX = pointerObj.offsetX + documentToTargetDelta.x; + pointerObj.pageY = pointerObj.offsetY + documentToTargetDelta.y; + + if (pointerObj.srcElement.offsetParent === target && document.documentMode && document.documentMode === 8 && pointerObj.type === 'mousedown') { + // source element is a child piece of VML, we're in IE8, and we've not called setCapture yet - add the origin of the source element + pointerObj.pageX += pointerObj.srcElement.offsetLeft; + pointerObj.pageY += pointerObj.srcElement.offsetTop; + } else if (pointerObj.srcElement !== target && !document.documentMode || document.documentMode < 8) { + // source element isn't the target (most likely it's a child piece of VML) and we're in a version of IE before IE8 - + // the offsetX/Y values are unpredictable so use the clientX/Y values and adjust by the scroll offsets of its parents + // to get the document-relative coordinates (the same as pageX/Y) + var sx = -2, + sy = -2; // adjust for old IE's 2-pixel border + for (var scrollElement = pointerObj.srcElement; scrollElement !== null; scrollElement = scrollElement.parentNode) { + sx += scrollElement.scrollLeft ? scrollElement.scrollLeft : 0; + sy += scrollElement.scrollTop ? scrollElement.scrollTop : 0; + } + + pointerObj.pageX = pointerObj.clientX + sx; + pointerObj.pageY = pointerObj.clientY + sy; + } + } + + + var pageX = pointerObj.pageX; + var pageY = pointerObj.pageY; + + if (theEvtObj.type.match(/(start|down)$/i)) { + // clause for processing MSPointerDown, touchstart, and mousedown + + // refresh the document-to-target delta on start in case the target has moved relative to document + documentToTargetDelta = computeDocumentToElementDelta(target); + + // protect against failing to get an up or end on this pointerId + if (lastXYById[pointerId]) { + if (endEvent) { + endEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + + delete lastXYById[pointerId]; + } + + if (startEvent) { + if (prevent) { + prevent = startEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + } + + // init last page positions for this pointer + lastXYById[pointerId] = { + x: pageX, + y: pageY + }; + + // IE pointer model + if (target.msSetPointerCapture) { + target.msSetPointerCapture(pointerId); + } else if (theEvtObj.type === 'mousedown' && numberOfKeys(lastXYById) === 1) { + if (useSetReleaseCapture) { + target.setCapture(true); + } else { + document.addEventListener('mousemove', doEvent, false); + document.addEventListener('mouseup', doEvent, false); + } + } + } else if (theEvtObj.type.match(/move$/i)) { + // clause handles mousemove, MSPointerMove, and touchmove + + if (lastXYById[pointerId] && !(lastXYById[pointerId].x === pageX && lastXYById[pointerId].y === pageY)) { + // only extend if the pointer is down and it's not the same as the last point + + if (moveEvent && prevent) { + prevent = moveEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + + // update last page positions for this pointer + lastXYById[pointerId].x = pageX; + lastXYById[pointerId].y = pageY; + } + } else if (lastXYById[pointerId] && theEvtObj.type.match(/(up|end|cancel)$/i)) { + // clause handles up/end/cancel + + if (endEvent && prevent) { + prevent = endEvent({ + target: theEvtObj.target, + which: theEvtObj.which, + pointerId: pointerId, + pageX: pageX, + pageY: pageY + }); + } + + // delete last page positions for this pointer + delete lastXYById[pointerId]; + + // in the Microsoft pointer model, release the capture for this pointer + // in the mouse model, release the capture or remove document-level event handlers if there are no down points + // nothing is required for the iOS touch model because capture is implied on touchstart + if (target.msReleasePointerCapture) { + target.msReleasePointerCapture(pointerId); + } else if (theEvtObj.type === 'mouseup' && numberOfKeys(lastXYById) === 0) { + if (useSetReleaseCapture) { + target.releaseCapture(); + } else { + document.removeEventListener('mousemove', doEvent, false); + document.removeEventListener('mouseup', doEvent, false); + } + } + } + } + + if (prevent) { + if (theEvtObj.preventDefault) { + theEvtObj.preventDefault(); + } + + if (theEvtObj.preventManipulation) { + theEvtObj.preventManipulation(); + } + + if (theEvtObj.preventMouseEvent) { + theEvtObj.preventMouseEvent(); + } + } + }; + + var useSetReleaseCapture = false; + // saving the settings for contentZooming and touchaction before activation + var contentZooming, msTouchAction; + + this.enable = function() { + + if (window.navigator.msPointerEnabled) { + // Microsoft pointer model + target.addEventListener('MSPointerDown', doEvent, false); + target.addEventListener('MSPointerMove', doEvent, false); + target.addEventListener('MSPointerUp', doEvent, false); + target.addEventListener('MSPointerCancel', doEvent, false); + + // css way to prevent panning in our target area + if (typeof target.style.msContentZooming !== 'undefined') { + contentZooming = target.style.msContentZooming; + target.style.msContentZooming = 'none'; + } + + // new in Windows Consumer Preview: css way to prevent all built-in touch actions on our target + // without this, you cannot touch draw on the element because IE will intercept the touch events + if (typeof target.style.msTouchAction !== 'undefined') { + msTouchAction = target.style.msTouchAction; + target.style.msTouchAction = 'none'; + } + } else if (target.addEventListener) { + // iOS touch model + target.addEventListener('touchstart', doEvent, false); + target.addEventListener('touchmove', doEvent, false); + target.addEventListener('touchend', doEvent, false); + target.addEventListener('touchcancel', doEvent, false); + + // mouse model + target.addEventListener('mousedown', doEvent, false); + + // mouse model with capture + // rejecting gecko because, unlike ie, firefox does not send events to target when the mouse is outside target + if (target.setCapture && !window.navigator.userAgent.match(/\bGecko\b/)) { + useSetReleaseCapture = true; + + target.addEventListener('mousemove', doEvent, false); + target.addEventListener('mouseup', doEvent, false); + } + } else if (target.attachEvent && target.setCapture) { + // legacy IE mode - mouse with capture + useSetReleaseCapture = true; + target.attachEvent('onmousedown', function() { + doEvent(window.event); + window.event.returnValue = false; + return false; + }); + target.attachEvent('onmousemove', function() { + doEvent(window.event); + window.event.returnValue = false; + return false; + }); + target.attachEvent('onmouseup', function() { + doEvent(window.event); + window.event.returnValue = false; + return false; + }); + } + }; + + this.disable = function() { + if (window.navigator.msPointerEnabled) { + // Microsoft pointer model + target.removeEventListener('MSPointerDown', doEvent, false); + target.removeEventListener('MSPointerMove', doEvent, false); + target.removeEventListener('MSPointerUp', doEvent, false); + target.removeEventListener('MSPointerCancel', doEvent, false); + + // reset zooming to saved value + if (contentZooming) { + target.style.msContentZooming = contentZooming; + } + + // reset touch action setting + if (msTouchAction) { + target.style.msTouchAction = msTouchAction; + } + } else if (target.removeEventListener) { + // iOS touch model + target.removeEventListener('touchstart', doEvent, false); + target.removeEventListener('touchmove', doEvent, false); + target.removeEventListener('touchend', doEvent, false); + target.removeEventListener('touchcancel', doEvent, false); + + // mouse model + target.removeEventListener('mousedown', doEvent, false); + + // mouse model with capture + // rejecting gecko because, unlike ie, firefox does not send events to target when the mouse is outside target + if (target.setCapture && !window.navigator.userAgent.match(/\bGecko\b/)) { + useSetReleaseCapture = true; + + target.removeEventListener('mousemove', doEvent, false); + target.removeEventListener('mouseup', doEvent, false); + } + } else if (target.detachEvent && target.setCapture) { + // legacy IE mode - mouse with capture + useSetReleaseCapture = true; + target.detachEvent('onmousedown'); + target.detachEvent('onmousemove'); + target.detachEvent('onmouseup'); + } + }; + + return this; + }; + + } + ]) + + /** + * The gridster directive + * + * @param {object} $parse + * @param {object} $timeout + */ + .directive('gridster', ['$timeout', '$rootScope', '$window', + function($timeout, $rootScope, $window) { + return { + restrict: 'EAC', + // without transclude, some child items may lose their parent scope + transclude: true, + replace: true, + template: '
    ', + controller: 'GridsterCtrl', + controllerAs: 'gridster', + scope: { + config: '=?gridster' + }, + compile: function() { + + return function(scope, $elem, attrs, gridster) { + gridster.loaded = false; + + scope.gridsterClass = function() { + return { + gridster: true, + 'gridster-desktop': !gridster.isMobile, + 'gridster-mobile': gridster.isMobile, + 'gridster-loaded': gridster.loaded + }; + }; + + /** + * @returns {Object} style object for preview element + */ + scope.previewStyle = function() { + if (!gridster.movingItem) { + return { + display: 'none' + }; + } + + return { + display: 'block', + height: (gridster.movingItem.sizeY * gridster.curRowHeight - gridster.margins[0]) + 'px', + width: (gridster.movingItem.sizeX * gridster.curColWidth - gridster.margins[1]) + 'px', + top: (gridster.movingItem.row * gridster.curRowHeight + (gridster.outerMargin ? gridster.margins[0] : 0)) + 'px', + left: (gridster.movingItem.col * gridster.curColWidth + (gridster.outerMargin ? gridster.margins[1] : 0)) + 'px' + }; + }; + + var refresh = function() { + gridster.setOptions(scope.config); + + // resolve "auto" & "match" values + if (gridster.width === 'auto') { + gridster.curWidth = $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + } else { + gridster.curWidth = gridster.width; + } + + if (gridster.colWidth === 'auto') { + gridster.curColWidth = (gridster.curWidth + (gridster.outerMargin ? -gridster.margins[1] : gridster.margins[1])) / gridster.columns; + } else { + gridster.curColWidth = gridster.colWidth; + } + + gridster.curRowHeight = gridster.rowHeight; + if (typeof gridster.rowHeight === 'string') { + if (gridster.rowHeight === 'match') { + gridster.curRowHeight = Math.round(gridster.curColWidth); + } else if (gridster.rowHeight.indexOf('*') !== -1) { + gridster.curRowHeight = Math.round(gridster.curColWidth * gridster.rowHeight.replace('*', '').replace(' ', '')); + } else if (gridster.rowHeight.indexOf('/') !== -1) { + gridster.curRowHeight = Math.round(gridster.curColWidth / gridster.rowHeight.replace('/', '').replace(' ', '')); + } + } + + gridster.isMobile = gridster.mobileModeEnabled && gridster.curWidth <= gridster.mobileBreakPoint; + + // loop through all items and reset their CSS + for (var rowIndex = 0, l = gridster.grid.length; rowIndex < l; ++rowIndex) { + var columns = gridster.grid[rowIndex]; + if (!columns) { + continue; + } + + for (var colIndex = 0, len = columns.length; colIndex < len; ++colIndex) { + if (columns[colIndex]) { + var item = columns[colIndex]; + item.setElementPosition(); + item.setElementSizeY(); + item.setElementSizeX(); + } + } + } + + updateHeight(); + }; + + // update grid items on config changes + scope.$watch('config', refresh, true); + + scope.$watch('config.draggable', function() { + $rootScope.$broadcast('gridster-draggable-changed'); + }, true); + + scope.$watch('config.resizable', function() { + $rootScope.$broadcast('gridster-resizable-changed'); + }, true); + + var updateHeight = function() { + $elem.css('height', (gridster.gridHeight * gridster.curRowHeight) + (gridster.outerMargin ? gridster.margins[0] : -gridster.margins[0]) + 'px'); + }; + + scope.$watch('gridster.gridHeight', updateHeight); + + scope.$watch('gridster.movingItem', function() { + gridster.updateHeight(gridster.movingItem ? gridster.movingItem.sizeY : 0); + }); + + var prevWidth = $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + + function resize() { + var width = $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + + if (!width || width === prevWidth || gridster.movingItem) { + return; + } + prevWidth = width; + + if (gridster.loaded) { + $elem.removeClass('gridster-loaded'); + } + + refresh(); + + if (gridster.loaded) { + $elem.addClass('gridster-loaded'); + } + + scope.$parent.$broadcast('gridster-resized', [width, $elem.offsetHeight]); + } + + // track element width changes any way we can + function onResize() { + resize(); + $timeout(function() { + scope.$apply(); + }); + } + if (typeof $elem.resize === 'function') { + $elem.resize(onResize); + } + var $win = angular.element($window); + $win.on('resize', onResize); + + scope.$watch(function() { + return $elem[0].offsetWidth || parseInt($elem.css('width'), 10); + }, resize); + + // be sure to cleanup + scope.$on('$destroy', function() { + gridster.destroy(); + $win.off('resize', onResize); + }); + + // allow a little time to place items before floating up + $timeout(function() { + scope.$watch('gridster.floating', function() { + gridster.floatItemsUp(); + }); + gridster.loaded = true; + }, 100); + + + + // Custom code + + /** + * Callback called when starting to drag from palette to canvas. + */ + $rootScope.startDragCallback = function (event, ui) { + $timeout(function () { + var fieldId = event.target.id; + var fieldType; + + var colspan = 1; + if (fieldId === 'group' || fieldId === 'dynamic-table') { + colspan = 2; + } + + var numberOfRows = 1; + if (fieldId === 'multi-line-text') { + numberOfRows = 2; + } else if (fieldId === 'dynamic-table') { + numberOfRows = 2; + } + + scope.startDragItem = { + type: fieldId, + fieldType: fieldType, + name: 'Label', + required: false, + readOnly: false, + sizeX: colspan, + sizeY: numberOfRows, + row: -1, + col: -1 + }; + + if (fieldId === 'radio-buttons' || fieldId === 'dropdown') { + scope.startDragItem.options = [ + {name: 'Option 1'} + ]; + } + + }, 0); + }; + + /** + * Callback called when stopping to drag from palette to canvas. + */ + $rootScope.dropCallback = function (event, ui) { + $timeout(function () { + gridster.movingItem = null; + var offset = jQuery($elem[0]).offset(); + var row = gridster.pixelsToRows(event.clientY - offset.top, true) - 1; + var column = gridster.pixelsToColumns(event.clientX - offset.left, true) - 1; + if (row >= 0 && column >= 0) { + + scope.startDragItem.row = row; + scope.startDragItem.col = column; + } + }, 0); + }; + + /** + * Callback called during dragging from palette to canvas. + */ + $rootScope.dragCallback = function (event, ui) { + + var offset = jQuery($elem[0]).offset(); + var row = gridster.pixelsToRows(event.clientY - offset.top, true) - 1; + var column = gridster.pixelsToColumns(event.clientX - offset.left, true) - 1; + + if (!scope.startDragItem) { + return; + } + + if (scope.startDragItem.row === row && scope.startDragItem.col === column) { + return; + } + + if ( ((scope.startDragItem.row === -1 || scope.startDragItem.col === -1) && row >= 0 && column >= 0) + || (scope.startDragItem.row >= 0 && scope.startDragItem.col >= 0 && (row < 0 || column < 0)) ) { + $timeout(function () { + if ((scope.startDragItem.row === -1 || scope.startDragItem.col === -1) && row >= 0 && column >= 0) { + scope.$parent.formItems.push(scope.startDragItem); + + gridster.movingItem = scope.startDragItem; + gridster.updateHeight(1); + } + + if (scope.startDragItem.row >= 0 && scope.startDragItem.col >= 0 && (row < 0 || column < 0)) { + scope.$parent.formItems.pop(); + gridster.movingItem = null; + } + + + }, 0); + } + + $timeout(function () { + scope.startDragItem.row = row; + scope.startDragItem.col = column; + }, 0); + + }; + + // END custom code + + + }; + } + }; + } + ]) + + .controller('GridsterItemCtrl', function() { + this.$element = null; + this.gridster = null; + this.row = null; + this.col = null; + this.sizeX = null; + this.sizeY = null; + this.minSizeX = 0; + this.minSizeY = 0; + this.maxSizeX = null; + this.maxSizeY = null; + + this.init = function($element, gridster) { + this.$element = $element; + this.gridster = gridster; + this.sizeX = gridster.defaultSizeX; + this.sizeY = gridster.defaultSizeY; + }; + + this.destroy = function() { + this.gridster = null; + this.$element = null; + }; + + /** + * Returns the items most important attributes + */ + this.toJSON = function() { + return { + row: this.row, + col: this.col, + sizeY: this.sizeY, + sizeX: this.sizeX + }; + }; + + this.isMoving = function() { + return this.gridster.movingItem === this; + }; + + /** + * Set the items position + * + * @param {number} row + * @param {number} column + */ + this.setPosition = function(row, column) { + this.gridster.putItem(this, row, column); + + if (!this.isMoving()) { + this.setElementPosition(); + } + }; + + /** + * Sets a specified size property + * + * @param {string} key Can be either "x" or "y" + * @param {number} value The size amount + */ + this.setSize = function(key, value, preventMove) { + key = key.toUpperCase(); + var camelCase = 'size' + key, + titleCase = 'Size' + key; + if (value === '') { + return; + } + value = parseInt(value, 10); + if (isNaN(value) || value === 0) { + value = this.gridster['default' + titleCase]; + } + var max = key === 'X' ? this.gridster.columns : this.gridster.maxRows; + if (this['max' + titleCase]) { + max = Math.min(this['max' + titleCase], max); + } + if (this.gridster['max' + titleCase]) { + max = Math.min(this.gridster['max' + titleCase], max); + } + if (key === 'X' && this.cols) { + max -= this.cols; + } else if (key === 'Y' && this.rows) { + max -= this.rows; + } + + var min = 0; + if (this['min' + titleCase]) { + min = Math.max(this['min' + titleCase], min); + } + if (this.gridster['min' + titleCase]) { + min = Math.max(this.gridster['min' + titleCase], min); + } + + value = Math.max(Math.min(value, max), min); + + var changed = (this[camelCase] !== value || (this['old' + titleCase] && this['old' + titleCase] !== value)); + this['old' + titleCase] = this[camelCase] = value; + + if (!this.isMoving()) { + this['setElement' + titleCase](); + } + if (!preventMove && changed) { + this.gridster.moveOverlappingItems(this); + this.gridster.layoutChanged(); + } + + return changed; + }; + + /** + * Sets the items sizeY property + * + * @param {number} rows + */ + this.setSizeY = function(rows, preventMove) { + return this.setSize('Y', rows, preventMove); + }; + + /** + * Sets the items sizeX property + * + * @param {number} rows + */ + this.setSizeX = function(columns, preventMove) { + return this.setSize('X', columns, preventMove); + }; + + /** + * Sets an elements position on the page + * + * @param {number} row + * @param {number} column + */ + this.setElementPosition = function() { + if (this.gridster.isMobile) { + this.$element.css({ + marginLeft: this.gridster.margins[0] + 'px', + marginRight: this.gridster.margins[0] + 'px', + marginTop: this.gridster.margins[1] + 'px', + marginBottom: this.gridster.margins[1] + 'px', + top: '', + left: '' + }); + } else { + this.$element.css({ + margin: 0, + top: (this.row * this.gridster.curRowHeight + (this.gridster.outerMargin ? this.gridster.margins[0] : 0)) + 'px', + left: (this.col * this.gridster.curColWidth + (this.gridster.outerMargin ? this.gridster.margins[1] : 0)) + 'px' + }); + } + }; + + /** + * Sets an elements height + */ + this.setElementSizeY = function() { + if (this.gridster.isMobile && !this.gridster.saveGridItemCalculatedHeightInMobile) { + this.$element.css('height', ''); + } else { + this.$element.css('height', (this.sizeY * this.gridster.curRowHeight - this.gridster.margins[0]) + 'px'); + } + }; + + /** + * Sets an elements width + */ + this.setElementSizeX = function() { + if (this.gridster.isMobile) { + this.$element.css('width', ''); + } else { + this.$element.css('width', (this.sizeX * this.gridster.curColWidth - this.gridster.margins[1]) + 'px'); + } + }; + + /** + * Gets an element's width + */ + this.getElementSizeX = function() { + return (this.sizeX * this.gridster.curColWidth - this.gridster.margins[1]); + }; + + /** + * Gets an element's height + */ + this.getElementSizeY = function() { + return (this.sizeY * this.gridster.curRowHeight - this.gridster.margins[0]); + }; + + }) + + .factory('GridsterDraggable', ['$document', '$timeout', '$window', + function($document, $timeout, $window) { + function GridsterDraggable($el, scope, gridster, item, itemOptions) { + + var elmX, elmY, elmW, elmH, + + mouseX = 0, + mouseY = 0, + lastMouseX = 0, + lastMouseY = 0, + mOffX = 0, + mOffY = 0, + + minTop = 0, + maxTop = 9999, + minLeft = 0, + realdocument = $document[0]; + + var originalCol, originalRow; + var inputTags = ['select', 'input', 'textarea', 'button']; + + function mouseDown(e) { + if (inputTags.indexOf(e.target.nodeName.toLowerCase()) !== -1) { + return false; + } + + // exit, if a resize handle was hit + if (angular.element(e.target).hasClass('gridster-item-resizable-handler')) { + return false; + } + + // exit, if the target has it's own click event + if (angular.element(e.target).attr('onclick') || angular.element(e.target).attr('ng-click')) { + return false; + } + + switch (e.which) { + case 1: + // left mouse button + break; + case 2: + case 3: + // right or middle mouse button + return; + } + + lastMouseX = e.pageX; + lastMouseY = e.pageY; + + elmX = parseInt($el.css('left'), 10); + elmY = parseInt($el.css('top'), 10); + elmW = $el[0].offsetWidth; + elmH = $el[0].offsetHeight; + + originalCol = item.col; + originalRow = item.row; + + dragStart(e); + + return true; + } + + function mouseMove(e) { + if (!$el.hasClass('gridster-item-moving') || $el.hasClass('gridster-item-resizing')) { + return false; + } + + var maxLeft = gridster.curWidth - 1; + + // Get the current mouse position. + mouseX = e.pageX; + mouseY = e.pageY; + + // Get the deltas + var diffX = mouseX - lastMouseX + mOffX; + var diffY = mouseY - lastMouseY + mOffY; + mOffX = mOffY = 0; + + // Update last processed mouse positions. + lastMouseX = mouseX; + lastMouseY = mouseY; + + var dX = diffX, + dY = diffY; + if (elmX + dX < minLeft) { + diffX = minLeft - elmX; + mOffX = dX - diffX; + } else if (elmX + elmW + dX > maxLeft) { + diffX = maxLeft - elmX - elmW; + mOffX = dX - diffX; + } + + if (elmY + dY < minTop) { + diffY = minTop - elmY; + mOffY = dY - diffY; + } else if (elmY + elmH + dY > maxTop) { + diffY = maxTop - elmY - elmH; + mOffY = dY - diffY; + } + elmX += diffX; + elmY += diffY; + + // set new position + $el.css({ + 'top': elmY + 'px', + 'left': elmX + 'px' + }); + + drag(e); + + return true; + } + + function mouseUp(e) { + if (!$el.hasClass('gridster-item-moving') || $el.hasClass('gridster-item-resizing')) { + return false; + } + + mOffX = mOffY = 0; + + dragStop(e); + + return true; + } + + function dragStart(event) { + $el.addClass('gridster-item-moving'); + gridster.movingItem = item; + + gridster.updateHeight(item.sizeY); + scope.$apply(function() { + if (gridster.draggable && gridster.draggable.start) { + gridster.draggable.start(event, $el, itemOptions); + } + }); + } + + function drag(event) { + var oldRow = item.row, + oldCol = item.col, + hasCallback = gridster.draggable && gridster.draggable.drag, + scrollSensitivity = gridster.draggable.scrollSensitivity, + scrollSpeed = gridster.draggable.scrollSpeed; + + var row = gridster.pixelsToRows(elmY); + var col = gridster.pixelsToColumns(elmX); + + var itemsInTheWay = gridster.getItems(row, col, item.sizeX, item.sizeY, item); + var hasItemsInTheWay = itemsInTheWay.length !== 0; + + if (gridster.swapping === true && hasItemsInTheWay) { + var boundingBoxItem = gridster.getBoundingBox(itemsInTheWay); + var sameSize = boundingBoxItem.sizeX === item.sizeX && boundingBoxItem.sizeY === item.sizeY; + var sameRow = boundingBoxItem.row === row; + var sameCol = boundingBoxItem.col === col; + var samePosition = sameRow && sameCol; + var inline = sameRow || sameCol; + + if (sameSize && itemsInTheWay.length === 1) { + if (samePosition) { + gridster.swapItems(item, itemsInTheWay[0]); + } else if (inline) { + return; + } + } else if (boundingBoxItem.sizeX <= item.sizeX && boundingBoxItem.sizeY <= item.sizeY && inline) { + var emptyRow = item.row <= row ? item.row : row + item.sizeY; + var emptyCol = item.col <= col ? item.col : col + item.sizeX; + var rowOffset = emptyRow - boundingBoxItem.row; + var colOffset = emptyCol - boundingBoxItem.col; + + for (var i = 0, l = itemsInTheWay.length; i < l; ++i) { + var itemInTheWay = itemsInTheWay[i]; + + var itemsInFreeSpace = gridster.getItems( + itemInTheWay.row + rowOffset, + itemInTheWay.col + colOffset, + itemInTheWay.sizeX, + itemInTheWay.sizeY, + item + ); + + if (itemsInFreeSpace.length === 0) { + gridster.putItem(itemInTheWay, itemInTheWay.row + rowOffset, itemInTheWay.col + colOffset); + } + } + } + } + + if (gridster.pushing !== false || !hasItemsInTheWay) { + item.row = row; + item.col = col; + } + + if (event.pageY - realdocument.body.scrollTop < scrollSensitivity) { + realdocument.body.scrollTop = realdocument.body.scrollTop - scrollSpeed; + } else if ($window.innerHeight - (event.pageY - realdocument.body.scrollTop) < scrollSensitivity) { + realdocument.body.scrollTop = realdocument.body.scrollTop + scrollSpeed; + } + + if (event.pageX - realdocument.body.scrollLeft < scrollSensitivity) { + realdocument.body.scrollLeft = realdocument.body.scrollLeft - scrollSpeed; + } else if ($window.innerWidth - (event.pageX - realdocument.body.scrollLeft) < scrollSensitivity) { + realdocument.body.scrollLeft = realdocument.body.scrollLeft + scrollSpeed; + } + + if (hasCallback || oldRow !== item.row || oldCol !== item.col) { + scope.$apply(function() { + if (hasCallback) { + gridster.draggable.drag(event, $el, itemOptions); + } + }); + } + } + + function dragStop(event) { + $el.removeClass('gridster-item-moving'); + var row = gridster.pixelsToRows(elmY); + var col = gridster.pixelsToColumns(elmX); + if (gridster.pushing !== false || gridster.getItems(row, col, item.sizeX, item.sizeY, item).length === 0) { + item.row = row; + item.col = col; + } + gridster.movingItem = null; + item.setPosition(item.row, item.col); + + scope.$apply(function() { + if (gridster.draggable && gridster.draggable.stop) { + gridster.draggable.stop(event, $el, itemOptions); + } + }); + } + + var enabled = false; + var $dragHandle = null; + var unifiedInput; + + this.enable = function() { + var self = this; + // disable and timeout required for some template rendering + $timeout(function() { + self.disable(); + + if (gridster.draggable && gridster.draggable.handle) { + $dragHandle = angular.element($el[0].querySelector(gridster.draggable.handle)); + if ($dragHandle.length === 0) { + // fall back to element if handle not found... + $dragHandle = $el; + } + } else { + $dragHandle = $el; + } + + unifiedInput = new gridster.unifiedInput($dragHandle[0], mouseDown, mouseMove, mouseUp); + unifiedInput.enable(); + + enabled = true; + }); + }; + + this.disable = function() { + if (!enabled) { + return; + } + + unifiedInput.disable(); + unifiedInput = undefined; + enabled = false; + }; + + this.toggle = function(enabled) { + if (enabled) { + this.enable(); + } else { + this.disable(); + } + }; + + this.destroy = function() { + this.disable(); + }; + } + + return GridsterDraggable; + } + ]) + + .factory('GridsterResizable', [ + function() { + function GridsterResizable($el, scope, gridster, item, itemOptions) { + + function ResizeHandle(handleClass) { + + var hClass = handleClass; + + var elmX, elmY, elmW, elmH, + + mouseX = 0, + mouseY = 0, + lastMouseX = 0, + lastMouseY = 0, + mOffX = 0, + mOffY = 0, + + minTop = 0, + maxTop = 9999, + minLeft = 0; + + var getMinHeight = function() { + return gridster.curRowHeight - gridster.margins[0]; + }; + var getMinWidth = function() { + return gridster.curColWidth - gridster.margins[1]; + }; + + var originalWidth, originalHeight; + var savedDraggable; + + function mouseDown(e) { + switch (e.which) { + case 1: + // left mouse button + break; + case 2: + case 3: + // right or middle mouse button + return; + } + + // save the draggable setting to restore after resize + savedDraggable = gridster.draggable.enabled; + if (savedDraggable) { + gridster.draggable.enabled = false; + scope.$broadcast('gridster-draggable-changed'); + } + + // Get the current mouse position. + lastMouseX = e.pageX; + lastMouseY = e.pageY; + + // Record current widget dimensions + elmX = parseInt($el.css('left'), 10); + elmY = parseInt($el.css('top'), 10); + elmW = $el[0].offsetWidth; + elmH = $el[0].offsetHeight; + + originalWidth = item.sizeX; + originalHeight = item.sizeY; + + resizeStart(e); + + return true; + } + + function resizeStart(e) { + $el.addClass('gridster-item-moving'); + $el.addClass('gridster-item-resizing'); + + gridster.movingItem = item; + + item.setElementSizeX(); + item.setElementSizeY(); + item.setElementPosition(); + gridster.updateHeight(1); + + scope.$apply(function() { + // callback + if (gridster.resizable && gridster.resizable.start) { + gridster.resizable.start(e, $el, itemOptions); // options is the item model + } + }); + } + + function mouseMove(e) { + var maxLeft = gridster.curWidth - 1; + + // Get the current mouse position. + mouseX = e.pageX; + mouseY = e.pageY; + + // Get the deltas + var diffX = mouseX - lastMouseX + mOffX; + var diffY = mouseY - lastMouseY + mOffY; + mOffX = mOffY = 0; + + // Update last processed mouse positions. + lastMouseX = mouseX; + lastMouseY = mouseY; + + var dY = diffY, + dX = diffX; + + if (hClass.indexOf('n') >= 0) { + if (elmH - dY < getMinHeight()) { + diffY = elmH - getMinHeight(); + mOffY = dY - diffY; + } else if (elmY + dY < minTop) { + diffY = minTop - elmY; + mOffY = dY - diffY; + } + elmY += diffY; + elmH -= diffY; + } + if (hClass.indexOf('s') >= 0) { + if (elmH + dY < getMinHeight()) { + diffY = getMinHeight() - elmH; + mOffY = dY - diffY; + } else if (elmY + elmH + dY > maxTop) { + diffY = maxTop - elmY - elmH; + mOffY = dY - diffY; + } + elmH += diffY; + } + if (hClass.indexOf('w') >= 0) { + if (elmW - dX < getMinWidth()) { + diffX = elmW - getMinWidth(); + mOffX = dX - diffX; + } else if (elmX + dX < minLeft) { + diffX = minLeft - elmX; + mOffX = dX - diffX; + } + elmX += diffX; + elmW -= diffX; + } + if (hClass.indexOf('e') >= 0) { + if (elmW + dX < getMinWidth()) { + diffX = getMinWidth() - elmW; + mOffX = dX - diffX; + } else if (elmX + elmW + dX > maxLeft) { + diffX = maxLeft - elmX - elmW; + mOffX = dX - diffX; + } + elmW += diffX; + } + + // set new position + $el.css({ + 'top': elmY + 'px', + 'left': elmX + 'px', + 'width': elmW + 'px', + 'height': elmH + 'px' + }); + + resize(e); + + return true; + } + + function mouseUp(e) { + // restore draggable setting to its original state + if (gridster.draggable.enabled !== savedDraggable) { + gridster.draggable.enabled = savedDraggable; + scope.$broadcast('gridster-draggable-changed'); + } + + mOffX = mOffY = 0; + + resizeStop(e); + + return true; + } + + function resize(e) { + var oldRow = item.row, + oldCol = item.col, + oldSizeX = item.sizeX, + oldSizeY = item.sizeY, + hasCallback = gridster.resizable && gridster.resizable.resize; + + var col = item.col; + // only change column if grabbing left edge + if (['w', 'nw', 'sw'].indexOf(handleClass) !== -1) { + col = gridster.pixelsToColumns(elmX, false); + } + + var row = item.row; + // only change row if grabbing top edge + if (['n', 'ne', 'nw'].indexOf(handleClass) !== -1) { + row = gridster.pixelsToRows(elmY, false); + } + + var sizeX = item.sizeX; + // only change row if grabbing left or right edge + if (['n', 's'].indexOf(handleClass) === -1) { + sizeX = gridster.pixelsToColumns(elmW, true); + } + + var sizeY = item.sizeY; + // only change row if grabbing top or bottom edge + if (['e', 'w'].indexOf(handleClass) === -1) { + sizeY = gridster.pixelsToRows(elmH, true); + } + + if (gridster.pushing !== false || gridster.getItems(row, col, sizeX, sizeY, item).length === 0) { + item.row = row; + item.col = col; + item.sizeX = sizeX; + item.sizeY = sizeY; + } + var isChanged = item.row !== oldRow || item.col !== oldCol || item.sizeX !== oldSizeX || item.sizeY !== oldSizeY; + + if (hasCallback || isChanged) { + scope.$apply(function() { + if (hasCallback) { + gridster.resizable.resize(e, $el, itemOptions); // options is the item model + } + }); + } + } + + function resizeStop(e) { + $el.removeClass('gridster-item-moving'); + $el.removeClass('gridster-item-resizing'); + + gridster.movingItem = null; + + item.setPosition(item.row, item.col); + item.setSizeY(item.sizeY); + item.setSizeX(item.sizeX); + + scope.$apply(function() { + if (gridster.resizable && gridster.resizable.stop) { + gridster.resizable.stop(e, $el, itemOptions); // options is the item model + } + }); + } + + var $dragHandle = null; + var unifiedInput; + + this.enable = function() { + if (!$dragHandle) { + $dragHandle = angular.element('
    '); + $el.append($dragHandle); + } + + unifiedInput = new gridster.unifiedInput($dragHandle[0], mouseDown, mouseMove, mouseUp); + unifiedInput.enable(); + }; + + this.disable = function() { + if ($dragHandle) { + $dragHandle.remove(); + $dragHandle = null; + } + + unifiedInput.disable(); + unifiedInput = undefined; + }; + + this.destroy = function() { + this.disable(); + }; + } + + var handles = []; + var handlesOpts = gridster.resizable.handles; + if (typeof handlesOpts === 'string') { + handlesOpts = gridster.resizable.handles.split(','); + } + var enabled = false; + + for (var c = 0, l = handlesOpts.length; c < l; c++) { + handles.push(new ResizeHandle(handlesOpts[c])); + } + + this.enable = function() { + if (enabled) { + return; + } + for (var c = 0, l = handles.length; c < l; c++) { + handles[c].enable(); + } + enabled = true; + }; + + this.disable = function() { + if (!enabled) { + return; + } + for (var c = 0, l = handles.length; c < l; c++) { + handles[c].disable(); + } + enabled = false; + }; + + this.toggle = function(enabled) { + if (enabled) { + this.enable(); + } else { + this.disable(); + } + }; + + this.destroy = function() { + for (var c = 0, l = handles.length; c < l; c++) { + handles[c].destroy(); + } + }; + } + return GridsterResizable; + } + ]) + + /** + * GridsterItem directive + */ + .directive('gridsterItem', ['$parse', 'GridsterDraggable', 'GridsterResizable', + function($parse, GridsterDraggable, GridsterResizable) { + return { + restrict: 'EA', + controller: 'GridsterItemCtrl', + require: ['^gridster', 'gridsterItem'], + link: function(scope, $el, attrs, controllers) { + var optionsKey = attrs.gridsterItem, + options; + + var gridster = controllers[0], + item = controllers[1]; + + // bind the item's position properties + if (optionsKey) { + var $optionsGetter = $parse(optionsKey); + options = $optionsGetter(scope) || {}; + if (!options && $optionsGetter.assign) { + options = { + row: item.row, + col: item.col, + sizeX: item.sizeX, + sizeY: item.sizeY, + minSizeX: 0, + minSizeY: 0, + maxSizeX: null, + maxSizeY: null + }; + $optionsGetter.assign(scope, options); + } + } else { + options = attrs; + } + + item.init($el, gridster); + + $el.addClass('gridster-item'); + + var aspects = ['minSizeX', 'maxSizeX', 'minSizeY', 'maxSizeY', 'sizeX', 'sizeY', 'row', 'col'], + $getters = {}; + + var aspectFn = function(aspect) { + var key; + if (typeof options[aspect] === 'string') { + key = options[aspect]; + } else if (typeof options[aspect.toLowerCase()] === 'string') { + key = options[aspect.toLowerCase()]; + } else if (optionsKey) { + key = $parse(optionsKey + '.' + aspect); + } else { + return; + } + $getters[aspect] = $parse(key); + + // when the value changes externally, update the internal item object + scope.$watch(key, function(newVal) { + newVal = parseInt(newVal, 10); + if (!isNaN(newVal)) { + item[aspect] = newVal; + } + }); + + // initial set + var val = $getters[aspect](scope); + if (typeof val === 'number') { + item[aspect] = val; + } + }; + + for (var i = 0, l = aspects.length; i < l; ++i) { + aspectFn(aspects[i]); + } + + scope.$broadcast('gridster-item-initialized', [item.sizeY, item.sizeX, item.getElementSizeY(), item.getElementSizeX()]); + + function positionChanged() { + // call setPosition so the element and gridster controller are updated + item.setPosition(item.row, item.col); + + // when internal item position changes, update externally bound values + if ($getters.row && $getters.row.assign) { + $getters.row.assign(scope, item.row); + } + if ($getters.col && $getters.col.assign) { + $getters.col.assign(scope, item.col); + } + } + scope.$watch(function() { + return item.row + ',' + item.col; + }, positionChanged); + + function sizeChanged() { + var changedX = item.setSizeX(item.sizeX, true); + if (changedX && $getters.sizeX && $getters.sizeX.assign) { + $getters.sizeX.assign(scope, item.sizeX); + } + var changedY = item.setSizeY(item.sizeY, true); + if (changedY && $getters.sizeY && $getters.sizeY.assign) { + $getters.sizeY.assign(scope, item.sizeY); + } + + if (changedX || changedY) { + item.gridster.moveOverlappingItems(item); + gridster.layoutChanged(); + } + } + scope.$watch(function() { + return item.sizeY + ',' + item.sizeX + '|' + item.minSizeX + ',' + item.maxSizeX + ',' + item.minSizeY + ',' + item.maxSizeY; + }, sizeChanged); + + var draggable = new GridsterDraggable($el, scope, gridster, item, options); + var resizable = new GridsterResizable($el, scope, gridster, item, options); + + scope.$on('gridster-draggable-changed', function() { + draggable.toggle(!gridster.isMobile && gridster.draggable && gridster.draggable.enabled); + }); + scope.$on('gridster-resizable-changed', function() { + resizable.toggle(!gridster.isMobile && gridster.resizable && gridster.resizable.enabled); + }); + scope.$on('gridster-resized', function() { + resizable.toggle(!gridster.isMobile && gridster.resizable && gridster.resizable.enabled); + }); + scope.$watch(function() { + return gridster.isMobile; + }, function() { + resizable.toggle(!gridster.isMobile && gridster.resizable && gridster.resizable.enabled); + draggable.toggle(!gridster.isMobile && gridster.draggable && gridster.draggable.enabled); + }); + + function whichTransitionEvent() { + var el = document.createElement('div'); + var transitions = { + 'transition': 'transitionend', + 'OTransition': 'oTransitionEnd', + 'MozTransition': 'transitionend', + 'WebkitTransition': 'webkitTransitionEnd' + }; + for (var t in transitions) { + if (el.style[t] !== undefined) { + return transitions[t]; + } + } + } + + $el.on(whichTransitionEvent(), function() { + scope.$apply(function() { + scope.$broadcast('gridster-item-transition-end'); + }); + }); + + return scope.$on('$destroy', function() { + try { + resizable.destroy(); + draggable.destroy(); + } catch (e) {} + + try { + gridster.removeItem(item); + } catch (e) {} + + try { + item.destroy(); + } catch (e) {} + }); + } + }; + } + ]) + + ; + +})(angular); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.css b/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.css new file mode 100644 index 0000000..3976680 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.css @@ -0,0 +1 @@ +.gridster{position:relative;margin:auto;height:0}.gridster-content>ul{margin:0;list-style:none;padding:0}.gridster-item{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;list-style:none;z-index:2;position:absolute;display:none}.gridster-loaded{-webkit-transition:height .3s;-moz-transition:height .3s;-o-transition:height .3s;transition:height .3s}.gridster-loaded .gridster-item{display:block;position:absolute;-webkit-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-moz-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;-o-transition:opacity .3s, left .3s, top .3s, width .3s, height .3s;transition:opacity .3s, left .3s, top .3s, width .3s, height .3s}.gridster-mobile{height:auto !important}.gridster-mobile .gridster-item{height:auto;position:static;float:none}.gridster-preview-holder{display:none;z-index:1;position:absolute;background-color:#ddd;border-color:#fff;opacity:0.2}.gridster-item.gridster-item-moving,.gridster-item.gridster-preview-holder{-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.gridster-item.ng-leave.ng-leave-active{opacity:0}.gridster-item.ng-enter{opacity:1}.gridster-item-moving{z-index:3}.gridster-item-resizable-handler{position:absolute;font-size:1px;display:block}.handle-se{cursor:se-resize;width:0;height:0;right:1px;bottom:1px;border-style:solid;border-width:0 0 12px 12px;border-color:transparent}.handle-ne{cursor:ne-resize;width:12px;height:12px;right:1px;top:1px}.handle-nw{cursor:nw-resize;width:12px;height:12px;left:1px;top:1px}.handle-sw{cursor:sw-resize;width:12px;height:12px;left:1px;bottom:1px}.handle-e{cursor:e-resize;width:12px;bottom:0;right:1px;top:0}.handle-s{cursor:s-resize;height:12px;right:0;bottom:1px;left:0}.handle-n{cursor:n-resize;height:12px;right:0;top:1px;left:0}.handle-w{cursor:w-resize;width:12px;left:1px;top:0;bottom:0}.gridster .gridster-item:hover .gridster-box{border:1.5px solid #B3B2B3}.gridster .gridster-item:hover .handle-se{border-color:transparent transparent #ccc} \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.js new file mode 100644 index 0000000..79eb6a6 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-gridster_0.11.7/angular-gridster.min.js @@ -0,0 +1,8 @@ +/* + * angular-gridster + * http://manifestwebdesign.github.io/angular-gridster + * + * @version: 0.11.7 + * @license: MIT + */ +!function(a){"use strict";a.module("gridster",[]).constant("gridsterConfig",{columns:6,pushing:!0,floating:!0,swapping:!1,width:"auto",colWidth:"auto",rowHeight:"match",margins:[10,10],outerMargin:!0,isMobile:!1,mobileBreakPoint:600,mobileModeEnabled:!0,minColumns:1,minRows:1,maxRows:100,defaultSizeX:2,defaultSizeY:1,minSizeX:1,maxSizeX:null,minSizeY:1,maxSizeY:null,saveGridItemCalculatedHeightInMobile:!1,resizable:{enabled:!0,handles:["s","e","n","w","se","ne","sw","nw"]},draggable:{enabled:!0,scrollSensitivity:20,scrollSpeed:15}}).controller("GridsterCtrl",["gridsterConfig","$timeout",function(b,c){var d=this;a.extend(this,b),this.resizable=a.extend({},b.resizable||{}),this.draggable=a.extend({},b.draggable||{});var e=!1;this.layoutChanged=function(){e||(e=!0,c(function(){e=!1,d.loaded&&d.floatItemsUp(),d.updateHeight(d.movingItem?d.movingItem.sizeY:0)}))},this.grid=[],this.destroy=function(){this.grid&&(this.grid.length=0,this.grid=null)},this.setOptions=function(b){if(b)if(b=a.extend({},b),b.draggable&&(a.extend(this.draggable,b.draggable),delete b.draggable),b.resizable&&(a.extend(this.resizable,b.resizable),delete b.resizable),a.extend(this,b),this.margins&&2===this.margins.length)for(var c=0,d=this.margins.length;d>c;++c)this.margins[c]=parseInt(this.margins[c],10),isNaN(this.margins[c])&&(this.margins[c]=0);else this.margins=[0,0]},this.canItemOccupy=function(a,b,c){return b>-1&&c>-1&&a.sizeX+c<=this.columns&&a.sizeY+b<=this.maxRows},this.autoSetItemPosition=function(a){for(var b=0;bg;++g)for(var h=0;c>h;++h){var i=this.getItem(a+g,b+h,e);!i||e&&-1!==e.indexOf(i)||-1!==f.indexOf(i)||f.push(i)}return f},this.getBoundingBox=function(a){if(0===a.length)return null;if(1===a.length)return{row:a[0].row,col:a[0].col,sizeY:a[0].sizeY,sizeX:a[0].sizeX};for(var b=0,c=0,d=9999,e=9999,f=0,g=a.length;g>f;++f){var h=a[f];d=Math.min(h.row,d),e=Math.min(h.col,e),b=Math.max(h.row+h.sizeY,b),c=Math.max(h.col+h.sizeX,c)}return{row:d,col:e,sizeY:b-d,sizeX:c-e}},this.removeItem=function(a){for(var b=0,c=this.grid.length;c>b;++b){var d=this.grid[b];if(d){var e=d.indexOf(a);if(-1!==e){d[e]=null;break}}}this.layoutChanged()},this.getItem=function(a,b,c){!c||c instanceof Array||(c=[c]);for(var d=1;a>-1;){for(var e=1,f=b;f>-1;){var g=this.grid[a];if(g){var h=g[f];if(h&&(!c||-1===c.indexOf(h))&&h.sizeX>=e&&h.sizeY>=d)return h}++e,--f}--a,++d}return null},this.putItems=function(a){for(var b=0,c=a.length;c>b;++b)this.putItem(a[b])},this.putItem=function(a,b,c,d){if(("undefined"==typeof b||null===b)&&(b=a.row,c=a.col,"undefined"==typeof b||null===b))return void this.autoSetItemPosition(a);if(this.canItemOccupy(a,b,c)||(c=Math.min(this.columns-a.sizeX,Math.max(0,c)),b=Math.min(this.maxRows-a.sizeY,Math.max(0,b))),null!==a.oldRow&&"undefined"!=typeof a.oldRow){var e=a.oldRow===b&&a.oldColumn===c,f=this.grid[b]&&this.grid[b][c]===a;if(e&&f)return a.row=b,void(a.col=c);var g=this.grid[a.oldRow];g&&g[a.oldColumn]===a&&delete g[a.oldColumn]}a.oldRow=a.row=b,a.oldColumn=a.col=c,this.moveOverlappingItems(a,d),this.grid[b]||(this.grid[b]=[]),this.grid[b][c]=a,this.movingItem===a&&this.floatItemUp(a),this.layoutChanged()},this.swapItems=function(a,b){this.grid[a.row][a.col]=b,this.grid[b.row][b.col]=a;var c=a.row,d=a.col;a.row=b.row,a.col=b.col,b.row=c,b.col=d},this.moveOverlappingItems=function(a,b){b?-1===b.indexOf(a)&&(b=b.slice(0),b.push(a)):b=[a];var c=this.getItems(a.row,a.col,a.sizeX,a.sizeY,b);this.moveItemsDown(c,a.row+a.sizeY,b)},this.moveItemsDown=function(a,b,c){if(a&&0!==a.length){a.sort(function(a,b){return a.row-b.row}),c=c?c.slice(0):[];var d,e,f,g={};for(e=0,f=a.length;f>e;++e){d=a[e];var h=g[d.col];("undefined"==typeof h||d.rowe;++e){d=a[e];var i=b-g[d.col];this.moveItemDown(d,d.row+i,c),c.push(d)}}},this.moveItemDown=function(a,b,c){if(!(a.row>=b)){for(;a.rowa;++a){var c=this.grid[a];if(c)for(var d=0,e=c.length;e>d;++d){var f=c[d];f&&this.floatItemUp(f)}}},this.floatItemUp=function(a){if(this.floating!==!1){for(var b=a.col,c=a.sizeY,d=a.sizeX,e=null,f=null,g=a.row-1;g>-1;){var h=this.getItems(g,b,d,c,a);if(0!==h.length)break;e=g,f=b,--g}null!==e&&this.putItem(a,e,f)}},this.updateHeight=function(a){var b=this.minRows;a=a||0;for(var c=this.grid.length;c>=0;--c){var d=this.grid[c];if(d)for(var e=0,f=d.length;f>e;++e)d[e]&&(b=Math.max(b,c+a+d[e].sizeY))}this.gridHeight=this.maxRows-b>0?Math.min(this.maxRows,b):Math.max(this.maxRows,b)},this.pixelsToRows=function(a,b){return b===!0?Math.ceil(a/this.curRowHeight):b===!1?Math.floor(a/this.curRowHeight):Math.round(a/this.curRowHeight)},this.pixelsToColumns=function(a,b){return b===!0?Math.ceil(a/this.curColWidth):b===!1?Math.floor(a/this.curColWidth):Math.round(a/this.curColWidth)},this.unifiedInput=function(a,b,c,d){var e,f,g={},h=function(a){if(Object.keys)return Object.keys(a).length;var b,c=0;for(b in a)++c;return c},i=function(a){for(var b=0,c=0,d=navigator.userAgent.match(/\bMSIE\b/),e=a;null!=e;e=e.offsetParent)d&&(!document.documentMode||document.documentMode<8)&&"relative"===e.currentStyle.position&&e.offsetParent&&"relative"===e.offsetParent.currentStyle.position&&e.offsetLeft===e.offsetParent.offsetLeft?c+=e.offsetTop:(b+=e.offsetLeft,c+=e.offsetTop);return{x:b,y:c}},j=i(a),k=function(e){if("mousemove"!==e.type||0!==h(g)){for(var f=!0,m=e.changedTouches?e.changedTouches:[e],n=0;n
    ',controller:"GridsterCtrl",controllerAs:"gridster",scope:{config:"=?gridster"},compile:function(){return function(e,f,g,h){function i(){var a=f[0].offsetWidth||parseInt(f.css("width"),10);a&&a!==m&&!h.movingItem&&(m=a,h.loaded&&f.removeClass("gridster-loaded"),k(),h.loaded&&f.addClass("gridster-loaded"),e.$parent.$broadcast("gridster-resized",[a,f.offsetHeight]))}function j(){i(),b(function(){e.$apply()})}h.loaded=!1,e.gridsterClass=function(){return{gridster:!0,"gridster-desktop":!h.isMobile,"gridster-mobile":h.isMobile,"gridster-loaded":h.loaded}},e.previewStyle=function(){return h.movingItem?{display:"block",height:h.movingItem.sizeY*h.curRowHeight-h.margins[0]+"px",width:h.movingItem.sizeX*h.curColWidth-h.margins[1]+"px",top:h.movingItem.row*h.curRowHeight+(h.outerMargin?h.margins[0]:0)+"px",left:h.movingItem.col*h.curColWidth+(h.outerMargin?h.margins[1]:0)+"px"}:{display:"none"}};var k=function(){h.setOptions(e.config),h.curWidth="auto"===h.width?f[0].offsetWidth||parseInt(f.css("width"),10):h.width,h.curColWidth="auto"===h.colWidth?(h.curWidth+(h.outerMargin?-h.margins[1]:h.margins[1]))/h.columns:h.colWidth,h.curRowHeight=h.rowHeight,"string"==typeof h.rowHeight&&("match"===h.rowHeight?h.curRowHeight=Math.round(h.curColWidth):-1!==h.rowHeight.indexOf("*")?h.curRowHeight=Math.round(h.curColWidth*h.rowHeight.replace("*","").replace(" ","")):-1!==h.rowHeight.indexOf("/")&&(h.curRowHeight=Math.round(h.curColWidth/h.rowHeight.replace("/","").replace(" ","")))),h.isMobile=h.mobileModeEnabled&&h.curWidth<=h.mobileBreakPoint;for(var a=0,b=h.grid.length;b>a;++a){var c=h.grid[a];if(c)for(var d=0,g=c.length;g>d;++d)if(c[d]){var i=c[d];i.setElementPosition(),i.setElementSizeY(),i.setElementSizeX()}}l()};e.$watch("config",k,!0),e.$watch("config.draggable",function(){c.$broadcast("gridster-draggable-changed")},!0),e.$watch("config.resizable",function(){c.$broadcast("gridster-resizable-changed")},!0);var l=function(){f.css("height",h.gridHeight*h.curRowHeight+(h.outerMargin?h.margins[0]:-h.margins[0])+"px")};e.$watch("gridster.gridHeight",l),e.$watch("gridster.movingItem",function(){h.updateHeight(h.movingItem?h.movingItem.sizeY:0)});var m=f[0].offsetWidth||parseInt(f.css("width"),10);"function"==typeof f.resize&&f.resize(j);var n=a.element(d);n.on("resize",j),e.$watch(function(){return f[0].offsetWidth||parseInt(f.css("width"),10)},i),e.$on("$destroy",function(){h.destroy(),n.off("resize",j)}),b(function(){e.$watch("gridster.floating",function(){h.floatItemsUp()}),h.loaded=!0},100)}}}}]).controller("GridsterItemCtrl",function(){this.$element=null,this.gridster=null,this.row=null,this.col=null,this.sizeX=null,this.sizeY=null,this.minSizeX=0,this.minSizeY=0,this.maxSizeX=null,this.maxSizeY=null,this.init=function(a,b){this.$element=a,this.gridster=b,this.sizeX=b.defaultSizeX,this.sizeY=b.defaultSizeY},this.destroy=function(){this.gridster=null,this.$element=null},this.toJSON=function(){return{row:this.row,col:this.col,sizeY:this.sizeY,sizeX:this.sizeX}},this.isMoving=function(){return this.gridster.movingItem===this},this.setPosition=function(a,b){this.gridster.putItem(this,a,b),this.isMoving()||this.setElementPosition()},this.setSize=function(a,b,c){a=a.toUpperCase();var d="size"+a,e="Size"+a;if(""!==b){b=parseInt(b,10),(isNaN(b)||0===b)&&(b=this.gridster["default"+e]);var f="X"===a?this.gridster.columns:this.gridster.maxRows;this["max"+e]&&(f=Math.min(this["max"+e],f)),this.gridster["max"+e]&&(f=Math.min(this.gridster["max"+e],f)),"X"===a&&this.cols?f-=this.cols:"Y"===a&&this.rows&&(f-=this.rows);var g=0;this["min"+e]&&(g=Math.max(this["min"+e],g)),this.gridster["min"+e]&&(g=Math.max(this.gridster["min"+e],g)),b=Math.max(Math.min(b,f),g);var h=this[d]!==b||this["old"+e]&&this["old"+e]!==b;return this["old"+e]=this[d]=b,this.isMoving()||this["setElement"+e](),!c&&h&&(this.gridster.moveOverlappingItems(this),this.gridster.layoutChanged()),h}},this.setSizeY=function(a,b){return this.setSize("Y",a,b)},this.setSizeX=function(a,b){return this.setSize("X",a,b)},this.setElementPosition=function(){this.$element.css(this.gridster.isMobile?{marginLeft:this.gridster.margins[0]+"px",marginRight:this.gridster.margins[0]+"px",marginTop:this.gridster.margins[1]+"px",marginBottom:this.gridster.margins[1]+"px",top:"",left:""}:{margin:0,top:this.row*this.gridster.curRowHeight+(this.gridster.outerMargin?this.gridster.margins[0]:0)+"px",left:this.col*this.gridster.curColWidth+(this.gridster.outerMargin?this.gridster.margins[1]:0)+"px"})},this.setElementSizeY=function(){this.gridster.isMobile&&!this.gridster.saveGridItemCalculatedHeightInMobile?this.$element.css("height",""):this.$element.css("height",this.sizeY*this.gridster.curRowHeight-this.gridster.margins[0]+"px")},this.setElementSizeX=function(){this.gridster.isMobile?this.$element.css("width",""):this.$element.css("width",this.sizeX*this.gridster.curColWidth-this.gridster.margins[1]+"px")},this.getElementSizeX=function(){return this.sizeX*this.gridster.curColWidth-this.gridster.margins[1]},this.getElementSizeY=function(){return this.sizeY*this.gridster.curRowHeight-this.gridster.margins[0]}}).factory("GridsterDraggable",["$document","$timeout","$window",function(b,c,d){function e(e,f,g,h,i){function j(b){if(-1!==G.indexOf(b.target.nodeName.toLowerCase()))return!1;if(a.element(b.target).hasClass("gridster-item-resizable-handler"))return!1;if(a.element(b.target).attr("onclick")||a.element(b.target).attr("ng-click"))return!1;switch(b.which){case 1:break;case 2:case 3:return}return y=b.pageX,z=b.pageY,p=parseInt(e.css("left"),10),q=parseInt(e.css("top"),10),r=e[0].offsetWidth,s=e[0].offsetHeight,t=h.col,u=h.row,m(b),!0}function k(a){if(!e.hasClass("gridster-item-moving")||e.hasClass("gridster-item-resizing"))return!1;var b=g.curWidth-1;w=a.pageX,x=a.pageY;var c=w-y+A,d=x-z+B;A=B=0,y=w,z=x;var f=c,h=d;return E>p+f?(c=E-p,A=f-c):p+r+f>b&&(c=b-p-r,A=f-c),C>q+h?(d=C-q,B=h-d):q+s+h>D&&(d=D-q-s,B=h-d),p+=c,q+=d,e.css({top:q+"px",left:p+"px"}),n(a),!0}function l(a){return!e.hasClass("gridster-item-moving")||e.hasClass("gridster-item-resizing")?!1:(A=B=0,o(a),!0)}function m(a){e.addClass("gridster-item-moving"),g.movingItem=h,g.updateHeight(h.sizeY),f.$apply(function(){g.draggable&&g.draggable.start&&g.draggable.start(a,e,i)})}function n(a){var b=h.row,c=h.col,j=g.draggable&&g.draggable.drag,k=g.draggable.scrollSensitivity,l=g.draggable.scrollSpeed,m=g.pixelsToRows(q),n=g.pixelsToColumns(p),o=g.getItems(m,n,h.sizeX,h.sizeY,h),r=0!==o.length;if(g.swapping===!0&&r){var s=g.getBoundingBox(o),t=s.sizeX===h.sizeX&&s.sizeY===h.sizeY,u=s.row===m,v=s.col===n,w=u&&v,x=u||v;if(t&&1===o.length){if(w)g.swapItems(h,o[0]);else if(x)return}else if(s.sizeX<=h.sizeX&&s.sizeY<=h.sizeY&&x)for(var y=h.row<=m?h.row:m+h.sizeY,z=h.col<=n?h.col:n+h.sizeX,A=y-s.row,B=z-s.col,C=0,D=o.length;D>C;++C){var E=o[C],G=g.getItems(E.row+A,E.col+B,E.sizeX,E.sizeY,h);0===G.length&&g.putItem(E,E.row+A,E.col+B)}}g.pushing===!1&&r||(h.row=m,h.col=n),a.pageY-F.body.scrollTop=0&&(q-go+g&&(f=C-o,B=g-f),o+=f,q-=f),v.indexOf("s")>=0&&(q+gD&&(f=D-o-q,B=g-f),q+=f),v.indexOf("w")>=0&&(p-hn+h&&(e=E-n,A=h-e),n+=e,p-=e),v.indexOf("e")>=0&&(p+hc&&(e=c-n-p,A=h-e),p+=e),b.css({top:o+"px",left:n+"px",width:p+"px",height:q+"px"}),l(a),!0}function k(a){return d.draggable.enabled!==t&&(d.draggable.enabled=t,c.$broadcast("gridster-draggable-changed")),A=B=0,m(a),!0}function l(a){var h=e.row,i=e.col,j=e.sizeX,k=e.sizeY,l=d.resizable&&d.resizable.resize,m=e.col;-1!==["w","nw","sw"].indexOf(g)&&(m=d.pixelsToColumns(n,!1));var r=e.row;-1!==["n","ne","nw"].indexOf(g)&&(r=d.pixelsToRows(o,!1));var s=e.sizeX;-1===["n","s"].indexOf(g)&&(s=d.pixelsToColumns(p,!0));var t=e.sizeY;-1===["e","w"].indexOf(g)&&(t=d.pixelsToRows(q,!0)),(d.pushing!==!1||0===d.getItems(r,m,s,t,e).length)&&(e.row=r,e.col=m,e.sizeX=s,e.sizeY=t);var u=e.row!==h||e.col!==i||e.sizeX!==j||e.sizeY!==k;(l||u)&&c.$apply(function(){l&&d.resizable.resize(a,b,f)})}function m(a){b.removeClass("gridster-item-moving"),b.removeClass("gridster-item-resizing"),d.movingItem=null,e.setPosition(e.row,e.col),e.setSizeY(e.sizeY),e.setSizeX(e.sizeX),c.$apply(function(){d.resizable&&d.resizable.stop&&d.resizable.stop(a,b,f)})}var n,o,p,q,r,s,t,u,v=g,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=9999,E=0,F=function(){return d.curRowHeight-d.margins[0]},G=function(){return d.curColWidth-d.margins[1]},H=null;this.enable=function(){H||(H=a.element('
    '),b.append(H)),u=new d.unifiedInput(H[0],h,j,k),u.enable()},this.disable=function(){H&&(H.remove(),H=null),u.disable(),u=void 0},this.destroy=function(){this.disable()}}var h=[],i=d.resizable.handles;"string"==typeof i&&(i=d.resizable.handles.split(","));for(var j=!1,k=0,l=i.length;l>k;k++)h.push(new g(i[k]));this.enable=function(){if(!j){for(var a=0,b=h.length;b>a;a++)h[a].enable();j=!0}},this.disable=function(){if(j){for(var a=0,b=h.length;b>a;a++)h[a].disable();j=!1}},this.toggle=function(a){a?this.enable():this.disable()},this.destroy=function(){for(var a=0,b=h.length;b>a;a++)h[a].destroy()}}return b}]).directive("gridsterItem",["$parse","GridsterDraggable","GridsterResizable",function(a,b,c){return{restrict:"EA",controller:"GridsterItemCtrl",require:["^gridster","gridsterItem"],link:function(d,e,f,g){function h(){n.setPosition(n.row,n.col),q.row&&q.row.assign&&q.row.assign(d,n.row),q.col&&q.col.assign&&q.col.assign(d,n.col)}function i(){var a=n.setSizeX(n.sizeX,!0);a&&q.sizeX&&q.sizeX.assign&&q.sizeX.assign(d,n.sizeX);var b=n.setSizeY(n.sizeY,!0);b&&q.sizeY&&q.sizeY.assign&&q.sizeY.assign(d,n.sizeY),(a||b)&&(n.gridster.moveOverlappingItems(n),m.layoutChanged())}function j(){var a=document.createElement("div"),b={transition:"transitionend",OTransition:"oTransitionEnd",MozTransition:"transitionend",WebkitTransition:"webkitTransitionEnd"};for(var c in b)if(void 0!==a.style[c])return b[c]}var k,l=f.gridsterItem,m=g[0],n=g[1];if(l){var o=a(l);k=o(d)||{},!k&&o.assign&&(k={row:n.row,col:n.col,sizeX:n.sizeX,sizeY:n.sizeY,minSizeX:0,minSizeY:0,maxSizeX:null,maxSizeY:null},o.assign(d,k))}else k=f;n.init(e,m),e.addClass("gridster-item");for(var p=["minSizeX","maxSizeX","minSizeY","maxSizeY","sizeX","sizeY","row","col"],q={},r=function(b){var c;if("string"==typeof k[b])c=k[b];else if("string"==typeof k[b.toLowerCase()])c=k[b.toLowerCase()];else{if(!l)return;c=a(l+"."+b)}q[b]=a(c),d.$watch(c,function(a){a=parseInt(a,10),isNaN(a)||(n[b]=a)});var e=q[b](d);"number"==typeof e&&(n[b]=e)},s=0,t=p.length;t>s;++s)r(p[s]);d.$broadcast("gridster-item-initialized",[n.sizeY,n.sizeX,n.getElementSizeY(),n.getElementSizeX()]),d.$watch(function(){return n.row+","+n.col},h),d.$watch(function(){return n.sizeY+","+n.sizeX+"|"+n.minSizeX+","+n.maxSizeX+","+n.minSizeY+","+n.maxSizeY},i);var u=new b(e,d,m,n,k),v=new c(e,d,m,n,k);return d.$on("gridster-draggable-changed",function(){u.toggle(!m.isMobile&&m.draggable&&m.draggable.enabled)}),d.$on("gridster-resizable-changed",function(){v.toggle(!m.isMobile&&m.resizable&&m.resizable.enabled)}),d.$on("gridster-resized",function(){v.toggle(!m.isMobile&&m.resizable&&m.resizable.enabled)}),d.$watch(function(){return m.isMobile},function(){v.toggle(!m.isMobile&&m.resizable&&m.resizable.enabled),u.toggle(!m.isMobile&&m.draggable&&m.draggable.enabled)}),e.on(j(),function(){d.$apply(function(){d.$broadcast("gridster-item-transition-end")})}),d.$on("$destroy",function(){try{v.destroy(),u.destroy()}catch(a){}try{m.removeItem(n)}catch(a){}try{n.destroy()}catch(a){}})}}}])}(angular); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js b/zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js new file mode 100644 index 0000000..fa747f0 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-hotkeys_1.4.5/hotkeys--activiti-patch.js @@ -0,0 +1,1533 @@ +/*! + * angular-hotkeys v1.4.5 + * https://chieffancypants.github.io/angular-hotkeys + * Copyright (c) 2014 Wes Cruver + * License: MIT + */ +/* + * angular-hotkeys + * + * Automatic keyboard shortcuts for your angular apps + * + * (c) 2014 Wes Cruver + * License: MIT + */ + +(function() { + + 'use strict'; + + angular.module('cfp.hotkeys', []).provider('hotkeys', function() { + + /** + * Configurable setting to disable the cheatsheet entirely + * @type {Boolean} + */ + this.includeCheatSheet = true; + + /** + * Configurable setting for the cheat sheet title + * @type {String} + */ + + this.templateTitle = 'Keyboard Shortcuts:'; + + /** + * Cheat sheet template in the event you want to totally customize it. + * @type {String} + */ + this.template = ''; + + /** + * Configurable setting for the cheat sheet hotkey + * @type {String} + */ + this.cheatSheetHotkey = '?'; + + /** + * Configurable setting for the cheat sheet description + * @type {String} + */ + this.cheatSheetDescription = 'Show / hide this help menu'; + + this.$get = ['$rootElement', '$rootScope', '$compile', '$window', '$document', function ($rootElement, $rootScope, $compile, $window, $document) { + + // monkeypatch Mousetrap's stopCallback() function + // this version doesn't return true when the element is an INPUT, SELECT, or TEXTAREA + // (instead we will perform this check per-key in the _add() method) + Mousetrap.stopCallback = function(event, element) { + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + return (element.contentEditable && element.contentEditable == 'true'); + }; + + /** + * Convert strings like cmd into symbols like ⌘ + * @param {String} combo Key combination, e.g. 'mod+f' + * @return {String} The key combination with symbols + */ + function symbolize (combo) { + var map = { + command : '⌘', + shift : '⇧', + left : '←', + right : '→', + up : '↑', + down : '↓', + 'return' : '↩', + backspace : '⌫' + }; + combo = combo.split('+'); + + for (var i = 0; i < combo.length; i++) { + // try to resolve command / ctrl based on OS: + if (combo[i] === 'mod') { + if ($window.navigator && $window.navigator.platform.indexOf('Mac') >=0 ) { + combo[i] = 'command'; + } else { + combo[i] = 'ctrl'; + } + } + + combo[i] = map[combo[i]] || combo[i]; + } + + return combo.join(' + '); + } + + /** + * Hotkey object used internally for consistency + * + * @param {array} combo The keycombo. it's an array to support multiple combos + * @param {String} description Description for the keycombo + * @param {Function} callback function to execute when keycombo pressed + * @param {string} action the type of event to listen for (for mousetrap) + * @param {array} allowIn an array of tag names to allow this combo in ('INPUT', 'SELECT', and/or 'TEXTAREA') + * @param {Boolean} persistent Whether the hotkey persists navigation events + */ + function Hotkey (combo, description, callback, action, allowIn, persistent) { + // TODO: Check that the values are sane because we could + // be trying to instantiate a new Hotkey with outside dev's + // supplied values + + this.combo = combo instanceof Array ? combo : [combo]; + this.description = description; + this.callback = callback; + this.action = action; + this.allowIn = allowIn; + this.persistent = persistent; + } + + /** + * Helper method to format (symbolize) the key combo for display + * + * @return {[Array]} An array of the key combination sequence + * for example: "command+g c i" becomes ["⌘ + g", "c", "i"] + * + * TODO: this gets called a lot. We should cache the result + */ + Hotkey.prototype.format = function() { + + // Don't show all the possible key combos, just the first one. Not sure + // of usecase here, so open a ticket if my assumptions are wrong + var combo = this.combo[0]; + + var sequence = combo.split(/[\s]/); + for (var i = 0; i < sequence.length; i++) { + sequence[i] = symbolize(sequence[i]); + } + + return sequence; + }; + + /** + * A new scope used internally for the cheatsheet + * @type {$rootScope.Scope} + */ + var scope = $rootScope.$new(); + + /** + * Holds an array of Hotkey objects currently bound + * @type {Array} + */ + scope.hotkeys = []; + + /** + * Contains the state of the help's visibility + * @type {Boolean} + */ + scope.helpVisible = false; + + /** + * Holds the title string for the help menu + * @type {String} + */ + scope.title = this.templateTitle; + + /** + * Expose toggleCheatSheet to hotkeys scope so we can call it using + * ng-click from the template + * @type {function} + */ + scope.toggleCheatSheet = toggleCheatSheet; + + + /** + * Holds references to the different scopes that have bound hotkeys + * attached. This is useful to catch when the scopes are `$destroy`d and + * then automatically unbind the hotkey. + * + * @type {Array} + */ + var boundScopes = []; + + + $rootScope.$on('$routeChangeSuccess', function (event, route) { + purgeHotkeys(); + + if (route && route.hotkeys) { + angular.forEach(route.hotkeys, function (hotkey) { + // a string was given, which implies this is a function that is to be + // $eval()'d within that controller's scope + // TODO: hotkey here is super confusing. sometimes a function (that gets turned into an array), sometimes a string + var callback = hotkey[2]; + if (typeof(callback) === 'string' || callback instanceof String) { + hotkey[2] = [callback, route]; + } + + // todo: perform check to make sure not already defined: + // this came from a route, so it's likely not meant to be persistent + hotkey[5] = false; + _add.apply(this, hotkey); + }); + } + }); + + + // Auto-create a help menu: + if (this.includeCheatSheet) { + var document = $document[0]; + var element = $rootElement[0]; + var helpMenu = angular.element(this.template); + _add(this.cheatSheetHotkey, this.cheatSheetDescription, toggleCheatSheet); + + // If $rootElement is document or documentElement, then body must be used + if (element === document || element === document.documentElement) { + element = document.body; + } + + angular.element(element).append($compile(helpMenu)(scope)); + } + + + /** + * Purges all non-persistent hotkeys (such as those defined in routes) + * + * Without this, the same hotkey would get recreated everytime + * the route is accessed. + */ + function purgeHotkeys() { + var i = scope.hotkeys.length; + while (i--) { + var hotkey = scope.hotkeys[i]; + if (hotkey && !hotkey.persistent) { + _del(hotkey); + } + } + } + + /** + * Toggles the help menu element's visiblity + */ + var previousEsc = false; + + function toggleCheatSheet() { + scope.helpVisible = !scope.helpVisible; + + // Bind to esc to remove the cheat sheet. Ideally, this would be done + // as a directive in the template, but that would create a nasty + // circular dependency issue that I don't feel like sorting out. + if (scope.helpVisible) { + previousEsc = _get('esc'); + _del('esc'); + + // Here's an odd way to do this: we're going to use the original + // description of the hotkey on the cheat sheet so that it shows up. + // without it, no entry for esc will ever show up (#22) + _add('esc', previousEsc.description, toggleCheatSheet); + } else { + _del('esc'); + + // restore the previously bound ESC key + if (previousEsc !== false) { + _add(previousEsc); + } + } + } + + /** + * Creates a new Hotkey and creates the Mousetrap binding + * + * @param {string} combo mousetrap key binding + * @param {string} description description for the help menu + * @param {Function} callback method to call when key is pressed + * @param {string} action the type of event to listen for (for mousetrap) + * @param {array} allowIn an array of tag names to allow this combo in ('INPUT', 'SELECT', and/or 'TEXTAREA') + * @param {boolean} persistent if true, the binding is preserved upon route changes + */ + function _add (combo, description, callback, action, allowIn, persistent) { + + // used to save original callback for "allowIn" wrapping: + var _callback; + + // these elements are prevented by the default Mousetrap.stopCallback(): + var preventIn = ['INPUT', 'SELECT', 'TEXTAREA']; + + // Determine if object format was given: + var objType = Object.prototype.toString.call(combo); + + if (objType === '[object Object]') { + description = combo.description; + callback = combo.callback; + action = combo.action; + persistent = combo.persistent; + allowIn = combo.allowIn; + combo = combo.combo; + } + + // description is optional: + if (description instanceof Function) { + action = callback; + callback = description; + description = '$$undefined$$'; + } else if (angular.isUndefined(description)) { + description = '$$undefined$$'; + } + + // any items added through the public API are for controllers + // that persist through navigation, and thus undefined should mean + // true in this case. + if (persistent === undefined) { + persistent = true; + } + + // if callback is defined, then wrap it in a function + // that checks if the event originated from a form element. + // the function blocks the callback from executing unless the element is specified + // in allowIn (emulates Mousetrap.stopCallback() on a per-key level) + if (typeof callback === 'function') { + + // save the original callback + _callback = callback; + + // make sure allowIn is an array + if (!(allowIn instanceof Array)) { + allowIn = []; + } + + // remove anything from preventIn that's present in allowIn + var index; + for (var i=0; i < allowIn.length; i++) { + allowIn[i] = allowIn[i].toUpperCase(); + index = preventIn.indexOf(allowIn[i]); + if (index !== -1) { + preventIn.splice(index, 1); + } + } + + // create the new wrapper callback + callback = function(event) { + var shouldExecute = true; + var target = event.target || event.srcElement; // srcElement is IE only + var nodeName = target.nodeName.toUpperCase(); + + // check if the input has a mousetrap class, and skip checking preventIn if so + if ((' ' + target.className + ' ').indexOf(' mousetrap ') > -1) { + shouldExecute = true; + } else { + // don't execute callback if the event was fired from inside an element listed in preventIn + for (var i=0; i -1) { + // if the combo has other combos bound, don't unbind the whole thing, just the one combo: + if (scope.hotkeys[index].combo.length > 1) { + scope.hotkeys[index].combo.splice(scope.hotkeys[index].combo.indexOf(combo), 1); + } else { + scope.hotkeys.splice(index, 1); + } + return true; + } + } + + return false; + + } + + /** + * Get a Hotkey object by key binding + * + * @param {[string]} combo the key the Hotkey is bound to + * @return {Hotkey} The Hotkey object + */ + function _get (combo) { + + var hotkey; + + for (var i = 0; i < scope.hotkeys.length; i++) { + hotkey = scope.hotkeys[i]; + + if (hotkey.combo.indexOf(combo) > -1) { + return hotkey; + } + } + + return false; + } + + /** + * Binds the hotkey to a particular scope. Useful if the scope is + * destroyed, we can automatically destroy the hotkey binding. + * + * @param {Object} scope The scope to bind to + */ + function bindTo (scope) { + // Only initialize once to allow multiple calls for same scope. + if (!(scope.$id in boundScopes)) { + + // Add the scope to the list of bound scopes + boundScopes[scope.$id] = []; + + scope.$on('$destroy', function () { + var i = boundScopes[scope.$id].length; + while (i--) { + _del(boundScopes[scope.$id][i]); + delete boundScopes[scope.$id][i]; + } + }); + } + // return an object with an add function so we can keep track of the + // hotkeys and their scope that we added via this chaining method + return { + add: function (args) { + var hotkey; + + if (arguments.length > 1) { + hotkey = _add.apply(this, arguments); + } else { + hotkey = _add(args); + } + + boundScopes[scope.$id].push(hotkey); + return this; + } + }; + } + + /** + * All callbacks sent to Mousetrap are wrapped using this function + * so that we can force a $scope.$apply() + * + * @param {Function} callback [description] + * @return {[type]} [description] + */ + function wrapApply (callback) { + // return mousetrap a function to call + return function (event, combo) { + + // if this is an array, it means we provided a route object + // because the scope wasn't available yet, so rewrap the callback + // now that the scope is available: + if (callback instanceof Array) { + var funcString = callback[0]; + var route = callback[1]; + callback = function (event) { + route.scope.$eval(funcString); + }; + } + + // this takes place outside angular, so we'll have to call + // $apply() to make sure angular's digest happens + $rootScope.$apply(function() { + // call the original hotkey callback with the keyboard event + callback(event, _get(combo)); + }); + }; + } + + + var publicApi = { + add : _add, + del : _del, + get : _get, + bindTo : bindTo, + template : this.template, + toggleCheatSheet : toggleCheatSheet, + includeCheatSheet : this.includeCheatSheet, + cheatSheetHotkey : this.cheatSheetHotkey, + cheatSheetDescription : this.cheatSheetDescription, + purgeHotkeys : purgeHotkeys, + templateTitle : this.templateTitle + }; + + return publicApi; + + }]; + }) + + .directive('hotkey', ['hotkeys', function (hotkeys) { + return { + restrict: 'A', + link: function (scope, el, attrs) { + var key, allowIn; + + angular.forEach(scope.$eval(attrs.hotkey), function (func, hotkey) { + // split and trim the hotkeys string into array + allowIn = typeof attrs.hotkeyAllowIn === "string" ? attrs.hotkeyAllowIn.split(/[\s,]+/) : []; + + key = hotkey; + + hotkeys.add({ + combo: hotkey, + description: attrs.hotkeyDescription, + callback: func, + action: attrs.hotkeyAction, + allowIn: allowIn + }); + }); + + // remove the hotkey if the directive is destroyed: + el.bind('$destroy', function() { + hotkeys.del(key); + }); + } + }; + }]) + + .run(['hotkeys', function(hotkeys) { + // force hotkeys to run by injecting it. Without this, hotkeys only runs + // when a controller or something else asks for it via DI. + }]); + +})(); + +/*global define:false */ +/** + * Copyright 2013 Craig Campbell + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Mousetrap is a simple keyboard shortcut library for Javascript with + * no external dependencies + * + * @version 1.4.6 + * @url craig.is/killing/mice + */ +(function(window, document, undefined) { + + /** + * mapping of special keycodes to their corresponding keys + * + * everything in this dictionary cannot use keypress events + * so it has to be here to map to the correct keycodes for + * keyup/keydown events + * + * @type {Object} + */ + var _MAP = { + 8: 'backspace', + 9: 'tab', + 13: 'enter', + 16: 'shift', + 17: 'ctrl', + 18: 'alt', + 20: 'capslock', + 27: 'esc', + 32: 'space', + 33: 'pageup', + 34: 'pagedown', + 35: 'end', + 36: 'home', + 37: 'left', + 38: 'up', + 39: 'right', + 40: 'down', + 45: 'ins', + 46: 'del', + 91: 'meta', + 93: 'meta', + 224: 'meta' + }, + + /** + * mapping for special characters so they can support + * + * this dictionary is only used incase you want to bind a + * keyup or keydown event to one of these keys + * + * @type {Object} + */ + _KEYCODE_MAP = { + 106: '*', + 107: '+', + 109: '-', + 110: '.', + 111 : '/', + 186: ';', + 187: '=', + 188: ',', + 189: '-', + 190: '.', + 191: '/', + 192: '`', + 219: '[', + 220: '\\', + 221: ']', + 222: '\'' + }, + + /** + * this is a mapping of keys that require shift on a US keypad + * back to the non shift equivelents + * + * this is so you can use keyup events with these keys + * + * note that this will only work reliably on US keyboards + * + * @type {Object} + */ + _SHIFT_MAP = { + '~': '`', + '!': '1', + '@': '2', + '#': '3', + '$': '4', + '%': '5', + '^': '6', + '&': '7', + '*': '8', + '(': '9', + ')': '0', + '_': '-', + '+': '=', + ':': ';', + '\"': '\'', + '<': ',', + '>': '.', + '?': '/', + '|': '\\' + }, + + /** + * this is a list of special strings you can use to map + * to modifier keys when you specify your keyboard shortcuts + * + * @type {Object} + */ + _SPECIAL_ALIASES = { + 'option': 'alt', + 'command': 'meta', + 'return': 'enter', + 'escape': 'esc', + 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl' + }, + + /** + * variable to store the flipped version of _MAP from above + * needed to check if we should use keypress or not when no action + * is specified + * + * @type {Object|undefined} + */ + _REVERSE_MAP, + + /** + * a list of all the callbacks setup via Mousetrap.bind() + * + * @type {Object} + */ + _callbacks = {}, + + /** + * direct map of string combinations to callbacks used for trigger() + * + * @type {Object} + */ + _directMap = {}, + + /** + * keeps track of what level each sequence is at since multiple + * sequences can start out with the same sequence + * + * @type {Object} + */ + _sequenceLevels = {}, + + /** + * variable to store the setTimeout call + * + * @type {null|number} + */ + _resetTimer, + + /** + * temporary state where we will ignore the next keyup + * + * @type {boolean|string} + */ + _ignoreNextKeyup = false, + + /** + * temporary state where we will ignore the next keypress + * + * @type {boolean} + */ + _ignoreNextKeypress = false, + + /** + * are we currently inside of a sequence? + * type of action ("keyup" or "keydown" or "keypress") or false + * + * @type {boolean|string} + */ + _nextExpectedAction = false; + + /** + * loop through the f keys, f1 to f19 and add them to the map + * programatically + */ + for (var i = 1; i < 20; ++i) { + _MAP[111 + i] = 'f' + i; + } + + /** + * loop through to map numbers on the numeric keypad + */ + for (i = 0; i <= 9; ++i) { + _MAP[i + 96] = i; + } + + /** + * cross browser add event method + * + * @param {Element|HTMLDocument} object + * @param {string} type + * @param {Function} callback + * @returns void + */ + function _addEvent(object, type, callback) { + if (object.addEventListener) { + object.addEventListener(type, callback, false); + return; + } + + object.attachEvent('on' + type, callback); + } + + /** + * takes the event and returns the key character + * + * @param {Event} e + * @return {string} + */ + function _characterFromEvent(e) { + + // for keypress events we should return the character as is + if (e.type == 'keypress') { + var character = String.fromCharCode(e.which); + + // if the shift key is not pressed then it is safe to assume + // that we want the character to be lowercase. this means if + // you accidentally have caps lock on then your key bindings + // will continue to work + // + // the only side effect that might not be desired is if you + // bind something like 'A' cause you want to trigger an + // event when capital A is pressed caps lock will no longer + // trigger the event. shift+a will though. + if (!e.shiftKey) { + character = character.toLowerCase(); + } + + return character; + } + + // for non keypress events the special maps are needed + if (_MAP[e.which]) { + return _MAP[e.which]; + } + + if (_KEYCODE_MAP[e.which]) { + return _KEYCODE_MAP[e.which]; + } + + // if it is not in the special map + + // with keydown and keyup events the character seems to always + // come in as an uppercase character whether you are pressing shift + // or not. we should make sure it is always lowercase for comparisons + return String.fromCharCode(e.which).toLowerCase(); + } + + /** + * checks if two arrays are equal + * + * @param {Array} modifiers1 + * @param {Array} modifiers2 + * @returns {boolean} + */ + function _modifiersMatch(modifiers1, modifiers2) { + return modifiers1.sort().join(',') === modifiers2.sort().join(','); + } + + /** + * resets all sequence counters except for the ones passed in + * + * @param {Object} doNotReset + * @returns void + */ + function _resetSequences(doNotReset) { + doNotReset = doNotReset || {}; + + var activeSequences = false, + key; + + for (key in _sequenceLevels) { + if (doNotReset[key]) { + activeSequences = true; + continue; + } + _sequenceLevels[key] = 0; + } + + if (!activeSequences) { + _nextExpectedAction = false; + } + } + + /** + * finds all callbacks that match based on the keycode, modifiers, + * and action + * + * @param {string} character + * @param {Array} modifiers + * @param {Event|Object} e + * @param {string=} sequenceName - name of the sequence we are looking for + * @param {string=} combination + * @param {number=} level + * @returns {Array} + */ + function _getMatches(character, modifiers, e, sequenceName, combination, level) { + var i, + callback, + matches = [], + action = e.type; + + // if there are no events related to this keycode + if (!_callbacks[character]) { + return []; + } + + // if a modifier key is coming up on its own we should allow it + if (action == 'keyup' && _isModifier(character)) { + modifiers = [character]; + } + + // loop through all callbacks for the key that was pressed + // and see if any of them match + for (i = 0; i < _callbacks[character].length; ++i) { + callback = _callbacks[character][i]; + + // if a sequence name is not specified, but this is a sequence at + // the wrong level then move onto the next match + if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) { + continue; + } + + // if the action we are looking for doesn't match the action we got + // then we should keep going + if (action != callback.action) { + continue; + } + + // if this is a keypress event and the meta key and control key + // are not pressed that means that we need to only look at the + // character, otherwise check the modifiers as well + // + // chrome will not fire a keypress if meta or control is down + // safari will fire a keypress if meta or meta+shift is down + // firefox will fire a keypress if meta or control is down + if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { + + // when you bind a combination or sequence a second time it + // should overwrite the first one. if a sequenceName or + // combination is specified in this call it does just that + // + // @todo make deleting its own method? + var deleteCombo = !sequenceName && callback.combo == combination; + var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level; + if (deleteCombo || deleteSequence) { + _callbacks[character].splice(i, 1); + } + + matches.push(callback); + } + } + + return matches; + } + + /** + * takes a key event and figures out what the modifiers are + * + * @param {Event} e + * @returns {Array} + */ + function _eventModifiers(e) { + var modifiers = []; + + if (e.shiftKey) { + modifiers.push('shift'); + } + + if (e.altKey) { + modifiers.push('alt'); + } + + if (e.ctrlKey) { + modifiers.push('ctrl'); + } + + if (e.metaKey) { + modifiers.push('meta'); + } + + return modifiers; + } + + /** + * prevents default for this event + * + * @param {Event} e + * @returns void + */ + function _preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + return; + } + + e.returnValue = false; + } + + /** + * stops propogation for this event + * + * @param {Event} e + * @returns void + */ + function _stopPropagation(e) { + if (e.stopPropagation) { + e.stopPropagation(); + return; + } + + e.cancelBubble = true; + } + + /** + * actually calls the callback function + * + * if your callback function returns false this will use the jquery + * convention - prevent default and stop propogation on the event + * + * @param {Function} callback + * @param {Event} e + * @returns void + */ + function _fireCallback(callback, e, combo, sequence) { + + // if this event should not happen stop here + if (Mousetrap.stopCallback(e, e.target || e.srcElement, combo, sequence)) { + return; + } + + if (callback(e, combo) === false) { + _preventDefault(e); + _stopPropagation(e); + } + } + + /** + * handles a character key event + * + * @param {string} character + * @param {Array} modifiers + * @param {Event} e + * @returns void + */ + function _handleKey(character, modifiers, e) { + var callbacks = _getMatches(character, modifiers, e), + i, + doNotReset = {}, + maxLevel = 0, + processedSequenceCallback = false; + + // Calculate the maxLevel for sequences so we can only execute the longest callback sequence + for (i = 0; i < callbacks.length; ++i) { + if (callbacks[i].seq) { + maxLevel = Math.max(maxLevel, callbacks[i].level); + } + } + + // loop through matching callbacks for this key event + for (i = 0; i < callbacks.length; ++i) { + + // fire for all sequence callbacks + // this is because if for example you have multiple sequences + // bound such as "g i" and "g t" they both need to fire the + // callback for matching g cause otherwise you can only ever + // match the first one + if (callbacks[i].seq) { + + // only fire callbacks for the maxLevel to prevent + // subsequences from also firing + // + // for example 'a option b' should not cause 'option b' to fire + // even though 'option b' is part of the other sequence + // + // any sequences that do not match here will be discarded + // below by the _resetSequences call + if (callbacks[i].level != maxLevel) { + continue; + } + + processedSequenceCallback = true; + + // keep a list of which sequences were matches for later + doNotReset[callbacks[i].seq] = 1; + _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq); + continue; + } + + // if there were no sequence matches but we are still here + // that means this is a regular match so we should fire that + if (!processedSequenceCallback) { + _fireCallback(callbacks[i].callback, e, callbacks[i].combo); + } + } + + // if the key you pressed matches the type of sequence without + // being a modifier (ie "keyup" or "keypress") then we should + // reset all sequences that were not matched by this event + // + // this is so, for example, if you have the sequence "h a t" and you + // type "h e a r t" it does not match. in this case the "e" will + // cause the sequence to reset + // + // modifier keys are ignored because you can have a sequence + // that contains modifiers such as "enter ctrl+space" and in most + // cases the modifier key will be pressed before the next key + // + // also if you have a sequence such as "ctrl+b a" then pressing the + // "b" key will trigger a "keypress" and a "keydown" + // + // the "keydown" is expected when there is a modifier, but the + // "keypress" ends up matching the _nextExpectedAction since it occurs + // after and that causes the sequence to reset + // + // we ignore keypresses in a sequence that directly follow a keydown + // for the same character + var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress; + if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) { + _resetSequences(doNotReset); + } + + _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown'; + } + + /** + * handles a keydown event + * + * @param {Event} e + * @returns void + */ + function _handleKeyEvent(e) { + + // normalize e.which for key events + // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion + if (typeof e.which !== 'number') { + e.which = e.keyCode; + } + + var character = _characterFromEvent(e); + + // no character found then stop + if (!character) { + return; + } + + // need to use === for the character check because the character can be 0 + if (e.type == 'keyup' && _ignoreNextKeyup === character) { + _ignoreNextKeyup = false; + return; + } + + Mousetrap.handleKey(character, _eventModifiers(e), e); + } + + /** + * determines if the keycode specified is a modifier key or not + * + * @param {string} key + * @returns {boolean} + */ + function _isModifier(key) { + return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; + } + + /** + * called to set a 1 second timeout on the specified sequence + * + * this is so after each key press in the sequence you have 1 second + * to press the next key before you have to start over + * + * @returns void + */ + function _resetSequenceTimer() { + clearTimeout(_resetTimer); + _resetTimer = setTimeout(_resetSequences, 1000); + } + + /** + * reverses the map lookup so that we can look for specific keys + * to see what can and can't use keypress + * + * @return {Object} + */ + function _getReverseMap() { + if (!_REVERSE_MAP) { + _REVERSE_MAP = {}; + for (var key in _MAP) { + + // pull out the numeric keypad from here cause keypress should + // be able to detect the keys from the character + if (key > 95 && key < 112) { + continue; + } + + if (_MAP.hasOwnProperty(key)) { + _REVERSE_MAP[_MAP[key]] = key; + } + } + } + return _REVERSE_MAP; + } + + /** + * picks the best action based on the key combination + * + * @param {string} key - character for key + * @param {Array} modifiers + * @param {string=} action passed in + */ + function _pickBestAction(key, modifiers, action) { + + // if no action was picked in we should try to pick the one + // that we think would work best for this key + if (!action) { + action = _getReverseMap()[key] ? 'keydown' : 'keypress'; + } + + // modifier keys don't work as expected with keypress, + // switch to keydown + if (action == 'keypress' && modifiers.length) { + action = 'keydown'; + } + + return action; + } + + /** + * binds a key sequence to an event + * + * @param {string} combo - combo specified in bind call + * @param {Array} keys + * @param {Function} callback + * @param {string=} action + * @returns void + */ + function _bindSequence(combo, keys, callback, action) { + + // start off by adding a sequence level record for this combination + // and setting the level to 0 + _sequenceLevels[combo] = 0; + + /** + * callback to increase the sequence level for this sequence and reset + * all other sequences that were active + * + * @param {string} nextAction + * @returns {Function} + */ + function _increaseSequence(nextAction) { + return function() { + _nextExpectedAction = nextAction; + ++_sequenceLevels[combo]; + _resetSequenceTimer(); + }; + } + + /** + * wraps the specified callback inside of another function in order + * to reset all sequence counters as soon as this sequence is done + * + * @param {Event} e + * @returns void + */ + function _callbackAndReset(e) { + _fireCallback(callback, e, combo); + + // we should ignore the next key up if the action is key down + // or keypress. this is so if you finish a sequence and + // release the key the final key will not trigger a keyup + if (action !== 'keyup') { + _ignoreNextKeyup = _characterFromEvent(e); + } + + // weird race condition if a sequence ends with the key + // another sequence begins with + setTimeout(_resetSequences, 10); + } + + // loop through keys one at a time and bind the appropriate callback + // function. for any key leading up to the final one it should + // increase the sequence. after the final, it should reset all sequences + // + // if an action is specified in the original bind call then that will + // be used throughout. otherwise we will pass the action that the + // next key in the sequence should match. this allows a sequence + // to mix and match keypress and keydown events depending on which + // ones are better suited to the key provided + for (var i = 0; i < keys.length; ++i) { + var isFinal = i + 1 === keys.length; + var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action); + _bindSingle(keys[i], wrappedCallback, action, combo, i); + } + } + + /** + * Converts from a string key combination to an array + * + * @param {string} combination like "command+shift+l" + * @return {Array} + */ + function _keysFromString(combination) { + if (combination === '+') { + return ['+']; + } + + return combination.split('+'); + } + + /** + * Gets info for a specific key combination + * + * @param {string} combination key combination ("command+s" or "a" or "*") + * @param {string=} action + * @returns {Object} + */ + function _getKeyInfo(combination, action) { + var keys, + key, + i, + modifiers = []; + + // take the keys from this pattern and figure out what the actual + // pattern is all about + keys = _keysFromString(combination); + + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + + // normalize key names + if (_SPECIAL_ALIASES[key]) { + key = _SPECIAL_ALIASES[key]; + } + + // if this is not a keypress event then we should + // be smart about using shift keys + // this will only work for US keyboards however + if (action && action != 'keypress' && _SHIFT_MAP[key]) { + key = _SHIFT_MAP[key]; + modifiers.push('shift'); + } + + // if this key is a modifier then add it to the list of modifiers + if (_isModifier(key)) { + modifiers.push(key); + } + } + + // depending on what the key combination is + // we will try to pick the best event for it + action = _pickBestAction(key, modifiers, action); + + return { + key: key, + modifiers: modifiers, + action: action + }; + } + + /** + * binds a single keyboard combination + * + * @param {string} combination + * @param {Function} callback + * @param {string=} action + * @param {string=} sequenceName - name of sequence if part of sequence + * @param {number=} level - what part of the sequence the command is + * @returns void + */ + function _bindSingle(combination, callback, action, sequenceName, level) { + + // store a direct mapped reference for use with Mousetrap.trigger + _directMap[combination + ':' + action] = callback; + + // make sure multiple spaces in a row become a single space + combination = combination.replace(/\s+/g, ' '); + + var sequence = combination.split(' '), + info; + + // if this pattern is a sequence of keys then run through this method + // to reprocess each pattern one key at a time + if (sequence.length > 1) { + _bindSequence(combination, sequence, callback, action); + return; + } + + info = _getKeyInfo(combination, action); + + // make sure to initialize array if this is the first time + // a callback is added for this key + _callbacks[info.key] = _callbacks[info.key] || []; + + // remove an existing match if there is one + _getMatches(info.key, info.modifiers, {type: info.action}, sequenceName, combination, level); + + // add this call back to the array + // if it is a sequence put it at the beginning + // if not put it at the end + // + // this is important because the way these are processed expects + // the sequence ones to come first + _callbacks[info.key][sequenceName ? 'unshift' : 'push']({ + callback: callback, + modifiers: info.modifiers, + action: info.action, + seq: sequenceName, + level: level, + combo: combination + }); + } + + /** + * binds multiple combinations to the same callback + * + * @param {Array} combinations + * @param {Function} callback + * @param {string|undefined} action + * @returns void + */ + function _bindMultiple(combinations, callback, action) { + for (var i = 0; i < combinations.length; ++i) { + _bindSingle(combinations[i], callback, action); + } + } + + // start! + _addEvent(document, 'keypress', _handleKeyEvent); + _addEvent(document, 'keydown', _handleKeyEvent); + _addEvent(document, 'keyup', _handleKeyEvent); + + var Mousetrap = { + + /** + * binds an event to mousetrap + * + * can be a single key, a combination of keys separated with +, + * an array of keys, or a sequence of keys separated by spaces + * + * be sure to list the modifier keys first to make sure that the + * correct key ends up getting bound (the last key in the pattern) + * + * @param {string|Array} keys + * @param {Function} callback + * @param {string=} action - 'keypress', 'keydown', or 'keyup' + * @returns void + */ + bind: function(keys, callback, action) { + keys = keys instanceof Array ? keys : [keys]; + _bindMultiple(keys, callback, action); + return this; + }, + + /** + * unbinds an event to mousetrap + * + * the unbinding sets the callback function of the specified key combo + * to an empty function and deletes the corresponding key in the + * _directMap dict. + * + * TODO: actually remove this from the _callbacks dictionary instead + * of binding an empty function + * + * the keycombo+action has to be exactly the same as + * it was defined in the bind method + * + * @param {string|Array} keys + * @param {string} action + * @returns void + */ + unbind: function(keys, action) { + return Mousetrap.bind(keys, function() {}, action); + }, + + /** + * triggers an event that has already been bound + * + * @param {string} keys + * @param {string=} action + * @returns void + */ + trigger: function(keys, action) { + if (_directMap[keys + ':' + action]) { + _directMap[keys + ':' + action]({}, keys); + } + return this; + }, + + /** + * resets the library back to its initial state. this is useful + * if you want to clear out the current keyboard shortcuts and bind + * new ones - for example if you switch to another page + * + * @returns void + */ + reset: function() { + _callbacks = {}; + _directMap = {}; + return this; + }, + + /** + * should we stop this event before firing off callbacks + * + * @param {Event} e + * @param {Element} element + * @return {boolean} + */ + stopCallback: function(e, element) { + + // if the element has the class "mousetrap" then no need to stop + if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { + return false; + } + + // stop for input, select, and textarea + return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable; + }, + + /** + * exposes _handleKey publicly so it can be overwritten by extensions + */ + handleKey: _handleKey + }; + + // expose mousetrap to the global object + window.Mousetrap = Mousetrap; + + /* + + Can't let hotkeys define itself as a module since it will cause Flowable to not work in Alfresco Share: + In Share this file is being loaded from a +
    + Snippet: + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveHowSourceRendered
    ng-bind-htmlAutomatically uses $sanitize
    <div ng-bind-html="snippet">
    </div>
    ng-bind-htmlBypass $sanitize by explicitly trusting the dangerous value +
    <div ng-bind-html="deliberatelyTrustDangerousSnippet()">
    +</div>
    +
    ng-bindAutomatically escapes
    <div ng-bind="snippet">
    </div>
    +
    + + + it('should sanitize the html snippet by default', function() { + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('

    an html\nclick here\nsnippet

    '); + }); + + it('should inline raw snippet if bound to a trusted value', function() { + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). + toBe("

    an html\n" + + "click here\n" + + "snippet

    "); + }); + + it('should escape snippet without any filter', function() { + expect(element(by.css('#bind-default div')).getInnerHtml()). + toBe("<p style=\"color:blue\">an html\n" + + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + + "snippet</p>"); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( + 'new text'); + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( + "new <b onclick=\"alert(1)\">text</b>"); + }); +
    + + */ +function $SanitizeProvider() { + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; +} + +function sanitizeText(chars) { + var buf = []; + var writer = htmlSanitizeWriter(buf, angular.noop); + writer.chars(chars); + return buf.join(''); +} + + +// Regular Expressions for parsing tags and attributes +var START_TAG_REGEXP = + /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/, + END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, + BEGIN_TAG_REGEXP = /^/g, + DOCTYPE_REGEXP = /]*?)>/i, + CDATA_REGEXP = //g, + SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + + +// Good source of info about elements and attributes +// http://dev.w3.org/html5/spec/Overview.html#semantics +// http://simon.html5.org/html-elements + +// Safe Void Elements - HTML5 +// http://dev.w3.org/html5/spec/Overview.html#void-elements +var voidElements = makeMap("area,br,col,hr,img,wbr"); + +// Elements that you can, intentionally, leave open (and which close themselves) +// http://dev.w3.org/html5/spec/Overview.html#optional-tags +var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), + optionalEndTagInlineElements = makeMap("rp,rt"), + optionalEndTagElements = angular.extend({}, + optionalEndTagInlineElements, + optionalEndTagBlockElements); + +// Safe Block Elements - HTML5 +var blockElements = angular.extend({}, optionalEndTagBlockElements, makeMap("address,article," + + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul")); + +// Inline Elements - HTML5 +var inlineElements = angular.extend({}, optionalEndTagInlineElements, makeMap("a,abbr,acronym,b," + + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + + "samp,small,span,strike,strong,sub,sup,time,tt,u,var")); + +// SVG Elements +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements +var svgElements = makeMap("animate,animateColor,animateMotion,animateTransform,circle,defs," + + "desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient," + + "line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,set," + + "stop,svg,switch,text,title,tspan,use"); + +// Special Elements (can contain anything) +var specialElements = makeMap("script,style"); + +var validElements = angular.extend({}, + voidElements, + blockElements, + inlineElements, + optionalEndTagElements, + svgElements); + +//Attributes that have href and hence need to be sanitized +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href"); + +var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + + 'scope,scrolling,shape,size,span,start,summary,target,title,type,' + + 'valign,value,vspace,width'); + +// SVG attributes (without "id" and "name" attributes) +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes +var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + 'attributeName,attributeType,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,' + + 'color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,' + + 'font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,' + + 'gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,' + + 'keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,' + + 'markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,' + + 'overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,' + + 'repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,' + + 'stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,' + + 'stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,' + + 'stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,' + + 'underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,' + + 'viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,' + + 'xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,' + + 'zoomAndPan'); + +var validAttrs = angular.extend({}, + uriAttrs, + svgAttrs, + htmlAttrs); + +function makeMap(str) { + var obj = {}, items = str.split(','), i; + for (i = 0; i < items.length; i++) obj[items[i]] = true; + return obj; +} + + +/** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ +function htmlParser(html, handler) { + if (typeof html !== 'string') { + if (html === null || typeof html === 'undefined') { + html = ''; + } else { + html = '' + html; + } + } + var index, chars, match, stack = [], last = html, text; + stack.last = function() { return stack[stack.length - 1]; }; + + while (html) { + text = ''; + chars = true; + + // Make sure we're not in a script or style element + if (!stack.last() || !specialElements[stack.last()]) { + + // Comment + if (html.indexOf("", index) === index) { + if (handler.comment) handler.comment(html.substring(4, index)); + html = html.substring(index + 3); + chars = false; + } + // DOCTYPE + } else if (DOCTYPE_REGEXP.test(html)) { + match = html.match(DOCTYPE_REGEXP); + + if (match) { + html = html.replace(match[0], ''); + chars = false; + } + // end tag + } else if (BEGING_END_TAGE_REGEXP.test(html)) { + match = html.match(END_TAG_REGEXP); + + if (match) { + html = html.substring(match[0].length); + match[0].replace(END_TAG_REGEXP, parseEndTag); + chars = false; + } + + // start tag + } else if (BEGIN_TAG_REGEXP.test(html)) { + match = html.match(START_TAG_REGEXP); + + if (match) { + // We only have a valid start-tag if there is a '>'. + if (match[4]) { + html = html.substring(match[0].length); + match[0].replace(START_TAG_REGEXP, parseStartTag); + } + chars = false; + } else { + // no ending tag found --- this piece should be encoded as an entity. + text += '<'; + html = html.substring(1); + } + } + + if (chars) { + index = html.indexOf("<"); + + text += index < 0 ? html : html.substring(0, index); + html = index < 0 ? "" : html.substring(index); + + if (handler.chars) handler.chars(decodeEntities(text)); + } + + } else { + // IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w]. + html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), + function(all, text) { + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); + + if (handler.chars) handler.chars(decodeEntities(text)); + + return ""; + }); + + parseEndTag("", stack.last()); + } + + if (html == last) { + throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + + "of html: {0}", html); + } + last = html; + } + + // Clean up any remaining tags + parseEndTag(); + + function parseStartTag(tag, tagName, rest, unary) { + tagName = angular.lowercase(tagName); + if (blockElements[tagName]) { + while (stack.last() && inlineElements[stack.last()]) { + parseEndTag("", stack.last()); + } + } + + if (optionalEndTagElements[tagName] && stack.last() == tagName) { + parseEndTag("", tagName); + } + + unary = voidElements[tagName] || !!unary; + + if (!unary) + stack.push(tagName); + + var attrs = {}; + + rest.replace(ATTR_REGEXP, + function(match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { + var value = doubleQuotedValue + || singleQuotedValue + || unquotedValue + || ''; + + attrs[name] = decodeEntities(value); + }); + if (handler.start) handler.start(tagName, attrs, unary); + } + + function parseEndTag(tag, tagName) { + var pos = 0, i; + tagName = angular.lowercase(tagName); + if (tagName) + // Find the closest opened tag of the same type + for (pos = stack.length - 1; pos >= 0; pos--) + if (stack[pos] == tagName) + break; + + if (pos >= 0) { + // Close all the open elements, up the stack + for (i = stack.length - 1; i >= pos; i--) + if (handler.end) handler.end(stack[i]); + + // Remove the open elements from the stack + stack.length = pos; + } + } +} + +var hiddenPre=document.createElement("pre"); +var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; +/** + * decodes all entities into regular string + * @param value + * @returns {string} A string with decoded entities. + */ +function decodeEntities(value) { + if (!value) { return ''; } + + // Note: IE8 does not preserve spaces at the start/end of innerHTML + // so we must capture them and reattach them afterward + var parts = spaceRe.exec(value); + var spaceBefore = parts[1]; + var spaceAfter = parts[3]; + var content = parts[2]; + if (content) { + hiddenPre.innerHTML=content.replace(//g, '>'); +} + +/** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.jain('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ +function htmlSanitizeWriter(buf, uriValidator) { + var ignore = false; + var out = angular.bind(buf, buf.push); + return { + start: function(tag, attrs, unary) { + tag = angular.lowercase(tag); + if (!ignore && specialElements[tag]) { + ignore = tag; + } + if (!ignore && validElements[tag] === true) { + out('<'); + out(tag); + angular.forEach(attrs, function(value, key) { + var lkey=angular.lowercase(key); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out(unary ? '/>' : '>'); + } + }, + end: function(tag) { + tag = angular.lowercase(tag); + if (!ignore && validElements[tag] === true) { + out(''); + } + if (tag == ignore) { + ignore = false; + } + }, + chars: function(chars) { + if (!ignore) { + out(encodeEntities(chars)); + } + } + }; +} + + +// define ngSanitize module and register $sanitize service +angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); + +/* global sanitizeText: false */ + +/** + * @ngdoc filter + * @name linky + * @kind function + * + * @description + * Finds links in text input and turns them into html links. Supports http/https/ftp/mailto and + * plain email address links. + * + * Requires the {@link ngSanitize `ngSanitize`} module to be installed. + * + * @param {string} text Input text. + * @param {string} target Window (_blank|_self|_parent|_top) or named frame to open links in. + * @returns {string} Html-linkified text. + * + * @usage + + * + * @example + + + +
    + Snippet: + + + + + + + + + + + + + + + + + + + + + +
    FilterSourceRendered
    linky filter +
    <div ng-bind-html="snippet | linky">
    </div>
    +
    +
    +
    linky target +
    <div ng-bind-html="snippetWithTarget | linky:'_blank'">
    </div>
    +
    +
    +
    no filter
    <div ng-bind="snippet">
    </div>
    + + + it('should linkify the snippet with urls', function() { + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); + }); + + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); + }); + + it('should update', function() { + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); + }); + + it('should work with the target property', function() { + expect(element(by.id('linky-target')). + element(by.binding("snippetWithTarget | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); + }); + + + */ +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { + var LINKY_URL_REGEXP = + /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"”’]/, + MAILTO_REGEXP = /^mailto:/; + + return function(text, target) { + if (!text) return text; + var match; + var raw = text; + var html = []; + var url; + var i; + while ((match = raw.match(LINKY_URL_REGEXP))) { + // We can not end in these as they are sometimes found at the end of the sentence + url = match[0]; + // if we did not match ftp/http/www/mailto then assume mailto + if (!match[2] && !match[4]) { + url = (match[3] ? 'http://' : 'mailto:') + url; + } + i = match.index; + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); + raw = raw.substring(i + match[0].length); + } + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + html.push('
    '); + addText(text); + html.push(''); + } + }; +}]); + + +})(window, window.angular); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js new file mode 100644 index 0000000..e6c2b1e --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js @@ -0,0 +1,16 @@ +/* + AngularJS v1.3.13 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(n,h,p){'use strict';function E(a){var d=[];s(d,h.noop).chars(a);return d.join("")}function g(a){var d={};a=a.split(",");var c;for(c=0;c=c;e--)d.end&&d.end(f[e]);f.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,f=[],m=a,l;for(f.last=function(){return f[f.length-1]};a;){l="";k=!0;if(f.last()&&x[f.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+f.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");d.chars&&d.chars(r(b));return""}),e("",f.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e",b)===b&&(d.comment&& +d.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(y.test(a)){if(b=a.match(y))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(z))a=a.substring(b[0].length),b[0].replace(z,e),k=!1}else K.test(a)&&((b=a.match(A))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(A,c)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),d.chars&&d.chars(r(l)))}if(a==m)throw L("badparse",a);m=a}e()}function r(a){if(!a)return"";var d=M.exec(a);a=d[1]; +var c=d[3];if(d=d[2])q.innerHTML=d.replace(//g,">")}function s(a,d){var c=!1,e=h.bind(a,a.push);return{start:function(a,k,f){a=h.lowercase(a);!c&&x[a]&&(c=a);c||!0!==C[a]||(e("<"),e(a), +h.forEach(k,function(c,f){var k=h.lowercase(f),g="img"===a&&"src"===k||"background"===k;!0!==P[k]||!0===D[k]&&!d(c,g)||(e(" "),e(f),e('="'),e(B(c)),e('"'))}),e(f?"/>":">"))},end:function(a){a=h.lowercase(a);c||!0!==C[a]||(e(""));a==c&&(c=!1)},chars:function(a){c||e(B(a))}}}var L=h.$$minErr("$sanitize"),A=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,z=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, +K=/^]*?)>/i,I=/"\u201d\u2019]/,c=/^mailto:/;return function(e,b){function k(a){a&&g.push(E(a))} +function f(a,c){g.push("');k(c);g.push("")}if(!e)return e;for(var m,l=e,g=[],n,p;m=l.match(d);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),f(n,m[0].replace(c,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular); +//# sourceMappingURL=angular-sanitize.min.js.map diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map b/zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map new file mode 100644 index 0000000..66bf00a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-sanitize_1.3.13/angular-sanitize.min.js.map @@ -0,0 +1,8 @@ +{ +"version":3, +"file":"angular-sanitize.min.js", +"lineCount":15, +"mappings":"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", +"sources":["angular-sanitize.js"], +"names":["window","angular","undefined","sanitizeText","chars","buf","htmlSanitizeWriter","writer","noop","join","makeMap","str","obj","items","split","i","length","htmlParser","html","handler","parseStartTag","tag","tagName","rest","unary","lowercase","blockElements","stack","last","inlineElements","parseEndTag","optionalEndTagElements","voidElements","push","attrs","replace","ATTR_REGEXP","match","name","doubleQuotedValue","singleQuotedValue","unquotedValue","decodeEntities","start","pos","end","index","text","stack.last","specialElements","RegExp","all","COMMENT_REGEXP","CDATA_REGEXP","indexOf","lastIndexOf","comment","substring","DOCTYPE_REGEXP","test","BEGING_END_TAGE_REGEXP","END_TAG_REGEXP","BEGIN_TAG_REGEXP","START_TAG_REGEXP","$sanitizeMinErr","value","parts","spaceRe","exec","spaceBefore","spaceAfter","content","hiddenPre","innerHTML","textContent","innerText","encodeEntities","SURROGATE_PAIR_REGEXP","hi","charCodeAt","low","NON_ALPHANUMERIC_REGEXP","uriValidator","ignore","out","bind","validElements","forEach","key","lkey","isImage","validAttrs","uriAttrs","$$minErr","optionalEndTagBlockElements","optionalEndTagInlineElements","extend","svgElements","htmlAttrs","svgAttrs","document","createElement","module","provider","$SanitizeProvider","$get","$$sanitizeUri","uri","filter","$sanitize","LINKY_URL_REGEXP","MAILTO_REGEXP","target","addText","addLink","url","isDefined","raw","substr"] +} diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-scroll_0.5.7/angular-scroll.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-scroll_0.5.7/angular-scroll.min.js new file mode 100644 index 0000000..d979dfe --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-scroll_0.5.7/angular-scroll.min.js @@ -0,0 +1 @@ +var duScrollDefaultEasing=function(e){return.5>e?Math.pow(2*e,2)/2:1-Math.pow(2*(1-e),2)/2};angular.module("duScroll",["duScroll.scrollspy","duScroll.requestAnimation","duScroll.smoothScroll","duScroll.scrollContainer","duScroll.scrollHelpers"]).value("duScrollDuration",350).value("duScrollGreedy",!1).value("duScrollEasing",duScrollDefaultEasing),angular.module("duScroll.scrollHelpers",[]).run(["$window","$q","cancelAnimation","requestAnimation","duScrollEasing",function(e,t,n,r,o){var l=angular.element.prototype;this.$get=function(){return l};var i=function(e){return"undefined"!=typeof HTMLDocument&&e instanceof HTMLDocument||e.nodeType&&e.nodeType===e.DOCUMENT_NODE},u=function(e){return"undefined"!=typeof HTMLElement&&e instanceof HTMLElement||e.nodeType&&e.nodeType===e.ELEMENT_NODE},c=function(e){return u(e)||i(e)?e:e[0]};l.scrollTo=function(t,n,r){var o;if(angular.isElement(t)?o=this.scrollToElement:r&&(o=this.scrollToAnimated),o)return o.apply(this,arguments);var l=c(this);return i(l)?e.scrollTo(t,n):(l.scrollLeft=t,void(l.scrollTop=n))};var a,s;l.scrollToAnimated=function(e,l,i,u){i&&!u&&(u=o);var c=this.scrollLeft(),d=this.scrollTop(),f=Math.round(e-c),p=Math.round(l-d),m=null;a&&(n(a),s.reject());var g=this;if(s=t.defer(),!f&&!p)return s.resolve(),s.promise;var v=function(e){null===m&&(m=e);var t=e-m,n=t>=i?1:u(t/i);g.scrollTo(c+Math.ceil(f*n),d+Math.ceil(p*n)),1>n?a=r(v):(a=null,s.resolve())};return g.scrollTo(c,d),a=r(v),s.promise},l.scrollToElement=function(e,t,n,r){var o=c(this),l=this.scrollTop()+c(e).getBoundingClientRect().top-t;return u(o)&&(l-=o.getBoundingClientRect().top),this.scrollTo(0,l,n,r)};var d={scrollLeft:function(t,n,r){if(angular.isNumber(t))return this.scrollTo(t,this.scrollTop(),n,r);var o=c(this);return i(o)?e.scrollX||document.documentElement.scrollLeft||document.body.scrollLeft:o.scrollLeft},scrollTop:function(t,n,r){if(angular.isNumber(t))return this.scrollTo(this.scrollTop(),t,n,r);var o=c(this);return i(o)?e.scrollY||document.documentElement.scrollTop||document.body.scrollTop:o.scrollTop}},f=function(e,t){return function(n,r){return r?t.apply(this,arguments):e.apply(this,arguments)}};for(var p in d)l[p]=l[p]?f(l[p],d[p]):d[p]}]),angular.module("duScroll.polyfill",[]).factory("polyfill",["$window",function(e){var t=["webkit","moz","o","ms"];return function(n,r){if(e[n])return e[n];for(var o,l=n.substr(0,1).toUpperCase()+n.substr(1),i=0;i',link:function(b,c,d,e){function f(b){var c=h;b?c=b.toString():a.isUndefined(h)&&(c=b),e.$setViewValue(c)}var g=c.find("input"),h=b.$eval(d.fallbackValue),i=function(a){b.$apply(function(){f(a)})},j=function(){return g.spectrum("toggle"),!1},k=a.extend({color:e.$viewValue,change:i,move:i,hide:i},b.$eval(d.options));d.triggerId&&a.element(document.body).on("click","#"+d.triggerId,j),e.$render=function(){g.spectrum("set",e.$viewValue||"")},k.color&&(g.spectrum("set",k.color||""),f(k.color)),g.spectrum(k),b.$on("$destroy",function(){g.spectrum("destroy")})}}})}(angular); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css b/zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css new file mode 100644 index 0000000..6a83b72 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.css @@ -0,0 +1,519 @@ +/*** +Spectrum Colorpicker v1.3.4 +https://github.com/bgrins/spectrum +Author: Brian Grinstead +License: MIT +***/ + +.sp-container { + position:absolute; + top:0; + left:0; + display:inline-block; + *display: inline; + *zoom: 1; + /* https://github.com/bgrins/spectrum/issues/40 */ + z-index: 9999994; + overflow: hidden; +} +.sp-container.sp-flat { + position: relative; +} + +/* Fix for * { box-sizing: border-box; } */ +.sp-container, +.sp-container * { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ +.sp-top { + position:relative; + width: 100%; + display:inline-block; +} +.sp-top-inner { + position:absolute; + top:0; + left:0; + bottom:0; + right:0; +} +.sp-color { + position: absolute; + top:0; + left:0; + bottom:0; + right:20%; +} +.sp-hue { + position: absolute; + top:0; + right:0; + bottom:0; + left:84%; + height: 100%; +} + +.sp-clear-enabled .sp-hue { + top:33px; + height: 77.5%; +} + +.sp-fill { + padding-top: 80%; +} +.sp-sat, .sp-val { + position: absolute; + top:0; + left:0; + right:0; + bottom:0; +} + +.sp-alpha-enabled .sp-top { + margin-bottom: 18px; +} +.sp-alpha-enabled .sp-alpha { + display: block; +} +.sp-alpha-handle { + position:absolute; + top:-4px; + bottom: -4px; + width: 6px; + left: 50%; + cursor: pointer; + border: 1px solid black; + background: white; + opacity: .8; +} +.sp-alpha { + display: none; + position: absolute; + bottom: -14px; + right: 0; + left: 0; + height: 8px; +} +.sp-alpha-inner { + border: solid 1px #333; +} + +.sp-clear { + display: none; +} + +.sp-clear.sp-clear-display { + background-position: center; +} + +.sp-clear-enabled .sp-clear { + display: block; + position:absolute; + top:0px; + right:0; + bottom:0; + left:84%; + height: 28px; +} + +/* Don't allow text selection */ +.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { + -webkit-user-select:none; + -moz-user-select: -moz-none; + -o-user-select:none; + user-select: none; +} + +.sp-container.sp-input-disabled .sp-input-container { + display: none; +} +.sp-container.sp-buttons-disabled .sp-button-container { + display: none; +} +.sp-palette-only .sp-picker-container { + display: none; +} +.sp-palette-disabled .sp-palette-container { + display: none; +} + +.sp-initial-disabled .sp-initial { + display: none; +} + + +/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ +.sp-sat { + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; + filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81'); +} +.sp-val { + background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); + background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); + background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0)); + background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0)); + -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; + filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000'); +} + +.sp-hue { + background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); + background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); + background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); +} + +/* IE filters do not support multiple color stops. + Generate 6 divs, line them up, and do two color gradients for each. + Yes, really. + */ +.sp-1 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00'); +} +.sp-2 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00'); +} +.sp-3 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff'); +} +.sp-4 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff'); +} +.sp-5 { + height:16%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff'); +} +.sp-6 { + height:17%; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000'); +} + +.sp-hidden { + display: none !important; +} + +/* Clearfix hack */ +.sp-cf:before, .sp-cf:after { content: ""; display: table; } +.sp-cf:after { clear: both; } +.sp-cf { *zoom: 1; } + +/* Mobile devices, make hue slider bigger so it is easier to slide */ +@media (max-device-width: 480px) { + .sp-color { right: 40%; } + .sp-hue { left: 63%; } + .sp-fill { padding-top: 60%; } +} +.sp-dragger { + border-radius: 5px; + height: 5px; + width: 5px; + border: 1px solid #fff; + background: #000; + cursor: pointer; + position:absolute; + top:0; + left: 0; +} +.sp-slider { + position: absolute; + top:0; + cursor:pointer; + height: 3px; + left: -1px; + right: -1px; + border: 1px solid #000; + background: white; + opacity: .8; +} + +/* +Theme authors: +Here are the basic themeable display options (colors, fonts, global widths). +See http://bgrins.github.io/spectrum/themes/ for instructions. +*/ + +.sp-container { + border-radius: 0; + background-color: #ECECEC; + border: solid 1px #f0c49B; + padding: 0; +} +.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear +{ + font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + box-sizing: border-box; +} +.sp-top +{ + margin-bottom: 3px; +} +.sp-color, .sp-hue, .sp-clear +{ + border: solid 1px #666; +} + +/* Input */ +.sp-input-container { + float:right; + width: 100px; + margin-bottom: 4px; +} +.sp-initial-disabled .sp-input-container { + width: 100%; +} +.sp-input { + font-size: 12px !important; + border: 1px inset; + padding: 4px 5px; + margin: 0; + width: 100%; + background:transparent; + border-radius: 3px; + color: #222; +} +.sp-input:focus { + border: 1px solid orange; +} +.sp-input.sp-validation-error +{ + border: 1px solid red; + background: #fdd; +} +.sp-picker-container , .sp-palette-container +{ + float:left; + position: relative; + padding: 10px; + padding-bottom: 300px; + margin-bottom: -290px; +} +.sp-picker-container +{ + width: 172px; + border-left: solid 1px #fff; +} + +/* Palettes */ +.sp-palette-container +{ + border-right: solid 1px #ccc; +} + +.sp-palette .sp-thumb-el { + display: block; + position:relative; + float:left; + width: 24px; + height: 15px; + margin: 3px; + cursor: pointer; + border:solid 2px transparent; +} +.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { + border-color: orange; +} +.sp-thumb-el +{ + position:relative; +} + +/* Initial */ +.sp-initial +{ + float: left; + border: solid 1px #333; +} +.sp-initial span { + width: 30px; + height: 25px; + border:none; + display:block; + float:left; + margin:0; +} + +.sp-initial .sp-clear-display { + background-position: center; +} + +/* Buttons */ +.sp-button-container { + float: right; +} + +/* Replacer (the little preview div that shows up instead of the ) */ +.sp-replacer { + margin:0; + overflow:hidden; + cursor:pointer; + padding: 4px; + display:inline-block; + *zoom: 1; + *display: inline; + border: solid 1px #91765d; + background: #eee; + color: #333; + vertical-align: middle; +} +.sp-replacer:hover, .sp-replacer.sp-active { + border-color: #F0C49B; + color: #111; +} +.sp-replacer.sp-disabled { + cursor:default; + border-color: silver; + color: silver; +} +.sp-dd { + padding: 2px 0; + height: 16px; + line-height: 16px; + float:left; + font-size:10px; +} +.sp-preview +{ + position:relative; + width:25px; + height: 20px; + border: solid 1px #222; + margin-right: 5px; + float:left; + z-index: 0; +} + +.sp-palette +{ + *width: 220px; + max-width: 220px; +} +.sp-palette .sp-thumb-el +{ + width:16px; + height: 16px; + margin:2px 1px; + border: solid 1px #d0d0d0; +} + +.sp-container +{ + padding-bottom:0; +} + + +/* Buttons: http://hellohappy.org/css3-buttons/ */ +.sp-container button { + background-color: #eeeeee; + background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); + background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); + background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); + background-image: -o-linear-gradient(top, #eeeeee, #cccccc); + background-image: linear-gradient(to bottom, #eeeeee, #cccccc); + border: 1px solid #ccc; + border-bottom: 1px solid #bbb; + border-radius: 3px; + color: #333; + font-size: 14px; + line-height: 1; + padding: 5px 4px; + text-align: center; + text-shadow: 0 1px 0 #eee; + vertical-align: middle; +} +.sp-container button:hover { + background-color: #dddddd; + background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); + background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); + background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); + border: 1px solid #bbb; + border-bottom: 1px solid #999; + cursor: pointer; + text-shadow: 0 1px 0 #ddd; +} +.sp-container button:active { + border: 1px solid #aaa; + border-bottom: 1px solid #888; + -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; + box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; +} +.sp-cancel +{ + font-size: 11px; + color: #d93f3f !important; + margin:0; + padding:2px; + margin-right: 5px; + vertical-align: middle; + text-decoration:none; + +} +.sp-cancel:hover +{ + color: #d93f3f !important; + text-decoration: underline; +} + + +.sp-palette span:hover, .sp-palette span.sp-thumb-active +{ + border-color: #000; +} + +.sp-preview, .sp-alpha, .sp-thumb-el +{ + position:relative; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); +} +.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner +{ + display:block; + position:absolute; + top:0;left:0;bottom:0;right:0; +} + +.sp-palette .sp-thumb-inner +{ + background-position: 50% 50%; + background-repeat: no-repeat; +} + +.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); +} + +.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner +{ + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); +} + +.sp-clear-display { + background-repeat:no-repeat; + background-position: center; + background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==); +} diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js b/zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js new file mode 100644 index 0000000..8ced40a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-spectrum-colorpicker_1.0.13/spectrum.js @@ -0,0 +1,2080 @@ +// Spectrum Colorpicker v1.3.4 +// https://github.com/bgrins/spectrum +// Author: Brian Grinstead +// License: MIT + +(function (window, $, undefined) { + var defaultOpts = { + + // Callbacks + beforeShow: noop, + move: noop, + change: noop, + show: noop, + hide: noop, + + // Options + color: false, + flat: false, + showInput: false, + allowEmpty: false, + showButtons: true, + clickoutFiresChange: false, + showInitial: false, + showPalette: false, + showPaletteOnly: false, + showSelectionPalette: true, + localStorageKey: false, + appendTo: "body", + maxSelectionSize: 7, + cancelText: "cancel", + chooseText: "choose", + clearText: "Clear Color Selection", + preferredFormat: false, + className: "", // Deprecated - use containerClassName and replacerClassName instead. + containerClassName: "", + replacerClassName: "", + showAlpha: false, + theme: "sp-light", + palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]], + selectionPalette: [], + disabled: false + }, + spectrums = [], + IE = !!/msie/i.exec( window.navigator.userAgent ), + rgbaSupport = (function() { + function contains( str, substr ) { + return !!~('' + str).indexOf(substr); + } + + var elem = document.createElement('div'); + var style = elem.style; + style.cssText = 'background-color:rgba(0,0,0,.5)'; + return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla'); + })(), + inputTypeColorSupport = (function() { + var colorInput = $("")[0]; + return colorInput.type === "color" && colorInput.value !== "!"; + })(), + replaceInput = [ + "
    ", + "
    ", + "
    ", + "
    " + ].join(''), + markup = (function () { + + // IE does not support gradients with multiple stops, so we need to simulate + // that for the rainbow slider with 8 divs that each have a single gradient + var gradientFix = ""; + if (IE) { + for (var i = 1; i <= 6; i++) { + gradientFix += "
    "; + } + } + + return [ + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + gradientFix, + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "", + "
    ", + "
    ", + "
    ", + "", + "", + "
    ", + "
    ", + "
    " + ].join(""); + })(); + + function paletteTemplate (p, color, className, tooltipFormat) { + var html = []; + for (var i = 0; i < p.length; i++) { + var current = p[i]; + if(current) { + var tiny = tinycolor(current); + var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light"; + c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : ""; + + var formattedString = tiny.toString(tooltipFormat || "rgb"); + var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter(); + html.push(''); + } else { + var cls = 'sp-clear-display'; + html.push(''); + } + } + return "
    " + html.join('') + "
    "; + } + + function hideAll() { + for (var i = 0; i < spectrums.length; i++) { + if (spectrums[i]) { + spectrums[i].hide(); + } + } + } + + function instanceOptions(o, callbackContext) { + var opts = $.extend({}, defaultOpts, o); + opts.callbacks = { + 'move': bind(opts.move, callbackContext), + 'change': bind(opts.change, callbackContext), + 'show': bind(opts.show, callbackContext), + 'hide': bind(opts.hide, callbackContext), + 'beforeShow': bind(opts.beforeShow, callbackContext) + }; + + return opts; + } + + function spectrum(element, o) { + + var opts = instanceOptions(o, element), + flat = opts.flat, + showSelectionPalette = opts.showSelectionPalette, + localStorageKey = opts.localStorageKey, + theme = opts.theme, + callbacks = opts.callbacks, + resize = throttle(reflow, 10), + visible = false, + dragWidth = 0, + dragHeight = 0, + dragHelperHeight = 0, + slideHeight = 0, + slideWidth = 0, + alphaWidth = 0, + alphaSlideHelperWidth = 0, + slideHelperHeight = 0, + currentHue = 0, + currentSaturation = 0, + currentValue = 0, + currentAlpha = 1, + palette = [], + paletteArray = [], + paletteLookup = {}, + selectionPalette = opts.selectionPalette.slice(0), + maxSelectionSize = opts.maxSelectionSize, + draggingClass = "sp-dragging", + shiftMovementDirection = null; + + var doc = element.ownerDocument, + body = doc.body, + boundElement = $(element), + disabled = false, + container = $(markup, doc).addClass(theme), + dragger = container.find(".sp-color"), + dragHelper = container.find(".sp-dragger"), + slider = container.find(".sp-hue"), + slideHelper = container.find(".sp-slider"), + alphaSliderInner = container.find(".sp-alpha-inner"), + alphaSlider = container.find(".sp-alpha"), + alphaSlideHelper = container.find(".sp-alpha-handle"), + textInput = container.find(".sp-input"), + paletteContainer = container.find(".sp-palette"), + initialColorContainer = container.find(".sp-initial"), + cancelButton = container.find(".sp-cancel"), + clearButton = container.find(".sp-clear"), + chooseButton = container.find(".sp-choose"), + isInput = boundElement.is("input"), + isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color", + shouldReplace = isInput && !flat, + replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]), + offsetElement = (shouldReplace) ? replacer : boundElement, + previewElement = replacer.find(".sp-preview-inner"), + initialColor = opts.color || (isInput && boundElement.val()), + colorOnShow = false, + preferredFormat = opts.preferredFormat, + currentPreferredFormat = preferredFormat, + clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange, + isEmpty = !initialColor, + allowEmpty = opts.allowEmpty && !isInputTypeColor; + + function applyOptions() { + + if (opts.showPaletteOnly) { + opts.showPalette = true; + } + + if (opts.palette) { + palette = opts.palette.slice(0); + paletteArray = $.isArray(palette[0]) ? palette : [palette]; + paletteLookup = {}; + for (var i = 0; i < paletteArray.length; i++) { + for (var j = 0; j < paletteArray[i].length; j++) { + var rgb = tinycolor(paletteArray[i][j]).toRgbString(); + paletteLookup[rgb] = true; + } + } + } + + container.toggleClass("sp-flat", flat); + container.toggleClass("sp-input-disabled", !opts.showInput); + container.toggleClass("sp-alpha-enabled", opts.showAlpha); + container.toggleClass("sp-clear-enabled", allowEmpty); + container.toggleClass("sp-buttons-disabled", !opts.showButtons); + container.toggleClass("sp-palette-disabled", !opts.showPalette); + container.toggleClass("sp-palette-only", opts.showPaletteOnly); + container.toggleClass("sp-initial-disabled", !opts.showInitial); + container.addClass(opts.className).addClass(opts.containerClassName); + + reflow(); + } + + function initialize() { + + if (IE) { + container.find("*:not(input)").attr("unselectable", "on"); + } + + applyOptions(); + + if (shouldReplace) { + boundElement.after(replacer).hide(); + } + + if (!allowEmpty) { + clearButton.hide(); + } + + if (flat) { + boundElement.after(container).hide(); + } + else { + + var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo); + if (appendTo.length !== 1) { + appendTo = $("body"); + } + + appendTo.append(container); + } + + updateSelectionPaletteFromStorage(); + + offsetElement.bind("click.spectrum touchstart.spectrum", function (e) { + if (!disabled) { + toggle(); + } + + e.stopPropagation(); + + if (!$(e.target).is("input")) { + e.preventDefault(); + } + }); + + if(boundElement.is(":disabled") || (opts.disabled === true)) { + disable(); + } + + // Prevent clicks from bubbling up to document. This would cause it to be hidden. + container.click(stopPropagation); + + // Handle user typed input + textInput.change(setFromTextInput); + textInput.bind("paste", function () { + setTimeout(setFromTextInput, 1); + }); + textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } }); + + cancelButton.text(opts.cancelText); + cancelButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + hide("cancel"); + }); + + clearButton.attr("title", opts.clearText); + clearButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + isEmpty = true; + move(); + + if(flat) { + //for the flat style, this is a change event + updateOriginalInput(true); + } + }); + + chooseButton.text(opts.chooseText); + chooseButton.bind("click.spectrum", function (e) { + e.stopPropagation(); + e.preventDefault(); + + if (isValid()) { + updateOriginalInput(true); + hide(); + } + }); + + draggable(alphaSlider, function (dragX, dragY, e) { + currentAlpha = (dragX / alphaWidth); + isEmpty = false; + if (e.shiftKey) { + currentAlpha = Math.round(currentAlpha * 10) / 10; + } + + move(); + }, dragStart, dragStop); + + draggable(slider, function (dragX, dragY) { + currentHue = parseFloat(dragY / slideHeight); + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + move(); + }, dragStart, dragStop); + + draggable(dragger, function (dragX, dragY, e) { + + // shift+drag should snap the movement to either the x or y axis. + if (!e.shiftKey) { + shiftMovementDirection = null; + } + else if (!shiftMovementDirection) { + var oldDragX = currentSaturation * dragWidth; + var oldDragY = dragHeight - (currentValue * dragHeight); + var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY); + + shiftMovementDirection = furtherFromX ? "x" : "y"; + } + + var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x"; + var setValue = !shiftMovementDirection || shiftMovementDirection === "y"; + + if (setSaturation) { + currentSaturation = parseFloat(dragX / dragWidth); + } + if (setValue) { + currentValue = parseFloat((dragHeight - dragY) / dragHeight); + } + + isEmpty = false; + if (!opts.showAlpha) { + currentAlpha = 1; + } + + move(); + + }, dragStart, dragStop); + + if (!!initialColor) { + set(initialColor); + + // In case color was black - update the preview UI and set the format + // since the set function will not run (default color is black). + updateUI(); + currentPreferredFormat = preferredFormat || tinycolor(initialColor).format; + + addColorToSelectionPalette(initialColor); + } + else { + updateUI(); + } + + if (flat) { + show(); + } + + function palletElementClick(e) { + if (e.data && e.data.ignore) { + set($(this).data("color")); + move(); + } + else { + set($(this).data("color")); + move(); + updateOriginalInput(true); + hide(); + } + + return false; + } + + var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum"; + paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick); + initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick); + } + + function updateSelectionPaletteFromStorage() { + + if (localStorageKey && window.localStorage) { + + // Migrate old palettes over to new format. May want to remove this eventually. + try { + var oldPalette = window.localStorage[localStorageKey].split(",#"); + if (oldPalette.length > 1) { + delete window.localStorage[localStorageKey]; + $.each(oldPalette, function(i, c) { + addColorToSelectionPalette(c); + }); + } + } + catch(e) { } + + try { + selectionPalette = window.localStorage[localStorageKey].split(";"); + } + catch (e) { } + } + } + + function addColorToSelectionPalette(color) { + if (showSelectionPalette) { + var rgb = tinycolor(color).toRgbString(); + if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) { + selectionPalette.push(rgb); + while(selectionPalette.length > maxSelectionSize) { + selectionPalette.shift(); + } + } + + if (localStorageKey && window.localStorage) { + try { + window.localStorage[localStorageKey] = selectionPalette.join(";"); + } + catch(e) { } + } + } + } + + function getUniqueSelectionPalette() { + var unique = []; + if (opts.showPalette) { + for (i = 0; i < selectionPalette.length; i++) { + var rgb = tinycolor(selectionPalette[i]).toRgbString(); + + if (!paletteLookup[rgb]) { + unique.push(selectionPalette[i]); + } + } + } + + return unique.reverse().slice(0, opts.maxSelectionSize); + } + + function drawPalette() { + + var currentColor = get(); + + var html = $.map(paletteArray, function (palette, i) { + return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts.preferredFormat); + }); + + updateSelectionPaletteFromStorage(); + + if (selectionPalette) { + html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts.preferredFormat)); + } + + paletteContainer.html(html.join("")); + } + + function drawInitial() { + if (opts.showInitial) { + var initial = colorOnShow; + var current = get(); + initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts.preferredFormat)); + } + } + + function dragStart() { + if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) { + reflow(); + } + container.addClass(draggingClass); + shiftMovementDirection = null; + boundElement.trigger('dragstart.spectrum', [ get() ]); + } + + function dragStop() { + container.removeClass(draggingClass); + boundElement.trigger('dragstop.spectrum', [ get() ]); + } + + function setFromTextInput() { + + var value = textInput.val(); + + if ((value === null || value === "") && allowEmpty) { + set(null); + updateOriginalInput(true); + } + else { + var tiny = tinycolor(value); + if (tiny.ok) { + set(tiny); + updateOriginalInput(true); + } + else { + textInput.addClass("sp-validation-error"); + } + } + } + + function toggle() { + if (visible) { + hide(); + } + else { + show(); + } + } + + function show() { + var event = $.Event('beforeShow.spectrum'); + + if (visible) { + reflow(); + return; + } + + boundElement.trigger(event, [ get() ]); + + if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) { + return; + } + + hideAll(); + visible = true; + + $(doc).bind("click.spectrum", hide); + $(window).bind("resize.spectrum", resize); + replacer.addClass("sp-active"); + container.removeClass("sp-hidden"); + + reflow(); + updateUI(); + + colorOnShow = get(); + + drawInitial(); + callbacks.show(colorOnShow); + boundElement.trigger('show.spectrum', [ colorOnShow ]); + } + + function hide(e) { + + // Return on right click + if (e && e.type == "click" && e.button == 2) { return; } + + // Return if hiding is unnecessary + if (!visible || flat) { return; } + visible = false; + + $(doc).unbind("click.spectrum", hide); + $(window).unbind("resize.spectrum", resize); + + replacer.removeClass("sp-active"); + container.addClass("sp-hidden"); + + var colorHasChanged = !tinycolor.equals(get(), colorOnShow); + + if (colorHasChanged) { + if (clickoutFiresChange && e !== "cancel") { + updateOriginalInput(true); + } + else { + revert(); + } + } + + callbacks.hide(get()); + boundElement.trigger('hide.spectrum', [ get() ]); + } + + function revert() { + set(colorOnShow, true); + } + + function set(color, ignoreFormatChange) { + if (tinycolor.equals(color, get())) { + // Update UI just in case a validation error needs + // to be cleared. + updateUI(); + return; + } + + var newColor, newHsv; + if (!color && allowEmpty) { + isEmpty = true; + } else { + isEmpty = false; + newColor = tinycolor(color); + newHsv = newColor.toHsv(); + + currentHue = (newHsv.h % 360) / 360; + currentSaturation = newHsv.s; + currentValue = newHsv.v; + currentAlpha = newHsv.a; + } + updateUI(); + + if (newColor && newColor.ok && !ignoreFormatChange) { + currentPreferredFormat = preferredFormat || newColor.format; + } + } + + function get(opts) { + opts = opts || { }; + + if (allowEmpty && isEmpty) { + return null; + } + + return tinycolor.fromRatio({ + h: currentHue, + s: currentSaturation, + v: currentValue, + a: Math.round(currentAlpha * 100) / 100 + }, { format: opts.format || currentPreferredFormat }); + } + + function isValid() { + return !textInput.hasClass("sp-validation-error"); + } + + function move() { + updateUI(); + + callbacks.move(get()); + boundElement.trigger('move.spectrum', [ get() ]); + } + + function updateUI() { + + textInput.removeClass("sp-validation-error"); + + updateHelperLocations(); + + // Update dragger background color (gradients take care of saturation and value). + var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 }); + dragger.css("background-color", flatColor.toHexString()); + + // Get a format that alpha will be included in (hex and names ignore alpha) + var format = currentPreferredFormat; + if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) { + if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") { + format = "rgb"; + } + } + + var realColor = get({ format: format }), + displayColor = ''; + + //reset background info for preview element + previewElement.removeClass("sp-clear-display"); + previewElement.css('background-color', 'transparent'); + + if (!realColor && allowEmpty) { + // Update the replaced elements background with icon indicating no color selection + previewElement.addClass("sp-clear-display"); + } + else { + var realHex = realColor.toHexString(), + realRgb = realColor.toRgbString(); + + // Update the replaced elements background color (with actual selected color) + if (rgbaSupport || realColor.alpha === 1) { + previewElement.css("background-color", realRgb); + } + else { + previewElement.css("background-color", "transparent"); + previewElement.css("filter", realColor.toFilter()); + } + + if (opts.showAlpha) { + var rgb = realColor.toRgb(); + rgb.a = 0; + var realAlpha = tinycolor(rgb).toRgbString(); + var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")"; + + if (IE) { + alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex)); + } + else { + alphaSliderInner.css("background", "-webkit-" + gradient); + alphaSliderInner.css("background", "-moz-" + gradient); + alphaSliderInner.css("background", "-ms-" + gradient); + // Use current syntax gradient on unprefixed property. + alphaSliderInner.css("background", + "linear-gradient(to right, " + realAlpha + ", " + realHex + ")"); + } + } + + displayColor = realColor.toString(format); + } + + // Update the text entry input as it changes happen + if (opts.showInput) { + textInput.val(displayColor); + } + + if (opts.showPalette) { + drawPalette(); + } + + drawInitial(); + } + + function updateHelperLocations() { + var s = currentSaturation; + var v = currentValue; + + if(allowEmpty && isEmpty) { + //if selected color is empty, hide the helpers + alphaSlideHelper.hide(); + slideHelper.hide(); + dragHelper.hide(); + } + else { + //make sure helpers are visible + alphaSlideHelper.show(); + slideHelper.show(); + dragHelper.show(); + + // Where to show the little circle in that displays your current selected color + var dragX = s * dragWidth; + var dragY = dragHeight - (v * dragHeight); + dragX = Math.max( + -dragHelperHeight, + Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight) + ); + dragY = Math.max( + -dragHelperHeight, + Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight) + ); + dragHelper.css({ + "top": dragY + "px", + "left": dragX + "px" + }); + + var alphaX = currentAlpha * alphaWidth; + alphaSlideHelper.css({ + "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px" + }); + + // Where to show the bar that displays your current selected hue + var slideY = (currentHue) * slideHeight; + slideHelper.css({ + "top": (slideY - slideHelperHeight) + "px" + }); + } + } + + function updateOriginalInput(fireCallback) { + var color = get(), + displayColor = '', + hasChanged = !tinycolor.equals(color, colorOnShow); + + if (color) { + displayColor = color.toString(currentPreferredFormat); + // Update the selection palette with the current color + addColorToSelectionPalette(color); + } + + if (isInput) { + boundElement.val(displayColor); + } + + colorOnShow = color; + + if (fireCallback && hasChanged) { + callbacks.change(color); + boundElement.trigger('change', [ color ]); + } + } + + function reflow() { + dragWidth = dragger.width(); + dragHeight = dragger.height(); + dragHelperHeight = dragHelper.height(); + slideWidth = slider.width(); + slideHeight = slider.height(); + slideHelperHeight = slideHelper.height(); + alphaWidth = alphaSlider.width(); + alphaSlideHelperWidth = alphaSlideHelper.width(); + + if (!flat) { + container.css("position", "absolute"); + container.offset(getOffset(container, offsetElement)); + } + + updateHelperLocations(); + + if (opts.showPalette) { + drawPalette(); + } + + boundElement.trigger('reflow.spectrum'); + } + + function destroy() { + boundElement.show(); + offsetElement.unbind("click.spectrum touchstart.spectrum"); + container.remove(); + replacer.remove(); + spectrums[spect.id] = null; + } + + function option(optionName, optionValue) { + if (optionName === undefined) { + return $.extend({}, opts); + } + if (optionValue === undefined) { + return opts[optionName]; + } + + opts[optionName] = optionValue; + applyOptions(); + } + + function enable() { + disabled = false; + boundElement.attr("disabled", false); + offsetElement.removeClass("sp-disabled"); + } + + function disable() { + hide(); + disabled = true; + boundElement.attr("disabled", true); + offsetElement.addClass("sp-disabled"); + } + + initialize(); + + var spect = { + show: show, + hide: hide, + toggle: toggle, + reflow: reflow, + option: option, + enable: enable, + disable: disable, + set: function (c) { + set(c); + updateOriginalInput(); + }, + get: get, + destroy: destroy, + container: container + }; + + spect.id = spectrums.push(spect) - 1; + + return spect; + } + + /** + * checkOffset - get the offset below/above and left/right element depending on screen position + * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js + */ + function getOffset(picker, input) { + var extraY = 0; + var dpWidth = picker.outerWidth(); + var dpHeight = picker.outerHeight(); + var inputHeight = input.outerHeight(); + var doc = picker[0].ownerDocument; + var docElem = doc.documentElement; + var viewWidth = docElem.clientWidth + $(doc).scrollLeft(); + var viewHeight = docElem.clientHeight + $(doc).scrollTop(); + var offset = input.offset(); + offset.top += inputHeight; + + offset.left -= + Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? + Math.abs(offset.left + dpWidth - viewWidth) : 0); + + offset.top -= + Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? + Math.abs(dpHeight + inputHeight - extraY) : extraY)); + + return offset; + } + + /** + * noop - do nothing + */ + function noop() { + + } + + /** + * stopPropagation - makes the code only doing this a little easier to read in line + */ + function stopPropagation(e) { + e.stopPropagation(); + } + + /** + * Create a function bound to a given object + * Thanks to underscore.js + */ + function bind(func, obj) { + var slice = Array.prototype.slice; + var args = slice.call(arguments, 2); + return function () { + return func.apply(obj, args.concat(slice.call(arguments))); + }; + } + + /** + * Lightweight drag helper. Handles containment within the element, so that + * when dragging, the x is within [0,element.width] and y is within [0,element.height] + */ + function draggable(element, onmove, onstart, onstop) { + onmove = onmove || function () { }; + onstart = onstart || function () { }; + onstop = onstop || function () { }; + var doc = element.ownerDocument || document; + var dragging = false; + var offset = {}; + var maxHeight = 0; + var maxWidth = 0; + var hasTouch = ('ontouchstart' in window); + + var duringDragEvents = {}; + duringDragEvents["selectstart"] = prevent; + duringDragEvents["dragstart"] = prevent; + duringDragEvents["touchmove mousemove"] = move; + duringDragEvents["touchend mouseup"] = stop; + + function prevent(e) { + if (e.stopPropagation) { + e.stopPropagation(); + } + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + } + + function move(e) { + if (dragging) { + // Mouseup happened outside of window + if (IE && document.documentMode < 9 && !e.button) { + return stop(); + } + + var touches = e.originalEvent.touches; + var pageX = touches ? touches[0].pageX : e.pageX; + var pageY = touches ? touches[0].pageY : e.pageY; + + var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth)); + var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight)); + + if (hasTouch) { + // Stop scrolling in iOS + prevent(e); + } + + onmove.apply(element, [dragX, dragY, e]); + } + } + + function start(e) { + var rightclick = (e.which) ? (e.which == 3) : (e.button == 2); + var touches = e.originalEvent.touches; + + if (!rightclick && !dragging) { + if (onstart.apply(element, arguments) !== false) { + dragging = true; + maxHeight = $(element).height(); + maxWidth = $(element).width(); + offset = $(element).offset(); + + $(doc).bind(duringDragEvents); + $(doc.body).addClass("sp-dragging"); + + if (!hasTouch) { + move(e); + } + + prevent(e); + } + } + } + + function stop() { + if (dragging) { + $(doc).unbind(duringDragEvents); + $(doc.body).removeClass("sp-dragging"); + onstop.apply(element, arguments); + } + dragging = false; + } + + $(element).bind("touchstart mousedown", start); + } + + function throttle(func, wait, debounce) { + var timeout; + return function () { + var context = this, args = arguments; + var throttler = function () { + timeout = null; + func.apply(context, args); + }; + if (debounce) clearTimeout(timeout); + if (debounce || !timeout) timeout = setTimeout(throttler, wait); + }; + } + + function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}} + + /** + * Define a jQuery plugin + */ + var dataID = "spectrum.id"; + $.fn.spectrum = function (opts, extra) { + + if (typeof opts == "string") { + + var returnValue = this; + var args = Array.prototype.slice.call( arguments, 1 ); + + this.each(function () { + var spect = spectrums[$(this).data(dataID)]; + if (spect) { + var method = spect[opts]; + if (!method) { + throw new Error( "Spectrum: no such method: '" + opts + "'" ); + } + + if (opts == "get") { + returnValue = spect.get(); + } + else if (opts == "container") { + returnValue = spect.container; + } + else if (opts == "option") { + returnValue = spect.option.apply(spect, args); + } + else if (opts == "destroy") { + spect.destroy(); + $(this).removeData(dataID); + } + else { + method.apply(spect, args); + } + } + }); + + return returnValue; + } + + // Initializing a new instance of spectrum + return this.spectrum("destroy").each(function () { + var options = $.extend({}, opts, $(this).data()); + var spect = spectrum(this, options); + $(this).data(dataID, spect.id); + }); + }; + + $.fn.spectrum.load = true; + $.fn.spectrum.loadOpts = {}; + $.fn.spectrum.draggable = draggable; + $.fn.spectrum.defaults = defaultOpts; + + $.spectrum = { }; + $.spectrum.localization = { }; + $.spectrum.palettes = { }; + + $.fn.spectrum.processNativeColorInputs = function () { + if (!inputTypeColorSupport) { + $("input[type=color]").spectrum({ + preferredFormat: "hex6" + }); + } + }; + + // TinyColor v0.9.17 + // https://github.com/bgrins/TinyColor + // 2013-08-10, Brian Grinstead, MIT License + + (function() { + + var trimLeft = /^[\s,#]+/, + trimRight = /\s+$/, + tinyCounter = 0, + math = Math, + mathRound = math.round, + mathMin = math.min, + mathMax = math.max, + mathRandom = math.random; + + function tinycolor (color, opts) { + + color = (color) ? color : ''; + opts = opts || { }; + + // If input is already a tinycolor, return itself + if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { + return color; + } + + var rgb = inputToRGB(color); + var r = rgb.r, + g = rgb.g, + b = rgb.b, + a = rgb.a, + roundA = mathRound(100*a) / 100, + format = opts.format || rgb.format; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (r < 1) { r = mathRound(r); } + if (g < 1) { g = mathRound(g); } + if (b < 1) { b = mathRound(b); } + + return { + ok: rgb.ok, + format: format, + _tc_id: tinyCounter++, + alpha: a, + getAlpha: function() { + return a; + }, + setAlpha: function(value) { + a = boundAlpha(value); + roundA = mathRound(100*a) / 100; + }, + toHsv: function() { + var hsv = rgbToHsv(r, g, b); + return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a }; + }, + toHsvString: function() { + var hsv = rgbToHsv(r, g, b); + var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); + return (a == 1) ? + "hsv(" + h + ", " + s + "%, " + v + "%)" : + "hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")"; + }, + toHsl: function() { + var hsl = rgbToHsl(r, g, b); + return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a }; + }, + toHslString: function() { + var hsl = rgbToHsl(r, g, b); + var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); + return (a == 1) ? + "hsl(" + h + ", " + s + "%, " + l + "%)" : + "hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")"; + }, + toHex: function(allow3Char) { + return rgbToHex(r, g, b, allow3Char); + }, + toHexString: function(allow3Char) { + return '#' + this.toHex(allow3Char); + }, + toHex8: function() { + return rgbaToHex(r, g, b, a); + }, + toHex8String: function() { + return '#' + this.toHex8(); + }, + toRgb: function() { + return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a }; + }, + toRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" : + "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")"; + }, + toPercentageRgb: function() { + return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a }; + }, + toPercentageRgbString: function() { + return (a == 1) ? + "rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" : + "rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")"; + }, + toName: function() { + if (a === 0) { + return "transparent"; + } + + return hexNames[rgbToHex(r, g, b, true)] || false; + }, + toFilter: function(secondColor) { + var hex8String = '#' + rgbaToHex(r, g, b, a); + var secondHex8String = hex8String; + var gradientType = opts && opts.gradientType ? "GradientType = 1, " : ""; + + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = s.toHex8String(); + } + + return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"; + }, + toString: function(format) { + var formatSet = !!format; + format = format || this.format; + + var formattedString = false; + var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0; + var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); + + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + + if (formatWithAlpha) { + return this.toRgbString(); + } + + return formattedString || this.toHexString(); + } + }; + } + + // If input is an object, force 1 into "1.0" to handle ratios properly + // String input requires "1.0" as input, so 1 will be treated as 1 + tinycolor.fromRatio = function(color, opts) { + if (typeof color == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } + else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + + return tinycolor(color, opts); + }; + + // Given a string or object, convert that input to RGB + // Possible string inputs: + // + // "red" + // "#f00" or "f00" + // "#ff0000" or "ff0000" + // "#ff000000" or "ff000000" + // "rgb 255 0 0" or "rgb (255, 0, 0)" + // "rgb 1.0 0 0" or "rgb (1, 0, 0)" + // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" + // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" + // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" + // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" + // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" + // + function inputToRGB(color) { + + var rgb = { r: 0, g: 0, b: 0 }; + var a = 1; + var ok = false; + var format = false; + + if (typeof color == "string") { + color = stringInputToObject(color); + } + + if (typeof color == "object") { + if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { + color.s = convertToPercentage(color.s); + color.v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, color.s, color.v); + ok = true; + format = "hsv"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { + color.s = convertToPercentage(color.s); + color.l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, color.s, color.l); + ok = true; + format = "hsl"; + } + + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + + a = boundAlpha(a); + + return { + ok: ok, + format: color.format || format, + r: mathMin(255, mathMax(rgb.r, 0)), + g: mathMin(255, mathMax(rgb.g, 0)), + b: mathMin(255, mathMax(rgb.b, 0)), + a: a + }; + } + + + // Conversion Functions + // -------------------- + + // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: + // + + // `rgbToRgb` + // Handle bounds / percentage checking to conform to CSS color spec + // + // *Assumes:* r, g, b in [0, 255] or [0, 1] + // *Returns:* { r, g, b } in [0, 255] + function rgbToRgb(r, g, b){ + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; + } + + // `rgbToHsl` + // Converts an RGB color value to HSL. + // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] + // *Returns:* { h, s, l } in [0,1] + function rgbToHsl(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return { h: h, s: s, l: l }; + } + + // `hslToRgb` + // Converts an HSL color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hslToRgb(h, s, l) { + var r, g, b; + + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + if(s === 0) { + r = g = b = l; // achromatic + } + else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHsv` + // Converts an RGB color value to HSV + // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] + // *Returns:* { h, s, v } in [0,1] + function rgbToHsv(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max === 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } + else { + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h, s: s, v: v }; + } + + // `hsvToRgb` + // Converts an HSV color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + + var i = math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + + return { r: r * 255, g: g * 255, b: b * 255 }; + } + + // `rgbToHex` + // Converts an RGB color to hex + // Assumes r, g, and b are contained in the set [0, 255] + // Returns a 3 or 6 character hex + function rgbToHex(r, g, b, allow3Char) { + + var hex = [ + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + + return hex.join(""); + } + // `rgbaToHex` + // Converts an RGBA color plus alpha transparency to hex + // Assumes r, g, b and a are contained in the set [0, 255] + // Returns an 8 character hex + function rgbaToHex(r, g, b, a) { + + var hex = [ + pad2(convertDecimalToHex(a)), + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + return hex.join(""); + } + + // `equals` + // Can be called with any tinycolor input + tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) { return false; } + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); + }; + tinycolor.random = function() { + return tinycolor.fromRatio({ + r: mathRandom(), + g: mathRandom(), + b: mathRandom() + }); + }; + + + // Modification Functions + // ---------------------- + // Thanks to less.js for some of the basics here + // + + tinycolor.desaturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.saturate = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + }; + tinycolor.greyscale = function(color) { + return tinycolor.desaturate(color, 100); + }; + tinycolor.lighten = function(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.darken = function (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + }; + tinycolor.complement = function(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); + }; + + + // Combination Functions + // --------------------- + // Thanks to jQuery xColor for some of the ideas behind these + // + + tinycolor.triad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.tetrad = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) + ]; + }; + tinycolor.splitcomplement = function(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), + tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) + ]; + }; + tinycolor.analogous = function(color, results, slices) { + results = results || 6; + slices = slices || 30; + + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + + for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; + }; + tinycolor.monochromatic = function(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, s = hsv.s, v = hsv.v; + var ret = []; + var modification = 1 / results; + + while (results--) { + ret.push(tinycolor({ h: h, s: s, v: v})); + v = (v + modification) % 1; + } + + return ret; + }; + + + // Readability Functions + // --------------------- + // + + // `readability` + // Analyze the 2 colors and returns an object with the following properties: + // `brightness`: difference in brightness between the two colors + // `color`: difference in color/hue between the two colors + tinycolor.readability = function(color1, color2) { + var a = tinycolor(color1).toRgb(); + var b = tinycolor(color2).toRgb(); + var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000; + var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000; + var colorDiff = ( + Math.max(a.r, b.r) - Math.min(a.r, b.r) + + Math.max(a.g, b.g) - Math.min(a.g, b.g) + + Math.max(a.b, b.b) - Math.min(a.b, b.b) + ); + + return { + brightness: Math.abs(brightnessA - brightnessB), + color: colorDiff + }; + }; + + // `readable` + // http://www.w3.org/TR/AERT#color-contrast + // Ensure that foreground and background color combinations provide sufficient contrast. + // *Example* + // tinycolor.readable("#000", "#111") => false + tinycolor.readable = function(color1, color2) { + var readability = tinycolor.readability(color1, color2); + return readability.brightness > 125 && readability.color > 500; + }; + + // `mostReadable` + // Given a base color and a list of possible foreground or background + // colors for that base, returns the most readable color. + // *Example* + // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000" + tinycolor.mostReadable = function(baseColor, colorList) { + var bestColor = null; + var bestScore = 0; + var bestIsReadable = false; + for (var i=0; i < colorList.length; i++) { + + // We normalize both around the "acceptable" breaking point, + // but rank brightness constrast higher than hue. + + var readability = tinycolor.readability(baseColor, colorList[i]); + var readable = readability.brightness > 125 && readability.color > 500; + var score = 3 * (readability.brightness / 125) + (readability.color / 500); + + if ((readable && ! bestIsReadable) || + (readable && bestIsReadable && score > bestScore) || + ((! readable) && (! bestIsReadable) && score > bestScore)) { + bestIsReadable = readable; + bestScore = score; + bestColor = tinycolor(colorList[i]); + } + } + return bestColor; + }; + + + // Big List of Colors + // ------------------ + // + var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" + }; + + // Make it easy to access colors via `hexNames[hex]` + var hexNames = tinycolor.hexNames = flip(names); + + + // Utilities + // --------- + + // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` + function flip(o) { + var flipped = { }; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; + } + + // Return a valid alpha value [0,1] with all invalid values being set to 1 + function boundAlpha(a) { + a = parseFloat(a); + + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + + return a; + } + + // Take input from [0, n] and return it as [0, 1] + function bound01(n, max) { + if (isOnePointZero(n)) { n = "100%"; } + + var processPercent = isPercentage(n); + n = mathMin(max, mathMax(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if ((math.abs(n - max) < 0.000001)) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return (n % max) / parseFloat(max); + } + + // Force a number between 0 and 1 + function clamp01(val) { + return mathMin(1, mathMax(0, val)); + } + + // Parse a base-16 hex value into a base-10 integer + function parseIntFromHex(val) { + return parseInt(val, 16); + } + + // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 + // + function isOnePointZero(n) { + return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; + } + + // Check to see if string passed in is a percentage + function isPercentage(n) { + return typeof n === "string" && n.indexOf('%') != -1; + } + + // Force a hex value to have 2 characters + function pad2(c) { + return c.length == 1 ? '0' + c : '' + c; + } + + // Replace a decimal with it's percentage value + function convertToPercentage(n) { + if (n <= 1) { + n = (n * 100) + "%"; + } + + return n; + } + + // Converts a decimal to a hex value + function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); + } + // Converts a hex value to a decimal + function convertHexToDecimal(h) { + return (parseIntFromHex(h) / 255); + } + + var matchers = (function() { + + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + + return { + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; + })(); + + // `stringInputToObject` + // Permissive string parsing. Take in a number of formats, and output an object + // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` + function stringInputToObject(color) { + + color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } + else if (color == 'transparent') { + return { r: 0, g: 0, b: 0, a: 0, format: "name" }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if ((match = matchers.rgb.exec(color))) { + return { r: match[1], g: match[2], b: match[3] }; + } + if ((match = matchers.rgba.exec(color))) { + return { r: match[1], g: match[2], b: match[3], a: match[4] }; + } + if ((match = matchers.hsl.exec(color))) { + return { h: match[1], s: match[2], l: match[3] }; + } + if ((match = matchers.hsla.exec(color))) { + return { h: match[1], s: match[2], l: match[3], a: match[4] }; + } + if ((match = matchers.hsv.exec(color))) { + return { h: match[1], s: match[2], v: match[3] }; + } + if ((match = matchers.hex8.exec(color))) { + return { + a: convertHexToDecimal(match[1]), + r: parseIntFromHex(match[2]), + g: parseIntFromHex(match[3]), + b: parseIntFromHex(match[4]), + format: named ? "name" : "hex8" + }; + } + if ((match = matchers.hex6.exec(color))) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if ((match = matchers.hex3.exec(color))) { + return { + r: parseIntFromHex(match[1] + '' + match[1]), + g: parseIntFromHex(match[2] + '' + match[2]), + b: parseIntFromHex(match[3] + '' + match[3]), + format: named ? "name" : "hex" + }; + } + + return false; + } + + // Expose tinycolor to window, does not need to run in non-browser context. + window.tinycolor = tinycolor; + + })(); + + + $(function () { + if ($.fn.spectrum.load) { + $.fn.spectrum.processNativeColorInputs(); + } + }); + +})(window, jQuery); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.js b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.js new file mode 100644 index 0000000..5971d88 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.js @@ -0,0 +1,5014 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +(function(window, document, undefined) { +'use strict'; +// Source: module.js +angular.module('mgcrea.ngStrap', [ + 'mgcrea.ngStrap.modal', + 'mgcrea.ngStrap.aside', + 'mgcrea.ngStrap.alert', + 'mgcrea.ngStrap.button', + 'mgcrea.ngStrap.select', + 'mgcrea.ngStrap.datepicker', + 'mgcrea.ngStrap.timepicker', + 'mgcrea.ngStrap.navbar', + 'mgcrea.ngStrap.tooltip', + 'mgcrea.ngStrap.popover', + 'mgcrea.ngStrap.dropdown', + 'mgcrea.ngStrap.typeahead', + 'mgcrea.ngStrap.scrollspy', + 'mgcrea.ngStrap.affix', + 'mgcrea.ngStrap.tab', + 'mgcrea.ngStrap.collapse' +]); + +// Source: affix.js +angular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce']) + + .provider('$affix', function() { + + var defaults = this.defaults = { + offsetTop: 'auto' + }; + + this.$get = ["$window", "debounce", "dimensions", function($window, debounce, dimensions) { + + var bodyEl = angular.element($window.document.body); + var windowEl = angular.element($window); + + function AffixFactory(element, config) { + + var $affix = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + var targetEl = options.target; + + // Initial private vars + var reset = 'affix affix-top affix-bottom', + setWidth = false, + initialAffixTop = 0, + initialOffsetTop = 0, + offsetTop = 0, + offsetBottom = 0, + affixed = null, + unpin = null; + + var parent = element.parent(); + // Options: custom parent + if (options.offsetParent) { + if (options.offsetParent.match(/^\d+$/)) { + for (var i = 0; i < (options.offsetParent * 1) - 1; i++) { + parent = parent.parent(); + } + } + else { + parent = angular.element(options.offsetParent); + } + } + + $affix.init = function() { + + this.$parseOffsets(); + initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop; + setWidth = !element[0].style.width; + + // Bind events + targetEl.on('scroll', this.checkPosition); + targetEl.on('click', this.checkPositionWithEventLoop); + windowEl.on('resize', this.$debouncedOnResize); + + // Both of these checkPosition() calls are necessary for the case where + // the user hits refresh after scrolling to the bottom of the page. + this.checkPosition(); + this.checkPositionWithEventLoop(); + + }; + + $affix.destroy = function() { + + // Unbind events + targetEl.off('scroll', this.checkPosition); + targetEl.off('click', this.checkPositionWithEventLoop); + windowEl.off('resize', this.$debouncedOnResize); + + }; + + $affix.checkPositionWithEventLoop = function() { + + // IE 9 throws an error if we use 'this' instead of '$affix' + // in this setTimeout call + setTimeout($affix.checkPosition, 1); + + }; + + $affix.checkPosition = function() { + // if (!this.$element.is(':visible')) return + + var scrollTop = getScrollTop(); + var position = dimensions.offset(element[0]); + var elementHeight = dimensions.height(element[0]); + + // Get required affix class according to position + var affix = getRequiredAffixClass(unpin, position, elementHeight); + + // Did affix status changed this last check? + if(affixed === affix) return; + affixed = affix; + + // Add proper affix class + element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : '')); + + if(affix === 'top') { + unpin = null; + element.css('position', (options.offsetParent) ? '' : 'relative'); + if(setWidth) { + element.css('width', ''); + } + element.css('top', ''); + } else if(affix === 'bottom') { + if (options.offsetUnpin) { + unpin = -(options.offsetUnpin * 1); + } + else { + // Calculate unpin threshold when affixed to bottom. + // Hopefully the browser scrolls pixel by pixel. + unpin = position.top - scrollTop; + } + if(setWidth) { + element.css('width', ''); + } + element.css('position', (options.offsetParent) ? '' : 'relative'); + element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px')); + } else { // affix === 'middle' + unpin = null; + if(setWidth) { + element.css('width', element[0].offsetWidth + 'px'); + } + element.css('position', 'fixed'); + element.css('top', initialAffixTop + 'px'); + } + + }; + + $affix.$onResize = function() { + $affix.$parseOffsets(); + $affix.checkPosition(); + }; + $affix.$debouncedOnResize = debounce($affix.$onResize, 50); + + $affix.$parseOffsets = function() { + var initialPosition = element.css('position'); + // Reset position to calculate correct offsetTop + element.css('position', (options.offsetParent) ? '' : 'relative'); + + if(options.offsetTop) { + if(options.offsetTop === 'auto') { + options.offsetTop = '+0'; + } + if(options.offsetTop.match(/^[-+]\d+$/)) { + initialAffixTop = - options.offsetTop * 1; + if(options.offsetParent) { + offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1); + } + else { + offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1); + } + } + else { + offsetTop = options.offsetTop * 1; + } + } + + if(options.offsetBottom) { + if(options.offsetParent && options.offsetBottom.match(/^[-+]\d+$/)) { + // add 1 pixel due to rounding problems... + offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1; + } + else { + offsetBottom = options.offsetBottom * 1; + } + } + + // Bring back the element's position after calculations + element.css('position', initialPosition); + }; + + // Private methods + + function getRequiredAffixClass(unpin, position, elementHeight) { + + var scrollTop = getScrollTop(); + var scrollHeight = getScrollHeight(); + + if(scrollTop <= offsetTop) { + return 'top'; + } else if(unpin !== null && (scrollTop + unpin <= position.top)) { + return 'middle'; + } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) { + return 'bottom'; + } else { + return 'middle'; + } + + } + + function getScrollTop() { + return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop; + } + + function getScrollHeight() { + return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight; + } + + $affix.init(); + return $affix; + + } + + return AffixFactory; + + }]; + + }) + + .directive('bsAffix', ["$affix", "$window", function($affix, $window) { + + return { + restrict: 'EAC', + require: '^?bsAffixTarget', + link: function postLink(scope, element, attr, affixTarget) { + + var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)}; + angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + var affix = $affix(element, options); + scope.$on('$destroy', function() { + affix && affix.destroy(); + options = null; + affix = null; + }); + + } + }; + + }]) + + .directive('bsAffixTarget', function() { + return { + controller: ["$element", function($element) { + this.$element = $element; + }] + }; + }); + +// Source: alert.js +// @BUG: following snippet won't compile correctly +// @TODO: submit issue to core +// ' ' + + +angular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal']) + + .provider('$alert', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'alert', + prefixEvent: 'alert', + placement: null, + template: 'alert/alert.tpl.html', + container: false, + element: null, + backdrop: false, + keyboard: true, + show: true, + // Specific options + duration: false, + type: false, + dismissable: true + }; + + this.$get = ["$modal", "$timeout", function($modal, $timeout) { + + function AlertFactory(config) { + + var $alert = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $alert = $modal(options); + + // Support scope as string options [/*title, content, */ type, dismissable] + $alert.$scope.dismissable = !!options.dismissable; + if(options.type) { + $alert.$scope.type = options.type; + } + + // Support auto-close duration + var show = $alert.show; + if(options.duration) { + $alert.show = function() { + show(); + $timeout(function() { + $alert.hide(); + }, options.duration * 1000); + }; + } + + return $alert; + + } + + return AlertFactory; + + }]; + + }) + + .directive('bsAlert', ["$window", "$sce", "$alert", function($window, $sce, $alert) { + + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope, element: element, show: false}; + angular.forEach(['template', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content', 'type'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + + // Support scope as an object + attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + }, true); + + // Initialize alert + var alert = $alert(options); + + // Trigger + element.on(attr.trigger || 'click', alert.toggle); + + // Garbage collection + scope.$on('$destroy', function() { + if (alert) alert.destroy(); + options = null; + alert = null; + }); + + } + }; + + }]); + +// Source: aside.js +angular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal']) + + .provider('$aside', function() { + + var defaults = this.defaults = { + animation: 'am-fade-and-slide-right', + prefixClass: 'aside', + prefixEvent: 'aside', + placement: 'right', + template: 'aside/aside.tpl.html', + contentTemplate: false, + container: false, + element: null, + backdrop: true, + keyboard: true, + html: false, + show: true + }; + + this.$get = ["$modal", function($modal) { + + function AsideFactory(config) { + + var $aside = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $aside = $modal(options); + + return $aside; + + } + + return AsideFactory; + + }]; + + }) + + .directive('bsAside', ["$window", "$sce", "$aside", function($window, $sce, $aside) { + + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + // Directive options + var options = {scope: scope, element: element, show: false}; + angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + + // Support scope as an object + attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + }, true); + + // Initialize aside + var aside = $aside(options); + + // Trigger + element.on(attr.trigger || 'click', aside.toggle); + + // Garbage collection + scope.$on('$destroy', function() { + if (aside) aside.destroy(); + options = null; + aside = null; + }); + + } + }; + + }]); + +// Source: button.js +angular.module('mgcrea.ngStrap.button', []) + + .provider('$button', function() { + + var defaults = this.defaults = { + activeClass:'active', + toggleEvent:'click' + }; + + this.$get = function() { + return {defaults: defaults}; + }; + + }) + + .directive('bsCheckboxGroup', function() { + + return { + restrict: 'A', + require: 'ngModel', + compile: function postLink(element, attr) { + element.attr('data-toggle', 'buttons'); + element.removeAttr('ng-model'); + var children = element[0].querySelectorAll('input[type="checkbox"]'); + angular.forEach(children, function(child) { + var childEl = angular.element(child); + childEl.attr('bs-checkbox', ''); + childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value')); + }); + } + + }; + + }) + + .directive('bsCheckbox', ["$button", "$$rAF", function($button, $$rAF) { + + var defaults = $button.defaults; + var constantValueRegExp = /^(true|false|\d+)$/; + + return { + restrict: 'A', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + var options = defaults; + + // Support label > input[type="checkbox"] + var isInput = element[0].nodeName === 'INPUT'; + var activeElement = isInput ? element.parent() : element; + + var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true; + if(constantValueRegExp.test(attr.trueValue)) { + trueValue = scope.$eval(attr.trueValue); + } + var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false; + if(constantValueRegExp.test(attr.falseValue)) { + falseValue = scope.$eval(attr.falseValue); + } + + // Parse exotic values + var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean'; + if(hasExoticValues) { + controller.$parsers.push(function(viewValue) { + // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue); + return viewValue ? trueValue : falseValue; + }); + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + return angular.equals(modelValue, trueValue); + }); + // Fix rendering for exotic values + scope.$watch(attr.ngModel, function(newValue, oldValue) { + controller.$render(); + }); + } + + // model -> view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + var isActive = angular.equals(controller.$modelValue, trueValue); + $$rAF(function() { + if(isInput) element[0].checked = isActive; + activeElement.toggleClass(options.activeClass, isActive); + }); + }; + + // view -> model + element.bind(options.toggleEvent, function() { + scope.$apply(function () { + // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue); + if(!isInput) { + controller.$setViewValue(!activeElement.hasClass('active')); + } + if(!hasExoticValues) { + controller.$render(); + } + }); + }); + + } + + }; + + }]) + + .directive('bsRadioGroup', function() { + + return { + restrict: 'A', + require: 'ngModel', + compile: function postLink(element, attr) { + element.attr('data-toggle', 'buttons'); + element.removeAttr('ng-model'); + var children = element[0].querySelectorAll('input[type="radio"]'); + angular.forEach(children, function(child) { + angular.element(child).attr('bs-radio', ''); + angular.element(child).attr('ng-model', attr.ngModel); + }); + } + + }; + + }) + + .directive('bsRadio', ["$button", "$$rAF", function($button, $$rAF) { + + var defaults = $button.defaults; + var constantValueRegExp = /^(true|false|\d+)$/; + + return { + restrict: 'A', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + var options = defaults; + + // Support `label > input[type="radio"]` markup + var isInput = element[0].nodeName === 'INPUT'; + var activeElement = isInput ? element.parent() : element; + + var value = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value; + + // model -> view + controller.$render = function () { + // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + var isActive = angular.equals(controller.$modelValue, value); + $$rAF(function() { + if(isInput) element[0].checked = isActive; + activeElement.toggleClass(options.activeClass, isActive); + }); + }; + + // view -> model + element.bind(options.toggleEvent, function() { + scope.$apply(function () { + // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue); + controller.$setViewValue(value); + controller.$render(); + }); + }); + + } + + }; + + }]); + +// Source: collapse.js +angular.module('mgcrea.ngStrap.collapse', []) + + .provider('$collapse', function() { + + var defaults = this.defaults = { + animation: 'am-collapse', + disallowToggle: false, + activeClass: 'in', + startCollapsed: false, + allowMultiple: false + }; + + var controller = this.controller = function($scope, $element, $attrs) { + var self = this; + + // Attributes options + self.$options = angular.copy(defaults); + angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) { + if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; + }); + + self.$toggles = []; + self.$targets = []; + + self.$viewChangeListeners = []; + + self.$registerToggle = function(element) { + self.$toggles.push(element); + }; + self.$registerTarget = function(element) { + self.$targets.push(element); + }; + + self.$unregisterToggle = function(element) { + var index = self.$toggles.indexOf(element); + // remove toggle from $toggles array + self.$toggles.splice(index, 1); + }; + self.$unregisterTarget = function(element) { + var index = self.$targets.indexOf(element); + + // remove element from $targets array + self.$targets.splice(index, 1); + + if (self.$options.allowMultiple) { + // remove target index from $active array values + deactivateItem(element); + } + + // fix active item indexes + fixActiveItemIndexes(index); + + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); + }; + + // use array to store all the currently open panels + self.$targets.$active = !self.$options.startCollapsed ? [0] : []; + self.$setActive = $scope.$setActive = function(value) { + if(angular.isArray(value)) { + self.$targets.$active = angular.copy(value); + } + else if(!self.$options.disallowToggle) { + // toogle element active status + isActive(value) ? deactivateItem(value) : activateItem(value); + } else { + activateItem(value); + } + + self.$viewChangeListeners.forEach(function(fn) { + fn(); + }); + }; + + self.$activeIndexes = function() { + return self.$options.allowMultiple ? self.$targets.$active : + self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1; + }; + + function fixActiveItemIndexes(index) { + // item with index was removed, so we + // need to adjust other items index values + var activeIndexes = self.$targets.$active; + for(var i = 0; i < activeIndexes.length; i++) { + if (index < activeIndexes[i]) { + activeIndexes[i] = activeIndexes[i] - 1; + } + + // the last item is active, so we need to + // adjust its index + if (activeIndexes[i] === self.$targets.length) { + activeIndexes[i] = self.$targets.length - 1; + } + } + } + + function isActive(value) { + var activeItems = self.$targets.$active; + return activeItems.indexOf(value) === -1 ? false : true; + } + + function deactivateItem(value) { + var index = self.$targets.$active.indexOf(value); + if (index !== -1) { + self.$targets.$active.splice(index, 1); + } + } + + function activateItem(value) { + if (!self.$options.allowMultiple) { + // remove current selected item + self.$targets.$active.splice(0, 1); + } + + if (self.$targets.$active.indexOf(value) === -1) { + self.$targets.$active.push(value); + } + } + + }; + + this.$get = function() { + var $collapse = {}; + $collapse.defaults = defaults; + $collapse.controller = controller; + return $collapse; + }; + + }) + + .directive('bsCollapse', ["$window", "$animate", "$collapse", function($window, $animate, $collapse) { + + var defaults = $collapse.defaults; + + return { + require: ['?ngModel', 'bsCollapse'], + controller: ['$scope', '$element', '$attrs', $collapse.controller], + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + + if(ngModelCtrl) { + + // Update the modelValue following + bsCollapseCtrl.$viewChangeListeners.push(function() { + ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes()); + }); + + // modelValue -> $formatters -> viewValue + ngModelCtrl.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + if (angular.isArray(modelValue)) { + // model value is an array, so just replace + // the active items directly + bsCollapseCtrl.$setActive(modelValue); + } + else { + var activeIndexes = bsCollapseCtrl.$activeIndexes(); + + if (angular.isArray(activeIndexes)) { + // we have an array of selected indexes + if (activeIndexes.indexOf(modelValue * 1) === -1) { + // item with modelValue index is not active + bsCollapseCtrl.$setActive(modelValue * 1); + } + } + else if (activeIndexes !== modelValue * 1) { + bsCollapseCtrl.$setActive(modelValue * 1); + } + } + return modelValue; + }); + + } + + } + }; + + }]) + + .directive('bsCollapseToggle', function() { + + return { + require: ['^?ngModel', '^bsCollapse'], + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + + // Add base attr + element.attr('data-toggle', 'collapse'); + + // Push pane to parent bsCollapse controller + bsCollapseCtrl.$registerToggle(element); + + // remove toggle from collapse controller when toggle is destroyed + scope.$on('$destroy', function() { + bsCollapseCtrl.$unregisterToggle(element); + }); + + element.on('click', function() { + var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element); + bsCollapseCtrl.$setActive(index * 1); + scope.$apply(); + }); + + } + }; + + }) + + .directive('bsCollapseTarget', ["$animate", function($animate) { + + return { + require: ['^?ngModel', '^bsCollapse'], + // scope: true, + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsCollapseCtrl = controllers[1]; + + // Add base class + element.addClass('collapse'); + + // Add animation class + if(bsCollapseCtrl.$options.animation) { + element.addClass(bsCollapseCtrl.$options.animation); + } + + // Push pane to parent bsCollapse controller + bsCollapseCtrl.$registerTarget(element); + + // remove pane target from collapse controller when target is destroyed + scope.$on('$destroy', function() { + bsCollapseCtrl.$unregisterTarget(element); + }); + + function render() { + var index = bsCollapseCtrl.$targets.indexOf(element); + var active = bsCollapseCtrl.$activeIndexes(); + var action = 'removeClass'; + if (angular.isArray(active)) { + if (active.indexOf(index) !== -1) { + action = 'addClass'; + } + } + else if (index === active) { + action = 'addClass'; + } + + $animate[action](element, bsCollapseCtrl.$options.activeClass); + } + + bsCollapseCtrl.$viewChangeListeners.push(function() { + render(); + }); + render(); + + } + }; + + }]); + +// Source: datepicker.js +angular.module('mgcrea.ngStrap.datepicker', [ + 'mgcrea.ngStrap.helpers.dateParser', + 'mgcrea.ngStrap.helpers.dateFormatter', + 'mgcrea.ngStrap.tooltip']) + + .provider('$datepicker', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'datepicker', + placement: 'bottom-left', + template: 'datepicker/datepicker.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + // lang: $locale.id, + useNative: false, + dateType: 'date', + dateFormat: 'shortDate', + modelDateFormat: null, + dayFormat: 'dd', + monthFormat: 'MMM', + yearFormat: 'yyyy', + monthTitleFormat: 'MMMM yyyy', + yearTitleFormat: 'yyyy', + strictFormat: false, + autoclose: false, + minDate: -Infinity, + maxDate: +Infinity, + startView: 0, + minView: 0, + startWeek: 0, + daysOfWeekDisabled: '', + iconLeft: 'glyphicon glyphicon-chevron-left', + iconRight: 'glyphicon glyphicon-chevron-right' + }; + + this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "datepickerViews", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); + + function DatepickerFactory(element, controller, config) { + + var $datepicker = $tooltip(element, angular.extend({}, defaults, config)); + var parentScope = config.scope; + var options = $datepicker.$options; + var scope = $datepicker.$scope; + if(options.startView) options.startView -= options.minView; + + // View vars + + var pickerViews = datepickerViews($datepicker); + $datepicker.$views = pickerViews.views; + var viewDate = pickerViews.viewDate; + scope.$mode = options.startView; + scope.$iconLeft = options.iconLeft; + scope.$iconRight = options.iconRight; + var $picker = $datepicker.$views[scope.$mode]; + + // Scope methods + + scope.$select = function(date) { + $datepicker.select(date); + }; + scope.$selectPane = function(value) { + $datepicker.$selectPane(value); + }; + scope.$toggleMode = function() { + $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length); + }; + + // Public methods + + $datepicker.update = function(date) { + // console.warn('$datepicker.update() newValue=%o', date); + if(angular.isDate(date) && !isNaN(date.getTime())) { + $datepicker.$date = date; + $picker.update.call($picker, date); + } + // Build only if pristine + $datepicker.$build(true); + }; + + $datepicker.updateDisabledDates = function(dateRanges) { + options.disabledDateRanges = dateRanges; + for(var i = 0, l = scope.rows.length; i < l; i++) { + angular.forEach(scope.rows[i], $datepicker.$setDisabledEl); + } + }; + + $datepicker.select = function(date, keep) { + // console.warn('$datepicker.select', date, scope.$mode); + if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date); + if(!scope.$mode || keep) { + controller.$setViewValue(angular.copy(date)); + controller.$render(); + if(options.autoclose && !keep) { + $timeout(function() { $datepicker.hide(true); }); + } + } else { + angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()}); + $datepicker.setMode(scope.$mode - 1); + $datepicker.$build(); + } + }; + + $datepicker.setMode = function(mode) { + // console.warn('$datepicker.setMode', mode); + scope.$mode = mode; + $picker = $datepicker.$views[scope.$mode]; + $datepicker.$build(); + }; + + // Protected methods + + $datepicker.$build = function(pristine) { + // console.warn('$datepicker.$build() viewDate=%o', viewDate); + if(pristine === true && $picker.built) return; + if(pristine === false && !$picker.built) return; + $picker.build.call($picker); + }; + + $datepicker.$updateSelected = function() { + for(var i = 0, l = scope.rows.length; i < l; i++) { + angular.forEach(scope.rows[i], updateSelected); + } + }; + + $datepicker.$isSelected = function(date) { + return $picker.isSelected(date); + }; + + $datepicker.$setDisabledEl = function(el) { + el.disabled = $picker.isDisabled(el.date); + }; + + $datepicker.$selectPane = function(value) { + var steps = $picker.steps; + // set targetDate to first day of month to avoid problems with + // date values rollover. This assumes the viewDate does not + // depend on the day of the month + var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1)); + angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()}); + $datepicker.$build(); + }; + + $datepicker.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + if(targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); + } + targetEl.triggerHandler('click'); + } + }; + + $datepicker.$onKeyDown = function(evt) { + if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + evt.preventDefault(); + evt.stopPropagation(); + + if(evt.keyCode === 13) { + if(!scope.$mode) { + return $datepicker.hide(true); + } else { + return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); }); + } + } + + // Navigate with keyboard + $picker.onKeyDown(evt); + parentScope.$digest(); + }; + + // Private + + function updateSelected(el) { + el.selected = $datepicker.$isSelected(el.date); + } + + function focusElement() { + element[0].focus(); + } + + // Overrides + + var _init = $datepicker.init; + $datepicker.init = function() { + if(isNative && options.useNative) { + element.prop('type', 'date'); + element.css('-webkit-appearance', 'textfield'); + return; + } else if(isTouch) { + element.prop('type', 'text'); + element.attr('readonly', 'true'); + element.on('click', focusElement); + } + _init(); + }; + + var _destroy = $datepicker.destroy; + $datepicker.destroy = function() { + if(isNative && options.useNative) { + element.off('click', focusElement); + } + _destroy(); + }; + + var _show = $datepicker.show; + $datepicker.show = function() { + _show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + // if $datepicker is no longer showing, don't setup events + if(!$datepicker.$isShown) return; + $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $datepicker.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $datepicker.hide; + $datepicker.hide = function(blur) { + if(!$datepicker.$isShown) return; + $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $datepicker.$onKeyDown); + } + _hide(blur); + }; + + return $datepicker; + + } + + DatepickerFactory.defaults = defaults; + return DatepickerFactory; + + }]; + + }) + + .directive('bsDatepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$datepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) { + + var defaults = $datepicker.defaults; + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, controller: controller}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!datepicker || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i); + newValue === true ? datepicker.show() : datepicker.hide(); + }); + + // Initialize datepicker + var datepicker = $datepicker(element, controller, options); + options = datepicker.$options; + // Set expected iOS format + if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd'; + + var lang = options.lang; + + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat}); + + // Observe attributes for changes + angular.forEach(['minDate', 'maxDate'], function(key) { + // console.warn('attr.$observe(%s)', key, attr[key]); + angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { + // console.warn('attr.$observe(%s)=%o', key, newValue); + datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue); + // Build only if dirty + !isNaN(datepicker.$options[key]) && datepicker.$build(false); + validateAgainstMinMaxDate(controller.$dateValue); + }); + }); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + datepicker.update(controller.$dateValue); + }, true); + + // Normalize undefined/null/empty array, + // so that we don't treat changing from undefined->null as a change. + function normalizeDateRanges(ranges) { + if (!ranges || !ranges.length) return null; + return ranges; + } + + if (angular.isDefined(attr.disabledDates)) { + scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) { + disabledRanges = normalizeDateRanges(disabledRanges); + previousValue = normalizeDateRanges(previousValue); + + if (disabledRanges) { + datepicker.updateDisabledDates(disabledRanges); + } + }); + } + + function validateAgainstMinMaxDate(parsedDate) { + if (!angular.isDate(parsedDate)) return; + var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate; + var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate; + var isValid = isMinValid && isMaxValid; + controller.$setValidity('date', isValid); + controller.$setValidity('min', isMinValid); + controller.$setValidity('max', isMaxValid); + // Only update the model when we have a valid date + if(isValid) controller.$dateValue = parsedDate; + } + + // viewValue -> $parsers -> modelValue + controller.$parsers.unshift(function(viewValue) { + // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue); + // Null values should correctly reset the model value & validity + if(!viewValue) { + controller.$setValidity('date', true); + // BREAKING CHANGE: + // return null (not undefined) when input value is empty, so angularjs 1.3 + // ngModelController can go ahead and run validators, like ngRequired + return null; + } + var parsedDate = dateParser.parse(viewValue, controller.$dateValue); + if(!parsedDate || isNaN(parsedDate.getTime())) { + controller.$setValidity('date', false); + // return undefined, causes ngModelController to + // invalidate model value + return; + } else { + validateAgainstMinMaxDate(parsedDate); + } + if(options.dateType === 'string') { + return formatDate(parsedDate, options.modelDateFormat || options.dateFormat); + } else if(options.dateType === 'number') { + return controller.$dateValue.getTime(); + } else if(options.dateType === 'unix') { + return controller.$dateValue.getTime() / 1000; + } else if(options.dateType === 'iso') { + return controller.$dateValue.toISOString(); + } else { + return new Date(controller.$dateValue); + } + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var date; + if(angular.isUndefined(modelValue) || modelValue === null) { + date = NaN; + } else if(angular.isDate(modelValue)) { + date = modelValue; + } else if(options.dateType === 'string') { + date = dateParser.parse(modelValue, null, options.modelDateFormat); + } else if(options.dateType === 'unix') { + date = new Date(modelValue * 1000); + } else { + date = new Date(modelValue); + } + // Setup default value? + // if(isNaN(date.getTime())) { + // var today = new Date(); + // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0); + // } + controller.$dateValue = date; + return getDateFormattedString(); + }); + + // viewValue -> element + controller.$render = function() { + // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue); + element.val(getDateFormattedString()); + }; + + function getDateFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat); + } + + // Garbage collection + scope.$on('$destroy', function() { + if(datepicker) datepicker.destroy(); + options = null; + datepicker = null; + }); + + } + }; + + }]) + + .provider('datepickerViews', function() { + + var defaults = this.defaults = { + dayFormat: 'dd', + daySplit: 7 + }; + + // Split array into smaller arrays + function split(arr, size) { + var arrays = []; + while(arr.length > 0) { + arrays.push(arr.splice(0, size)); + } + return arrays; + } + + // Modulus operator + function mod(n, m) { + return ((n % m) + m) % m; + } + + this.$get = ["$dateFormatter", "$dateParser", "$sce", function($dateFormatter, $dateParser, $sce) { + + return function(picker) { + + var scope = picker.$scope; + var options = picker.$options; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat}); + + var weekDaysMin = $dateFormatter.weekdaysShort(lang); + var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek)); + var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + ''); + + var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date()); + var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()}; + var timezoneOffset = startDate.getTimezoneOffset() * 6e4; + + var views = [{ + format: options.dayFormat, + split: 7, + steps: { month: 1 }, + update: function(date, force) { + if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$build(); + } else if(date.getDate() !== viewDate.date) { + viewDate.date = picker.$date.getDate(); + picker.$updateSelected(); + } + }, + build: function() { + var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset(); + var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset(); + var today = new Date().toDateString(); + // Handle daylight time switch + if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3); + var days = [], day; + for(var i = 0; i < 42; i++) { // < 7 * 6 + day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i)); + days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)}); + } + scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat); + scope.showLabels = true; + scope.labels = weekDaysLabelsHtml; + scope.rows = split(days, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate(); + }, + isDisabled: function(date) { + var time = date.getTime(); + + // Disabled because of min/max date. + if (time < options.minDate || time > options.maxDate) return true; + + // Disabled due to being a disabled day of the week + if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true; + + // Disabled because of disabled date range. + if (options.disabledDateRanges) { + for (var i = 0; i < options.disabledDateRanges.length; i++) { + if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) { + return true; + } + } + } + + return false; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; + } + var actualTime = picker.$date.getTime(); + var newDate; + + if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5); + else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5); + else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5); + else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5); + + if (!this.isDisabled(newDate)) picker.select(newDate, true); + } + }, { + name: 'month', + format: options.monthFormat, + split: 4, + steps: { year: 1 }, + update: function(date, force) { + if(!this.built || date.getFullYear() !== viewDate.year) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$build(); + } else if(date.getMonth() !== viewDate.month) { + angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$updateSelected(); + } + }, + build: function() { + var firstMonth = new Date(viewDate.year, 0, 1); + var months = [], month; + for (var i = 0; i < 12; i++) { + month = new Date(viewDate.year, i, 1); + months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)}); + } + scope.title = formatDate(month, options.yearTitleFormat); + scope.showLabels = false; + scope.rows = split(months, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth(); + }, + isDisabled: function(date) { + var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0); + return lastDate < options.minDate || date.getTime() > options.maxDate; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; + } + var actualMonth = picker.$date.getMonth(); + var newDate = new Date(picker.$date); + + if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1); + else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4); + else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1); + else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4); + + if (!this.isDisabled(newDate)) picker.select(newDate, true); + } + }, { + name: 'year', + format: options.yearFormat, + split: 4, + steps: { year: 12 }, + update: function(date, force) { + if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$build(); + } else if(date.getFullYear() !== viewDate.year) { + angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()}); + picker.$updateSelected(); + } + }, + build: function() { + var firstYear = viewDate.year - viewDate.year % (this.split * 3); + var years = [], year; + for (var i = 0; i < 12; i++) { + year = new Date(firstYear + i, 0, 1); + years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)}); + } + scope.title = years[0].label + '-' + years[years.length - 1].label; + scope.showLabels = false; + scope.rows = split(years, this.split); + this.built = true; + }, + isSelected: function(date) { + return picker.$date && date.getFullYear() === picker.$date.getFullYear(); + }, + isDisabled: function(date) { + var lastDate = +new Date(date.getFullYear() + 1, 0, 0); + return lastDate < options.minDate || date.getTime() > options.maxDate; + }, + onKeyDown: function(evt) { + if (!picker.$date) { + return; + } + var actualYear = picker.$date.getFullYear(), + newDate = new Date(picker.$date); + + if(evt.keyCode === 37) newDate.setYear(actualYear - 1); + else if(evt.keyCode === 38) newDate.setYear(actualYear - 4); + else if(evt.keyCode === 39) newDate.setYear(actualYear + 1); + else if(evt.keyCode === 40) newDate.setYear(actualYear + 4); + + if (!this.isDisabled(newDate)) picker.select(newDate, true); + } + }]; + + return { + views: options.minView ? Array.prototype.slice.call(views, options.minView) : views, + viewDate: viewDate + }; + + }; + + }]; + + }); + +// Source: dropdown.js +angular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip']) + + .provider('$dropdown', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'dropdown', + placement: 'bottom-left', + template: 'dropdown/dropdown.tpl.html', + trigger: 'click', + container: false, + keyboard: true, + html: false, + delay: 0 + }; + + this.$get = ["$window", "$rootScope", "$tooltip", "$timeout", function($window, $rootScope, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector; + + function DropdownFactory(element, config) { + + var $dropdown = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + + $dropdown = $tooltip(element, options); + var parentEl = element.parent(); + + // Protected methods + + $dropdown.$onKeyDown = function(evt) { + if (!/(38|40)/.test(evt.keyCode)) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Retrieve focused index + var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a')); + if(!items.length) return; + var index; + angular.forEach(items, function(el, i) { + if(matchesSelector && matchesSelector.call(el, ':focus')) index = i; + }); + + // Navigate with keyboard + if(evt.keyCode === 38 && index > 0) index--; + else if(evt.keyCode === 40 && index < items.length - 1) index++; + else if(angular.isUndefined(index)) index = 0; + items.eq(index)[0].focus(); + + }; + + // Overrides + + var show = $dropdown.show; + $dropdown.show = function() { + show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown); + bodyEl.on('click', onBodyClick); + }, 0, false); + parentEl.hasClass('dropdown') && parentEl.addClass('open'); + }; + + var hide = $dropdown.hide; + $dropdown.hide = function() { + if(!$dropdown.$isShown) return; + options.keyboard && $dropdown.$element.off('keydown', $dropdown.$onKeyDown); + bodyEl.off('click', onBodyClick); + parentEl.hasClass('dropdown') && parentEl.removeClass('open'); + hide(); + }; + + var destroy = $dropdown.destroy; + $dropdown.destroy = function() { + bodyEl.off('click', onBodyClick); + destroy(); + }; + + // Private functions + + function onBodyClick(evt) { + if(evt.target === element[0]) return; + return evt.target !== element[0] && $dropdown.hide(); + } + + return $dropdown; + + } + + return DropdownFactory; + + }]; + + }) + + .directive('bsDropdown', ["$window", "$sce", "$dropdown", function($window, $sce, $dropdown) { + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as an object + attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) { + scope.content = newValue; + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!dropdown || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i); + newValue === true ? dropdown.show() : dropdown.hide(); + }); + + // Initialize dropdown + var dropdown = $dropdown(element, options); + + // Garbage collection + scope.$on('$destroy', function() { + if (dropdown) dropdown.destroy(); + options = null; + dropdown = null; + }); + + } + }; + + }]); + +// Source: date-formatter.js +angular.module('mgcrea.ngStrap.helpers.dateFormatter', []) + + .service('$dateFormatter', ["$locale", "dateFilter", function($locale, dateFilter) { + + // The unused `lang` arguments are on purpose. The default implementation does not + // use them and it always uses the locale loaded into the `$locale` service. + // Custom implementations might use it, thus allowing different directives to + // have different languages. + + this.getDefaultLocale = function() { + return $locale.id; + }; + + // Format is either a data format name, e.g. "shortTime" or "fullDate", or a date format + // Return either the corresponding date format or the given date format. + this.getDatetimeFormat = function(format, lang) { + return $locale.DATETIME_FORMATS[format] || format; + }; + + this.weekdaysShort = function(lang) { + return $locale.DATETIME_FORMATS.SHORTDAY; + }; + + function splitTimeFormat(format) { + return /(h+)([:\.])?(m+)[ ]?(a?)/i.exec(format).slice(1); + } + + // h:mm a => h + this.hoursFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[0]; + }; + + // h:mm a => mm + this.minutesFormat = function(timeFormat) { + return splitTimeFormat(timeFormat)[2]; + }; + + // h:mm a => : + this.timeSeparator = function(timeFormat) { + return splitTimeFormat(timeFormat)[1]; + }; + + // h:mm a => true, H.mm => false + this.showAM = function(timeFormat) { + return !!splitTimeFormat(timeFormat)[3]; + }; + + this.formatDate = function(date, format, lang){ + return dateFilter(date, format); + }; + + }]); + +// Source: date-parser.js +angular.module('mgcrea.ngStrap.helpers.dateParser', []) + +.provider('$dateParser', ["$localeProvider", function($localeProvider) { + + // define a custom ParseDate object to use instead of native Date + // to avoid date values wrapping when setting date component values + function ParseDate() { + this.year = 1970; + this.month = 0; + this.day = 1; + this.hours = 0; + this.minutes = 0; + this.seconds = 0; + this.milliseconds = 0; + } + + ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; }; + ParseDate.prototype.setSeconds = function(value) { this.seconds = value; }; + ParseDate.prototype.setMinutes = function(value) { this.minutes = value; }; + ParseDate.prototype.setHours = function(value) { this.hours = value; }; + ParseDate.prototype.getHours = function() { return this.hours; }; + ParseDate.prototype.setDate = function(value) { this.day = value; }; + ParseDate.prototype.setMonth = function(value) { this.month = value; }; + ParseDate.prototype.setFullYear = function(value) { this.year = value; }; + ParseDate.prototype.fromDate = function(value) { + this.year = value.getFullYear(); + this.month = value.getMonth(); + this.day = value.getDate(); + this.hours = value.getHours(); + this.minutes = value.getMinutes(); + this.seconds = value.getSeconds(); + this.milliseconds = value.getMilliseconds(); + return this; + }; + + ParseDate.prototype.toDate = function() { + return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds); + }; + + var proto = ParseDate.prototype; + + function noop() { + } + + function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + } + + function indexOfCaseInsensitive(array, value) { + var len = array.length, str=value.toString().toLowerCase(); + for (var i=0; i 12 when midnight changeover, but then cannot generate + * midnight datetime, so jump to 1AM, otherwise reset. + * @param date (Date) the date to check + * @return (Date) the corrected date + * + * __ copied from jquery ui datepicker __ + */ + $dateParser.daylightSavingAdjust = function(date) { + if (!date) { + return null; + } + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }; + + // Private functions + + function setMapForFormat(format) { + var keys = Object.keys(setFnMap), i; + var map = [], sortedMap = []; + // Map to setFn + var clonedFormat = format; + for(i = 0; i < keys.length; i++) { + if(format.split(keys[i]).length > 1) { + var index = clonedFormat.search(keys[i]); + format = format.split(keys[i]).join(''); + if(setFnMap[keys[i]]) { + map[index] = setFnMap[keys[i]]; + } + } + } + // Sort result map + angular.forEach(map, function(v) { + // conditional required since angular.forEach broke around v1.2.21 + // related pr: https://github.com/angular/angular.js/pull/8525 + if(v) sortedMap.push(v); + }); + return sortedMap; + } + + function escapeReservedSymbols(text) { + return text.replace(/\//g, '[\\/]').replace('/-/g', '[-]').replace(/\./g, '[.]').replace(/\\s/g, '[\\s]'); + } + + function regExpForFormat(format) { + var keys = Object.keys(regExpMap), i; + + var re = format; + // Abstract replaces to avoid collisions + for(i = 0; i < keys.length; i++) { + re = re.split(keys[i]).join('${' + i + '}'); + } + // Replace abstracted values + for(i = 0; i < keys.length; i++) { + re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')'); + } + format = escapeReservedSymbols(format); + + return new RegExp('^' + re + '$', ['i']); + } + + $dateParser.init(); + return $dateParser; + + }; + + return DateParserFactory; + + }]; + +}]); + +// Source: debounce.js +angular.module('mgcrea.ngStrap.helpers.debounce', []) + +// @source jashkenas/underscore +// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693 +.factory('debounce', ["$timeout", function($timeout) { + return function(func, wait, immediate) { + var timeout = null; + return function() { + var context = this, + args = arguments, + callNow = immediate && !timeout; + if(timeout) { + $timeout.cancel(timeout); + } + timeout = $timeout(function later() { + timeout = null; + if(!immediate) { + func.apply(context, args); + } + }, wait, false); + if(callNow) { + func.apply(context, args); + } + return timeout; + }; + }; +}]) + + +// @source jashkenas/underscore +// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661 +.factory('throttle', ["$timeout", function($timeout) { + return function(func, wait, options) { + var timeout = null; + options || (options = {}); + return function() { + var context = this, + args = arguments; + if(!timeout) { + if(options.leading !== false) { + func.apply(context, args); + } + timeout = $timeout(function later() { + timeout = null; + if(options.trailing !== false) { + func.apply(context, args); + } + }, wait, false); + } + }; + }; +}]); + +// Source: dimensions.js +angular.module('mgcrea.ngStrap.helpers.dimensions', []) + + .factory('dimensions', ["$document", "$window", function($document, $window) { + + var jqLite = angular.element; + var fn = {}; + + /** + * Test the element nodeName + * @param element + * @param name + */ + var nodeName = fn.nodeName = function(element, name) { + return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase(); + }; + + /** + * Returns the element computed style + * @param element + * @param prop + * @param extra + */ + fn.css = function(element, prop, extra) { + var value; + if (element.currentStyle) { //IE + value = element.currentStyle[prop]; + } else if (window.getComputedStyle) { + value = window.getComputedStyle(element)[prop]; + } else { + value = element.style[prop]; + } + return extra === true ? parseFloat(value) || 0 : value; + }; + + /** + * Provides read-only equivalent of jQuery's offset function: + * @required-by bootstrap-tooltip, bootstrap-affix + * @url http://api.jquery.com/offset/ + * @param element + */ + fn.offset = function(element) { + var boxRect = element.getBoundingClientRect(); + var docElement = element.ownerDocument; + return { + width: boxRect.width || element.offsetWidth, + height: boxRect.height || element.offsetHeight, + top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0), + left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0) + }; + }; + + /** + * Provides read-only equivalent of jQuery's position function + * @required-by bootstrap-tooltip, bootstrap-affix + * @url http://api.jquery.com/offset/ + * @param element + */ + fn.position = function(element) { + + var offsetParentRect = {top: 0, left: 0}, + offsetParentElement, + offset; + + // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent + if (fn.css(element, 'position') === 'fixed') { + + // We assume that getBoundingClientRect is available when computed position is fixed + offset = element.getBoundingClientRect(); + + } else { + + // Get *real* offsetParentElement + offsetParentElement = offsetParent(element); + + // Get correct offsets + offset = fn.offset(element); + if (!nodeName(offsetParentElement, 'html')) { + offsetParentRect = fn.offset(offsetParentElement); + } + + // Add offsetParent borders + offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true); + offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true); + } + + // Subtract parent offsets and element margins + return { + width: element.offsetWidth, + height: element.offsetHeight, + top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true), + left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true) + }; + + }; + + /** + * Returns the closest, non-statically positioned offsetParent of a given element + * @required-by fn.position + * @param element + */ + var offsetParent = function offsetParentElement(element) { + var docElement = element.ownerDocument; + var offsetParent = element.offsetParent || docElement; + if(nodeName(offsetParent, '#document')) return docElement.documentElement; + while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') { + offsetParent = offsetParent.offsetParent; + } + return offsetParent || docElement.documentElement; + }; + + /** + * Provides equivalent of jQuery's height function + * @required-by bootstrap-affix + * @url http://api.jquery.com/height/ + * @param element + * @param outer + */ + fn.height = function(element, outer) { + var value = element.offsetHeight; + if(outer) { + value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true); + } else { + value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true); + } + return value; + }; + + /** + * Provides equivalent of jQuery's width function + * @required-by bootstrap-affix + * @url http://api.jquery.com/width/ + * @param element + * @param outer + */ + fn.width = function(element, outer) { + var value = element.offsetWidth; + if(outer) { + value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true); + } else { + value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true); + } + return value; + }; + + return fn; + + }]); + +// Source: parse-options.js +angular.module('mgcrea.ngStrap.helpers.parseOptions', []) + + .provider('$parseOptions', function() { + + var defaults = this.defaults = { + regexp: /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/ + }; + + this.$get = ["$parse", "$q", function($parse, $q) { + + function ParseOptionsFactory(attr, config) { + + var $parseOptions = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + $parseOptions.$values = []; + + // Private vars + var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn; + + $parseOptions.init = function() { + $parseOptions.$match = match = attr.match(options.regexp); + displayFn = $parse(match[2] || match[1]), + valueName = match[4] || match[6], + keyName = match[5], + groupByFn = $parse(match[3] || ''), + valueFn = $parse(match[2] ? match[1] : valueName), + valuesFn = $parse(match[7]); + }; + + $parseOptions.valuesFn = function(scope, controller) { + return $q.when(valuesFn(scope, controller)) + .then(function(values) { + $parseOptions.$values = values ? parseValues(values, scope) : {}; + return $parseOptions.$values; + }); + }; + + $parseOptions.displayValue = function(modelValue) { + var scope = {}; + scope[valueName] = modelValue; + return displayFn(scope); + }; + + // Private functions + + function parseValues(values, scope) { + return values.map(function(match, index) { + var locals = {}, label, value; + locals[valueName] = match; + label = displayFn(scope, locals); + value = valueFn(scope, locals); + return {label: label, value: value, index: index}; + }); + } + + $parseOptions.init(); + return $parseOptions; + + } + + return ParseOptionsFactory; + + }]; + + }); + +// Source: raf.js +(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng') + +.factory('$$rAF', ["$window", "$timeout", function($window, $timeout) { + + var requestAnimationFrame = $window.requestAnimationFrame || + $window.webkitRequestAnimationFrame || + $window.mozRequestAnimationFrame; + + var cancelAnimationFrame = $window.cancelAnimationFrame || + $window.webkitCancelAnimationFrame || + $window.mozCancelAnimationFrame || + $window.webkitCancelRequestAnimationFrame; + + var rafSupported = !!requestAnimationFrame; + var raf = rafSupported ? + function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + } : + function(fn) { + var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666 + return function() { + $timeout.cancel(timer); + }; + }; + + raf.supported = rafSupported; + + return raf; + +}]); + +// .factory('$$animateReflow', function($$rAF, $document) { + +// var bodyEl = $document[0].body; + +// return function(fn) { +// //the returned function acts as the cancellation function +// return $$rAF(function() { +// //the line below will force the browser to perform a repaint +// //so that all the animated elements within the animation frame +// //will be properly updated and drawn on screen. This is +// //required to perform multi-class CSS based animations with +// //Firefox. DO NOT REMOVE THIS LINE. +// var a = bodyEl.offsetWidth + 1; +// fn(); +// }); +// }; + +// }); + +// Source: modal.js +angular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions']) + + .provider('$modal', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + backdropAnimation: 'am-fade', + prefixClass: 'modal', + prefixEvent: 'modal', + placement: 'top', + template: 'modal/modal.tpl.html', + contentTemplate: false, + container: false, + element: null, + backdrop: true, + keyboard: true, + html: false, + show: true + }; + + this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$timeout", "$sce", "dimensions", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) { + + var forEach = angular.forEach; + var trim = String.prototype.trim; + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + var bodyElement = angular.element($window.document.body); + var htmlReplaceRegExp = /ng-bind="/ig; + + function ModalFactory(config) { + + var $modal = {}; + + // Common vars + var options = $modal.$options = angular.extend({}, defaults, config); + $modal.$promise = fetchTemplate(options.template); + var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + if(!options.element && !options.container) { + options.container = 'body'; + } + + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $modal.$id = options.id || options.element && options.element.attr('id') || ''; + + // Support scope as string options + forEach(['title', 'content'], function(key) { + if(options[key]) scope[key] = $sce.trustAsHtml(options[key]); + }); + + // Provide scope helpers + scope.$hide = function() { + scope.$$postDigest(function() { + $modal.hide(); + }); + }; + scope.$show = function() { + scope.$$postDigest(function() { + $modal.show(); + }); + }; + scope.$toggle = function() { + scope.$$postDigest(function() { + $modal.toggle(); + }); + }; + // Publish isShown as a protected var on scope + $modal.$isShown = scope.$isShown = false; + + // Support contentTemplate option + if(options.contentTemplate) { + $modal.$promise = $modal.$promise.then(function(template) { + var templateEl = angular.element(template); + return fetchTemplate(options.contentTemplate) + .then(function(contentTemplate) { + var contentEl = findElement('[ng-bind="content"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate); + // Drop the default footer as you probably don't want it if you use a custom contentTemplate + if(!config.template) contentEl.next().remove(); + return templateEl[0].outerHTML; + }); + }); + } + + // Fetch, compile then initialize modal + var modalLinker, modalElement; + var backdropElement = angular.element('
    '); + $modal.$promise.then(function(template) { + if(angular.isObject(template)) template = template.data; + if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="'); + template = trim.apply(template); + modalLinker = $compile(template); + $modal.init(); + }); + + $modal.init = function() { + + // Options: show + if(options.show) { + scope.$$postDigest(function() { + $modal.show(); + }); + } + + }; + + $modal.destroy = function() { + + // Remove element + if(modalElement) { + modalElement.remove(); + modalElement = null; + } + if(backdropElement) { + backdropElement.remove(); + backdropElement = null; + } + + // Destroy scope + scope.$destroy(); + + }; + + $modal.show = function() { + if($modal.$isShown) return; + + if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) { + return; + } + var parent, after; + if(angular.isElement(options.container)) { + parent = options.container; + after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null; + } else { + if (options.container) { + parent = findElement(options.container); + after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null; + } else { + parent = null; + after = options.element; + } + } + + // Fetch a cloned element linked from template + modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {}); + + // Set the initial positioning. + modalElement.css({display: 'block'}).addClass(options.placement); + + // Options: animation + if(options.animation) { + if(options.backdrop) { + backdropElement.addClass(options.backdropAnimation); + } + modalElement.addClass(options.animation); + } + + if(options.backdrop) { + $animate.enter(backdropElement, bodyElement, null); + } + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback); + if(promise && promise.then) promise.then(enterAnimateCallback); + + $modal.$isShown = scope.$isShown = true; + safeDigest(scope); + // Focus once the enter-animation has started + // Weird PhantomJS bug hack + var el = modalElement[0]; + requestAnimationFrame(function() { + el.focus(); + }); + + bodyElement.addClass(options.prefixClass + '-open'); + if(options.animation) { + bodyElement.addClass(options.prefixClass + '-with-' + options.animation); + } + + // Bind events + if(options.backdrop) { + modalElement.on('click', hideOnBackdropClick); + backdropElement.on('click', hideOnBackdropClick); + backdropElement.on('wheel', preventEventDefault); + } + if(options.keyboard) { + modalElement.on('keyup', $modal.$onKeyUp); + } + }; + + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $modal); + } + + $modal.hide = function() { + if(!$modal.$isShown) return; + + if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) { + return; + } + var promise = $animate.leave(modalElement, leaveAnimateCallback); + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + if(promise && promise.then) promise.then(leaveAnimateCallback); + + if(options.backdrop) { + $animate.leave(backdropElement); + } + $modal.$isShown = scope.$isShown = false; + safeDigest(scope); + + // Unbind events + if(options.backdrop) { + modalElement.off('click', hideOnBackdropClick); + backdropElement.off('click', hideOnBackdropClick); + backdropElement.off('wheel', preventEventDefault); + } + if(options.keyboard) { + modalElement.off('keyup', $modal.$onKeyUp); + } + }; + + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $modal); + bodyElement.removeClass(options.prefixClass + '-open'); + if(options.animation) { + bodyElement.removeClass(options.prefixClass + '-with-' + options.animation); + } + } + + $modal.toggle = function() { + + $modal.$isShown ? $modal.hide() : $modal.show(); + + }; + + $modal.focus = function() { + modalElement[0].focus(); + }; + + // Protected methods + + $modal.$onKeyUp = function(evt) { + + if (evt.which === 27 && $modal.$isShown) { + $modal.hide(); + evt.stopPropagation(); + } + + }; + + // Private methods + + function hideOnBackdropClick(evt) { + if(evt.target !== evt.currentTarget) return; + options.backdrop === 'static' ? $modal.focus() : $modal.hide(); + } + + function preventEventDefault(evt) { + evt.preventDefault(); + } + + return $modal; + + } + + // Helper functions + + function safeDigest(scope) { + scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest(); + } + + function findElement(query, element) { + return angular.element((element || document).querySelectorAll(query)); + } + + var fetchPromises = {}; + function fetchTemplate(template) { + if(fetchPromises[template]) return fetchPromises[template]; + return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template)) + .then(function(res) { + if(angular.isObject(res)) { + $templateCache.put(template, res.data); + return res.data; + } + return res; + })); + } + + return ModalFactory; + + }]; + + }) + + .directive('bsModal', ["$window", "$sce", "$modal", function($window, $sce, $modal) { + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope, element: element, show: false}; + angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + }); + }); + + // Support scope as an object + attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + }, true); + + // Initialize modal + var modal = $modal(options); + + // Trigger + element.on(attr.trigger || 'click', modal.toggle); + + // Garbage collection + scope.$on('$destroy', function() { + if (modal) modal.destroy(); + options = null; + modal = null; + }); + + } + }; + + }]); + +// Source: navbar.js +angular.module('mgcrea.ngStrap.navbar', []) + + .provider('$navbar', function() { + + var defaults = this.defaults = { + activeClass: 'active', + routeAttr: 'data-match-route', + strict: false + }; + + this.$get = function() { + return {defaults: defaults}; + }; + + }) + + .directive('bsNavbar', ["$window", "$location", "$navbar", function($window, $location, $navbar) { + + var defaults = $navbar.defaults; + + return { + restrict: 'A', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = angular.copy(defaults); + angular.forEach(Object.keys(defaults), function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Watch for the $location + scope.$watch(function() { + + return $location.path(); + + }, function(newValue, oldValue) { + + var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']'); + + angular.forEach(liElements, function(li) { + + var liElement = angular.element(li); + var pattern = liElement.attr(options.routeAttr).replace('/', '\\/'); + if(options.strict) { + pattern = '^' + pattern + '$'; + } + var regexp = new RegExp(pattern, ['i']); + + if(regexp.test(newValue)) { + liElement.addClass(options.activeClass); + } else { + liElement.removeClass(options.activeClass); + } + + }); + + }); + + } + + }; + + }]); + +// Source: popover.js +angular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip']) + + .provider('$popover', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + customClass: '', + container: false, + target: false, + placement: 'right', + template: 'popover/popover.tpl.html', + contentTemplate: false, + trigger: 'click', + keyboard: true, + html: false, + title: '', + content: '', + delay: 0, + autoClose: false + }; + + this.$get = ["$tooltip", function($tooltip) { + + function PopoverFactory(element, config) { + + // Common vars + var options = angular.extend({}, defaults, config); + + var $popover = $tooltip(element, options); + + // Support scope as string options [/*title, */content] + if(options.content) { + $popover.$scope.content = options.content; + } + + return $popover; + + } + + return PopoverFactory; + + }]; + + }) + + .directive('bsPopover', ["$window", "$sce", "$popover", function($window, $sce, $popover) { + + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Support scope as data-attrs + angular.forEach(['title', 'content'], function(key) { + attr[key] && attr.$observe(key, function(newValue, oldValue) { + scope[key] = $sce.trustAsHtml(newValue); + angular.isDefined(oldValue) && requestAnimationFrame(function() { + popover && popover.$applyPlacement(); + }); + }); + }); + + // Support scope as an object + attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.content = newValue; + } + angular.isDefined(oldValue) && requestAnimationFrame(function() { + popover && popover.$applyPlacement(); + }); + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!popover || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i); + newValue === true ? popover.show() : popover.hide(); + }); + + // Initialize popover + var popover = $popover(element, options); + + // Garbage collection + scope.$on('$destroy', function() { + if (popover) popover.destroy(); + options = null; + popover = null; + }); + + } + }; + + }]); + +// Source: select.js +angular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) + + .provider('$select', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'select', + prefixEvent: '$select', + placement: 'bottom-left', + template: 'select/select.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + multiple: false, + allNoneButtons: false, + sort: true, + caretHtml: ' ', + placeholder: 'Choose among the following...', + allText: 'All', + noneText: 'None', + maxLength: 3, + maxLengthHtml: 'selected', + iconCheckmark: 'glyphicon glyphicon-ok' + }; + + this.$get = ["$window", "$document", "$rootScope", "$tooltip", "$timeout", function($window, $document, $rootScope, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + + function SelectFactory(element, controller, config) { + + var $select = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $select = $tooltip(element, options); + var scope = $select.$scope; + + scope.$matches = []; + scope.$activeIndex = 0; + scope.$isMultiple = options.multiple; + scope.$showAllNoneButtons = options.allNoneButtons && options.multiple; + scope.$iconCheckmark = options.iconCheckmark; + scope.$allText = options.allText; + scope.$noneText = options.noneText; + + scope.$activate = function(index) { + scope.$$postDigest(function() { + $select.activate(index); + }); + }; + + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $select.select(index); + }); + }; + + scope.$isVisible = function() { + return $select.$isVisible(); + }; + + scope.$isActive = function(index) { + return $select.$isActive(index); + }; + + scope.$selectAll = function () { + for (var i = 0; i < scope.$matches.length; i++) { + if (!scope.$isActive(i)) { + scope.$select(i); + } + } + }; + + scope.$selectNone = function () { + for (var i = 0; i < scope.$matches.length; i++) { + if (scope.$isActive(i)) { + scope.$select(i); + } + } + }; + + // Public methods + + $select.update = function(matches) { + scope.$matches = matches; + $select.$updateActiveIndex(); + }; + + $select.activate = function(index) { + if(options.multiple) { + scope.$activeIndex.sort(); + $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index); + if(options.sort) scope.$activeIndex.sort(); + } else { + scope.$activeIndex = index; + } + return scope.$activeIndex; + }; + + $select.select = function(index) { + var value = scope.$matches[index].value; + scope.$apply(function() { + $select.activate(index); + if(options.multiple) { + controller.$setViewValue(scope.$activeIndex.map(function(index) { + return scope.$matches[index].value; + })); + } else { + controller.$setViewValue(value); + // Hide if single select + $select.hide(); + } + }); + // Emit event + scope.$emit(options.prefixEvent + '.select', value, index, $select); + }; + + // Protected methods + + $select.$updateActiveIndex = function() { + if(controller.$modelValue && scope.$matches.length) { + if(options.multiple && angular.isArray(controller.$modelValue)) { + scope.$activeIndex = controller.$modelValue.map(function(value) { + return $select.$getIndex(value); + }); + } else { + scope.$activeIndex = $select.$getIndex(controller.$modelValue); + } + } else if(scope.$activeIndex >= scope.$matches.length) { + scope.$activeIndex = options.multiple ? [] : 0; + } + }; + + $select.$isVisible = function() { + if(!options.minLength || !controller) { + return scope.$matches.length; + } + // minLength support + return scope.$matches.length && controller.$viewValue.length >= options.minLength; + }; + + $select.$isActive = function(index) { + if(options.multiple) { + return scope.$activeIndex.indexOf(index) !== -1; + } else { + return scope.$activeIndex === index; + } + }; + + $select.$getIndex = function(value) { + var l = scope.$matches.length, i = l; + if(!l) return; + for(i = l; i--;) { + if(scope.$matches[i].value === value) break; + } + if(i < 0) return; + return i; + }; + + $select.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + targetEl.triggerHandler('click'); + } + }; + + $select.$onKeyDown = function(evt) { + if (!/(9|13|38|40)/.test(evt.keyCode)) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Select with enter + if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) { + return $select.select(scope.$activeIndex); + } + + // Navigate with keyboard + if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; + else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; + else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); + }; + + // Overrides + + var _show = $select.show; + $select.show = function() { + _show(); + if(options.multiple) { + $select.$element.addClass('select-multiple'); + } + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $select.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $select.hide; + $select.hide = function() { + $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $select.$onKeyDown); + } + _hide(true); + }; + + return $select; + + } + + SelectFactory.defaults = defaults; + return SelectFactory; + + }]; + + }) + + .directive('bsSelect', ["$window", "$parse", "$q", "$select", "$parseOptions", function($window, $parse, $q, $select, $parseOptions) { + + var defaults = $select.defaults; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, placeholder: defaults.placeholder}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Add support for select markup + if(element[0].nodeName.toLowerCase() === 'select') { + var inputEl = element; + inputEl.css('display', 'none'); + element = angular.element(''); + inputEl.after(element); + } + + // Build proper ngOptions + var parsedOptions = $parseOptions(attr.ngOptions); + + // Initialize select + var select = $select(element, controller, options); + + // Watch ngOptions values before filtering for changes + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').trim(); + scope.$watch(watchedOptions, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue); + parsedOptions.valuesFn(scope, controller) + .then(function(values) { + select.update(values); + controller.$render(); + }); + }, true); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue); + select.$updateActiveIndex(); + controller.$render(); + }, true); + + // Model rendering in view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + var selected, index; + if(options.multiple && angular.isArray(controller.$modelValue)) { + selected = controller.$modelValue.map(function(value) { + index = select.$getIndex(value); + return angular.isDefined(index) ? select.$scope.$matches[index].label : false; + }).filter(angular.isDefined); + if(selected.length > (options.maxLength || defaults.maxLength)) { + selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml); + } else { + selected = selected.join(', '); + } + } else { + index = select.$getIndex(controller.$modelValue); + selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false; + } + element.html((selected ? selected : options.placeholder) + defaults.caretHtml); + }; + + if(options.multiple){ + controller.$isEmpty = function(value){ + return !value || value.length === 0; + }; + } + + // Garbage collection + scope.$on('$destroy', function() { + if (select) select.destroy(); + options = null; + select = null; + }); + + } + }; + + }]); + +// Source: tab.js +angular.module('mgcrea.ngStrap.tab', []) + + .provider('$tab', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + template: 'tab/tab.tpl.html', + navClass: 'nav-tabs', + activeClass: 'active' + }; + + var controller = this.controller = function($scope, $element, $attrs) { + var self = this; + + // Attributes options + self.$options = angular.copy(defaults); + angular.forEach(['animation', 'navClass', 'activeClass'], function(key) { + if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key]; + }); + + // Publish options on scope + $scope.$navClass = self.$options.navClass; + $scope.$activeClass = self.$options.activeClass; + + self.$panes = $scope.$panes = []; + + // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners + // Because we deprecated ngModel usage, we rename viewChangeListeners to + // activePaneChangeListeners to make more sense. + self.$activePaneChangeListeners = self.$viewChangeListeners = []; + + self.$push = function(pane) { + self.$panes.push(pane); + }; + + self.$remove = function(pane) { + var index = self.$panes.indexOf(pane); + var activeIndex = self.$panes.$active; + + // remove pane from $panes array + self.$panes.splice(index, 1); + + if (index < activeIndex) { + // we removed a pane before the active pane, so we need to + // decrement the active pane index + activeIndex--; + } + else if (index === activeIndex && activeIndex === self.$panes.length) { + // we remove the active pane and it was the one at the end, + // so select the previous one + activeIndex--; + } + self.$setActive(activeIndex); + }; + + self.$panes.$active = 0; + self.$setActive = $scope.$setActive = function(value) { + self.$panes.$active = value; + self.$activePaneChangeListeners.forEach(function(fn) { + fn(); + }); + }; + + }; + + this.$get = function() { + var $tab = {}; + $tab.defaults = defaults; + $tab.controller = controller; + return $tab; + }; + + }) + + .directive('bsTabs', ["$window", "$animate", "$tab", "$parse", function($window, $animate, $tab, $parse) { + + var defaults = $tab.defaults; + + return { + require: ['?ngModel', 'bsTabs'], + transclude: true, + scope: true, + controller: ['$scope', '$element', '$attrs', $tab.controller], + templateUrl: function(element, attr) { + return attr.template || defaults.template; + }, + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsTabsCtrl = controllers[1]; + + // DEPRECATED: ngModel, please use bsActivePane + // 'ngModel' is deprecated bacause if interferes with form validation + // and status, so avoid using it here. + if(ngModelCtrl) { + console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!'); + + // Update the modelValue following + bsTabsCtrl.$activePaneChangeListeners.push(function() { + ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active); + }); + + // modelValue -> $formatters -> viewValue + ngModelCtrl.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + bsTabsCtrl.$setActive(modelValue * 1); + return modelValue; + }); + + } + + if (attrs.bsActivePane) { + // adapted from angularjs ngModelController bindings + // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730 + var parsedBsActivePane = $parse(attrs.bsActivePane); + + // Update bsActivePane value with change + bsTabsCtrl.$activePaneChangeListeners.push(function() { + parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active); + }); + + // watch bsActivePane for value changes + scope.$watch(attrs.bsActivePane, function(newValue, oldValue) { + bsTabsCtrl.$setActive(newValue * 1); + }, true); + } + } + }; + + }]) + + .directive('bsPane', ["$window", "$animate", "$sce", function($window, $animate, $sce) { + + return { + require: ['^?ngModel', '^bsTabs'], + scope: true, + link: function postLink(scope, element, attrs, controllers) { + + var ngModelCtrl = controllers[0]; + var bsTabsCtrl = controllers[1]; + + // Add base class + element.addClass('tab-pane'); + + // Observe title attribute for change + attrs.$observe('title', function(newValue, oldValue) { + scope.title = $sce.trustAsHtml(newValue); + }); + + // Add animation class + if(bsTabsCtrl.$options.animation) { + element.addClass(bsTabsCtrl.$options.animation); + } + + // Push pane to parent bsTabs controller + bsTabsCtrl.$push(scope); + + // remove pane from tab controller when pane is destroyed + scope.$on('$destroy', function() { + bsTabsCtrl.$remove(scope); + }); + + function render() { + var index = bsTabsCtrl.$panes.indexOf(scope); + var active = bsTabsCtrl.$panes.$active; + $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass); + } + + bsTabsCtrl.$activePaneChangeListeners.push(function() { + render(); + }); + render(); + + } + }; + + }]); + +// Source: scrollspy.js +angular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions']) + + .provider('$scrollspy', function() { + + // Pool of registered spies + var spies = this.$$spies = {}; + + var defaults = this.defaults = { + debounce: 150, + throttle: 100, + offset: 100 + }; + + this.$get = ["$window", "$document", "$rootScope", "dimensions", "debounce", "throttle", function($window, $document, $rootScope, dimensions, debounce, throttle) { + + var windowEl = angular.element($window); + var docEl = angular.element($document.prop('documentElement')); + var bodyEl = angular.element($window.document.body); + + // Helper functions + + function nodeName(element, name) { + return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase(); + } + + function ScrollSpyFactory(config) { + + // Common vars + var options = angular.extend({}, defaults, config); + if(!options.element) options.element = bodyEl; + var isWindowSpy = nodeName(options.element, 'body'); + var scrollEl = isWindowSpy ? windowEl : options.element; + var scrollId = isWindowSpy ? 'window' : options.id; + + // Use existing spy + if(spies[scrollId]) { + spies[scrollId].$$count++; + return spies[scrollId]; + } + + var $scrollspy = {}; + + // Private vars + var unbindViewContentLoaded, unbindIncludeContentLoaded; + var trackedElements = $scrollspy.$trackedElements = []; + var sortedElements = []; + var activeTarget; + var debouncedCheckPosition; + var throttledCheckPosition; + var debouncedCheckOffsets; + var viewportHeight; + var scrollTop; + + $scrollspy.init = function() { + + // Setup internal ref counter + this.$$count = 1; + + // Bind events + debouncedCheckPosition = debounce(this.checkPosition, options.debounce); + throttledCheckPosition = throttle(this.checkPosition, options.throttle); + scrollEl.on('click', this.checkPositionWithEventLoop); + windowEl.on('resize', debouncedCheckPosition); + scrollEl.on('scroll', throttledCheckPosition); + + debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce); + unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets); + unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets); + debouncedCheckOffsets(); + + // Register spy for reuse + if(scrollId) { + spies[scrollId] = $scrollspy; + } + + }; + + $scrollspy.destroy = function() { + + // Check internal ref counter + this.$$count--; + if(this.$$count > 0) { + return; + } + + // Unbind events + scrollEl.off('click', this.checkPositionWithEventLoop); + windowEl.off('resize', debouncedCheckPosition); + scrollEl.off('scroll', throttledCheckPosition); + unbindViewContentLoaded(); + unbindIncludeContentLoaded(); + if (scrollId) { + delete spies[scrollId]; + } + }; + + $scrollspy.checkPosition = function() { + + // Not ready yet + if(!sortedElements.length) return; + + // Calculate the scroll position + scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0; + + // Calculate the viewport height for use by the components + viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight')); + + // Activate first element if scroll is smaller + if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) { + return $scrollspy.$activateElement(sortedElements[0]); + } + + // Activate proper element + for (var i = sortedElements.length; i--;) { + if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue; + if(activeTarget === sortedElements[i].target) continue; + if(scrollTop < sortedElements[i].offsetTop) continue; + if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue; + return $scrollspy.$activateElement(sortedElements[i]); + } + + }; + + $scrollspy.checkPositionWithEventLoop = function() { + // IE 9 throws an error if we use 'this' instead of '$scrollspy' + // in this setTimeout call + setTimeout($scrollspy.checkPosition, 1); + }; + + // Protected methods + + $scrollspy.$activateElement = function(element) { + if(activeTarget) { + var activeElement = $scrollspy.$getTrackedElement(activeTarget); + if(activeElement) { + activeElement.source.removeClass('active'); + if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) { + activeElement.source.parent().parent().removeClass('active'); + } + } + } + activeTarget = element.target; + element.source.addClass('active'); + if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) { + element.source.parent().parent().addClass('active'); + } + }; + + $scrollspy.$getTrackedElement = function(target) { + return trackedElements.filter(function(obj) { + return obj.target === target; + })[0]; + }; + + // Track offsets behavior + + $scrollspy.checkOffsets = function() { + + angular.forEach(trackedElements, function(trackedElement) { + var targetElement = document.querySelector(trackedElement.target); + trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null; + if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1; + }); + + sortedElements = trackedElements + .filter(function(el) { + return el.offsetTop !== null; + }) + .sort(function(a, b) { + return a.offsetTop - b.offsetTop; + }); + + debouncedCheckPosition(); + + }; + + $scrollspy.trackElement = function(target, source) { + trackedElements.push({target: target, source: source}); + }; + + $scrollspy.untrackElement = function(target, source) { + var toDelete; + for (var i = trackedElements.length; i--;) { + if(trackedElements[i].target === target && trackedElements[i].source === source) { + toDelete = i; + break; + } + } + trackedElements = trackedElements.splice(toDelete, 1); + }; + + $scrollspy.activate = function(i) { + trackedElements[i].addClass('active'); + }; + + // Initialize plugin + + $scrollspy.init(); + return $scrollspy; + + } + + return ScrollSpyFactory; + + }]; + + }) + + .directive('bsScrollspy', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { + + return { + restrict: 'EAC', + link: function postLink(scope, element, attr) { + + var options = {scope: scope}; + angular.forEach(['offset', 'target'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + var scrollspy = $scrollspy(options); + scrollspy.trackElement(options.target, element); + + scope.$on('$destroy', function() { + if (scrollspy) { + scrollspy.untrackElement(options.target, element); + scrollspy.destroy(); + } + options = null; + scrollspy = null; + }); + + } + }; + + }]) + + + .directive('bsScrollspyList', ["$rootScope", "debounce", "dimensions", "$scrollspy", function($rootScope, debounce, dimensions, $scrollspy) { + + return { + restrict: 'A', + compile: function postLink(element, attr) { + var children = element[0].querySelectorAll('li > a[href]'); + angular.forEach(children, function(child) { + var childEl = angular.element(child); + childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href')); + }); + } + + }; + + }]); + +// Source: timepicker.js +angular.module('mgcrea.ngStrap.timepicker', [ + 'mgcrea.ngStrap.helpers.dateParser', + 'mgcrea.ngStrap.helpers.dateFormatter', + 'mgcrea.ngStrap.tooltip']) + + .provider('$timepicker', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'timepicker', + placement: 'bottom-left', + template: 'timepicker/timepicker.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + // lang: $locale.id, + useNative: true, + timeType: 'date', + timeFormat: 'shortTime', + modelTimeFormat: null, + autoclose: false, + minTime: -Infinity, + maxTime: +Infinity, + length: 5, + hourStep: 1, + minuteStep: 5, + iconUp: 'glyphicon glyphicon-chevron-up', + iconDown: 'glyphicon glyphicon-chevron-down', + arrowBehavior: 'pager' + }; + + this.$get = ["$window", "$document", "$rootScope", "$sce", "$dateFormatter", "$tooltip", "$timeout", function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var isTouch = ('createTouch' in $window.document) && isNative; + if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale(); + + function timepickerFactory(element, controller, config) { + + var $timepicker = $tooltip(element, angular.extend({}, defaults, config)); + var parentScope = config.scope; + var options = $timepicker.$options; + var scope = $timepicker.$scope; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + // View vars + + var selectedIndex = 0; + var startDate = controller.$dateValue || new Date(); + var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()}; + + var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang); + + var hoursFormat = $dateFormatter.hoursFormat(format), + timeSeparator = $dateFormatter.timeSeparator(format), + minutesFormat = $dateFormatter.minutesFormat(format), + showAM = $dateFormatter.showAM(format); + + scope.$iconUp = options.iconUp; + scope.$iconDown = options.iconDown; + + // Scope methods + + scope.$select = function(date, index) { + $timepicker.select(date, index); + }; + scope.$moveIndex = function(value, index) { + $timepicker.$moveIndex(value, index); + }; + scope.$switchMeridian = function(date) { + $timepicker.switchMeridian(date); + }; + + // Public methods + + $timepicker.update = function(date) { + // console.warn('$timepicker.update() newValue=%o', date); + if(angular.isDate(date) && !isNaN(date.getTime())) { + $timepicker.$date = date; + angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()}); + $timepicker.$build(); + } else if(!$timepicker.$isBuilt) { + $timepicker.$build(); + } + }; + + $timepicker.select = function(date, index, keep) { + // console.warn('$timepicker.select', date, scope.$mode); + if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1); + if(!angular.isDate(date)) date = new Date(date); + if(index === 0) controller.$dateValue.setHours(date.getHours()); + else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes()); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + if(options.autoclose && !keep) { + $timeout(function() { $timepicker.hide(true); }); + } + }; + + $timepicker.switchMeridian = function(date) { + if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) { + return; + } + var hours = (date || controller.$dateValue).getHours(); + controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12); + controller.$setViewValue(angular.copy(controller.$dateValue)); + controller.$render(); + }; + + // Protected methods + + $timepicker.$build = function() { + // console.warn('$timepicker.$build() viewDate=%o', viewDate); + var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10); + var hours = [], hour; + for(i = 0; i < options.length; i++) { + hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep); + hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)}); + } + var minutes = [], minute; + for(i = 0; i < options.length; i++) { + minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep); + minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)}); + } + + var rows = []; + for(i = 0; i < options.length; i++) { + rows.push([hours[i], minutes[i]]); + } + scope.rows = rows; + scope.showAM = showAM; + scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12; + scope.timeSeparator = timeSeparator; + $timepicker.$isBuilt = true; + }; + + $timepicker.$isSelected = function(date, index) { + if(!$timepicker.$date) return false; + else if(index === 0) { + return date.getHours() === $timepicker.$date.getHours(); + } else if(index === 1) { + return date.getMinutes() === $timepicker.$date.getMinutes(); + } + }; + + $timepicker.$isDisabled = function(date, index) { + var selectedTime; + if(index === 0) { + selectedTime = date.getTime() + viewDate.minute * 6e4; + } else if(index === 1) { + selectedTime = date.getTime() + viewDate.hour * 36e5; + } + return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1; + }; + + scope.$arrowAction = function (value, index) { + if (options.arrowBehavior === 'picker') { + $timepicker.$setTimeByStep(value,index); + } else { + $timepicker.$moveIndex(value,index); + } + }; + + $timepicker.$setTimeByStep = function(value, index) { + var newDate = new Date($timepicker.$date); + var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; + var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; + if (index === 0) { + newDate.setHours(hours - (parseInt(options.hourStep, 10) * value)); + } + else { + newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value)); + } + $timepicker.select(newDate, index, true); + }; + + $timepicker.$moveIndex = function(value, index) { + var targetDate; + if(index === 0) { + targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute); + angular.extend(viewDate, {hour: targetDate.getHours()}); + } else if(index === 1) { + targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep)); + angular.extend(viewDate, {minute: targetDate.getMinutes()}); + } + $timepicker.$build(); + }; + + $timepicker.$onMouseDown = function(evt) { + // Prevent blur on mousedown on .dropdown-menu + if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault(); + evt.stopPropagation(); + // Emulate click for mobile devices + if(isTouch) { + var targetEl = angular.element(evt.target); + if(targetEl[0].nodeName.toLowerCase() !== 'button') { + targetEl = targetEl.parent(); + } + targetEl.triggerHandler('click'); + } + }; + + $timepicker.$onKeyDown = function(evt) { + if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return; + evt.preventDefault(); + evt.stopPropagation(); + + // Close on enter + if(evt.keyCode === 13) return $timepicker.hide(true); + + // Navigate with keyboard + var newDate = new Date($timepicker.$date); + var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length; + var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length; + var lateralMove = /(37|39)/.test(evt.keyCode); + var count = 2 + showAM * 1; + + // Navigate indexes (left, right) + if (lateralMove) { + if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1; + else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0; + } + + // Update values (up, down) + var selectRange = [0, hoursLength]; + if(selectedIndex === 0) { + if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10)); + else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10)); + // re-calculate hours length because we have changed hours value + hoursLength = formatDate(newDate, hoursFormat).length; + selectRange = [0, hoursLength]; + } else if(selectedIndex === 1) { + if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10)); + else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10)); + // re-calculate minutes length because we have changes minutes value + minutesLength = formatDate(newDate, minutesFormat).length; + selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength]; + } else if(selectedIndex === 2) { + if(!lateralMove) $timepicker.switchMeridian(); + selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3]; + } + $timepicker.select(newDate, selectedIndex, true); + createSelection(selectRange[0], selectRange[1]); + parentScope.$digest(); + }; + + // Private + + function createSelection(start, end) { + if(element[0].createTextRange) { + var selRange = element[0].createTextRange(); + selRange.collapse(true); + selRange.moveStart('character', start); + selRange.moveEnd('character', end); + selRange.select(); + } else if(element[0].setSelectionRange) { + element[0].setSelectionRange(start, end); + } else if(angular.isUndefined(element[0].selectionStart)) { + element[0].selectionStart = start; + element[0].selectionEnd = end; + } + } + + function focusElement() { + element[0].focus(); + } + + // Overrides + + var _init = $timepicker.init; + $timepicker.init = function() { + if(isNative && options.useNative) { + element.prop('type', 'time'); + element.css('-webkit-appearance', 'textfield'); + return; + } else if(isTouch) { + element.prop('type', 'text'); + element.attr('readonly', 'true'); + element.on('click', focusElement); + } + _init(); + }; + + var _destroy = $timepicker.destroy; + $timepicker.destroy = function() { + if(isNative && options.useNative) { + element.off('click', focusElement); + } + _destroy(); + }; + + var _show = $timepicker.show; + $timepicker.show = function() { + _show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $timepicker.$onKeyDown); + } + }, 0, false); + }; + + var _hide = $timepicker.hide; + $timepicker.hide = function(blur) { + if(!$timepicker.$isShown) return; + $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $timepicker.$onKeyDown); + } + _hide(blur); + }; + + return $timepicker; + + } + + timepickerFactory.defaults = defaults; + return timepickerFactory; + + }]; + + }) + + + .directive('bsTimepicker', ["$window", "$parse", "$q", "$dateFormatter", "$dateParser", "$timepicker", function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) { + + var defaults = $timepicker.defaults; + var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent); + var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope, controller: controller}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!timepicker || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i); + newValue === true ? timepicker.show() : timepicker.hide(); + }); + + // Initialize timepicker + if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm'; + var timepicker = $timepicker(element, controller, options); + options = timepicker.$options; + + var lang = options.lang; + var formatDate = function(date, format) { + return $dateFormatter.formatDate(date, format, lang); + }; + + // Initialize parser + var dateParser = $dateParser({format: options.timeFormat, lang: lang}); + + // Observe attributes for changes + angular.forEach(['minTime', 'maxTime'], function(key) { + // console.warn('attr.$observe(%s)', key, attr[key]); + angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) { + timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue); + !isNaN(timepicker.$options[key]) && timepicker.$build(); + validateAgainstMinMaxTime(controller.$dateValue); + }); + }); + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue); + timepicker.update(controller.$dateValue); + }, true); + + function validateAgainstMinMaxTime(parsedTime) { + if (!angular.isDate(parsedTime)) return; + var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime; + var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime; + var isValid = isMinValid && isMaxValid; + controller.$setValidity('date', isValid); + controller.$setValidity('min', isMinValid); + controller.$setValidity('max', isMaxValid); + // Only update the model when we have a valid date + if(!isValid) { + return; + } + controller.$dateValue = parsedTime; + } + + // viewValue -> $parsers -> modelValue + controller.$parsers.unshift(function(viewValue) { + // console.warn('$parser("%s"): viewValue=%o', element.attr('ng-model'), viewValue); + // Null values should correctly reset the model value & validity + if(!viewValue) { + // BREAKING CHANGE: + // return null (not undefined) when input value is empty, so angularjs 1.3 + // ngModelController can go ahead and run validators, like ngRequired + controller.$setValidity('date', true); + return null; + } + var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue); + if(!parsedTime || isNaN(parsedTime.getTime())) { + controller.$setValidity('date', false); + // return undefined, causes ngModelController to + // invalidate model value + return; + } else { + validateAgainstMinMaxTime(parsedTime); + } + if(options.timeType === 'string') { + return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat); + } else if(options.timeType === 'number') { + return controller.$dateValue.getTime(); + } else if(options.timeType === 'unix') { + return controller.$dateValue.getTime() / 1000; + } else if(options.timeType === 'iso') { + return controller.$dateValue.toISOString(); + } else { + return new Date(controller.$dateValue); + } + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var date; + if(angular.isUndefined(modelValue) || modelValue === null) { + date = NaN; + } else if(angular.isDate(modelValue)) { + date = modelValue; + } else if(options.timeType === 'string') { + date = dateParser.parse(modelValue, null, options.modelTimeFormat); + } else if(options.timeType === 'unix') { + date = new Date(modelValue * 1000); + } else { + date = new Date(modelValue); + } + // Setup default value? + // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5); + controller.$dateValue = date; + return getTimeFormattedString(); + }); + + // viewValue -> element + controller.$render = function() { + // console.warn('$render("%s"): viewValue=%o', element.attr('ng-model'), controller.$viewValue); + element.val(getTimeFormattedString()); + }; + + function getTimeFormattedString() { + return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat); + } + + // Garbage collection + scope.$on('$destroy', function() { + if (timepicker) timepicker.destroy(); + options = null; + timepicker = null; + }); + + } + }; + + }]); + +// Source: tooltip.js +angular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions']) + + .provider('$tooltip', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + customClass: '', + prefixClass: 'tooltip', + prefixEvent: 'tooltip', + container: false, + target: false, + placement: 'top', + template: 'tooltip/tooltip.tpl.html', + contentTemplate: false, + trigger: 'hover focus', + keyboard: false, + html: false, + show: false, + title: '', + type: '', + delay: 0, + autoClose: false, + bsEnabled: true + }; + + this.$get = ["$window", "$rootScope", "$compile", "$q", "$templateCache", "$http", "$animate", "$sce", "dimensions", "$$rAF", "$timeout", function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) { + + var trim = String.prototype.trim; + var isTouch = 'createTouch' in $window.document; + var htmlReplaceRegExp = /ng-bind="/ig; + var $body = angular.element($window.document); + + function TooltipFactory(element, config) { + + var $tooltip = {}; + + // Common vars + var nodeName = element[0].nodeName.toLowerCase(); + var options = $tooltip.$options = angular.extend({}, defaults, config); + $tooltip.$promise = fetchTemplate(options.template); + var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new(); + if(options.delay && angular.isString(options.delay)) { + var split = options.delay.split(',').map(parseFloat); + options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0]; + } + + // store $id to identify the triggering element in events + // give priority to options.id, otherwise, try to use + // element id if defined + $tooltip.$id = options.id || element.attr('id') || ''; + + // Support scope as string options + if(options.title) { + scope.title = $sce.trustAsHtml(options.title); + } + + // Provide scope helpers + scope.$setEnabled = function(isEnabled) { + scope.$$postDigest(function() { + $tooltip.setEnabled(isEnabled); + }); + }; + scope.$hide = function() { + scope.$$postDigest(function() { + $tooltip.hide(); + }); + }; + scope.$show = function() { + scope.$$postDigest(function() { + $tooltip.show(); + }); + }; + scope.$toggle = function() { + scope.$$postDigest(function() { + $tooltip.toggle(); + }); + }; + // Publish isShown as a protected var on scope + $tooltip.$isShown = scope.$isShown = false; + + // Private vars + var timeout, hoverState; + + // Support contentTemplate option + if(options.contentTemplate) { + $tooltip.$promise = $tooltip.$promise.then(function(template) { + var templateEl = angular.element(template); + return fetchTemplate(options.contentTemplate) + .then(function(contentTemplate) { + var contentEl = findElement('[ng-bind="content"]', templateEl[0]); + if(!contentEl.length) contentEl = findElement('[ng-bind="title"]', templateEl[0]); + contentEl.removeAttr('ng-bind').html(contentTemplate); + return templateEl[0].outerHTML; + }); + }); + } + + // Fetch, compile then initialize tooltip + var tipLinker, tipElement, tipTemplate, tipContainer, tipScope; + $tooltip.$promise.then(function(template) { + if(angular.isObject(template)) template = template.data; + if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html="'); + template = trim.apply(template); + tipTemplate = template; + tipLinker = $compile(template); + $tooltip.init(); + }); + + $tooltip.init = function() { + + // Options: delay + if (options.delay && angular.isNumber(options.delay)) { + options.delay = { + show: options.delay, + hide: options.delay + }; + } + + // Replace trigger on touch devices ? + // if(isTouch && options.trigger === defaults.trigger) { + // options.trigger.replace(/hover/g, 'click'); + // } + + // Options : container + if(options.container === 'self') { + tipContainer = element; + } else if(angular.isElement(options.container)) { + tipContainer = options.container; + } else if(options.container) { + tipContainer = findElement(options.container); + } + + // Options: trigger + bindTriggerEvents(); + + // Options: target + if(options.target) { + options.target = angular.isElement(options.target) ? options.target : findElement(options.target); + } + + // Options: show + if(options.show) { + scope.$$postDigest(function() { + options.trigger === 'focus' ? element[0].focus() : $tooltip.show(); + }); + } + + }; + + $tooltip.destroy = function() { + + // Unbind events + unbindTriggerEvents(); + + // Remove element + destroyTipElement(); + + // Destroy scope + scope.$destroy(); + + }; + + $tooltip.enter = function() { + + clearTimeout(timeout); + hoverState = 'in'; + if (!options.delay || !options.delay.show) { + return $tooltip.show(); + } + + timeout = setTimeout(function() { + if (hoverState ==='in') $tooltip.show(); + }, options.delay.show); + + }; + + $tooltip.show = function() { + if (!options.bsEnabled || $tooltip.$isShown) return; + + scope.$emit(options.prefixEvent + '.show.before', $tooltip); + var parent, after; + if (options.container) { + parent = tipContainer; + if (tipContainer[0].lastChild) { + after = angular.element(tipContainer[0].lastChild); + } else { + after = null; + } + } else { + parent = null; + after = element; + } + + + // Hide any existing tipElement + if(tipElement) destroyTipElement(); + // Fetch a cloned element linked from template + tipScope = $tooltip.$scope.$new(); + tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {}); + + // Set the initial positioning. Make the tooltip invisible + // so IE doesn't try to focus on it off screen. + tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'}); + + // Options: animation + if(options.animation) tipElement.addClass(options.animation); + // Options: type + if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type); + // Options: custom classes + if(options.customClass) tipElement.addClass(options.customClass); + + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback); + if(promise && promise.then) promise.then(enterAnimateCallback); + + $tooltip.$isShown = scope.$isShown = true; + safeDigest(scope); + $$rAF(function () { + $tooltip.$applyPlacement(); + + // Once placed, make the tooltip visible + if(tipElement) tipElement.css({visibility: 'visible'}); + }); // var a = bodyEl.offsetWidth + 1; ? + + // Bind events + if(options.keyboard) { + if(options.trigger !== 'focus') { + $tooltip.focus(); + } + bindKeyboardEvents(); + } + + if(options.autoClose) { + bindAutoCloseEvents(); + } + + }; + + function enterAnimateCallback() { + scope.$emit(options.prefixEvent + '.show', $tooltip); + } + + $tooltip.leave = function() { + + clearTimeout(timeout); + hoverState = 'out'; + if (!options.delay || !options.delay.hide) { + return $tooltip.hide(); + } + timeout = setTimeout(function () { + if (hoverState === 'out') { + $tooltip.hide(); + } + }, options.delay.hide); + + }; + + var _blur; + var _tipToHide; + $tooltip.hide = function(blur) { + + if(!$tooltip.$isShown) return; + scope.$emit(options.prefixEvent + '.hide.before', $tooltip); + + // store blur value for leaveAnimateCallback to use + _blur = blur; + + // store current tipElement reference to use + // in leaveAnimateCallback + _tipToHide = tipElement; + + // Support v1.3+ $animate + // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9 + var promise = $animate.leave(tipElement, leaveAnimateCallback); + if(promise && promise.then) promise.then(leaveAnimateCallback); + + $tooltip.$isShown = scope.$isShown = false; + safeDigest(scope); + + // Unbind events + if(options.keyboard && tipElement !== null) { + unbindKeyboardEvents(); + } + + if(options.autoClose && tipElement !== null) { + unbindAutoCloseEvents(); + } + }; + + function leaveAnimateCallback() { + scope.$emit(options.prefixEvent + '.hide', $tooltip); + + // check if current tipElement still references + // the same element when hide was called + if (tipElement === _tipToHide) { + // Allow to blur the input when hidden, like when pressing enter key + if(_blur && options.trigger === 'focus') { + return element[0].blur(); + } + + // clean up child scopes + destroyTipElement(); + } + } + + $tooltip.toggle = function() { + $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter(); + }; + + $tooltip.focus = function() { + tipElement[0].focus(); + }; + + $tooltip.setEnabled = function(isEnabled) { + options.bsEnabled = isEnabled; + }; + + // Protected methods + + $tooltip.$applyPlacement = function() { + if(!tipElement) return; + + // Determine if we're doing an auto or normal placement + var placement = options.placement, + autoToken = /\s?auto?\s?/i, + autoPlace = autoToken.test(placement); + + if (autoPlace) { + placement = placement.replace(autoToken, '') || defaults.placement; + } + + // Need to add the position class before we get + // the offsets + tipElement.addClass(options.placement); + + // Get the position of the target element + // and the height and width of the tooltip so we can center it. + var elementPosition = getPosition(), + tipWidth = tipElement.prop('offsetWidth'), + tipHeight = tipElement.prop('offsetHeight'); + + // If we're auto placing, we need to check the positioning + if (autoPlace) { + var originalPlacement = placement; + var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent(); + var containerPosition = getPosition(container); + + // Determine if the vertical placement + if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) { + placement = originalPlacement.replace('bottom', 'top'); + } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) { + placement = originalPlacement.replace('top', 'bottom'); + } + + // Determine the horizontal placement + // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right + // and flow in the opposite direction of their placement. + if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') && + elementPosition.right + tipWidth > containerPosition.width) { + + placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right'); + } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') && + elementPosition.left - tipWidth < containerPosition.left) { + + placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left'); + } + + tipElement.removeClass(originalPlacement).addClass(placement); + } + + // Get the tooltip's top and left coordinates to center it with this directive. + var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight); + applyPlacementCss(tipPosition.top, tipPosition.left); + }; + + $tooltip.$onKeyUp = function(evt) { + if (evt.which === 27 && $tooltip.$isShown) { + $tooltip.hide(); + evt.stopPropagation(); + } + }; + + $tooltip.$onFocusKeyUp = function(evt) { + if (evt.which === 27) { + element[0].blur(); + evt.stopPropagation(); + } + }; + + $tooltip.$onFocusElementMouseDown = function(evt) { + evt.preventDefault(); + evt.stopPropagation(); + // Some browsers do not auto-focus buttons (eg. Safari) + $tooltip.$isShown ? element[0].blur() : element[0].focus(); + }; + + // bind/unbind events + function bindTriggerEvents() { + var triggers = options.trigger.split(' '); + angular.forEach(triggers, function(trigger) { + if(trigger === 'click') { + element.on('click', $tooltip.toggle); + } else if(trigger !== 'manual') { + element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter); + element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave); + nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown); + } + }); + } + + function unbindTriggerEvents() { + var triggers = options.trigger.split(' '); + for (var i = triggers.length; i--;) { + var trigger = triggers[i]; + if(trigger === 'click') { + element.off('click', $tooltip.toggle); + } else if(trigger !== 'manual') { + element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter); + element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave); + nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown); + } + } + } + + function bindKeyboardEvents() { + if(options.trigger !== 'focus') { + tipElement.on('keyup', $tooltip.$onKeyUp); + } else { + element.on('keyup', $tooltip.$onFocusKeyUp); + } + } + + function unbindKeyboardEvents() { + if(options.trigger !== 'focus') { + tipElement.off('keyup', $tooltip.$onKeyUp); + } else { + element.off('keyup', $tooltip.$onFocusKeyUp); + } + } + + var _autoCloseEventsBinded = false; + function bindAutoCloseEvents() { + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + // Stop propagation when clicking inside tooltip + tipElement.on('click', stopEventPropagation); + + // Hide when clicking outside tooltip + $body.on('click', $tooltip.hide); + + _autoCloseEventsBinded = true; + }, 0, false); + } + + function unbindAutoCloseEvents() { + if (_autoCloseEventsBinded) { + tipElement.off('click', stopEventPropagation); + $body.off('click', $tooltip.hide); + _autoCloseEventsBinded = false; + } + } + + function stopEventPropagation(event) { + event.stopPropagation(); + } + + // Private methods + + function getPosition($element) { + $element = $element || (options.target || element); + + var el = $element[0]; + + var elRect = el.getBoundingClientRect(); + if (elRect.width === null) { + // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 + elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }); + } + + var elPos; + if (options.container === 'body') { + elPos = dimensions.offset(el); + } else { + elPos = dimensions.position(el); + } + + return angular.extend({}, elRect, elPos); + } + + function getCalculatedOffset(placement, position, actualWidth, actualHeight) { + var offset; + var split = placement.split('-'); + + switch (split[0]) { + case 'right': + offset = { + top: position.top + position.height / 2 - actualHeight / 2, + left: position.left + position.width + }; + break; + case 'bottom': + offset = { + top: position.top + position.height, + left: position.left + position.width / 2 - actualWidth / 2 + }; + break; + case 'left': + offset = { + top: position.top + position.height / 2 - actualHeight / 2, + left: position.left - actualWidth + }; + break; + default: + offset = { + top: position.top - actualHeight, + left: position.left + position.width / 2 - actualWidth / 2 + }; + break; + } + + if(!split[1]) { + return offset; + } + + // Add support for corners @todo css + if(split[0] === 'top' || split[0] === 'bottom') { + switch (split[1]) { + case 'left': + offset.left = position.left; + break; + case 'right': + offset.left = position.left + position.width - actualWidth; + } + } else if(split[0] === 'left' || split[0] === 'right') { + switch (split[1]) { + case 'top': + offset.top = position.top - actualHeight; + break; + case 'bottom': + offset.top = position.top + position.height; + } + } + + return offset; + } + + function applyPlacementCss(top, left) { + tipElement.css({ top: top + 'px', left: left + 'px' }); + } + + function destroyTipElement() { + // Cancel pending callbacks + clearTimeout(timeout); + + if($tooltip.$isShown && tipElement !== null) { + if(options.autoClose) { + unbindAutoCloseEvents(); + } + + if(options.keyboard) { + unbindKeyboardEvents(); + } + } + + if(tipScope) { + tipScope.$destroy(); + tipScope = null; + } + + if(tipElement) { + tipElement.remove(); + tipElement = $tooltip.$element = null; + } + } + + return $tooltip; + + } + + // Helper functions + + function safeDigest(scope) { + scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest(); + } + + function findElement(query, element) { + return angular.element((element || document).querySelectorAll(query)); + } + + var fetchPromises = {}; + function fetchTemplate(template) { + if(fetchPromises[template]) return fetchPromises[template]; + return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template)) + .then(function(res) { + if(angular.isObject(res)) { + $templateCache.put(template, res.data); + return res.data; + } + return res; + })); + } + + return TooltipFactory; + + }]; + + }) + + .directive('bsTooltip', ["$window", "$location", "$sce", "$tooltip", "$$rAF", function($window, $location, $sce, $tooltip, $$rAF) { + + return { + restrict: 'EAC', + scope: true, + link: function postLink(scope, element, attr, transclusion) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // overwrite inherited title value when no value specified + // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11 + if (!scope.hasOwnProperty('title')){ + scope.title = ''; + } + + // Observe scope attributes for change + attr.$observe('title', function(newValue) { + if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) { + var oldValue = scope.title; + scope.title = $sce.trustAsHtml(newValue); + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); + }); + } + }); + + // Support scope as an object + attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) { + if(angular.isObject(newValue)) { + angular.extend(scope, newValue); + } else { + scope.title = newValue; + } + angular.isDefined(oldValue) && $$rAF(function() { + tooltip && tooltip.$applyPlacement(); + }); + }, true); + + // Visibility binding support + attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) { + if(!tooltip || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i); + newValue === true ? tooltip.show() : tooltip.hide(); + }); + + // Enabled binding support + attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) { + // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue); + if(!tooltip || !angular.isDefined(newValue)) return; + if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i); + newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true); + }); + + // Initialize popover + var tooltip = $tooltip(element, options); + + // Garbage collection + scope.$on('$destroy', function() { + if(tooltip) tooltip.destroy(); + options = null; + tooltip = null; + }); + + } + }; + + }]); + +// Source: typeahead.js +angular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions']) + + .provider('$typeahead', function() { + + var defaults = this.defaults = { + animation: 'am-fade', + prefixClass: 'typeahead', + prefixEvent: '$typeahead', + placement: 'bottom-left', + template: 'typeahead/typeahead.tpl.html', + trigger: 'focus', + container: false, + keyboard: true, + html: false, + delay: 0, + minLength: 1, + filter: 'filter', + limit: 6, + comparator: '' + }; + + this.$get = ["$window", "$rootScope", "$tooltip", "$timeout", function($window, $rootScope, $tooltip, $timeout) { + + var bodyEl = angular.element($window.document.body); + + function TypeaheadFactory(element, controller, config) { + + var $typeahead = {}; + + // Common vars + var options = angular.extend({}, defaults, config); + + $typeahead = $tooltip(element, options); + var parentScope = config.scope; + var scope = $typeahead.$scope; + + scope.$resetMatches = function(){ + scope.$matches = []; + scope.$activeIndex = 0; + }; + scope.$resetMatches(); + + scope.$activate = function(index) { + scope.$$postDigest(function() { + $typeahead.activate(index); + }); + }; + + scope.$select = function(index, evt) { + scope.$$postDigest(function() { + $typeahead.select(index); + }); + }; + + scope.$isVisible = function() { + return $typeahead.$isVisible(); + }; + + // Public methods + + $typeahead.update = function(matches) { + scope.$matches = matches; + if(scope.$activeIndex >= matches.length) { + scope.$activeIndex = 0; + } + }; + + $typeahead.activate = function(index) { + scope.$activeIndex = index; + }; + + $typeahead.select = function(index) { + var value = scope.$matches[index].value; + // console.log('$setViewValue', value); + controller.$setViewValue(value); + controller.$render(); + scope.$resetMatches(); + if(parentScope) parentScope.$digest(); + // Emit event + scope.$emit(options.prefixEvent + '.select', value, index, $typeahead); + }; + + // Protected methods + + $typeahead.$isVisible = function() { + if(!options.minLength || !controller) { + return !!scope.$matches.length; + } + // minLength support + return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength; + }; + + $typeahead.$getIndex = function(value) { + var l = scope.$matches.length, i = l; + if(!l) return; + for(i = l; i--;) { + if(scope.$matches[i].value === value) break; + } + if(i < 0) return; + return i; + }; + + $typeahead.$onMouseDown = function(evt) { + // Prevent blur on mousedown + evt.preventDefault(); + evt.stopPropagation(); + }; + + $typeahead.$onKeyDown = function(evt) { + if(!/(38|40|13)/.test(evt.keyCode)) return; + + // Let ngSubmit pass if the typeahead tip is hidden + if($typeahead.$isVisible()) { + evt.preventDefault(); + evt.stopPropagation(); + } + + // Select with enter + if(evt.keyCode === 13 && scope.$matches.length) { + $typeahead.select(scope.$activeIndex); + } + + // Navigate with keyboard + else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--; + else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++; + else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0; + scope.$digest(); + }; + + // Overrides + + var show = $typeahead.show; + $typeahead.show = function() { + show(); + // use timeout to hookup the events to prevent + // event bubbling from being processed imediately. + $timeout(function() { + $typeahead.$element.on('mousedown', $typeahead.$onMouseDown); + if(options.keyboard) { + element.on('keydown', $typeahead.$onKeyDown); + } + }, 0, false); + }; + + var hide = $typeahead.hide; + $typeahead.hide = function() { + $typeahead.$element.off('mousedown', $typeahead.$onMouseDown); + if(options.keyboard) { + element.off('keydown', $typeahead.$onKeyDown); + } + hide(); + }; + + return $typeahead; + + } + + TypeaheadFactory.defaults = defaults; + return TypeaheadFactory; + + }]; + + }) + + .directive('bsTypeahead', ["$window", "$parse", "$q", "$typeahead", "$parseOptions", function($window, $parse, $q, $typeahead, $parseOptions) { + + var defaults = $typeahead.defaults; + + return { + restrict: 'EAC', + require: 'ngModel', + link: function postLink(scope, element, attr, controller) { + + // Directive options + var options = {scope: scope}; + angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) { + if(angular.isDefined(attr[key])) options[key] = attr[key]; + }); + + // Build proper ngOptions + var filter = options.filter || defaults.filter; + var limit = options.limit || defaults.limit; + var comparator = options.comparator || defaults.comparator; + + var ngOptions = attr.ngOptions; + if(filter) ngOptions += ' | ' + filter + ':$viewValue'; + if (comparator) ngOptions += ':' + comparator; + if(limit) ngOptions += ' | limitTo:' + limit; + var parsedOptions = $parseOptions(ngOptions); + + // Initialize typeahead + var typeahead = $typeahead(element, controller, options); + + // Watch options on demand + if(options.watchOptions) { + // Watch ngOptions values before filtering for changes, drop function calls + var watchedOptions = parsedOptions.$match[7].replace(/\|.+/, '').replace(/\(.*\)/g, '').trim(); + scope.$watch(watchedOptions, function (newValue, oldValue) { + // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue); + parsedOptions.valuesFn(scope, controller).then(function (values) { + typeahead.update(values); + controller.$render(); + }); + }, true); + } + + // Watch model for changes + scope.$watch(attr.ngModel, function(newValue, oldValue) { + // console.warn('$watch', element.attr('ng-model'), newValue); + scope.$modelValue = newValue; // Publish modelValue on scope for custom templates + parsedOptions.valuesFn(scope, controller) + .then(function(values) { + // Prevent input with no future prospect if selectMode is truthy + // @TODO test selectMode + if(options.selectMode && !values.length && newValue.length > 0) { + controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1)); + return; + } + if(values.length > limit) values = values.slice(0, limit); + var isVisible = typeahead.$isVisible(); + isVisible && typeahead.update(values); + // Do not re-queue an update if a correct value has been selected + if(values.length === 1 && values[0].value === newValue) return; + !isVisible && typeahead.update(values); + // Queue a new rendering that will leverage collection loading + controller.$render(); + }); + }); + + // modelValue -> $formatters -> viewValue + controller.$formatters.push(function(modelValue) { + // console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue); + var displayValue = parsedOptions.displayValue(modelValue); + return displayValue === undefined ? '' : displayValue; + }); + + // Model rendering in view + controller.$render = function () { + // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue); + if(controller.$isEmpty(controller.$viewValue)) return element.val(''); + var index = typeahead.$getIndex(controller.$modelValue); + var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue; + selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected; + element.val(selected ? selected.toString().replace(/<(?:.|\n)*?>/gm, '').trim() : ''); + }; + + // Garbage collection + scope.$on('$destroy', function() { + if (typeahead) typeahead.destroy(); + options = null; + typeahead = null; + }); + + } + }; + + }]); + +})(window, document); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js new file mode 100644 index 0000000..4ec9e14 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js @@ -0,0 +1,11 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +!function(e,t,n){"use strict";angular.module("mgcrea.ngStrap",["mgcrea.ngStrap.modal","mgcrea.ngStrap.aside","mgcrea.ngStrap.alert","mgcrea.ngStrap.button","mgcrea.ngStrap.select","mgcrea.ngStrap.datepicker","mgcrea.ngStrap.timepicker","mgcrea.ngStrap.navbar","mgcrea.ngStrap.tooltip","mgcrea.ngStrap.popover","mgcrea.ngStrap.dropdown","mgcrea.ngStrap.typeahead","mgcrea.ngStrap.scrollspy","mgcrea.ngStrap.affix","mgcrea.ngStrap.tab","mgcrea.ngStrap.collapse"]),angular.module("mgcrea.ngStrap.affix",["mgcrea.ngStrap.helpers.dimensions","mgcrea.ngStrap.helpers.debounce"]).provider("$affix",function(){var e=this.defaults={offsetTop:"auto"};this.$get=["$window","debounce","dimensions",function(t,n,a){function o(o,s){function l(e,t,n){var a=u(),o=c();return v>=a?"top":null!==e&&a+e<=t.top?"middle":null!==y&&t.top+n+$>=o-y?"bottom":"middle"}function u(){return p[0]===t?t.pageYOffset:p[0].scrollTop}function c(){return p[0]===t?t.document.body.scrollHeight:p[0].scrollHeight}var d={},f=angular.extend({},e,s),p=f.target,g="affix affix-top affix-bottom",m=!1,$=0,h=0,v=0,y=0,w=null,b=null,D=o.parent();if(f.offsetParent)if(f.offsetParent.match(/^\d+$/))for(var k=0;k<1*f.offsetParent-1;k++)D=D.parent();else D=angular.element(f.offsetParent);return d.init=function(){this.$parseOffsets(),h=a.offset(o[0]).top+$,m=!o[0].style.width,p.on("scroll",this.checkPosition),p.on("click",this.checkPositionWithEventLoop),r.on("resize",this.$debouncedOnResize),this.checkPosition(),this.checkPositionWithEventLoop()},d.destroy=function(){p.off("scroll",this.checkPosition),p.off("click",this.checkPositionWithEventLoop),r.off("resize",this.$debouncedOnResize)},d.checkPositionWithEventLoop=function(){setTimeout(d.checkPosition,1)},d.checkPosition=function(){var e=u(),t=a.offset(o[0]),n=a.height(o[0]),r=l(b,t,n);w!==r&&(w=r,o.removeClass(g).addClass("affix"+("middle"!==r?"-"+r:"")),"top"===r?(b=null,o.css("position",f.offsetParent?"":"relative"),m&&o.css("width",""),o.css("top","")):"bottom"===r?(b=f.offsetUnpin?-(1*f.offsetUnpin):t.top-e,m&&o.css("width",""),o.css("position",f.offsetParent?"":"relative"),o.css("top",f.offsetParent?"":i[0].offsetHeight-y-n-h+"px")):(b=null,m&&o.css("width",o[0].offsetWidth+"px"),o.css("position","fixed"),o.css("top",$+"px")))},d.$onResize=function(){d.$parseOffsets(),d.checkPosition()},d.$debouncedOnResize=n(d.$onResize,50),d.$parseOffsets=function(){var e=o.css("position");o.css("position",f.offsetParent?"":"relative"),f.offsetTop&&("auto"===f.offsetTop&&(f.offsetTop="+0"),f.offsetTop.match(/^[-+]\d+$/)?($=1*-f.offsetTop,v=f.offsetParent?a.offset(D[0]).top+1*f.offsetTop:a.offset(o[0]).top-a.css(o[0],"marginTop",!0)+1*f.offsetTop):v=1*f.offsetTop),f.offsetBottom&&(y=f.offsetParent&&f.offsetBottom.match(/^[-+]\d+$/)?c()-(a.offset(D[0]).top+a.height(D[0]))+1*f.offsetBottom+1:1*f.offsetBottom),o.css("position",e)},d.init(),d}var i=angular.element(t.document.body),r=angular.element(t);return o}]}).directive("bsAffix",["$affix","$window",function(e,t){return{restrict:"EAC",require:"^?bsAffixTarget",link:function(n,a,o,i){var r={scope:n,offsetTop:"auto",target:i?i.$element:angular.element(t)};angular.forEach(["offsetTop","offsetBottom","offsetParent","offsetUnpin"],function(e){angular.isDefined(o[e])&&(r[e]=o[e])});var s=e(a,r);n.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]).directive("bsAffixTarget",function(){return{controller:["$element",function(e){this.$element=e}]}}),angular.module("mgcrea.ngStrap.alert",["mgcrea.ngStrap.modal"]).provider("$alert",function(){var e=this.defaults={animation:"am-fade",prefixClass:"alert",prefixEvent:"alert",placement:null,template:"alert/alert.tpl.html",container:!1,element:null,backdrop:!1,keyboard:!0,show:!0,duration:!1,type:!1,dismissable:!0};this.$get=["$modal","$timeout",function(t,n){function a(a){var o={},i=angular.extend({},e,a);o=t(i),o.$scope.dismissable=!!i.dismissable,i.type&&(o.$scope.type=i.type);var r=o.show;return i.duration&&(o.show=function(){r(),n(function(){o.hide()},1e3*i.duration)}),o}return a}]}).directive("bsAlert",["$window","$sce","$alert",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","placement","keyboard","html","container","animation","duration","dismissable"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content","type"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAlert&&e.$watch(o.bsAlert,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.aside",["mgcrea.ngStrap.modal"]).provider("$aside",function(){var e=this.defaults={animation:"am-fade-and-slide-right",prefixClass:"aside",prefixEvent:"aside",placement:"right",template:"aside/aside.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$modal",function(t){function n(n){var a={},o=angular.extend({},e,n);return a=t(o)}return n}]}).directive("bsAside",["$window","$sce","$aside",function(e,t,n){e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsAside&&e.$watch(o.bsAside,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.button",[]).provider("$button",function(){var e=this.defaults={activeClass:"active",toggleEvent:"click"};this.$get=function(){return{defaults:e}}}).directive("bsCheckboxGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="checkbox"]');angular.forEach(n,function(e){var n=angular.element(e);n.attr("bs-checkbox",""),n.attr("ng-model",t.ngModel+"."+n.attr("value"))})}}}).directive("bsCheckbox",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=angular.isDefined(i.trueValue)?i.trueValue:!0;a.test(i.trueValue)&&(c=e.$eval(i.trueValue));var d=angular.isDefined(i.falseValue)?i.falseValue:!1;a.test(i.falseValue)&&(d=e.$eval(i.falseValue));var f="boolean"!=typeof c||"boolean"!=typeof d;f&&(r.$parsers.push(function(e){return e?c:d}),r.$formatters.push(function(e){return angular.equals(e,c)}),e.$watch(i.ngModel,function(){r.$render()})),r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){l||r.$setViewValue(!u.hasClass("active")),f||r.$render()})})}}}]).directive("bsRadioGroup",function(){return{restrict:"A",require:"ngModel",compile:function(e,t){e.attr("data-toggle","buttons"),e.removeAttr("ng-model");var n=e[0].querySelectorAll('input[type="radio"]');angular.forEach(n,function(e){angular.element(e).attr("bs-radio",""),angular.element(e).attr("ng-model",t.ngModel)})}}}).directive("bsRadio",["$button","$$rAF",function(e,t){var n=e.defaults,a=/^(true|false|\d+)$/;return{restrict:"A",require:"ngModel",link:function(e,o,i,r){var s=n,l="INPUT"===o[0].nodeName,u=l?o.parent():o,c=a.test(i.value)?e.$eval(i.value):i.value;r.$render=function(){var e=angular.equals(r.$modelValue,c);t(function(){l&&(o[0].checked=e),u.toggleClass(s.activeClass,e)})},o.bind(s.toggleEvent,function(){e.$apply(function(){r.$setViewValue(c),r.$render()})})}}}]),angular.module("mgcrea.ngStrap.collapse",[]).provider("$collapse",function(){var e=this.defaults={animation:"am-collapse",disallowToggle:!1,activeClass:"in",startCollapsed:!1,allowMultiple:!1},t=this.controller=function(t,n,a){function o(e){for(var t=l.$targets.$active,n=0;nt;t++)angular.forEach(g.rows[t],u.$setDisabledEl)},u.select=function(e,t){angular.isDate(n.$dateValue)||(n.$dateValue=new Date(e)),!g.$mode||t?(n.$setViewValue(angular.copy(e)),n.$render(),p.autoclose&&!t&&l(function(){u.hide(!0)})):(angular.extend($,{year:e.getFullYear(),month:e.getMonth(),date:e.getDate()}),u.setMode(g.$mode-1),u.$build())},u.setMode=function(e){g.$mode=e,h=u.$views[g.$mode],u.$build()},u.$build=function(e){e===!0&&h.built||(e!==!1||h.built)&&h.build.call(h)},u.$updateSelected=function(){for(var e=0,t=g.rows.length;t>e;e++)angular.forEach(g.rows[e],o)},u.$isSelected=function(e){return h.isSelected(e)},u.$setDisabledEl=function(e){e.disabled=h.isDisabled(e.date)},u.$selectPane=function(e){var t=h.steps,n=new Date(Date.UTC($.year+(t.year||0)*e,$.month+(t.month||0)*e,1));angular.extend($,{year:n.getUTCFullYear(),month:n.getUTCMonth(),date:n.getUTCDate()}),u.$build()},u.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),d){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},u.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return g.$mode?g.$apply(function(){u.setMode(g.$mode-1)}):u.hide(!0);h.onKeyDown(e),f.$digest()}};var v=u.init;u.init=function(){return c&&p.useNative?(t.prop("type","date"),void t.css("-webkit-appearance","textfield")):(d&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",i)),void v())};var y=u.destroy;u.destroy=function(){c&&p.useNative&&t.off("click",i),y()};var w=u.show;u.show=function(){w(),l(function(){u.$isShown&&(u.$element.on(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.on("keydown",u.$onKeyDown))},0,!1)};var b=u.hide;return u.hide=function(e){u.$isShown&&(u.$element.off(d?"touchstart":"mousedown",u.$onMouseDown),p.keyboard&&t.off("keydown",u.$onKeyDown),b(e))},u}var c=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),d="createTouch"in t.document&&c;return e.lang||(e.lang=i.getDefaultLocale()),u.defaults=e,u}]}).directive("bsDatepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$datepicker",function(e,t,n,a,o,i){var r=(i.defaults,/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent));return{restrict:"EAC",require:"ngModel",link:function(e,t,n,s){function l(e){return e&&e.length?e:null}function u(e){if(angular.isDate(e)){var t=isNaN(f.$options.minDate)||e.getTime()>=f.$options.minDate,n=isNaN(f.$options.maxDate)||e.getTime()<=f.$options.maxDate,a=t&&n;s.$setValidity("date",a),s.$setValidity("min",t),s.$setValidity("max",n),a&&(s.$dateValue=e)}}function c(){return!s.$dateValue||isNaN(s.$dateValue.getTime())?"":g(s.$dateValue,d.dateFormat)}var d={scope:e,controller:s};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","dateType","dateFormat","modelDateFormat","dayFormat","strictFormat","startWeek","startDate","useNative","lang","startView","minView","iconLeft","iconRight","daysOfWeekDisabled","id"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(datepicker),?/i)),e===!0?f.show():f.hide())});var f=i(t,s,d);d=f.$options,r&&d.useNative&&(d.dateFormat="yyyy-MM-dd");var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.dateFormat,lang:p,strict:d.strictFormat});angular.forEach(["minDate","maxDate"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getDateForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(!1),u(s.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(s.$dateValue)},!0),angular.isDefined(n.disabledDates)&&e.$watch(n.disabledDates,function(e,t){e=l(e),t=l(t),e&&f.updateDisabledDates(e)}),s.$parsers.unshift(function(e){if(!e)return s.$setValidity("date",!0),null;var t=m.parse(e,s.$dateValue);return!t||isNaN(t.getTime())?void s.$setValidity("date",!1):(u(t),"string"===d.dateType?g(t,d.modelDateFormat||d.dateFormat):"number"===d.dateType?s.$dateValue.getTime():"unix"===d.dateType?s.$dateValue.getTime()/1e3:"iso"===d.dateType?s.$dateValue.toISOString():new Date(s.$dateValue))}),s.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.dateType?m.parse(e,null,d.modelDateFormat):new Date("unix"===d.dateType?1e3*e:e),s.$dateValue=t,c()}),s.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]).provider("datepickerViews",function(){function e(e,t){for(var n=[];e.length>0;)n.push(e.splice(0,t));return n}function t(e,t){return(e%t+t)%t}this.defaults={dayFormat:"dd",daySplit:7};this.$get=["$dateFormatter","$dateParser","$sce",function(n,a,o){return function(i){var r=i.$scope,s=i.$options,l=s.lang,u=function(e,t){return n.formatDate(e,t,l)},c=a({format:s.dateFormat,lang:l,strict:s.strictFormat}),d=n.weekdaysShort(l),f=d.slice(s.startWeek).concat(d.slice(0,s.startWeek)),p=o.trustAsHtml(''+f.join('')+""),g=i.$date||(s.startDate?c.getDateForAttribute("startDate",s.startDate):new Date),m={year:g.getFullYear(),month:g.getMonth(),date:g.getDate()},$=(6e4*g.getTimezoneOffset(),[{format:s.dayFormat,split:7,steps:{month:1},update:function(e,t){!this.built||t||e.getFullYear()!==m.year||e.getMonth()!==m.month?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getDate()!==m.date&&(m.date=i.$date.getDate(),i.$updateSelected())},build:function(){var n=new Date(m.year,m.month,1),a=n.getTimezoneOffset(),o=new Date(+n-864e5*t(n.getDay()-s.startWeek,7)),l=o.getTimezoneOffset(),d=(new Date).toDateString();l!==a&&(o=new Date(+o+6e4*(l-a)));for(var f,g=[],$=0;42>$;$++)f=c.daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth(),o.getDate()+$)),g.push({date:f,isToday:f.toDateString()===d,label:u(f,this.format),selected:i.$date&&this.isSelected(f),muted:f.getMonth()!==m.month,disabled:this.isDisabled(f)});r.title=u(n,s.monthTitleFormat),r.showLabels=!0,r.labels=p,r.rows=e(g,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()&&e.getDate()===i.$date.getDate()},isDisabled:function(e){var t=e.getTime();if(ts.maxDate)return!0;if(-1!==s.daysOfWeekDisabled.indexOf(e.getDay()))return!0;if(s.disabledDateRanges)for(var n=0;n=s.disabledDateRanges[n].start&&t<=s.disabledDateRanges[n].end)return!0;return!1},onKeyDown:function(e){if(i.$date){var t,n=i.$date.getTime();37===e.keyCode?t=new Date(n-864e5):38===e.keyCode?t=new Date(n-6048e5):39===e.keyCode?t=new Date(n+864e5):40===e.keyCode&&(t=new Date(n+6048e5)),this.isDisabled(t)||i.select(t,!0)}}},{name:"month",format:s.monthFormat,split:4,steps:{year:1},update:function(e){this.built&&e.getFullYear()===m.year?e.getMonth()!==m.month&&(angular.extend(m,{month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected()):(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build())},build:function(){for(var t,n=(new Date(m.year,0,1),[]),a=0;12>a;a++)t=new Date(m.year,a,1),n.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=u(t,s.yearTitleFormat),r.showLabels=!1,r.rows=e(n,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()&&e.getMonth()===i.$date.getMonth()},isDisabled:function(e){var t=+new Date(e.getFullYear(),e.getMonth()+1,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getMonth(),n=new Date(i.$date);37===e.keyCode?n.setMonth(t-1):38===e.keyCode?n.setMonth(t-4):39===e.keyCode?n.setMonth(t+1):40===e.keyCode&&n.setMonth(t+4),this.isDisabled(n)||i.select(n,!0)}}},{name:"year",format:s.yearFormat,split:4,steps:{year:12},update:function(e,t){!this.built||t||parseInt(e.getFullYear()/20,10)!==parseInt(m.year/20,10)?(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$build()):e.getFullYear()!==m.year&&(angular.extend(m,{year:i.$date.getFullYear(),month:i.$date.getMonth(),date:i.$date.getDate()}),i.$updateSelected())},build:function(){for(var t,n=m.year-m.year%(3*this.split),a=[],o=0;12>o;o++)t=new Date(n+o,0,1),a.push({date:t,label:u(t,this.format),selected:i.$isSelected(t),disabled:this.isDisabled(t)});r.title=a[0].label+"-"+a[a.length-1].label,r.showLabels=!1,r.rows=e(a,this.split),this.built=!0},isSelected:function(e){return i.$date&&e.getFullYear()===i.$date.getFullYear()},isDisabled:function(e){var t=+new Date(e.getFullYear()+1,0,0);return ts.maxDate},onKeyDown:function(e){if(i.$date){var t=i.$date.getFullYear(),n=new Date(i.$date);37===e.keyCode?n.setYear(t-1):38===e.keyCode?n.setYear(t-4):39===e.keyCode?n.setYear(t+1):40===e.keyCode&&n.setYear(t+4),this.isDisabled(n)||i.select(n,!0)}}}]);return{views:s.minView?Array.prototype.slice.call($,s.minView):$,viewDate:m}}}]}),angular.module("mgcrea.ngStrap.dropdown",["mgcrea.ngStrap.tooltip"]).provider("$dropdown",function(){var e=this.defaults={animation:"am-fade",prefixClass:"dropdown",placement:"bottom-left",template:"dropdown/dropdown.tpl.html",trigger:"click",container:!1,keyboard:!0,html:!1,delay:0};this.$get=["$window","$rootScope","$tooltip","$timeout",function(t,n,a,o){function i(t,i){function l(e){return e.target!==t[0]?e.target!==t[0]&&u.hide():void 0}{var u={},c=angular.extend({},e,i);u.$scope=c.scope&&c.scope.$new()||n.$new()}u=a(t,c);var d=t.parent();u.$onKeyDown=function(e){if(/(38|40)/.test(e.keyCode)){e.preventDefault(),e.stopPropagation();var t=angular.element(u.$element[0].querySelectorAll("li:not(.divider) a"));if(t.length){var n;angular.forEach(t,function(e,t){s&&s.call(e,":focus")&&(n=t)}),38===e.keyCode&&n>0?n--:40===e.keyCode&&no;o++)if(e[o].toLowerCase()===a)return o;return-1}e.prototype.setMilliseconds=function(e){this.milliseconds=e},e.prototype.setSeconds=function(e){this.seconds=e},e.prototype.setMinutes=function(e){this.minutes=e},e.prototype.setHours=function(e){this.hours=e},e.prototype.getHours=function(){return this.hours},e.prototype.setDate=function(e){this.day=e},e.prototype.setMonth=function(e){this.month=e},e.prototype.setFullYear=function(e){this.year=e},e.prototype.fromDate=function(e){return this.year=e.getFullYear(),this.month=e.getMonth(),this.day=e.getDate(),this.hours=e.getHours(),this.minutes=e.getMinutes(),this.seconds=e.getSeconds(),this.milliseconds=e.getMilliseconds(),this},e.prototype.toDate=function(){return new Date(this.year,this.month,this.day,this.hours,this.minutes,this.seconds,this.milliseconds)};var o=e.prototype,i=this.defaults={format:"shortDate",strict:!1};this.$get=["$locale","dateFilter",function(r,s){var l=function(l){function u(e){var t,n=Object.keys(h),a=[],o=[],i=e;for(t=0;t1){var r=i.search(n[t]);e=e.split(n[t]).join(""),h[n[t]]&&(a[r]=h[n[t]])}return angular.forEach(a,function(e){e&&o.push(e)}),o}function c(e){return e.replace(/\//g,"[\\/]").replace("/-/g","[-]").replace(/\./g,"[.]").replace(/\\s/g,"[\\s]")}function d(e){var t,n=Object.keys($),a=e;for(t=0;t12?e.getHours()+2:0),e):null},m.init(),m};return l}]}]),angular.module("mgcrea.ngStrap.helpers.debounce",[]).factory("debounce",["$timeout",function(e){return function(t,n,a){var o=null;return function(){var i=this,r=arguments,s=a&&!o;return o&&e.cancel(o),o=e(function(){o=null,a||t.apply(i,r)},n,!1),s&&t.apply(i,r),o}}}]).factory("throttle",["$timeout",function(e){return function(t,n,a){var o=null;return a||(a={}),function(){var i=this,r=arguments;o||(a.leading!==!1&&t.apply(i,r),o=e(function(){o=null,a.trailing!==!1&&t.apply(i,r)},n,!1))}}}]),angular.module("mgcrea.ngStrap.helpers.dimensions",[]).factory("dimensions",["$document","$window",function(){var t=(angular.element,{}),n=t.nodeName=function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()};t.css=function(t,n,a){var o;return o=t.currentStyle?t.currentStyle[n]:e.getComputedStyle?e.getComputedStyle(t)[n]:t.style[n],a===!0?parseFloat(o)||0:o},t.offset=function(t){var n=t.getBoundingClientRect(),a=t.ownerDocument;return{width:n.width||t.offsetWidth,height:n.height||t.offsetHeight,top:n.top+(e.pageYOffset||a.documentElement.scrollTop)-(a.documentElement.clientTop||0),left:n.left+(e.pageXOffset||a.documentElement.scrollLeft)-(a.documentElement.clientLeft||0)}},t.position=function(e){var o,i,r={top:0,left:0};return"fixed"===t.css(e,"position")?i=e.getBoundingClientRect():(o=a(e),i=t.offset(e),n(o,"html")||(r=t.offset(o)),r.top+=t.css(o,"borderTopWidth",!0),r.left+=t.css(o,"borderLeftWidth",!0)),{width:e.offsetWidth,height:e.offsetHeight,top:i.top-r.top-t.css(e,"marginTop",!0),left:i.left-r.left-t.css(e,"marginLeft",!0)}};var a=function(e){var a=e.ownerDocument,o=e.offsetParent||a;if(n(o,"#document"))return a.documentElement;for(;o&&!n(o,"html")&&"static"===t.css(o,"position");)o=o.offsetParent;return o||a.documentElement};return t.height=function(e,n){var a=e.offsetHeight;return n?a+=t.css(e,"marginTop",!0)+t.css(e,"marginBottom",!0):a-=t.css(e,"paddingTop",!0)+t.css(e,"paddingBottom",!0)+t.css(e,"borderTopWidth",!0)+t.css(e,"borderBottomWidth",!0),a},t.width=function(e,n){var a=e.offsetWidth;return n?a+=t.css(e,"marginLeft",!0)+t.css(e,"marginRight",!0):a-=t.css(e,"paddingLeft",!0)+t.css(e,"paddingRight",!0)+t.css(e,"borderLeftWidth",!0)+t.css(e,"borderRightWidth",!0),a},t}]),angular.module("mgcrea.ngStrap.helpers.parseOptions",[]).provider("$parseOptions",function(){var e=this.defaults={regexp:/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/};this.$get=["$parse","$q",function(t,n){function a(a,o){function i(e,t){return e.map(function(e,n){var a,o,i={};return i[c]=e,a=u(t,i),o=p(t,i),{label:a,value:o,index:n}})}var r={},s=angular.extend({},e,o);r.$values=[];var l,u,c,d,f,p,g;return r.init=function(){r.$match=l=a.match(s.regexp),u=t(l[2]||l[1]),c=l[4]||l[6],d=l[5],f=t(l[3]||""),p=t(l[2]?l[1]:c),g=t(l[7])},r.valuesFn=function(e,t){return n.when(g(e,t)).then(function(t){return r.$values=t?i(t,e):{},r.$values +})},r.displayValue=function(e){var t={};return t[c]=e,u(t)},r.init(),r}return a}]}),angular.version.minor<3&&angular.version.dot<14&&angular.module("ng").factory("$$rAF",["$window","$timeout",function(e,t){var n=e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame,a=e.cancelAnimationFrame||e.webkitCancelAnimationFrame||e.mozCancelAnimationFrame||e.webkitCancelRequestAnimationFrame,o=!!n,i=o?function(e){var t=n(e);return function(){a(t)}}:function(e){var n=t(e,16.66,!1);return function(){t.cancel(n)}};return i.supported=o,i}]),angular.module("mgcrea.ngStrap.modal",["mgcrea.ngStrap.helpers.dimensions"]).provider("$modal",function(){var e=this.defaults={animation:"am-fade",backdropAnimation:"am-fade",prefixClass:"modal",prefixEvent:"modal",placement:"top",template:"modal/modal.tpl.html",contentTemplate:!1,container:!1,element:null,backdrop:!0,keyboard:!0,html:!1,show:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$timeout","$sce","dimensions",function(n,a,o,i,r,s,l,u,c){function d(t){function n(){w.$emit(d.prefixEvent+".show",u)}function i(){w.$emit(d.prefixEvent+".hide",u),v.removeClass(d.prefixClass+"-open"),d.animation&&v.removeClass(d.prefixClass+"-with-"+d.animation)}function r(e){e.target===e.currentTarget&&("static"===d.backdrop?u.focus():u.hide())}function s(e){e.preventDefault()}var u={},d=u.$options=angular.extend({},e,t);u.$promise=g(d.template);var w=u.$scope=d.scope&&d.scope.$new()||a.$new();d.element||d.container||(d.container="body"),u.$id=d.id||d.element&&d.element.attr("id")||"",m(["title","content"],function(e){d[e]&&(w[e]=c.trustAsHtml(d[e]))}),w.$hide=function(){w.$$postDigest(function(){u.hide()})},w.$show=function(){w.$$postDigest(function(){u.show()})},w.$toggle=function(){w.$$postDigest(function(){u.toggle()})},u.$isShown=w.$isShown=!1,d.contentTemplate&&(u.$promise=u.$promise.then(function(e){var n=angular.element(e);return g(d.contentTemplate).then(function(e){var a=p('[ng-bind="content"]',n[0]).removeAttr("ng-bind").html(e);return t.template||a.next().remove(),n[0].outerHTML})}));var b,D,k=angular.element('
    ');return u.$promise.then(function(e){angular.isObject(e)&&(e=e.data),d.html&&(e=e.replace(y,'ng-bind-html="')),e=$.apply(e),b=o(e),u.init()}),u.init=function(){d.show&&w.$$postDigest(function(){u.show()})},u.destroy=function(){D&&(D.remove(),D=null),k&&(k.remove(),k=null),w.$destroy()},u.show=function(){if(!u.$isShown&&!w.$emit(d.prefixEvent+".show.before",u).defaultPrevented){var e,t;angular.isElement(d.container)?(e=d.container,t=d.container[0].lastChild?angular.element(d.container[0].lastChild):null):d.container?(e=p(d.container),t=e[0].lastChild?angular.element(e[0].lastChild):null):(e=null,t=d.element),D=u.$element=b(w,function(){}),D.css({display:"block"}).addClass(d.placement),d.animation&&(d.backdrop&&k.addClass(d.backdropAnimation),D.addClass(d.animation)),d.backdrop&&l.enter(k,v,null);var a=l.enter(D,e,t,n);a&&a.then&&a.then(n),u.$isShown=w.$isShown=!0,f(w);var o=D[0];h(function(){o.focus()}),v.addClass(d.prefixClass+"-open"),d.animation&&v.addClass(d.prefixClass+"-with-"+d.animation),d.backdrop&&(D.on("click",r),k.on("click",r),k.on("wheel",s)),d.keyboard&&D.on("keyup",u.$onKeyUp)}},u.hide=function(){if(u.$isShown&&!w.$emit(d.prefixEvent+".hide.before",u).defaultPrevented){var e=l.leave(D,i);e&&e.then&&e.then(i),d.backdrop&&l.leave(k),u.$isShown=w.$isShown=!1,f(w),d.backdrop&&(D.off("click",r),k.off("click",r),k.off("wheel",s)),d.keyboard&&D.off("keyup",u.$onKeyUp)}},u.toggle=function(){u.$isShown?u.hide():u.show()},u.focus=function(){D[0].focus()},u.$onKeyUp=function(e){27===e.which&&u.$isShown&&(u.hide(),e.stopPropagation())},u}function f(e){e.$$phase||e.$root&&e.$root.$$phase||e.$digest()}function p(e,n){return angular.element((n||t).querySelectorAll(e))}function g(e){return w[e]?w[e]:w[e]=i.when(r.get(e)||s.get(e)).then(function(t){return angular.isObject(t)?(r.put(e,t.data),t.data):t})}var m=angular.forEach,$=String.prototype.trim,h=n.requestAnimationFrame||n.setTimeout,v=angular.element(n.document.body),y=/ng-bind="/gi,w={};return d}]}).directive("bsModal",["$window","$sce","$modal",function(e,t,n){return{restrict:"EAC",scope:!0,link:function(e,a,o){var i={scope:e,element:a,show:!1};angular.forEach(["template","contentTemplate","placement","backdrop","keyboard","html","container","animation","id"],function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),angular.forEach(["title","content"],function(n){o[n]&&o.$observe(n,function(a){e[n]=t.trustAsHtml(a)})}),o.bsModal&&e.$watch(o.bsModal,function(t){angular.isObject(t)?angular.extend(e,t):e.content=t},!0);var r=n(i);a.on(o.trigger||"click",r.toggle),e.$on("$destroy",function(){r&&r.destroy(),i=null,r=null})}}}]),angular.module("mgcrea.ngStrap.navbar",[]).provider("$navbar",function(){var e=this.defaults={activeClass:"active",routeAttr:"data-match-route",strict:!1};this.$get=function(){return{defaults:e}}}).directive("bsNavbar",["$window","$location","$navbar",function(e,t,n){var a=n.defaults;return{restrict:"A",link:function(e,n,o){var i=angular.copy(a);angular.forEach(Object.keys(a),function(e){angular.isDefined(o[e])&&(i[e]=o[e])}),e.$watch(function(){return t.path()},function(e){var t=n[0].querySelectorAll("li["+i.routeAttr+"]");angular.forEach(t,function(t){var n=angular.element(t),a=n.attr(i.routeAttr).replace("/","\\/");i.strict&&(a="^"+a+"$");var o=new RegExp(a,["i"]);o.test(e)?n.addClass(i.activeClass):n.removeClass(i.activeClass)})})}}}]),angular.module("mgcrea.ngStrap.popover",["mgcrea.ngStrap.tooltip"]).provider("$popover",function(){var e=this.defaults={animation:"am-fade",customClass:"",container:!1,target:!1,placement:"right",template:"popover/popover.tpl.html",contentTemplate:!1,trigger:"click",keyboard:!0,html:!1,title:"",content:"",delay:0,autoClose:!1};this.$get=["$tooltip",function(t){function n(n,a){var o=angular.extend({},e,a),i=t(n,o);return o.content&&(i.$scope.content=o.content),i}return n}]}).directive("bsPopover",["$window","$sce","$popover",function(e,t,n){var a=e.requestAnimationFrame||e.setTimeout;return{restrict:"EAC",scope:!0,link:function(e,o,i){var r={scope:e};angular.forEach(["template","contentTemplate","placement","container","target","delay","trigger","keyboard","html","animation","customClass","autoClose","id"],function(e){angular.isDefined(i[e])&&(r[e]=i[e])}),angular.forEach(["title","content"],function(n){i[n]&&i.$observe(n,function(o,i){e[n]=t.trustAsHtml(o),angular.isDefined(i)&&a(function(){s&&s.$applyPlacement()})})}),i.bsPopover&&e.$watch(i.bsPopover,function(t,n){angular.isObject(t)?angular.extend(e,t):e.content=t,angular.isDefined(n)&&a(function(){s&&s.$applyPlacement()})},!0),i.bsShow&&e.$watch(i.bsShow,function(e){s&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(popover),?/i)),e===!0?s.show():s.hide())});var s=n(o,r);e.$on("$destroy",function(){s&&s.destroy(),r=null,s=null})}}}]),angular.module("mgcrea.ngStrap.select",["mgcrea.ngStrap.tooltip","mgcrea.ngStrap.helpers.parseOptions"]).provider("$select",function(){var e=this.defaults={animation:"am-fade",prefixClass:"select",prefixEvent:"$select",placement:"bottom-left",template:"select/select.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,multiple:!1,allNoneButtons:!1,sort:!0,caretHtml:' ',placeholder:"Choose among the following...",allText:"All",noneText:"None",maxLength:3,maxLengthHtml:"selected",iconCheckmark:"glyphicon glyphicon-ok"};this.$get=["$window","$document","$rootScope","$tooltip","$timeout",function(t,n,a,o,i){function r(t,n,a){var r={},s=angular.extend({},e,a);r=o(t,s);var u=r.$scope;u.$matches=[],u.$activeIndex=0,u.$isMultiple=s.multiple,u.$showAllNoneButtons=s.allNoneButtons&&s.multiple,u.$iconCheckmark=s.iconCheckmark,u.$allText=s.allText,u.$noneText=s.noneText,u.$activate=function(e){u.$$postDigest(function(){r.activate(e)})},u.$select=function(e){u.$$postDigest(function(){r.select(e)})},u.$isVisible=function(){return r.$isVisible()},u.$isActive=function(e){return r.$isActive(e)},u.$selectAll=function(){for(var e=0;e=u.$matches.length&&(u.$activeIndex=s.multiple?[]:0)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&n.$viewValue.length>=s.minLength:u.$matches.length},r.$isActive=function(e){return s.multiple?-1!==u.$activeIndex.indexOf(e):u.$activeIndex===e},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){if(e.preventDefault(),e.stopPropagation(),l){var t=angular.element(e.target);t.triggerHandler("click")}},r.$onKeyDown=function(e){if(/(9|13|38|40)/.test(e.keyCode)){if(e.preventDefault(),e.stopPropagation(),!s.multiple&&(13===e.keyCode||9===e.keyCode))return r.select(u.$activeIndex);38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex'),l.after(t)}var u=o(n.ngOptions),c=a(t,r,s),d=u.$match[7].replace(/\|.+/,"").trim();e.$watch(d,function(){u.valuesFn(e,r).then(function(e){c.update(e),r.$render()})},!0),e.$watch(n.ngModel,function(){c.$updateActiveIndex(),r.$render()},!0),r.$render=function(){var e,n;s.multiple&&angular.isArray(r.$modelValue)?(e=r.$modelValue.map(function(e){return n=c.$getIndex(e),angular.isDefined(n)?c.$scope.$matches[n].label:!1}).filter(angular.isDefined),e=e.length>(s.maxLength||i.maxLength)?e.length+" "+(s.maxLengthHtml||i.maxLengthHtml):e.join(", ")):(n=c.$getIndex(r.$modelValue),e=angular.isDefined(n)?c.$scope.$matches[n].label:!1),t.html((e?e:s.placeholder)+i.caretHtml)},s.multiple&&(r.$isEmpty=function(e){return!e||0===e.length}),e.$on("$destroy",function(){c&&c.destroy(),s=null,c=null})}}}]),angular.module("mgcrea.ngStrap.tab",[]).provider("$tab",function(){var e=this.defaults={animation:"am-fade",template:"tab/tab.tpl.html",navClass:"nav-tabs",activeClass:"active"},t=this.controller=function(t,n,a){var o=this;o.$options=angular.copy(e),angular.forEach(["animation","navClass","activeClass"],function(e){angular.isDefined(a[e])&&(o.$options[e]=a[e])}),t.$navClass=o.$options.navClass,t.$activeClass=o.$options.activeClass,o.$panes=t.$panes=[],o.$activePaneChangeListeners=o.$viewChangeListeners=[],o.$push=function(e){o.$panes.push(e)},o.$remove=function(e){var t=o.$panes.indexOf(e),n=o.$panes.$active;o.$panes.splice(t,1),n>t?n--:t===n&&n===o.$panes.length&&n--,o.$setActive(n)},o.$panes.$active=0,o.$setActive=t.$setActive=function(e){o.$panes.$active=e,o.$activePaneChangeListeners.forEach(function(e){e()})}};this.$get=function(){var n={};return n.defaults=e,n.controller=t,n}}).directive("bsTabs",["$window","$animate","$tab","$parse",function(e,t,n,a){var o=n.defaults;return{require:["?ngModel","bsTabs"],transclude:!0,scope:!0,controller:["$scope","$element","$attrs",n.controller],templateUrl:function(e,t){return t.template||o.template},link:function(e,t,n,o){var i=o[0],r=o[1];if(i&&(console.warn("Usage of ngModel is deprecated, please use bsActivePane instead!"),r.$activePaneChangeListeners.push(function(){i.$setViewValue(r.$panes.$active)}),i.$formatters.push(function(e){return r.$setActive(1*e),e})),n.bsActivePane){var s=a(n.bsActivePane);r.$activePaneChangeListeners.push(function(){s.assign(e,r.$panes.$active)}),e.$watch(n.bsActivePane,function(e){r.$setActive(1*e)},!0)}}}}]).directive("bsPane",["$window","$animate","$sce",function(e,t,n){return{require:["^?ngModel","^bsTabs"],scope:!0,link:function(e,a,o,i){function r(){var n=s.$panes.indexOf(e),o=s.$panes.$active;t[n===o?"addClass":"removeClass"](a,s.$options.activeClass)}var s=(i[0],i[1]);a.addClass("tab-pane"),o.$observe("title",function(t){e.title=n.trustAsHtml(t)}),s.$options.animation&&a.addClass(s.$options.animation),s.$push(e),e.$on("$destroy",function(){s.$remove(e)}),s.$activePaneChangeListeners.push(function(){r()}),r()}}}]),angular.module("mgcrea.ngStrap.scrollspy",["mgcrea.ngStrap.helpers.debounce","mgcrea.ngStrap.helpers.dimensions"]).provider("$scrollspy",function(){var e=this.$$spies={},n=this.defaults={debounce:150,throttle:100,offset:100};this.$get=["$window","$document","$rootScope","dimensions","debounce","throttle",function(a,o,i,r,s,l){function u(e,t){return e[0].nodeName&&e[0].nodeName.toLowerCase()===t.toLowerCase()}function c(o){var c=angular.extend({},n,o);c.element||(c.element=p);var g=u(c.element,"body"),m=g?d:c.element,$=g?"window":c.id;if(e[$])return e[$].$$count++,e[$];var h,v,y,w,b,D,k,T,S={},x=S.$trackedElements=[],C=[];return S.init=function(){this.$$count=1,w=s(this.checkPosition,c.debounce),b=l(this.checkPosition,c.throttle),m.on("click",this.checkPositionWithEventLoop),d.on("resize",w),m.on("scroll",b),D=s(this.checkOffsets,c.debounce),h=i.$on("$viewContentLoaded",D),v=i.$on("$includeContentLoaded",D),D(),$&&(e[$]=S)},S.destroy=function(){this.$$count--,this.$$count>0||(m.off("click",this.checkPositionWithEventLoop),d.off("resize",w),m.off("scroll",b),h(),v(),$&&delete e[$])},S.checkPosition=function(){if(C.length){if(T=(g?a.pageYOffset:m.prop("scrollTop"))||0,k=Math.max(a.innerHeight,f.prop("clientHeight")),TC[e+1].offsetTop))return S.$activateElement(C[e])}},S.checkPositionWithEventLoop=function(){setTimeout(S.checkPosition,1)},S.$activateElement=function(e){if(y){var t=S.$getTrackedElement(y);t&&(t.source.removeClass("active"),u(t.source,"li")&&u(t.source.parent().parent(),"li")&&t.source.parent().parent().removeClass("active"))}y=e.target,e.source.addClass("active"),u(e.source,"li")&&u(e.source.parent().parent(),"li")&&e.source.parent().parent().addClass("active")},S.$getTrackedElement=function(e){return x.filter(function(t){return t.target===e})[0]},S.checkOffsets=function(){angular.forEach(x,function(e){var n=t.querySelector(e.target);e.offsetTop=n?r.offset(n).top:null,c.offset&&null!==e.offsetTop&&(e.offsetTop-=1*c.offset)}),C=x.filter(function(e){return null!==e.offsetTop}).sort(function(e,t){return e.offsetTop-t.offsetTop}),w()},S.trackElement=function(e,t){x.push({target:e,source:t})},S.untrackElement=function(e,t){for(var n,a=x.length;a--;)if(x[a].target===e&&x[a].source===t){n=a;break}x=x.splice(n,1)},S.activate=function(e){x[e].addClass("active")},S.init(),S}var d=angular.element(a),f=angular.element(o.prop("documentElement")),p=angular.element(a.document.body);return c}]}).directive("bsScrollspy",["$rootScope","debounce","dimensions","$scrollspy",function(e,t,n,a){return{restrict:"EAC",link:function(e,t,n){var o={scope:e};angular.forEach(["offset","target"],function(e){angular.isDefined(n[e])&&(o[e]=n[e])});var i=a(o);i.trackElement(o.target,t),e.$on("$destroy",function(){i&&(i.untrackElement(o.target,t),i.destroy()),o=null,i=null})}}}]).directive("bsScrollspyList",["$rootScope","debounce","dimensions","$scrollspy",function(){return{restrict:"A",compile:function(e){var t=e[0].querySelectorAll("li > a[href]");angular.forEach(t,function(e){var t=angular.element(e);t.parent().attr("bs-scrollspy","").attr("data-target",t.attr("href"))})}}}]),angular.module("mgcrea.ngStrap.timepicker",["mgcrea.ngStrap.helpers.dateParser","mgcrea.ngStrap.helpers.dateFormatter","mgcrea.ngStrap.tooltip"]).provider("$timepicker",function(){var e=this.defaults={animation:"am-fade",prefixClass:"timepicker",placement:"bottom-left",template:"timepicker/timepicker.tpl.html",trigger:"focus",container:!1,keyboard:!0,html:!1,delay:0,useNative:!0,timeType:"date",timeFormat:"shortTime",modelTimeFormat:null,autoclose:!1,minTime:-1/0,maxTime:+1/0,length:5,hourStep:1,minuteStep:5,iconUp:"glyphicon glyphicon-chevron-up",iconDown:"glyphicon glyphicon-chevron-down",arrowBehavior:"pager"};this.$get=["$window","$document","$rootScope","$sce","$dateFormatter","$tooltip","$timeout",function(t,n,a,o,i,r,s){function l(t,n,a){function o(e,n){if(t[0].createTextRange){var a=t[0].createTextRange();a.collapse(!0),a.moveStart("character",e),a.moveEnd("character",n),a.select()}else t[0].setSelectionRange?t[0].setSelectionRange(e,n):angular.isUndefined(t[0].selectionStart)&&(t[0].selectionStart=e,t[0].selectionEnd=n)}function l(){t[0].focus()}var d=r(t,angular.extend({},e,a)),f=a.scope,p=d.$options,g=d.$scope,m=p.lang,$=function(e,t){return i.formatDate(e,t,m)},h=0,v=n.$dateValue||new Date,y={hour:v.getHours(),meridian:v.getHours()<12,minute:v.getMinutes(),second:v.getSeconds(),millisecond:v.getMilliseconds()},w=i.getDatetimeFormat(p.timeFormat,m),b=i.hoursFormat(w),D=i.timeSeparator(w),k=i.minutesFormat(w),T=i.showAM(w);g.$iconUp=p.iconUp,g.$iconDown=p.iconDown,g.$select=function(e,t){d.select(e,t)},g.$moveIndex=function(e,t){d.$moveIndex(e,t)},g.$switchMeridian=function(e){d.switchMeridian(e)},d.update=function(e){angular.isDate(e)&&!isNaN(e.getTime())?(d.$date=e,angular.extend(y,{hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}),d.$build()):d.$isBuilt||d.$build()},d.select=function(e,t,a){(!n.$dateValue||isNaN(n.$dateValue.getTime()))&&(n.$dateValue=new Date(1970,0,1)),angular.isDate(e)||(e=new Date(e)),0===t?n.$dateValue.setHours(e.getHours()):1===t&&n.$dateValue.setMinutes(e.getMinutes()),n.$setViewValue(angular.copy(n.$dateValue)),n.$render(),p.autoclose&&!a&&s(function(){d.hide(!0)})},d.switchMeridian=function(e){if(n.$dateValue&&!isNaN(n.$dateValue.getTime())){var t=(e||n.$dateValue).getHours();n.$dateValue.setHours(12>t?t+12:t-12),n.$setViewValue(angular.copy(n.$dateValue)),n.$render()}},d.$build=function(){var e,t,n=g.midIndex=parseInt(p.length/2,10),a=[];for(e=0;e1*p.maxTime},g.$arrowAction=function(e,t){"picker"===p.arrowBehavior?d.$setTimeByStep(e,t):d.$moveIndex(e,t)},d.$setTimeByStep=function(e,t){{var n=new Date(d.$date),a=n.getHours(),o=($(n,b).length,n.getMinutes());$(n,k).length}0===t?n.setHours(a-parseInt(p.hourStep,10)*e):n.setMinutes(o-parseInt(p.minuteStep,10)*e),d.select(n,t,!0)},d.$moveIndex=function(e,t){var n;0===t?(n=new Date(1970,0,1,y.hour+e*p.length,y.minute),angular.extend(y,{hour:n.getHours()})):1===t&&(n=new Date(1970,0,1,y.hour,y.minute+e*p.length*p.minuteStep),angular.extend(y,{minute:n.getMinutes()})),d.$build()},d.$onMouseDown=function(e){if("input"!==e.target.nodeName.toLowerCase()&&e.preventDefault(),e.stopPropagation(),c){var t=angular.element(e.target);"button"!==t[0].nodeName.toLowerCase()&&(t=t.parent()),t.triggerHandler("click")}},d.$onKeyDown=function(e){if(/(38|37|39|40|13)/.test(e.keyCode)&&!e.shiftKey&&!e.altKey){if(e.preventDefault(),e.stopPropagation(),13===e.keyCode)return d.hide(!0);var t=new Date(d.$date),n=t.getHours(),a=$(t,b).length,i=t.getMinutes(),r=$(t,k).length,s=/(37|39)/.test(e.keyCode),l=2+1*T;s&&(37===e.keyCode?h=1>h?l-1:h-1:39===e.keyCode&&(h=l-1>h?h+1:0));var u=[0,a];0===h?(38===e.keyCode?t.setHours(n-parseInt(p.hourStep,10)):40===e.keyCode&&t.setHours(n+parseInt(p.hourStep,10)),a=$(t,b).length,u=[0,a]):1===h?(38===e.keyCode?t.setMinutes(i-parseInt(p.minuteStep,10)):40===e.keyCode&&t.setMinutes(i+parseInt(p.minuteStep,10)),r=$(t,k).length,u=[a+1,a+1+r]):2===h&&(s||d.switchMeridian(),u=[a+1+r+1,a+1+r+3]),d.select(t,h,!0),o(u[0],u[1]),f.$digest()}};var S=d.init;d.init=function(){return u&&p.useNative?(t.prop("type","time"),void t.css("-webkit-appearance","textfield")):(c&&(t.prop("type","text"),t.attr("readonly","true"),t.on("click",l)),void S())};var x=d.destroy;d.destroy=function(){u&&p.useNative&&t.off("click",l),x()};var C=d.show;d.show=function(){C(),s(function(){d.$element.on(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.on("keydown",d.$onKeyDown)},0,!1)};var M=d.hide;return d.hide=function(e){d.$isShown&&(d.$element.off(c?"touchstart":"mousedown",d.$onMouseDown),p.keyboard&&t.off("keydown",d.$onKeyDown),M(e))},d}var u=(angular.element(t.document.body),/(ip(a|o)d|iphone|android)/gi.test(t.navigator.userAgent)),c="createTouch"in t.document&&u;return e.lang||(e.lang=i.getDefaultLocale()),l.defaults=e,l}]}).directive("bsTimepicker",["$window","$parse","$q","$dateFormatter","$dateParser","$timepicker",function(e,t,n,a,o,i){{var r=i.defaults,s=/(ip(a|o)d|iphone|android)/gi.test(e.navigator.userAgent);e.requestAnimationFrame||e.setTimeout}return{restrict:"EAC",require:"ngModel",link:function(e,t,n,l){function u(e){if(angular.isDate(e)){var t=isNaN(d.minTime)||new Date(e.getTime()).setFullYear(1970,0,1)>=d.minTime,n=isNaN(d.maxTime)||new Date(e.getTime()).setFullYear(1970,0,1)<=d.maxTime,a=t&&n;l.$setValidity("date",a),l.$setValidity("min",t),l.$setValidity("max",n),a&&(l.$dateValue=e)}}function c(){return!l.$dateValue||isNaN(l.$dateValue.getTime())?"":g(l.$dateValue,d.timeFormat)}var d={scope:e,controller:l};angular.forEach(["placement","container","delay","trigger","keyboard","html","animation","template","autoclose","timeType","timeFormat","modelTimeFormat","useNative","hourStep","minuteStep","length","arrowBehavior","iconUp","iconDown","id"],function(e){angular.isDefined(n[e])&&(d[e]=n[e])}),n.bsShow&&e.$watch(n.bsShow,function(e){f&&angular.isDefined(e)&&(angular.isString(e)&&(e=!!e.match(/true|,?(timepicker),?/i)),e===!0?f.show():f.hide())}),s&&(d.useNative||r.useNative)&&(d.timeFormat="HH:mm");var f=i(t,l,d);d=f.$options;var p=d.lang,g=function(e,t){return a.formatDate(e,t,p)},m=o({format:d.timeFormat,lang:p});angular.forEach(["minTime","maxTime"],function(e){angular.isDefined(n[e])&&n.$observe(e,function(t){f.$options[e]=m.getTimeForAttribute(e,t),!isNaN(f.$options[e])&&f.$build(),u(l.$dateValue)})}),e.$watch(n.ngModel,function(){f.update(l.$dateValue)},!0),l.$parsers.unshift(function(e){if(!e)return l.$setValidity("date",!0),null;var t=angular.isDate(e)?e:m.parse(e,l.$dateValue);return!t||isNaN(t.getTime())?void l.$setValidity("date",!1):(u(t),"string"===d.timeType?g(t,d.modelTimeFormat||d.timeFormat):"number"===d.timeType?l.$dateValue.getTime():"unix"===d.timeType?l.$dateValue.getTime()/1e3:"iso"===d.timeType?l.$dateValue.toISOString():new Date(l.$dateValue))}),l.$formatters.push(function(e){var t;return t=angular.isUndefined(e)||null===e?0/0:angular.isDate(e)?e:"string"===d.timeType?m.parse(e,null,d.modelTimeFormat):new Date("unix"===d.timeType?1e3*e:e),l.$dateValue=t,c()}),l.$render=function(){t.val(c())},e.$on("$destroy",function(){f&&f.destroy(),d=null,f=null})}}}]),angular.module("mgcrea.ngStrap.tooltip",["mgcrea.ngStrap.helpers.dimensions"]).provider("$tooltip",function(){var e=this.defaults={animation:"am-fade",customClass:"",prefixClass:"tooltip",prefixEvent:"tooltip",container:!1,target:!1,placement:"top",template:"tooltip/tooltip.tpl.html",contentTemplate:!1,trigger:"hover focus",keyboard:!1,html:!1,show:!1,title:"",type:"",delay:0,autoClose:!1,bsEnabled:!0};this.$get=["$window","$rootScope","$compile","$q","$templateCache","$http","$animate","$sce","dimensions","$$rAF","$timeout",function(n,a,o,i,r,s,l,u,c,d,f){function p(n,i){function r(){O.$emit(P.prefixEvent+".show",F)}function s(){if(O.$emit(P.prefixEvent+".hide",F),R===W){if(U&&"focus"===P.trigger)return n[0].blur();A()}}function p(){var e=P.trigger.split(" ");angular.forEach(e,function(e){"click"===e?n.on("click",F.toggle):"manual"!==e&&(n.on("hover"===e?"mouseenter":"focus",F.enter),n.on("hover"===e?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==e&&n.on(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))})}function b(){for(var e=P.trigger.split(" "),t=e.length;t--;){var a=e[t];"click"===a?n.off("click",F.toggle):"manual"!==a&&(n.off("hover"===a?"mouseenter":"focus",F.enter),n.off("hover"===a?"mouseleave":"blur",F.leave),"button"===V&&"hover"!==a&&n.off(v?"touchstart":"mousedown",F.$onFocusElementMouseDown))}}function D(){"focus"!==P.trigger?R.on("keyup",F.$onKeyUp):n.on("keyup",F.$onFocusKeyUp)}function k(){"focus"!==P.trigger?R.off("keyup",F.$onKeyUp):n.off("keyup",F.$onFocusKeyUp)}function T(){f(function(){R.on("click",x),w.on("click",F.hide),j=!0},0,!1)}function S(){j&&(R.off("click",x),w.off("click",F.hide),j=!1)}function x(e){e.stopPropagation()}function C(e){e=e||P.target||n;var t=e[0],a=t.getBoundingClientRect();null===a.width&&(a=angular.extend({},a,{width:a.right-a.left,height:a.bottom-a.top}));var o;return o="body"===P.container?c.offset(t):c.position(t),angular.extend({},a,o)}function M(e,t,n,a){var o,i=e.split("-");switch(i[0]){case"right":o={top:t.top+t.height/2-a/2,left:t.left+t.width};break;case"bottom":o={top:t.top+t.height,left:t.left+t.width/2-n/2};break;case"left":o={top:t.top+t.height/2-a/2,left:t.left-n};break;default:o={top:t.top-a,left:t.left+t.width/2-n/2}}if(!i[1])return o;if("top"===i[0]||"bottom"===i[0])switch(i[1]){case"left":o.left=t.left;break;case"right":o.left=t.left+t.width-n}else if("left"===i[0]||"right"===i[0])switch(i[1]){case"top":o.top=t.top-a;break;case"bottom":o.top=t.top+t.height}return o}function E(e,t){R.css({top:e+"px",left:t+"px"})}function A(){clearTimeout(H),F.$isShown&&null!==R&&(P.autoClose&&S(),P.keyboard&&k()),K&&(K.$destroy(),K=null),R&&(R.remove(),R=F.$element=null)}var F={},V=n[0].nodeName.toLowerCase(),P=F.$options=angular.extend({},e,i);F.$promise=$(P.template);var O=F.$scope=P.scope&&P.scope.$new()||a.$new();if(P.delay&&angular.isString(P.delay)){var I=P.delay.split(",").map(parseFloat);P.delay=I.length>1?{show:I[0],hide:I[1]}:I[0]}F.$id=P.id||n.attr("id")||"",P.title&&(O.title=u.trustAsHtml(P.title)),O.$setEnabled=function(e){O.$$postDigest(function(){F.setEnabled(e)})},O.$hide=function(){O.$$postDigest(function(){F.hide()})},O.$show=function(){O.$$postDigest(function(){F.show()})},O.$toggle=function(){O.$$postDigest(function(){F.toggle()})},F.$isShown=O.$isShown=!1;var H,N;P.contentTemplate&&(F.$promise=F.$promise.then(function(e){var t=angular.element(e);return $(P.contentTemplate).then(function(e){var n=m('[ng-bind="content"]',t[0]);return n.length||(n=m('[ng-bind="title"]',t[0])),n.removeAttr("ng-bind").html(e),t[0].outerHTML})}));var L,R,q,Y,K;F.$promise.then(function(e){angular.isObject(e)&&(e=e.data),P.html&&(e=e.replace(y,'ng-bind-html="')),e=h.apply(e),q=e,L=o(e),F.init()}),F.init=function(){P.delay&&angular.isNumber(P.delay)&&(P.delay={show:P.delay,hide:P.delay}),"self"===P.container?Y=n:angular.isElement(P.container)?Y=P.container:P.container&&(Y=m(P.container)),p(),P.target&&(P.target=angular.isElement(P.target)?P.target:m(P.target)),P.show&&O.$$postDigest(function(){"focus"===P.trigger?n[0].focus():F.show()})},F.destroy=function(){b(),A(),O.$destroy()},F.enter=function(){return clearTimeout(H),N="in",P.delay&&P.delay.show?void(H=setTimeout(function(){"in"===N&&F.show()},P.delay.show)):F.show()},F.show=function(){if(P.bsEnabled&&!F.$isShown){O.$emit(P.prefixEvent+".show.before",F);var e,t;P.container?(e=Y,t=Y[0].lastChild?angular.element(Y[0].lastChild):null):(e=null,t=n),R&&A(),K=F.$scope.$new(),R=F.$element=L(K,function(){}),R.css({top:"-9999px",left:"-9999px",display:"block",visibility:"hidden"}),P.animation&&R.addClass(P.animation),P.type&&R.addClass(P.prefixClass+"-"+P.type),P.customClass&&R.addClass(P.customClass);var a=l.enter(R,e,t,r);a&&a.then&&a.then(r),F.$isShown=O.$isShown=!0,g(O),d(function(){F.$applyPlacement(),R&&R.css({visibility:"visible"})}),P.keyboard&&("focus"!==P.trigger&&F.focus(),D()),P.autoClose&&T()}},F.leave=function(){return clearTimeout(H),N="out",P.delay&&P.delay.hide?void(H=setTimeout(function(){"out"===N&&F.hide()},P.delay.hide)):F.hide()};var U,W;F.hide=function(e){if(F.$isShown){O.$emit(P.prefixEvent+".hide.before",F),U=e,W=R;var t=l.leave(R,s);t&&t.then&&t.then(s),F.$isShown=O.$isShown=!1,g(O),P.keyboard&&null!==R&&k(),P.autoClose&&null!==R&&S()}},F.toggle=function(){F.$isShown?F.leave():F.enter()},F.focus=function(){R[0].focus()},F.setEnabled=function(e){P.bsEnabled=e},F.$applyPlacement=function(){if(R){var a=P.placement,o=/\s?auto?\s?/i,i=o.test(a);i&&(a=a.replace(o,"")||e.placement),R.addClass(P.placement);var r=C(),s=R.prop("offsetWidth"),l=R.prop("offsetHeight");if(i){var u=a,c=P.container?angular.element(t.querySelector(P.container)):n.parent(),d=C(c);u.indexOf("bottom")>=0&&r.bottom+l>d.bottom?a=u.replace("bottom","top"):u.indexOf("top")>=0&&r.top-ld.width?a="right"===u?"left":a.replace("left","right"):("left"===u||"bottom-right"===u||"top-right"===u)&&r.left-s=e.length&&(u.$activeIndex=0)},r.activate=function(e){u.$activeIndex=e},r.select=function(e){var t=u.$matches[e].value;n.$setViewValue(t),n.$render(),u.$resetMatches(),l&&l.$digest(),u.$emit(s.prefixEvent+".select",t,e,r)},r.$isVisible=function(){return s.minLength&&n?u.$matches.length&&angular.isString(n.$viewValue)&&n.$viewValue.length>=s.minLength:!!u.$matches.length},r.$getIndex=function(e){var t=u.$matches.length,n=t;if(t){for(n=t;n--&&u.$matches[n].value!==e;);if(!(0>n))return n}},r.$onMouseDown=function(e){e.preventDefault(),e.stopPropagation()},r.$onKeyDown=function(e){/(38|40|13)/.test(e.keyCode)&&(r.$isVisible()&&(e.preventDefault(),e.stopPropagation()),13===e.keyCode&&u.$matches.length?r.select(u.$activeIndex):38===e.keyCode&&u.$activeIndex>0?u.$activeIndex--:40===e.keyCode&&u.$activeIndex0)return void s.$setViewValue(s.$viewValue.substring(0,s.$viewValue.length-1));e.length>c&&(e=e.slice(0,c));var n=g.$isVisible();n&&g.update(e),(1!==e.length||e[0].value!==t)&&(!n&&g.update(e),s.$render())})}),s.$formatters.push(function(e){var t=p.displayValue(e);return t===n?"":t}),s.$render=function(){if(s.$isEmpty(s.$viewValue))return t.val("");var e=g.$getIndex(s.$modelValue),n=angular.isDefined(e)?g.$scope.$matches[e].label:s.$viewValue;n=angular.isObject(n)?p.displayValue(n):n,t.val(n?n.toString().replace(/<(?:.|\n)*?>/gm,"").trim():"")},e.$on("$destroy",function(){g&&g.destroy(),l=null,g=null})}}}])}(window,document); +//# sourceMappingURL=angular-strap.min.js.map \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js.map b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js.map new file mode 100644 index 0000000..94d507a --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["module.js","affix/affix.js","alert/alert.js","aside/aside.js","button/button.js","collapse/collapse.js","datepicker/datepicker.js","dropdown/dropdown.js","helpers/date-formatter.js","helpers/date-parser.js","helpers/debounce.js","helpers/dimensions.js","helpers/parse-options.js","helpers/raf.js","modal/modal.js","navbar/navbar.js","popover/popover.js","select/select.js","tab/tab.js","scrollspy/scrollspy.js","timepicker/timepicker.js","tooltip/tooltip.js","typeahead/typeahead.js"],"names":[],"mappings":"UAOE,EAAA,EAAA,wBAGA,OAAA,kBACA,uBACA,uBACA,uBACA,wBACA,wBACA,4BACA,6ECjBF,mDAEA,sIAQI,OAAK,wBAAA,oCAAyB,6CAExB,SAAS,gCAGb,UAAS,6FAwKH,GAAO,EAAA,EAAA,MAEP,GAAO,MACF,oDAMe,OAAf,GAAe,EAAA,IAAA,EAAA,GAAA,EAAA,EACf,kBAOT,QAAO,KACP,MAAO,GAAA,KAAA,EAAA,EAAA,YAAA,EAAA,GAAA,uBAIT,MAAO,GAAA,KAAA,EAAA,EAAA,SAAA,KAAA,aAAA,EAAA,GAAA,gBApLD,MAGA,EAAA,QAAY,UAAA,EAAA,GACZ,EAAA,EAAe,wCAIf,GAAS,MAET,EAAQ,EACV,EAAY,EACV,EAAa,IACX,cAGC,EAAA,iGAKP,EAAc,EAAA,aAIZ,GAAW,QAAC,QAAW,EAAM,uBAI7B,KAAY,kMAaZ,KAAA,gBACA,KAAA,qIASA,EAAA,IAAW,SAAO,KAAA,qBAIpB,EAAO,2BAA2B,WAIhC,WAAI,EAAW,cAAkB,MAI7B,cAAQ,WAGZ,GAAG,GAAY,IACf,EAAU,EAAA,OAAA,EAAA,+BAOR,KAAY,MACT,IAGH,YAAY,GAAO,SAAA,SAAA,WAAA,EAAA,IAAA,EAAA,KAEf,QAAJ,KACE,2EAKA,IAAQ,MAAS,mBAGjB,EADC,EAAA,cACoB,EAAb,EAAI,aAKN,EAAA,IAAA,EAEN,qBAGF,EAAQ,IAAI,WAAO,EAAkB,aAAA,GAAA,oFAKzC,EAAO,IAAA,QAAY,EAAW,GAAA,YAAA,MAE5B,EAAO,IAAA,WAAA,uDAOP,EAAA,qCAGK,mBAAQ,EAAsB,EAAA,UAAA,kCAGjC,GAAW,EAAgB,IAAA,cAEtB,IAAA,WAAQ,EAAc,aAAA,GAAA,0BAGpB,WAAA,cACH,UAAY,wCAGX,GAAA,EAAA,YACH,EAAA,8CAIO,EAAc,OAAA,EAAA,IAAA,IAAA,EAAA,IAAA,EAAA,GAAA,aAAA,GAAA,EAAA,EAAA,6CAWzB,oDAAY,KAAY,EAAA,OAAA,EAAA,IAAA,IAAA,EAAA,OAAA,EAAA,KAAA,EAAA,EAAA,aAAA,oBAQxB,EAAI,IAAA,WAAe,kBA9JrB,GAAI,QAAU,QAAQ,EAAW,SAAU,MAC3C,EAAI,QAAW,QAAQ,EAgM3B,OAAO,iBAMH,WAAiB,SAAA,UAAa,SAAgB,EAAA,iCAI1C,uBACJ,SAAsB,EAAA,EAAW,EAAA,MAE/B,IAAU,MAAA,EAAA,UAAA,OAAA,OAAA,EAAA,EAAA,SAAA,QAAA,QAAA,YACV,SAAQ,YAAA,eAAA,eAAA,eAAA,SAAA,yGAQf,EAAU,wHC7NP,OAAA,wBAAW,kCAEX,SAAW,cAEX,GAAU,KAAA,UACV,UAAU,UACV,YAAM,4BAEN,UAAU,KACV,SAAM,uBACN,WAAA,2BAGF,UAAK,4BAIG,6EAQJ,GAAA,wCAQE,OAAO,cAAkB,EAAA,cACvB,SACA,OAAS,KAAA,EAAW,uCAMxB,EAAO,KAAA,sCAIF,IAAA,EAAA,cAQT,MAAI,sEAQsB,EAAO,uBAAwB,EAAA,kEAQjD,IAAM,MAAY,EAAA,QAAY,EAAA,MAAA,0KAM7B,SAAQ,QAAS,UAAW,QAAA,SAAA,KAC7B,IAAQ,EAAO,SAAO,EAAA,SAAA,KACjB,GAAA,EAAA,YAAA,iDAML,QAAQ,SAAO,uBAGnB,EAAQ,QAAQ,UAKd,GAAU,EAAA,iEAOf,GAAA,EAAA,UChHL,EAAA,2BAUM,OAAA,wBAAW,kCAEX,SAAA,cAEA,GAAS,KAAA,UACT,UAAU,0BACV,YAAU,QACV,YAAM,QACN,UAAM,2DAGR,WAAK,eAEH,UAAS,oBAEH,kEAWN,EAAO,QAAA,UAAA,EAAA,iBAQT,MAAI,sEAQiB,EAAY,uBAAmB,EAAa,+CAK7D,SAAiB,EAAS,EAAY,MAElC,IAAM,MAAY,EAAA,QAAY,EAAA,MAAA,8KAM7B,SAAQ,QAAS,WAAW,SAAA,KAC7B,IAAQ,EAAO,SAAO,EAAA,SAAA,KACjB,GAAA,EAAA,YAAA,iDAML,QAAQ,SAAO,uBAGnB,EAAQ,QAAQ,UAKd,GAAU,EAAA,iEAOf,GAAA,EAAA,UCxFL,EAAA,uEAYM,UAAQ,yEAOV,MAAA,KAAO,WACL,OAAA,SAAU,gBAKJ,kBAAmB,2BAGrB,YACA,+NAQP,EAAU,KAAA,WAAA,EAAA,QAAc,IAAA,EAAS,KAAS,0BAQjC,cAAS,UAAgB,QAAS,SAAM,EAAY,MAExD,GAAI,EAAU,gDAIV,2BAEA,SAAY,EAAQ,EAAU,EAAK,MAErC,GAAY,EAGX,EAA8B,UAA9B,EAAA,GAAoB,SACrB,EAAa,EAAY,EAAK,SAAA,wEAIhC,EAAI,EAAA,MAAkB,EAAO,eAE3B,GAAW,QAAS,UAAK,EAAS,YAAW,EAAA,YAAA,2BAEpC,EAAA,MAAY,EAAA,4FAQrB,MAAM,GAAY,EAAS,gEAQ3B,EAAI,OAAA,EAAW,QAAQ,WACvB,EAAM,kCAOR,GAAA,GAAa,QAAQ,OAAA,EAAa,YAAW,EAC3C,GAAM,+BAEJ,EAAa,YAAA,EAAA,YAAA,sIAuBb,eAAW,2BAGb,6NAQP,QAAU,QAAA,GAAA,KAAA,WAAW,EAAS,yBAQrB,WAAS,UAAS,QAAO,SAAe,EAAA,MAE5C,GAAI,EAAU,gDAIV,2BAEA,SAAQ,EAAA,EAAyB,EAAK,WAKxC,EAA8B,UAA1B,EAAW,GAAQ,SACvB,EAAiB,EAAA,EAAA,SAAA,EAEf,EAAA,EAA0B,KAAA,EAAQ,OAAa,EAAA,MAAA,EAAA,OAAA,EAAA,2BAKnD,GAAA,GAAa,QAAQ,OAAA,EAAa,YAAW,EAC3C,GAAM,+BAEJ,EAAW,YAAc,EAAA,YAAA,6EAShC,EAAA,2BC/JC,OAAA,8DAIF,GAAI,GAAA,KAAa,UACf,UAAW,iDAGX,gBAAgB,EAChB,eAAQ,uDA2EF,GADF,GAAkB,EAAA,SAAY,QAC5B,EAAA,EAAA,EAAc,EAAU,OAAS,0BAOrC,EAAmB,KAAQ,EAAA,SAAY,2CAMhC,GAAS,kEAKX,GAAc,sCAEZ,MAAL,yGAWY,KAAZ,EAAA,SAAY,QAAA,QAAA,IAChB,EAAA,SAAU,QAAW,KAAA,GAvGrB,GAAA,GAAK,IAGL,GAAK,SAAA,QAAA,KAAuB,6GAEvB,QAAA,UAAkB,EAAA,MAAS,EAAS,SAAA,GAAA,EAAA,MAGzC,EAAK,cACH,wCAIA,gBAAiB,SAAS,qDAI5B,EAAK,SAAA,KAAA,oCAIH,GAAA,GAAK,EAAS,SAAO,QAAO,EAE5B,GAAI,SAAK,OAAS,EAAA,MAEhB,kBAAe,SAAA,8BAIjB,GAAA,SAAA,OAAqB,EAAA,GAErB,EAAK,SAAA,oBAMP,EAAc,GAEZ,EAAG,qBAAgB,QAAQ,SAAA,GACzB,kBAKK,QAAA,EAAA,SAAA,mBAAA,KACL,WAAa,EAAA,WAAA,SAAA,yDAIb,EAAA,SAAA,eAIJ,EAAK,sEAQH,eAAoB,WACpB,MAAI,GAAQ,SAAO,cAAc,EAAQ,SAAK,QACd,IAA9B,EAAI,SAAQ,QAAA,OAAkB,EAAA,SAAA,QAAA,GAAA,0BA8CrC,GAAA,0BAEC,EAAI,WAAqB,gFAQjB,EAAiB,8GAKnB,SAAe,EAAA,EAAqB,EAAK,oBAKzC,oFAQQ,YAAgB,KAAA,SAAA,MAEpB,QAAI,QAAQ,gDAQV,SAAA,QAAe,qPAkCT,gBAAM,kJAUzB,EAAU,yBAQD,oBAAiB,WAAY,SAAA,mBAGzB,YAAS,yDAwBN,EAAkB,SAAA,QAAA,GACzB,EAAS,EAAA,oDAGe,KAA1B,EAAS,QAAQ,mBAIjB,IAAA,wDA5BQ,EAAS,QAInB,GAAA,SAAe,YAGf,EAAU,SAAY,WACpB,EAAA,SAAe,EAAA,SAAkB,aAIrB,gBAAe,KAGvB,IAAA,WAAgB,aACP,kBAAoB,KAmBtC,EAAA,qBAAA,KAAA,WCzQL,MAEQ,iBAQF,OAAA,4IAKA,cAAW,cAEX,GAAM,KAAA,UACN,UAAO,mCAEP,UAAW,cACX,SAAU,iCACV,QAAA,QACA,WAAA,EACA,UAAA,EACA,MAAA,EACA,MAAA,EAEA,WAAA,EACA,SAAA,OACA,WAAW,YACX,gBAAU,KACV,UAAU,KACV,YAAW,MACX,WAAS,OACT,iBAAW,YACX,gBAAA,OACA,cAAU,EACV,WAAW,4BAGb,UAAK,YAEH,UAAI,EACJ,mBAAe,GACf,SAAI,mCACJ,UAAI,sPAyJG,OACD,GAAQ,QA9IZ,GAAI,GAAc,EAAA,EAAgB,QAAA,UAAA,EAAA,IAClC,EAAY,EAAS,MACjB,EAAA,EAAW,SACf,EAAM,EAAgB,MACtB,GAAM,YAAY,EAAQ,WAAA,EAAA,oCAM1B,IAAA,GAAM,EAAmB,WACvB,MAAY,EAAO,iCAErB,EAAM,WAAA,EAAc,aAClB,GAAY,EAAY,OAAA,EAAA,oEAQ1B,EAAY,YAAS,MAEhB,YAAe,aAChB,SAAY,EAAQ,MAAA,GAAA,EAAA,OAAA,8BAOxB,QAAY,OAAA,KAAA,MAAsB,EAAA,aAChC,EAAQ,MAAA,EACR,EAAQ,OAAO,KAAI,EAAW,oDAO9B,EAAI,mBAAe,CACnB,KAAI,GAAA,GAAM,EAAA,EAAS,EAAM,KAAA,OAAA,EAAA,EAAA,IACvB,QAAA,QAAW,EAAA,KAAc,GAAA,EAAa,wCAMtC,QAAQ,OAAO,EAAW,cAAW,EAAe,WAAY,GAAA,MAAA,KAChE,EAAA,OAAY,GACZ,EAAA,cAAY,QAAA,KAAA,6DAMd,QAAM,OAAQ,GAAA,KAAA,EAAA,cAAA,MAAA,EAAA,WAAA,KAAA,EAAA,YACd,EAAU,QAAY,EAAA,MAAa,GACnC,EAAY,2CAOZ,EAAG,EAAa,OAAQ,EAAQ,OAChC,EAAG,YAKK,OAAW,SAAM,yHAS3B,QAAY,QAAA,EAAA,KAAiB,GAAA,IAI7B,EAAY,YAAc,SAAS,GACjC,MAAI,GAAQ,WAAQ,iCAIpB,EAAA,SAAI,EAAiB,WAAU,EAAI,+CAQ/B,EAAA,GAAA,MAAA,KAAA,IAAA,EAAA,MAAA,EAAA,MAAA,GAAA,EAAA,EAAA,OAAA,EAAA,OAAA,GAAA,EAAA,0FAEJ,EAAY,YAGR,aAAoB,SAAA,QAEtB,wCAIJ,GAAA,GAAY,QAAa,QAAS,EAAK,OACJ,YAA5B,EAAA,GAAA,SAAmB,gBACpB,EAAA,EAAA,wCAMK,WAAA,SAAA,MACL,mBAAoB,KAAA,EAAA,WAAa,EAAY,WAAQ,EAAM,iEAK/D,MAAA,GAAQ,iDACR,EAAY,MAAA,mCAuBV,GAAQ,EAAK,OACL,KAAG,kCAEb,EAAA,KAAA,OAAA,uDAGE,IACJ,EAAY,KAAA,OAAU,QACpB,EAAG,KAAY,WAAQ,QACrB,EAAQ,GAAA,QAAI,QAEd,MAGF,IAAI,GAAQ,EAAY,OACxB,GAAY,QAAO,WACjB,GAAA,EAAA,4BAGA,QAGE,GAAA,EAAY,OACT,KAAQ,4BAMX,EAAQ,WACZ,EAAY,SAAO,GAAS,EAAM,aAAA,YAAA,EAAA,cAC5B,EAAA,UACJ,EAAY,GAAA,UAAa,EAAU,cAEjC,GAAA,2CAKJ,EAAO,+GAKT,EAAO,UArML,IADI,QAAc,QAAO,EAAA,SAAA,MACrB,8BAAsB,KAAA,EAAA,UAAA,YAC1B,EAAY,eAAY,GAAA,UAAA,CA4M5B,OA3MI,GAAW,OAAA,EAAW,KAAQ,EAAa,iCA2M3C,gBAMI,gBAAkB,UAAO,SAAS,KAAM,iBAAY,cAAA,cAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,MAGxD,eAAI,8BAAqC,KAAA,EAAA,UAAA,mFAqDrC,GAAgB,sBAEZ,qBAeN,GAAG,QAAS,OAAA,GAAZ,qIAIF,GAAW,aAAS,OAAQ,mDAIxB,IAAA,EAAW,WAAqB,YAkElC,2FAxIA,IAAW,MAAS,EAAA,WAAW,WAC/B,SAAa,YAAO,YAAoB,QAAA,UAAW,WAAA,OAAA,YAAA,WAAA,YAAA,WAAA,aAAA,kBAAA,YAAA,eAAA,YAAA,YAAA,YAAA,OAAA,YAAA,UAAA,WAAA,YAAA,qBAAA,MAAA,SAAA,0CAKrD,EAAA,QAAU,EAAW,OAAA,EAAA,OAAA,SAAA,6BAElB,QAAA,SAAY,KAAQ,IAAmB,EAAa,MAAA,0DAKrD,GAAO,EAAe,EAAW,EAAc,gBAGjD,GAAI,EAAa,YAAa,EAAQ,WAAQ,2CAK5C,MAAA,GAAkB,WAAc,EAAK,EAAS,gKAUhD,EAAa,SAAK,GAAS,EAAS,oBAAoB,EAAA,IAErD,MAAA,EAAA,SAAA,KAAA,EAAA,QAAA,yBAMD,OAAO,EAAA,QAAA,yHAcT,EAAS,EAA0B,GAE7B,GACA,EAAA,oBAA8B,OAkBzB,SAAA,QAAA,SAAA,GAGT,IAAI,QACF,GAAW,aAAa,QAAQ,GAI3B,kCAGP,QAAG,GAAQ,MAAa,EAAU,eAChC,GAAO,aAAW,QAAY,MAKd,GAEX,aAAA,SACE,EAAS,EAAW,EAAA,iBAAA,EAAA,wGAKH,QAAjB,EAAA,oCAGN,GAAQ,MAAA,EAAY,iBAKd,YAAW,KAAM,SAAA,MAExB,SAEA,WADK,YAAA,IAAA,OAAA,EACE,mHAQF,6CAcT,EAAU,IAAA,wDAWf,EAAS,qBAQR,kBAA0B,2BAUxB,IADF,GAAA,MACE,EAAS,OAAS,wBAGpB,OAAK,WAIG,GAAA,EAAQ,UACR,EAAA,EAAU,GAAO,EAhBb,KAAA,oBACD,sBAkBP,MAAI,iBAAsB,cAAc,OAAA,SAAA,EAAA,EAAA,qCAKpC,EAAA,EAAc,SAEd,EAAA,EAAA,qBAEJ,MAAI,GAAmB,WAAU,EAAQ,EAAA,IAErC,EAAA,GAAiB,OAAU,EAAA,WAAsB,KAAA,EAAA,OAAA,EAAA,eAEjD,EAAS,EAAA,cAAA,GACT,EAAgB,EAAA,MAAA,EAAA,WAAA,OAAA,EAAA,MAAA,EAAA,EAAA,YAChB,EAAO,EAAA,YAAA,+BAAA,EAAA,KAAA,qCAAA,SAEP,EAAQ,EAAS,QAAM,EAAO,UAAA,EAAA,oBAAA,YAAA,EAAA,WAAA,GAAA,UACnB,KAAA,EAAS,cAAc,MAAA,EAAkB,WAAiB,KAAK,EAAA,cACzB,IAArC,EAAO,6BAGf,EAAS,gBACT,wCAGJ,KAAO,OAAW,GAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,aAAA,EAAA,OAChB,QAAI,OAAA,GAAsB,KAAK,EAAS,MAAM,cAAgB,MAAI,EAAA,MAAA,WAAwB,KAAA,EAAgB,MAAA,YAC1G,EAAI,UACA,EAAQ,YAAW,EAAA,gCAEvB,EAAG,0BAGD,cACA,GAAiB,GAAK,MAAA,EAAa,KAAA,EAAA,MAAmB,GAAO,EAAuB,EAAc,6FAEpG,GAAM,GAAQ,OAAA,cAEd,KAAe,IAAA,EAAA,GAAA,OAAA,EAAA,KAAA,EAAA,IAEf,KAAA,GADa,GAAb,KACK,EAAA,EAAQ,GAAA,EAAA,mFAEf,EAAA,MAAY,KAAS,EAAA,QAAM,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,KAAA,QAAA,SAAA,EAAA,OAAA,KAAA,WAAA,GAAA,MAAA,EAAA,aAAA,EAAA,MAAA,SAAA,KAAA,WAAA,qCAG3B,EAAA,YAAqB,EACnB,EAAI,OAAO,wOAWP,EAAI,EAAQ,SAAQ,EAAA,EAAmB,QAAG,OAAS,2DAMvD,IAAA,EAAO,iEAET,GAAA,GAAW,EAAc,mBAAA,GAAA,OAAA,GAAA,EAAA,mBAAA,GAAA,IAClB,OAAO,sBAOJ,SAAI,MACP,EAAO,OAGZ,MAAI,EAAM,EAAW,MAAA,SAGjB,MAAN,EAAM,QAAA,EAAA,GAAA,MAAA,EAAA,OACU,KAAR,EAAA,QAAQ,EAAA,GAAA,MAAA,EAAA,QACT,KAAA,EAAA,QAAA,EAAA,GAAA,MAAA,EAAA,OACQ,KAAN,EAAA,UAAM,EAAA,GAAA,MAAA,EAAA,SAET,KAAK,WAAS,IAAK,EAAA,OAAkB,GAAS,2BAIhD,EAAQ,kBACR,oCAGJ,KAAO,OAAW,EAAA,gBAAA,EAAA,KAGP,EAAI,aAAgB,EAAA,QAC3B,QAAQ,OAAI,GAAc,MAAM,EAAG,MAAA,WAAA,KAAA,EAAA,MAAA,YACnC,EAAO,oBAJT,QAAI,OAAa,GAAS,KAAA,EAAe,MAAG,cAAA,MAAA,EAAA,MAAA,WAAA,KAAA,EAAA,MAAA,YAC5C,EAAI,iBAMJ,kBAEa,GAAb,GADa,GAAM,MAAA,EAAa,KAAA,EAAA,oBAGlC,EAAY,GAAA,MAAS,EAAM,KAAA,EAAA,GACzB,EAAO,MAAO,KAAA,EAAc,MAAA,EAAkB,EAAO,KAAA,QAAM,SAAiB,EAAK,YAAe,GAAO,SAAM,KAAA,WAAA,IAE/G,GAAA,MAAY,EAAe,EAAA,EAAA,iBACzB,EAAI,YAAY,EAChB,EAAA,KAAO,EAAW,EAAQ,KAAA,iCAGrB,SAAc,SACjB,GAAA,OAAA,EAAA,gBAAA,EAAA,MAAA,eAAA,EAAA,aAAA,EAAA,MAAA,uBAEE,SAAc,GAClB,GAAI,IAAU,GAAI,MAAK,EAAO,cAAA,EAAA,WAAA,EAAA,wDAGtB,SAAI,MACP,EAAO,OAGZ,GAAI,GAAM,EAAW,MAAU,8BAG3B,MAAN,EAAM,QAAA,EAAA,SAAA,EAAA,GACU,KAAR,EAAA,QAAQ,EAAA,SAAA,EAAA,GACT,KAAA,EAAA,QAAA,EAAA,SAAA,EAAA,GACQ,KAAN,EAAA,SAAM,EAAA,SAAA,EAAA,GAET,KAAK,WAAS,IAAS,EAAS,OAAK,GAAA,0BAIvC,EAAQ,iBACR,wCAGJ,KAAO,OAAW,GAAA,SAAA,EAAA,cAAA,GAAA,MAAA,SAAA,EAAA,KAAA,GAAA,KAChB,QAAI,OAAY,GAAS,KAAO,EAAS,MAAA,cAAqB,MAAA,EAAA,MAAA,WAAA,KAAA,EAAA,MAAA,YAC9D,EAAI,UACK,EAAI,gBAAgB,EAAA,OAC3B,QAAO,OAAI,GAAK,KAAe,EAAG,MAAA,cAAA,MAAA,EAAA,MAAA,WAAA,KAAA,EAAA,MAAA,YAClC,EAAM,0BAGR,kBAEa,GADb,EAAa,EAAM,KAAY,EAAA,MAAA,EAAA,KAAA,OAC/B,kBAEF,EAAA,GAAY,MAAA,EAAe,EAAA,EAAA,GACzB,EAAO,MAAO,KAAA,EAAS,MAAK,EAAA,EAAkB,KAAO,QAAM,SAAA,EAAA,YAAA,GAAA,SAAA,KAAA,WAAA,IAE7D,GAAA,MAAY,EAAS,GAAA,MAAM,IAAA,EAAA,EAAA,OAAA,GAAA,MACzB,EAAI,YAAY,EAChB,EAAA,KAAO,EAAW,EAAQ,KAAA,iCAGrB,SAAc,SACjB,GAAA,OAAA,EAAA,gBAAA,EAAA,MAAA,0BAEE,SAAa,MACb,IAAU,GAAI,MAAK,EAAO,cAAA,EAAA,EAAA,wDAGtB,SAAI,MACP,EAAO,OAGZ,GAAI,GAAM,EAAW,MAAA,gEAIpB,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,GACoB,KAAlB,EAAQ,QAAgB,EAAA,QAAgB,EAAY,GACjD,KAAA,EAAA,SAAA,EAAA,QAAA,EAAA,kDAOf,MAAA,EAAA,QAAA,MAAA,UAAA,MAAA,KAAA,EAAA,EAAA,SAAA,ECxnBL,SAAA,gBAUM,OAAA,2BAAU,oCAEV,YAAW,cAEX,GAAM,KAAA,UACN,UAAO,yDAGT,SAAK,6CAEH,WAAI,EACJ,UAAI,UAEJ,MAAA,qFAQE,GAAqB,EAAS,iBAkEhC,MAAO,GAAA,SAAA,EAAA,6BAAP,iBA7DE,EAAU,QAAA,UAAsB,EAAK,EAC9B,GAAe,OAAI,EAAU,OAAA,EAAA,MAAA,QAAA,EAAA,SAE9B,EAAA,EAAA,sBAKA,WAAA,SAAA,GACJ,GAAA,UAAQ,KAAQ,EAAO,SAAvB,GACE,oCAIF,IAAG,GAAI,QAAY,QAAM,EAAW,SAAA,GAAA,iBAAA,4BAC5B,aAER,SAAM,QAAU,EAAG,SAAA,EAAA,0DAMA,KAAjB,EAAO,SAAU,EAAA,EAAA,OAAA,EAAA,IACX,QAAO,YAAW,KAAA,EAAA,GAC1B,EAAA,GAAA,GAAA,GAAA,iBAMM,EAAA,OACN,KAAS,eAIX,EAAU,WACR,EAAI,UAAU,EAAU,SAAA,GAAA,UAAA,EAAA,YACxB,EAAQ,GAAA,QAAY,IACpB,GAAA,GACA,EAAS,SAAS,aAAe,EAAS,SAAA,qBAI5C,GAAI,KAAU,WACd,EAAU,WACR,EAAO,UAAa,EAAA,SAAA,IAAA,UAAA,EAAA,YACpB,EAAA,IAAA,QAAA,sDAKF,IAAA,GAAS,EAAY,iBACZ,QAAW,WAClB,EAAO,IAAI,QAAA,aA9Db,GAAI,QAAU,QAAQ,EAAW,SAAU,MAC3C,EAAY,QAAU,UAAS,iBAAyB,QAAM,UAAU,uBAAW,QAAA,UAAA,oBAAA,QAAA,UAAA,mBAAA,QAAA,UAAA,gBA4EvF,OAAO,iBAMC,cAAW,UAAO,OAAA,YAAA,SAAA,EAAA,EAAA,0DAQnB,IAAA,MAAA,kKAMD,YAAa,EAAO,OAAS,EAAA,WAAkB,SAAA,sFAOjD,QAAU,SAAY,KAAW,IAAA,EAAA,MAAA,yBAC/B,KAAI,EAAU,EAAS,OAAA,EAAA,mDAQ5B,GAAA,EAAA,UC7IL,EAAA,qFAYM,kBAAe,UAAA,aAAA,SAAA,EAAA,kHAajB,KAAA,kBAAyB,SAAQ,GAC/B,MAAO,GAAA,iBAAA,IAAiC,iCAI1C,MAAK,GAAA,iBAAuB,qIAmB5B,MAAK,GAAa,GAAe,SAIhC,OAAA,SAAA,GCrDL,QAAA,EAAA,GAAA,kCAIC,MAAS,GAAA,EAAA,eAMN,OAAK,iDAEA,eAAQ,kBAAA,uCAMf,KAAA,MAAU,EACV,KAAA,IAAU,EACV,KAAA,MAAU,EACV,KAAA,QAAU,EACV,KAAA,QAAU,EACV,KAAA,aAAoB,UA4Bd,oBAIJ,OAAQ,MAAA,WAAA,KAAA,SAAA,GAGV,QAAI,GAA2B,EAAA,GAE7B,IAAA,GADA,GAAQ,EAAA,OAAA,EAAA,EAAA,WAAA,cACA,EAAA,EAAA,EAAA,EAAA,sCAGV,OAAK,GArCL,EAAU,UAAU,gBAAW,SAAgB,GAAA,KAAA,aAAA,KACxC,UAAa,WAAA,SAAA,GAAA,KAAA,QAAA,KACb,UAAQ,WAAM,SAAA,GAAA,KAAA,QAAA,KACd,UAAY,SAAA,SAAA,GAAA,KAAA,MAAA,KACZ,UAAQ,SAAM,WAAA,MAAA,MAAA,SACd,UAAU,QAAM,SAAA,GAAA,KAAA,IAAA,KAChB,UAAU,SAAM,SAAA,GAAA,KAAA,MAAA,KAChB,UAAA,YAAqB,SAAA,GAAA,KAAA,KAAA,KACnB,UAAA,SAAA,SAAA,4DAGT,KAAA,IAAU,EAAA,UACR,KAAA,MAAW,EAAK,mEAGlB,KAAI,aAAkB,EAAA,sDAKtB,MAAS,IAAA,MAAA,KAAa,KAAA,KAAA,MAAA,KAAA,IAAA,KAAA,MAAA,KAAA,QAAA,KAAA,QAAA,KAAA,yDAqBd,4BAIJ,MAAI,UAAY,aAAA,SAAA,EAAA,MAEd,GAAU,SAAA,WAmJN,GAAgB,MACM,GAAtB,EAAG,OAAS,KAAK,QACX,2DAKV,GAAQ,GAAQ,EAAK,OAAY,EAAA,uCAG5B,EAAG,GAAU,EAAK,EAAA,KAUvB,MALF,SAAS,QAAA,EAAA,SAAsB,kBAKzB,gBAIJ,MAAI,GAAO,QAAS,MAAA,SAAa,QAAA,OAAA,OAAA,QAAA,MAAA,OAAA,QAAA,OAAA,uBAIjC,GAAiC,GAA7B,EAAO,OAAI,KAAK,8BAKpB,EAAO,EAAA,MAAI,EAAO,IAAM,KAAK,KAAM,EAAA,IAGrC,KAAA,EAAA,EAAY,EAAA,EAAA,OAAA,IACZ,EAAO,EAAA,MAAA,KAAA,EAAA,KAAA,KAAA,IAAA,EAAA,EAAA,IAAA,IAIT,eAAO,GAAA,QAAA,IAAA,EAAA,KAAA,SAtIL,GAAA,EApDE,EAAU,QAAA,UAAA,EAAA,GAEV,KAEA,GACA,IAAU,WACV,GAAU,aACV,EAAU,EAAQ,OAAA,cAAqB,mBACvC,GAAU,aACV,EAAU,EAAA,OAAA,cAAA,mBACV,GAAU,mBACV,EAAU,EAAQ,OAAA,iBAA4B,oBAC9C,GAAU,oBACV,EAAU,EAAA,OAAA,eAAA,iBACV,EAAU,QACV,KAAU,EAAA,iBAAA,IAAA,KAAA,KACV,IAAU,EAAA,iBAAA,SAAA,KAAA,KACV,GAAU,gIAGZ,IAAI,EAAW,iBAAA,WAAA,KAAA,KACb,GAAU,gBACV,EAAU,EAAM,OAAA,eAAA,iBAChB,KAAU,gCACV,GAAU,WACV,EAAU,EAAM,OAAA,wBAAA,kBAGhB,GACA,IAAU,EAAM,gBAChB,GAAU,EAAA,WACV,EAAU,EAAA,WACV,GAAU,EAAM,WAChB,EAAU,EAAM,WAChB,GAAU,EAAA,SACV,EAAU,EAAA,SACV,GAAU,EAAA,SACV,EAAU,EAAA,SACV,KAAU,EACV,IAAU,EACV,GAAU,EAAA,QACV,EAAU,EAAM,kKAGlB,IAAW,SAAA,GAAA,MAAA,MAAA,SAAA,EAAA,EAAA,iBAAA,WAAA,iDAEX,EAAY,SAAO,GAAW,MAAA,MAAA,SAAA,EAAA,EAAA,IAC5B,KAAA,EAAY,YACZ,GAAQ,SAAA,GAAgB,MAAA,MAAY,YAAA,IAAA,EAAA,IACpC,EAAS,EAAA,YA6Id,UAxIY,KAAM,2EAGf,EAAA,EAAoB,EAAgB,YAG/B,QAAe,SAAQ,GAC1B,MAAA,SAAI,OAAc,IAAS,MAAA,EAAgB,WACvC,EAAA,KAAA,4BAKJ,IAAQ,EAAW,EAAQ,iBAAiB,IAAA,GAC1C,QAAA,OAAa,KAAM,EAAa,EAAQ,EAAM,GAAU,EAAA,oCAGtD,EAAU,EAAK,KAAA,sBAIjB,GADE,IAA8C,GAAA,IAAA,SAA9C,IAAmB,MAAA,EAAgB,WAAW,EAAA,GAAA,MAAA,KAAA,EAAA,EAAA,IAChD,EAAO,EAAA,EAAA,EAAA,OAAA,EAAA,8CAOT,OAAI,UAAA,EAAA,IAAA,MAAA,EAAA,aAIF,KAGQ,oBAAkB,SAAA,EAAA,MAC1B,MAEO,UAAP,EAAe,OACV,GAAA,KACL,GAAO,GAAI,MAAK,EAAA,cAAA,EAAA,WAAA,EAAA,WAAA,YAAA,EAAA,EAAA,GAAA,EAAA,EAAA,EAAA,YAAA,EAAA,EAAA,mFAGX,EAAA,8DAGG,YAAZ,GAAY,KAA+B,sBAKlC,MAGE,oBAAkB,SAAY,EAAA,eAIrC,GADK,WACE,GAAA,OAAA,YAAkB,KAAW,EAAA,iGAG/B,EAAA,0LAwBP,EAAI,SAAU,EAAA,WAAY,GAAA,EAAA,WAAA,EAAA,MAFnB,eAqDZ,yBC/PG,OAAI,8CAIF,YAAS,WAAO,SAAA,6BAElB,GAAU,WACR,eACA,GAAI,OACG,iBAcd,OAZQ,IACH,EAAG,OAAS,kBAGZ,EAAO,4CAQJ,eAQD,YAAW,WAAY,SAAO,mBACvB,EAAM,EAAS,yBAEtB,MACE,cACA,GAAG,OACD,cAED,EAAM,WAAA,+BAId,EAAA,KCrDH,EAAA,YAAA,2IAcI,GACE,IADE,QAAc,4HAmBhB,GAAA,+dAoCE,GAAiB,IAAA,EAAA,KAAA,SAKK,UAAtB,EAAA,IAAA,EAAA,YAGA,EAAS,EAAG,2EAcZ,EAAY,KAAM,EAAA,IAAA,EAA8B,kBAAsB,GACtE,EAAa,MAAO,EAAA,IAAA,EAA+B,mBAAS,qmBC1FpE,ODgJI,yDClJJ,GAAA,EAAA,IAAA,EAAA,eAAA,GAAA,EAAA,IAAA,EAAA,gBAAA,GAAA,EAAA,IAAA,EAAA,mBAAA,GAAA,EAAA,IAAA,EAAA,oBAAA,GAEQ,gBAQJ,OAAK,mDAEH,gBAAS,cAEP,GAAI,KAAA,sMAIJ,MAAA,SAAc,KAAU,SAAA,EAAA,8DAyCxB,GAAc,GAAA,EAAd,WACA,GAAO,GAAA,yDAnCL,EAAY,QAAO,UAAY,EAAM,KACzB,cAGZ,GAAA,EAAiB,EAAW,EAAW,EAAA,EAAA,CAuC5C,uDAnCG,EAAc,EAAA,EAAW,IAAA,EAAS,IAChC,EAAU,EAAK,IAAS,EAAA,KAClB,EAAS,KACb,EAAc,EAAA,IAAU,MACjB,EAAA,EAAc,GAAA,EAAA,GAAA,cAIzB,EAAc,SAAA,SAAe,EAAS,GACpC,MAAI,GAAA,KAAQ,EAAA,EAAA,IACZ,KAAM,SAAA,SACN,GAAO,QAAU,EAAA,EAAA,EAAA;IAKnB,EAAS,aAAoB,SAAO,GAClC,GAAA,eACM,GAAa,EACjB,EAAO,aAgBd,uBC1DC,QAAA,MAAA,GAAuB,QAAQ,QAAA,IAAA,IAAA,QAAA,OAAA,iCAER,WAAQ,SAAA,EAAA,kCAGd,EAAA,6BACX,EAAA,yBAEN,EAAS,EAAsB,sBACb,EAAA,4BACK,EAAA,6DAGzB,IAAa,EACX,EAAI,WACG,MACL,GAAA,EAAgB,wCAMtB,GAAO,GAAA,EAAA,EAAA,OAAA,qBAEN,EAAA,OAAA,uCCxBG,OAAA,wBAAa,+CAEb,SAAU,cAEV,GAAW,KAAA,UACX,UAAS,UACT,kBAAU,UACV,YAAU,QACV,YAAM,QACN,UAAM,yDAGR,WAAK,eAEH,UAAI,EACJ,UAAI,EACJ,MAAI,EACJ,MAAI,QAGJ,MAAS,UAAa,aAAQ,WAAA,KAAA,iBAAA,QAAA,WAAA,WAAA,OAAA,aAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,WAQxB,GAAQ,WAiKR,sCAgCJ,QAAO,sCAEL,EAAO,YAAW,EAAO,YAAgB,sFA8B3C,EAAO,SAAA,EAAA,gKA1NP,IAAA,GAAO,EAAM,OAAc,EAAQ,OAAA,EAAW,MAAQ,QAAa,EAAS,oDAQ5E,EAAM,IAAA,EAAQ,IAAW,EAAA,SAAA,EAAA,QAAA,KAAA,OAAA,qHAUzB,EAAM,wFASN,EAAG,aAAQ,WACT,EAAO,cAIH,SAAI,EAAY,UAAY,IAG5B,gMAQN,OADI,GAAA,UAAkB,EAAQ,OAAQ,SAC/B,EAAc,GAAA,4FAQrB,GAAO,SAAO,KAAA,SAAW,6EAGvB,EAAW,EAAA,MAAM,KACT,EAAa,KACjB,2BAMN,EAAO,8CAQH,QAAA,0BAKF,EAAM,qBAIR,EAAc,QAIV,cAIA,KAAS,eACT,EAAQ,WAER,EAAI,MAAQ,EAAA,YAAW,eAAA,GAAA,wBAGhB,UACL,UAAS,EAAA,cACT,EAAQ,mHAKZ,EAAA,EAAe,GAAO,UAAW,QAAA,QAAY,EAAO,GAAA,WAAS,cAG7D,EAAA,EAAkB,WAKd,EAAgB,SAAS,EAAQ,EAAA,6DAMnC,EAAS,wDAIX,EAAc,SAAS,EAAM,YAG7B,EAAO,UACP,EAAW,MAAA,EAAA,EAAA,KAIX,IAAA,GAAA,EAAsB,MAAA,EAAW,EAAA,EAAA,EAC/B,IAAG,EAAA,MAAA,EAAA,KAAA,4BAGL,EAAA,yCAQE,SAAmB,EAAA,YAAS,SAC5B,EAAA,uFAOJ,EAAS,GAAA,QAAuB,GAC9B,EAAY,GAAQ,QAAA,gBAGtB,EAAc,GAAA,QAAW,EAAA,8BASvB,GAAG,EAAA,WAEA,EAAA,MAAQ,EAAU,YAAA,eAAA,GAAA,iBAArB,CAGA,GAAA,GAAO,EAAW,MAAM,EAAW,wBAKjC,EAAA,UACA,EAAA,MAAA,4BAGF,EAAW,iCAKb,EAAS,IAAA,QAAuB,GAC9B,EAAY,IAAQ,QAAA,IAEjB,EAAQ,UACT,EAAY,IAAA,QAAY,EAAQ,gEAkB9B,MAAI,aACC,GAAA,2DAQX,EAAS,OACP,EAAG,sBAsBP,QAAI,GAAgB,GACpB,EAAA,SAAS,EAAc,OAAU,EAAA,MAAA,SAAA,EAAA,kBAGzB,GAAS,EAAK,SACf,SAAQ,SAAS,GAAM,GAAA,iBAAA,YAI1B,GAAO,qEAIX,MAAO,SAAA,SAAA,mCAlQL,GAAI,QAAS,wEAGb,EAAc,QAAO,QAAW,EAAQ,SAAO,MAC/C,EAAkB,kBAsQtB,OAAO,iBAMC,WAAW,UAAO,OAAO,SAAS,SAAe,EAAA,EAAA,0DAQjD,IAAM,MAAY,EAAA,QAAY,EAAA,MAAA,mLAM7B,SAAQ,QAAS,WAAW,SAAA,KAC7B,IAAQ,EAAO,SAAO,EAAA,SAAA,KACjB,GAAA,EAAA,YAAA,iDAML,QAAQ,SAAO,uBAGnB,EAAQ,QAAQ,UAKd,GAAU,EAAA,iEAOf,GAAA,EAAA,UCrVL,EAAA,uEAYS,UAAO,4FAQZ,MAAI,KAAA,0GAQA,GAAQ,EAAQ,qDAOd,GAAO,QAAU,KAAA,8CAEhB,QAAS,UAAU,EAAA,MAAU,EAAA,GAAA,EAAA,QAI9B,OAAQ,iBAEF,GAAA,iBAED,uFAMD,GAAU,QAAS,QAAQ,KACtB,EAAA,KAAA,EAAA,WAAA,QAAA,IAAA,MACL,GAAA,kIC3CR,OAAQ,0BAAA,oCAER,WAAU,cAEV,GAAS,KAAA,UACT,UAAU,UACV,YAAM,GACN,WAAO,EACP,QAAA,EACA,UAAO,QACP,SAAA,8DAGF,UAAK,UAEH,MAAA,iCAGM,6CAKD,GAAiB,EAAA,+CAQtB,GAAO,wCAQT,MAAI,6EAQA,GAAsB,EAAA,uBAAA,EAAA,kEAQlB,IAAM,MAAY,WAClB,SAAQ,WAAU,kBAAa,YAAsB,YAAW,SAAA,QAAA,UAAA,WAAA,OAAA,YAAA,cAAA,YAAA,MAAA,SAAA,WAC9D,UAAW,EAAQ,MAAA,EAAA,GAAA,EAAA,uFAMzB,EAAK,GAAA,EAAa,YAAa,GAC7B,QAAG,UAAiB,IAAW,EAAA,WAC7B,GAAQ,EAAO,wEAOhB,QAAA,SAAA,uBAGH,EAAK,QAAU,EAEb,QAAG,UAAQ,IAAoB,EAAsB,WACrD,GAAa,EAAO,2FAOtB,QAAU,SAAY,KAAW,IAAA,EAAA,MAAA,wBAC/B,KAAa,EAAA,EAAQ,OAAA,EAAA,mDAQ1B,GAAA,EAAA,UCxGL,EAAA,2BAUM,OAAA,yBAAW,yBAAA,iDAEX,UAAS,cAET,GAAU,KAAA,UACV,UAAM,UACN,YAAO,SACP,YAAU,UACV,UAAA,cACA,SAAM,yBACN,QAAA,QACA,WAAA,EACA,UAAS,EACT,MAAA,EACA,MAAA,EACA,UAAA,EACA,gBAAe,wDAGjB,YAAK,8CAEH,SAAI,OACJ,UAAI,EACJ,cAAe,wDAIb,MAAI,UAAU,YAAA,aAAA,WAAA,WAAA,SAAA,EAAA,EAAA,EAAA,EAAA,WAMV,GAAgB,EAAA,EAAA,GAEpB,GAAA,MAGA,EAAM,QAAA,UAAsB,EAAQ,EAEpC,GAAM,EAAW,EAAQ,EACzB,IAAA,GAAM,EAAY,MAElB,GAAM,cACJ,aAAmB,IACjB,YAAQ,EAAS,kHAIrB,EAAM,UAAU,EAAS,WAErB,UAAQ,SAAO,8FAQnB,EAAM,OAAY,MAIlB,EAAM,WAAa,WACjB,MAAK,GAAQ,6DAOf,EAAM,WAAA,WACJ,IAAK,GAAI,GAAI,EAAG,EAAI,EAAM,SAAS,OAAQ,IACrC,EAAM,UAAU,IAClB,EAAM,QAAQ,iEAOZ,EAAA,UAAS,IACf,EAAM,QAAW,MAOf,OAAQ,SAAU,KACf,SAAQ,IACN,wBAGP,SAAa,SAAA,4CAGf,EAAQ,UAAS,GAAS,EAAO,aAAA,OAAA,EAAA,aAAA,QAAA,GAAA,GAAA,EAAA,aAAA,KAAA,GAC3B,EAAQ,MAAM,EAAA,aAAgB,QAEhC,EAAA,aAAiB,EAEf,EAAA,uBAGK,SAAA,MACL,GAAA,EAAW,SAAA,GAAc,4BAEzB,SAAQ,6HAYR,MAAM,EAAA,YAAe,UAAW,EAAgB,EAAA,sCAM1C,aAAM,EAAgB,SAAM,sBACpC,EAAM,UAAe,QAAQ,QAAA,EAAgB,mEAKtB,EAAC,UAAY,EAAA,kFAOxC,EAAQ,WAAY,WAClB,MAAG,GAAQ,WAAU,sDACZ,EAAM,SAAA,QAMjB,EAAQ,UAAY,SAAS,GAC3B,MAAA,GAAQ,SACD,KAAA,EAAA,aAAA,QAAA,GAEF,EAAM,eAAY,sDAMzB,IAAA,EAAA,cAEM,EAAA,SAAA,GAAA,QAAA,cAGJ,MAAG,gCAQH,sBAFF,EAAA,kBAEE,EAAI,CACJ,GAAI,GAAA,QAAA,QAAA,EAAA,gGAWJ,sBAHA,EAAG,mBAGH,EAAM,WAAA,KAAA,EAAA,SAAA,IAAA,EAAA,wCAKY,MAAhB,EAAA,SAAgB,EAAA,aAAA,EAAA,EAAA,eACM,KAAlB,EAAA,SAAkB,EAAA,aAAA,EAAA,SAAA,OAAA,EAAA,EAAA,eACxB,QAAA,YAAA,EAAA,gBAAA,EAAA,aAAA,GACA,EAAG,eAKH,GAAS,EAAA,OACP,KAAQ,iBAEN,iDAKN,EAAI,WACJ,EAAQ,SAAO,GAAA,EAAW,aAAA,YAAA,EAAA,cACxB,EAAQ,UACL,EAAQ,GAAA,UAAU,EAAA,uCAMvB,GAAO,KAAA,+GAKT,GAAO,SA3LL,qCAAI,8BAAuC,KAAA,EAAA,UAAA,2CAmM/C,qBAAI,qGAQA,GAAI,EAAW,2EAQb,IAAY,MAAA,EAAW,YAAA,EAAA,YAMzB,YALE,SAAU,YAAgB,YAAA,QAAA,UAAA,WAAA,OAAA,YAAA,WAAA,cAAA,WAAA,iBAAA,YAAA,gBAAA,UAAA,WAAA,gBAAA,YAAA,MAAA,SAAA,GAC1B,QAAQ,UAAM,EAAA,MAAA,EAAA,GAAA,EAAA,MAIuB,WAAvC,EAAI,GAAA,SAAgB,cAAmB,iCAGvC,EAAI,QAAS,QAAQ,2FAQjB,EAAO,EAAO,EAAA,EAAA,GAGf,EAAA,EAAA,OAAA,GAAA,QAAA,OAAA,IAAA,6BAGH,EAAa,SAAK,EAAS,oBAEzB,EAAO,OAAA,GACP,EAAW,+CAOX,EAAG,uBACD,iBAIG,QAAS,iBAEL,IACL,UAAW,QAAc,QAAA,EAAA,8CAG3B,SADK,EAAA,UAAA,GACG,QAAO,UAAU,GAAW,EAAA,OAAA,SAAA,GAAA,OAAA,IACpC,OAAA,QAAW,WAEb,sCAAc,EAAA,OAAW,KAAW,EAAQ,eAAe,EAAS,8BAKlE,EAAQ,EAAA,UAAe,EAAW,4GAMpC,EAAI,WACJ,EAAU,SAAA,SAAA,GACV,OAAS,GAAA,IAAA,EAAA,qCAMd,GAAA,EAAA,UC7TL,EAAA,2BAUM,OAAA,uDAIA,GAAW,KAAA,0DAGX,SAAK,WACL,YAAQ,kFAQR,QAAK,SAAS,YAAgB,WAAA,eAAA,SAAA,mDAK9B,EAAK,UAAA,EAAA,SAAA,iDAGH,OAAY,EAAK,YAKjB,2BAA8B,EAAA,4CAG9B,EAAK,OAAO,KAAA,oDAKV,EAAA,EAAA,OAAA,6BAKA,EAAA,MAKC,IAAO,GAAU,IAAA,EAAA,OAAA,QAGpB,8EAOJ,EAAK,OAAO,QAAW,EACrB,EAAI,2BAAO,QAAA,SAAA,GACX,6BAOH,GAAA,0BAEC,EAAI,WAAgB,iBAMlB,UAAa,UAAU,WAAY,OAAU,SAAK,SAAA,EAAA,EAAA,EAAA,MAEhD,GAAO,EAAK,0DAIR,SACA,uHAKD,SAAa,EAAA,EAAA,EAAA,4BASd,QAAA,KAAY,sEAGH,2BAAA,KAAA,+CAKX,EAAU,YAAc,KAAA,SAAA,GAGtB,yBAAI,qBAQJ,GAAA,GAAmB,EAAA,EAAc,8HASxC,EAAU,WAAA,EAAA,wBAQD,UAAA,UAAa,WAAY,OAAA,SAAA,EAAA,EAAA,mBAGrB,YAAS,wDA6BjB,GAAA,GAAA,EAAA,OAAA,QAAA,yFAzBgB,EAAK,QAIrB,GAAG,SAAW,sEAQd,EAAU,SAAY,WACpB,EAAA,SAAW,EAAQ,SAAA,aAIf,MAAQ,8CAajB,EAAA,2BAAA,KAAA,WClLL,MAEQ,iBAQF,OAAA,4BAAU,kCAAA,+CAEV,aAAQ,WAGV,GAAA,GAAK,KAAA,WAEH,EAAI,KAAW,UACf,SAAI,IACJ,SAAI,qBAIJ,MAAS,UAAS,YAAe,aAAA,aAAA,WAAA,WAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,WAQ3B,GAAQ,EAAS,GACrB,MAAI,GAAA,GAAc,UAAS,EAAQ,GAAA,SAAS,gBAAA,EAAA,+BAM1C,GAAM,QAAU,UAAA,EAAA,EAChB,GAAO,UAAM,EAAA,QAAA,6CAGX,EAAA,EAAa,SAAA,EAAA,EAGjB,IAAA,EAAI,GAEJ,MADA,GAAI,GAAA,UACA,EAAA,EAGJ,IAGI,GAAA,MAKF,MAGA,EAXE,6BAKJ,cAQW,KAAG,0BAMZ,EAAA,EAA6B,KAAA,cAAe,EAAA,UAC5C,EAAA,EAAA,KAAA,cAAA,EAAA,yEAGA,EAAG,GAAA,SAAU,gHASb,EAAK,GAAA,yBAQL,KAAA,UACA,KAAA,QAAA,qEAOF,EAAW,IAAA,SAAA,WAGL,uGAcJ,EAAa,KAAA,IAAA,EAAe,YAAc,EAAA,KAAA,iBAGxC,EAAG,EAAY,GAAe,WAAc,IAAA,EAAA,GAAA,OAC5C,MAAG,GAAe,iBAAU,EAAY,4FAM5C,IAAW,EAAA,GAA6B,wDAGtC,MAAA,GAAW,iBAA0B,EAAA,MAKvC,EAAW,2BAA4B,sBAGhC,EAAe,cAAA,yCAOpB,GAAA,GAAe,EAAQ,mBAAA,EACvB,KACG,EAAS,OAAQ,YAAiB,UACnC,EAAQ,EAAgB,OAAS,OAAS,EAAA,EAAA,OAAA,SAAA,SAAA,yDAK5C,EAAO,EAAgB,SACrB,OAAW,SAAW,UACrB,EAAA,EAAA,OAAA,OAAA,EAAA,EAAA,OAAA,SAAA,SAAA,sDAKL,EAAW,mBAAe,SAAW,+BAEnC,MAAQ,GAAA,SAAQ,IACd,MAKF,aAAiB,mBAEf,QAAU,EAAc,SAAA,kCAEzB,GAAc,UAAM,EAAA,EAAA,OAAA,GAAA,IAAA,KACnB,EAAS,QAAc,OAAF,EAAE,YAAA,EAAA,WAAA,EAAA,EAAA,UAGzB,EAAA,iDAIF,KAAA,SAAW,EAAA,GACT,MAAA,GAAA,UAAsB,EAAA,YAGxB,OAIM,aAAW,SAAA,EAAA,KACX,MAAA,OAAA,EAAA,OAAA,OAGJ,eAAkB,SAAgB,EAAO,6BAG3C,GAAA,EAAsB,GAAA,SAAY,GAAA,EAAA,GAAA,SAAA,EAAA,CAChC,EAAA,0JAvKJ,EAAS,QAAA,QAAiB,EAAQ,SAAA,KAyLpC,OAAO,iBAME,eAAQ,aAAsB,WAAQ,aAAY,aAAA,SAAA,EAAA,EAAA,EAAA,mBAGnD,WACJ,SAAU,EAAa,EAAQ,GAE/B,GAAA,IAAU,MAAY,WAChB,SAAW,SAAA,UAAA,SAAA,GACb,QAAA,UAAU,EAAA,MAAe,EAAQ,GAAQ,EAAA,SAG3C,GAAU,EAAA,KACV,aAAY,EAAA,OAAA,4GAiBZ,mBAAsB,aAAA,WAAyB,aAAe,aAAa,8FAMhF,SAAA,QAAA,EAAA,SAAA,GC7PL,GAAA,GAAA,QAAA,QAAA,wFAUM,OAAA,4IAKA,cAAW,cAEX,GAAM,KAAA,UACN,UAAO,mCAEP,UAAW,cACX,SAAU,iCACV,QAAA,QACA,WAAA,EACA,UAAA,EACA,MAAA,EACA,MAAA,EAEA,WAAU,EACV,SAAA,OACA,WAAQ,YACR,gBAAU,KACV,WAAA,4BAGF,OAAK,aAEH,WAAI,EACJ,OAAI,iCACJ,SAAI,mCACJ,cAAa,qIAUP,GAAa,EAAe,EAAQ,WAuNpC,GAAW,EAAA,QACH,GAAA,gBAAoB,CAC5B,GAAA,GAAW,EAAA,GAAA,iBACX,GAAQ,UAAG,sEAIN,GAAA,GAAA,kBACP,EAAQ,GAAG,kBAAA,EAAA,iGAOR,OACD,GAAQ,4EAhOR,EAAA,EAAY,KACZ,EAAY,SAAM,EAAU,+BAM9B,EAAgB,EAChB,EAAS,EAAe,YAAO,GAAA,iIAGjC,EAAM,EAAoB,kBAAA,EAAA,WAAA,2CAI1B,EAAgB,EAAe,cAAO,GACpC,EAAA,EAAmB,OAAM,EAE3B,GAAM,QAAA,EAAa,SACjB,UAAY,EAAW,2EAQzB,EAAY,WAAS,EAAS,MAEzB,gBAAe,SAAU,KAC1B,eAAoB,iEAQxB,EAAY,MAAS,oHAEnB,EAAI,UACA,EAAe,UACnB,EAAa,YAIV,OAAQ,SAAc,EAAM,EAAA,kKAKrB,IAAZ,GAAY,EAAiB,WAAe,WAAA,EAAA,cAC1C,EAAK,cAAW,QAAc,KAAM,EAAW,eAC7C,2BAEF,EAAI,WAAiB,EAAW,MAAA,oFAQlC,GAAA,IAAY,GAAS,EAAW,YAAA,iDAE9B,EAAO,cAAiB,QAAA,KAAW,EAAS,aAC5C,EAAI,cAKA,OAAc,cAEhB,GACc,EADd,EAAa,EAAK,SAAe,SAAS,EAAA,OAAU,EAAA,IACpD,yEAGF,EAAI,MAAO,KAAA,EAAA,MAAA,EAAA,EAAA,GAAA,SAAA,EAAA,OAAA,EAAA,YAAA,EAAA,GAAA,SAAA,EAAA,YAAA,EAAA,QAEE,GAAX,4BAEF,EAAM,GAAO,MAAA,KAAA,EAAA,EAAA,EAAA,EAAA,QAAA,EAAA,GAAA,EAAA,YACb,EAAM,MAAS,KAAA,EAAA,MAAA,EAAA,EAAA,GAAA,SAAA,EAAA,OAAA,EAAA,YAAA,EAAA,GAAA,SAAA,EAAA,YAAA,EAAA,IAGf,IAAA,gDAIA,GAAI,KAAA,IACC,OAAG,IACN,MAAY,EAAA,OAAe,EAAY,GAAM,MAAA,WAAA,mBAC3B,IACX,UAAK,+BAIhB,MAAA,GAAY,MACN,IAAA,EACD,EAAU,aAAG,EAAA,MAAA,WACC,IAAf,EACK,EAAG,eAAa,EAAA,MAAA,aADrB,QAHsB,2CAUpB,KAAN,EACE,EAAY,EAAA,UAA4B,IAAV,EAAU,OAC1B,IAAZ,MACK,EAAA,UAAA,KAAA,EAAA,oCAKT,EAAA,aAAY,SAAiB,EAAS,GACb,WAAnB,EAAA,cACJ,EAAY,eAAQ,EAAY,GAEhC,EAAc,WAAG,EAAA,MAIP,eAAW,SAAW,EAAS,4BAEzC,EAAY,EAAO,cAAgB,EAAA,EAAA,GAAA,2CAGrC,EAAY,SAAA,EAAa,SAAS,EAAO,SAAO,IAAA,GAG5C,EAAA,WAAiB,EAAW,SAAM,EAAS,WAAgB,IAAA,KAEnD,OAAA,EAAa,GAAA,+BAIvB,GAAA,0DAGF,QAAY,OAAA,GAAe,KAAS,EAAK,sBAEvC,EAAc,GAAA,MAAS,KAAA,EAAA,EAAA,EAAkB,KAAS,EAAI,OAAA,EAAA,EAAA,OAAA,EAAA,YACtD,QAAI,OAAA,GAAA,OAAA,EAAA,gBAEJ,EAAY,YAGR,aAAoB,SAAA,MAEE,UAAxB,EAAA,OAAS,SAAA,eAAe,EAAA,wCAI5B,GAAA,GAAY,QAAa,QAAS,EAAK,OACJ,YAA5B,EAAA,GAAA,SAAmB,gBACpB,EAAA,EAAA,+DAOJ,GAAI,mBAAmB,KAAA,EAAA,WAAY,EAAA,WAAA,EAAA,OAAnC,IACA,EAAI,iBACJ,EAAI,sDAMF,GAAO,GAAA,MAAY,EAAI,SACf,EAAI,WAAgB,EAAgB,EAAA,EAAgB,GAAY,2EAMxE,KACY,OAAP,QAAO,EAAyC,EAAjB,EAAiB,EAAS,EAAQ,EAAU,sCAKhF,IAAO,EAAY,EACP,6DAEI,KAAhB,EAAA,SAA2B,EAAS,SAAA,EAAe,SAAA,EAAA,SAAA,OAE3C,EAAA,EAAqB,GAAA,OAC7B,GAAI,EAAa,IACF,IAAf,4DAEiB,KAAnB,EAAY,SAAgB,EAAA,WAAe,EAAA,SAAA,EAAA,WAAA,KAE3C,EAAY,EAAA,EAAA,GAAA,yEAMZ,EAAW,OAAG,EAAA,GAAiB,KACzB,EAAsB,GAAA,EAAA,MACjB,eA0BT,GAAQ,EAAK,OACL,KAAG,kCAEb,EAAA,KAAA,OAAA,uDAGE,IACJ,EAAY,KAAA,OAAU,QACpB,EAAG,KAAY,WAAQ,QACrB,EAAQ,GAAA,QAAI,QAEd,MAGF,IAAI,GAAQ,EAAY,OACxB,GAAY,QAAO,WACjB,GAAA,EAAA,4BAGA,WAGI,EAAW,2BAKjB,EAAI,WACJ,EAAY,SAAO,GAAS,EAAM,aAAA,YAAA,EAAA,cAC5B,EAAA,UACJ,EAAY,GAAA,UAAa,EAAU,aAEjC,GAAA,2CAKJ,EAAO,+GAKT,EAAO,UA1RL,IADI,QAAc,QAAO,EAAA,SAAA,MACrB,8BAAsB,KAAA,EAAA,UAAA,YAC1B,EAAY,eAAY,GAAA,UAAA,+CAgS7B,EAAU,SAAA,kBAQP,gBAAS,UAAA,SAAA,KAAA,iBAAA,cAAA,cAAA,SAAA,EAAA,EAAA,EAAA,EAAA,EAAA,gFAIe,GAAO,uBAAY,EAAA,wFAkDvC,GAAI,QAAS,OAAA,GAAb,IACI,GAAA,MAAA,EAAA,UAAA,GAAA,MAAA,EAAA,WAAA,YAAA,KAAA,EAAA,IAAA,EAAA,mFAEJ,EAAW,GAAa,wGAuExB,2FApHA,IAAW,MAAS,EAAA,WAAW,WAC/B,SAAa,YAAO,YAAoB,QAAA,UAAW,WAAA,OAAA,YAAA,WAAA,YAAA,WAAA,aAAA,kBAAA,YAAA,WAAA,aAAA,SAAA,gBAAA,SAAA,WAAA,MAAA,SAAA,0CAKrD,EAAI,QAAA,EAAa,OAAA,EAAY,OAAS,SAAY,GAClD,GAAqB,QAAA,UAAA,kEAErB,KAAW,EAAQ,EAAA,OAAA,EAAA,8EAMnB,GAAI,EAAa,sBAGjB,EAAiB,SAAA,EAAW,+BAKxB,EAAA,GAA0B,OAAA,EAAW,WAAA,KAAA,sDAKzC,QAAM,UAAY,EAAA,KAAS,EAAS,SAAU,EAAA,SAAU,6CAEtD,MAAA,EAAkB,SAAW,KAAA,EAAA,SAC5B,EAAA,EAAA,kBAKG,OAAA,EAAA,QAAmB,WAEvB,EAAW,OAAA,EAAa,cACxB,KAkBS,SAAA,QAAA,SAAA,GAGT,IAAI,QAIF,GAAA,aAAA,QAAA,GACK,sDAGP,QAAG,GAAQ,MAAa,EAAU,eAChC,GAAO,aAAW,QAAY,MAKd,GAEX,aAAA,SACE,EAAS,EAAW,EAAA,iBAAA,EAAA,wGAKH,QAAjB,EAAA,oCAGN,GAAQ,MAAA,EAAY,iBAKd,YAAW,KAAM,SAAA,MAExB,SAEA,WADK,YAAA,IAAA,OAAA,EACE,8CAIT,EAAW,MAAa,EAAA,KAAA,EAAA,0BACjB,SAAA,EAAA,4DAcT,EAAU,IAAA,kCASb,GAAA,EAAA,UC7dL,EAAA,2BAUM,OAAA,0BAAa,+CAEb,WAAQ,cAER,GAAU,KAAA,UACV,UAAA,UACA,YAAS,GACT,YAAU,UACV,YAAM,UACN,WAAM,EACN,QAAO,EACP,UAAM,MACN,SAAO,2BACP,iBAAW,EACX,QAAA,kCAGF,MAAK,WAEH,KAAI,GACJ,MAAI,EACJ,WAAI,EACJ,WAAI,wKAUE,GAAiB,EAAS,WA+MvB,OACH,MAAO,EAAS,YAAA,QAAA,WAkDd,0EAQN,MAAS,GAAS,GAAA,MAIlB,cAgGM,iGAKG,WAAA,IACH,EAAA,GAAmB,UAAR,EAAsB,aAAA,QAAA,EAAA,OACrC,EAAS,GAAa,UAAT,EAAuB,aAAA,OAAA,EAAA,OACpB,WAAd,GAAuB,UAAA,GAAA,EAAA,GAAA,EAAA,aAAA,YAAA,EAAA,qCAKrB,YACA,GAAA,EAAa,QAAY,MAAA,qEAKtB,WAAA,IACJ,EAAQ,IAAY,UAAZ,EAAqB,aAAA,QAAA,EAAA,OAC9B,EAAA,IAAuB,UAAT,EAAkB,aAAA,OAAA,EAAA,OAC3B,cAAA,UAAA,GAAA,EAAA,IAAA,EAAA,aAAA,YAAA,EAAA,4BAKT,QAAS,KACgB,UAApB,EAAQ,QACT,EAAW,GAAA,QAAI,EAAS,UAExB,EAAQ,GAAA,QAAI,EAAS,eAIzB,QAAI,KACK,UAAT,EAAS,kCAGP,EAAS,IAAA,QAAW,EAAA,uBAKlB,OAGI,2BAKJ,EAAA,GAAA,QAAe,EAAS,MAExB,GAAyB,SAI7B,QAAS,KACP,+DAQA,EAAI,0BAKF,GAAiB,mBAGnB,IAAI,GAAA,EAAA,GAEF,EAAQ,EAAA,uBACH,UAAA,kFAYP,OALF,wBAAS,EAAA,OAAoB,GAEvB,EAAQ,SAAgB,GAGvB,QAAA,UAAA,EAAA,WAGD,GAAsB,EAAS,EAAA,EAAA,SAEjC,EAAA,EAAA,MAAA,YAEA,EAAS,QACP,oCAGF,KAAA,EAAA,KAAA,EAAA,MAEA,WACE,+BAGF,KAAA,EAAA,KAAA,EAAA,MAAA,EAAA,EAAA,EAEA,WACE,mCAGF,KAAA,EAAA,KAAA,QAGF,SACE,8CAOE,EAAA,SACA,MAIY,UAAT,IAA0B,WAAV,EAAA,GACrB,OAAQ,EAAM,IACd,IAAK,OACH,EAAO,KAAM,EAAS,IACtB,MACF,KAAK,QACH,EAAO,KAAM,EAAS,KAAM,EAAS,MAAA,qDAIzC,IAAO,yBAGT,KAAS,SACP,EAAW,IAAM,EAAK,IAAM,EAAY,wBAOrC,GAAqB,EAAA,KACnB,KAAQ,IAAA,EAAW,KAAA,KAAA,EAAA,iCAKpB,uCAID,mFA5gBH,iJAOF,IAAA,EAAS,OAAM,QAAQ,SAAc,EAAK,OAAS,wFAQnD,EAAM,IAAA,EAAc,IAAS,EAAA,KAAW,OAAA,iGAUxC,EAAM,WAAQ,mDAKd,EAAM,wFASN,EAAI,aAAS,2BAKL,SAAA,EAAa,UAAgB,QAG3B,IAGJ,kKAQD,OAFD,GAAW,SAAY,EAAa,EAAA,oBAAc,EAAA,KACtD,EAAS,WAAc,WAAS,KAAU,GAC7B,EAAS,GAAA,yDAQtB,QAAS,SAAO,KAAW,EAAA,EAAA,6DAGzB,EAAY,IACF,EAAQ,KACd,0HAoBJ,EAAA,+CAGG,EAAQ,YACT,EAAQ,EAAiB,EAAU,YAIrC,0EAQF,EAAS,0GAiBP,EAAK,cAIL,MAAU,+BAEC,6DAOS,OAAd,GAAc,EAAc,QAClC,EAAI,MAAQ,mBAIR,KAAQ,gBACH,YAAA,EAAA,wDAGF,CACL,GAAS,WACT,EAAQ,0DAOV,EAAW,KACX,EAAA,UAOA,EAAW,EAAA,OAAW,gHAQtB,EAAI,WAAU,EAAe,SAAY,EAAQ,wDAIjD,EAAW,aAAA,EAAA,SAAA,EAAA,mCAKT,IAAG,EAAY,MAAW,EAAK,KAAA,iCAIjC,EAAG,WACD,EAAG,kBAGH,GAAA,EAAA,KAAA,WAAA,cAIA,EAAA,oEAiBI,MAAA,oCAGK,iCAIb,EAAI,WAAA,WACA,QAAA,GACJ,EAAS,QAEJ,EAAC,MAAS,oBAIb,wBAIA,GAAA,EAAa,SAAb,yCAIA,EAAI,EAIJ,EAAW,KAIT,GAAA,EAAA,MAAA,EAAA,wBAGF,EAAG,SAAQ,EAAa,UAAA,IACtB,yBAIJ,iCAwBA,EAAS,OAAA,WACP,EAAQ,SAAY,EAAA,QAAA,EAAA,oFAahB,gBAAW,cACb,sCAKF,EAAW,EAAS,KAAQ,kEAY1B,GAAI,0DAKO,IACT,GAAY,4HAMd,EAAK,EAAsB,QAAW,SAAA,OAClC,EAAwB,QAAA,QAAW,GAAA,EAAyB,IAAA,EAAA,EAAA,2NAclE,EAAmC,SAAnC,EAA+C,QAAA,EAAA,QAAA,QAAA,SAGjD,EAAS,YAAW,GAAc,SAAA,wCAQ5B,SAAc,SAAI,GACT,KAAX,EAAA,OAAW,EAAA,WACX,EAAI,+BAKF,cAAA,SAAA,GACA,KAAA,EAAA,oBAEJ,EAAA,oBAIF,EAAS,yBAAoB,SAAA,GAC3B,EAAI,iBACJ,EAAA,oBAEI,SAAW,EAAS,GAAA,OAAS,EAAA,GAAA,2BA6LrC,QAAI,GAAgB,GACpB,EAAA,SAAS,EAAc,OAAU,EAAA,MAAA,SAAA,EAAA,kBAGzB,GAAS,EAAK,SACf,SAAQ,SAAS,GAAM,GAAA,iBAAA,YAI1B,GAAO,qEAIX,MAAO,SAAA,SAAA,yFAvjBL,EAAe,cACf,EAAI,QAAU,QAAS,EAAW,cA8jBtC,OAAO,iBAMC,aAAW,UAAO,YAAA,OAAA,WAAA,QAAA,SAAA,EAAA,EAAA,EAAA,EAAA,0DAQpB,IAAM,MAAQ;iOAOZ,EAAM,eAAa,aACnB,MAAQ,qGAOZ,GAAK,MAAa,EAAA,YAAa,GAC7B,QAAG,UAAiB,IAAW,EAAA,WAC7B,GAAQ,EAAO,uEAOhB,QAAA,SAAA,uBAGH,EAAK,MAAU,EAEb,QAAG,UAAQ,IAAoB,EAAA,WAC/B,GAAa,EAAO,iEAMhB,GAAY,QAAQ,UAAU,KAC/B,QAAQ,SAAS,KAAW,IAAa,EAAS,MAAM,wBAC3D,KAAa,EAAA,EAAQ,OAAQ,EAAW,UAI1C,EAAI,WAAU,EAAS,OAAA,EAAS,UAAA,SAAA,6BAGhC,QAAU,SAAY,KAAW,IAAA,EAAA,MAAA,0BACX,EAAA,WAApB,KAAY,GAAQ,GAAA,+CAQzB,GAAA,EAAA,UC1qBL,EAAA,2BAUM,OAAA,4BAAW,yBAAA,iDAEX,aAAS,cAET,GAAU,KAAA,UACV,UAAM,UACN,YAAO,YACP,YAAW,aACX,UAAQ,cACR,SAAO,+BACP,QAAA,iCAGF,MAAK,UAEH,UAAI,kBAEJ,MAAA,mGAQM,GAAc,EAAO,EAAA,YAKvB,EAAM,QAAA,UAAe,EAAA,EAEvB,GAAM,EAAA,EAAA,iBAEN,EAAM,EAAY,SAEd,cAAW,2CAIf,EAAM,kBAEF,UAAW,SAAO,+GAYjB,WAAM,iBACP,GAAM,gBAKF,OAAA,SAAe,2CAGvB,EAAA,aAAoB,MAIlB,SAAW,SAAA,GACX,EAAM,aAAA,KAGA,OAAM,SAAQ,4DAKtB,EAAA,gBACK,GAAS,EAAc,kDAO5B,EAAW,WAAY,WACrB,MAAI,GAAI,WAAe,wFAChB,EAAA,SAAA,2DAQT,IAAA,EAAA,cAEM,EAAA,SAAA,GAAA,QAAA,oDAQJ,EAAG,mBACD,oIAaI,KAAN,EAAM,SAAA,EAAA,SAAA,gCAKc,KAAlB,EAAO,SAAW,EAAA,aAAA,EAAA,EAAA,eACJ,KAAlB,EAAW,SAAkB,EAAA,aAAA,EAAA,SAAA,OAAA,EAAA,EAAA,eAC3B,QAAA,YAAA,EAAA,gBAAA,EAAA,aAAA,uBAMI,EAAW,2BAKjB,EAAW,WACX,EAAW,SAAO,GAAA,YAAW,EAAA,cAC3B,EAAW,UACR,EAAQ,GAAA,UAAU,EAAA,uCAMvB,GAAO,KAAA,gGAKT,uCAQF,qBAAI,2GAQA,GAAI,EAAkB,wEAQtB,GAAI,IAAA,MAAa,+LAEb,QAAA,UAAiB,EAAA,MAAA,EAAA,GAAA,EAAA,KAIrB,IAAI,GAAA,EAAgB,QAAA,EAAc,mGAM/B,IAAQ,GAAc,IAAA,8BAEvB,GAAI,EAAiB,GAGnB,EAAA,EAAuB,EAAO,EAAY,8GAQ9C,EAAkB,SAAS,EAAA,GAAmB,KAAA,SAAU,eAEtD,EAAM,cAEL,KAIG,OAAA,EAAW,QAAA,SAAc,qBAGjB,SAAS,EAAO,QACtB,SAAA,GAGJ,GAAG,EAAO,aAAgB,EAAO,QAAG,EAAU,OAAU,aACvD,GAAA,cAAuB,EAAO,WAAA,UAAA,EAAA,EAAA,WAAA,OAAA,sEAOZ,IAAvB,EAAW,QAAiB,EAAS,GAAA,QAAY,qBAG/C,EAAO,8CAOP,GAAI,GAAQ,EAAoB,aAAW,EAC3C,OAAI,KAAmB,EAAU,GAAA,yBAMnC,GAAA,EAAU,SAAY,EAAW,YAAA,MAAA,GAAA,IAAA,GAC/B,IAAI,GAAA,EAAW,UAAU,EAAA,aACzB,EAAU,QAAA,UAAA,GAAA,EAAA,OAAA,SAAA,GAAA,MAAA,EAAA,UACV,GAAA,QAAY,SAAA,GAAA,EAAA,aAAA,GAAA,4FAMjB,GAAA,EAAA","file":"angular-strap.min.js","sourcesContent":["\nangular.module('mgcrea.ngStrap', [\n 'mgcrea.ngStrap.modal',\n 'mgcrea.ngStrap.aside',\n 'mgcrea.ngStrap.alert',\n 'mgcrea.ngStrap.button',\n 'mgcrea.ngStrap.select',\n 'mgcrea.ngStrap.datepicker',\n 'mgcrea.ngStrap.timepicker',\n 'mgcrea.ngStrap.navbar',\n 'mgcrea.ngStrap.tooltip',\n 'mgcrea.ngStrap.popover',\n 'mgcrea.ngStrap.dropdown',\n 'mgcrea.ngStrap.typeahead',\n 'mgcrea.ngStrap.scrollspy',\n 'mgcrea.ngStrap.affix',\n 'mgcrea.ngStrap.tab',\n 'mgcrea.ngStrap.collapse'\n]);\n","'use strict';\n\nangular.module('mgcrea.ngStrap.affix', ['mgcrea.ngStrap.helpers.dimensions', 'mgcrea.ngStrap.helpers.debounce'])\n\n .provider('$affix', function() {\n\n var defaults = this.defaults = {\n offsetTop: 'auto'\n };\n\n this.$get = function($window, debounce, dimensions) {\n\n var bodyEl = angular.element($window.document.body);\n var windowEl = angular.element($window);\n\n function AffixFactory(element, config) {\n\n var $affix = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var targetEl = options.target;\n\n // Initial private vars\n var reset = 'affix affix-top affix-bottom',\n setWidth = false,\n initialAffixTop = 0,\n initialOffsetTop = 0,\n offsetTop = 0,\n offsetBottom = 0,\n affixed = null,\n unpin = null;\n\n var parent = element.parent();\n // Options: custom parent\n if (options.offsetParent) {\n if (options.offsetParent.match(/^\\d+$/)) {\n for (var i = 0; i < (options.offsetParent * 1) - 1; i++) {\n parent = parent.parent();\n }\n }\n else {\n parent = angular.element(options.offsetParent);\n }\n }\n\n $affix.init = function() {\n\n this.$parseOffsets();\n initialOffsetTop = dimensions.offset(element[0]).top + initialAffixTop;\n setWidth = !element[0].style.width;\n\n // Bind events\n targetEl.on('scroll', this.checkPosition);\n targetEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', this.$debouncedOnResize);\n\n // Both of these checkPosition() calls are necessary for the case where\n // the user hits refresh after scrolling to the bottom of the page.\n this.checkPosition();\n this.checkPositionWithEventLoop();\n\n };\n\n $affix.destroy = function() {\n\n // Unbind events\n targetEl.off('scroll', this.checkPosition);\n targetEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', this.$debouncedOnResize);\n\n };\n\n $affix.checkPositionWithEventLoop = function() {\n\n // IE 9 throws an error if we use 'this' instead of '$affix'\n // in this setTimeout call\n setTimeout($affix.checkPosition, 1);\n\n };\n\n $affix.checkPosition = function() {\n // if (!this.$element.is(':visible')) return\n\n var scrollTop = getScrollTop();\n var position = dimensions.offset(element[0]);\n var elementHeight = dimensions.height(element[0]);\n\n // Get required affix class according to position\n var affix = getRequiredAffixClass(unpin, position, elementHeight);\n\n // Did affix status changed this last check?\n if(affixed === affix) return;\n affixed = affix;\n\n // Add proper affix class\n element.removeClass(reset).addClass('affix' + ((affix !== 'middle') ? '-' + affix : ''));\n\n if(affix === 'top') {\n unpin = null;\n element.css('position', (options.offsetParent) ? '' : 'relative');\n if(setWidth) {\n element.css('width', '');\n }\n element.css('top', '');\n } else if(affix === 'bottom') {\n if (options.offsetUnpin) {\n unpin = -(options.offsetUnpin * 1);\n }\n else {\n // Calculate unpin threshold when affixed to bottom.\n // Hopefully the browser scrolls pixel by pixel.\n unpin = position.top - scrollTop;\n }\n if(setWidth) {\n element.css('width', '');\n }\n element.css('position', (options.offsetParent) ? '' : 'relative');\n element.css('top', (options.offsetParent) ? '' : ((bodyEl[0].offsetHeight - offsetBottom - elementHeight - initialOffsetTop) + 'px'));\n } else { // affix === 'middle'\n unpin = null;\n if(setWidth) {\n element.css('width', element[0].offsetWidth + 'px');\n }\n element.css('position', 'fixed');\n element.css('top', initialAffixTop + 'px');\n }\n\n };\n\n $affix.$onResize = function() {\n $affix.$parseOffsets();\n $affix.checkPosition();\n };\n $affix.$debouncedOnResize = debounce($affix.$onResize, 50);\n\n $affix.$parseOffsets = function() {\n var initialPosition = element.css('position');\n // Reset position to calculate correct offsetTop\n element.css('position', (options.offsetParent) ? '' : 'relative');\n\n if(options.offsetTop) {\n if(options.offsetTop === 'auto') {\n options.offsetTop = '+0';\n }\n if(options.offsetTop.match(/^[-+]\\d+$/)) {\n initialAffixTop = - options.offsetTop * 1;\n if(options.offsetParent) {\n offsetTop = dimensions.offset(parent[0]).top + (options.offsetTop * 1);\n }\n else {\n offsetTop = dimensions.offset(element[0]).top - dimensions.css(element[0], 'marginTop', true) + (options.offsetTop * 1);\n }\n }\n else {\n offsetTop = options.offsetTop * 1;\n }\n }\n\n if(options.offsetBottom) {\n if(options.offsetParent && options.offsetBottom.match(/^[-+]\\d+$/)) {\n // add 1 pixel due to rounding problems...\n offsetBottom = getScrollHeight() - (dimensions.offset(parent[0]).top + dimensions.height(parent[0])) + (options.offsetBottom * 1) + 1;\n }\n else {\n offsetBottom = options.offsetBottom * 1;\n }\n }\n\n // Bring back the element's position after calculations\n element.css('position', initialPosition);\n };\n\n // Private methods\n\n function getRequiredAffixClass(unpin, position, elementHeight) {\n\n var scrollTop = getScrollTop();\n var scrollHeight = getScrollHeight();\n\n if(scrollTop <= offsetTop) {\n return 'top';\n } else if(unpin !== null && (scrollTop + unpin <= position.top)) {\n return 'middle';\n } else if(offsetBottom !== null && (position.top + elementHeight + initialAffixTop >= scrollHeight - offsetBottom)) {\n return 'bottom';\n } else {\n return 'middle';\n }\n\n }\n\n function getScrollTop() {\n return targetEl[0] === $window ? $window.pageYOffset : targetEl[0].scrollTop;\n }\n\n function getScrollHeight() {\n return targetEl[0] === $window ? $window.document.body.scrollHeight : targetEl[0].scrollHeight;\n }\n\n $affix.init();\n return $affix;\n\n }\n\n return AffixFactory;\n\n };\n\n })\n\n .directive('bsAffix', function($affix, $window) {\n\n return {\n restrict: 'EAC',\n require: '^?bsAffixTarget',\n link: function postLink(scope, element, attr, affixTarget) {\n\n var options = {scope: scope, offsetTop: 'auto', target: affixTarget ? affixTarget.$element : angular.element($window)};\n angular.forEach(['offsetTop', 'offsetBottom', 'offsetParent', 'offsetUnpin'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var affix = $affix(element, options);\n scope.$on('$destroy', function() {\n affix && affix.destroy();\n options = null;\n affix = null;\n });\n\n }\n };\n\n })\n\n .directive('bsAffixTarget', function() {\n return {\n controller: function($element) {\n this.$element = $element;\n }\n };\n });\n","'use strict';\n\n// @BUG: following snippet won't compile correctly\n// @TODO: submit issue to core\n// ' ' +\n\nangular.module('mgcrea.ngStrap.alert', ['mgcrea.ngStrap.modal'])\n\n .provider('$alert', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'alert',\n prefixEvent: 'alert',\n placement: null,\n template: 'alert/alert.tpl.html',\n container: false,\n element: null,\n backdrop: false,\n keyboard: true,\n show: true,\n // Specific options\n duration: false,\n type: false,\n dismissable: true\n };\n\n this.$get = function($modal, $timeout) {\n\n function AlertFactory(config) {\n\n var $alert = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $alert = $modal(options);\n\n // Support scope as string options [/*title, content, */ type, dismissable]\n $alert.$scope.dismissable = !!options.dismissable;\n if(options.type) {\n $alert.$scope.type = options.type;\n }\n\n // Support auto-close duration\n var show = $alert.show;\n if(options.duration) {\n $alert.show = function() {\n show();\n $timeout(function() {\n $alert.hide();\n }, options.duration * 1000);\n };\n }\n\n return $alert;\n\n }\n\n return AlertFactory;\n\n };\n\n })\n\n .directive('bsAlert', function($window, $sce, $alert) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'placement', 'keyboard', 'html', 'container', 'animation', 'duration', 'dismissable'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content', 'type'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAlert && scope.$watch(attr.bsAlert, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize alert\n var alert = $alert(options);\n\n // Trigger\n element.on(attr.trigger || 'click', alert.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (alert) alert.destroy();\n options = null;\n alert = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.aside', ['mgcrea.ngStrap.modal'])\n\n .provider('$aside', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade-and-slide-right',\n prefixClass: 'aside',\n prefixEvent: 'aside',\n placement: 'right',\n template: 'aside/aside.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($modal) {\n\n function AsideFactory(config) {\n\n var $aside = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $aside = $modal(options);\n\n return $aside;\n\n }\n\n return AsideFactory;\n\n };\n\n })\n\n .directive('bsAside', function($window, $sce, $aside) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsAside && scope.$watch(attr.bsAside, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize aside\n var aside = $aside(options);\n\n // Trigger\n element.on(attr.trigger || 'click', aside.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (aside) aside.destroy();\n options = null;\n aside = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.button', [])\n\n .provider('$button', function() {\n\n var defaults = this.defaults = {\n activeClass:'active',\n toggleEvent:'click'\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsCheckboxGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"checkbox\"]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.attr('bs-checkbox', '');\n childEl.attr('ng-model', attr.ngModel + '.' + childEl.attr('value'));\n });\n }\n\n };\n\n })\n\n .directive('bsCheckbox', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support label > input[type=\"checkbox\"]\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var trueValue = angular.isDefined(attr.trueValue) ? attr.trueValue : true;\n if(constantValueRegExp.test(attr.trueValue)) {\n trueValue = scope.$eval(attr.trueValue);\n }\n var falseValue = angular.isDefined(attr.falseValue) ? attr.falseValue : false;\n if(constantValueRegExp.test(attr.falseValue)) {\n falseValue = scope.$eval(attr.falseValue);\n }\n\n // Parse exotic values\n var hasExoticValues = typeof trueValue !== 'boolean' || typeof falseValue !== 'boolean';\n if(hasExoticValues) {\n controller.$parsers.push(function(viewValue) {\n // console.warn('$parser', element.attr('ng-model'), 'viewValue', viewValue);\n return viewValue ? trueValue : falseValue;\n });\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n return angular.equals(modelValue, trueValue);\n });\n // Fix rendering for exotic values\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n controller.$render();\n });\n }\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, trueValue);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('ng-model'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n if(!isInput) {\n controller.$setViewValue(!activeElement.hasClass('active'));\n }\n if(!hasExoticValues) {\n controller.$render();\n }\n });\n });\n\n }\n\n };\n\n })\n\n .directive('bsRadioGroup', function() {\n\n return {\n restrict: 'A',\n require: 'ngModel',\n compile: function postLink(element, attr) {\n element.attr('data-toggle', 'buttons');\n element.removeAttr('ng-model');\n var children = element[0].querySelectorAll('input[type=\"radio\"]');\n angular.forEach(children, function(child) {\n angular.element(child).attr('bs-radio', '');\n angular.element(child).attr('ng-model', attr.ngModel);\n });\n }\n\n };\n\n })\n\n .directive('bsRadio', function($button, $$rAF) {\n\n var defaults = $button.defaults;\n var constantValueRegExp = /^(true|false|\\d+)$/;\n\n return {\n restrict: 'A',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n var options = defaults;\n\n // Support `label > input[type=\"radio\"]` markup\n var isInput = element[0].nodeName === 'INPUT';\n var activeElement = isInput ? element.parent() : element;\n\n var value = constantValueRegExp.test(attr.value) ? scope.$eval(attr.value) : attr.value;\n\n // model -> view\n controller.$render = function () {\n // console.warn('$render', element.attr('value'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var isActive = angular.equals(controller.$modelValue, value);\n $$rAF(function() {\n if(isInput) element[0].checked = isActive;\n activeElement.toggleClass(options.activeClass, isActive);\n });\n };\n\n // view -> model\n element.bind(options.toggleEvent, function() {\n scope.$apply(function () {\n // console.warn('!click', element.attr('value'), 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue, 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue);\n controller.$setViewValue(value);\n controller.$render();\n });\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.collapse', [])\n\n .provider('$collapse', function() {\n\n var defaults = this.defaults = {\n animation: 'am-collapse',\n disallowToggle: false,\n activeClass: 'in',\n startCollapsed: false,\n allowMultiple: false\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n self.$toggles = [];\n self.$targets = [];\n\n self.$viewChangeListeners = [];\n\n self.$registerToggle = function(element) {\n self.$toggles.push(element);\n };\n self.$registerTarget = function(element) {\n self.$targets.push(element);\n };\n\n self.$unregisterToggle = function(element) {\n var index = self.$toggles.indexOf(element);\n // remove toggle from $toggles array\n self.$toggles.splice(index, 1);\n };\n self.$unregisterTarget = function(element) {\n var index = self.$targets.indexOf(element);\n\n // remove element from $targets array\n self.$targets.splice(index, 1);\n\n if (self.$options.allowMultiple) {\n // remove target index from $active array values\n deactivateItem(element);\n }\n\n // fix active item indexes\n fixActiveItemIndexes(index);\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n // use array to store all the currently open panels\n self.$targets.$active = !self.$options.startCollapsed ? [0] : [];\n self.$setActive = $scope.$setActive = function(value) {\n if(angular.isArray(value)) {\n self.$targets.$active = angular.copy(value);\n }\n else if(!self.$options.disallowToggle) {\n // toogle element active status\n isActive(value) ? deactivateItem(value) : activateItem(value);\n } else {\n activateItem(value);\n }\n\n self.$viewChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n self.$activeIndexes = function() {\n return self.$options.allowMultiple ? self.$targets.$active :\n self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;\n };\n\n function fixActiveItemIndexes(index) {\n // item with index was removed, so we\n // need to adjust other items index values\n var activeIndexes = self.$targets.$active;\n for(var i = 0; i < activeIndexes.length; i++) {\n if (index < activeIndexes[i]) {\n activeIndexes[i] = activeIndexes[i] - 1;\n }\n\n // the last item is active, so we need to\n // adjust its index\n if (activeIndexes[i] === self.$targets.length) {\n activeIndexes[i] = self.$targets.length - 1;\n }\n }\n }\n\n function isActive(value) {\n var activeItems = self.$targets.$active;\n return activeItems.indexOf(value) === -1 ? false : true;\n }\n\n function deactivateItem(value) {\n var index = self.$targets.$active.indexOf(value);\n if (index !== -1) {\n self.$targets.$active.splice(index, 1);\n }\n }\n\n function activateItem(value) {\n if (!self.$options.allowMultiple) {\n // remove current selected item\n self.$targets.$active.splice(0, 1);\n }\n\n if (self.$targets.$active.indexOf(value) === -1) {\n self.$targets.$active.push(value);\n }\n }\n\n };\n\n this.$get = function() {\n var $collapse = {};\n $collapse.defaults = defaults;\n $collapse.controller = controller;\n return $collapse;\n };\n\n })\n\n .directive('bsCollapse', function($window, $animate, $collapse) {\n\n var defaults = $collapse.defaults;\n\n return {\n require: ['?ngModel', 'bsCollapse'],\n controller: ['$scope', '$element', '$attrs', $collapse.controller],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n if(ngModelCtrl) {\n\n // Update the modelValue following\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n if (angular.isArray(modelValue)) {\n // model value is an array, so just replace\n // the active items directly\n bsCollapseCtrl.$setActive(modelValue);\n }\n else {\n var activeIndexes = bsCollapseCtrl.$activeIndexes();\n\n if (angular.isArray(activeIndexes)) {\n // we have an array of selected indexes\n if (activeIndexes.indexOf(modelValue * 1) === -1) {\n // item with modelValue index is not active\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n else if (activeIndexes !== modelValue * 1) {\n bsCollapseCtrl.$setActive(modelValue * 1);\n }\n }\n return modelValue;\n });\n\n }\n\n }\n };\n\n })\n\n .directive('bsCollapseToggle', function() {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base attr\n element.attr('data-toggle', 'collapse');\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerToggle(element);\n\n // remove toggle from collapse controller when toggle is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterToggle(element);\n });\n\n element.on('click', function() {\n var index = attrs.bsCollapseToggle || bsCollapseCtrl.$toggles.indexOf(element);\n bsCollapseCtrl.$setActive(index * 1);\n scope.$apply();\n });\n\n }\n };\n\n })\n\n .directive('bsCollapseTarget', function($animate) {\n\n return {\n require: ['^?ngModel', '^bsCollapse'],\n // scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsCollapseCtrl = controllers[1];\n\n // Add base class\n element.addClass('collapse');\n\n // Add animation class\n if(bsCollapseCtrl.$options.animation) {\n element.addClass(bsCollapseCtrl.$options.animation);\n }\n\n // Push pane to parent bsCollapse controller\n bsCollapseCtrl.$registerTarget(element);\n\n // remove pane target from collapse controller when target is destroyed\n scope.$on('$destroy', function() {\n bsCollapseCtrl.$unregisterTarget(element);\n });\n\n function render() {\n var index = bsCollapseCtrl.$targets.indexOf(element);\n var active = bsCollapseCtrl.$activeIndexes();\n var action = 'removeClass';\n if (angular.isArray(active)) {\n if (active.indexOf(index) !== -1) {\n action = 'addClass';\n }\n }\n else if (index === active) {\n action = 'addClass';\n }\n\n $animate[action](element, bsCollapseCtrl.$options.activeClass);\n }\n\n bsCollapseCtrl.$viewChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.datepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$datepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'datepicker',\n placement: 'bottom-left',\n template: 'datepicker/datepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: false,\n dateType: 'date',\n dateFormat: 'shortDate',\n modelDateFormat: null,\n dayFormat: 'dd',\n monthFormat: 'MMM',\n yearFormat: 'yyyy',\n monthTitleFormat: 'MMMM yyyy',\n yearTitleFormat: 'yyyy',\n strictFormat: false,\n autoclose: false,\n minDate: -Infinity,\n maxDate: +Infinity,\n startView: 0,\n minView: 0,\n startWeek: 0,\n daysOfWeekDisabled: '',\n iconLeft: 'glyphicon glyphicon-chevron-left',\n iconRight: 'glyphicon glyphicon-chevron-right'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, datepickerViews, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function DatepickerFactory(element, controller, config) {\n\n var $datepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $datepicker.$options;\n var scope = $datepicker.$scope;\n if(options.startView) options.startView -= options.minView;\n\n // View vars\n\n var pickerViews = datepickerViews($datepicker);\n $datepicker.$views = pickerViews.views;\n var viewDate = pickerViews.viewDate;\n scope.$mode = options.startView;\n scope.$iconLeft = options.iconLeft;\n scope.$iconRight = options.iconRight;\n var $picker = $datepicker.$views[scope.$mode];\n\n // Scope methods\n\n scope.$select = function(date) {\n $datepicker.select(date);\n };\n scope.$selectPane = function(value) {\n $datepicker.$selectPane(value);\n };\n scope.$toggleMode = function() {\n $datepicker.setMode((scope.$mode + 1) % $datepicker.$views.length);\n };\n\n // Public methods\n\n $datepicker.update = function(date) {\n // console.warn('$datepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $datepicker.$date = date;\n $picker.update.call($picker, date);\n }\n // Build only if pristine\n $datepicker.$build(true);\n };\n\n $datepicker.updateDisabledDates = function(dateRanges) {\n options.disabledDateRanges = dateRanges;\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], $datepicker.$setDisabledEl);\n }\n };\n\n $datepicker.select = function(date, keep) {\n // console.warn('$datepicker.select', date, scope.$mode);\n if(!angular.isDate(controller.$dateValue)) controller.$dateValue = new Date(date);\n if(!scope.$mode || keep) {\n controller.$setViewValue(angular.copy(date));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $datepicker.hide(true); });\n }\n } else {\n angular.extend(viewDate, {year: date.getFullYear(), month: date.getMonth(), date: date.getDate()});\n $datepicker.setMode(scope.$mode - 1);\n $datepicker.$build();\n }\n };\n\n $datepicker.setMode = function(mode) {\n // console.warn('$datepicker.setMode', mode);\n scope.$mode = mode;\n $picker = $datepicker.$views[scope.$mode];\n $datepicker.$build();\n };\n\n // Protected methods\n\n $datepicker.$build = function(pristine) {\n // console.warn('$datepicker.$build() viewDate=%o', viewDate);\n if(pristine === true && $picker.built) return;\n if(pristine === false && !$picker.built) return;\n $picker.build.call($picker);\n };\n\n $datepicker.$updateSelected = function() {\n for(var i = 0, l = scope.rows.length; i < l; i++) {\n angular.forEach(scope.rows[i], updateSelected);\n }\n };\n\n $datepicker.$isSelected = function(date) {\n return $picker.isSelected(date);\n };\n\n $datepicker.$setDisabledEl = function(el) {\n el.disabled = $picker.isDisabled(el.date);\n };\n\n $datepicker.$selectPane = function(value) {\n var steps = $picker.steps;\n // set targetDate to first day of month to avoid problems with\n // date values rollover. This assumes the viewDate does not\n // depend on the day of the month\n var targetDate = new Date(Date.UTC(viewDate.year + ((steps.year || 0) * value), viewDate.month + ((steps.month || 0) * value), 1));\n angular.extend(viewDate, {year: targetDate.getUTCFullYear(), month: targetDate.getUTCMonth(), date: targetDate.getUTCDate()});\n $datepicker.$build();\n };\n\n $datepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $datepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n if(evt.keyCode === 13) {\n if(!scope.$mode) {\n return $datepicker.hide(true);\n } else {\n return scope.$apply(function() { $datepicker.setMode(scope.$mode - 1); });\n }\n }\n\n // Navigate with keyboard\n $picker.onKeyDown(evt);\n parentScope.$digest();\n };\n\n // Private\n\n function updateSelected(el) {\n el.selected = $datepicker.$isSelected(el.date);\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $datepicker.init;\n $datepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'date');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $datepicker.destroy;\n $datepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $datepicker.show;\n $datepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // if $datepicker is no longer showing, don't setup events\n if(!$datepicker.$isShown) return;\n $datepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $datepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $datepicker.hide;\n $datepicker.hide = function(blur) {\n if(!$datepicker.$isShown) return;\n $datepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $datepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $datepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $datepicker;\n\n }\n\n DatepickerFactory.defaults = defaults;\n return DatepickerFactory;\n\n };\n\n })\n\n .directive('bsDatepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $datepicker) {\n\n var defaults = $datepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'dateType', 'dateFormat', 'modelDateFormat', 'dayFormat', 'strictFormat', 'startWeek', 'startDate', 'useNative', 'lang', 'startView', 'minView', 'iconLeft', 'iconRight', 'daysOfWeekDisabled', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!datepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(datepicker),?/i);\n newValue === true ? datepicker.show() : datepicker.hide();\n });\n\n // Initialize datepicker\n var datepicker = $datepicker(element, controller, options);\n options = datepicker.$options;\n // Set expected iOS format\n if(isNative && options.useNative) options.dateFormat = 'yyyy-MM-dd';\n\n var lang = options.lang;\n\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n // Observe attributes for changes\n angular.forEach(['minDate', 'maxDate'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n // console.warn('attr.$observe(%s)=%o', key, newValue);\n datepicker.$options[key] = dateParser.getDateForAttribute(key, newValue);\n // Build only if dirty\n !isNaN(datepicker.$options[key]) && datepicker.$build(false);\n validateAgainstMinMaxDate(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n datepicker.update(controller.$dateValue);\n }, true);\n\n // Normalize undefined/null/empty array,\n // so that we don't treat changing from undefined->null as a change.\n function normalizeDateRanges(ranges) {\n if (!ranges || !ranges.length) return null;\n return ranges;\n }\n\n if (angular.isDefined(attr.disabledDates)) {\n scope.$watch(attr.disabledDates, function(disabledRanges, previousValue) {\n disabledRanges = normalizeDateRanges(disabledRanges);\n previousValue = normalizeDateRanges(previousValue);\n\n if (disabledRanges) {\n datepicker.updateDisabledDates(disabledRanges);\n }\n });\n }\n\n function validateAgainstMinMaxDate(parsedDate) {\n if (!angular.isDate(parsedDate)) return;\n var isMinValid = isNaN(datepicker.$options.minDate) || parsedDate.getTime() >= datepicker.$options.minDate;\n var isMaxValid = isNaN(datepicker.$options.maxDate) || parsedDate.getTime() <= datepicker.$options.maxDate;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(isValid) controller.$dateValue = parsedDate;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n controller.$setValidity('date', true);\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n return null;\n }\n var parsedDate = dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedDate || isNaN(parsedDate.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxDate(parsedDate);\n }\n if(options.dateType === 'string') {\n return formatDate(parsedDate, options.modelDateFormat || options.dateFormat);\n } else if(options.dateType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.dateType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.dateType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.dateType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelDateFormat);\n } else if(options.dateType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) {\n // var today = new Date();\n // date = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0);\n // }\n controller.$dateValue = date;\n return getDateFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getDateFormattedString());\n };\n\n function getDateFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.dateFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(datepicker) datepicker.destroy();\n options = null;\n datepicker = null;\n });\n\n }\n };\n\n })\n\n .provider('datepickerViews', function() {\n\n var defaults = this.defaults = {\n dayFormat: 'dd',\n daySplit: 7\n };\n\n // Split array into smaller arrays\n function split(arr, size) {\n var arrays = [];\n while(arr.length > 0) {\n arrays.push(arr.splice(0, size));\n }\n return arrays;\n }\n\n // Modulus operator\n function mod(n, m) {\n return ((n % m) + m) % m;\n }\n\n this.$get = function($dateFormatter, $dateParser, $sce) {\n\n return function(picker) {\n\n var scope = picker.$scope;\n var options = picker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n var dateParser = $dateParser({format: options.dateFormat, lang: lang, strict: options.strictFormat});\n\n var weekDaysMin = $dateFormatter.weekdaysShort(lang);\n var weekDaysLabels = weekDaysMin.slice(options.startWeek).concat(weekDaysMin.slice(0, options.startWeek));\n var weekDaysLabelsHtml = $sce.trustAsHtml('' + weekDaysLabels.join('') + '');\n\n var startDate = picker.$date || (options.startDate ? dateParser.getDateForAttribute('startDate', options.startDate) : new Date());\n var viewDate = {year: startDate.getFullYear(), month: startDate.getMonth(), date: startDate.getDate()};\n var timezoneOffset = startDate.getTimezoneOffset() * 6e4;\n\n var views = [{\n format: options.dayFormat,\n split: 7,\n steps: { month: 1 },\n update: function(date, force) {\n if(!this.built || force || date.getFullYear() !== viewDate.year || date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getDate() !== viewDate.date) {\n viewDate.date = picker.$date.getDate();\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstDayOfMonth = new Date(viewDate.year, viewDate.month, 1), firstDayOfMonthOffset = firstDayOfMonth.getTimezoneOffset();\n var firstDate = new Date(+firstDayOfMonth - mod(firstDayOfMonth.getDay() - options.startWeek, 7) * 864e5), firstDateOffset = firstDate.getTimezoneOffset();\n var today = new Date().toDateString();\n // Handle daylight time switch\n if(firstDateOffset !== firstDayOfMonthOffset) firstDate = new Date(+firstDate + (firstDateOffset - firstDayOfMonthOffset) * 60e3);\n var days = [], day;\n for(var i = 0; i < 42; i++) { // < 7 * 6\n day = dateParser.daylightSavingAdjust(new Date(firstDate.getFullYear(), firstDate.getMonth(), firstDate.getDate() + i));\n days.push({date: day, isToday: day.toDateString() === today, label: formatDate(day, this.format), selected: picker.$date && this.isSelected(day), muted: day.getMonth() !== viewDate.month, disabled: this.isDisabled(day)});\n }\n scope.title = formatDate(firstDayOfMonth, options.monthTitleFormat);\n scope.showLabels = true;\n scope.labels = weekDaysLabelsHtml;\n scope.rows = split(days, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth() && date.getDate() === picker.$date.getDate();\n },\n isDisabled: function(date) {\n var time = date.getTime();\n\n // Disabled because of min/max date.\n if (time < options.minDate || time > options.maxDate) return true;\n\n // Disabled due to being a disabled day of the week\n if (options.daysOfWeekDisabled.indexOf(date.getDay()) !== -1) return true;\n\n // Disabled because of disabled date range.\n if (options.disabledDateRanges) {\n for (var i = 0; i < options.disabledDateRanges.length; i++) {\n if (time >= options.disabledDateRanges[i].start && time <= options.disabledDateRanges[i].end) {\n return true;\n }\n }\n }\n\n return false;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualTime = picker.$date.getTime();\n var newDate;\n\n if(evt.keyCode === 37) newDate = new Date(actualTime - 1 * 864e5);\n else if(evt.keyCode === 38) newDate = new Date(actualTime - 7 * 864e5);\n else if(evt.keyCode === 39) newDate = new Date(actualTime + 1 * 864e5);\n else if(evt.keyCode === 40) newDate = new Date(actualTime + 7 * 864e5);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'month',\n format: options.monthFormat,\n split: 4,\n steps: { year: 1 },\n update: function(date, force) {\n if(!this.built || date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getMonth() !== viewDate.month) {\n angular.extend(viewDate, {month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstMonth = new Date(viewDate.year, 0, 1);\n var months = [], month;\n for (var i = 0; i < 12; i++) {\n month = new Date(viewDate.year, i, 1);\n months.push({date: month, label: formatDate(month, this.format), selected: picker.$isSelected(month), disabled: this.isDisabled(month)});\n }\n scope.title = formatDate(month, options.yearTitleFormat);\n scope.showLabels = false;\n scope.rows = split(months, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear() && date.getMonth() === picker.$date.getMonth();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear(), date.getMonth() + 1, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualMonth = picker.$date.getMonth();\n var newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setMonth(actualMonth - 1);\n else if(evt.keyCode === 38) newDate.setMonth(actualMonth - 4);\n else if(evt.keyCode === 39) newDate.setMonth(actualMonth + 1);\n else if(evt.keyCode === 40) newDate.setMonth(actualMonth + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }, {\n name: 'year',\n format: options.yearFormat,\n split: 4,\n steps: { year: 12 },\n update: function(date, force) {\n if(!this.built || force || parseInt(date.getFullYear()/20, 10) !== parseInt(viewDate.year/20, 10)) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$build();\n } else if(date.getFullYear() !== viewDate.year) {\n angular.extend(viewDate, {year: picker.$date.getFullYear(), month: picker.$date.getMonth(), date: picker.$date.getDate()});\n picker.$updateSelected();\n }\n },\n build: function() {\n var firstYear = viewDate.year - viewDate.year % (this.split * 3);\n var years = [], year;\n for (var i = 0; i < 12; i++) {\n year = new Date(firstYear + i, 0, 1);\n years.push({date: year, label: formatDate(year, this.format), selected: picker.$isSelected(year), disabled: this.isDisabled(year)});\n }\n scope.title = years[0].label + '-' + years[years.length - 1].label;\n scope.showLabels = false;\n scope.rows = split(years, this.split);\n this.built = true;\n },\n isSelected: function(date) {\n return picker.$date && date.getFullYear() === picker.$date.getFullYear();\n },\n isDisabled: function(date) {\n var lastDate = +new Date(date.getFullYear() + 1, 0, 0);\n return lastDate < options.minDate || date.getTime() > options.maxDate;\n },\n onKeyDown: function(evt) {\n if (!picker.$date) {\n return;\n }\n var actualYear = picker.$date.getFullYear(),\n newDate = new Date(picker.$date);\n\n if(evt.keyCode === 37) newDate.setYear(actualYear - 1);\n else if(evt.keyCode === 38) newDate.setYear(actualYear - 4);\n else if(evt.keyCode === 39) newDate.setYear(actualYear + 1);\n else if(evt.keyCode === 40) newDate.setYear(actualYear + 4);\n\n if (!this.isDisabled(newDate)) picker.select(newDate, true);\n }\n }];\n\n return {\n views: options.minView ? Array.prototype.slice.call(views, options.minView) : views,\n viewDate: viewDate\n };\n\n };\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.dropdown', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$dropdown', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'dropdown',\n placement: 'bottom-left',\n template: 'dropdown/dropdown.tpl.html',\n trigger: 'click',\n container: false,\n keyboard: true,\n html: false,\n delay: 0\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var matchesSelector = Element.prototype.matchesSelector || Element.prototype.webkitMatchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector;\n\n function DropdownFactory(element, config) {\n\n var $dropdown = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n var scope = $dropdown.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n\n $dropdown = $tooltip(element, options);\n var parentEl = element.parent();\n\n // Protected methods\n\n $dropdown.$onKeyDown = function(evt) {\n if (!/(38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Retrieve focused index\n var items = angular.element($dropdown.$element[0].querySelectorAll('li:not(.divider) a'));\n if(!items.length) return;\n var index;\n angular.forEach(items, function(el, i) {\n if(matchesSelector && matchesSelector.call(el, ':focus')) index = i;\n });\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && index > 0) index--;\n else if(evt.keyCode === 40 && index < items.length - 1) index++;\n else if(angular.isUndefined(index)) index = 0;\n items.eq(index)[0].focus();\n\n };\n\n // Overrides\n\n var show = $dropdown.show;\n $dropdown.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n options.keyboard && $dropdown.$element.on('keydown', $dropdown.$onKeyDown);\n bodyEl.on('click', onBodyClick);\n }, 0, false);\n parentEl.hasClass('dropdown') && parentEl.addClass('open');\n };\n\n var hide = $dropdown.hide;\n $dropdown.hide = function() {\n if(!$dropdown.$isShown) return;\n options.keyboard && $dropdown.$element.off('keydown', $dropdown.$onKeyDown);\n bodyEl.off('click', onBodyClick);\n parentEl.hasClass('dropdown') && parentEl.removeClass('open');\n hide();\n };\n\n var destroy = $dropdown.destroy;\n $dropdown.destroy = function() {\n bodyEl.off('click', onBodyClick);\n destroy();\n };\n\n // Private functions\n\n function onBodyClick(evt) {\n if(evt.target === element[0]) return;\n return evt.target !== element[0] && $dropdown.hide();\n }\n\n return $dropdown;\n\n }\n\n return DropdownFactory;\n\n };\n\n })\n\n .directive('bsDropdown', function($window, $sce, $dropdown) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as an object\n attr.bsDropdown && scope.$watch(attr.bsDropdown, function(newValue, oldValue) {\n scope.content = newValue;\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!dropdown || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(dropdown),?/i);\n newValue === true ? dropdown.show() : dropdown.hide();\n });\n\n // Initialize dropdown\n var dropdown = $dropdown(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (dropdown) dropdown.destroy();\n options = null;\n dropdown = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateFormatter', [])\n\n .service('$dateFormatter', function($locale, dateFilter) {\n\n // The unused `lang` arguments are on purpose. The default implementation does not\n // use them and it always uses the locale loaded into the `$locale` service.\n // Custom implementations might use it, thus allowing different directives to\n // have different languages.\n\n this.getDefaultLocale = function() {\n return $locale.id;\n };\n\n // Format is either a data format name, e.g. \"shortTime\" or \"fullDate\", or a date format\n // Return either the corresponding date format or the given date format.\n this.getDatetimeFormat = function(format, lang) {\n return $locale.DATETIME_FORMATS[format] || format;\n };\n\n this.weekdaysShort = function(lang) {\n return $locale.DATETIME_FORMATS.SHORTDAY;\n };\n\n function splitTimeFormat(format) {\n return /(h+)([:\\.])?(m+)[ ]?(a?)/i.exec(format).slice(1);\n }\n\n // h:mm a => h\n this.hoursFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[0];\n };\n\n // h:mm a => mm\n this.minutesFormat = function(timeFormat) {\n return splitTimeFormat(timeFormat)[2];\n };\n\n // h:mm a => :\n this.timeSeparator = function(timeFormat) {\n return splitTimeFormat(timeFormat)[1];\n };\n\n // h:mm a => true, H.mm => false\n this.showAM = function(timeFormat) {\n return !!splitTimeFormat(timeFormat)[3];\n };\n\n this.formatDate = function(date, format, lang){\n return dateFilter(date, format);\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dateParser', [])\n\n.provider('$dateParser', function($localeProvider) {\n\n // define a custom ParseDate object to use instead of native Date\n // to avoid date values wrapping when setting date component values\n function ParseDate() {\n this.year = 1970;\n this.month = 0;\n this.day = 1;\n this.hours = 0;\n this.minutes = 0;\n this.seconds = 0;\n this.milliseconds = 0;\n }\n\n ParseDate.prototype.setMilliseconds = function(value) { this.milliseconds = value; };\n ParseDate.prototype.setSeconds = function(value) { this.seconds = value; };\n ParseDate.prototype.setMinutes = function(value) { this.minutes = value; };\n ParseDate.prototype.setHours = function(value) { this.hours = value; };\n ParseDate.prototype.getHours = function() { return this.hours; };\n ParseDate.prototype.setDate = function(value) { this.day = value; };\n ParseDate.prototype.setMonth = function(value) { this.month = value; };\n ParseDate.prototype.setFullYear = function(value) { this.year = value; };\n ParseDate.prototype.fromDate = function(value) {\n this.year = value.getFullYear();\n this.month = value.getMonth();\n this.day = value.getDate();\n this.hours = value.getHours();\n this.minutes = value.getMinutes();\n this.seconds = value.getSeconds();\n this.milliseconds = value.getMilliseconds();\n return this;\n };\n\n ParseDate.prototype.toDate = function() {\n return new Date(this.year, this.month, this.day, this.hours, this.minutes, this.seconds, this.milliseconds);\n };\n\n var proto = ParseDate.prototype;\n\n function noop() {\n }\n\n function isNumeric(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n function indexOfCaseInsensitive(array, value) {\n var len = array.length, str=value.toString().toLowerCase();\n for (var i=0; i 12 when midnight changeover, but then cannot generate\n * midnight datetime, so jump to 1AM, otherwise reset.\n * @param date (Date) the date to check\n * @return (Date) the corrected date\n *\n * __ copied from jquery ui datepicker __\n */\n $dateParser.daylightSavingAdjust = function(date) {\n if (!date) {\n return null;\n }\n date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);\n return date;\n };\n\n // Private functions\n\n function setMapForFormat(format) {\n var keys = Object.keys(setFnMap), i;\n var map = [], sortedMap = [];\n // Map to setFn\n var clonedFormat = format;\n for(i = 0; i < keys.length; i++) {\n if(format.split(keys[i]).length > 1) {\n var index = clonedFormat.search(keys[i]);\n format = format.split(keys[i]).join('');\n if(setFnMap[keys[i]]) {\n map[index] = setFnMap[keys[i]];\n }\n }\n }\n // Sort result map\n angular.forEach(map, function(v) {\n // conditional required since angular.forEach broke around v1.2.21\n // related pr: https://github.com/angular/angular.js/pull/8525\n if(v) sortedMap.push(v);\n });\n return sortedMap;\n }\n\n function escapeReservedSymbols(text) {\n return text.replace(/\\//g, '[\\\\/]').replace('/-/g', '[-]').replace(/\\./g, '[.]').replace(/\\\\s/g, '[\\\\s]');\n }\n\n function regExpForFormat(format) {\n var keys = Object.keys(regExpMap), i;\n\n var re = format;\n // Abstract replaces to avoid collisions\n for(i = 0; i < keys.length; i++) {\n re = re.split(keys[i]).join('${' + i + '}');\n }\n // Replace abstracted values\n for(i = 0; i < keys.length; i++) {\n re = re.split('${' + i + '}').join('(' + regExpMap[keys[i]] + ')');\n }\n format = escapeReservedSymbols(format);\n\n return new RegExp('^' + re + '$', ['i']);\n }\n\n $dateParser.init();\n return $dateParser;\n\n };\n\n return DateParserFactory;\n\n };\n\n});\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.debounce', [])\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L693\n.factory('debounce', function($timeout) {\n return function(func, wait, immediate) {\n var timeout = null;\n return function() {\n var context = this,\n args = arguments,\n callNow = immediate && !timeout;\n if(timeout) {\n $timeout.cancel(timeout);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(!immediate) {\n func.apply(context, args);\n }\n }, wait, false);\n if(callNow) {\n func.apply(context, args);\n }\n return timeout;\n };\n };\n})\n\n\n// @source jashkenas/underscore\n// @url https://github.com/jashkenas/underscore/blob/1.5.2/underscore.js#L661\n.factory('throttle', function($timeout) {\n return function(func, wait, options) {\n var timeout = null;\n options || (options = {});\n return function() {\n var context = this,\n args = arguments;\n if(!timeout) {\n if(options.leading !== false) {\n func.apply(context, args);\n }\n timeout = $timeout(function later() {\n timeout = null;\n if(options.trailing !== false) {\n func.apply(context, args);\n }\n }, wait, false);\n }\n };\n };\n});\n\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.dimensions', [])\n\n .factory('dimensions', function($document, $window) {\n\n var jqLite = angular.element;\n var fn = {};\n\n /**\n * Test the element nodeName\n * @param element\n * @param name\n */\n var nodeName = fn.nodeName = function(element, name) {\n return element.nodeName && element.nodeName.toLowerCase() === name.toLowerCase();\n };\n\n /**\n * Returns the element computed style\n * @param element\n * @param prop\n * @param extra\n */\n fn.css = function(element, prop, extra) {\n var value;\n if (element.currentStyle) { //IE\n value = element.currentStyle[prop];\n } else if (window.getComputedStyle) {\n value = window.getComputedStyle(element)[prop];\n } else {\n value = element.style[prop];\n }\n return extra === true ? parseFloat(value) || 0 : value;\n };\n\n /**\n * Provides read-only equivalent of jQuery's offset function:\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.offset = function(element) {\n var boxRect = element.getBoundingClientRect();\n var docElement = element.ownerDocument;\n return {\n width: boxRect.width || element.offsetWidth,\n height: boxRect.height || element.offsetHeight,\n top: boxRect.top + (window.pageYOffset || docElement.documentElement.scrollTop) - (docElement.documentElement.clientTop || 0),\n left: boxRect.left + (window.pageXOffset || docElement.documentElement.scrollLeft) - (docElement.documentElement.clientLeft || 0)\n };\n };\n\n /**\n * Provides read-only equivalent of jQuery's position function\n * @required-by bootstrap-tooltip, bootstrap-affix\n * @url http://api.jquery.com/offset/\n * @param element\n */\n fn.position = function(element) {\n\n var offsetParentRect = {top: 0, left: 0},\n offsetParentElement,\n offset;\n\n // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent\n if (fn.css(element, 'position') === 'fixed') {\n\n // We assume that getBoundingClientRect is available when computed position is fixed\n offset = element.getBoundingClientRect();\n\n } else {\n\n // Get *real* offsetParentElement\n offsetParentElement = offsetParent(element);\n\n // Get correct offsets\n offset = fn.offset(element);\n if (!nodeName(offsetParentElement, 'html')) {\n offsetParentRect = fn.offset(offsetParentElement);\n }\n\n // Add offsetParent borders\n offsetParentRect.top += fn.css(offsetParentElement, 'borderTopWidth', true);\n offsetParentRect.left += fn.css(offsetParentElement, 'borderLeftWidth', true);\n }\n\n // Subtract parent offsets and element margins\n return {\n width: element.offsetWidth,\n height: element.offsetHeight,\n top: offset.top - offsetParentRect.top - fn.css(element, 'marginTop', true),\n left: offset.left - offsetParentRect.left - fn.css(element, 'marginLeft', true)\n };\n\n };\n\n /**\n * Returns the closest, non-statically positioned offsetParent of a given element\n * @required-by fn.position\n * @param element\n */\n var offsetParent = function offsetParentElement(element) {\n var docElement = element.ownerDocument;\n var offsetParent = element.offsetParent || docElement;\n if(nodeName(offsetParent, '#document')) return docElement.documentElement;\n while(offsetParent && !nodeName(offsetParent, 'html') && fn.css(offsetParent, 'position') === 'static') {\n offsetParent = offsetParent.offsetParent;\n }\n return offsetParent || docElement.documentElement;\n };\n\n /**\n * Provides equivalent of jQuery's height function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/height/\n * @param element\n * @param outer\n */\n fn.height = function(element, outer) {\n var value = element.offsetHeight;\n if(outer) {\n value += fn.css(element, 'marginTop', true) + fn.css(element, 'marginBottom', true);\n } else {\n value -= fn.css(element, 'paddingTop', true) + fn.css(element, 'paddingBottom', true) + fn.css(element, 'borderTopWidth', true) + fn.css(element, 'borderBottomWidth', true);\n }\n return value;\n };\n\n /**\n * Provides equivalent of jQuery's width function\n * @required-by bootstrap-affix\n * @url http://api.jquery.com/width/\n * @param element\n * @param outer\n */\n fn.width = function(element, outer) {\n var value = element.offsetWidth;\n if(outer) {\n value += fn.css(element, 'marginLeft', true) + fn.css(element, 'marginRight', true);\n } else {\n value -= fn.css(element, 'paddingLeft', true) + fn.css(element, 'paddingRight', true) + fn.css(element, 'borderLeftWidth', true) + fn.css(element, 'borderRightWidth', true);\n }\n return value;\n };\n\n return fn;\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.helpers.parseOptions', [])\n\n .provider('$parseOptions', function() {\n\n var defaults = this.defaults = {\n regexp: /^\\s*(.*?)(?:\\s+as\\s+(.*?))?(?:\\s+group\\s+by\\s+(.*))?\\s+for\\s+(?:([\\$\\w][\\$\\w]*)|(?:\\(\\s*([\\$\\w][\\$\\w]*)\\s*,\\s*([\\$\\w][\\$\\w]*)\\s*\\)))\\s+in\\s+(.*?)(?:\\s+track\\s+by\\s+(.*?))?$/\n };\n\n this.$get = function($parse, $q) {\n\n function ParseOptionsFactory(attr, config) {\n\n var $parseOptions = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n $parseOptions.$values = [];\n\n // Private vars\n var match, displayFn, valueName, keyName, groupByFn, valueFn, valuesFn;\n\n $parseOptions.init = function() {\n $parseOptions.$match = match = attr.match(options.regexp);\n displayFn = $parse(match[2] || match[1]),\n valueName = match[4] || match[6],\n keyName = match[5],\n groupByFn = $parse(match[3] || ''),\n valueFn = $parse(match[2] ? match[1] : valueName),\n valuesFn = $parse(match[7]);\n };\n\n $parseOptions.valuesFn = function(scope, controller) {\n return $q.when(valuesFn(scope, controller))\n .then(function(values) {\n $parseOptions.$values = values ? parseValues(values, scope) : {};\n return $parseOptions.$values;\n });\n };\n\n $parseOptions.displayValue = function(modelValue) {\n var scope = {};\n scope[valueName] = modelValue;\n return displayFn(scope);\n };\n\n // Private functions\n\n function parseValues(values, scope) {\n return values.map(function(match, index) {\n var locals = {}, label, value;\n locals[valueName] = match;\n label = displayFn(scope, locals);\n value = valueFn(scope, locals);\n return {label: label, value: value, index: index};\n });\n }\n\n $parseOptions.init();\n return $parseOptions;\n\n }\n\n return ParseOptionsFactory;\n\n };\n\n });\n","'use strict';\n\n(angular.version.minor < 3 && angular.version.dot < 14) && angular.module('ng')\n\n.factory('$$rAF', function($window, $timeout) {\n\n var requestAnimationFrame = $window.requestAnimationFrame ||\n $window.webkitRequestAnimationFrame ||\n $window.mozRequestAnimationFrame;\n\n var cancelAnimationFrame = $window.cancelAnimationFrame ||\n $window.webkitCancelAnimationFrame ||\n $window.mozCancelAnimationFrame ||\n $window.webkitCancelRequestAnimationFrame;\n\n var rafSupported = !!requestAnimationFrame;\n var raf = rafSupported ?\n function(fn) {\n var id = requestAnimationFrame(fn);\n return function() {\n cancelAnimationFrame(id);\n };\n } :\n function(fn) {\n var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666\n return function() {\n $timeout.cancel(timer);\n };\n };\n\n raf.supported = rafSupported;\n\n return raf;\n\n});\n\n// .factory('$$animateReflow', function($$rAF, $document) {\n\n// var bodyEl = $document[0].body;\n\n// return function(fn) {\n// //the returned function acts as the cancellation function\n// return $$rAF(function() {\n// //the line below will force the browser to perform a repaint\n// //so that all the animated elements within the animation frame\n// //will be properly updated and drawn on screen. This is\n// //required to perform multi-class CSS based animations with\n// //Firefox. DO NOT REMOVE THIS LINE.\n// var a = bodyEl.offsetWidth + 1;\n// fn();\n// });\n// };\n\n// });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.modal', ['mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$modal', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n backdropAnimation: 'am-fade',\n prefixClass: 'modal',\n prefixEvent: 'modal',\n placement: 'top',\n template: 'modal/modal.tpl.html',\n contentTemplate: false,\n container: false,\n element: null,\n backdrop: true,\n keyboard: true,\n html: false,\n show: true\n };\n\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $timeout, $sce, dimensions) {\n\n var forEach = angular.forEach;\n var trim = String.prototype.trim;\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n var bodyElement = angular.element($window.document.body);\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n\n function ModalFactory(config) {\n\n var $modal = {};\n\n // Common vars\n var options = $modal.$options = angular.extend({}, defaults, config);\n $modal.$promise = fetchTemplate(options.template);\n var scope = $modal.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n if(!options.element && !options.container) {\n options.container = 'body';\n }\n\n // store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $modal.$id = options.id || options.element && options.element.attr('id') || '';\n\n // Support scope as string options\n forEach(['title', 'content'], function(key) {\n if(options[key]) scope[key] = $sce.trustAsHtml(options[key]);\n });\n\n // Provide scope helpers\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $modal.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $modal.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $modal.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $modal.$isShown = scope.$isShown = false;\n\n // Support contentTemplate option\n if(options.contentTemplate) {\n $modal.$promise = $modal.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]).removeAttr('ng-bind').html(contentTemplate);\n // Drop the default footer as you probably don't want it if you use a custom contentTemplate\n if(!config.template) contentEl.next().remove();\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize modal\n var modalLinker, modalElement;\n var backdropElement = angular.element('
    ');\n $modal.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n modalLinker = $compile(template);\n $modal.init();\n });\n\n $modal.init = function() {\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n $modal.show();\n });\n }\n\n };\n\n $modal.destroy = function() {\n\n // Remove element\n if(modalElement) {\n modalElement.remove();\n modalElement = null;\n }\n if(backdropElement) {\n backdropElement.remove();\n backdropElement = null;\n }\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $modal.show = function() {\n if($modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.show.before', $modal).defaultPrevented) {\n return;\n }\n var parent, after;\n if(angular.isElement(options.container)) {\n parent = options.container;\n after = options.container[0].lastChild ? angular.element(options.container[0].lastChild) : null;\n } else {\n if (options.container) {\n parent = findElement(options.container);\n after = parent[0].lastChild ? angular.element(parent[0].lastChild) : null;\n } else {\n parent = null;\n after = options.element;\n }\n }\n\n // Fetch a cloned element linked from template\n modalElement = $modal.$element = modalLinker(scope, function(clonedElement, scope) {});\n\n // Set the initial positioning.\n modalElement.css({display: 'block'}).addClass(options.placement);\n\n // Options: animation\n if(options.animation) {\n if(options.backdrop) {\n backdropElement.addClass(options.backdropAnimation);\n }\n modalElement.addClass(options.animation);\n }\n\n if(options.backdrop) {\n $animate.enter(backdropElement, bodyElement, null);\n }\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(modalElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $modal.$isShown = scope.$isShown = true;\n safeDigest(scope);\n // Focus once the enter-animation has started\n // Weird PhantomJS bug hack\n var el = modalElement[0];\n requestAnimationFrame(function() {\n el.focus();\n });\n\n bodyElement.addClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.addClass(options.prefixClass + '-with-' + options.animation);\n }\n\n // Bind events\n if(options.backdrop) {\n modalElement.on('click', hideOnBackdropClick);\n backdropElement.on('click', hideOnBackdropClick);\n backdropElement.on('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.on('keyup', $modal.$onKeyUp);\n }\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $modal);\n }\n\n $modal.hide = function() {\n if(!$modal.$isShown) return;\n\n if(scope.$emit(options.prefixEvent + '.hide.before', $modal).defaultPrevented) {\n return;\n }\n var promise = $animate.leave(modalElement, leaveAnimateCallback);\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n if(options.backdrop) {\n $animate.leave(backdropElement);\n }\n $modal.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.backdrop) {\n modalElement.off('click', hideOnBackdropClick);\n backdropElement.off('click', hideOnBackdropClick);\n backdropElement.off('wheel', preventEventDefault);\n }\n if(options.keyboard) {\n modalElement.off('keyup', $modal.$onKeyUp);\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $modal);\n bodyElement.removeClass(options.prefixClass + '-open');\n if(options.animation) {\n bodyElement.removeClass(options.prefixClass + '-with-' + options.animation);\n }\n }\n\n $modal.toggle = function() {\n\n $modal.$isShown ? $modal.hide() : $modal.show();\n\n };\n\n $modal.focus = function() {\n modalElement[0].focus();\n };\n\n // Protected methods\n\n $modal.$onKeyUp = function(evt) {\n\n if (evt.which === 27 && $modal.$isShown) {\n $modal.hide();\n evt.stopPropagation();\n }\n\n };\n\n // Private methods\n\n function hideOnBackdropClick(evt) {\n if(evt.target !== evt.currentTarget) return;\n options.backdrop === 'static' ? $modal.focus() : $modal.hide();\n }\n\n function preventEventDefault(evt) {\n evt.preventDefault();\n }\n\n return $modal;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\n }\n\n return ModalFactory;\n\n };\n\n })\n\n .directive('bsModal', function($window, $sce, $modal) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope, element: element, show: false};\n angular.forEach(['template', 'contentTemplate', 'placement', 'backdrop', 'keyboard', 'html', 'container', 'animation', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n });\n });\n\n // Support scope as an object\n attr.bsModal && scope.$watch(attr.bsModal, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n }, true);\n\n // Initialize modal\n var modal = $modal(options);\n\n // Trigger\n element.on(attr.trigger || 'click', modal.toggle);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (modal) modal.destroy();\n options = null;\n modal = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.navbar', [])\n\n .provider('$navbar', function() {\n\n var defaults = this.defaults = {\n activeClass: 'active',\n routeAttr: 'data-match-route',\n strict: false\n };\n\n this.$get = function() {\n return {defaults: defaults};\n };\n\n })\n\n .directive('bsNavbar', function($window, $location, $navbar) {\n\n var defaults = $navbar.defaults;\n\n return {\n restrict: 'A',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = angular.copy(defaults);\n angular.forEach(Object.keys(defaults), function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Watch for the $location\n scope.$watch(function() {\n\n return $location.path();\n\n }, function(newValue, oldValue) {\n\n var liElements = element[0].querySelectorAll('li[' + options.routeAttr + ']');\n\n angular.forEach(liElements, function(li) {\n\n var liElement = angular.element(li);\n var pattern = liElement.attr(options.routeAttr).replace('/', '\\\\/');\n if(options.strict) {\n pattern = '^' + pattern + '$';\n }\n var regexp = new RegExp(pattern, ['i']);\n\n if(regexp.test(newValue)) {\n liElement.addClass(options.activeClass);\n } else {\n liElement.removeClass(options.activeClass);\n }\n\n });\n\n });\n\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.popover', ['mgcrea.ngStrap.tooltip'])\n\n .provider('$popover', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n container: false,\n target: false,\n placement: 'right',\n template: 'popover/popover.tpl.html',\n contentTemplate: false,\n trigger: 'click',\n keyboard: true,\n html: false,\n title: '',\n content: '',\n delay: 0,\n autoClose: false\n };\n\n this.$get = function($tooltip) {\n\n function PopoverFactory(element, config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n var $popover = $tooltip(element, options);\n\n // Support scope as string options [/*title, */content]\n if(options.content) {\n $popover.$scope.content = options.content;\n }\n\n return $popover;\n\n }\n\n return PopoverFactory;\n\n };\n\n })\n\n .directive('bsPopover', function($window, $sce, $popover) {\n\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'customClass', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Support scope as data-attrs\n angular.forEach(['title', 'content'], function(key) {\n attr[key] && attr.$observe(key, function(newValue, oldValue) {\n scope[key] = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n });\n });\n\n // Support scope as an object\n attr.bsPopover && scope.$watch(attr.bsPopover, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.content = newValue;\n }\n angular.isDefined(oldValue) && requestAnimationFrame(function() {\n popover && popover.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!popover || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(popover),?/i);\n newValue === true ? popover.show() : popover.hide();\n });\n\n // Initialize popover\n var popover = $popover(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (popover) popover.destroy();\n options = null;\n popover = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.select', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$select', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'select',\n prefixEvent: '$select',\n placement: 'bottom-left',\n template: 'select/select.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n multiple: false,\n allNoneButtons: false,\n sort: true,\n caretHtml: ' ',\n placeholder: 'Choose among the following...',\n allText: 'All',\n noneText: 'None',\n maxLength: 3,\n maxLengthHtml: 'selected',\n iconCheckmark: 'glyphicon glyphicon-ok'\n };\n\n this.$get = function($window, $document, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n\n function SelectFactory(element, controller, config) {\n\n var $select = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $select = $tooltip(element, options);\n var scope = $select.$scope;\n\n scope.$matches = [];\n scope.$activeIndex = 0;\n scope.$isMultiple = options.multiple;\n scope.$showAllNoneButtons = options.allNoneButtons && options.multiple;\n scope.$iconCheckmark = options.iconCheckmark;\n scope.$allText = options.allText;\n scope.$noneText = options.noneText;\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $select.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $select.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $select.$isVisible();\n };\n\n scope.$isActive = function(index) {\n return $select.$isActive(index);\n };\n\n scope.$selectAll = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (!scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n scope.$selectNone = function () {\n for (var i = 0; i < scope.$matches.length; i++) {\n if (scope.$isActive(i)) {\n scope.$select(i);\n }\n }\n };\n\n // Public methods\n\n $select.update = function(matches) {\n scope.$matches = matches;\n $select.$updateActiveIndex();\n };\n\n $select.activate = function(index) {\n if(options.multiple) {\n scope.$activeIndex.sort();\n $select.$isActive(index) ? scope.$activeIndex.splice(scope.$activeIndex.indexOf(index), 1) : scope.$activeIndex.push(index);\n if(options.sort) scope.$activeIndex.sort();\n } else {\n scope.$activeIndex = index;\n }\n return scope.$activeIndex;\n };\n\n $select.select = function(index) {\n var value = scope.$matches[index].value;\n scope.$apply(function() {\n $select.activate(index);\n if(options.multiple) {\n controller.$setViewValue(scope.$activeIndex.map(function(index) {\n return scope.$matches[index].value;\n }));\n } else {\n controller.$setViewValue(value);\n // Hide if single select\n $select.hide();\n }\n });\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $select);\n };\n\n // Protected methods\n\n $select.$updateActiveIndex = function() {\n if(controller.$modelValue && scope.$matches.length) {\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n scope.$activeIndex = controller.$modelValue.map(function(value) {\n return $select.$getIndex(value);\n });\n } else {\n scope.$activeIndex = $select.$getIndex(controller.$modelValue);\n }\n } else if(scope.$activeIndex >= scope.$matches.length) {\n scope.$activeIndex = options.multiple ? [] : 0;\n }\n };\n\n $select.$isVisible = function() {\n if(!options.minLength || !controller) {\n return scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && controller.$viewValue.length >= options.minLength;\n };\n\n $select.$isActive = function(index) {\n if(options.multiple) {\n return scope.$activeIndex.indexOf(index) !== -1;\n } else {\n return scope.$activeIndex === index;\n }\n };\n\n $select.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $select.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n targetEl.triggerHandler('click');\n }\n };\n\n $select.$onKeyDown = function(evt) {\n if (!/(9|13|38|40)/.test(evt.keyCode)) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Select with enter\n if(!options.multiple && (evt.keyCode === 13 || evt.keyCode === 9)) {\n return $select.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var _show = $select.show;\n $select.show = function() {\n _show();\n if(options.multiple) {\n $select.$element.addClass('select-multiple');\n }\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $select.$element.on(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $select.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $select.hide;\n $select.hide = function() {\n $select.$element.off(isTouch ? 'touchstart' : 'mousedown', $select.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $select.$onKeyDown);\n }\n _hide(true);\n };\n\n return $select;\n\n }\n\n SelectFactory.defaults = defaults;\n return SelectFactory;\n\n };\n\n })\n\n .directive('bsSelect', function($window, $parse, $q, $select, $parseOptions) {\n\n var defaults = $select.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, placeholder: defaults.placeholder};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'placeholder', 'multiple', 'allNoneButtons', 'maxLength', 'maxLengthHtml', 'allText', 'noneText', 'iconCheckmark', 'autoClose', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Add support for select markup\n if(element[0].nodeName.toLowerCase() === 'select') {\n var inputEl = element;\n inputEl.css('display', 'none');\n element = angular.element('');\n inputEl.after(element);\n }\n\n // Build proper ngOptions\n var parsedOptions = $parseOptions(attr.ngOptions);\n\n // Initialize select\n var select = $select(element, controller, options);\n\n // Watch ngOptions values before filtering for changes\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').trim();\n scope.$watch(watchedOptions, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n select.update(values);\n controller.$render();\n });\n }, true);\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue);\n select.$updateActiveIndex();\n controller.$render();\n }, true);\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n var selected, index;\n if(options.multiple && angular.isArray(controller.$modelValue)) {\n selected = controller.$modelValue.map(function(value) {\n index = select.$getIndex(value);\n return angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }).filter(angular.isDefined);\n if(selected.length > (options.maxLength || defaults.maxLength)) {\n selected = selected.length + ' ' + (options.maxLengthHtml || defaults.maxLengthHtml);\n } else {\n selected = selected.join(', ');\n }\n } else {\n index = select.$getIndex(controller.$modelValue);\n selected = angular.isDefined(index) ? select.$scope.$matches[index].label : false;\n }\n element.html((selected ? selected : options.placeholder) + defaults.caretHtml);\n };\n\n if(options.multiple){\n controller.$isEmpty = function(value){\n return !value || value.length === 0;\n };\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (select) select.destroy();\n options = null;\n select = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tab', [])\n\n .provider('$tab', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n template: 'tab/tab.tpl.html',\n navClass: 'nav-tabs',\n activeClass: 'active'\n };\n\n var controller = this.controller = function($scope, $element, $attrs) {\n var self = this;\n\n // Attributes options\n self.$options = angular.copy(defaults);\n angular.forEach(['animation', 'navClass', 'activeClass'], function(key) {\n if(angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];\n });\n\n // Publish options on scope\n $scope.$navClass = self.$options.navClass;\n $scope.$activeClass = self.$options.activeClass;\n\n self.$panes = $scope.$panes = [];\n\n // DEPRECATED: $viewChangeListeners, please use $activePaneChangeListeners\n // Because we deprecated ngModel usage, we rename viewChangeListeners to \n // activePaneChangeListeners to make more sense.\n self.$activePaneChangeListeners = self.$viewChangeListeners = [];\n\n self.$push = function(pane) {\n self.$panes.push(pane);\n };\n\n self.$remove = function(pane) {\n var index = self.$panes.indexOf(pane);\n var activeIndex = self.$panes.$active;\n\n // remove pane from $panes array\n self.$panes.splice(index, 1);\n\n if (index < activeIndex) {\n // we removed a pane before the active pane, so we need to \n // decrement the active pane index\n activeIndex--;\n }\n else if (index === activeIndex && activeIndex === self.$panes.length) {\n // we remove the active pane and it was the one at the end,\n // so select the previous one\n activeIndex--;\n }\n self.$setActive(activeIndex);\n };\n\n self.$panes.$active = 0;\n self.$setActive = $scope.$setActive = function(value) {\n self.$panes.$active = value;\n self.$activePaneChangeListeners.forEach(function(fn) {\n fn();\n });\n };\n\n };\n\n this.$get = function() {\n var $tab = {};\n $tab.defaults = defaults;\n $tab.controller = controller;\n return $tab;\n };\n\n })\n\n .directive('bsTabs', function($window, $animate, $tab, $parse) {\n\n var defaults = $tab.defaults;\n\n return {\n require: ['?ngModel', 'bsTabs'],\n transclude: true,\n scope: true,\n controller: ['$scope', '$element', '$attrs', $tab.controller],\n templateUrl: function(element, attr) {\n return attr.template || defaults.template;\n },\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // DEPRECATED: ngModel, please use bsActivePane\n // 'ngModel' is deprecated bacause if interferes with form validation\n // and status, so avoid using it here.\n if(ngModelCtrl) {\n console.warn('Usage of ngModel is deprecated, please use bsActivePane instead!');\n\n // Update the modelValue following\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n ngModelCtrl.$setViewValue(bsTabsCtrl.$panes.$active);\n });\n\n // modelValue -> $formatters -> viewValue\n ngModelCtrl.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n bsTabsCtrl.$setActive(modelValue * 1);\n return modelValue;\n });\n\n }\n\n if (attrs.bsActivePane) {\n // adapted from angularjs ngModelController bindings\n // https://github.com/angular/angular.js/blob/v1.3.1/src%2Fng%2Fdirective%2Finput.js#L1730\n var parsedBsActivePane = $parse(attrs.bsActivePane);\n\n // Update bsActivePane value with change\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n parsedBsActivePane.assign(scope, bsTabsCtrl.$panes.$active);\n });\n\n // watch bsActivePane for value changes\n scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {\n bsTabsCtrl.$setActive(newValue * 1);\n }, true);\n }\n }\n };\n\n })\n\n .directive('bsPane', function($window, $animate, $sce) {\n\n return {\n require: ['^?ngModel', '^bsTabs'],\n scope: true,\n link: function postLink(scope, element, attrs, controllers) {\n\n var ngModelCtrl = controllers[0];\n var bsTabsCtrl = controllers[1];\n\n // Add base class\n element.addClass('tab-pane');\n\n // Observe title attribute for change\n attrs.$observe('title', function(newValue, oldValue) {\n scope.title = $sce.trustAsHtml(newValue);\n });\n\n // Add animation class\n if(bsTabsCtrl.$options.animation) {\n element.addClass(bsTabsCtrl.$options.animation);\n }\n\n // Push pane to parent bsTabs controller\n bsTabsCtrl.$push(scope);\n\n // remove pane from tab controller when pane is destroyed\n scope.$on('$destroy', function() {\n bsTabsCtrl.$remove(scope);\n });\n\n function render() {\n var index = bsTabsCtrl.$panes.indexOf(scope);\n var active = bsTabsCtrl.$panes.$active;\n $animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);\n }\n\n bsTabsCtrl.$activePaneChangeListeners.push(function() {\n render();\n });\n render();\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.scrollspy', ['mgcrea.ngStrap.helpers.debounce', 'mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$scrollspy', function() {\n\n // Pool of registered spies\n var spies = this.$$spies = {};\n\n var defaults = this.defaults = {\n debounce: 150,\n throttle: 100,\n offset: 100\n };\n\n this.$get = function($window, $document, $rootScope, dimensions, debounce, throttle) {\n\n var windowEl = angular.element($window);\n var docEl = angular.element($document.prop('documentElement'));\n var bodyEl = angular.element($window.document.body);\n\n // Helper functions\n\n function nodeName(element, name) {\n return element[0].nodeName && element[0].nodeName.toLowerCase() === name.toLowerCase();\n }\n\n function ScrollSpyFactory(config) {\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n if(!options.element) options.element = bodyEl;\n var isWindowSpy = nodeName(options.element, 'body');\n var scrollEl = isWindowSpy ? windowEl : options.element;\n var scrollId = isWindowSpy ? 'window' : options.id;\n\n // Use existing spy\n if(spies[scrollId]) {\n spies[scrollId].$$count++;\n return spies[scrollId];\n }\n\n var $scrollspy = {};\n\n // Private vars\n var unbindViewContentLoaded, unbindIncludeContentLoaded;\n var trackedElements = $scrollspy.$trackedElements = [];\n var sortedElements = [];\n var activeTarget;\n var debouncedCheckPosition;\n var throttledCheckPosition;\n var debouncedCheckOffsets;\n var viewportHeight;\n var scrollTop;\n\n $scrollspy.init = function() {\n\n // Setup internal ref counter\n this.$$count = 1;\n\n // Bind events\n debouncedCheckPosition = debounce(this.checkPosition, options.debounce);\n throttledCheckPosition = throttle(this.checkPosition, options.throttle);\n scrollEl.on('click', this.checkPositionWithEventLoop);\n windowEl.on('resize', debouncedCheckPosition);\n scrollEl.on('scroll', throttledCheckPosition);\n\n debouncedCheckOffsets = debounce(this.checkOffsets, options.debounce);\n unbindViewContentLoaded = $rootScope.$on('$viewContentLoaded', debouncedCheckOffsets);\n unbindIncludeContentLoaded = $rootScope.$on('$includeContentLoaded', debouncedCheckOffsets);\n debouncedCheckOffsets();\n\n // Register spy for reuse\n if(scrollId) {\n spies[scrollId] = $scrollspy;\n }\n\n };\n\n $scrollspy.destroy = function() {\n\n // Check internal ref counter\n this.$$count--;\n if(this.$$count > 0) {\n return;\n }\n\n // Unbind events\n scrollEl.off('click', this.checkPositionWithEventLoop);\n windowEl.off('resize', debouncedCheckPosition);\n scrollEl.off('scroll', throttledCheckPosition);\n unbindViewContentLoaded();\n unbindIncludeContentLoaded();\n if (scrollId) {\n delete spies[scrollId];\n }\n };\n\n $scrollspy.checkPosition = function() {\n\n // Not ready yet\n if(!sortedElements.length) return;\n\n // Calculate the scroll position\n scrollTop = (isWindowSpy ? $window.pageYOffset : scrollEl.prop('scrollTop')) || 0;\n\n // Calculate the viewport height for use by the components\n viewportHeight = Math.max($window.innerHeight, docEl.prop('clientHeight'));\n\n // Activate first element if scroll is smaller\n if(scrollTop < sortedElements[0].offsetTop && activeTarget !== sortedElements[0].target) {\n return $scrollspy.$activateElement(sortedElements[0]);\n }\n\n // Activate proper element\n for (var i = sortedElements.length; i--;) {\n if(angular.isUndefined(sortedElements[i].offsetTop) || sortedElements[i].offsetTop === null) continue;\n if(activeTarget === sortedElements[i].target) continue;\n if(scrollTop < sortedElements[i].offsetTop) continue;\n if(sortedElements[i + 1] && scrollTop > sortedElements[i + 1].offsetTop) continue;\n return $scrollspy.$activateElement(sortedElements[i]);\n }\n\n };\n\n $scrollspy.checkPositionWithEventLoop = function() {\n // IE 9 throws an error if we use 'this' instead of '$scrollspy'\n // in this setTimeout call\n setTimeout($scrollspy.checkPosition, 1);\n };\n\n // Protected methods\n\n $scrollspy.$activateElement = function(element) {\n if(activeTarget) {\n var activeElement = $scrollspy.$getTrackedElement(activeTarget);\n if(activeElement) {\n activeElement.source.removeClass('active');\n if(nodeName(activeElement.source, 'li') && nodeName(activeElement.source.parent().parent(), 'li')) {\n activeElement.source.parent().parent().removeClass('active');\n }\n }\n }\n activeTarget = element.target;\n element.source.addClass('active');\n if(nodeName(element.source, 'li') && nodeName(element.source.parent().parent(), 'li')) {\n element.source.parent().parent().addClass('active');\n }\n };\n\n $scrollspy.$getTrackedElement = function(target) {\n return trackedElements.filter(function(obj) {\n return obj.target === target;\n })[0];\n };\n\n // Track offsets behavior\n\n $scrollspy.checkOffsets = function() {\n\n angular.forEach(trackedElements, function(trackedElement) {\n var targetElement = document.querySelector(trackedElement.target);\n trackedElement.offsetTop = targetElement ? dimensions.offset(targetElement).top : null;\n if(options.offset && trackedElement.offsetTop !== null) trackedElement.offsetTop -= options.offset * 1;\n });\n\n sortedElements = trackedElements\n .filter(function(el) {\n return el.offsetTop !== null;\n })\n .sort(function(a, b) {\n return a.offsetTop - b.offsetTop;\n });\n\n debouncedCheckPosition();\n\n };\n\n $scrollspy.trackElement = function(target, source) {\n trackedElements.push({target: target, source: source});\n };\n\n $scrollspy.untrackElement = function(target, source) {\n var toDelete;\n for (var i = trackedElements.length; i--;) {\n if(trackedElements[i].target === target && trackedElements[i].source === source) {\n toDelete = i;\n break;\n }\n }\n trackedElements = trackedElements.splice(toDelete, 1);\n };\n\n $scrollspy.activate = function(i) {\n trackedElements[i].addClass('active');\n };\n\n // Initialize plugin\n\n $scrollspy.init();\n return $scrollspy;\n\n }\n\n return ScrollSpyFactory;\n\n };\n\n })\n\n .directive('bsScrollspy', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'EAC',\n link: function postLink(scope, element, attr) {\n\n var options = {scope: scope};\n angular.forEach(['offset', 'target'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n var scrollspy = $scrollspy(options);\n scrollspy.trackElement(options.target, element);\n\n scope.$on('$destroy', function() {\n if (scrollspy) {\n scrollspy.untrackElement(options.target, element);\n scrollspy.destroy();\n }\n options = null;\n scrollspy = null;\n });\n\n }\n };\n\n })\n\n\n .directive('bsScrollspyList', function($rootScope, debounce, dimensions, $scrollspy) {\n\n return {\n restrict: 'A',\n compile: function postLink(element, attr) {\n var children = element[0].querySelectorAll('li > a[href]');\n angular.forEach(children, function(child) {\n var childEl = angular.element(child);\n childEl.parent().attr('bs-scrollspy', '').attr('data-target', childEl.attr('href'));\n });\n }\n\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.timepicker', [\n 'mgcrea.ngStrap.helpers.dateParser',\n 'mgcrea.ngStrap.helpers.dateFormatter',\n 'mgcrea.ngStrap.tooltip'])\n\n .provider('$timepicker', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'timepicker',\n placement: 'bottom-left',\n template: 'timepicker/timepicker.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n // lang: $locale.id,\n useNative: true,\n timeType: 'date',\n timeFormat: 'shortTime',\n modelTimeFormat: null,\n autoclose: false,\n minTime: -Infinity,\n maxTime: +Infinity,\n length: 5,\n hourStep: 1,\n minuteStep: 5,\n iconUp: 'glyphicon glyphicon-chevron-up',\n iconDown: 'glyphicon glyphicon-chevron-down',\n arrowBehavior: 'pager'\n };\n\n this.$get = function($window, $document, $rootScope, $sce, $dateFormatter, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var isTouch = ('createTouch' in $window.document) && isNative;\n if(!defaults.lang) defaults.lang = $dateFormatter.getDefaultLocale();\n\n function timepickerFactory(element, controller, config) {\n\n var $timepicker = $tooltip(element, angular.extend({}, defaults, config));\n var parentScope = config.scope;\n var options = $timepicker.$options;\n var scope = $timepicker.$scope;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // View vars\n\n var selectedIndex = 0;\n var startDate = controller.$dateValue || new Date();\n var viewDate = {hour: startDate.getHours(), meridian: startDate.getHours() < 12, minute: startDate.getMinutes(), second: startDate.getSeconds(), millisecond: startDate.getMilliseconds()};\n\n var format = $dateFormatter.getDatetimeFormat(options.timeFormat, lang);\n\n var hoursFormat = $dateFormatter.hoursFormat(format),\n timeSeparator = $dateFormatter.timeSeparator(format),\n minutesFormat = $dateFormatter.minutesFormat(format),\n showAM = $dateFormatter.showAM(format);\n\n scope.$iconUp = options.iconUp;\n scope.$iconDown = options.iconDown;\n\n // Scope methods\n\n scope.$select = function(date, index) {\n $timepicker.select(date, index);\n };\n scope.$moveIndex = function(value, index) {\n $timepicker.$moveIndex(value, index);\n };\n scope.$switchMeridian = function(date) {\n $timepicker.switchMeridian(date);\n };\n\n // Public methods\n\n $timepicker.update = function(date) {\n // console.warn('$timepicker.update() newValue=%o', date);\n if(angular.isDate(date) && !isNaN(date.getTime())) {\n $timepicker.$date = date;\n angular.extend(viewDate, {hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(), millisecond: date.getMilliseconds()});\n $timepicker.$build();\n } else if(!$timepicker.$isBuilt) {\n $timepicker.$build();\n }\n };\n\n $timepicker.select = function(date, index, keep) {\n // console.warn('$timepicker.select', date, scope.$mode);\n if(!controller.$dateValue || isNaN(controller.$dateValue.getTime())) controller.$dateValue = new Date(1970, 0, 1);\n if(!angular.isDate(date)) date = new Date(date);\n if(index === 0) controller.$dateValue.setHours(date.getHours());\n else if(index === 1) controller.$dateValue.setMinutes(date.getMinutes());\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n if(options.autoclose && !keep) {\n $timeout(function() { $timepicker.hide(true); });\n }\n };\n\n $timepicker.switchMeridian = function(date) {\n if (!controller.$dateValue || isNaN(controller.$dateValue.getTime())) {\n return;\n }\n var hours = (date || controller.$dateValue).getHours();\n controller.$dateValue.setHours(hours < 12 ? hours + 12 : hours - 12);\n controller.$setViewValue(angular.copy(controller.$dateValue));\n controller.$render();\n };\n\n // Protected methods\n\n $timepicker.$build = function() {\n // console.warn('$timepicker.$build() viewDate=%o', viewDate);\n var i, midIndex = scope.midIndex = parseInt(options.length / 2, 10);\n var hours = [], hour;\n for(i = 0; i < options.length; i++) {\n hour = new Date(1970, 0, 1, viewDate.hour - (midIndex - i) * options.hourStep);\n hours.push({date: hour, label: formatDate(hour, hoursFormat), selected: $timepicker.$date && $timepicker.$isSelected(hour, 0), disabled: $timepicker.$isDisabled(hour, 0)});\n }\n var minutes = [], minute;\n for(i = 0; i < options.length; i++) {\n minute = new Date(1970, 0, 1, 0, viewDate.minute - (midIndex - i) * options.minuteStep);\n minutes.push({date: minute, label: formatDate(minute, minutesFormat), selected: $timepicker.$date && $timepicker.$isSelected(minute, 1), disabled: $timepicker.$isDisabled(minute, 1)});\n }\n\n var rows = [];\n for(i = 0; i < options.length; i++) {\n rows.push([hours[i], minutes[i]]);\n }\n scope.rows = rows;\n scope.showAM = showAM;\n scope.isAM = ($timepicker.$date || hours[midIndex].date).getHours() < 12;\n scope.timeSeparator = timeSeparator;\n $timepicker.$isBuilt = true;\n };\n\n $timepicker.$isSelected = function(date, index) {\n if(!$timepicker.$date) return false;\n else if(index === 0) {\n return date.getHours() === $timepicker.$date.getHours();\n } else if(index === 1) {\n return date.getMinutes() === $timepicker.$date.getMinutes();\n }\n };\n\n $timepicker.$isDisabled = function(date, index) {\n var selectedTime;\n if(index === 0) {\n selectedTime = date.getTime() + viewDate.minute * 6e4;\n } else if(index === 1) {\n selectedTime = date.getTime() + viewDate.hour * 36e5;\n }\n return selectedTime < options.minTime * 1 || selectedTime > options.maxTime * 1;\n };\n\n scope.$arrowAction = function (value, index) {\n if (options.arrowBehavior === 'picker') {\n $timepicker.$setTimeByStep(value,index);\n } else {\n $timepicker.$moveIndex(value,index);\n }\n };\n\n $timepicker.$setTimeByStep = function(value, index) {\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n if (index === 0) {\n newDate.setHours(hours - (parseInt(options.hourStep, 10) * value));\n }\n else {\n newDate.setMinutes(minutes - (parseInt(options.minuteStep, 10) * value));\n }\n $timepicker.select(newDate, index, true);\n };\n\n $timepicker.$moveIndex = function(value, index) {\n var targetDate;\n if(index === 0) {\n targetDate = new Date(1970, 0, 1, viewDate.hour + (value * options.length), viewDate.minute);\n angular.extend(viewDate, {hour: targetDate.getHours()});\n } else if(index === 1) {\n targetDate = new Date(1970, 0, 1, viewDate.hour, viewDate.minute + (value * options.length * options.minuteStep));\n angular.extend(viewDate, {minute: targetDate.getMinutes()});\n }\n $timepicker.$build();\n };\n\n $timepicker.$onMouseDown = function(evt) {\n // Prevent blur on mousedown on .dropdown-menu\n if(evt.target.nodeName.toLowerCase() !== 'input') evt.preventDefault();\n evt.stopPropagation();\n // Emulate click for mobile devices\n if(isTouch) {\n var targetEl = angular.element(evt.target);\n if(targetEl[0].nodeName.toLowerCase() !== 'button') {\n targetEl = targetEl.parent();\n }\n targetEl.triggerHandler('click');\n }\n };\n\n $timepicker.$onKeyDown = function(evt) {\n if (!/(38|37|39|40|13)/.test(evt.keyCode) || evt.shiftKey || evt.altKey) return;\n evt.preventDefault();\n evt.stopPropagation();\n\n // Close on enter\n if(evt.keyCode === 13) return $timepicker.hide(true);\n\n // Navigate with keyboard\n var newDate = new Date($timepicker.$date);\n var hours = newDate.getHours(), hoursLength = formatDate(newDate, hoursFormat).length;\n var minutes = newDate.getMinutes(), minutesLength = formatDate(newDate, minutesFormat).length;\n var lateralMove = /(37|39)/.test(evt.keyCode);\n var count = 2 + showAM * 1;\n\n // Navigate indexes (left, right)\n if (lateralMove) {\n if(evt.keyCode === 37) selectedIndex = selectedIndex < 1 ? count - 1 : selectedIndex - 1;\n else if(evt.keyCode === 39) selectedIndex = selectedIndex < count - 1 ? selectedIndex + 1 : 0;\n }\n\n // Update values (up, down)\n var selectRange = [0, hoursLength];\n if(selectedIndex === 0) {\n if(evt.keyCode === 38) newDate.setHours(hours - parseInt(options.hourStep, 10));\n else if(evt.keyCode === 40) newDate.setHours(hours + parseInt(options.hourStep, 10));\n // re-calculate hours length because we have changed hours value\n hoursLength = formatDate(newDate, hoursFormat).length;\n selectRange = [0, hoursLength];\n } else if(selectedIndex === 1) {\n if(evt.keyCode === 38) newDate.setMinutes(minutes - parseInt(options.minuteStep, 10));\n else if(evt.keyCode === 40) newDate.setMinutes(minutes + parseInt(options.minuteStep, 10));\n // re-calculate minutes length because we have changes minutes value\n minutesLength = formatDate(newDate, minutesFormat).length;\n selectRange = [hoursLength + 1, hoursLength + 1 + minutesLength];\n } else if(selectedIndex === 2) {\n if(!lateralMove) $timepicker.switchMeridian();\n selectRange = [hoursLength + 1 + minutesLength + 1, hoursLength + 1 + minutesLength + 3];\n }\n $timepicker.select(newDate, selectedIndex, true);\n createSelection(selectRange[0], selectRange[1]);\n parentScope.$digest();\n };\n\n // Private\n\n function createSelection(start, end) {\n if(element[0].createTextRange) {\n var selRange = element[0].createTextRange();\n selRange.collapse(true);\n selRange.moveStart('character', start);\n selRange.moveEnd('character', end);\n selRange.select();\n } else if(element[0].setSelectionRange) {\n element[0].setSelectionRange(start, end);\n } else if(angular.isUndefined(element[0].selectionStart)) {\n element[0].selectionStart = start;\n element[0].selectionEnd = end;\n }\n }\n\n function focusElement() {\n element[0].focus();\n }\n\n // Overrides\n\n var _init = $timepicker.init;\n $timepicker.init = function() {\n if(isNative && options.useNative) {\n element.prop('type', 'time');\n element.css('-webkit-appearance', 'textfield');\n return;\n } else if(isTouch) {\n element.prop('type', 'text');\n element.attr('readonly', 'true');\n element.on('click', focusElement);\n }\n _init();\n };\n\n var _destroy = $timepicker.destroy;\n $timepicker.destroy = function() {\n if(isNative && options.useNative) {\n element.off('click', focusElement);\n }\n _destroy();\n };\n\n var _show = $timepicker.show;\n $timepicker.show = function() {\n _show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $timepicker.$element.on(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $timepicker.$onKeyDown);\n }\n }, 0, false);\n };\n\n var _hide = $timepicker.hide;\n $timepicker.hide = function(blur) {\n if(!$timepicker.$isShown) return;\n $timepicker.$element.off(isTouch ? 'touchstart' : 'mousedown', $timepicker.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $timepicker.$onKeyDown);\n }\n _hide(blur);\n };\n\n return $timepicker;\n\n }\n\n timepickerFactory.defaults = defaults;\n return timepickerFactory;\n\n };\n\n })\n\n\n .directive('bsTimepicker', function($window, $parse, $q, $dateFormatter, $dateParser, $timepicker) {\n\n var defaults = $timepicker.defaults;\n var isNative = /(ip(a|o)d|iphone|android)/ig.test($window.navigator.userAgent);\n var requestAnimationFrame = $window.requestAnimationFrame || $window.setTimeout;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope, controller: controller};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'autoclose', 'timeType', 'timeFormat', 'modelTimeFormat', 'useNative', 'hourStep', 'minuteStep', 'length', 'arrowBehavior', 'iconUp', 'iconDown', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!timepicker || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(timepicker),?/i);\n newValue === true ? timepicker.show() : timepicker.hide();\n });\n\n // Initialize timepicker\n if(isNative && (options.useNative || defaults.useNative)) options.timeFormat = 'HH:mm';\n var timepicker = $timepicker(element, controller, options);\n options = timepicker.$options;\n\n var lang = options.lang;\n var formatDate = function(date, format) {\n return $dateFormatter.formatDate(date, format, lang);\n };\n\n // Initialize parser\n var dateParser = $dateParser({format: options.timeFormat, lang: lang});\n\n // Observe attributes for changes\n angular.forEach(['minTime', 'maxTime'], function(key) {\n // console.warn('attr.$observe(%s)', key, attr[key]);\n angular.isDefined(attr[key]) && attr.$observe(key, function(newValue) {\n timepicker.$options[key] = dateParser.getTimeForAttribute(key, newValue);\n !isNaN(timepicker.$options[key]) && timepicker.$build();\n validateAgainstMinMaxTime(controller.$dateValue);\n });\n });\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.ngModel, newValue, oldValue, controller.$dateValue);\n timepicker.update(controller.$dateValue);\n }, true);\n\n function validateAgainstMinMaxTime(parsedTime) {\n if (!angular.isDate(parsedTime)) return;\n var isMinValid = isNaN(options.minTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) >= options.minTime;\n var isMaxValid = isNaN(options.maxTime) || new Date(parsedTime.getTime()).setFullYear(1970, 0, 1) <= options.maxTime;\n var isValid = isMinValid && isMaxValid;\n controller.$setValidity('date', isValid);\n controller.$setValidity('min', isMinValid);\n controller.$setValidity('max', isMaxValid);\n // Only update the model when we have a valid date\n if(!isValid) {\n return;\n }\n controller.$dateValue = parsedTime;\n }\n\n // viewValue -> $parsers -> modelValue\n controller.$parsers.unshift(function(viewValue) {\n // console.warn('$parser(\"%s\"): viewValue=%o', element.attr('ng-model'), viewValue);\n // Null values should correctly reset the model value & validity\n if(!viewValue) {\n // BREAKING CHANGE:\n // return null (not undefined) when input value is empty, so angularjs 1.3\n // ngModelController can go ahead and run validators, like ngRequired\n controller.$setValidity('date', true);\n return null;\n }\n var parsedTime = angular.isDate(viewValue) ? viewValue : dateParser.parse(viewValue, controller.$dateValue);\n if(!parsedTime || isNaN(parsedTime.getTime())) {\n controller.$setValidity('date', false);\n // return undefined, causes ngModelController to\n // invalidate model value\n return;\n } else {\n validateAgainstMinMaxTime(parsedTime);\n }\n if(options.timeType === 'string') {\n return formatDate(parsedTime, options.modelTimeFormat || options.timeFormat);\n } else if(options.timeType === 'number') {\n return controller.$dateValue.getTime();\n } else if(options.timeType === 'unix') {\n return controller.$dateValue.getTime() / 1000;\n } else if(options.timeType === 'iso') {\n return controller.$dateValue.toISOString();\n } else {\n return new Date(controller.$dateValue);\n }\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var date;\n if(angular.isUndefined(modelValue) || modelValue === null) {\n date = NaN;\n } else if(angular.isDate(modelValue)) {\n date = modelValue;\n } else if(options.timeType === 'string') {\n date = dateParser.parse(modelValue, null, options.modelTimeFormat);\n } else if(options.timeType === 'unix') {\n date = new Date(modelValue * 1000);\n } else {\n date = new Date(modelValue);\n }\n // Setup default value?\n // if(isNaN(date.getTime())) date = new Date(new Date().setMinutes(0) + 36e5);\n controller.$dateValue = date;\n return getTimeFormattedString();\n });\n\n // viewValue -> element\n controller.$render = function() {\n // console.warn('$render(\"%s\"): viewValue=%o', element.attr('ng-model'), controller.$viewValue);\n element.val(getTimeFormattedString());\n };\n\n function getTimeFormattedString() {\n return !controller.$dateValue || isNaN(controller.$dateValue.getTime()) ? '' : formatDate(controller.$dateValue, options.timeFormat);\n }\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (timepicker) timepicker.destroy();\n options = null;\n timepicker = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.tooltip', ['mgcrea.ngStrap.helpers.dimensions'])\n\n .provider('$tooltip', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n customClass: '',\n prefixClass: 'tooltip',\n prefixEvent: 'tooltip',\n container: false,\n target: false,\n placement: 'top',\n template: 'tooltip/tooltip.tpl.html',\n contentTemplate: false,\n trigger: 'hover focus',\n keyboard: false,\n html: false,\n show: false,\n title: '',\n type: '',\n delay: 0,\n autoClose: false,\n bsEnabled: true\n };\n\n this.$get = function($window, $rootScope, $compile, $q, $templateCache, $http, $animate, $sce, dimensions, $$rAF, $timeout) {\n\n var trim = String.prototype.trim;\n var isTouch = 'createTouch' in $window.document;\n var htmlReplaceRegExp = /ng-bind=\"/ig;\n var $body = angular.element($window.document);\n\n function TooltipFactory(element, config) {\n\n var $tooltip = {};\n\n // Common vars\n var nodeName = element[0].nodeName.toLowerCase();\n var options = $tooltip.$options = angular.extend({}, defaults, config);\n $tooltip.$promise = fetchTemplate(options.template);\n var scope = $tooltip.$scope = options.scope && options.scope.$new() || $rootScope.$new();\n if(options.delay && angular.isString(options.delay)) {\n var split = options.delay.split(',').map(parseFloat);\n options.delay = split.length > 1 ? {show: split[0], hide: split[1]} : split[0];\n }\n\n // store $id to identify the triggering element in events\n // give priority to options.id, otherwise, try to use\n // element id if defined\n $tooltip.$id = options.id || element.attr('id') || '';\n\n // Support scope as string options\n if(options.title) {\n scope.title = $sce.trustAsHtml(options.title);\n }\n\n // Provide scope helpers\n scope.$setEnabled = function(isEnabled) {\n scope.$$postDigest(function() {\n $tooltip.setEnabled(isEnabled);\n });\n };\n scope.$hide = function() {\n scope.$$postDigest(function() {\n $tooltip.hide();\n });\n };\n scope.$show = function() {\n scope.$$postDigest(function() {\n $tooltip.show();\n });\n };\n scope.$toggle = function() {\n scope.$$postDigest(function() {\n $tooltip.toggle();\n });\n };\n // Publish isShown as a protected var on scope\n $tooltip.$isShown = scope.$isShown = false;\n\n // Private vars\n var timeout, hoverState;\n\n // Support contentTemplate option\n if(options.contentTemplate) {\n $tooltip.$promise = $tooltip.$promise.then(function(template) {\n var templateEl = angular.element(template);\n return fetchTemplate(options.contentTemplate)\n .then(function(contentTemplate) {\n var contentEl = findElement('[ng-bind=\"content\"]', templateEl[0]);\n if(!contentEl.length) contentEl = findElement('[ng-bind=\"title\"]', templateEl[0]);\n contentEl.removeAttr('ng-bind').html(contentTemplate);\n return templateEl[0].outerHTML;\n });\n });\n }\n\n // Fetch, compile then initialize tooltip\n var tipLinker, tipElement, tipTemplate, tipContainer, tipScope;\n $tooltip.$promise.then(function(template) {\n if(angular.isObject(template)) template = template.data;\n if(options.html) template = template.replace(htmlReplaceRegExp, 'ng-bind-html=\"');\n template = trim.apply(template);\n tipTemplate = template;\n tipLinker = $compile(template);\n $tooltip.init();\n });\n\n $tooltip.init = function() {\n\n // Options: delay\n if (options.delay && angular.isNumber(options.delay)) {\n options.delay = {\n show: options.delay,\n hide: options.delay\n };\n }\n\n // Replace trigger on touch devices ?\n // if(isTouch && options.trigger === defaults.trigger) {\n // options.trigger.replace(/hover/g, 'click');\n // }\n\n // Options : container\n if(options.container === 'self') {\n tipContainer = element;\n } else if(angular.isElement(options.container)) {\n tipContainer = options.container;\n } else if(options.container) {\n tipContainer = findElement(options.container);\n }\n\n // Options: trigger\n bindTriggerEvents();\n\n // Options: target\n if(options.target) {\n options.target = angular.isElement(options.target) ? options.target : findElement(options.target);\n }\n\n // Options: show\n if(options.show) {\n scope.$$postDigest(function() {\n options.trigger === 'focus' ? element[0].focus() : $tooltip.show();\n });\n }\n\n };\n\n $tooltip.destroy = function() {\n\n // Unbind events\n unbindTriggerEvents();\n\n // Remove element\n destroyTipElement();\n\n // Destroy scope\n scope.$destroy();\n\n };\n\n $tooltip.enter = function() {\n\n clearTimeout(timeout);\n hoverState = 'in';\n if (!options.delay || !options.delay.show) {\n return $tooltip.show();\n }\n\n timeout = setTimeout(function() {\n if (hoverState ==='in') $tooltip.show();\n }, options.delay.show);\n\n };\n\n $tooltip.show = function() {\n if (!options.bsEnabled || $tooltip.$isShown) return;\n\n scope.$emit(options.prefixEvent + '.show.before', $tooltip);\n var parent, after;\n if (options.container) {\n parent = tipContainer;\n if (tipContainer[0].lastChild) {\n after = angular.element(tipContainer[0].lastChild);\n } else {\n after = null;\n }\n } else {\n parent = null;\n after = element;\n }\n\n\n // Hide any existing tipElement\n if(tipElement) destroyTipElement();\n // Fetch a cloned element linked from template\n tipScope = $tooltip.$scope.$new();\n tipElement = $tooltip.$element = tipLinker(tipScope, function(clonedElement, scope) {});\n\n // Set the initial positioning. Make the tooltip invisible\n // so IE doesn't try to focus on it off screen.\n tipElement.css({top: '-9999px', left: '-9999px', display: 'block', visibility: 'hidden'});\n\n // Options: animation\n if(options.animation) tipElement.addClass(options.animation);\n // Options: type\n if(options.type) tipElement.addClass(options.prefixClass + '-' + options.type);\n // Options: custom classes\n if(options.customClass) tipElement.addClass(options.customClass);\n\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.enter(tipElement, parent, after, enterAnimateCallback);\n if(promise && promise.then) promise.then(enterAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = true;\n safeDigest(scope);\n $$rAF(function () {\n $tooltip.$applyPlacement();\n\n // Once placed, make the tooltip visible\n if(tipElement) tipElement.css({visibility: 'visible'});\n }); // var a = bodyEl.offsetWidth + 1; ?\n\n // Bind events\n if(options.keyboard) {\n if(options.trigger !== 'focus') {\n $tooltip.focus();\n }\n bindKeyboardEvents();\n }\n\n if(options.autoClose) {\n bindAutoCloseEvents();\n }\n\n };\n\n function enterAnimateCallback() {\n scope.$emit(options.prefixEvent + '.show', $tooltip);\n }\n\n $tooltip.leave = function() {\n\n clearTimeout(timeout);\n hoverState = 'out';\n if (!options.delay || !options.delay.hide) {\n return $tooltip.hide();\n }\n timeout = setTimeout(function () {\n if (hoverState === 'out') {\n $tooltip.hide();\n }\n }, options.delay.hide);\n\n };\n\n var _blur;\n var _tipToHide;\n $tooltip.hide = function(blur) {\n\n if(!$tooltip.$isShown) return;\n scope.$emit(options.prefixEvent + '.hide.before', $tooltip);\n\n // store blur value for leaveAnimateCallback to use\n _blur = blur;\n\n // store current tipElement reference to use\n // in leaveAnimateCallback\n _tipToHide = tipElement;\n\n // Support v1.3+ $animate\n // https://github.com/angular/angular.js/commit/bf0f5502b1bbfddc5cdd2f138efd9188b8c652a9\n var promise = $animate.leave(tipElement, leaveAnimateCallback);\n if(promise && promise.then) promise.then(leaveAnimateCallback);\n\n $tooltip.$isShown = scope.$isShown = false;\n safeDigest(scope);\n\n // Unbind events\n if(options.keyboard && tipElement !== null) {\n unbindKeyboardEvents();\n }\n\n if(options.autoClose && tipElement !== null) {\n unbindAutoCloseEvents();\n }\n };\n\n function leaveAnimateCallback() {\n scope.$emit(options.prefixEvent + '.hide', $tooltip);\n\n // check if current tipElement still references\n // the same element when hide was called\n if (tipElement === _tipToHide) {\n // Allow to blur the input when hidden, like when pressing enter key\n if(_blur && options.trigger === 'focus') {\n return element[0].blur();\n }\n\n // clean up child scopes\n destroyTipElement();\n }\n }\n\n $tooltip.toggle = function() {\n $tooltip.$isShown ? $tooltip.leave() : $tooltip.enter();\n };\n\n $tooltip.focus = function() {\n tipElement[0].focus();\n };\n\n $tooltip.setEnabled = function(isEnabled) {\n options.bsEnabled = isEnabled;\n };\n\n // Protected methods\n\n $tooltip.$applyPlacement = function() {\n if(!tipElement) return;\n\n // Determine if we're doing an auto or normal placement\n var placement = options.placement,\n autoToken = /\\s?auto?\\s?/i,\n autoPlace = autoToken.test(placement);\n\n if (autoPlace) {\n placement = placement.replace(autoToken, '') || defaults.placement;\n }\n\n // Need to add the position class before we get\n // the offsets\n tipElement.addClass(options.placement);\n\n // Get the position of the target element\n // and the height and width of the tooltip so we can center it.\n var elementPosition = getPosition(),\n tipWidth = tipElement.prop('offsetWidth'),\n tipHeight = tipElement.prop('offsetHeight');\n\n // If we're auto placing, we need to check the positioning\n if (autoPlace) {\n var originalPlacement = placement;\n var container = options.container ? angular.element(document.querySelector(options.container)) : element.parent();\n var containerPosition = getPosition(container);\n\n // Determine if the vertical placement\n if (originalPlacement.indexOf('bottom') >= 0 && elementPosition.bottom + tipHeight > containerPosition.bottom) {\n placement = originalPlacement.replace('bottom', 'top');\n } else if (originalPlacement.indexOf('top') >= 0 && elementPosition.top - tipHeight < containerPosition.top) {\n placement = originalPlacement.replace('top', 'bottom');\n }\n\n // Determine the horizontal placement\n // The exotic placements of left and right are opposite of the standard placements. Their arrows are put on the left/right\n // and flow in the opposite direction of their placement.\n if ((originalPlacement === 'right' || originalPlacement === 'bottom-left' || originalPlacement === 'top-left') &&\n elementPosition.right + tipWidth > containerPosition.width) {\n\n placement = originalPlacement === 'right' ? 'left' : placement.replace('left', 'right');\n } else if ((originalPlacement === 'left' || originalPlacement === 'bottom-right' || originalPlacement === 'top-right') &&\n elementPosition.left - tipWidth < containerPosition.left) {\n\n placement = originalPlacement === 'left' ? 'right' : placement.replace('right', 'left');\n }\n\n tipElement.removeClass(originalPlacement).addClass(placement);\n }\n\n // Get the tooltip's top and left coordinates to center it with this directive.\n var tipPosition = getCalculatedOffset(placement, elementPosition, tipWidth, tipHeight);\n applyPlacementCss(tipPosition.top, tipPosition.left);\n };\n\n $tooltip.$onKeyUp = function(evt) {\n if (evt.which === 27 && $tooltip.$isShown) {\n $tooltip.hide();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusKeyUp = function(evt) {\n if (evt.which === 27) {\n element[0].blur();\n evt.stopPropagation();\n }\n };\n\n $tooltip.$onFocusElementMouseDown = function(evt) {\n evt.preventDefault();\n evt.stopPropagation();\n // Some browsers do not auto-focus buttons (eg. Safari)\n $tooltip.$isShown ? element[0].blur() : element[0].focus();\n };\n\n // bind/unbind events\n function bindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n angular.forEach(triggers, function(trigger) {\n if(trigger === 'click') {\n element.on('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.on(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.on(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.on(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n });\n }\n\n function unbindTriggerEvents() {\n var triggers = options.trigger.split(' ');\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i];\n if(trigger === 'click') {\n element.off('click', $tooltip.toggle);\n } else if(trigger !== 'manual') {\n element.off(trigger === 'hover' ? 'mouseenter' : 'focus', $tooltip.enter);\n element.off(trigger === 'hover' ? 'mouseleave' : 'blur', $tooltip.leave);\n nodeName === 'button' && trigger !== 'hover' && element.off(isTouch ? 'touchstart' : 'mousedown', $tooltip.$onFocusElementMouseDown);\n }\n }\n }\n\n function bindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.on('keyup', $tooltip.$onKeyUp);\n } else {\n element.on('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n function unbindKeyboardEvents() {\n if(options.trigger !== 'focus') {\n tipElement.off('keyup', $tooltip.$onKeyUp);\n } else {\n element.off('keyup', $tooltip.$onFocusKeyUp);\n }\n }\n\n var _autoCloseEventsBinded = false;\n function bindAutoCloseEvents() {\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n // Stop propagation when clicking inside tooltip\n tipElement.on('click', stopEventPropagation);\n\n // Hide when clicking outside tooltip\n $body.on('click', $tooltip.hide);\n\n _autoCloseEventsBinded = true;\n }, 0, false);\n }\n\n function unbindAutoCloseEvents() {\n if (_autoCloseEventsBinded) {\n tipElement.off('click', stopEventPropagation);\n $body.off('click', $tooltip.hide);\n _autoCloseEventsBinded = false;\n }\n }\n\n function stopEventPropagation(event) {\n event.stopPropagation();\n }\n\n // Private methods\n\n function getPosition($element) {\n $element = $element || (options.target || element);\n\n var el = $element[0];\n\n var elRect = el.getBoundingClientRect();\n if (elRect.width === null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = angular.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top });\n }\n\n var elPos;\n if (options.container === 'body') {\n elPos = dimensions.offset(el);\n } else {\n elPos = dimensions.position(el);\n }\n\n return angular.extend({}, elRect, elPos);\n }\n\n function getCalculatedOffset(placement, position, actualWidth, actualHeight) {\n var offset;\n var split = placement.split('-');\n\n switch (split[0]) {\n case 'right':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left + position.width\n };\n break;\n case 'bottom':\n offset = {\n top: position.top + position.height,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n case 'left':\n offset = {\n top: position.top + position.height / 2 - actualHeight / 2,\n left: position.left - actualWidth\n };\n break;\n default:\n offset = {\n top: position.top - actualHeight,\n left: position.left + position.width / 2 - actualWidth / 2\n };\n break;\n }\n\n if(!split[1]) {\n return offset;\n }\n\n // Add support for corners @todo css\n if(split[0] === 'top' || split[0] === 'bottom') {\n switch (split[1]) {\n case 'left':\n offset.left = position.left;\n break;\n case 'right':\n offset.left = position.left + position.width - actualWidth;\n }\n } else if(split[0] === 'left' || split[0] === 'right') {\n switch (split[1]) {\n case 'top':\n offset.top = position.top - actualHeight;\n break;\n case 'bottom':\n offset.top = position.top + position.height;\n }\n }\n\n return offset;\n }\n\n function applyPlacementCss(top, left) {\n tipElement.css({ top: top + 'px', left: left + 'px' });\n }\n\n function destroyTipElement() {\n // Cancel pending callbacks\n clearTimeout(timeout);\n\n if($tooltip.$isShown && tipElement !== null) {\n if(options.autoClose) {\n unbindAutoCloseEvents();\n }\n\n if(options.keyboard) {\n unbindKeyboardEvents();\n }\n }\n\n if(tipScope) {\n tipScope.$destroy();\n tipScope = null;\n }\n\n if(tipElement) {\n tipElement.remove();\n tipElement = $tooltip.$element = null;\n }\n }\n\n return $tooltip;\n\n }\n\n // Helper functions\n\n function safeDigest(scope) {\n scope.$$phase || (scope.$root && scope.$root.$$phase) || scope.$digest();\n }\n\n function findElement(query, element) {\n return angular.element((element || document).querySelectorAll(query));\n }\n\n var fetchPromises = {};\n function fetchTemplate(template) {\n if(fetchPromises[template]) return fetchPromises[template];\n return (fetchPromises[template] = $q.when($templateCache.get(template) || $http.get(template))\n .then(function(res) {\n if(angular.isObject(res)) {\n $templateCache.put(template, res.data);\n return res.data;\n }\n return res;\n }));\n }\n\n return TooltipFactory;\n\n };\n\n })\n\n .directive('bsTooltip', function($window, $location, $sce, $tooltip, $$rAF) {\n\n return {\n restrict: 'EAC',\n scope: true,\n link: function postLink(scope, element, attr, transclusion) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['template', 'contentTemplate', 'placement', 'container', 'target', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'backdropAnimation', 'type', 'customClass', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // overwrite inherited title value when no value specified\n // fix for angular 1.3.1 531a8de72c439d8ddd064874bf364c00cedabb11\n if (!scope.hasOwnProperty('title')){\n scope.title = '';\n }\n\n // Observe scope attributes for change\n attr.$observe('title', function(newValue) {\n if (angular.isDefined(newValue) || !scope.hasOwnProperty('title')) {\n var oldValue = scope.title;\n scope.title = $sce.trustAsHtml(newValue);\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }\n });\n\n // Support scope as an object\n attr.bsTooltip && scope.$watch(attr.bsTooltip, function(newValue, oldValue) {\n if(angular.isObject(newValue)) {\n angular.extend(scope, newValue);\n } else {\n scope.title = newValue;\n }\n angular.isDefined(oldValue) && $$rAF(function() {\n tooltip && tooltip.$applyPlacement();\n });\n }, true);\n\n // Visibility binding support\n attr.bsShow && scope.$watch(attr.bsShow, function(newValue, oldValue) {\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|,?(tooltip),?/i);\n newValue === true ? tooltip.show() : tooltip.hide();\n });\n\n // Enabled binding support\n attr.bsEnabled && scope.$watch(attr.bsEnabled, function(newValue, oldValue) {\n // console.warn('scope.$watch(%s)', attr.bsEnabled, newValue, oldValue);\n if(!tooltip || !angular.isDefined(newValue)) return;\n if(angular.isString(newValue)) newValue = !!newValue.match(/true|1|,?(tooltip),?/i);\n newValue === false ? tooltip.setEnabled(false) : tooltip.setEnabled(true);\n });\n\n // Initialize popover\n var tooltip = $tooltip(element, options);\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if(tooltip) tooltip.destroy();\n options = null;\n tooltip = null;\n });\n\n }\n };\n\n });\n","'use strict';\n\nangular.module('mgcrea.ngStrap.typeahead', ['mgcrea.ngStrap.tooltip', 'mgcrea.ngStrap.helpers.parseOptions'])\n\n .provider('$typeahead', function() {\n\n var defaults = this.defaults = {\n animation: 'am-fade',\n prefixClass: 'typeahead',\n prefixEvent: '$typeahead',\n placement: 'bottom-left',\n template: 'typeahead/typeahead.tpl.html',\n trigger: 'focus',\n container: false,\n keyboard: true,\n html: false,\n delay: 0,\n minLength: 1,\n filter: 'filter',\n limit: 6,\n comparator: ''\n };\n\n this.$get = function($window, $rootScope, $tooltip, $timeout) {\n\n var bodyEl = angular.element($window.document.body);\n\n function TypeaheadFactory(element, controller, config) {\n\n var $typeahead = {};\n\n // Common vars\n var options = angular.extend({}, defaults, config);\n\n $typeahead = $tooltip(element, options);\n var parentScope = config.scope;\n var scope = $typeahead.$scope;\n\n scope.$resetMatches = function(){\n scope.$matches = [];\n scope.$activeIndex = 0;\n };\n scope.$resetMatches();\n\n scope.$activate = function(index) {\n scope.$$postDigest(function() {\n $typeahead.activate(index);\n });\n };\n\n scope.$select = function(index, evt) {\n scope.$$postDigest(function() {\n $typeahead.select(index);\n });\n };\n\n scope.$isVisible = function() {\n return $typeahead.$isVisible();\n };\n\n // Public methods\n\n $typeahead.update = function(matches) {\n scope.$matches = matches;\n if(scope.$activeIndex >= matches.length) {\n scope.$activeIndex = 0;\n }\n };\n\n $typeahead.activate = function(index) {\n scope.$activeIndex = index;\n };\n\n $typeahead.select = function(index) {\n var value = scope.$matches[index].value;\n // console.log('$setViewValue', value);\n controller.$setViewValue(value);\n controller.$render();\n scope.$resetMatches();\n if(parentScope) parentScope.$digest();\n // Emit event\n scope.$emit(options.prefixEvent + '.select', value, index, $typeahead);\n };\n\n // Protected methods\n\n $typeahead.$isVisible = function() {\n if(!options.minLength || !controller) {\n return !!scope.$matches.length;\n }\n // minLength support\n return scope.$matches.length && angular.isString(controller.$viewValue) && controller.$viewValue.length >= options.minLength;\n };\n\n $typeahead.$getIndex = function(value) {\n var l = scope.$matches.length, i = l;\n if(!l) return;\n for(i = l; i--;) {\n if(scope.$matches[i].value === value) break;\n }\n if(i < 0) return;\n return i;\n };\n\n $typeahead.$onMouseDown = function(evt) {\n // Prevent blur on mousedown\n evt.preventDefault();\n evt.stopPropagation();\n };\n\n $typeahead.$onKeyDown = function(evt) {\n if(!/(38|40|13)/.test(evt.keyCode)) return;\n\n // Let ngSubmit pass if the typeahead tip is hidden\n if($typeahead.$isVisible()) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Select with enter\n if(evt.keyCode === 13 && scope.$matches.length) {\n $typeahead.select(scope.$activeIndex);\n }\n\n // Navigate with keyboard\n else if(evt.keyCode === 38 && scope.$activeIndex > 0) scope.$activeIndex--;\n else if(evt.keyCode === 40 && scope.$activeIndex < scope.$matches.length - 1) scope.$activeIndex++;\n else if(angular.isUndefined(scope.$activeIndex)) scope.$activeIndex = 0;\n scope.$digest();\n };\n\n // Overrides\n\n var show = $typeahead.show;\n $typeahead.show = function() {\n show();\n // use timeout to hookup the events to prevent\n // event bubbling from being processed imediately.\n $timeout(function() {\n $typeahead.$element.on('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.on('keydown', $typeahead.$onKeyDown);\n }\n }, 0, false);\n };\n\n var hide = $typeahead.hide;\n $typeahead.hide = function() {\n $typeahead.$element.off('mousedown', $typeahead.$onMouseDown);\n if(options.keyboard) {\n element.off('keydown', $typeahead.$onKeyDown);\n }\n hide();\n };\n\n return $typeahead;\n\n }\n\n TypeaheadFactory.defaults = defaults;\n return TypeaheadFactory;\n\n };\n\n })\n\n .directive('bsTypeahead', function($window, $parse, $q, $typeahead, $parseOptions) {\n\n var defaults = $typeahead.defaults;\n\n return {\n restrict: 'EAC',\n require: 'ngModel',\n link: function postLink(scope, element, attr, controller) {\n\n // Directive options\n var options = {scope: scope};\n angular.forEach(['placement', 'container', 'delay', 'trigger', 'keyboard', 'html', 'animation', 'template', 'filter', 'limit', 'minLength', 'watchOptions', 'selectMode', 'comparator', 'id'], function(key) {\n if(angular.isDefined(attr[key])) options[key] = attr[key];\n });\n\n // Build proper ngOptions\n var filter = options.filter || defaults.filter;\n var limit = options.limit || defaults.limit;\n var comparator = options.comparator || defaults.comparator;\n\n var ngOptions = attr.ngOptions;\n if(filter) ngOptions += ' | ' + filter + ':$viewValue';\n if (comparator) ngOptions += ':' + comparator;\n if(limit) ngOptions += ' | limitTo:' + limit;\n var parsedOptions = $parseOptions(ngOptions);\n\n // Initialize typeahead\n var typeahead = $typeahead(element, controller, options);\n\n // Watch options on demand\n if(options.watchOptions) {\n // Watch ngOptions values before filtering for changes, drop function calls\n var watchedOptions = parsedOptions.$match[7].replace(/\\|.+/, '').replace(/\\(.*\\)/g, '').trim();\n scope.$watch(watchedOptions, function (newValue, oldValue) {\n // console.warn('scope.$watch(%s)', watchedOptions, newValue, oldValue);\n parsedOptions.valuesFn(scope, controller).then(function (values) {\n typeahead.update(values);\n controller.$render();\n });\n }, true);\n }\n\n // Watch model for changes\n scope.$watch(attr.ngModel, function(newValue, oldValue) {\n // console.warn('$watch', element.attr('ng-model'), newValue);\n scope.$modelValue = newValue; // Publish modelValue on scope for custom templates\n parsedOptions.valuesFn(scope, controller)\n .then(function(values) {\n // Prevent input with no future prospect if selectMode is truthy\n // @TODO test selectMode\n if(options.selectMode && !values.length && newValue.length > 0) {\n controller.$setViewValue(controller.$viewValue.substring(0, controller.$viewValue.length - 1));\n return;\n }\n if(values.length > limit) values = values.slice(0, limit);\n var isVisible = typeahead.$isVisible();\n isVisible && typeahead.update(values);\n // Do not re-queue an update if a correct value has been selected\n if(values.length === 1 && values[0].value === newValue) return;\n !isVisible && typeahead.update(values);\n // Queue a new rendering that will leverage collection loading\n controller.$render();\n });\n });\n\n // modelValue -> $formatters -> viewValue\n controller.$formatters.push(function(modelValue) {\n // console.warn('$formatter(\"%s\"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);\n var displayValue = parsedOptions.displayValue(modelValue);\n return displayValue === undefined ? '' : displayValue;\n });\n\n // Model rendering in view\n controller.$render = function () {\n // console.warn('$render', element.attr('ng-model'), 'controller.$modelValue', typeof controller.$modelValue, controller.$modelValue, 'controller.$viewValue', typeof controller.$viewValue, controller.$viewValue);\n if(controller.$isEmpty(controller.$viewValue)) return element.val('');\n var index = typeahead.$getIndex(controller.$modelValue);\n var selected = angular.isDefined(index) ? typeahead.$scope.$matches[index].label : controller.$viewValue;\n selected = angular.isObject(selected) ? parsedOptions.displayValue(selected) : selected;\n element.val(selected ? selected.toString().replace(/<(?:.|\\n)*?>/gm, '').trim() : '');\n };\n\n // Garbage collection\n scope.$on('$destroy', function() {\n if (typeahead) typeahead.destroy();\n options = null;\n typeahead = null;\n });\n\n }\n };\n\n });\n"],"sourceRoot":"/source/"} \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.js b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.js new file mode 100644 index 0000000..d85aa53 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.js @@ -0,0 +1,89 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +(function(window, document, undefined) { +'use strict'; + +// Source: alert.tpl.js +angular.module('mgcrea.ngStrap.alert').run(['$templateCache', function($templateCache) { + + $templateCache.put('alert/alert.tpl.html', '
     
    '); + +}]); + +// Source: aside.tpl.js +angular.module('mgcrea.ngStrap.aside').run(['$templateCache', function($templateCache) { + + $templateCache.put('aside/aside.tpl.html', ''); + +}]); + +// Source: datepicker.tpl.js +angular.module('mgcrea.ngStrap.datepicker').run(['$templateCache', function($templateCache) { + + $templateCache.put('datepicker/datepicker.tpl.html', ''); + +}]); + +// Source: dropdown.tpl.js +angular.module('mgcrea.ngStrap.dropdown').run(['$templateCache', function($templateCache) { + + $templateCache.put('dropdown/dropdown.tpl.html', ''); + +}]); + +// Source: modal.tpl.js +angular.module('mgcrea.ngStrap.modal').run(['$templateCache', function($templateCache) { + + $templateCache.put('modal/modal.tpl.html', ''); + +}]); + +// Source: popover.tpl.js +angular.module('mgcrea.ngStrap.popover').run(['$templateCache', function($templateCache) { + + $templateCache.put('popover/popover.tpl.html', '

    '); + +}]); + +// Source: select.tpl.js +angular.module('mgcrea.ngStrap.select').run(['$templateCache', function($templateCache) { + + $templateCache.put('select/select.tpl.html', ''); + +}]); + +// Source: tab.tpl.js +angular.module('mgcrea.ngStrap.tab').run(['$templateCache', function($templateCache) { + + $templateCache.put('tab/tab.tpl.html', '
    '); + +}]); + +// Source: timepicker.tpl.js +angular.module('mgcrea.ngStrap.timepicker').run(['$templateCache', function($templateCache) { + + $templateCache.put('timepicker/timepicker.tpl.html', ''); + +}]); + +// Source: tooltip.tpl.js +angular.module('mgcrea.ngStrap.tooltip').run(['$templateCache', function($templateCache) { + + $templateCache.put('tooltip/tooltip.tpl.html', '
    '); + +}]); + +// Source: typeahead.tpl.js +angular.module('mgcrea.ngStrap.typeahead').run(['$templateCache', function($templateCache) { + + $templateCache.put('typeahead/typeahead.tpl.html', ''); + +}]); + + +})(window, document); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.min.js new file mode 100644 index 0000000..c8f44b6 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-strap_2.1.6/angular-strap.tpl.min.js @@ -0,0 +1,8 @@ +/** + * angular-strap + * @version v2.1.6 - 2015-01-11 + * @link http://mgcrea.github.io/angular-strap + * @author Olivier Louvignes (olivier@mg-crea.com) + * @license MIT License, http://www.opensource.org/licenses/MIT + */ +!function(){"use strict";angular.module("mgcrea.ngStrap.alert").run(["$templateCache",function(t){t.put("alert/alert.tpl.html",'
     
    ')}]),angular.module("mgcrea.ngStrap.aside").run(["$templateCache",function(t){t.put("aside/aside.tpl.html",'')}]),angular.module("mgcrea.ngStrap.datepicker").run(["$templateCache",function(t){t.put("datepicker/datepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.dropdown").run(["$templateCache",function(t){t.put("dropdown/dropdown.tpl.html",'')}]),angular.module("mgcrea.ngStrap.modal").run(["$templateCache",function(t){t.put("modal/modal.tpl.html",'')}]),angular.module("mgcrea.ngStrap.popover").run(["$templateCache",function(t){t.put("popover/popover.tpl.html",'

    ')}]),angular.module("mgcrea.ngStrap.select").run(["$templateCache",function(t){t.put("select/select.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tab").run(["$templateCache",function(t){t.put("tab/tab.tpl.html",'
    ')}]),angular.module("mgcrea.ngStrap.timepicker").run(["$templateCache",function(t){t.put("timepicker/timepicker.tpl.html",'')}]),angular.module("mgcrea.ngStrap.tooltip").run(["$templateCache",function(t){t.put("tooltip/tooltip.tpl.html",'
    ')}]),angular.module("mgcrea.ngStrap.typeahead").run(["$templateCache",function(t){t.put("typeahead/typeahead.tpl.html",'')}])}(window,document); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/.bower.json b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/.bower.json new file mode 100644 index 0000000..d2b66a9 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/.bower.json @@ -0,0 +1,19 @@ +{ + "name": "angular-translate-loader-static-files", + "version": "0.1.6", + "main": "./angular-translate-loader-static-files.js", + "dependencies": { + "angular": "1.0.8", + "angular-translate": "~1.1.1" + }, + "homepage": "https://github.com/PascalPrecht/bower-angular-translate-loader-static-files", + "_release": "0.1.6", + "_resolution": { + "type": "version", + "tag": "0.1.6", + "commit": "eaac546d29d6cde45873e6bad9d18cdff071d983" + }, + "_source": "git://github.com/PascalPrecht/bower-angular-translate-loader-static-files.git", + "_target": "0.1.6", + "_originalSource": "angular-translate-loader-static-files" +} \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js new file mode 100644 index 0000000..a68fbc7 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.js @@ -0,0 +1,112 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +$translateStaticFilesLoader.$inject = ['$q', '$http']; +angular.module('pascalprecht.translate') +/** + * @ngdoc object + * @name pascalprecht.translate.$translateStaticFilesLoader + * @requires $q + * @requires $http + * + * @description + * Creates a loading function for a typical static file url pattern: + * "lang-en_US.json", "lang-de_DE.json", etc. Using this builder, + * the response of these urls must be an object of key-value pairs. + * + * @param {object} options Options object, which gets prefix, suffix, key, and fileMap + */ +.factory('$translateStaticFilesLoader', $translateStaticFilesLoader); + +function $translateStaticFilesLoader($q, $http) { + + 'use strict'; + + return function (options) { + + if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) { + throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!'); + } + + if (!options.files) { + options.files = [{ + prefix: options.prefix, + suffix: options.suffix + }]; + } + + var load = function (file) { + if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) { + throw new Error('Couldn\'t load static file, no prefix or suffix specified!'); + } + + var fileUrl = [ + file.prefix, + options.key, + file.suffix + ].join(''); + + if (angular.isObject(options.fileMap) && options.fileMap[fileUrl]) { + fileUrl = options.fileMap[fileUrl]; + } + + return $http(angular.extend({ + url: fileUrl, + method: 'GET' + }, options.$http)) + .then(function(result) { + return result.data; + }, function () { + return $q.reject(options.key); + }); + }; + + var promises = [], + length = options.files.length; + + for (var i = 0; i < length; i++) { + promises.push(load({ + prefix: options.files[i].prefix, + key: options.key, + suffix: options.files[i].suffix + })); + } + + return $q.all(promises) + .then(function (data) { + var length = data.length, + mergedData = {}; + + for (var i = 0; i < length; i++) { + for (var key in data[i]) { + mergedData[key] = data[i][key]; + } + } + + return mergedData; + }); + }; +} + +$translateStaticFilesLoader.displayName = '$translateStaticFilesLoader'; +return 'pascalprecht.translate'; + +})); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js new file mode 100644 index 0000000..8ba0b60 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a,b){"use strict";return function(c){if(!(c&&(angular.isArray(c.files)||angular.isString(c.prefix)&&angular.isString(c.suffix))))throw new Error("Couldn't load static files, no files and prefix or suffix specified!");c.files||(c.files=[{prefix:c.prefix,suffix:c.suffix}]);for(var d=function(d){if(!d||!angular.isString(d.prefix)||!angular.isString(d.suffix))throw new Error("Couldn't load static file, no prefix or suffix specified!");var e=[d.prefix,c.key,d.suffix].join("");return angular.isObject(c.fileMap)&&c.fileMap[e]&&(e=c.fileMap[e]),b(angular.extend({url:e,method:"GET"},c.$http)).then(function(a){return a.data},function(){return a.reject(c.key)})},e=[],f=c.files.length,g=0;g= 4) { + var $cookies = $injector.get('$cookies'); + delegate = { + get : function (key) { + return $cookies.get(key); + }, + put : function (key, value) { + $cookies.put(key, value); + } + }; + } else { + var $cookieStore = $injector.get('$cookieStore'); + delegate = { + get : function (key) { + return $cookieStore.get(key); + }, + put : function (key, value) { + $cookieStore.put(key, value); + } + }; + } + + var $translateCookieStorage = { + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#get + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Returns an item from cookieStorage by given name. + * + * @param {string} name Item name + * @return {string} Value of item name + */ + get : function (name) { + return delegate.get(name); + }, + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#set + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Sets an item in cookieStorage by given name. + * + * @deprecated use #put + * + * @param {string} name Item name + * @param {string} value Item value + */ + set : function (name, value) { + delegate.put(name, value); + }, + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateCookieStorage#put + * @methodOf pascalprecht.translate.$translateCookieStorage + * + * @description + * Sets an item in cookieStorage by given name. + * + * @param {string} name Item name + * @param {string} value Item value + */ + put : function (name, value) { + delegate.put(name, value); + } + }; + + return $translateCookieStorage; +} + +$translateCookieStorageFactory.displayName = '$translateCookieStorage'; +return 'pascalprecht.translate'; + +})); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js new file mode 100644 index 0000000..54467c5 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-translate-storage-cookie/angular-translate-storage-cookie.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a){"use strict";var b;if(1===angular.version.major&&angular.version.minor>=4){var c=a.get("$cookies");b={get:function(a){return c.get(a)},put:function(a,b){c.put(a,b)}}}else{var d=a.get("$cookieStore");b={get:function(a){return d.get(a)},put:function(a,b){d.put(a,b)}}}var e={get:function(a){return b.get(a)},set:function(a,c){b.put(a,c)},put:function(a,c){b.put(a,c)}};return e}return a.$inject=["$injector"],angular.module("pascalprecht.translate").factory("$translateCookieStorage",a),a.displayName="$translateCookieStorage","pascalprecht.translate"}); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.js b/zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.js new file mode 100644 index 0000000..c2e2e14 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.js @@ -0,0 +1,3709 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define([], function () { + return (factory()); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(); + } else { + factory(); + } +}(this, function () { + +/** + * @ngdoc overview + * @name pascalprecht.translate + * + * @description + * The main module which holds everything together. + */ +runTranslate.$inject = ['$translate']; +$translate.$inject = ['$STORAGE_KEY', '$windowProvider', '$translateSanitizationProvider', 'pascalprechtTranslateOverrider']; +$translateDefaultInterpolation.$inject = ['$interpolate', '$translateSanitization']; +translateDirective.$inject = ['$translate', '$interpolate', '$compile', '$parse', '$rootScope']; +translateAttrDirective.$inject = ['$translate', '$rootScope']; +translateCloakDirective.$inject = ['$translate', '$rootScope']; +translateFilterFactory.$inject = ['$parse', '$translate']; +$translationCache.$inject = ['$cacheFactory']; +angular.module('pascalprecht.translate', ['ng']) + .run(runTranslate); + +function runTranslate($translate) { + + 'use strict'; + + var key = $translate.storageKey(), + storage = $translate.storage(); + + var fallbackFromIncorrectStorageValue = function () { + var preferred = $translate.preferredLanguage(); + if (angular.isString(preferred)) { + $translate.use(preferred); + // $translate.use() will also remember the language. + // So, we don't need to call storage.put() here. + } else { + storage.put(key, $translate.use()); + } + }; + + fallbackFromIncorrectStorageValue.displayName = 'fallbackFromIncorrectStorageValue'; + + if (storage) { + if (!storage.get(key)) { + fallbackFromIncorrectStorageValue(); + } else { + $translate.use(storage.get(key))['catch'](fallbackFromIncorrectStorageValue); + } + } else if (angular.isString($translate.preferredLanguage())) { + $translate.use($translate.preferredLanguage()); + } +} + +runTranslate.displayName = 'runTranslate'; + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateSanitizationProvider + * + * @description + * + * Configurations for $translateSanitization + */ +angular.module('pascalprecht.translate').provider('$translateSanitization', $translateSanitizationProvider); + +function $translateSanitizationProvider () { + + 'use strict'; + + var $sanitize, + $sce, + currentStrategy = null, // TODO change to either 'sanitize', 'escape' or ['sanitize', 'escapeParameters'] in 3.0. + hasConfiguredStrategy = false, + hasShownNoStrategyConfiguredWarning = false, + strategies; + + /** + * Definition of a sanitization strategy function + * @callback StrategyFunction + * @param {string|object} value - value to be sanitized (either a string or an interpolated value map) + * @param {string} mode - either 'text' for a string (translation) or 'params' for the interpolated params + * @return {string|object} + */ + + /** + * @ngdoc property + * @name strategies + * @propertyOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Following strategies are built-in: + *
    + *
    sanitize
    + *
    Sanitizes HTML in the translation text using $sanitize
    + *
    escape
    + *
    Escapes HTML in the translation
    + *
    sanitizeParameters
    + *
    Sanitizes HTML in the values of the interpolation parameters using $sanitize
    + *
    escapeParameters
    + *
    Escapes HTML in the values of the interpolation parameters
    + *
    escaped
    + *
    Support legacy strategy name 'escaped' for backwards compatibility (will be removed in 3.0)
    + *
    + * + */ + + strategies = { + sanitize: function (value, mode/*, context*/) { + if (mode === 'text') { + value = htmlSanitizeValue(value); + } + return value; + }, + escape: function (value, mode/*, context*/) { + if (mode === 'text') { + value = htmlEscapeValue(value); + } + return value; + }, + sanitizeParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlSanitizeValue); + } + return value; + }, + escapeParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlEscapeValue); + } + return value; + }, + sce: function (value, mode, context) { + if (mode === 'text') { + value = htmlTrustValue(value); + } else if (mode === 'params') { + if (context !== 'filter') { + // do html escape in filter context #1101 + value = mapInterpolationParameters(value, htmlEscapeValue); + } + } + return value; + }, + sceParameters: function (value, mode/*, context*/) { + if (mode === 'params') { + value = mapInterpolationParameters(value, htmlTrustValue); + } + return value; + } + }; + // Support legacy strategy name 'escaped' for backwards compatibility. + // TODO should be removed in 3.0 + strategies.escaped = strategies.escapeParameters; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#addStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Adds a sanitization strategy to the list of known strategies. + * + * @param {string} strategyName - unique key for a strategy + * @param {StrategyFunction} strategyFunction - strategy function + * @returns {object} this + */ + this.addStrategy = function (strategyName, strategyFunction) { + strategies[strategyName] = strategyFunction; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#removeStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Removes a sanitization strategy from the list of known strategies. + * + * @param {string} strategyName - unique key for a strategy + * @returns {object} this + */ + this.removeStrategy = function (strategyName) { + delete strategies[strategyName]; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitizationProvider#useStrategy + * @methodOf pascalprecht.translate.$translateSanitizationProvider + * + * @description + * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. + * + * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. + * @returns {object} this + */ + this.useStrategy = function (strategy) { + hasConfiguredStrategy = true; + currentStrategy = strategy; + return this; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translateSanitization + * @requires $injector + * @requires $log + * + * @description + * Sanitizes interpolation parameters and translated texts. + * + */ + this.$get = ['$injector', '$log', function ($injector, $log) { + + var cachedStrategyMap = {}; + + var applyStrategies = function (value, mode, context, selectedStrategies) { + angular.forEach(selectedStrategies, function (selectedStrategy) { + if (angular.isFunction(selectedStrategy)) { + value = selectedStrategy(value, mode, context); + } else if (angular.isFunction(strategies[selectedStrategy])) { + value = strategies[selectedStrategy](value, mode, context); + } else if (angular.isString(strategies[selectedStrategy])) { + if (!cachedStrategyMap[strategies[selectedStrategy]]) { + try { + cachedStrategyMap[strategies[selectedStrategy]] = $injector.get(strategies[selectedStrategy]); + } catch (e) { + cachedStrategyMap[strategies[selectedStrategy]] = function() {}; + throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); + } + } + value = cachedStrategyMap[strategies[selectedStrategy]](value, mode, context); + } else { + throw new Error('pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: \'' + selectedStrategy + '\''); + } + }); + return value; + }; + + // TODO: should be removed in 3.0 + var showNoStrategyConfiguredWarning = function () { + if (!hasConfiguredStrategy && !hasShownNoStrategyConfiguredWarning) { + $log.warn('pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details.'); + hasShownNoStrategyConfiguredWarning = true; + } + }; + + if ($injector.has('$sanitize')) { + $sanitize = $injector.get('$sanitize'); + } + if ($injector.has('$sce')) { + $sce = $injector.get('$sce'); + } + + return { + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitization#useStrategy + * @methodOf pascalprecht.translate.$translateSanitization + * + * @description + * Selects a sanitization strategy. When an array is provided the strategies will be executed in order. + * + * @param {string|StrategyFunction|array} strategy The sanitization strategy / strategies which should be used. Either a name of an existing strategy, a custom strategy function, or an array consisting of multiple names and / or custom functions. + */ + useStrategy: (function (self) { + return function (strategy) { + self.useStrategy(strategy); + }; + })(this), + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateSanitization#sanitize + * @methodOf pascalprecht.translate.$translateSanitization + * + * @description + * Sanitizes a value. + * + * @param {string|object} value The value which should be sanitized. + * @param {string} mode The current sanitization mode, either 'params' or 'text'. + * @param {string|StrategyFunction|array} [strategy] Optional custom strategy which should be used instead of the currently selected strategy. + * @param {string} [context] The context of this call: filter, service. Default is service + * @returns {string|object} sanitized value + */ + sanitize: function (value, mode, strategy, context) { + if (!currentStrategy) { + showNoStrategyConfiguredWarning(); + } + + if (!strategy && strategy !== null) { + strategy = currentStrategy; + } + + if (!strategy) { + return value; + } + + if (!context) { + context = 'service'; + } + + var selectedStrategies = angular.isArray(strategy) ? strategy : [strategy]; + return applyStrategies(value, mode, context, selectedStrategies); + } + }; + }]; + + var htmlEscapeValue = function (value) { + var element = angular.element('
    '); + element.text(value); // not chainable, see #1044 + return element.html(); + }; + + var htmlSanitizeValue = function (value) { + if (!$sanitize) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as \'escape\'.'); + } + return $sanitize(value); + }; + + var htmlTrustValue = function (value) { + if (!$sce) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot find $sce service.'); + } + return $sce.trustAsHtml(value); + }; + + var mapInterpolationParameters = function (value, iteratee, stack) { + if (angular.isDate(value)) { + return value; + } else if (angular.isObject(value)) { + var result = angular.isArray(value) ? [] : {}; + + if (!stack) { + stack = []; + } else { + if (stack.indexOf(value) > -1) { + throw new Error('pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object'); + } + } + + stack.push(value); + angular.forEach(value, function (propertyValue, propertyKey) { + + /* Skipping function properties. */ + if (angular.isFunction(propertyValue)) { + return; + } + + result[propertyKey] = mapInterpolationParameters(propertyValue, iteratee, stack); + }); + stack.splice(-1, 1); // remove last + + return result; + } else if (angular.isNumber(value)) { + return value; + } else if (!angular.isUndefined(value) && value !== null) { + return iteratee(value); + } else { + return value; + } + }; +} + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateProvider + * @description + * + * $translateProvider allows developers to register translation-tables, asynchronous loaders + * and similar to configure translation behavior directly inside of a module. + * + */ +angular.module('pascalprecht.translate') + .constant('pascalprechtTranslateOverrider', {}) + .provider('$translate', $translate); + +function $translate($STORAGE_KEY, $windowProvider, $translateSanitizationProvider, pascalprechtTranslateOverrider) { + + 'use strict'; + + var $translationTable = {}, + $preferredLanguage, + $availableLanguageKeys = [], + $languageKeyAliases, + $fallbackLanguage, + $fallbackWasString, + $uses, + $nextLang, + $storageFactory, + $storageKey = $STORAGE_KEY, + $storagePrefix, + $missingTranslationHandlerFactory, + $interpolationFactory, + $interpolatorFactories = [], + $loaderFactory, + $cloakClassName = 'translate-cloak', + $loaderOptions, + $notFoundIndicatorLeft, + $notFoundIndicatorRight, + $postCompilingEnabled = false, + $forceAsyncReloadEnabled = false, + $nestedObjectDelimeter = '.', + $isReady = false, + $keepContent = false, + loaderCache, + directivePriority = 0, + statefulFilter = true, + postProcessFn, + uniformLanguageTagResolver = 'default', + languageTagResolver = { + 'default' : function (tag) { + return (tag || '').split('-').join('_'); + }, + java : function (tag) { + var temp = (tag || '').split('-').join('_'); + var parts = temp.split('_'); + return parts.length > 1 ? (parts[0].toLowerCase() + '_' + parts[1].toUpperCase()) : temp; + }, + bcp47 : function (tag) { + var temp = (tag || '').split('_').join('-'); + var parts = temp.split('-'); + return parts.length > 1 ? (parts[0].toLowerCase() + '-' + parts[1].toUpperCase()) : temp; + }, + 'iso639-1' : function (tag) { + var temp = (tag || '').split('_').join('-'); + var parts = temp.split('-'); + return parts[0].toLowerCase(); + } + }; + + var version = '2.15.1'; + + // tries to determine the browsers language + var getFirstBrowserLanguage = function () { + + // internal purpose only + if (angular.isFunction(pascalprechtTranslateOverrider.getLocale)) { + return pascalprechtTranslateOverrider.getLocale(); + } + + var nav = $windowProvider.$get().navigator, + browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage'], + i, + language; + + // support for HTML 5.1 "navigator.languages" + if (angular.isArray(nav.languages)) { + for (i = 0; i < nav.languages.length; i++) { + language = nav.languages[i]; + if (language && language.length) { + return language; + } + } + } + + // support for other well known properties in browsers + for (i = 0; i < browserLanguagePropertyKeys.length; i++) { + language = nav[browserLanguagePropertyKeys[i]]; + if (language && language.length) { + return language; + } + } + + return null; + }; + getFirstBrowserLanguage.displayName = 'angular-translate/service: getFirstBrowserLanguage'; + + // tries to determine the browsers locale + var getLocale = function () { + var locale = getFirstBrowserLanguage() || ''; + if (languageTagResolver[uniformLanguageTagResolver]) { + locale = languageTagResolver[uniformLanguageTagResolver](locale); + } + return locale; + }; + getLocale.displayName = 'angular-translate/service: getLocale'; + + /** + * @name indexOf + * @private + * + * @description + * indexOf polyfill. Kinda sorta. + * + * @param {array} array Array to search in. + * @param {string} searchElement Element to search for. + * + * @returns {int} Index of search element. + */ + var indexOf = function (array, searchElement) { + for (var i = 0, len = array.length; i < len; i++) { + if (array[i] === searchElement) { + return i; + } + } + return -1; + }; + + /** + * @name trim + * @private + * + * @description + * trim polyfill + * + * @returns {string} The string stripped of whitespace from both ends + */ + var trim = function () { + return this.toString().replace(/^\s+|\s+$/g, ''); + }; + + var negotiateLocale = function (preferred) { + if (!preferred) { + return; + } + + var avail = [], + locale = angular.lowercase(preferred), + i = 0, + n = $availableLanguageKeys.length; + + for (; i < n; i++) { + avail.push(angular.lowercase($availableLanguageKeys[i])); + } + + // Check for an exact match in our list of available keys + if (indexOf(avail, locale) > -1) { + return preferred; + } + + if ($languageKeyAliases) { + var alias; + for (var langKeyAlias in $languageKeyAliases) { + if ($languageKeyAliases.hasOwnProperty(langKeyAlias)) { + var hasWildcardKey = false; + var hasExactKey = Object.prototype.hasOwnProperty.call($languageKeyAliases, langKeyAlias) && + angular.lowercase(langKeyAlias) === angular.lowercase(preferred); + + if (langKeyAlias.slice(-1) === '*') { + hasWildcardKey = langKeyAlias.slice(0, -1) === preferred.slice(0, langKeyAlias.length - 1); + } + if (hasExactKey || hasWildcardKey) { + alias = $languageKeyAliases[langKeyAlias]; + if (indexOf(avail, angular.lowercase(alias)) > -1) { + return alias; + } + } + } + } + } + + // Check for a language code without region + var parts = preferred.split('_'); + + if (parts.length > 1 && indexOf(avail, angular.lowercase(parts[0])) > -1) { + return parts[0]; + } + + // If everything fails, return undefined. + return; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#translations + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a new translation table for specific language key. + * + * To register a translation table for specific language, pass a defined language + * key as first parameter. + * + *
    +   *  // register translation table for language: 'de_DE'
    +   *  $translateProvider.translations('de_DE', {
    +   *    'GREETING': 'Hallo Welt!'
    +   *  });
    +   *
    +   *  // register another one
    +   *  $translateProvider.translations('en_US', {
    +   *    'GREETING': 'Hello world!'
    +   *  });
    +   * 
    + * + * When registering multiple translation tables for for the same language key, + * the actual translation table gets extended. This allows you to define module + * specific translation which only get added, once a specific module is loaded in + * your app. + * + * Invoking this method with no arguments returns the translation table which was + * registered with no language key. Invoking it with a language key returns the + * related translation table. + * + * @param {string} langKey A language key. + * @param {object} translationTable A plain old JavaScript object that represents a translation table. + * + */ + var translations = function (langKey, translationTable) { + + if (!langKey && !translationTable) { + return $translationTable; + } + + if (langKey && !translationTable) { + if (angular.isString(langKey)) { + return $translationTable[langKey]; + } + } else { + if (!angular.isObject($translationTable[langKey])) { + $translationTable[langKey] = {}; + } + angular.extend($translationTable[langKey], flatObject(translationTable)); + } + return this; + }; + + this.translations = translations; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#cloakClassName + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * + * Let's you change the class name for `translate-cloak` directive. + * Default class name is `translate-cloak`. + * + * @param {string} name translate-cloak class name + */ + this.cloakClassName = function (name) { + if (!name) { + return $cloakClassName; + } + $cloakClassName = name; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#nestedObjectDelimeter + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * + * Let's you change the delimiter for namespaced translations. + * Default delimiter is `.`. + * + * @param {string} delimiter namespace separator + */ + this.nestedObjectDelimeter = function (delimiter) { + if (!delimiter) { + return $nestedObjectDelimeter; + } + $nestedObjectDelimeter = delimiter; + return this; + }; + + /** + * @name flatObject + * @private + * + * @description + * Flats an object. This function is used to flatten given translation data with + * namespaces, so they are later accessible via dot notation. + */ + var flatObject = function (data, path, result, prevKey) { + var key, keyWithPath, keyWithShortPath, val; + + if (!path) { + path = []; + } + if (!result) { + result = {}; + } + for (key in data) { + if (!Object.prototype.hasOwnProperty.call(data, key)) { + continue; + } + val = data[key]; + if (angular.isObject(val)) { + flatObject(val, path.concat(key), result, key); + } else { + keyWithPath = path.length ? ('' + path.join($nestedObjectDelimeter) + $nestedObjectDelimeter + key) : key; + if (path.length && key === prevKey) { + // Create shortcut path (foo.bar == foo.bar.bar) + keyWithShortPath = '' + path.join($nestedObjectDelimeter); + // Link it to original path + result[keyWithShortPath] = '@:' + keyWithPath; + } + result[keyWithPath] = val; + } + } + return result; + }; + flatObject.displayName = 'flatObject'; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#addInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Adds interpolation services to angular-translate, so it can manage them. + * + * @param {object} factory Interpolation service factory + */ + this.addInterpolation = function (factory) { + $interpolatorFactories.push(factory); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMessageFormatInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use interpolation functionality of messageformat.js. + * This is useful when having high level pluralization and gender selection. + */ + this.useMessageFormatInterpolation = function () { + return this.useInterpolation('$translateMessageFormatInterpolation'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useInterpolation + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate which interpolation style to use as default, application-wide. + * Simply pass a factory/service name. The interpolation service has to implement + * the correct interface. + * + * @param {string} factory Interpolation service name. + */ + this.useInterpolation = function (factory) { + $interpolationFactory = factory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useSanitizeStrategy + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Simply sets a sanitation strategy type. + * + * @param {string} value Strategy type. + */ + this.useSanitizeValueStrategy = function (value) { + $translateSanitizationProvider.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#preferredLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which of the registered translation tables to use for translation + * at initial startup by passing a language key. Similar to `$translateProvider#use` + * only that it says which language to **prefer**. + * + * @param {string} langKey A language key. + */ + this.preferredLanguage = function (langKey) { + if (langKey) { + setupPreferredLanguage(langKey); + return this; + } + return $preferredLanguage; + }; + var setupPreferredLanguage = function (langKey) { + if (langKey) { + $preferredLanguage = langKey; + } + return $preferredLanguage; + }; + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicator + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found. E.g. when + * setting the indicator as 'X' and one tries to translate a translation id + * called `NOT_FOUND`, this will result in `X NOT_FOUND X`. + * + * Internally this methods sets a left indicator and a right indicator using + * `$translateProvider.translationNotFoundIndicatorLeft()` and + * `$translateProvider.translationNotFoundIndicatorRight()`. + * + * **Note**: These methods automatically add a whitespace between the indicators + * and the translation id. + * + * @param {string} indicator An indicator, could be any string. + */ + this.translationNotFoundIndicator = function (indicator) { + this.translationNotFoundIndicatorLeft(indicator); + this.translationNotFoundIndicatorRight(indicator); + return this; + }; + + /** + * ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found left to the + * translation id. + * + * @param {string} indicator An indicator. + */ + this.translationNotFoundIndicatorLeft = function (indicator) { + if (!indicator) { + return $notFoundIndicatorLeft; + } + $notFoundIndicatorLeft = indicator; + return this; + }; + + /** + * ngdoc function + * @name pascalprecht.translate.$translateProvider#translationNotFoundIndicatorLeft + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets an indicator which is used when a translation isn't found right to the + * translation id. + * + * @param {string} indicator An indicator. + */ + this.translationNotFoundIndicatorRight = function (indicator) { + if (!indicator) { + return $notFoundIndicatorRight; + } + $notFoundIndicatorRight = indicator; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#fallbackLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which of the registered translation tables to use when missing translations + * at initial startup by passing a language key. Similar to `$translateProvider#use` + * only that it says which language to **fallback**. + * + * @param {string||array} langKey A language key. + * + */ + this.fallbackLanguage = function (langKey) { + fallbackStack(langKey); + return this; + }; + + var fallbackStack = function (langKey) { + if (langKey) { + if (angular.isString(langKey)) { + $fallbackWasString = true; + $fallbackLanguage = [langKey]; + } else if (angular.isArray(langKey)) { + $fallbackWasString = false; + $fallbackLanguage = langKey; + } + if (angular.isString($preferredLanguage) && indexOf($fallbackLanguage, $preferredLanguage) < 0) { + $fallbackLanguage.push($preferredLanguage); + } + + return this; + } else { + if ($fallbackWasString) { + return $fallbackLanguage[0]; + } else { + return $fallbackLanguage; + } + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#use + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Set which translation table to use for translation by given language key. When + * trying to 'use' a language which isn't provided, it'll throw an error. + * + * You actually don't have to use this method since `$translateProvider#preferredLanguage` + * does the job too. + * + * @param {string} langKey A language key. + */ + this.use = function (langKey) { + if (langKey) { + if (!$translationTable[langKey] && (!$loaderFactory)) { + // only throw an error, when not loading translation data asynchronously + throw new Error('$translateProvider couldn\'t find translationTable for langKey: \'' + langKey + '\''); + } + $uses = langKey; + return this; + } + return $uses; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#resolveClientLocale + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver. + * + * @returns {string} the current client/browser language key + */ + this.resolveClientLocale = function () { + return getLocale(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#storageKey + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells the module which key must represent the choosed language by a user in the storage. + * + * @param {string} key A key for the storage. + */ + var storageKey = function (key) { + if (!key) { + if ($storagePrefix) { + return $storagePrefix + $storageKey; + } + return $storageKey; + } + $storageKey = key; + return this; + }; + + this.storageKey = storageKey; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useUrlLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateUrlLoader` extension service as loader. + * + * @param {string} url Url + * @param {Object=} options Optional configuration object + */ + this.useUrlLoader = function (url, options) { + return this.useLoader('$translateUrlLoader', angular.extend({url : url}, options)); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader. + * + * @param {Object=} options Optional configuration object + */ + this.useStaticFilesLoader = function (options) { + return this.useLoader('$translateStaticFilesLoader', options); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLoader + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use any other service as loader. + * + * @param {string} loaderFactory Factory name to use + * @param {Object=} options Optional configuration object + */ + this.useLoader = function (loaderFactory, options) { + $loaderFactory = loaderFactory; + $loaderOptions = options || {}; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLocalStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateLocalStorage` service as storage layer. + * + */ + this.useLocalStorage = function () { + return this.useStorage('$translateLocalStorage'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useCookieStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use `$translateCookieStorage` service as storage layer. + */ + this.useCookieStorage = function () { + return this.useStorage('$translateCookieStorage'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useStorage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use custom service as storage layer. + */ + this.useStorage = function (storageFactory) { + $storageFactory = storageFactory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#storagePrefix + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets prefix for storage key. + * + * @param {string} prefix Storage key prefix + */ + this.storagePrefix = function (prefix) { + if (!prefix) { + return prefix; + } + $storagePrefix = prefix; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandlerLog + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to use built-in log handler when trying to translate + * a translation Id which doesn't exist. + * + * This is actually a shortcut method for `useMissingTranslationHandler()`. + * + */ + this.useMissingTranslationHandlerLog = function () { + return this.useMissingTranslationHandler('$translateMissingTranslationHandlerLog'); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useMissingTranslationHandler + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Expects a factory name which later gets instantiated with `$injector`. + * This method can be used to tell angular-translate to use a custom + * missingTranslationHandler. Just build a factory which returns a function + * and expects a translation id as argument. + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.useMissingTranslationHandler('customHandler');
    +   *  });
    +   *
    +   *  app.factory('customHandler', function (dep1, dep2) {
    +   *    return function (translationId) {
    +   *      // something with translationId and dep1 and dep2
    +   *    };
    +   *  });
    +   * 
    + * + * @param {string} factory Factory name + */ + this.useMissingTranslationHandler = function (factory) { + $missingTranslationHandlerFactory = factory; + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#usePostCompiling + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If post compiling is enabled, all translated values will be processed + * again with AngularJS' $compile. + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.usePostCompiling(true);
    +   *  });
    +   * 
    + * + * @param {string} factory Factory name + */ + this.usePostCompiling = function (value) { + $postCompilingEnabled = !(!value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#forceAsyncReload + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If force async reload is enabled, async loader will always be called + * even if $translationTable already contains the language key, adding + * possible new entries to the $translationTable. + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.forceAsyncReload(true);
    +   *  });
    +   * 
    + * + * @param {boolean} value - valid values are true or false + */ + this.forceAsyncReload = function (value) { + $forceAsyncReloadEnabled = !(!value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#uniformLanguageTag + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate which language tag should be used as a result when determining + * the current browser language. + * + * This setting must be set before invoking {@link pascalprecht.translate.$translateProvider#methods_determinePreferredLanguage determinePreferredLanguage()}. + * + *
    +   * $translateProvider
    +   *   .uniformLanguageTag('bcp47')
    +   *   .determinePreferredLanguage()
    +   * 
    + * + * The resolver currently supports: + * * default + * (traditionally: hyphens will be converted into underscores, i.e. en-US => en_US) + * en-US => en_US + * en_US => en_US + * en-us => en_us + * * java + * like default, but the second part will be always in uppercase + * en-US => en_US + * en_US => en_US + * en-us => en_US + * * BCP 47 (RFC 4646 & 4647) + * en-US => en-US + * en_US => en-US + * en-us => en-US + * + * See also: + * * http://en.wikipedia.org/wiki/IETF_language_tag + * * http://www.w3.org/International/core/langtags/ + * * http://tools.ietf.org/html/bcp47 + * + * @param {string|object} options - options (or standard) + * @param {string} options.standard - valid values are 'default', 'bcp47', 'java' + */ + this.uniformLanguageTag = function (options) { + + if (!options) { + options = {}; + } else if (angular.isString(options)) { + options = { + standard : options + }; + } + + uniformLanguageTagResolver = options.standard; + + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#determinePreferredLanguage + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Tells angular-translate to try to determine on its own which language key + * to set as preferred language. When `fn` is given, angular-translate uses it + * to determine a language key, otherwise it uses the built-in `getLocale()` + * method. + * + * The `getLocale()` returns a language key in the format `[lang]_[country]` or + * `[lang]` depending on what the browser provides. + * + * Use this method at your own risk, since not all browsers return a valid + * locale (see {@link pascalprecht.translate.$translateProvider#methods_uniformLanguageTag uniformLanguageTag()}). + * + * @param {Function=} fn Function to determine a browser's locale + */ + this.determinePreferredLanguage = function (fn) { + + var locale = (fn && angular.isFunction(fn)) ? fn() : getLocale(); + + if (!$availableLanguageKeys.length) { + $preferredLanguage = locale; + } else { + $preferredLanguage = negotiateLocale(locale) || locale; + } + + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#registerAvailableLanguageKeys + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a set of language keys the app will work with. Use this method in + * combination with + * {@link pascalprecht.translate.$translateProvider#determinePreferredLanguage determinePreferredLanguage}. + * When available languages keys are registered, angular-translate + * tries to find the best fitting language key depending on the browsers locale, + * considering your language key convention. + * + * @param {object} languageKeys Array of language keys the your app will use + * @param {object=} aliases Alias map. + */ + this.registerAvailableLanguageKeys = function (languageKeys, aliases) { + if (languageKeys) { + $availableLanguageKeys = languageKeys; + if (aliases) { + $languageKeyAliases = aliases; + } + return this; + } + return $availableLanguageKeys; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#useLoaderCache + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Registers a cache for internal $http based loaders. + * {@link pascalprecht.translate.$translationCache $translationCache}. + * When false the cache will be disabled (default). When true or undefined + * the cache will be a default (see $cacheFactory). When an object it will + * be treat as a cache object itself: the usage is $http({cache: cache}) + * + * @param {object} cache boolean, string or cache-object + */ + this.useLoaderCache = function (cache) { + if (cache === false) { + // disable cache + loaderCache = undefined; + } else if (cache === true) { + // enable cache using AJS defaults + loaderCache = true; + } else if (typeof(cache) === 'undefined') { + // enable cache using default + loaderCache = '$translationCache'; + } else if (cache) { + // enable cache using given one (see $cacheFactory) + loaderCache = cache; + } + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#directivePriority + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Sets the default priority of the translate directive. The standard value is `0`. + * Calling this function without an argument will return the current value. + * + * @param {number} priority for the translate-directive + */ + this.directivePriority = function (priority) { + if (priority === undefined) { + // getter + return directivePriority; + } else { + // setter with chaining + directivePriority = priority; + return this; + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#statefulFilter + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * Since AngularJS 1.3, filters which are not stateless (depending at the scope) + * have to explicit define this behavior. + * Sets whether the translate filter should be stateful or stateless. The standard value is `true` + * meaning being stateful. + * Calling this function without an argument will return the current value. + * + * @param {boolean} state - defines the state of the filter + */ + this.statefulFilter = function (state) { + if (state === undefined) { + // getter + return statefulFilter; + } else { + // setter with chaining + statefulFilter = state; + return this; + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#postProcess + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * The post processor will be intercept right after the translation result. It can modify the result. + * + * @param {object} fn Function or service name (string) to be called after the translation value has been set / resolved. The function itself will enrich every value being processed and then continue the normal resolver process + */ + this.postProcess = function (fn) { + if (fn) { + postProcessFn = fn; + } else { + postProcessFn = undefined; + } + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateProvider#keepContent + * @methodOf pascalprecht.translate.$translateProvider + * + * @description + * If keepContent is set to true than translate directive will always use innerHTML + * as a default translation + * + * Example: + *
    +   *  app.config(function ($translateProvider) {
    +   *    $translateProvider.keepContent(true);
    +   *  });
    +   * 
    + * + * @param {boolean} value - valid values are true or false + */ + this.keepContent = function (value) { + $keepContent = !(!value); + return this; + }; + + /** + * @ngdoc object + * @name pascalprecht.translate.$translate + * @requires $interpolate + * @requires $log + * @requires $rootScope + * @requires $q + * + * @description + * The `$translate` service is the actual core of angular-translate. It expects a translation id + * and optional interpolate parameters to translate contents. + * + *
    +   *  $translate('HEADLINE_TEXT').then(function (translation) {
    +   *    $scope.translatedText = translation;
    +   *  });
    +   * 
    + * + * @param {string|array} translationId A token which represents a translation id + * This can be optionally an array of translation ids which + * results that the function returns an object where each key + * is the translation id and the value the translation. + * @param {object=} interpolateParams An object hash for dynamic values + * @param {string} interpolationId The id of the interpolation to use + * @param {string} defaultTranslationText the optional default translation text that is written as + * as default text in case it is not found in any configured language + * @param {string} forceLanguage A language to be used instead of the current language + * @returns {object} promise + */ + this.$get = ['$log', '$injector', '$rootScope', '$q', function ($log, $injector, $rootScope, $q) { + + var Storage, + defaultInterpolator = $injector.get($interpolationFactory || '$translateDefaultInterpolation'), + pendingLoader = false, + interpolatorHashMap = {}, + langPromises = {}, + fallbackIndex, + startFallbackIteration; + + var $translate = function (translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage) { + if (!$uses && $preferredLanguage) { + $uses = $preferredLanguage; + } + var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses + (negotiateLocale(forceLanguage) || forceLanguage) : $uses; + + // Check forceLanguage is present + if (forceLanguage) { + loadTranslationsIfMissing(forceLanguage); + } + + // Duck detection: If the first argument is an array, a bunch of translations was requested. + // The result is an object. + if (angular.isArray(translationId)) { + // Inspired by Q.allSettled by Kris Kowal + // https://github.com/kriskowal/q/blob/b0fa72980717dc202ffc3cbf03b936e10ebbb9d7/q.js#L1553-1563 + // This transforms all promises regardless resolved or rejected + var translateAll = function (translationIds) { + var results = {}; // storing the actual results + var promises = []; // promises to wait for + // Wraps the promise a) being always resolved and b) storing the link id->value + var translate = function (translationId) { + var deferred = $q.defer(); + var regardless = function (value) { + results[translationId] = value; + deferred.resolve([translationId, value]); + }; + // we don't care whether the promise was resolved or rejected; just store the values + $translate(translationId, interpolateParams, interpolationId, defaultTranslationText, forceLanguage).then(regardless, regardless); + return deferred.promise; + }; + for (var i = 0, c = translationIds.length; i < c; i++) { + promises.push(translate(translationIds[i])); + } + // wait for all (including storing to results) + return $q.all(promises).then(function () { + // return the results + return results; + }); + }; + return translateAll(translationId); + } + + var deferred = $q.defer(); + + // trim off any whitespace + if (translationId) { + translationId = trim.apply(translationId); + } + + var promiseToWaitFor = (function () { + var promise = $preferredLanguage ? + langPromises[$preferredLanguage] : + langPromises[uses]; + + fallbackIndex = 0; + + if ($storageFactory && !promise) { + // looks like there's no pending promise for $preferredLanguage or + // $uses. Maybe there's one pending for a language that comes from + // storage. + var langKey = Storage.get($storageKey); + promise = langPromises[langKey]; + + if ($fallbackLanguage && $fallbackLanguage.length) { + var index = indexOf($fallbackLanguage, langKey); + // maybe the language from storage is also defined as fallback language + // we increase the fallback language index to not search in that language + // as fallback, since it's probably the first used language + // in that case the index starts after the first element + fallbackIndex = (index === 0) ? 1 : 0; + + // but we can make sure to ALWAYS fallback to preferred language at least + if (indexOf($fallbackLanguage, $preferredLanguage) < 0) { + $fallbackLanguage.push($preferredLanguage); + } + } + } + return promise; + }()); + + if (!promiseToWaitFor) { + // no promise to wait for? okay. Then there's no loader registered + // nor is a one pending for language that comes from storage. + // We can just translate. + determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject); + } else { + var promiseResolved = function () { + // $uses may have changed while waiting + if (!forceLanguage) { + uses = $uses; + } + determineTranslation(translationId, interpolateParams, interpolationId, defaultTranslationText, uses).then(deferred.resolve, deferred.reject); + }; + promiseResolved.displayName = 'promiseResolved'; + + promiseToWaitFor['finally'](promiseResolved) + .catch(angular.noop); // we don't care about errors here, already handled + } + return deferred.promise; + }; + + /** + * @name applyNotFoundIndicators + * @private + * + * @description + * Applies not fount indicators to given translation id, if needed. + * This function gets only executed, if a translation id doesn't exist, + * which is why a translation id is expected as argument. + * + * @param {string} translationId Translation id. + * @returns {string} Same as given translation id but applied with not found + * indicators. + */ + var applyNotFoundIndicators = function (translationId) { + // applying notFoundIndicators + if ($notFoundIndicatorLeft) { + translationId = [$notFoundIndicatorLeft, translationId].join(' '); + } + if ($notFoundIndicatorRight) { + translationId = [translationId, $notFoundIndicatorRight].join(' '); + } + return translationId; + }; + + /** + * @name useLanguage + * @private + * + * @description + * Makes actual use of a language by setting a given language key as used + * language and informs registered interpolators to also use the given + * key as locale. + * + * @param {string} key Locale key. + */ + var useLanguage = function (key) { + $uses = key; + + // make sure to store new language key before triggering success event + if ($storageFactory) { + Storage.put($translate.storageKey(), $uses); + } + + $rootScope.$emit('$translateChangeSuccess', {language : key}); + + // inform default interpolator + defaultInterpolator.setLocale($uses); + + var eachInterpolator = function (interpolator, id) { + interpolatorHashMap[id].setLocale($uses); + }; + eachInterpolator.displayName = 'eachInterpolatorLocaleSetter'; + + // inform all others too! + angular.forEach(interpolatorHashMap, eachInterpolator); + $rootScope.$emit('$translateChangeEnd', {language : key}); + }; + + /** + * @name loadAsync + * @private + * + * @description + * Kicks off registered async loader using `$injector` and applies existing + * loader options. When resolved, it updates translation tables accordingly + * or rejects with given language key. + * + * @param {string} key Language key. + * @return {Promise} A promise. + */ + var loadAsync = function (key) { + if (!key) { + throw 'No language key specified for loading.'; + } + + var deferred = $q.defer(); + + $rootScope.$emit('$translateLoadingStart', {language : key}); + pendingLoader = true; + + var cache = loaderCache; + if (typeof(cache) === 'string') { + // getting on-demand instance of loader + cache = $injector.get(cache); + } + + var loaderOptions = angular.extend({}, $loaderOptions, { + key : key, + $http : angular.extend({}, { + cache : cache + }, $loaderOptions.$http) + }); + + var onLoaderSuccess = function (data) { + var translationTable = {}; + $rootScope.$emit('$translateLoadingSuccess', {language : key}); + + if (angular.isArray(data)) { + angular.forEach(data, function (table) { + angular.extend(translationTable, flatObject(table)); + }); + } else { + angular.extend(translationTable, flatObject(data)); + } + pendingLoader = false; + deferred.resolve({ + key : key, + table : translationTable + }); + $rootScope.$emit('$translateLoadingEnd', {language : key}); + }; + onLoaderSuccess.displayName = 'onLoaderSuccess'; + + var onLoaderError = function (key) { + $rootScope.$emit('$translateLoadingError', {language : key}); + deferred.reject(key); + $rootScope.$emit('$translateLoadingEnd', {language : key}); + }; + onLoaderError.displayName = 'onLoaderError'; + + $injector.get($loaderFactory)(loaderOptions) + .then(onLoaderSuccess, onLoaderError); + + return deferred.promise; + }; + + if ($storageFactory) { + Storage = $injector.get($storageFactory); + + if (!Storage.get || !Storage.put) { + throw new Error('Couldn\'t use storage \'' + $storageFactory + '\', missing get() or put() method!'); + } + } + + // if we have additional interpolations that were added via + // $translateProvider.addInterpolation(), we have to map'em + if ($interpolatorFactories.length) { + var eachInterpolationFactory = function (interpolatorFactory) { + var interpolator = $injector.get(interpolatorFactory); + // setting initial locale for each interpolation service + interpolator.setLocale($preferredLanguage || $uses); + // make'em recognizable through id + interpolatorHashMap[interpolator.getInterpolationIdentifier()] = interpolator; + }; + eachInterpolationFactory.displayName = 'interpolationFactoryAdder'; + + angular.forEach($interpolatorFactories, eachInterpolationFactory); + } + + /** + * @name getTranslationTable + * @private + * + * @description + * Returns a promise that resolves to the translation table + * or is rejected if an error occurred. + * + * @param langKey + * @returns {Q.promise} + */ + var getTranslationTable = function (langKey) { + var deferred = $q.defer(); + if (Object.prototype.hasOwnProperty.call($translationTable, langKey)) { + deferred.resolve($translationTable[langKey]); + } else if (langPromises[langKey]) { + var onResolve = function (data) { + translations(data.key, data.table); + deferred.resolve(data.table); + }; + onResolve.displayName = 'translationTableResolver'; + langPromises[langKey].then(onResolve, deferred.reject); + } else { + deferred.reject(); + } + return deferred.promise; + }; + + /** + * @name getFallbackTranslation + * @private + * + * @description + * Returns a promise that will resolve to the translation + * or be rejected if no translation was found for the language. + * This function is currently only used for fallback language translation. + * + * @param langKey The language to translate to. + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {Q.promise} + */ + var getFallbackTranslation = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var deferred = $q.defer(); + + var onResolve = function (translationTable) { + if (Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) { + Interpolator.setLocale(langKey); + var translation = translationTable[translationId]; + if (translation.substr(0, 2) === '@:') { + getFallbackTranslation(langKey, translation.substr(2), interpolateParams, Interpolator, sanitizeStrategy) + .then(deferred.resolve, deferred.reject); + } else { + var interpolatedValue = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'service', sanitizeStrategy, translationId); + interpolatedValue = applyPostProcessing(translationId, translationTable[translationId], interpolatedValue, interpolateParams, langKey); + + deferred.resolve(interpolatedValue); + + } + Interpolator.setLocale($uses); + } else { + deferred.reject(); + } + }; + onResolve.displayName = 'fallbackTranslationResolver'; + + getTranslationTable(langKey).then(onResolve, deferred.reject); + + return deferred.promise; + }; + + /** + * @name getFallbackTranslationInstant + * @private + * + * @description + * Returns a translation + * This function is currently only used for fallback language translation. + * + * @param langKey The language to translate to. + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy sanitize strategy override + * + * @returns {string} translation + */ + var getFallbackTranslationInstant = function (langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var result, translationTable = $translationTable[langKey]; + + if (translationTable && Object.prototype.hasOwnProperty.call(translationTable, translationId) && translationTable[translationId] !== null) { + Interpolator.setLocale(langKey); + result = Interpolator.interpolate(translationTable[translationId], interpolateParams, 'filter', sanitizeStrategy, translationId); + result = applyPostProcessing(translationId, translationTable[translationId], result, interpolateParams, langKey, sanitizeStrategy); + // workaround for TrustedValueHolderType + if (!angular.isString(result) && angular.isFunction(result.$$unwrapTrustedValue)) { + var result2 = result.$$unwrapTrustedValue(); + if (result2.substr(0, 2) === '@:') { + return getFallbackTranslationInstant(langKey, result2.substr(2), interpolateParams, Interpolator, sanitizeStrategy); + } + } else if (result.substr(0, 2) === '@:') { + return getFallbackTranslationInstant(langKey, result.substr(2), interpolateParams, Interpolator, sanitizeStrategy); + } + Interpolator.setLocale($uses); + } + + return result; + }; + + + /** + * @name translateByHandler + * @private + * + * Translate by missing translation handler. + * + * @param translationId + * @param interpolateParams + * @param defaultTranslationText + * @param sanitizeStrategy sanitize strategy override + * + * @returns translation created by $missingTranslationHandler or translationId is $missingTranslationHandler is + * absent + */ + var translateByHandler = function (translationId, interpolateParams, defaultTranslationText, sanitizeStrategy) { + // If we have a handler factory - we might also call it here to determine if it provides + // a default text for a translationid that can't be found anywhere in our tables + if ($missingTranslationHandlerFactory) { + return $injector.get($missingTranslationHandlerFactory)(translationId, $uses, interpolateParams, defaultTranslationText, sanitizeStrategy); + } else { + return translationId; + } + }; + + /** + * @name resolveForFallbackLanguage + * @private + * + * Recursive helper function for fallbackTranslation that will sequentially look + * for a translation in the fallbackLanguages starting with fallbackLanguageIndex. + * + * @param fallbackLanguageIndex + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param defaultTranslationText + * @param sanitizeStrategy + * @returns {Q.promise} Promise that will resolve to the translation. + */ + var resolveForFallbackLanguage = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) { + var deferred = $q.defer(); + + if (fallbackLanguageIndex < $fallbackLanguage.length) { + var langKey = $fallbackLanguage[fallbackLanguageIndex]; + getFallbackTranslation(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy).then( + function (data) { + deferred.resolve(data); + }, + function () { + // Look in the next fallback language for a translation. + // It delays the resolving by passing another promise to resolve. + return resolveForFallbackLanguage(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy).then(deferred.resolve, deferred.reject); + } + ); + } else { + // No translation found in any fallback language + // if a default translation text is set in the directive, then return this as a result + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + var missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText); + + // if no default translation is set and an error handler is defined, send it to the handler + // and then return the result if it isn't undefined + if ($missingTranslationHandlerFactory && missingTranslationHandlerTranslation) { + deferred.resolve(missingTranslationHandlerTranslation); + } else { + deferred.reject(applyNotFoundIndicators(translationId)); + } + } + } + return deferred.promise; + }; + + /** + * @name resolveForFallbackLanguageInstant + * @private + * + * Recursive helper function for fallbackTranslation that will sequentially look + * for a translation in the fallbackLanguages starting with fallbackLanguageIndex. + * + * @param fallbackLanguageIndex + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {string} translation + */ + var resolveForFallbackLanguageInstant = function (fallbackLanguageIndex, translationId, interpolateParams, Interpolator, sanitizeStrategy) { + var result; + + if (fallbackLanguageIndex < $fallbackLanguage.length) { + var langKey = $fallbackLanguage[fallbackLanguageIndex]; + result = getFallbackTranslationInstant(langKey, translationId, interpolateParams, Interpolator, sanitizeStrategy); + if (!result && result !== '') { + result = resolveForFallbackLanguageInstant(fallbackLanguageIndex + 1, translationId, interpolateParams, Interpolator); + } + } + return result; + }; + + /** + * Translates with the usage of the fallback languages. + * + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param defaultTranslationText + * @param sanitizeStrategy + * @returns {Q.promise} Promise, that resolves to the translation. + */ + var fallbackTranslation = function (translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) { + // Start with the fallbackLanguage with index 0 + return resolveForFallbackLanguage((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy); + }; + + /** + * Translates with the usage of the fallback languages. + * + * @param translationId + * @param interpolateParams + * @param Interpolator + * @param sanitizeStrategy + * @returns {String} translation + */ + var fallbackTranslationInstant = function (translationId, interpolateParams, Interpolator, sanitizeStrategy) { + // Start with the fallbackLanguage with index 0 + return resolveForFallbackLanguageInstant((startFallbackIteration > 0 ? startFallbackIteration : fallbackIndex), translationId, interpolateParams, Interpolator, sanitizeStrategy); + }; + + var determineTranslation = function (translationId, interpolateParams, interpolationId, defaultTranslationText, uses, sanitizeStrategy) { + + var deferred = $q.defer(); + + var table = uses ? $translationTable[uses] : $translationTable, + Interpolator = (interpolationId) ? interpolatorHashMap[interpolationId] : defaultInterpolator; + + // if the translation id exists, we can just interpolate it + if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) { + var translation = table[translationId]; + + // If using link, rerun $translate with linked translationId and return it + if (translation.substr(0, 2) === '@:') { + + $translate(translation.substr(2), interpolateParams, interpolationId, defaultTranslationText, uses) + .then(deferred.resolve, deferred.reject); + } else { + // + var resolvedTranslation = Interpolator.interpolate(translation, interpolateParams, 'service', sanitizeStrategy, translationId); + resolvedTranslation = applyPostProcessing(translationId, translation, resolvedTranslation, interpolateParams, uses); + deferred.resolve(resolvedTranslation); + } + } else { + var missingTranslationHandlerTranslation; + // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, defaultTranslationText); + } + + // since we couldn't translate the inital requested translation id, + // we try it now with one or more fallback languages, if fallback language(s) is + // configured. + if (uses && $fallbackLanguage && $fallbackLanguage.length) { + fallbackTranslation(translationId, interpolateParams, Interpolator, defaultTranslationText, sanitizeStrategy) + .then(function (translation) { + deferred.resolve(translation); + }, function (_translationId) { + deferred.reject(applyNotFoundIndicators(_translationId)); + }); + } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + deferred.resolve(missingTranslationHandlerTranslation); + } + } else { + if (defaultTranslationText) { + deferred.resolve(defaultTranslationText); + } else { + deferred.reject(applyNotFoundIndicators(translationId)); + } + } + } + return deferred.promise; + }; + + var determineTranslationInstant = function (translationId, interpolateParams, interpolationId, uses, sanitizeStrategy) { + + var result, table = uses ? $translationTable[uses] : $translationTable, + Interpolator = defaultInterpolator; + + // if the interpolation id exists use custom interpolator + if (interpolatorHashMap && Object.prototype.hasOwnProperty.call(interpolatorHashMap, interpolationId)) { + Interpolator = interpolatorHashMap[interpolationId]; + } + + // if the translation id exists, we can just interpolate it + if (table && Object.prototype.hasOwnProperty.call(table, translationId) && table[translationId] !== null) { + var translation = table[translationId]; + + // If using link, rerun $translate with linked translationId and return it + if (translation.substr(0, 2) === '@:') { + result = determineTranslationInstant(translation.substr(2), interpolateParams, interpolationId, uses, sanitizeStrategy); + } else { + result = Interpolator.interpolate(translation, interpolateParams, 'filter', sanitizeStrategy, translationId); + result = applyPostProcessing(translationId, translation, result, interpolateParams, uses, sanitizeStrategy); + } + } else { + var missingTranslationHandlerTranslation; + // for logging purposes only (as in $translateMissingTranslationHandlerLog), value is not returned to promise + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy); + } + + // since we couldn't translate the inital requested translation id, + // we try it now with one or more fallback languages, if fallback language(s) is + // configured. + if (uses && $fallbackLanguage && $fallbackLanguage.length) { + fallbackIndex = 0; + result = fallbackTranslationInstant(translationId, interpolateParams, Interpolator, sanitizeStrategy); + } else if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + result = missingTranslationHandlerTranslation; + } else { + result = applyNotFoundIndicators(translationId); + } + } + + return result; + }; + + var clearNextLangAndPromise = function (key) { + if ($nextLang === key) { + $nextLang = undefined; + } + langPromises[key] = undefined; + }; + + var applyPostProcessing = function (translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy) { + var fn = postProcessFn; + + if (fn) { + + if (typeof(fn) === 'string') { + // getting on-demand instance + fn = $injector.get(fn); + } + if (fn) { + return fn(translationId, translation, resolvedTranslation, interpolateParams, uses, sanitizeStrategy); + } + } + + return resolvedTranslation; + }; + + var loadTranslationsIfMissing = function (key) { + if (!$translationTable[key] && $loaderFactory && !langPromises[key]) { + langPromises[key] = loadAsync(key).then(function (translation) { + translations(translation.key, translation.table); + return translation; + }); + } + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#preferredLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key for the preferred language. + * + * @param {string} langKey language String or Array to be used as preferredLanguage (changing at runtime) + * + * @return {string} preferred language key + */ + $translate.preferredLanguage = function (langKey) { + if (langKey) { + setupPreferredLanguage(langKey); + } + return $preferredLanguage; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#cloakClassName + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the configured class name for `translate-cloak` directive. + * + * @return {string} cloakClassName + */ + $translate.cloakClassName = function () { + return $cloakClassName; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#nestedObjectDelimeter + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the configured delimiter for nested namespaces. + * + * @return {string} nestedObjectDelimeter + */ + $translate.nestedObjectDelimeter = function () { + return $nestedObjectDelimeter; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#fallbackLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key for the fallback languages or sets a new fallback stack. + * + * @param {string=} langKey language String or Array of fallback languages to be used (to change stack at runtime) + * + * @return {string||array} fallback language key + */ + $translate.fallbackLanguage = function (langKey) { + if (langKey !== undefined && langKey !== null) { + fallbackStack(langKey); + + // as we might have an async loader initiated and a new translation language might have been defined + // we need to add the promise to the stack also. So - iterate. + if ($loaderFactory) { + if ($fallbackLanguage && $fallbackLanguage.length) { + for (var i = 0, len = $fallbackLanguage.length; i < len; i++) { + if (!langPromises[$fallbackLanguage[i]]) { + langPromises[$fallbackLanguage[i]] = loadAsync($fallbackLanguage[i]); + } + } + } + } + $translate.use($translate.use()); + } + if ($fallbackWasString) { + return $fallbackLanguage[0]; + } else { + return $fallbackLanguage; + } + + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#useFallbackLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Sets the first key of the fallback language stack to be used for translation. + * Therefore all languages in the fallback array BEFORE this key will be skipped! + * + * @param {string=} langKey Contains the langKey the iteration shall start with. Set to false if you want to + * get back to the whole stack + */ + $translate.useFallbackLanguage = function (langKey) { + if (langKey !== undefined && langKey !== null) { + if (!langKey) { + startFallbackIteration = 0; + } else { + var langKeyPosition = indexOf($fallbackLanguage, langKey); + if (langKeyPosition > -1) { + startFallbackIteration = langKeyPosition; + } + } + + } + + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#proposedLanguage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the language key of language that is currently loaded asynchronously. + * + * @return {string} language key + */ + $translate.proposedLanguage = function () { + return $nextLang; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#storage + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns registered storage. + * + * @return {object} Storage + */ + $translate.storage = function () { + return Storage; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#negotiateLocale + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns a language key based on available languages and language aliases. If a + * language key cannot be resolved, returns undefined. + * + * If no or a falsy key is given, returns undefined. + * + * @param {string} [key] Language key + * @return {string|undefined} Language key or undefined if no language key is found. + */ + $translate.negotiateLocale = negotiateLocale; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#use + * @methodOf pascalprecht.translate.$translate + * + * @description + * Tells angular-translate which language to use by given language key. This method is + * used to change language at runtime. It also takes care of storing the language + * key in a configured store to let your app remember the choosed language. + * + * When trying to 'use' a language which isn't available it tries to load it + * asynchronously with registered loaders. + * + * Returns promise object with loaded language file data or string of the currently used language. + * + * If no or a falsy key is given it returns the currently used language key. + * The returned string will be ```undefined``` if setting up $translate hasn't finished. + * @example + * $translate.use("en_US").then(function(data){ + * $scope.text = $translate("HELLO"); + * }); + * + * @param {string} [key] Language key + * @return {object|string} Promise with loaded language data or the language key if a falsy param was given. + */ + $translate.use = function (key) { + if (!key) { + return $uses; + } + + var deferred = $q.defer(); + deferred.promise.then(null, angular.noop); // AJS "Possibly unhandled rejection" + + $rootScope.$emit('$translateChangeStart', {language : key}); + + // Try to get the aliased language key + var aliasedKey = negotiateLocale(key); + // Ensure only registered language keys will be loaded + if ($availableLanguageKeys.length > 0 && !aliasedKey) { + return $q.reject(key); + } + + if (aliasedKey) { + key = aliasedKey; + } + + // if there isn't a translation table for the language we've requested, + // we load it asynchronously + $nextLang = key; + if (($forceAsyncReloadEnabled || !$translationTable[key]) && $loaderFactory && !langPromises[key]) { + langPromises[key] = loadAsync(key).then(function (translation) { + translations(translation.key, translation.table); + deferred.resolve(translation.key); + if ($nextLang === key) { + useLanguage(translation.key); + } + return translation; + }, function (key) { + $rootScope.$emit('$translateChangeError', {language : key}); + deferred.reject(key); + $rootScope.$emit('$translateChangeEnd', {language : key}); + return $q.reject(key); + }); + langPromises[key]['finally'](function () { + clearNextLangAndPromise(key); + }).catch(angular.noop); // we don't care about errors (clearing) + } else if (langPromises[key]) { + // we are already loading this asynchronously + // resolve our new deferred when the old langPromise is resolved + langPromises[key].then(function (translation) { + if ($nextLang === translation.key) { + useLanguage(translation.key); + } + deferred.resolve(translation.key); + return translation; + }, function (key) { + // find first available fallback language if that request has failed + if (!$uses && $fallbackLanguage && $fallbackLanguage.length > 0 && $fallbackLanguage[0] !== key) { + return $translate.use($fallbackLanguage[0]).then(deferred.resolve, deferred.reject); + } else { + return deferred.reject(key); + } + }); + } else { + deferred.resolve(key); + useLanguage(key); + } + + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#resolveClientLocale + * @methodOf pascalprecht.translate.$translate + * + * @description + * This returns the current browser/client's language key. The result is processed with the configured uniform tag resolver. + * + * @returns {string} the current client/browser language key + */ + $translate.resolveClientLocale = function () { + return getLocale(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#storageKey + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the key for the storage. + * + * @return {string} storage key + */ + $translate.storageKey = function () { + return storageKey(); + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isPostCompilingEnabled + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether post compiling is enabled or not + * + * @return {bool} storage key + */ + $translate.isPostCompilingEnabled = function () { + return $postCompilingEnabled; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isForceAsyncReloadEnabled + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether force async reload is enabled or not + * + * @return {boolean} forceAsyncReload value + */ + $translate.isForceAsyncReloadEnabled = function () { + return $forceAsyncReloadEnabled; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isKeepContent + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether keepContent or not + * + * @return {boolean} keepContent value + */ + $translate.isKeepContent = function () { + return $keepContent; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#refresh + * @methodOf pascalprecht.translate.$translate + * + * @description + * Refreshes a translation table pointed by the given langKey. If langKey is not specified, + * the module will drop all existent translation tables and load new version of those which + * are currently in use. + * + * Refresh means that the module will drop target translation table and try to load it again. + * + * In case there are no loaders registered the refresh() method will throw an Error. + * + * If the module is able to refresh translation tables refresh() method will broadcast + * $translateRefreshStart and $translateRefreshEnd events. + * + * @example + * // this will drop all currently existent translation tables and reload those which are + * // currently in use + * $translate.refresh(); + * // this will refresh a translation table for the en_US language + * $translate.refresh('en_US'); + * + * @param {string} langKey A language key of the table, which has to be refreshed + * + * @return {promise} Promise, which will be resolved in case a translation tables refreshing + * process is finished successfully, and reject if not. + */ + $translate.refresh = function (langKey) { + if (!$loaderFactory) { + throw new Error('Couldn\'t refresh translation table, no loader registered!'); + } + + $rootScope.$emit('$translateRefreshStart', {language : langKey}); + + var deferred = $q.defer(), updatedLanguages = {}; + + //private helper + function loadNewData(languageKey) { + var promise = loadAsync(languageKey); + //update the load promise cache for this language + langPromises[languageKey] = promise; + //register a data handler for the promise + promise.then(function (data) { + //clear the cache for this language + $translationTable[languageKey] = {}; + //add the new data for this language + translations(languageKey, data.table); + //track that we updated this language + updatedLanguages[languageKey] = true; + }, + //handle rejection to appease the $q validation + angular.noop); + return promise; + } + + //set up post-processing + deferred.promise.then( + function () { + for (var key in $translationTable) { + if ($translationTable.hasOwnProperty(key)) { + //delete cache entries that were not updated + if (!(key in updatedLanguages)) { + delete $translationTable[key]; + } + } + } + if ($uses) { + useLanguage($uses); + } + }, + //handle rejection to appease the $q validation + angular.noop + ).finally( + function () { + $rootScope.$emit('$translateRefreshEnd', {language : langKey}); + } + ); + + if (!langKey) { + // if there's no language key specified we refresh ALL THE THINGS! + var languagesToReload = $fallbackLanguage && $fallbackLanguage.slice() || []; + if ($uses && languagesToReload.indexOf($uses) === -1) { + languagesToReload.push($uses); + } + $q.all(languagesToReload.map(loadNewData)).then(deferred.resolve, deferred.reject); + + } else if ($translationTable[langKey]) { + //just refresh the specified language cache + loadNewData(langKey).then(deferred.resolve, deferred.reject); + + } else { + deferred.reject(); + } + + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#instant + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns a translation instantly from the internal state of loaded translation. All rules + * regarding the current language, the preferred language of even fallback languages will be + * used except any promise handling. If a language was not found, an asynchronous loading + * will be invoked in the background. + * + * @param {string|array} translationId A token which represents a translation id + * This can be optionally an array of translation ids which + * results that the function's promise returns an object where + * each key is the translation id and the value the translation. + * @param {object} interpolateParams Params + * @param {string} interpolationId The id of the interpolation to use + * @param {string} forceLanguage A language to be used instead of the current language + * @param {string} sanitizeStrategy force sanitize strategy for this call instead of using the configured one + * + * @return {string|object} translation + */ + $translate.instant = function (translationId, interpolateParams, interpolationId, forceLanguage, sanitizeStrategy) { + + // we don't want to re-negotiate $uses + var uses = (forceLanguage && forceLanguage !== $uses) ? // we don't want to re-negotiate $uses + (negotiateLocale(forceLanguage) || forceLanguage) : $uses; + + // Detect undefined and null values to shorten the execution and prevent exceptions + if (translationId === null || angular.isUndefined(translationId)) { + return translationId; + } + + // Check forceLanguage is present + if (forceLanguage) { + loadTranslationsIfMissing(forceLanguage); + } + + // Duck detection: If the first argument is an array, a bunch of translations was requested. + // The result is an object. + if (angular.isArray(translationId)) { + var results = {}; + for (var i = 0, c = translationId.length; i < c; i++) { + results[translationId[i]] = $translate.instant(translationId[i], interpolateParams, interpolationId, forceLanguage, sanitizeStrategy); + } + return results; + } + + // We discarded unacceptable values. So we just need to verify if translationId is empty String + if (angular.isString(translationId) && translationId.length < 1) { + return translationId; + } + + // trim off any whitespace + if (translationId) { + translationId = trim.apply(translationId); + } + + var result, possibleLangKeys = []; + if ($preferredLanguage) { + possibleLangKeys.push($preferredLanguage); + } + if (uses) { + possibleLangKeys.push(uses); + } + if ($fallbackLanguage && $fallbackLanguage.length) { + possibleLangKeys = possibleLangKeys.concat($fallbackLanguage); + } + for (var j = 0, d = possibleLangKeys.length; j < d; j++) { + var possibleLangKey = possibleLangKeys[j]; + if ($translationTable[possibleLangKey]) { + if (typeof $translationTable[possibleLangKey][translationId] !== 'undefined') { + result = determineTranslationInstant(translationId, interpolateParams, interpolationId, uses, sanitizeStrategy); + } + } + if (typeof result !== 'undefined') { + break; + } + } + + if (!result && result !== '') { + if ($notFoundIndicatorLeft || $notFoundIndicatorRight) { + result = applyNotFoundIndicators(translationId); + } else { + // Return translation of default interpolator if not found anything. + result = defaultInterpolator.interpolate(translationId, interpolateParams, 'filter', sanitizeStrategy); + + // looks like the requested translation id doesn't exists. + // Now, if there is a registered handler for missing translations and no + // asyncLoader is pending, we execute the handler + var missingTranslationHandlerTranslation; + if ($missingTranslationHandlerFactory && !pendingLoader) { + missingTranslationHandlerTranslation = translateByHandler(translationId, interpolateParams, sanitizeStrategy); + } + + if ($missingTranslationHandlerFactory && !pendingLoader && missingTranslationHandlerTranslation) { + result = missingTranslationHandlerTranslation; + } + } + } + + return result; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#versionInfo + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the current version information for the angular-translate library + * + * @return {string} angular-translate version + */ + $translate.versionInfo = function () { + return version; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#loaderCache + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns the defined loaderCache. + * + * @return {boolean|string|object} current value of loaderCache + */ + $translate.loaderCache = function () { + return loaderCache; + }; + + // internal purpose only + $translate.directivePriority = function () { + return directivePriority; + }; + + // internal purpose only + $translate.statefulFilter = function () { + return statefulFilter; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#isReady + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns whether the service is "ready" to translate (i.e. loading 1st language). + * + * See also {@link pascalprecht.translate.$translate#methods_onReady onReady()}. + * + * @return {boolean} current value of ready + */ + $translate.isReady = function () { + return $isReady; + }; + + var $onReadyDeferred = $q.defer(); + $onReadyDeferred.promise.then(function () { + $isReady = true; + }); + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#onReady + * @methodOf pascalprecht.translate.$translate + * + * @description + * Calls the function provided or resolved the returned promise after the service is "ready" to translate (i.e. loading 1st language). + * + * See also {@link pascalprecht.translate.$translate#methods_isReady isReady()}. + * + * @param {Function=} fn Function to invoke when service is ready + * @return {object} Promise resolved when service is ready + */ + $translate.onReady = function (fn) { + var deferred = $q.defer(); + if (angular.isFunction(fn)) { + deferred.promise.then(fn); + } + if ($isReady) { + deferred.resolve(); + } else { + $onReadyDeferred.promise.then(deferred.resolve); + } + return deferred.promise; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#getAvailableLanguageKeys + * @methodOf pascalprecht.translate.$translate + * + * @description + * This function simply returns the registered language keys being defined before in the config phase + * With this, an application can use the array to provide a language selection dropdown or similar + * without any additional effort + * + * @returns {object} returns the list of possibly registered language keys and mapping or null if not defined + */ + $translate.getAvailableLanguageKeys = function () { + if ($availableLanguageKeys.length > 0) { + return $availableLanguageKeys; + } + return null; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translate#getTranslationTable + * @methodOf pascalprecht.translate.$translate + * + * @description + * Returns translation table by the given language key. + * + * Unless a language is provided it returns a translation table of the current one. + * Note: If translation dictionary is currently downloading or in progress + * it will return null. + * + * @param {string} langKey A token which represents a translation id + * + * @return {object} a copy of angular-translate $translationTable + */ + $translate.getTranslationTable = function (langKey) { + langKey = langKey || $translate.use(); + if (langKey && $translationTable[langKey]) { + return angular.copy($translationTable[langKey]); + } + return null; + }; + + // Whenever $translateReady is being fired, this will ensure the state of $isReady + var globalOnReadyListener = $rootScope.$on('$translateReady', function () { + $onReadyDeferred.resolve(); + globalOnReadyListener(); // one time only + globalOnReadyListener = null; + }); + var globalOnChangeListener = $rootScope.$on('$translateChangeEnd', function () { + $onReadyDeferred.resolve(); + globalOnChangeListener(); // one time only + globalOnChangeListener = null; + }); + + if ($loaderFactory) { + + // If at least one async loader is defined and there are no + // (default) translations available we should try to load them. + if (angular.equals($translationTable, {})) { + if ($translate.use()) { + $translate.use($translate.use()); + } + } + + // Also, if there are any fallback language registered, we start + // loading them asynchronously as soon as we can. + if ($fallbackLanguage && $fallbackLanguage.length) { + var processAsyncResult = function (translation) { + translations(translation.key, translation.table); + $rootScope.$emit('$translateChangeEnd', {language : translation.key}); + return translation; + }; + for (var i = 0, len = $fallbackLanguage.length; i < len; i++) { + var fallbackLanguageId = $fallbackLanguage[i]; + if ($forceAsyncReloadEnabled || !$translationTable[fallbackLanguageId]) { + langPromises[fallbackLanguageId] = loadAsync(fallbackLanguageId).then(processAsyncResult); + } + } + } + } else { + $rootScope.$emit('$translateReady', {language : $translate.use()}); + } + + return $translate; + }]; +} + +$translate.displayName = 'displayName'; + +/** + * @ngdoc object + * @name pascalprecht.translate.$translateDefaultInterpolation + * @requires $interpolate + * + * @description + * Uses angular's `$interpolate` services to interpolate strings against some values. + * + * Be aware to configure a proper sanitization strategy. + * + * See also: + * * {@link pascalprecht.translate.$translateSanitization} + * + * @return {object} $translateDefaultInterpolation Interpolator service + */ +angular.module('pascalprecht.translate').factory('$translateDefaultInterpolation', $translateDefaultInterpolation); + +function $translateDefaultInterpolation ($interpolate, $translateSanitization) { + + 'use strict'; + + var $translateInterpolator = {}, + $locale, + $identifier = 'default'; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#setLocale + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Sets current locale (this is currently not use in this interpolation). + * + * @param {string} locale Language key or locale. + */ + $translateInterpolator.setLocale = function (locale) { + $locale = locale; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#getInterpolationIdentifier + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Returns an identifier for this interpolation service. + * + * @returns {string} $identifier + */ + $translateInterpolator.getInterpolationIdentifier = function () { + return $identifier; + }; + + /** + * @deprecated will be removed in 3.0 + * @see {@link pascalprecht.translate.$translateSanitization} + */ + $translateInterpolator.useSanitizeValueStrategy = function (value) { + $translateSanitization.useStrategy(value); + return this; + }; + + /** + * @ngdoc function + * @name pascalprecht.translate.$translateDefaultInterpolation#interpolate + * @methodOf pascalprecht.translate.$translateDefaultInterpolation + * + * @description + * Interpolates given value agains given interpolate params using angulars + * `$interpolate` service. + * + * Since AngularJS 1.5, `value` must not be a string but can be anything input. + * + * @param {string} value translation + * @param {object} interpolationParams interpolation params + * @param {string} context current context (filter, directive, service) + * @param {string} sanitizeStrategy sanitize strategy + * @param {string} translationId current translationId + * + * @returns {string} interpolated string + */ + $translateInterpolator.interpolate = function (value, interpolationParams, context, sanitizeStrategy, translationId) { // jshint ignore:line + interpolationParams = interpolationParams || {}; + interpolationParams = $translateSanitization.sanitize(interpolationParams, 'params', sanitizeStrategy, context); + + var interpolatedText; + if (angular.isNumber(value)) { + // numbers are safe + interpolatedText = '' + value; + } else if (angular.isString(value)) { + // strings must be interpolated (that's the job here) + interpolatedText = $interpolate(value)(interpolationParams); + interpolatedText = $translateSanitization.sanitize(interpolatedText, 'text', sanitizeStrategy, context); + } else { + // neither a number or a string, cant interpolate => empty string + interpolatedText = ''; + } + + return interpolatedText; + }; + + return $translateInterpolator; +} + +$translateDefaultInterpolation.displayName = '$translateDefaultInterpolation'; + +angular.module('pascalprecht.translate').constant('$STORAGE_KEY', 'NG_TRANSLATE_LANG_KEY'); + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translate + * @requires $interpolate, + * @requires $compile, + * @requires $parse, + * @requires $rootScope + * @restrict AE + * + * @description + * Translates given translation id either through attribute or DOM content. + * Internally it uses $translate service to translate the translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate Translation id which could be either string or interpolated string. + * @param {string=} translate-values Values to pass into translation id. Can be passed as object literal string or interpolated object. + * @param {string=} translate-attr-ATTR translate Translation id and put it into ATTR attribute. + * @param {string=} translate-default will be used unless translation was successful + * @param {boolean=} translate-compile (default true if present) defines locally activation of {@link pascalprecht.translate.$translateProvider#methods_usePostCompiling} + * @param {boolean=} translate-keep-content (default true if present) defines that in case a KEY could not be translated, that the existing content is left in the innerHTML} + * + * @example + + +
    + +
    
    +        
    TRANSLATION_ID
    +
    
    +        
    
    +        
    {{translationId}}
    +
    
    +        
    WITH_VALUES
    +
    
    +        
    WITH_VALUES
    +
    
    +        
    
    +
    +      
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}', + 'WITH_CAMEL_CASE_KEY': 'The interpolation key is camel cased: {{camelCaseKey}}' + }).preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + + + it('should translate', function () { + inject(function ($rootScope, $compile) { + $rootScope.translationId = 'TRANSLATION_ID'; + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    TRANSLATION_ID

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    {{translationId}}

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('Hello there!'); + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.attr('title')).toBe('Hello there!'); + + element = $compile('

    ')($rootScope); + $rootScope.$digest(); + expect(element.text()).toBe('The interpolation key is camel cased: Hello'); + }); + }); +
    +
    + */ +.directive('translate', translateDirective); +function translateDirective($translate, $interpolate, $compile, $parse, $rootScope) { + + 'use strict'; + + /** + * @name trim + * @private + * + * @description + * trim polyfill + * + * @returns {string} The string stripped of whitespace from both ends + */ + var trim = function() { + return this.toString().replace(/^\s+|\s+$/g, ''); + }; + + return { + restrict: 'AE', + scope: true, + priority: $translate.directivePriority(), + compile: function (tElement, tAttr) { + + var translateValuesExist = (tAttr.translateValues) ? + tAttr.translateValues : undefined; + + var translateInterpolation = (tAttr.translateInterpolation) ? + tAttr.translateInterpolation : undefined; + + var translateValueExist = tElement[0].outerHTML.match(/translate-value-+/i); + + var interpolateRegExp = '^(.*)(' + $interpolate.startSymbol() + '.*' + $interpolate.endSymbol() + ')(.*)', + watcherRegExp = '^(.*)' + $interpolate.startSymbol() + '(.*)' + $interpolate.endSymbol() + '(.*)'; + + return function linkFn(scope, iElement, iAttr) { + + scope.interpolateParams = {}; + scope.preText = ''; + scope.postText = ''; + scope.translateNamespace = getTranslateNamespace(scope); + var translationIds = {}; + + var initInterpolationParams = function (interpolateParams, iAttr, tAttr) { + // initial setup + if (iAttr.translateValues) { + angular.extend(interpolateParams, $parse(iAttr.translateValues)(scope.$parent)); + } + // initially fetch all attributes if existing and fill the params + if (translateValueExist) { + for (var attr in tAttr) { + if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') { + var attributeName = angular.lowercase(attr.substr(14, 1)) + attr.substr(15); + interpolateParams[attributeName] = tAttr[attr]; + } + } + } + }; + + // Ensures any change of the attribute "translate" containing the id will + // be re-stored to the scope's "translationId". + // If the attribute has no content, the element's text value (white spaces trimmed off) will be used. + var observeElementTranslation = function (translationId) { + + // Remove any old watcher + if (angular.isFunction(observeElementTranslation._unwatchOld)) { + observeElementTranslation._unwatchOld(); + observeElementTranslation._unwatchOld = undefined; + } + + if (angular.equals(translationId , '') || !angular.isDefined(translationId)) { + var iElementText = trim.apply(iElement.text()); + + // Resolve translation id by inner html if required + var interpolateMatches = iElementText.match(interpolateRegExp); + // Interpolate translation id if required + if (angular.isArray(interpolateMatches)) { + scope.preText = interpolateMatches[1]; + scope.postText = interpolateMatches[3]; + translationIds.translate = $interpolate(interpolateMatches[2])(scope.$parent); + var watcherMatches = iElementText.match(watcherRegExp); + if (angular.isArray(watcherMatches) && watcherMatches[2] && watcherMatches[2].length) { + observeElementTranslation._unwatchOld = scope.$watch(watcherMatches[2], function (newValue) { + translationIds.translate = newValue; + updateTranslations(); + }); + } + } else { + // do not assigne the translation id if it is empty. + translationIds.translate = !iElementText ? undefined : iElementText; + } + } else { + translationIds.translate = translationId; + } + updateTranslations(); + }; + + var observeAttributeTranslation = function (translateAttr) { + iAttr.$observe(translateAttr, function (translationId) { + translationIds[translateAttr] = translationId; + updateTranslations(); + }); + }; + + // initial setup with values + initInterpolationParams(scope.interpolateParams, iAttr, tAttr); + + var firstAttributeChangedEvent = true; + iAttr.$observe('translate', function (translationId) { + if (typeof translationId === 'undefined') { + // case of element "xyz" + observeElementTranslation(''); + } else { + // case of regular attribute + if (translationId !== '' || !firstAttributeChangedEvent) { + translationIds.translate = translationId; + updateTranslations(); + } + } + firstAttributeChangedEvent = false; + }); + + for (var translateAttr in iAttr) { + if (iAttr.hasOwnProperty(translateAttr) && translateAttr.substr(0, 13) === 'translateAttr' && translateAttr.length > 13) { + observeAttributeTranslation(translateAttr); + } + } + + iAttr.$observe('translateDefault', function (value) { + scope.defaultText = value; + updateTranslations(); + }); + + if (translateValuesExist) { + iAttr.$observe('translateValues', function (interpolateParams) { + if (interpolateParams) { + scope.$parent.$watch(function () { + angular.extend(scope.interpolateParams, $parse(interpolateParams)(scope.$parent)); + }); + } + }); + } + + if (translateValueExist) { + var observeValueAttribute = function (attrName) { + iAttr.$observe(attrName, function (value) { + var attributeName = angular.lowercase(attrName.substr(14, 1)) + attrName.substr(15); + scope.interpolateParams[attributeName] = value; + }); + }; + for (var attr in iAttr) { + if (Object.prototype.hasOwnProperty.call(iAttr, attr) && attr.substr(0, 14) === 'translateValue' && attr !== 'translateValues') { + observeValueAttribute(attr); + } + } + } + + // Master update function + var updateTranslations = function () { + for (var key in translationIds) { + if (translationIds.hasOwnProperty(key) && translationIds[key] !== undefined) { + updateTranslation(key, translationIds[key], scope, scope.interpolateParams, scope.defaultText, scope.translateNamespace); + } + } + }; + + // Put translation processing function outside loop + var updateTranslation = function(translateAttr, translationId, scope, interpolateParams, defaultTranslationText, translateNamespace) { + if (translationId) { + // if translation id starts with '.' and translateNamespace given, prepend namespace + if (translateNamespace && translationId.charAt(0) === '.') { + translationId = translateNamespace + translationId; + } + + $translate(translationId, interpolateParams, translateInterpolation, defaultTranslationText, scope.translateLanguage) + .then(function (translation) { + applyTranslation(translation, scope, true, translateAttr); + }, function (translationId) { + applyTranslation(translationId, scope, false, translateAttr); + }); + } else { + // as an empty string cannot be translated, we can solve this using successful=false + applyTranslation(translationId, scope, false, translateAttr); + } + }; + + var applyTranslation = function (value, scope, successful, translateAttr) { + if (!successful) { + if (typeof scope.defaultText !== 'undefined') { + value = scope.defaultText; + } + } + if (translateAttr === 'translate') { + // default translate into innerHTML + if (successful || (!successful && !$translate.isKeepContent() && typeof iAttr.translateKeepContent === 'undefined')) { + iElement.empty().append(scope.preText + value + scope.postText); + } + var globallyEnabled = $translate.isPostCompilingEnabled(); + var locallyDefined = typeof tAttr.translateCompile !== 'undefined'; + var locallyEnabled = locallyDefined && tAttr.translateCompile !== 'false'; + if ((globallyEnabled && !locallyDefined) || locallyEnabled) { + $compile(iElement.contents())(scope); + } + } else { + // translate attribute + var attributeName = iAttr.$attr[translateAttr]; + if (attributeName.substr(0, 5) === 'data-') { + // ensure html5 data prefix is stripped + attributeName = attributeName.substr(5); + } + attributeName = attributeName.substr(15); + iElement.attr(attributeName, value); + } + }; + + if (translateValuesExist || translateValueExist || iAttr.translateDefault) { + scope.$watch('interpolateParams', updateTranslations, true); + } + + // Replaced watcher on translateLanguage with event listener + scope.$on('translateLanguageChanged', updateTranslations); + + // Ensures the text will be refreshed after the current language was changed + // w/ $translate.use(...) + var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations); + + // ensure translation will be looked up at least one + if (iElement.text().length) { + if (iAttr.translate) { + observeElementTranslation(iAttr.translate); + } else { + observeElementTranslation(''); + } + } else if (iAttr.translate) { + // ensure attribute will be not skipped + observeElementTranslation(iAttr.translate); + } + updateTranslations(); + scope.$on('$destroy', unbind); + }; + } + }; +} + +/** + * Returns the scope's namespace. + * @private + * @param scope + * @returns {string} + */ +function getTranslateNamespace(scope) { + 'use strict'; + if (scope.translateNamespace) { + return scope.translateNamespace; + } + if (scope.$parent) { + return getTranslateNamespace(scope.$parent); + } +} + +translateDirective.displayName = 'translateDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translate-attr + * @restrict A + * + * @description + * Translates attributes like translate-attr-ATTR, but with an object like ng-class. + * Internally it uses `translate` service to translate translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate-attr Object literal mapping attributes to translation ids. + * @param {string=} translate-values Values to pass into the translation ids. Can be passed as object literal string. + * + * @example + + +
    + + + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}', + }).preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + + + it('should translate', function () { + inject(function ($rootScope, $compile) { + $rootScope.translationId = 'TRANSLATION_ID'; + + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(element.attr('placeholder)).toBe('Hello there!'); + expect(element.attr('title)).toBe('The following value is dynamic: 5'); + }); + }); + +
    + */ +.directive('translateAttr', translateAttrDirective); +function translateAttrDirective($translate, $rootScope) { + + 'use strict'; + + return { + restrict: 'A', + priority: $translate.directivePriority(), + link: function linkFn(scope, element, attr) { + + var translateAttr, + translateValues, + previousAttributes = {}; + + // Main update translations function + var updateTranslations = function () { + angular.forEach(translateAttr, function (translationId, attributeName) { + if (!translationId) { + return; + } + previousAttributes[attributeName] = true; + + // if translation id starts with '.' and translateNamespace given, prepend namespace + if (scope.translateNamespace && translationId.charAt(0) === '.') { + translationId = scope.translateNamespace + translationId; + } + $translate(translationId, translateValues, attr.translateInterpolation, undefined, scope.translateLanguage) + .then(function (translation) { + element.attr(attributeName, translation); + }, function (translationId) { + element.attr(attributeName, translationId); + }); + }); + + // Removing unused attributes that were previously used + angular.forEach(previousAttributes, function (flag, attributeName) { + if (!translateAttr[attributeName]) { + element.removeAttr(attributeName); + delete previousAttributes[attributeName]; + } + }); + }; + + // Watch for attribute changes + watchAttribute( + scope, + attr.translateAttr, + function (newValue) { translateAttr = newValue; }, + updateTranslations + ); + // Watch for value changes + watchAttribute( + scope, + attr.translateValues, + function (newValue) { translateValues = newValue; }, + updateTranslations + ); + + if (attr.translateValues) { + scope.$watch(attr.translateValues, updateTranslations, true); + } + + // Replaced watcher on translateLanguage with event listener + scope.$on('translateLanguageChanged', updateTranslations); + + // Ensures the text will be refreshed after the current language was changed + // w/ $translate.use(...) + var unbind = $rootScope.$on('$translateChangeSuccess', updateTranslations); + + updateTranslations(); + scope.$on('$destroy', unbind); + } + }; +} + +function watchAttribute(scope, attribute, valueCallback, changeCallback) { + 'use strict'; + if (!attribute) { + return; + } + if (attribute.substr(0, 2) === '::') { + attribute = attribute.substr(2); + } else { + scope.$watch(attribute, function(newValue) { + valueCallback(newValue); + changeCallback(); + }, true); + } + valueCallback(scope.$eval(attribute)); +} + +translateAttrDirective.displayName = 'translateAttrDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateCloak + * @requires $translate + * @restrict A + * + * $description + * Adds a `translate-cloak` class name to the given element where this directive + * is applied initially and removes it, once a loader has finished loading. + * + * This directive can be used to prevent initial flickering when loading translation + * data asynchronously. + * + * The class name is defined in + * {@link pascalprecht.translate.$translateProvider#cloakClassName $translate.cloakClassName()}. + * + * @param {string=} translate-cloak If a translationId is provided, it will be used for showing + * or hiding the cloak. Basically it relies on the translation + * resolve. + */ +.directive('translateCloak', translateCloakDirective); + +function translateCloakDirective($translate, $rootScope) { + + 'use strict'; + + return { + compile : function (tElement) { + var applyCloak = function (element) { + element.addClass($translate.cloakClassName()); + }, + removeCloak = function (element) { + element.removeClass($translate.cloakClassName()); + }; + applyCloak(tElement); + + return function linkFn(scope, iElement, iAttr) { + //Create bound functions that incorporate the active DOM element. + var iRemoveCloak = removeCloak.bind(this, iElement), iApplyCloak = applyCloak.bind(this, iElement); + if (iAttr.translateCloak && iAttr.translateCloak.length) { + // Register a watcher for the defined translation allowing a fine tuned cloak + iAttr.$observe('translateCloak', function (translationId) { + $translate(translationId).then(iRemoveCloak, iApplyCloak); + }); + $rootScope.$on('$translateChangeSuccess', function () { + $translate(iAttr.translateCloak).then(iRemoveCloak, iApplyCloak); + }); + } else { + $translate.onReady(iRemoveCloak); + } + }; + } + }; +} + +translateCloakDirective.displayName = 'translateCloakDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateNamespace + * @restrict A + * + * @description + * Translates given translation id either through attribute or DOM content. + * Internally it uses `translate` filter to translate translation id. It possible to + * pass an optional `translate-values` object literal as string into translation id. + * + * @param {string=} translate namespace name which could be either string or interpolated string. + * + * @example + + +
    + +
    +

    .HEADERS.TITLE

    +

    .HEADERS.WELCOME

    +
    + +
    +

    .TITLE

    +

    .WELCOME

    +
    + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en',{ + 'TRANSLATION_ID': 'Hello there!', + 'CONTENT': { + 'HEADERS': { + TITLE: 'Title' + } + }, + 'CONTENT.HEADERS.WELCOME': 'Welcome' + }).preferredLanguage('en'); + + }); + + +
    + */ +.directive('translateNamespace', translateNamespaceDirective); + +function translateNamespaceDirective() { + + 'use strict'; + + return { + restrict: 'A', + scope: true, + compile: function () { + return { + pre: function (scope, iElement, iAttrs) { + scope.translateNamespace = getTranslateNamespace(scope); + + if (scope.translateNamespace && iAttrs.translateNamespace.charAt(0) === '.') { + scope.translateNamespace += iAttrs.translateNamespace; + } else { + scope.translateNamespace = iAttrs.translateNamespace; + } + } + }; + } + }; +} + +/** + * Returns the scope's namespace. + * @private + * @param scope + * @returns {string} + */ +function getTranslateNamespace(scope) { + 'use strict'; + if (scope.translateNamespace) { + return scope.translateNamespace; + } + if (scope.$parent) { + return getTranslateNamespace(scope.$parent); + } +} + +translateNamespaceDirective.displayName = 'translateNamespaceDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc directive + * @name pascalprecht.translate.directive:translateLanguage + * @restrict A + * + * @description + * Forces the language to the directives in the underlying scope. + * + * @param {string=} translate language that will be negotiated. + * + * @example + + +
    + +
    +

    HELLO

    +
    + +
    +

    HELLO

    +
    + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider + .translations('en',{ + 'HELLO': 'Hello world!' + }) + .translations('de',{ + 'HELLO': 'Hallo Welt!' + }) + .preferredLanguage('en'); + + }); + + +
    + */ +.directive('translateLanguage', translateLanguageDirective); + +function translateLanguageDirective() { + + 'use strict'; + + return { + restrict: 'A', + scope: true, + compile: function () { + return function linkFn(scope, iElement, iAttrs) { + + iAttrs.$observe('translateLanguage', function (newTranslateLanguage) { + scope.translateLanguage = newTranslateLanguage; + }); + + scope.$watch('translateLanguage', function(){ + scope.$broadcast('translateLanguageChanged'); + }); + }; + } + }; +} + +translateLanguageDirective.displayName = 'translateLanguageDirective'; + +angular.module('pascalprecht.translate') +/** + * @ngdoc filter + * @name pascalprecht.translate.filter:translate + * @requires $parse + * @requires pascalprecht.translate.$translate + * @function + * + * @description + * Uses `$translate` service to translate contents. Accepts interpolate parameters + * to pass dynamized values though translation. + * + * @param {string} translationId A translation id to be translated. + * @param {*=} interpolateParams Optional object literal (as hash or string) to pass values into translation. + * + * @returns {string} Translated text. + * + * @example + + +
    + +
    {{ 'TRANSLATION_ID' | translate }}
    +
    {{ translationId | translate }}
    +
    {{ 'WITH_VALUES' | translate:'{value: 5}' }}
    +
    {{ 'WITH_VALUES' | translate:values }}
    + +
    +
    + + angular.module('ngView', ['pascalprecht.translate']) + + .config(function ($translateProvider) { + + $translateProvider.translations('en', { + 'TRANSLATION_ID': 'Hello there!', + 'WITH_VALUES': 'The following value is dynamic: {{value}}' + }); + $translateProvider.preferredLanguage('en'); + + }); + + angular.module('ngView').controller('TranslateCtrl', function ($scope) { + $scope.translationId = 'TRANSLATION_ID'; + + $scope.values = { + value: 78 + }; + }); + +
    + */ +.filter('translate', translateFilterFactory); + +function translateFilterFactory($parse, $translate) { + + 'use strict'; + + var translateFilter = function (translationId, interpolateParams, interpolation, forceLanguage) { + if (!angular.isObject(interpolateParams)) { + var ctx = this || { + '__SCOPE_IS_NOT_AVAILABLE': 'More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f' + }; + interpolateParams = $parse(interpolateParams)(ctx); + } + + return $translate.instant(translationId, interpolateParams, interpolation, forceLanguage); + }; + + if ($translate.statefulFilter()) { + translateFilter.$stateful = true; + } + + return translateFilter; +} + +translateFilterFactory.displayName = 'translateFilterFactory'; + +angular.module('pascalprecht.translate') + +/** + * @ngdoc object + * @name pascalprecht.translate.$translationCache + * @requires $cacheFactory + * + * @description + * The first time a translation table is used, it is loaded in the translation cache for quick retrieval. You + * can load translation tables directly into the cache by consuming the + * `$translationCache` service directly. + * + * @return {object} $cacheFactory object. + */ + .factory('$translationCache', $translationCache); + +function $translationCache($cacheFactory) { + + 'use strict'; + + return $cacheFactory('translations'); +} + +$translationCache.displayName = '$translationCache'; +return 'pascalprecht.translate'; + +})); diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.min.js b/zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.min.js new file mode 100644 index 0000000..8549ef9 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular-translate_2.15.1/angular-translate.min.js @@ -0,0 +1,6 @@ +/*! + * angular-translate - v2.15.1 - 2017-03-04 + * + * Copyright (c) 2017 The angular-translate team, Pascal Precht; Licensed MIT + */ +!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a){"use strict";var b=a.storageKey(),c=a.storage(),d=function(){var d=a.preferredLanguage();angular.isString(d)?a.use(d):c.put(b,a.use())};d.displayName="fallbackFromIncorrectStorageValue",c?c.get(b)?a.use(c.get(b)).catch(d):d():angular.isString(a.preferredLanguage())&&a.use(a.preferredLanguage())}function b(){"use strict";var a,b,c,d=null,e=!1,f=!1;c={sanitize:function(a,b){return"text"===b&&(a=h(a)),a},escape:function(a,b){return"text"===b&&(a=g(a)),a},sanitizeParameters:function(a,b){return"params"===b&&(a=j(a,h)),a},escapeParameters:function(a,b){return"params"===b&&(a=j(a,g)),a},sce:function(a,b,c){return"text"===b?a=i(a):"params"===b&&"filter"!==c&&(a=j(a,g)),a},sceParameters:function(a,b){return"params"===b&&(a=j(a,i)),a}},c.escaped=c.escapeParameters,this.addStrategy=function(a,b){return c[a]=b,this},this.removeStrategy=function(a){return delete c[a],this},this.useStrategy=function(a){return e=!0,d=a,this},this.$get=["$injector","$log",function(g,h){var i={},j=function(a,b,d,e){return angular.forEach(e,function(e){if(angular.isFunction(e))a=e(a,b,d);else if(angular.isFunction(c[e]))a=c[e](a,b,d);else{if(!angular.isString(c[e]))throw new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'");if(!i[c[e]])try{i[c[e]]=g.get(c[e])}catch(a){throw i[c[e]]=function(){},new Error("pascalprecht.translate.$translateSanitization: Unknown sanitization strategy: '"+e+"'")}a=i[c[e]](a,b,d)}}),a},k=function(){e||f||(h.warn("pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details."),f=!0)};return g.has("$sanitize")&&(a=g.get("$sanitize")),g.has("$sce")&&(b=g.get("$sce")),{useStrategy:function(a){return function(b){a.useStrategy(b)}}(this),sanitize:function(a,b,c,e){if(d||k(),c||null===c||(c=d),!c)return a;e||(e="service");var f=angular.isArray(c)?c:[c];return j(a,b,e,f)}}}];var g=function(a){var b=angular.element("
    ");return b.text(a),b.html()},h=function(b){if(!a)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sanitize service. Either include the ngSanitize module (https://docs.angularjs.org/api/ngSanitize) or use a sanitization strategy which does not depend on $sanitize, such as 'escape'.");return a(b)},i=function(a){if(!b)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot find $sce service.");return b.trustAsHtml(a)},j=function(a,b,c){if(angular.isDate(a))return a;if(angular.isObject(a)){var d=angular.isArray(a)?[]:{};if(c){if(c.indexOf(a)>-1)throw new Error("pascalprecht.translate.$translateSanitization: Error cannot interpolate parameter due recursive object")}else c=[];return c.push(a),angular.forEach(a,function(a,e){angular.isFunction(a)||(d[e]=j(a,b,c))}),c.splice(-1,1),d}return angular.isNumber(a)?a:angular.isUndefined(a)||null===a?a:b(a)}}function c(a,b,c,d){"use strict";var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u={},v=[],w=a,x=[],y="translate-cloak",z=!1,A=!1,B=".",C=!1,D=!1,E=0,F=!0,G="default",H={default:function(a){return(a||"").split("-").join("_")},java:function(a){var b=(a||"").split("-").join("_"),c=b.split("_");return c.length>1?c[0].toLowerCase()+"_"+c[1].toUpperCase():b},bcp47:function(a){var b=(a||"").split("_").join("-"),c=b.split("-");return c.length>1?c[0].toLowerCase()+"-"+c[1].toUpperCase():b},"iso639-1":function(a){var b=(a||"").split("_").join("-"),c=b.split("-");return c[0].toLowerCase()}},I="2.15.1",J=function(){if(angular.isFunction(d.getLocale))return d.getLocale();var a,c,e=b.$get().navigator,f=["language","browserLanguage","systemLanguage","userLanguage"];if(angular.isArray(e.languages))for(a=0;a-1)return a;if(f){var g;for(var h in f)if(f.hasOwnProperty(h)){var i=!1,j=Object.prototype.hasOwnProperty.call(f,h)&&angular.lowercase(h)===angular.lowercase(a);if("*"===h.slice(-1)&&(i=h.slice(0,-1)===a.slice(0,h.length-1)),(j||i)&&(g=f[h],L(b,angular.lowercase(g))>-1))return g}}var k=a.split("_");return k.length>1&&L(b,angular.lowercase(k[0]))>-1?k[0]:void 0}},O=function(a,b){if(!a&&!b)return u;if(a&&!b){if(angular.isString(a))return u[a]}else angular.isObject(u[a])||(u[a]={}),angular.extend(u[a],P(b));return this};this.translations=O,this.cloakClassName=function(a){return a?(y=a,this):y},this.nestedObjectDelimeter=function(a){return a?(B=a,this):B};var P=function(a,b,c,d){var e,f,g,h;b||(b=[]),c||(c={});for(e in a)Object.prototype.hasOwnProperty.call(a,e)&&(h=a[e],angular.isObject(h)?P(h,b.concat(e),c,e):(f=b.length?""+b.join(B)+B+e:e,b.length&&e===d&&(g=""+b.join(B),c[g]="@:"+f),c[f]=h));return c};P.displayName="flatObject",this.addInterpolation=function(a){return x.push(a),this},this.useMessageFormatInterpolation=function(){return this.useInterpolation("$translateMessageFormatInterpolation")},this.useInterpolation=function(a){return n=a,this},this.useSanitizeValueStrategy=function(a){return c.useStrategy(a),this},this.preferredLanguage=function(a){return a?(Q(a),this):e};var Q=function(a){return a&&(e=a),e};this.translationNotFoundIndicator=function(a){return this.translationNotFoundIndicatorLeft(a),this.translationNotFoundIndicatorRight(a),this},this.translationNotFoundIndicatorLeft=function(a){return a?(q=a,this):q},this.translationNotFoundIndicatorRight=function(a){return a?(r=a,this):r},this.fallbackLanguage=function(a){return R(a),this};var R=function(a){return a?(angular.isString(a)?(h=!0,g=[a]):angular.isArray(a)&&(h=!1,g=a),angular.isString(e)&&L(g,e)<0&&g.push(e),this):h?g[0]:g};this.use=function(a){if(a){if(!u[a]&&!o)throw new Error("$translateProvider couldn't find translationTable for langKey: '"+a+"'");return i=a,this}return i},this.resolveClientLocale=function(){return K()};var S=function(a){return a?(w=a,this):l?l+w:w};this.storageKey=S,this.useUrlLoader=function(a,b){return this.useLoader("$translateUrlLoader",angular.extend({url:a},b))},this.useStaticFilesLoader=function(a){return this.useLoader("$translateStaticFilesLoader",a)},this.useLoader=function(a,b){return o=a,p=b||{},this},this.useLocalStorage=function(){return this.useStorage("$translateLocalStorage")},this.useCookieStorage=function(){return this.useStorage("$translateCookieStorage")},this.useStorage=function(a){return k=a,this},this.storagePrefix=function(a){return a?(l=a,this):a},this.useMissingTranslationHandlerLog=function(){return this.useMissingTranslationHandler("$translateMissingTranslationHandlerLog")},this.useMissingTranslationHandler=function(a){return m=a,this},this.usePostCompiling=function(a){return z=!!a,this},this.forceAsyncReload=function(a){return A=!!a,this},this.uniformLanguageTag=function(a){return a?angular.isString(a)&&(a={standard:a}):a={},G=a.standard,this},this.determinePreferredLanguage=function(a){var b=a&&angular.isFunction(a)?a():K();return e=v.length?N(b)||b:b,this},this.registerAvailableLanguageKeys=function(a,b){return a?(v=a,b&&(f=b),this):v},this.useLoaderCache=function(a){return a===!1?s=void 0:a===!0?s=!0:"undefined"==typeof a?s="$translationCache":a&&(s=a),this},this.directivePriority=function(a){return void 0===a?E:(E=a,this)},this.statefulFilter=function(a){return void 0===a?F:(F=a,this)},this.postProcess=function(a){return t=a?a:void 0,this},this.keepContent=function(a){return D=!!a,this},this.$get=["$log","$injector","$rootScope","$q",function(a,b,c,d){var f,l,G,H=b.get(n||"$translateDefaultInterpolation"),J=!1,T={},U={},V=function(a,b,c,h,j){!i&&e&&(i=e);var m=j&&j!==i?N(j)||j:i;if(j&&ka(j),angular.isArray(a)){var n=function(a){for(var e={},f=[],g=function(a){var f=d.defer(),g=function(b){e[a]=b,f.resolve([a,b])};return V(a,b,c,h,j).then(g,g),f.promise},i=0,k=a.length;i0?G:l,a,b,c,d,e)},fa=function(a,b,c,d){return da(G>0?G:l,a,b,c,d)},ga=function(a,b,c,e,f,h){var i=d.defer(),j=f?u[f]:u,k=c?T[c]:H;if(j&&Object.prototype.hasOwnProperty.call(j,a)&&null!==j[a]){var l=j[a];if("@:"===l.substr(0,2))V(l.substr(2),b,c,e,f).then(i.resolve,i.reject);else{var n=k.interpolate(l,b,"service",h,a);n=ja(a,l,n,b,f),i.resolve(n)}}else{var o;m&&!J&&(o=ba(a,b,e)),f&&g&&g.length?ea(a,b,k,e,h).then(function(a){i.resolve(a)},function(a){i.reject(W(a))}):m&&!J&&o?e?i.resolve(e):i.resolve(o):e?i.resolve(e):i.reject(W(a))}return i.promise},ha=function(a,b,c,d,e){var f,h=d?u[d]:u,i=H;if(T&&Object.prototype.hasOwnProperty.call(T,c)&&(i=T[c]),h&&Object.prototype.hasOwnProperty.call(h,a)&&null!==h[a]){var j=h[a];"@:"===j.substr(0,2)?f=ha(j.substr(2),b,c,d,e):(f=i.interpolate(j,b,"filter",e,a),f=ja(a,j,f,b,d,e))}else{var k;m&&!J&&(k=ba(a,b,e)),d&&g&&g.length?(l=0,f=fa(a,b,i,e)):f=m&&!J&&k?k:W(a)}return f},ia=function(a){j===a&&(j=void 0),U[a]=void 0},ja=function(a,c,d,e,f,g){var h=t;return h&&("string"==typeof h&&(h=b.get(h)),h)?h(a,c,d,e,f,g):d},ka=function(a){u[a]||!o||U[a]||(U[a]=Y(a).then(function(a){return O(a.key,a.table),a}))};V.preferredLanguage=function(a){return a&&Q(a),e},V.cloakClassName=function(){return y},V.nestedObjectDelimeter=function(){return B},V.fallbackLanguage=function(a){if(void 0!==a&&null!==a){if(R(a),o&&g&&g.length)for(var b=0,c=g.length;b-1&&(G=b)}else G=0},V.proposedLanguage=function(){return j},V.storage=function(){return f},V.negotiateLocale=N,V.use=function(a){if(!a)return i;var b=d.defer();b.promise.then(null,angular.noop),c.$emit("$translateChangeStart",{language:a});var e=N(a);return v.length>0&&!e?d.reject(a):(e&&(a=e),j=a,!A&&u[a]||!o||U[a]?U[a]?U[a].then(function(a){return j===a.key&&X(a.key),b.resolve(a.key),a},function(a){return!i&&g&&g.length>0&&g[0]!==a?V.use(g[0]).then(b.resolve,b.reject):b.reject(a)}):(b.resolve(a),X(a)):(U[a]=Y(a).then(function(c){return O(c.key,c.table),b.resolve(c.key),j===a&&X(c.key),c},function(a){return c.$emit("$translateChangeError",{language:a}),b.reject(a),c.$emit("$translateChangeEnd",{language:a}),d.reject(a)}),U[a].finally(function(){ia(a)}).catch(angular.noop)),b.promise)},V.resolveClientLocale=function(){return K()},V.storageKey=function(){return S()},V.isPostCompilingEnabled=function(){return z},V.isForceAsyncReloadEnabled=function(){return A},V.isKeepContent=function(){return D},V.refresh=function(a){function b(a){var b=Y(a);return U[a]=b,b.then(function(b){u[a]={},O(a,b.table),f[a]=!0},angular.noop),b}if(!o)throw new Error("Couldn't refresh translation table, no loader registered!");c.$emit("$translateRefreshStart",{language:a});var e=d.defer(),f={};if(e.promise.then(function(){for(var a in u)u.hasOwnProperty(a)&&(a in f||delete u[a]);i&&X(i)},angular.noop).finally(function(){c.$emit("$translateRefreshEnd",{language:a})}),a)u[a]?b(a).then(e.resolve,e.reject):e.reject();else{var h=g&&g.slice()||[];i&&h.indexOf(i)===-1&&h.push(i),d.all(h.map(b)).then(e.resolve,e.reject)}return e.promise},V.instant=function(a,b,c,d,f){var h=d&&d!==i?N(d)||d:i;if(null===a||angular.isUndefined(a))return a;if(d&&ka(d),angular.isArray(a)){for(var j={},k=0,l=a.length;k0?v:null},V.getTranslationTable=function(a){return a=a||V.use(),a&&u[a]?angular.copy(u[a]):null};var ma=c.$on("$translateReady",function(){la.resolve(),ma(),ma=null}),na=c.$on("$translateChangeEnd",function(){la.resolve(),na(),na=null});if(o){if(angular.equals(u,{})&&V.use()&&V.use(V.use()),g&&g.length)for(var oa=function(a){return O(a.key,a.table),c.$emit("$translateChangeEnd",{language:a.key}),a},pa=0,qa=g.length;pa13&&t(v);if(p.$observe("translateDefault",function(a){h.defaultText=a,y()}),j&&p.$observe("translateValues",function(a){a&&h.$parent.$watch(function(){angular.extend(h.interpolateParams,d(a)(h.$parent))})}),l){var w=function(a){p.$observe(a,function(b){var c=angular.lowercase(a.substr(14,1))+a.substr(15);h.interpolateParams[c]=b})};for(var x in p)Object.prototype.hasOwnProperty.call(p,x)&&"translateValue"===x.substr(0,14)&&"translateValues"!==x&&w(x)}var y=function(){for(var a in q)q.hasOwnProperty(a)&&void 0!==q[a]&&z(a,q[a],h,h.interpolateParams,h.defaultText,h.translateNamespace)},z=function(b,c,d,e,f,g){c?(g&&"."===c.charAt(0)&&(c=g+c),a(c,e,k,f,d.translateLanguage).then(function(a){A(a,d,!0,b)},function(a){A(a,d,!1,b)})):A(c,d,!1,b)},A=function(b,d,e,f){if(e||"undefined"!=typeof d.defaultText&&(b=d.defaultText),"translate"===f){(e||!e&&!a.isKeepContent()&&"undefined"==typeof p.translateKeepContent)&&o.empty().append(d.preText+b+d.postText);var g=a.isPostCompilingEnabled(),h="undefined"!=typeof i.translateCompile,j=h&&"false"!==i.translateCompile;(g&&!h||j)&&c(o.contents())(d)}else{var k=p.$attr[f];"data-"===k.substr(0,5)&&(k=k.substr(5)),k=k.substr(15),o.attr(k,b)}};(j||l||p.translateDefault)&&h.$watch("interpolateParams",y,!0),h.$on("translateLanguageChanged",y);var B=e.$on("$translateChangeSuccess",y);o.text().length?s(p.translate?p.translate:""):p.translate&&s(p.translate),y(),h.$on("$destroy",B)}}}}function f(a){"use strict";return a.translateNamespace?a.translateNamespace:a.$parent?f(a.$parent):void 0}function g(a,b){"use strict";return{restrict:"A",priority:a.directivePriority(),link:function(c,d,e){var f,g,i={},j=function(){angular.forEach(f,function(b,f){b&&(i[f]=!0,c.translateNamespace&&"."===b.charAt(0)&&(b=c.translateNamespace+b),a(b,g,e.translateInterpolation,void 0,c.translateLanguage).then(function(a){d.attr(f,a)},function(a){d.attr(f,a)}))}),angular.forEach(i,function(a,b){f[b]||(d.removeAttr(b),delete i[b])})};h(c,e.translateAttr,function(a){f=a},j),h(c,e.translateValues,function(a){g=a},j),e.translateValues&&c.$watch(e.translateValues,j,!0),c.$on("translateLanguageChanged",j);var k=b.$on("$translateChangeSuccess",j);j(),c.$on("$destroy",k)}}}function h(a,b,c,d){"use strict";b&&("::"===b.substr(0,2)?b=b.substr(2):a.$watch(b,function(a){c(a),d()},!0),c(a.$eval(b)))}function i(a,b){"use strict";return{compile:function(c){var d=function(b){b.addClass(a.cloakClassName())},e=function(b){b.removeClass(a.cloakClassName())};return d(c),function(c,f,g){var h=e.bind(this,f),i=d.bind(this,f);g.translateCloak&&g.translateCloak.length?(g.$observe("translateCloak",function(b){a(b).then(h,i)}),b.$on("$translateChangeSuccess",function(){a(g.translateCloak).then(h,i)})):a.onReady(h)}}}}function j(){"use strict";return{restrict:"A",scope:!0,compile:function(){return{pre:function(a,b,c){a.translateNamespace=f(a),a.translateNamespace&&"."===c.translateNamespace.charAt(0)?a.translateNamespace+=c.translateNamespace:a.translateNamespace=c.translateNamespace}}}}}function f(a){"use strict";return a.translateNamespace?a.translateNamespace:a.$parent?f(a.$parent):void 0}function k(){"use strict";return{restrict:"A",scope:!0,compile:function(){return function(a,b,c){c.$observe("translateLanguage",function(b){a.translateLanguage=b}),a.$watch("translateLanguage",function(){a.$broadcast("translateLanguageChanged")})}}}}function l(a,b){"use strict";var c=function(c,d,e,f){if(!angular.isObject(d)){var g=this||{__SCOPE_IS_NOT_AVAILABLE:"More info at https://github.com/angular/angular.js/commit/8863b9d04c722b278fa93c5d66ad1e578ad6eb1f"};d=a(d)(g)}return b.instant(c,d,e,f)};return b.statefulFilter()&&(c.$stateful=!0),c}function m(a){"use strict";return a("translations")}return a.$inject=["$translate"],c.$inject=["$STORAGE_KEY","$windowProvider","$translateSanitizationProvider","pascalprechtTranslateOverrider"],d.$inject=["$interpolate","$translateSanitization"],e.$inject=["$translate","$interpolate","$compile","$parse","$rootScope"],g.$inject=["$translate","$rootScope"],i.$inject=["$translate","$rootScope"],l.$inject=["$parse","$translate"],m.$inject=["$cacheFactory"],angular.module("pascalprecht.translate",["ng"]).run(a),a.displayName="runTranslate",angular.module("pascalprecht.translate").provider("$translateSanitization",b),angular.module("pascalprecht.translate").constant("pascalprechtTranslateOverrider",{}).provider("$translate",c),c.displayName="displayName",angular.module("pascalprecht.translate").factory("$translateDefaultInterpolation",d),d.displayName="$translateDefaultInterpolation",angular.module("pascalprecht.translate").constant("$STORAGE_KEY","NG_TRANSLATE_LANG_KEY"),angular.module("pascalprecht.translate").directive("translate",e),e.displayName="translateDirective",angular.module("pascalprecht.translate").directive("translateAttr",g),g.displayName="translateAttrDirective",angular.module("pascalprecht.translate").directive("translateCloak",i),i.displayName="translateCloakDirective",angular.module("pascalprecht.translate").directive("translateNamespace",j),j.displayName="translateNamespaceDirective",angular.module("pascalprecht.translate").directive("translateLanguage",k),k.displayName="translateLanguageDirective",angular.module("pascalprecht.translate").filter("translate",l),l.displayName="translateFilterFactory",angular.module("pascalprecht.translate").factory("$translationCache",m),m.displayName="$translationCache","pascalprecht.translate"}); \ No newline at end of file diff --git a/zbf-admin/src/main/resources/static/designer/libs/angular_1.3.13/angular.js b/zbf-admin/src/main/resources/static/designer/libs/angular_1.3.13/angular.js new file mode 100644 index 0000000..4f4f492 --- /dev/null +++ b/zbf-admin/src/main/resources/static/designer/libs/angular_1.3.13/angular.js @@ -0,0 +1,26130 @@ +/** + * @license AngularJS v1.3.13 + * (c) 2010-2014 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, document, undefined) {'use strict'; + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning + * error from returned function, for cases when a particular type of error is useful. + * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance + */ + +function minErr(module, ErrorConstructor) { + ErrorConstructor = ErrorConstructor || Error; + return function() { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + + message, i; + + message = prefix + template.replace(/\{\d+\}/g, function(match) { + var index = +match.slice(1, -1), arg; + + if (index + 2 < templateArgs.length) { + return toDebugString(templateArgs[index + 2]); + } + return match; + }); + + message = message + '\nhttp://errors.angularjs.org/1.3.13/' + + (module ? module + '/' : '') + code; + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' + + encodeURIComponent(toDebugString(arguments[i])); + } + return new ErrorConstructor(message); + }; +} + +/* We need to tell jshint what variables are being exported */ +/* global angular: true, + msie: true, + jqLite: true, + jQuery: true, + slice: true, + splice: true, + push: true, + toString: true, + ngMinErr: true, + angularModule: true, + uid: true, + REGEX_STRING_REGEXP: true, + VALIDITY_STATE_PROPERTY: true, + + lowercase: true, + uppercase: true, + manualLowercase: true, + manualUppercase: true, + nodeName_: true, + isArrayLike: true, + forEach: true, + sortedKeys: true, + forEachSorted: true, + reverseParams: true, + nextUid: true, + setHashKey: true, + extend: true, + int: true, + inherit: true, + noop: true, + identity: true, + valueFn: true, + isUndefined: true, + isDefined: true, + isObject: true, + isString: true, + isNumber: true, + isDate: true, + isArray: true, + isFunction: true, + isRegExp: true, + isWindow: true, + isScope: true, + isFile: true, + isFormData: true, + isBlob: true, + isBoolean: true, + isPromiseLike: true, + trim: true, + escapeForRegexp: true, + isElement: true, + makeMap: true, + includes: true, + arrayRemove: true, + copy: true, + shallowCopy: true, + equals: true, + csp: true, + concat: true, + sliceArgs: true, + bind: true, + toJsonReplacer: true, + toJson: true, + fromJson: true, + startingTag: true, + tryDecodeURIComponent: true, + parseKeyValue: true, + toKeyValue: true, + encodeUriSegment: true, + encodeUriQuery: true, + angularInit: true, + bootstrap: true, + getTestability: true, + snake_case: true, + bindJQuery: true, + assertArg: true, + assertArgFn: true, + assertNotHasOwnProperty: true, + getter: true, + getBlockNodes: true, + hasOwnProperty: true, + createMap: true, + + NODE_TYPE_ELEMENT: true, + NODE_TYPE_TEXT: true, + NODE_TYPE_COMMENT: true, + NODE_TYPE_DOCUMENT: true, + NODE_TYPE_DOCUMENT_FRAGMENT: true, +*/ + +//////////////////////////////////// + +/** + * @ngdoc module + * @name ng + * @module ng + * @description + * + * # ng (core module) + * The ng module is loaded by default when an AngularJS application is started. The module itself + * contains the essential components for an AngularJS application to function. The table below + * lists a high level breakdown of each of the services/factories, filters, directives and testing + * components available within this core module. + * + *
    + */ + +var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; + +// The name of a form control's ValidityState property. +// This is used so that it's possible for internal tests to create mock ValidityStates. +var VALIDITY_STATE_PROPERTY = 'validity'; + +/** + * @ngdoc function + * @name angular.lowercase + * @module ng + * @kind function + * + * @description Converts the specified string to lowercase. + * @param {string} string String to be converted to lowercase. + * @returns {string} Lowercased string. + */ +var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * @ngdoc function + * @name angular.uppercase + * @module ng + * @kind function + * + * @description Converts the specified string to uppercase. + * @param {string} string String to be converted to uppercase. + * @returns {string} Uppercased string. + */ +var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;}; + + +var manualLowercase = function(s) { + /* jshint bitwise: false */ + return isString(s) + ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) + : s; +}; +var manualUppercase = function(s) { + /* jshint bitwise: false */ + return isString(s) + ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) + : s; +}; + + +// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish +// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods +// with correct but slower alternatives. +if ('i' !== 'I'.toLowerCase()) { + lowercase = manualLowercase; + uppercase = manualUppercase; +} + + +var + msie, // holds major version number for IE, or NaN if UA is not IE. + jqLite, // delay binding since jQuery could be loaded after us. + jQuery, // delay binding + slice = [].slice, + splice = [].splice, + push = [].push, + toString = Object.prototype.toString, + ngMinErr = minErr('ng'), + + /** @name angular */ + angular = window.angular || (window.angular = {}), + angularModule, + uid = 0; + +/** + * documentMode is an IE-only property + * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx + */ +msie = document.documentMode; + + +/** + * @private + * @param {*} obj + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, + * String ...) + */ +function isArrayLike(obj) { + if (obj == null || isWindow(obj)) { + return false; + } + + var length = obj.length; + + if (obj.nodeType === NODE_TYPE_ELEMENT && length) { + return true; + } + + return isString(obj) || isArray(obj) || length === 0 || + typeof length === 'number' && length > 0 && (length - 1) in obj; +} + +/** + * @ngdoc function + * @name angular.forEach + * @module ng + * @kind function + * + * @description + * Invokes the `iterator` function once for each item in `obj` collection, which can be either an + * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value` + * is the value of an object property or an array element, `key` is the object property key or + * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional. + * + * It is worth noting that `.forEach` does not iterate over inherited properties because it filters + * using the `hasOwnProperty` method. + * + * Unlike ES262's + * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18), + * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just + * return the value provided. + * + ```js + var values = {name: 'misko', gender: 'male'}; + var log = []; + angular.forEach(values, function(value, key) { + this.push(key + ': ' + value); + }, log); + expect(log).toEqual(['name: misko', 'gender: male']); + ``` + * + * @param {Object|Array} obj Object to iterate over. + * @param {Function} iterator Iterator function. + * @param {Object=} context Object to become context (`this`) for the iterator function. + * @returns {Object|Array} Reference to `obj`. + */ + +function forEach(obj, iterator, context) { + var key, length; + if (obj) { + if (isFunction(obj)) { + for (key in obj) { + // Need to check if hasOwnProperty exists, + // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function + if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { + iterator.call(context, obj[key], key, obj); + } + } + } else if (isArray(obj) || isArrayLike(obj)) { + var isPrimitive = typeof obj !== 'object'; + for (key = 0, length = obj.length; key < length; key++) { + if (isPrimitive || key in obj) { + iterator.call(context, obj[key], key, obj); + } + } + } else if (obj.forEach && obj.forEach !== forEach) { + obj.forEach(iterator, context, obj); + } else { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(context, obj[key], key, obj); + } + } + } + } + return obj; +} + +function sortedKeys(obj) { + return Object.keys(obj).sort(); +} + +function forEachSorted(obj, iterator, context) { + var keys = sortedKeys(obj); + for (var i = 0; i < keys.length; i++) { + iterator.call(context, obj[keys[i]], keys[i]); + } + return keys; +} + + +/** + * when using forEach the params are value, key, but it is often useful to have key, value. + * @param {function(string, *)} iteratorFn + * @returns {function(*, string)} + */ +function reverseParams(iteratorFn) { + return function(value, key) { iteratorFn(key, value); }; +} + +/** + * A consistent way of creating unique IDs in angular. + * + * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before + * we hit number precision issues in JavaScript. + * + * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M + * + * @returns {number} an unique alpha-numeric string + */ +function nextUid() { + return ++uid; +} + + +/** + * Set or clear the hashkey for an object. + * @param obj object + * @param h the hashkey (!truthy to delete the hashkey) + */ +function setHashKey(obj, h) { + if (h) { + obj.$$hashKey = h; + } else { + delete obj.$$hashKey; + } +} + +/** + * @ngdoc function + * @name angular.extend + * @module ng + * @kind function + * + * @description + * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s) + * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so + * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`. + * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy). + * + * @param {Object} dst Destination object. + * @param {...Object} src Source object(s). + * @returns {Object} Reference to `dst`. + */ +function extend(dst) { + var h = dst.$$hashKey; + + for (var i = 1, ii = arguments.length; i < ii; i++) { + var obj = arguments[i]; + if (obj) { + var keys = Object.keys(obj); + for (var j = 0, jj = keys.length; j < jj; j++) { + var key = keys[j]; + dst[key] = obj[key]; + } + } + } + + setHashKey(dst, h); + return dst; +} + +function int(str) { + return parseInt(str, 10); +} + + +function inherit(parent, extra) { + return extend(Object.create(parent), extra); +} + +/** + * @ngdoc function + * @name angular.noop + * @module ng + * @kind function + * + * @description + * A function that performs no operations. This function can be useful when writing code in the + * functional style. + ```js + function foo(callback) { + var result = calculateResult(); + (callback || angular.noop)(result); + } + ``` + */ +function noop() {} +noop.$inject = []; + + +/** + * @ngdoc function + * @name angular.identity + * @module ng + * @kind function + * + * @description + * A function that returns its first argument. This function is useful when writing code in the + * functional style. + * + ```js + function transformer(transformationFn, value) { + return (transformationFn || angular.identity)(value); + }; + ``` + * @param {*} value to be returned. + * @returns {*} the value passed in. + */ +function identity($) {return $;} +identity.$inject = []; + + +function valueFn(value) {return function() {return value;};} + +/** + * @ngdoc function + * @name angular.isUndefined + * @module ng + * @kind function + * + * @description + * Determines if a reference is undefined. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is undefined. + */ +function isUndefined(value) {return typeof value === 'undefined';} + + +/** + * @ngdoc function + * @name angular.isDefined + * @module ng + * @kind function + * + * @description + * Determines if a reference is defined. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is defined. + */ +function isDefined(value) {return typeof value !== 'undefined';} + + +/** + * @ngdoc function + * @name angular.isObject + * @module ng + * @kind function + * + * @description + * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not + * considered to be objects. Note that JavaScript arrays are objects. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is an `Object` but not `null`. + */ +function isObject(value) { + // http://jsperf.com/isobject4 + return value !== null && typeof value === 'object'; +} + + +/** + * @ngdoc function + * @name angular.isString + * @module ng + * @kind function + * + * @description + * Determines if a reference is a `String`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `String`. + */ +function isString(value) {return typeof value === 'string';} + + +/** + * @ngdoc function + * @name angular.isNumber + * @module ng + * @kind function + * + * @description + * Determines if a reference is a `Number`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Number`. + */ +function isNumber(value) {return typeof value === 'number';} + + +/** + * @ngdoc function + * @name angular.isDate + * @module ng + * @kind function + * + * @description + * Determines if a value is a date. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Date`. + */ +function isDate(value) { + return toString.call(value) === '[object Date]'; +} + + +/** + * @ngdoc function + * @name angular.isArray + * @module ng + * @kind function + * + * @description + * Determines if a reference is an `Array`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is an `Array`. + */ +var isArray = Array.isArray; + +/** + * @ngdoc function + * @name angular.isFunction + * @module ng + * @kind function + * + * @description + * Determines if a reference is a `Function`. + * + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `Function`. + */ +function isFunction(value) {return typeof value === 'function';} + + +/** + * Determines if a value is a regular expression object. + * + * @private + * @param {*} value Reference to check. + * @returns {boolean} True if `value` is a `RegExp`. + */ +function isRegExp(value) { + return toString.call(value) === '[object RegExp]'; +} + + +/** + * Checks if `obj` is a window object. + * + * @private + * @param {*} obj Object to check + * @returns {boolean} True if `obj` is a window obj. + */ +function isWindow(obj) { + return obj && obj.window === obj; +} + + +function isScope(obj) { + return obj && obj.$evalAsync && obj.$watch; +} + + +function isFile(obj) { + return toString.call(obj) === '[object File]'; +} + + +function isFormData(obj) { + return toString.call(obj) === '[object FormData]'; +} + + +function isBlob(obj) { + return toString.call(obj) === '[object Blob]'; +} + + +function isBoolean(value) { + return typeof value === 'boolean'; +} + + +function isPromiseLike(obj) { + return obj && isFunction(obj.then); +} + + +var trim = function(value) { + return isString(value) ? value.trim() : value; +}; + +// Copied from: +// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021 +// Prereq: s is a string. +var escapeForRegexp = function(s) { + return s.replace(/([-()\[\]{}+?*.$\^|,:#= 0) + array.splice(index, 1); + return value; +} + +/** + * @ngdoc function + * @name angular.copy + * @module ng + * @kind function + * + * @description + * Creates a deep copy of `source`, which should be an object or an array. + * + * * If no destination is supplied, a copy of the object or array is created. + * * If a destination is provided, all of its elements (for arrays) or properties (for objects) + * are deleted and then all elements/properties from the source are copied to it. + * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. + * * If `source` is identical to 'destination' an exception will be thrown. + * + * @param {*} source The source that will be used to make a copy. + * Can be any type, including primitives, `null`, and `undefined`. + * @param {(Object|Array)=} destination Destination into which the source is copied. If + * provided, must be of the same type as `source`. + * @returns {*} The copy or updated `destination`, if `destination` was specified. + * + * @example + + +
    +
    + Name:
    + E-mail:
    + Gender: male + female
    + + +
    +
    form = {{user | json}}
    +
    master = {{master | json}}
    +
    + + +
    +
    + */ +function copy(source, destination, stackSource, stackDest) { + if (isWindow(source) || isScope(source)) { + throw ngMinErr('cpws', + "Can't copy! Making copies of Window or Scope instances is not supported."); + } + + if (!destination) { + destination = source; + if (source) { + if (isArray(source)) { + destination = copy(source, [], stackSource, stackDest); + } else if (isDate(source)) { + destination = new Date(source.getTime()); + } else if (isRegExp(source)) { + destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]); + destination.lastIndex = source.lastIndex; + } else if (isObject(source)) { + var emptyObject = Object.create(Object.getPrototypeOf(source)); + destination = copy(source, emptyObject, stackSource, stackDest); + } + } + } else { + if (source === destination) throw ngMinErr('cpi', + "Can't copy! Source and destination are identical."); + + stackSource = stackSource || []; + stackDest = stackDest || []; + + if (isObject(source)) { + var index = stackSource.indexOf(source); + if (index !== -1) return stackDest[index]; + + stackSource.push(source); + stackDest.push(destination); + } + + var result; + if (isArray(source)) { + destination.length = 0; + for (var i = 0; i < source.length; i++) { + result = copy(source[i], null, stackSource, stackDest); + if (isObject(source[i])) { + stackSource.push(source[i]); + stackDest.push(result); + } + destination.push(result); + } + } else { + var h = destination.$$hashKey; + if (isArray(destination)) { + destination.length = 0; + } else { + forEach(destination, function(value, key) { + delete destination[key]; + }); + } + for (var key in source) { + if (source.hasOwnProperty(key)) { + result = copy(source[key], null, stackSource, stackDest); + if (isObject(source[key])) { + stackSource.push(source[key]); + stackDest.push(result); + } + destination[key] = result; + } + } + setHashKey(destination,h); + } + + } + return destination; +} + +/** + * Creates a shallow copy of an object, an array or a primitive. + * + * Assumes that there are no proto properties for objects. + */ +function shallowCopy(src, dst) { + if (isArray(src)) { + dst = dst || []; + + for (var i = 0, ii = src.length; i < ii; i++) { + dst[i] = src[i]; + } + } else if (isObject(src)) { + dst = dst || {}; + + for (var key in src) { + if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) { + dst[key] = src[key]; + } + } + } + + return dst || src; +} + + +/** + * @ngdoc function + * @name angular.equals + * @module ng + * @kind function + * + * @description + * Determines if two objects or two values are equivalent. Supports value types, regular + * expressions, arrays and objects. + * + * Two objects or values are considered equivalent if at least one of the following is true: + * + * * Both objects or values pass `===` comparison. + * * Both objects or values are of the same type and all of their properties are equal by + * comparing them with `angular.equals`. + * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) + * * Both values represent the same regular expression (In JavaScript, + * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual + * representation matches). + * + * During a property comparison, properties of `function` type and properties with names + * that begin with `$` are ignored. + * + * Scope and DOMWindow objects are being compared only by identify (`===`). + * + * @param {*} o1 Object or value to compare. + * @param {*} o2 Object or value to compare. + * @returns {boolean} True if arguments are equal. + */ +function equals(o1, o2) { + if (o1 === o2) return true; + if (o1 === null || o2 === null) return false; + if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN + var t1 = typeof o1, t2 = typeof o2, length, key, keySet; + if (t1 == t2) { + if (t1 == 'object') { + if (isArray(o1)) { + if (!isArray(o2)) return false; + if ((length = o1.length) == o2.length) { + for (key = 0; key < length; key++) { + if (!equals(o1[key], o2[key])) return false; + } + return true; + } + } else if (isDate(o1)) { + if (!isDate(o2)) return false; + return equals(o1.getTime(), o2.getTime()); + } else if (isRegExp(o1) && isRegExp(o2)) { + return o1.toString() == o2.toString(); + } else { + if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false; + keySet = {}; + for (key in o1) { + if (key.charAt(0) === '$' || isFunction(o1[key])) continue; + if (!equals(o1[key], o2[key])) return false; + keySet[key] = true; + } + for (key in o2) { + if (!keySet.hasOwnProperty(key) && + key.charAt(0) !== '$' && + o2[key] !== undefined && + !isFunction(o2[key])) return false; + } + return true; + } + } + } + return false; +} + +var csp = function() { + if (isDefined(csp.isActive_)) return csp.isActive_; + + var active = !!(document.querySelector('[ng-csp]') || + document.querySelector('[data-ng-csp]')); + + if (!active) { + try { + /* jshint -W031, -W054 */ + new Function(''); + /* jshint +W031, +W054 */ + } catch (e) { + active = true; + } + } + + return (csp.isActive_ = active); +}; + + + +function concat(array1, array2, index) { + return array1.concat(slice.call(array2, index)); +} + +function sliceArgs(args, startIndex) { + return slice.call(args, startIndex || 0); +} + + +/* jshint -W101 */ +/** + * @ngdoc function + * @name angular.bind + * @module ng + * @kind function + * + * @description + * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for + * `fn`). You can supply optional `args` that are prebound to the function. This feature is also + * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as + * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application). + * + * @param {Object} self Context which `fn` should be evaluated in. + * @param {function()} fn Function to be bound. + * @param {...*} args Optional arguments to be prebound to the `fn` function call. + * @returns {function()} Function that wraps the `fn` with all the specified bindings. + */ +/* jshint +W101 */ +function bind(self, fn) { + var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : []; + if (isFunction(fn) && !(fn instanceof RegExp)) { + return curryArgs.length + ? function() { + return arguments.length + ? fn.apply(self, concat(curryArgs, arguments, 0)) + : fn.apply(self, curryArgs); + } + : function() { + return arguments.length + ? fn.apply(self, arguments) + : fn.call(self); + }; + } else { + // in IE, native methods are not functions so they cannot be bound (note: they don't need to be) + return fn; + } +} + + +function toJsonReplacer(key, value) { + var val = value; + + if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') { + val = undefined; + } else if (isWindow(value)) { + val = '$WINDOW'; + } else if (value && document === value) { + val = '$DOCUMENT'; + } else if (isScope(value)) { + val = '$SCOPE'; + } + + return val; +} + + +/** + * @ngdoc function + * @name angular.toJson + * @module ng + * @kind function + * + * @description + * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be + * stripped since angular uses this notation internally. + * + * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. + * @param {boolean|number=} pretty If set to true, the JSON output will contain newlines and whitespace. + * If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2). + * @returns {string|undefined} JSON-ified string representing `obj`. + */ +function toJson(obj, pretty) { + if (typeof obj === 'undefined') return undefined; + if (!isNumber(pretty)) { + pretty = pretty ? 2 : null; + } + return JSON.stringify(obj, toJsonReplacer, pretty); +} + + +/** + * @ngdoc function + * @name angular.fromJson + * @module ng + * @kind function + * + * @description + * Deserializes a JSON string. + * + * @param {string} json JSON string to deserialize. + * @returns {Object|Array|string|number} Deserialized JSON string. + */ +function fromJson(json) { + return isString(json) + ? JSON.parse(json) + : json; +} + + +/** + * @returns {string} Returns the string representation of the element. + */ +function startingTag(element) { + element = jqLite(element).clone(); + try { + // turns out IE does not let you set .html() on elements which + // are not allowed to have children. So we just ignore it. + element.empty(); + } catch (e) {} + var elemHtml = jqLite('
    ').append(element).html(); + try { + return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : + elemHtml. + match(/^(<[^>]+>)/)[1]. + replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); }); + } catch (e) { + return lowercase(elemHtml); + } + +} + + +///////////////////////////////////////////////// + +/** + * Tries to decode the URI component without throwing an exception. + * + * @private + * @param str value potential URI component to check. + * @returns {boolean} True if `value` can be decoded + * with the decodeURIComponent function. + */ +function tryDecodeURIComponent(value) { + try { + return decodeURIComponent(value); + } catch (e) { + // Ignore any invalid uri component + } +} + + +/** + * Parses an escaped url query string into key-value pairs. + * @returns {Object.} + */ +function parseKeyValue(/**string*/keyValue) { + var obj = {}, key_value, key; + forEach((keyValue || "").split('&'), function(keyValue) { + if (keyValue) { + key_value = keyValue.replace(/\+/g,'%20').split('='); + key = tryDecodeURIComponent(key_value[0]); + if (isDefined(key)) { + var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; + if (!hasOwnProperty.call(obj, key)) { + obj[key] = val; + } else if (isArray(obj[key])) { + obj[key].push(val); + } else { + obj[key] = [obj[key],val]; + } + } + } + }); + return obj; +} + +function toKeyValue(obj) { + var parts = []; + forEach(obj, function(value, key) { + if (isArray(value)) { + forEach(value, function(arrayValue) { + parts.push(encodeUriQuery(key, true) + + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); + }); + } else { + parts.push(encodeUriQuery(key, true) + + (value === true ? '' : '=' + encodeUriQuery(value, true))); + } + }); + return parts.length ? parts.join('&') : ''; +} + + +/** + * We need our custom method because encodeURIComponent is too aggressive and doesn't follow + * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path + * segments: + * segment = *pchar + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * pct-encoded = "%" HEXDIG HEXDIG + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +function encodeUriSegment(val) { + return encodeUriQuery(val, true). + replace(/%26/gi, '&'). + replace(/%3D/gi, '='). + replace(/%2B/gi, '+'); +} + + +/** + * This method is intended for encoding *key* or *value* parts of query component. We need a custom + * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be + * encoded per http://tools.ietf.org/html/rfc3986: + * query = *( pchar / "/" / "?" ) + * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + */ +function encodeUriQuery(val, pctEncodeSpaces) { + return encodeURIComponent(val). + replace(/%40/gi, '@'). + replace(/%3A/gi, ':'). + replace(/%24/g, '$'). + replace(/%2C/gi, ','). + replace(/%3B/gi, ';'). + replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); +} + +var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-']; + +function getNgAttribute(element, ngAttr) { + var attr, i, ii = ngAttrPrefixes.length; + element = jqLite(element); + for (i = 0; i < ii; ++i) { + attr = ngAttrPrefixes[i] + ngAttr; + if (isString(attr = element.attr(attr))) { + return attr; + } + } + return null; +} + +/** + * @ngdoc directive + * @name ngApp + * @module ng + * + * @element ANY + * @param {angular.Module} ngApp an optional application + * {@link angular.module module} name to load. + * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be + * created in "strict-di" mode. This means that the application will fail to invoke functions which + * do not use explicit function annotation (and are thus unsuitable for minification), as described + * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in + * tracking down the root of these bugs. + * + * @description + * + * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive + * designates the **root element** of the application and is typically placed near the root element + * of the page - e.g. on the `` or `` tags. + * + * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp` + * found in the document will be used to define the root element to auto-bootstrap as an + * application. To run multiple applications in an HTML document you must manually bootstrap them using + * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other. + * + * You can specify an **AngularJS module** to be used as the root module for the application. This + * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It + * should contain the application code needed or have dependencies on other modules that will + * contain the code. See {@link angular.module} for more information. + * + * In the example below if the `ngApp` directive were not placed on the `html` element then the + * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}` + * would not be resolved to `3`. + * + * `ngApp` is the easiest, and most common way to bootstrap an application. + * + + +
    + I can add: {{a}} + {{b}} = {{ a+b }} +
    +
    + + angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) { + $scope.a = 1; + $scope.b = 2; + }); + +
    + * + * Using `ngStrictDi`, you would see something like this: + * + + +
    +
    + I can add: {{a}} + {{b}} = {{ a+b }} + +

    This renders because the controller does not fail to + instantiate, by using explicit annotation style (see + script.js for details) +

    +
    + +
    + Name:
    + Hello, {{name}}! + +

    This renders because the controller does not fail to + instantiate, by using explicit annotation style + (see script.js for details) +

    +
    + +
    + I can add: {{a}} + {{b}} = {{ a+b }} + +

    The controller could not be instantiated, due to relying + on automatic function annotations (which are disabled in + strict mode). As such, the content of this section is not + interpolated, and there should be an error in your web console. +

    +
    +
    +
    + + angular.module('ngAppStrictDemo', []) + // BadController will fail to instantiate, due to relying on automatic function annotation, + // rather than an explicit annotation + .controller('BadController', function($scope) { + $scope.a = 1; + $scope.b = 2; + }) + // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated, + // due to using explicit annotations using the array style and $inject property, respectively. + .controller('GoodController1', ['$scope', function($scope) { + $scope.a = 1; + $scope.b = 2; + }]) + .controller('GoodController2', GoodController2); + function GoodController2($scope) { + $scope.name = "World"; + } + GoodController2.$inject = ['$scope']; + + + div[ng-controller] { + margin-bottom: 1em; + -webkit-border-radius: 4px; + border-radius: 4px; + border: 1px solid; + padding: .5em; + } + div[ng-controller^=Good] { + border-color: #d6e9c6; + background-color: #dff0d8; + color: #3c763d; + } + div[ng-controller^=Bad] { + border-color: #ebccd1; + background-color: #f2dede; + color: #a94442; + margin-bottom: 0; + } + +
    + */ +function angularInit(element, bootstrap) { + var appElement, + module, + config = {}; + + // The element `element` has priority over any other element + forEach(ngAttrPrefixes, function(prefix) { + var name = prefix + 'app'; + + if (!appElement && element.hasAttribute && element.hasAttribute(name)) { + appElement = element; + module = element.getAttribute(name); + } + }); + forEach(ngAttrPrefixes, function(prefix) { + var name = prefix + 'app'; + var candidate; + + if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) { + appElement = candidate; + module = candidate.getAttribute(name); + } + }); + if (appElement) { + config.strictDi = getNgAttribute(appElement, "strict-di") !== null; + bootstrap(appElement, module ? [module] : [], config); + } +} + +/** + * @ngdoc function + * @name angular.bootstrap + * @module ng + * @description + * Use this function to manually start up angular application. + * + * See: {@link guide/bootstrap Bootstrap} + * + * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually. + * They must use {@link ng.directive:ngApp ngApp}. + * + * Angular will detect if it has been loaded into the browser more than once and only allow the + * first loaded script to be bootstrapped and will report a warning to the browser console for + * each of the subsequent scripts. This prevents strange results in applications, where otherwise + * multiple instances of Angular try to work on the DOM. + * + * ```html + * + * + * + *
    + * {{greeting}} + *
    + * + * + * + * + * + * ``` + * + * @param {DOMElement} element DOM element which is the root of angular application. + * @param {Array=} modules an array of modules to load into the application. + * Each item in the array should be the name of a predefined module or a (DI annotated) + * function that will be invoked by the injector as a `config` block. + * See: {@link angular.module modules} + * @param {Object=} config an object for defining configuration options for the application. The + * following keys are supported: + * + * * `strictDi` - disable automatic function annotation for the application. This is meant to + * assist in finding bugs which break minified code. Defaults to `false`. + * + * @returns {auto.$injector} Returns the newly created injector for this app. + */ +function bootstrap(element, modules, config) { + if (!isObject(config)) config = {}; + var defaultConfig = { + strictDi: false + }; + config = extend(defaultConfig, config); + var doBootstrap = function() { + element = jqLite(element); + + if (element.injector()) { + var tag = (element[0] === document) ? 'document' : startingTag(element); + //Encode angle brackets to prevent input from being sanitized to empty string #8683 + throw ngMinErr( + 'btstrpd', + "App Already Bootstrapped with this Element '{0}'", + tag.replace(//,'>')); + } + + modules = modules || []; + modules.unshift(['$provide', function($provide) { + $provide.value('$rootElement', element); + }]); + + if (config.debugInfoEnabled) { + // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`. + modules.push(['$compileProvider', function($compileProvider) { + $compileProvider.debugInfoEnabled(true); + }]); + } + + modules.unshift('ng'); + var injector = createInjector(modules, config.strictDi); + injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', + function bootstrapApply(scope, element, compile, injector) { + scope.$apply(function() { + element.data('$injector', injector); + compile(element)(scope); + }); + }] + ); + return injector; + }; + + var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/; + var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + + if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) { + config.debugInfoEnabled = true; + window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, ''); + } + + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { + return doBootstrap(); + } + + window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); + angular.resumeBootstrap = function(extraModules) { + forEach(extraModules, function(module) { + modules.push(module); + }); + return doBootstrap(); + }; + + if (isFunction(angular.resumeDeferredBootstrap)) { + angular.resumeDeferredBootstrap(); + } +} + +/** + * @ngdoc function + * @name angular.reloadWithDebugInfo + * @module ng + * @description + * Use this function to reload the current application with debug information turned on. + * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`. + * + * See {@link ng.$compileProvider#debugInfoEnabled} for more. + */ +function reloadWithDebugInfo() { + window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name; + window.location.reload(); +} + +/** + * @name angular.getTestability + * @module ng + * @description + * Get the testability service for the instance of Angular on the given + * element. + * @param {DOMElement} element DOM element which is the root of angular application. + */ +function getTestability(rootElement) { + var injector = angular.element(rootElement).injector(); + if (!injector) { + throw ngMinErr('test', + 'no injector found for element argument to getTestability'); + } + return injector.get('$$testability'); +} + +var SNAKE_CASE_REGEXP = /[A-Z]/g; +function snake_case(name, separator) { + separator = separator || '_'; + return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { + return (pos ? separator : '') + letter.toLowerCase(); + }); +} + +var bindJQueryFired = false; +var skipDestroyOnNextJQueryCleanData; +function bindJQuery() { + var originalCleanData; + + if (bindJQueryFired) { + return; + } + + // bind to jQuery if present; + jQuery = window.jQuery; + // Use jQuery if it exists with proper functionality, otherwise default to us. + // Angular 1.2+ requires jQuery 1.7+ for on()/off() support. + // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older + // versions. It will not work for sure with jQuery <1.7, though. + if (jQuery && jQuery.fn.on) { + jqLite = jQuery; + extend(jQuery.fn, { + scope: JQLitePrototype.scope, + isolateScope: JQLitePrototype.isolateScope, + controller: JQLitePrototype.controller, + injector: JQLitePrototype.injector, + inheritedData: JQLitePrototype.inheritedData + }); + + // All nodes removed from the DOM via various jQuery APIs like .remove() + // are passed through jQuery.cleanData. Monkey-patch this method to fire + // the $destroy event on all removed nodes. + originalCleanData = jQuery.cleanData; + jQuery.cleanData = function(elems) { + var events; + if (!skipDestroyOnNextJQueryCleanData) { + for (var i = 0, elem; (elem = elems[i]) != null; i++) { + events = jQuery._data(elem, "events"); + if (events && events.$destroy) { + jQuery(elem).triggerHandler('$destroy'); + } + } + } else { + skipDestroyOnNextJQueryCleanData = false; + } + originalCleanData(elems); + }; + } else { + jqLite = JQLite; + } + + angular.element = jqLite; + + // Prevent double-proxying. + bindJQueryFired = true; +} + +/** + * throw error if the argument is falsy. + */ +function assertArg(arg, name, reason) { + if (!arg) { + throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); + } + return arg; +} + +function assertArgFn(arg, name, acceptArrayAnnotation) { + if (acceptArrayAnnotation && isArray(arg)) { + arg = arg[arg.length - 1]; + } + + assertArg(isFunction(arg), name, 'not a function, got ' + + (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg)); + return arg; +} + +/** + * throw error if the name given is hasOwnProperty + * @param {String} name the name to test + * @param {String} context the context in which the name is used, such as module or directive + */ +function assertNotHasOwnProperty(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context); + } +} + +/** + * Return the value accessible from the object by path. Any undefined traversals are ignored + * @param {Object} obj starting object + * @param {String} path path to traverse + * @param {boolean} [bindFnToScope=true] + * @returns {Object} value as accessible by path + */ +//TODO(misko): this function needs to be removed +function getter(obj, path, bindFnToScope) { + if (!path) return obj; + var keys = path.split('.'); + var key; + var lastInstance = obj; + var len = keys.length; + + for (var i = 0; i < len; i++) { + key = keys[i]; + if (obj) { + obj = (lastInstance = obj)[key]; + } + } + if (!bindFnToScope && isFunction(obj)) { + return bind(lastInstance, obj); + } + return obj; +} + +/** + * Return the DOM siblings between the first and last node in the given array. + * @param {Array} array like object + * @returns {jqLite} jqLite collection containing the nodes + */ +function getBlockNodes(nodes) { + // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original + // collection, otherwise update the original collection. + var node = nodes[0]; + var endNode = nodes[nodes.length - 1]; + var blockNodes = [node]; + + do { + node = node.nextSibling; + if (!node) break; + blockNodes.push(node); + } while (node !== endNode); + + return jqLite(blockNodes); +} + + +/** + * Creates a new object without a prototype. This object is useful for lookup without having to + * guard against prototypically inherited properties via hasOwnProperty. + * + * Related micro-benchmarks: + * - http://jsperf.com/object-create2 + * - http://jsperf.com/proto-map-lookup/2 + * - http://jsperf.com/for-in-vs-object-keys2 + * + * @returns {Object} + */ +function createMap() { + return Object.create(null); +} + +var NODE_TYPE_ELEMENT = 1; +var NODE_TYPE_TEXT = 3; +var NODE_TYPE_COMMENT = 8; +var NODE_TYPE_DOCUMENT = 9; +var NODE_TYPE_DOCUMENT_FRAGMENT = 11; + +/** + * @ngdoc type + * @name angular.Module + * @module ng + * @description + * + * Interface for configuring angular {@link angular.module modules}. + */ + +function setupModuleLoader(window) { + + var $injectorMinErr = minErr('$injector'); + var ngMinErr = minErr('ng'); + + function ensure(obj, name, factory) { + return obj[name] || (obj[name] = factory()); + } + + var angular = ensure(window, 'angular', Object); + + // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap + angular.$$minErr = angular.$$minErr || minErr; + + return ensure(angular, 'module', function() { + /** @type {Object.} */ + var modules = {}; + + /** + * @ngdoc function + * @name angular.module + * @module ng + * @description + * + * The `angular.module` is a global place for creating, registering and retrieving Angular + * modules. + * All modules (angular core or 3rd party) that should be available to an application must be + * registered using this mechanism. + * + * When passed two or more arguments, a new module is created. If passed only one argument, an + * existing module (the name passed as the first argument to `module`) is retrieved. + * + * + * # Module + * + * A module is a collection of services, directives, controllers, filters, and configuration information. + * `angular.module` is used to configure the {@link auto.$injector $injector}. + * + * ```js + * // Create a new module + * var myModule = angular.module('myModule', []); + * + * // register a new service + * myModule.value('appName', 'MyCoolApp'); + * + * // configure existing services inside initialization blocks. + * myModule.config(['$locationProvider', function($locationProvider) { + * // Configure existing providers + * $locationProvider.hashPrefix('!'); + * }]); + * ``` + * + * Then you can create an injector and load your modules like this: + * + * ```js + * var injector = angular.injector(['ng', 'myModule']) + * ``` + * + * However it's more likely that you'll just use + * {@link ng.directive:ngApp ngApp} or + * {@link angular.bootstrap} to simplify this process for you. + * + * @param {!string} name The name of the module to create or retrieve. + * @param {!Array.=} requires If specified then new module is being created. If + * unspecified then the module is being retrieved for further configuration. + * @param {Function=} configFn Optional configuration function for the module. Same as + * {@link angular.Module#config Module#config()}. + * @returns {module} new module with the {@link angular.Module} api. + */ + return function module(name, requires, configFn) { + var assertNotHasOwnProperty = function(name, context) { + if (name === 'hasOwnProperty') { + throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context); + } + }; + + assertNotHasOwnProperty(name, 'module'); + if (requires && modules.hasOwnProperty(name)) { + modules[name] = null; + } + return ensure(modules, name, function() { + if (!requires) { + throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " + + "the module name or forgot to load it. If registering a module ensure that you " + + "specify the dependencies as the second argument.", name); + } + + /** @type {!Array.>} */ + var invokeQueue = []; + + /** @type {!Array.} */ + var configBlocks = []; + + /** @type {!Array.} */ + var runBlocks = []; + + var config = invokeLater('$injector', 'invoke', 'push', configBlocks); + + /** @type {angular.Module} */ + var moduleInstance = { + // Private state + _invokeQueue: invokeQueue, + _configBlocks: configBlocks, + _runBlocks: runBlocks, + + /** + * @ngdoc property + * @name angular.Module#requires + * @module ng + * + * @description + * Holds the list of modules which the injector will load before the current module is + * loaded. + */ + requires: requires, + + /** + * @ngdoc property + * @name angular.Module#name + * @module ng + * + * @description + * Name of the module. + */ + name: name, + + + /** + * @ngdoc method + * @name angular.Module#provider + * @module ng + * @param {string} name service name + * @param {Function} providerType Construction function for creating new instance of the + * service. + * @description + * See {@link auto.$provide#provider $provide.provider()}. + */ + provider: invokeLater('$provide', 'provider'), + + /** + * @ngdoc method + * @name angular.Module#factory + * @module ng + * @param {string} name service name + * @param {Function} providerFunction Function for creating new instance of the service. + * @description + * See {@link auto.$provide#factory $provide.factory()}. + */ + factory: invokeLater('$provide', 'factory'), + + /** + * @ngdoc method + * @name angular.Module#service + * @module ng + * @param {string} name service name + * @param {Function} constructor A constructor function that will be instantiated. + * @description + * See {@link auto.$provide#service $provide.service()}. + */ + service: invokeLater('$provide', 'service'), + + /** + * @ngdoc method + * @name angular.Module#value + * @module ng + * @param {string} name service name + * @param {*} object Service instance object. + * @description + * See {@link auto.$provide#value $provide.value()}. + */ + value: invokeLater('$provide', 'value'), + + /** + * @ngdoc method + * @name angular.Module#constant + * @module ng + * @param {string} name constant name + * @param {*} object Constant value. + * @description + * Because the constant are fixed, they get applied before other provide methods. + * See {@link auto.$provide#constant $provide.constant()}. + */ + constant: invokeLater('$provide', 'constant', 'unshift'), + + /** + * @ngdoc method + * @name angular.Module#animation + * @module ng + * @param {string} name animation name + * @param {Function} animationFactory Factory function for creating new instance of an + * animation. + * @description + * + * **NOTE**: animations take effect only if the **ngAnimate** module is loaded. + * + * + * Defines an animation hook that can be later used with + * {@link ngAnimate.$animate $animate} service and directives that use this service. + * + * ```js + * module.animation('.animation-name', function($inject1, $inject2) { + * return { + * eventName : function(element, done) { + * //code to run the animation + * //once complete, then run done() + * return function cancellationFunction(element) { + * //code to cancel the animation + * } + * } + * } + * }) + * ``` + * + * See {@link ng.$animateProvider#register $animateProvider.register()} and + * {@link ngAnimate ngAnimate module} for more information. + */ + animation: invokeLater('$animateProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#filter + * @module ng + * @param {string} name Filter name. + * @param {Function} filterFactory Factory function for creating new instance of filter. + * @description + * See {@link ng.$filterProvider#register $filterProvider.register()}. + */ + filter: invokeLater('$filterProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#controller + * @module ng + * @param {string|Object} name Controller name, or an object map of controllers where the + * keys are the names and the values are the constructors. + * @param {Function} constructor Controller constructor function. + * @description + * See {@link ng.$controllerProvider#register $controllerProvider.register()}. + */ + controller: invokeLater('$controllerProvider', 'register'), + + /** + * @ngdoc method + * @name angular.Module#directive + * @module ng + * @param {string|Object} name Directive name, or an object map of directives where the + * keys are the names and the values are the factories. + * @param {Function} directiveFactory Factory function for creating new instance of + * directives. + * @description + * See {@link ng.$compileProvider#directive $compileProvider.directive()}. + */ + directive: invokeLater('$compileProvider', 'directive'), + + /** + * @ngdoc method + * @name angular.Module#config + * @module ng + * @param {Function} configFn Execute this function on module load. Useful for service + * configuration. + * @description + * Use this method to register work which needs to be performed on module loading. + * For more about how to configure services, see + * {@link providers#provider-recipe Provider Recipe}. + */ + config: config, + + /** + * @ngdoc method + * @name angular.Module#run + * @module ng + * @param {Function} initializationFn Execute this function after injector creation. + * Useful for application initialization. + * @description + * Use this method to register work which should be performed when the injector is done + * loading all modules. + */ + run: function(block) { + runBlocks.push(block); + return this; + } + }; + + if (configFn) { + config(configFn); + } + + return moduleInstance; + + /** + * @param {string} provider + * @param {string} method + * @param {String=} insertMethod + * @returns {angular.Module} + */ + function invokeLater(provider, method, insertMethod, queue) { + if (!queue) queue = invokeQueue; + return function() { + queue[insertMethod || 'push']([provider, method, arguments]); + return moduleInstance; + }; + } + }); + }; + }); + +} + +/* global: toDebugString: true */ + +function serializeObject(obj) { + var seen = []; + + return JSON.stringify(obj, function(key, val) { + val = toJsonReplacer(key, val); + if (isObject(val)) { + + if (seen.indexOf(val) >= 0) return '<>'; + + seen.push(val); + } + return val; + }); +} + +function toDebugString(obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return serializeObject(obj); + } + return obj; +} + +/* global angularModule: true, + version: true, + + $LocaleProvider, + $CompileProvider, + + htmlAnchorDirective, + inputDirective, + inputDirective, + formDirective, + scriptDirective, + selectDirective, + styleDirective, + optionDirective, + ngBindDirective, + ngBindHtmlDirective, + ngBindTemplateDirective, + ngClassDirective, + ngClassEvenDirective, + ngClassOddDirective, + ngCspDirective, + ngCloakDirective, + ngControllerDirective, + ngFormDirective, + ngHideDirective, + ngIfDirective, + ngIncludeDirective, + ngIncludeFillContentDirective, + ngInitDirective, + ngNonBindableDirective, + ngPluralizeDirective, + ngRepeatDirective, + ngShowDirective, + ngStyleDirective, + ngSwitchDirective, + ngSwitchWhenDirective, + ngSwitchDefaultDirective, + ngOptionsDirective, + ngTranscludeDirective, + ngModelDirective, + ngListDirective, + ngChangeDirective, + patternDirective, + patternDirective, + requiredDirective, + requiredDirective, + minlengthDirective, + minlengthDirective, + maxlengthDirective, + maxlengthDirective, + ngValueDirective, + ngModelOptionsDirective, + ngAttributeAliasDirectives, + ngEventDirectives, + + $AnchorScrollProvider, + $AnimateProvider, + $BrowserProvider, + $CacheFactoryProvider, + $ControllerProvider, + $DocumentProvider, + $ExceptionHandlerProvider, + $FilterProvider, + $InterpolateProvider, + $IntervalProvider, + $HttpProvider, + $HttpBackendProvider, + $LocationProvider, + $LogProvider, + $ParseProvider, + $RootScopeProvider, + $QProvider, + $$QProvider, + $$SanitizeUriProvider, + $SceProvider, + $SceDelegateProvider, + $SnifferProvider, + $TemplateCacheProvider, + $TemplateRequestProvider, + $$TestabilityProvider, + $TimeoutProvider, + $$RAFProvider, + $$AsyncCallbackProvider, + $WindowProvider, + $$jqLiteProvider +*/ + + +/** + * @ngdoc object + * @name angular.version + * @module ng + * @description + * An object that contains information about the current AngularJS version. This object has the + * following properties: + * + * - `full` – `{string}` – Full version string, such as "0.9.18". + * - `major` – `{number}` – Major version number, such as "0". + * - `minor` – `{number}` – Minor version number, such as "9". + * - `dot` – `{number}` – Dot version number, such as "18". + * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". + */ +var version = { + full: '1.3.13', // all of these placeholder strings will be replaced by grunt's + major: 1, // package task + minor: 3, + dot: 13, + codeName: 'meticulous-riffleshuffle' +}; + + +function publishExternalAPI(angular) { + extend(angular, { + 'bootstrap': bootstrap, + 'copy': copy, + 'extend': extend, + 'equals': equals, + 'element': jqLite, + 'forEach': forEach, + 'injector': createInjector, + 'noop': noop, + 'bind': bind, + 'toJson': toJson, + 'fromJson': fromJson, + 'identity': identity, + 'isUndefined': isUndefined, + 'isDefined': isDefined, + 'isString': isString, + 'isFunction': isFunction, + 'isObject': isObject, + 'isNumber': isNumber, + 'isElement': isElement, + 'isArray': isArray, + 'version': version, + 'isDate': isDate, + 'lowercase': lowercase, + 'uppercase': uppercase, + 'callbacks': {counter: 0}, + 'getTestability': getTestability, + '$$minErr': minErr, + '$$csp': csp, + 'reloadWithDebugInfo': reloadWithDebugInfo + }); + + angularModule = setupModuleLoader(window); + try { + angularModule('ngLocale'); + } catch (e) { + angularModule('ngLocale', []).provider('$locale', $LocaleProvider); + } + + angularModule('ng', ['ngLocale'], ['$provide', + function ngModule($provide) { + // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it. + $provide.provider({ + $$sanitizeUri: $$SanitizeUriProvider + }); + $provide.provider('$compile', $CompileProvider). + directive({ + a: htmlAnchorDirective, + input: inputDirective, + textarea: inputDirective, + form: formDirective, + script: scriptDirective, + select: selectDirective, + style: styleDirective, + option: optionDirective, + ngBind: ngBindDirective, + ngBindHtml: ngBindHtmlDirective, + ngBindTemplate: ngBindTemplateDirective, + ngClass: ngClassDirective, + ngClassEven: ngClassEvenDirective, + ngClassOdd: ngClassOddDirective, + ngCloak: ngCloakDirective, + ngController: ngControllerDirective, + ngForm: ngFormDirective, + ngHide: ngHideDirective, + ngIf: ngIfDirective, + ngInclude: ngIncludeDirective, + ngInit: ngInitDirective, + ngNonBindable: ngNonBindableDirective, + ngPluralize: ngPluralizeDirective, + ngRepeat: ngRepeatDirective, + ngShow: ngShowDirective, + ngStyle: ngStyleDirective, + ngSwitch: ngSwitchDirective, + ngSwitchWhen: ngSwitchWhenDirective, + ngSwitchDefault: ngSwitchDefaultDirective, + ngOptions: ngOptionsDirective, + ngTransclude: ngTranscludeDirective, + ngModel: ngModelDirective, + ngList: ngListDirective, + ngChange: ngChangeDirective, + pattern: patternDirective, + ngPattern: patternDirective, + required: requiredDirective, + ngRequired: requiredDirective, + minlength: minlengthDirective, + ngMinlength: minlengthDirective, + maxlength: maxlengthDirective, + ngMaxlength: maxlengthDirective, + ngValue: ngValueDirective, + ngModelOptions: ngModelOptionsDirective + }). + directive({ + ngInclude: ngIncludeFillContentDirective + }). + directive(ngAttributeAliasDirectives). + directive(ngEventDirectives); + $provide.provider({ + $anchorScroll: $AnchorScrollProvider, + $animate: $AnimateProvider, + $browser: $BrowserProvider, + $cacheFactory: $CacheFactoryProvider, + $controller: $ControllerProvider, + $document: $DocumentProvider, + $exceptionHandler: $ExceptionHandlerProvider, + $filter: $FilterProvider, + $interpolate: $InterpolateProvider, + $interval: $IntervalProvider, + $http: $HttpProvider, + $httpBackend: $HttpBackendProvider, + $location: $LocationProvider, + $log: $LogProvider, + $parse: $ParseProvider, + $rootScope: $RootScopeProvider, + $q: $QProvider, + $$q: $$QProvider, + $sce: $SceProvider, + $sceDelegate: $SceDelegateProvider, + $sniffer: $SnifferProvider, + $templateCache: $TemplateCacheProvider, + $templateRequest: $TemplateRequestProvider, + $$testability: $$TestabilityProvider, + $timeout: $TimeoutProvider, + $window: $WindowProvider, + $$rAF: $$RAFProvider, + $$asyncCallback: $$AsyncCallbackProvider, + $$jqLite: $$jqLiteProvider + }); + } + ]); +} + +/* global JQLitePrototype: true, + addEventListenerFn: true, + removeEventListenerFn: true, + BOOLEAN_ATTR: true, + ALIASED_ATTR: true, +*/ + +////////////////////////////////// +//JQLite +////////////////////////////////// + +/** + * @ngdoc function + * @name angular.element + * @module ng + * @kind function + * + * @description + * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element. + * + * If jQuery is available, `angular.element` is an alias for the + * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` + * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite." + * + *
    jqLite is a tiny, API-compatible subset of jQuery that allows + * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most + * commonly needed functionality with the goal of having a very small footprint.
    + * + * To use jQuery, simply load it before `DOMContentLoaded` event fired. + * + *
    **Note:** all element references in Angular are always wrapped with jQuery or + * jqLite; they are never raw DOM references.
    + * + * ## Angular's jqLite + * jqLite provides only the following jQuery methods: + * + * - [`addClass()`](http://api.jquery.com/addClass/) + * - [`after()`](http://api.jquery.com/after/) + * - [`append()`](http://api.jquery.com/append/) + * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters + * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData + * - [`children()`](http://api.jquery.com/children/) - Does not support selectors + * - [`clone()`](http://api.jquery.com/clone/) + * - [`contents()`](http://api.jquery.com/contents/) + * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()` + * - [`data()`](http://api.jquery.com/data/) + * - [`detach()`](http://api.jquery.com/detach/) + * - [`empty()`](http://api.jquery.com/empty/) + * - [`eq()`](http://api.jquery.com/eq/) + * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name + * - [`hasClass()`](http://api.jquery.com/hasClass/) + * - [`html()`](http://api.jquery.com/html/) + * - [`next()`](http://api.jquery.com/next/) - Does not support selectors + * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData + * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors + * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors + * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors + * - [`prepend()`](http://api.jquery.com/prepend/) + * - [`prop()`](http://api.jquery.com/prop/) + * - [`ready()`](http://api.jquery.com/ready/) + * - [`remove()`](http://api.jquery.com/remove/) + * - [`removeAttr()`](http://api.jquery.com/removeAttr/) + * - [`removeClass()`](http://api.jquery.com/removeClass/) + * - [`removeData()`](http://api.jquery.com/removeData/) + * - [`replaceWith()`](http://api.jquery.com/replaceWith/) + * - [`text()`](http://api.jquery.com/text/) + * - [`toggleClass()`](http://api.jquery.com/toggleClass/) + * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers. + * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces + * - [`val()`](http://api.jquery.com/val/) + * - [`wrap()`](http://api.jquery.com/wrap/) + * + * ## jQuery/jqLite Extras + * Angular also provides the following additional methods and events to both jQuery and jqLite: + * + * ### Events + * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event + * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM + * element before it is removed. + * + * ### Methods + * - `controller(name)` - retrieves the controller of the current element or its parent. By default + * retrieves controller associated with the `ngController` directive. If `name` is provided as + * camelCase directive name, then the controller for this directive will be retrieved (e.g. + * `'ngModel'`). + * - `injector()` - retrieves the injector of the current element or its parent. + * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current + * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to + * be enabled. + * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the + * current element. This getter should be used only on elements that contain a directive which starts a new isolate + * scope. Calling `scope()` on this element always returns the original non-isolate scope. + * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled. + * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top + * parent element is reached. + * + * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery. + * @returns {Object} jQuery object. + */ + +JQLite.expando = 'ng339'; + +var jqCache = JQLite.cache = {}, + jqId = 1, + addEventListenerFn = function(element, type, fn) { + element.addEventListener(type, fn, false); + }, + removeEventListenerFn = function(element, type, fn) { + element.removeEventListener(type, fn, false); + }; + +/* + * !!! This is an undocumented "private" function !!! + */ +JQLite._data = function(node) { + //jQuery always returns an object on cache miss + return this.cache[node[this.expando]] || {}; +}; + +function jqNextId() { return ++jqId; } + + +var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g; +var MOZ_HACK_REGEXP = /^moz([A-Z])/; +var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"}; +var jqLiteMinErr = minErr('jqLite'); + +/** + * Converts snake_case to camelCase. + * Also there is special case for Moz prefix starting with upper case letter. + * @param name Name to normalize + */ +function camelCase(name) { + return name. + replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) { + return offset ? letter.toUpperCase() : letter; + }). + replace(MOZ_HACK_REGEXP, 'Moz$1'); +} + +var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/; +var HTML_REGEXP = /<|&#?\w+;/; +var TAG_NAME_REGEXP = /<([\w:]+)/; +var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi; + +var wrapMap = { + 'option': [1, ''], + + 'thead': [1, '', '
    '], + 'col': [2, '', '
    '], + 'tr': [2, '', '
    '], + 'td': [3, '', '
    '], + '_default': [0, "", ""] +}; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function jqLiteIsTextNode(html) { + return !HTML_REGEXP.test(html); +} + +function jqLiteAcceptsData(node) { + // The window object can accept data but has no nodeType + // Otherwise we are only interested in elements (1) and documents (9) + var nodeType = node.nodeType; + return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT; +} + +function jqLiteBuildFragment(html, context) { + var tmp, tag, wrap, + fragment = context.createDocumentFragment(), + nodes = [], i; + + if (jqLiteIsTextNode(html)) { + // Convert non-html into a text node + nodes.push(context.createTextNode(html)); + } else { + // Convert html into DOM nodes + tmp = tmp || fragment.appendChild(context.createElement("div")); + tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase(); + wrap = wrapMap[tag] || wrapMap._default; + tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>") + wrap[2]; + + // Descend through wrappers to the right content + i = wrap[0]; + while (i--) { + tmp = tmp.lastChild; + } + + nodes = concat(nodes, tmp.childNodes); + + tmp = fragment.firstChild; + tmp.textContent = ""; + } + + // Remove wrapper from fragment + fragment.textContent = ""; + fragment.innerHTML = ""; // Clear inner HTML + forEach(nodes, function(node) { + fragment.appendChild(node); + }); + + return fragment; +} + +function jqLiteParseHTML(html, context) { + context = context || document; + var parsed; + + if ((parsed = SINGLE_TAG_REGEXP.exec(html))) { + return [context.createElement(parsed[1])]; + } + + if ((parsed = jqLiteBuildFragment(html, context))) { + return parsed.childNodes; + } + + return []; +} + +///////////////////////////////////////////// +function JQLite(element) { + if (element instanceof JQLite) { + return element; + } + + var argIsString; + + if (isString(element)) { + element = trim(element); + argIsString = true; + } + if (!(this instanceof JQLite)) { + if (argIsString && element.charAt(0) != '<') { + throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element'); + } + return new JQLite(element); + } + + if (argIsString) { + jqLiteAddNodes(this, jqLiteParseHTML(element)); + } else { + jqLiteAddNodes(this, element); + } +} + +function jqLiteClone(element) { + return element.cloneNode(true); +} + +function jqLiteDealoc(element, onlyDescendants) { + if (!onlyDescendants) jqLiteRemoveData(element); + + if (element.querySelectorAll) { + var descendants = element.querySelectorAll('*'); + for (var i = 0, l = descendants.length; i < l; i++) { + jqLiteRemoveData(descendants[i]); + } + } +} + +function jqLiteOff(element, type, fn, unsupported) { + if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument'); + + var expandoStore = jqLiteExpandoStore(element); + var events = expandoStore && expandoStore.events; + var handle = expandoStore && expandoStore.handle; + + if (!handle) return; //no listeners registered + + if (!type) { + for (type in events) { + if (type !== '$destroy') { + removeEventListenerFn(element, type, handle); + } + delete events[type]; + } + } else { + forEach(type.split(' '), function(type) { + if (isDefined(fn)) { + var listenerFns = events[type]; + arrayRemove(listenerFns || [], fn); + if (listenerFns && listenerFns.length > 0) { + return; + } + } + + removeEventListenerFn(element, type, handle); + delete events[type]; + }); + } +} + +function jqLiteRemoveData(element, name) { + var expandoId = element.ng339; + var expandoStore = expandoId && jqCache[expandoId]; + + if (expandoStore) { + if (name) { + delete expandoStore.data[name]; + return; + } + + if (expandoStore.handle) { + if (expandoStore.events.$destroy) { + expandoStore.handle({}, '$destroy'); + } + jqLiteOff(element); + } + delete jqCache[expandoId]; + element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it + } +} + + +function jqLiteExpandoStore(element, createIfNecessary) { + var expandoId = element.ng339, + expandoStore = expandoId && jqCache[expandoId]; + + if (createIfNecessary && !expandoStore) { + element.ng339 = expandoId = jqNextId(); + expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined}; + } + + return expandoStore; +} + + +function jqLiteData(element, key, value) { + if (jqLiteAcceptsData(element)) { + + var isSimpleSetter = isDefined(value); + var isSimpleGetter = !isSimpleSetter && key && !isObject(key); + var massGetter = !key; + var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter); + var data = expandoStore && expandoStore.data; + + if (isSimpleSetter) { // data('key', value) + data[key] = value; + } else { + if (massGetter) { // data() + return data; + } else { + if (isSimpleGetter) { // data('key') + // don't force creation of expandoStore if it doesn't exist yet + return data && data[key]; + } else { // mass-setter: data({key1: val1, key2: val2}) + extend(data, key); + } + } + } + } +} + +function jqLiteHasClass(element, selector) { + if (!element.getAttribute) return false; + return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " "). + indexOf(" " + selector + " ") > -1); +} + +function jqLiteRemoveClass(element, cssClasses) { + if (cssClasses && element.setAttribute) { + forEach(cssClasses.split(' '), function(cssClass) { + element.setAttribute('class', trim( + (" " + (element.getAttribute('class') || '') + " ") + .replace(/[\n\t]/g, " ") + .replace(" " + trim(cssClass) + " ", " ")) + ); + }); + } +} + +function jqLiteAddClass(element, cssClasses) { + if (cssClasses && element.setAttribute) { + var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ') + .replace(/[\n\t]/g, " "); + + forEach(cssClasses.split(' '), function(cssClass) { + cssClass = trim(cssClass); + if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) { + existingClasses += cssClass + ' '; + } + }); + + element.setAttribute('class', trim(existingClasses)); + } +} + + +function jqLiteAddNodes(root, elements) { + // THIS CODE IS VERY HOT. Don't make changes without benchmarking. + + if (elements) { + + // if a Node (the most common case) + if (elements.nodeType) { + root[root.length++] = elements; + } else { + var length = elements.length; + + // if an Array or NodeList and not a Window + if (typeof length === 'number' && elements.window !== elements) { + if (length) { + for (var i = 0; i < length; i++) { + root[root.length++] = elements[i]; + } + } + } else { + root[root.length++] = elements; + } + } + } +} + + +function jqLiteController(element, name) { + return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller'); +} + +function jqLiteInheritedData(element, name, value) { + // if element is the document object work with the html element instead + // this makes $(document).scope() possible + if (element.nodeType == NODE_TYPE_DOCUMENT) { + element = element.documentElement; + } + var names = isArray(name) ? name : [name]; + + while (element) { + for (var i = 0, ii = names.length; i < ii; i++) { + if ((value = jqLite.data(element, names[i])) !== undefined) return value; + } + + // If dealing with a document fragment node with a host element, and no parent, use the host + // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM + // to lookup parent controllers. + element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host); + } +} + +function jqLiteEmpty(element) { + jqLiteDealoc(element, true); + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +function jqLiteRemove(element, keepData) { + if (!keepData) jqLiteDealoc(element); + var parent = element.parentNode; + if (parent) parent.removeChild(element); +} + + +function jqLiteDocumentLoaded(action, win) { + win = win || window; + if (win.document.readyState === 'complete') { + // Force the action to be run async for consistent behaviour + // from the action's point of view + // i.e. it will definitely not be in a $apply + win.setTimeout(action); + } else { + // No need to unbind this handler as load is only ever called once + jqLite(win).on('load', action); + } +} + +////////////////////////////////////////// +// Functions which are declared directly. +////////////////////////////////////////// +var JQLitePrototype = JQLite.prototype = { + ready: function(fn) { + var fired = false; + + function trigger() { + if (fired) return; + fired = true; + fn(); + } + + // check if document is already loaded + if (document.readyState === 'complete') { + setTimeout(trigger); + } else { + this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9 + // we can not use jqLite since we are not done loading and jQuery could be loaded later. + // jshint -W064 + JQLite(window).on('load', trigger); // fallback to window.onload for others + // jshint +W064 + } + }, + toString: function() { + var value = []; + forEach(this, function(e) { value.push('' + e);}); + return '[' + value.join(', ') + ']'; + }, + + eq: function(index) { + return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]); + }, + + length: 0, + push: push, + sort: [].sort, + splice: [].splice +}; + +////////////////////////////////////////// +// Functions iterating getter/setters. +// these functions return self on setter and +// value on get. +////////////////////////////////////////// +var BOOLEAN_ATTR = {}; +forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) { + BOOLEAN_ATTR[lowercase(value)] = value; +}); +var BOOLEAN_ELEMENTS = {}; +forEach('input,select,option,textarea,button,form,details'.split(','), function(value) { + BOOLEAN_ELEMENTS[value] = true; +}); +var ALIASED_ATTR = { + 'ngMinlength': 'minlength', + 'ngMaxlength': 'maxlength', + 'ngMin': 'min', + 'ngMax': 'max', + 'ngPattern': 'pattern' +}; + +function getBooleanAttrName(element, name) { + // check dom last since we will most likely fail on name + var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()]; + + // booleanAttr is here twice to minimize DOM access + return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr; +} + +function getAliasedAttrName(element, name) { + var nodeName = element.nodeName; + return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name]; +} + +forEach({ + data: jqLiteData, + removeData: jqLiteRemoveData +}, function(fn, name) { + JQLite[name] = fn; +}); + +forEach({ + data: jqLiteData, + inheritedData: jqLiteInheritedData, + + scope: function(element) { + // Can't use jqLiteData here directly so we stay compatible with jQuery! + return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); + }, + + isolateScope: function(element) { + // Can't use jqLiteData here directly so we stay compatible with jQuery! + return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate'); + }, + + controller: jqLiteController, + + injector: function(element) { + return jqLiteInheritedData(element, '$injector'); + }, + + removeAttr: function(element, name) { + element.removeAttribute(name); + }, + + hasClass: jqLiteHasClass, + + css: function(element, name, value) { + name = camelCase(name); + + if (isDefined(value)) { + element.style[name] = value; + } else { + return element.style[name]; + } + }, + + attr: function(element, name, value) { + var lowercasedName = lowercase(name); + if (BOOLEAN_ATTR[lowercasedName]) { + if (isDefined(value)) { + if (!!value) { + element[name] = true; + element.setAttribute(name, lowercasedName); + } else { + element[name] = false; + element.removeAttribute(lowercasedName); + } + } else { + return (element[name] || + (element.attributes.getNamedItem(name) || noop).specified) + ? lowercasedName + : undefined; + } + } else if (isDefined(value)) { + element.setAttribute(name, value); + } else if (element.getAttribute) { + // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code + // some elements (e.g. Document) don't have get attribute, so return undefined + var ret = element.getAttribute(name, 2); + // normalize non-existing attributes to undefined (as jQuery) + return ret === null ? undefined : ret; + } + }, + + prop: function(element, name, value) { + if (isDefined(value)) { + element[name] = value; + } else { + return element[name]; + } + }, + + text: (function() { + getText.$dv = ''; + return getText; + + function getText(element, value) { + if (isUndefined(value)) { + var nodeType = element.nodeType; + return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : ''; + } + element.textContent = value; + } + })(), + + val: function(element, value) { + if (isUndefined(value)) { + if (element.multiple && nodeName_(element) === 'select') { + var result = []; + forEach(element.options, function(option) { + if (option.selected) { + result.push(option.value || option.text); + } + }); + return result.length === 0 ? null : result; + } + return element.value; + } + element.value = value; + }, + + html: function(element, value) { + if (isUndefined(value)) { + return element.innerHTML; + } + jqLiteDealoc(element, true); + element.innerHTML = value; + }, + + empty: jqLiteEmpty +}, function(fn, name) { + /** + * Properties: writes return selection, reads return first value + */ + JQLite.prototype[name] = function(arg1, arg2) { + var i, key; + var nodeCount = this.length; + + // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it + // in a way that survives minification. + // jqLiteEmpty takes no arguments but is a setter. + if (fn !== jqLiteEmpty && + (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) { + if (isObject(arg1)) { + + // we are a write, but the object properties are the key/values + for (i = 0; i < nodeCount; i++) { + if (fn === jqLiteData) { + // data() takes the whole object in jQuery + fn(this[i], arg1); + } else { + for (key in arg1) { + fn(this[i], key, arg1[key]); + } + } + } + // return self for chaining + return this; + } else { + // we are a read, so read the first child. + // TODO: do we still need this? + var value = fn.$dv; + // Only if we have $dv do we iterate over all, otherwise it is just the first element. + var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount; + for (var j = 0; j < jj; j++) { + var nodeValue = fn(this[j], arg1, arg2); + value = value ? value + nodeValue : nodeValue; + } + return value; + } + } else { + // we are a write, so apply to all children + for (i = 0; i < nodeCount; i++) { + fn(this[i], arg1, arg2); + } + // return self for chaining + return this; + } + }; +}); + +function createEventHandler(element, events) { + var eventHandler = function(event, type) { + // jQuery specific api + event.isDefaultPrevented = function() { + return event.defaultPrevented; + }; + + var eventFns = events[type || event.type]; + var eventFnsLength = eventFns ? eventFns.length : 0; + + if (!eventFnsLength) return; + + if (isUndefined(event.immediatePropagationStopped)) { + var originalStopImmediatePropagation = event.stopImmediatePropagation; + event.stopImmediatePropagation = function() { + event.immediatePropagationStopped = true; + + if (event.stopPropagation) { + event.stopPropagation(); + } + + if (originalStopImmediatePropagation) { + originalStopImmediatePropagation.call(event); + } + }; + } + + event.isImmediatePropagationStopped = function() { + return event.immediatePropagationStopped === true; + }; + + // Copy event handlers in case event handlers array is modified during execution. + if ((eventFnsLength > 1)) { + eventFns = shallowCopy(eventFns); + } + + for (var i = 0; i < eventFnsLength; i++) { + if (!event.isImmediatePropagationStopped()) { + eventFns[i].call(element, event); + } + } + }; + + // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all + // events on `element` + eventHandler.elem = element; + return eventHandler; +} + +////////////////////////////////////////// +// Functions iterating traversal. +// These functions chain results into a single +// selector. +////////////////////////////////////////// +forEach({ + removeData: jqLiteRemoveData, + + on: function jqLiteOn(element, type, fn, unsupported) { + if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters'); + + // Do not add event handlers to non-elements because they will not be cleaned up. + if (!jqLiteAcceptsData(element)) { + return; + } + + var expandoStore = jqLiteExpandoStore(element, true); + var events = expandoStore.events; + var handle = expandoStore.handle; + + if (!handle) { + handle = expandoStore.handle = createEventHandler(element, events); + } + + // http://jsperf.com/string-indexof-vs-split + var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type]; + var i = types.length; + + while (i--) { + type = types[i]; + var eventFns = events[type]; + + if (!eventFns) { + events[type] = []; + + if (type === 'mouseenter' || type === 'mouseleave') { + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + + jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) { + var target = this, related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if (!related || (related !== target && !target.contains(related))) { + handle(event, type); + } + }); + + } else { + if (type !== '$destroy') { + addEventListenerFn(element, type, handle); + } + } + eventFns = events[type]; + } + eventFns.push(fn); + } + }, + + off: jqLiteOff, + + one: function(element, type, fn) { + element = jqLite(element); + + //add the listener twice so that when it is called + //you can remove the original function and still be + //able to call element.off(ev, fn) normally + element.on(type, function onFn() { + element.off(type, fn); + element.off(type, onFn); + }); + element.on(type, fn); + }, + + replaceWith: function(element, replaceNode) { + var index, parent = element.parentNode; + jqLiteDealoc(element); + forEach(new JQLite(replaceNode), function(node) { + if (index) { + parent.insertBefore(node, index.nextSibling); + } else { + parent.replaceChild(node, element); + } + index = node; + }); + }, + + children: function(element) { + var children = []; + forEach(element.childNodes, function(element) { + if (element.nodeType === NODE_TYPE_ELEMENT) + children.push(element); + }); + return children; + }, + + contents: function(element) { + return element.contentDocument || element.childNodes || []; + }, + + append: function(element, node) { + var nodeType = element.nodeType; + if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return; + + node = new JQLite(node); + + for (var i = 0, ii = node.length; i < ii; i++) { + var child = node[i]; + element.appendChild(child); + } + }, + + prepend: function(element, node) { + if (element.nodeType === NODE_TYPE_ELEMENT) { + var index = element.firstChild; + forEach(new JQLite(node), function(child) { + element.insertBefore(child, index); + }); + } + }, + + wrap: function(element, wrapNode) { + wrapNode = jqLite(wrapNode).eq(0).clone()[0]; + var parent = element.parentNode; + if (parent) { + parent.replaceChild(wrapNode, element); + } + wrapNode.appendChild(element); + }, + + remove: jqLiteRemove, + + detach: function(element) { + jqLiteRemove(element, true); + }, + + after: function(element, newElement) { + var index = element, parent = element.parentNode; + newElement = new JQLite(newElement); + + for (var i = 0, ii = newElement.length; i < ii; i++) { + var node = newElement[i]; + parent.insertBefore(node, index.nextSibling); + index = node; + } + }, + + addClass: jqLiteAddClass, + removeClass: jqLiteRemoveClass, + + toggleClass: function(element, selector, condition) { + if (selector) { + forEach(selector.split(' '), function(className) { + var classCondition = condition; + if (isUndefined(classCondition)) { + classCondition = !jqLiteHasClass(element, className); + } + (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className); + }); + } + }, + + parent: function(element) { + var parent = element.parentNode; + return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null; + }, + + next: function(element) { + return element.nextElementSibling; + }, + + find: function(element, selector) { + if (element.getElementsByTagName) { + return element.getElementsByTagName(selector); + } else { + return []; + } + }, + + clone: jqLiteClone, + + triggerHandler: function(element, event, extraParameters) { + + var dummyEvent, eventFnsCopy, handlerArgs; + var eventName = event.type || event; + var expandoStore = jqLiteExpandoStore(element); + var events = expandoStore && expandoStore.events; + var eventFns = events && events[eventName]; + + if (eventFns) { + // Create a dummy event to pass to the handlers + dummyEvent = { + preventDefault: function() { this.defaultPrevented = true; }, + isDefaultPrevented: function() { return this.defaultPrevented === true; }, + stopImmediatePropagation: function() { this.immediatePropagationStopped = true; }, + isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; }, + stopPropagation: noop, + type: eventName, + target: element + }; + + // If a custom event was provided then extend our dummy event with it + if (event.type) { + dummyEvent = extend(dummyEvent, event); + } + + // Copy event handlers in case event handlers array is modified during execution. + eventFnsCopy = shallowCopy(eventFns); + handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent]; + + forEach(eventFnsCopy, function(fn) { + if (!dummyEvent.isImmediatePropagationStopped()) { + fn.apply(element, handlerArgs); + } + }); + } + } +}, function(fn, name) { + /** + * chaining functions + */ + JQLite.prototype[name] = function(arg1, arg2, arg3) { + var value; + + for (var i = 0, ii = this.length; i < ii; i++) { + if (isUndefined(value)) { + value = fn(this[i], arg1, arg2, arg3); + if (isDefined(value)) { + // any function which returns a value needs to be wrapped + value = jqLite(value); + } + } else { + jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3)); + } + } + return isDefined(value) ? value : this; + }; + + // bind legacy bind/unbind to on/off + JQLite.prototype.bind = JQLite.prototype.on; + JQLite.prototype.unbind = JQLite.prototype.off; +}); + + +// Provider for private $$jqLite service +function $$jqLiteProvider() { + this.$get = function $$jqLite() { + return extend(JQLite, { + hasClass: function(node, classes) { + if (node.attr) node = node[0]; + return jqLiteHasClass(node, classes); + }, + addClass: function(node, classes) { + if (node.attr) node = node[0]; + return jqLiteAddClass(node, classes); + }, + removeClass: function(node, classes) { + if (node.attr) node = node[0]; + return jqLiteRemoveClass(node, classes); + } + }); + }; +} + +/** + * Computes a hash of an 'obj'. + * Hash of a: + * string is string + * number is number as string + * object is either result of calling $$hashKey function on the object or uniquely generated id, + * that is also assigned to the $$hashKey property of the object. + * + * @param obj + * @returns {string} hash string such that the same input will have the same hash string. + * The resulting string key is in 'type:hashKey' format. + */ +function hashKey(obj, nextUidFn) { + var key = obj && obj.$$hashKey; + + if (key) { + if (typeof key === 'function') { + key = obj.$$hashKey(); + } + return key; + } + + var objType = typeof obj; + if (objType == 'function' || (objType == 'object' && obj !== null)) { + key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)(); + } else { + key = objType + ':' + obj; + } + + return key; +} + +/** + * HashMap which can use objects as keys + */ +function HashMap(array, isolatedUid) { + if (isolatedUid) { + var uid = 0; + this.nextUid = function() { + return ++uid; + }; + } + forEach(array, this.put, this); +} +HashMap.prototype = { + /** + * Store key value pair + * @param key key to store can be any type + * @param value value to store can be any type + */ + put: function(key, value) { + this[hashKey(key, this.nextUid)] = value; + }, + + /** + * @param key + * @returns {Object} the value for the key + */ + get: function(key) { + return this[hashKey(key, this.nextUid)]; + }, + + /** + * Remove the key/value pair + * @param key + */ + remove: function(key) { + var value = this[key = hashKey(key, this.nextUid)]; + delete this[key]; + return value; + } +}; + +/** + * @ngdoc function + * @module ng + * @name angular.injector + * @kind function + * + * @description + * Creates an injector object that can be used for retrieving services as well as for + * dependency injection (see {@link guide/di dependency injection}). + * + * @param {Array.} modules A list of module functions or their aliases. See + * {@link angular.module}. The `ng` module must be explicitly added. + * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which + * disallows argument name annotation inference. + * @returns {injector} Injector object. See {@link auto.$injector $injector}. + * + * @example + * Typical usage + * ```js + * // create an injector + * var $injector = angular.injector(['ng']); + * + * // use the injector to kick off your application + * // use the type inference to auto inject arguments, or use implicit injection + * $injector.invoke(function($rootScope, $compile, $document) { + * $compile($document)($rootScope); + * $rootScope.$digest(); + * }); + * ``` + * + * Sometimes you want to get access to the injector of a currently running Angular app + * from outside Angular. Perhaps, you want to inject and compile some markup after the + * application has been bootstrapped. You can do this using the extra `injector()` added + * to JQuery/jqLite elements. See {@link angular.element}. + * + * *This is fairly rare but could be the case if a third party library is injecting the + * markup.* + * + * In the following example a new block of HTML containing a `ng-controller` + * directive is added to the end of the document body by JQuery. We then compile and link + * it into the current AngularJS scope. + * + * ```js + * var $div = $('
    {{content.label}}
    '); + * $(document.body).append($div); + * + * angular.element(document).injector().invoke(function($compile) { + * var scope = angular.element($div).scope(); + * $compile($div)(scope); + * }); + * ``` + */ + + +/** + * @ngdoc module + * @name auto + * @description + * + * Implicit module which gets automatically added to each {@link auto.$injector $injector}. + */ + +var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m; +var FN_ARG_SPLIT = /,/; +var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; +var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; +var $injectorMinErr = minErr('$injector'); + +function anonFn(fn) { + // For anonymous functions, showing at the very least the function signature can help in + // debugging. + var fnText = fn.toString().replace(STRIP_COMMENTS, ''), + args = fnText.match(FN_ARGS); + if (args) { + return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')'; + } + return 'fn'; +} + +function annotate(fn, strictDi, name) { + var $inject, + fnText, + argDecl, + last; + + if (typeof fn === 'function') { + if (!($inject = fn.$inject)) { + $inject = []; + if (fn.length) { + if (strictDi) { + if (!isString(name) || !name) { + name = fn.name || anonFn(fn); + } + throw $injectorMinErr('strictdi', + '{0} is not using explicit annotation and cannot be invoked in strict mode', name); + } + fnText = fn.toString().replace(STRIP_COMMENTS, ''); + argDecl = fnText.match(FN_ARGS); + forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { + arg.replace(FN_ARG, function(all, underscore, name) { + $inject.push(name); + }); + }); + } + fn.$inject = $inject; + } + } else if (isArray(fn)) { + last = fn.length - 1; + assertArgFn(fn[last], 'fn'); + $inject = fn.slice(0, last); + } else { + assertArgFn(fn, 'fn', true); + } + return $inject; +} + +/////////////////////////////////////// + +/** + * @ngdoc service + * @name $injector + * + * @description + * + * `$injector` is used to retrieve object instances as defined by + * {@link auto.$provide provider}, instantiate types, invoke methods, + * and load modules. + * + * The following always holds true: + * + * ```js + * var $injector = angular.injector(); + * expect($injector.get('$injector')).toBe($injector); + * expect($injector.invoke(function($injector) { + * return $injector; + * })).toBe($injector); + * ``` + * + * # Injection Function Annotation + * + * JavaScript does not have annotations, and annotations are needed for dependency injection. The + * following are all valid ways of annotating function with injection arguments and are equivalent. + * + * ```js + * // inferred (only works if code not minified/obfuscated) + * $injector.invoke(function(serviceA){}); + * + * // annotated + * function explicit(serviceA) {}; + * explicit.$inject = ['serviceA']; + * $injector.invoke(explicit); + * + * // inline + * $injector.invoke(['serviceA', function(serviceA){}]); + * ``` + * + * ## Inference + * + * In JavaScript calling `toString()` on a function returns the function definition. The definition + * can then be parsed and the function arguments can be extracted. This method of discovering + * annotations is disallowed when the injector is in strict mode. + * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the + * argument names. + * + * ## `$inject` Annotation + * By adding an `$inject` property onto a function the injection parameters can be specified. + * + * ## Inline + * As an array of injection names, where the last item in the array is the function to call. + */ + +/** + * @ngdoc method + * @name $injector#get + * + * @description + * Return an instance of the service. + * + * @param {string} name The name of the instance to retrieve. + * @param {string} caller An optional string to provide the origin of the function call for error messages. + * @return {*} The instance. + */ + +/** + * @ngdoc method + * @name $injector#invoke + * + * @description + * Invoke the method and supply the method arguments from the `$injector`. + * + * @param {!Function} fn The function to invoke. Function parameters are injected according to the + * {@link guide/di $inject Annotation} rules. + * @param {Object=} self The `this` for the invoked method. + * @param {Object=} locals Optional object. If preset then any argument names are read from this + * object first, before the `$injector` is consulted. + * @returns {*} the value returned by the invoked `fn` function. + */ + +/** + * @ngdoc method + * @name $injector#has + * + * @description + * Allows the user to query if the particular service exists. + * + * @param {string} name Name of the service to query. + * @returns {boolean} `true` if injector has given service. + */ + +/** + * @ngdoc method + * @name $injector#instantiate + * @description + * Create a new instance of JS type. The method takes a constructor function, invokes the new + * operator, and supplies all of the arguments to the constructor function as specified by the + * constructor annotation. + * + * @param {Function} Type Annotated constructor function. + * @param {Object=} locals Optional object. If preset then any argument names are read from this + * object first, before the `$injector` is consulted. + * @returns {Object} new instance of `Type`. + */ + +/** + * @ngdoc method + * @name $injector#annotate + * + * @description + * Returns an array of service names which the function is requesting for injection. This API is + * used by the injector to determine which services need to be injected into the function when the + * function is invoked. There are three ways in which the function can be annotated with the needed + * dependencies. + * + * # Argument names + * + * The simplest form is to extract the dependencies from the arguments of the function. This is done + * by converting the function into a string using `toString()` method and extracting the argument + * names. + * ```js + * // Given + * function MyController($scope, $route) { + * // ... + * } + * + * // Then + * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); + * ``` + * + * You can disallow this method by using strict injection mode. + * + * This method does not work with code minification / obfuscation. For this reason the following + * annotation strategies are supported. + * + * # The `$inject` property + * + * If a function has an `$inject` property and its value is an array of strings, then the strings + * represent names of services to be injected into the function. + * ```js + * // Given + * var MyController = function(obfuscatedScope, obfuscatedRoute) { + * // ... + * } + * // Define function dependencies + * MyController['$inject'] = ['$scope', '$route']; + * + * // Then + * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']); + * ``` + * + * # The array notation + * + * It is often desirable to inline Injected functions and that's when setting the `$inject` property + * is very inconvenient. In these situations using the array notation to specify the dependencies in + * a way that survives minification is a better choice: + * + * ```js + * // We wish to write this (not minification / obfuscation safe) + * injector.invoke(function($compile, $rootScope) { + * // ... + * }); + * + * // We are forced to write break inlining + * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) { + * // ... + * }; + * tmpFn.$inject = ['$compile', '$rootScope']; + * injector.invoke(tmpFn); + * + * // To better support inline function the inline annotation is supported + * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) { + * // ... + * }]); + * + * // Therefore + * expect(injector.annotate( + * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}]) + * ).toEqual(['$compile', '$rootScope']); + * ``` + * + * @param {Function|Array.} fn Function for which dependent service names need to + * be retrieved as described above. + * + * @param {boolean=} [strictDi=false] Disallow argument name annotation inference. + * + * @returns {Array.} The names of the services which the function requires. + */ + + + + +/** + * @ngdoc service + * @name $provide + * + * @description + * + * The {@link auto.$provide $provide} service has a number of methods for registering components + * with the {@link auto.$injector $injector}. Many of these functions are also exposed on + * {@link angular.Module}. + * + * An Angular **service** is a singleton object created by a **service factory**. These **service + * factories** are functions which, in turn, are created by a **service provider**. + * The **service providers** are constructor functions. When instantiated they must contain a + * property called `$get`, which holds the **service factory** function. + * + * When you request a service, the {@link auto.$injector $injector} is responsible for finding the + * correct **service provider**, instantiating it and then calling its `$get` **service factory** + * function to get the instance of the **service**. + * + * Often services have no configuration options and there is no need to add methods to the service + * provider. The provider will be no more than a constructor function with a `$get` property. For + * these cases the {@link auto.$provide $provide} service has additional helper methods to register + * services without specifying a provider. + * + * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the + * {@link auto.$injector $injector} + * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by + * providers and services. + * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by + * services, not providers. + * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, + * that will be wrapped in a **service provider** object, whose `$get` property will contain the + * given factory function. + * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class` + * that will be wrapped in a **service provider** object, whose `$get` property will instantiate + * a new object using the given constructor function. + * + * See the individual methods for more information and examples. + */ + +/** + * @ngdoc method + * @name $provide#provider + * @description + * + * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions + * are constructor functions, whose instances are responsible for "providing" a factory for a + * service. + * + * Service provider names start with the name of the service they provide followed by `Provider`. + * For example, the {@link ng.$log $log} service has a provider called + * {@link ng.$logProvider $logProvider}. + * + * Service provider objects can have additional methods which allow configuration of the provider + * and its service. Importantly, you can configure what kind of service is created by the `$get` + * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a + * method {@link ng.$logProvider#debugEnabled debugEnabled} + * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the + * console or not. + * + * @param {string} name The name of the instance. NOTE: the provider will be available under `name + + 'Provider'` key. + * @param {(Object|function())} provider If the provider is: + * + * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using + * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created. + * - `Constructor`: a new instance of the provider will be created using + * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`. + * + * @returns {Object} registered provider instance + + * @example + * + * The following example shows how to create a simple event tracking service and register it using + * {@link auto.$provide#provider $provide.provider()}. + * + * ```js + * // Define the eventTracker provider + * function EventTrackerProvider() { + * var trackingUrl = '/track'; + * + * // A provider method for configuring where the tracked events should been saved + * this.setTrackingUrl = function(url) { + * trackingUrl = url; + * }; + * + * // The service factory function + * this.$get = ['$http', function($http) { + * var trackedEvents = {}; + * return { + * // Call this to track an event + * event: function(event) { + * var count = trackedEvents[event] || 0; + * count += 1; + * trackedEvents[event] = count; + * return count; + * }, + * // Call this to save the tracked events to the trackingUrl + * save: function() { + * $http.post(trackingUrl, trackedEvents); + * } + * }; + * }]; + * } + * + * describe('eventTracker', function() { + * var postSpy; + * + * beforeEach(module(function($provide) { + * // Register the eventTracker provider + * $provide.provider('eventTracker', EventTrackerProvider); + * })); + * + * beforeEach(module(function(eventTrackerProvider) { + * // Configure eventTracker provider + * eventTrackerProvider.setTrackingUrl('/custom-track'); + * })); + * + * it('tracks events', inject(function(eventTracker) { + * expect(eventTracker.event('login')).toEqual(1); + * expect(eventTracker.event('login')).toEqual(2); + * })); + * + * it('saves to the tracking url', inject(function(eventTracker, $http) { + * postSpy = spyOn($http, 'post'); + * eventTracker.event('login'); + * eventTracker.save(); + * expect(postSpy).toHaveBeenCalled(); + * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track'); + * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track'); + * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 }); + * })); + * }); + * ``` + */ + +/** + * @ngdoc method + * @name $provide#factory + * @description + * + * Register a **service factory**, which will be called to return the service instance. + * This is short for registering a service where its provider consists of only a `$get` property, + * which is the given service factory function. + * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to + * configure your service in a provider. + * + * @param {string} name The name of the instance. + * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand + * for `$provide.provider(name, {$get: $getFn})`. + * @returns {Object} registered provider instance + * + * @example + * Here is an example of registering a service + * ```js + * $provide.factory('ping', ['$http', function($http) { + * return function ping() { + * return $http.send('/ping'); + * }; + * }]); + * ``` + * You would then inject and use this service like this: + * ```js + * someModule.controller('Ctrl', ['ping', function(ping) { + * ping(); + * }]); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#service + * @description + * + * Register a **service constructor**, which will be invoked with `new` to create the service + * instance. + * This is short for registering a service where its provider's `$get` property is the service + * constructor function that will be used to instantiate the service instance. + * + * You should use {@link auto.$provide#service $provide.service(class)} if you define your service + * as a type/class. + * + * @param {string} name The name of the instance. + * @param {Function} constructor A class (constructor function) that will be instantiated. + * @returns {Object} registered provider instance + * + * @example + * Here is an example of registering a service using + * {@link auto.$provide#service $provide.service(class)}. + * ```js + * var Ping = function($http) { + * this.$http = $http; + * }; + * + * Ping.$inject = ['$http']; + * + * Ping.prototype.send = function() { + * return this.$http.get('/ping'); + * }; + * $provide.service('ping', Ping); + * ``` + * You would then inject and use this service like this: + * ```js + * someModule.controller('Ctrl', ['ping', function(ping) { + * ping.send(); + * }]); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#value + * @description + * + * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a + * number, an array, an object or a function. This is short for registering a service where its + * provider's `$get` property is a factory function that takes no arguments and returns the **value + * service**. + * + * Value services are similar to constant services, except that they cannot be injected into a + * module configuration function (see {@link angular.Module#config}) but they can be overridden by + * an Angular + * {@link auto.$provide#decorator decorator}. + * + * @param {string} name The name of the instance. + * @param {*} value The value. + * @returns {Object} registered provider instance + * + * @example + * Here are some examples of creating value services. + * ```js + * $provide.value('ADMIN_USER', 'admin'); + * + * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 }); + * + * $provide.value('halfOf', function(value) { + * return value / 2; + * }); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#constant + * @description + * + * Register a **constant service**, such as a string, a number, an array, an object or a function, + * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be + * injected into a module configuration function (see {@link angular.Module#config}) and it cannot + * be overridden by an Angular {@link auto.$provide#decorator decorator}. + * + * @param {string} name The name of the constant. + * @param {*} value The constant value. + * @returns {Object} registered instance + * + * @example + * Here a some examples of creating constants: + * ```js + * $provide.constant('SHARD_HEIGHT', 306); + * + * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']); + * + * $provide.constant('double', function(value) { + * return value * 2; + * }); + * ``` + */ + + +/** + * @ngdoc method + * @name $provide#decorator + * @description + * + * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator + * intercepts the creation of a service, allowing it to override or modify the behaviour of the + * service. The object returned by the decorator may be the original service, or a new service + * object which replaces or wraps and delegates to the original service. + * + * @param {string} name The name of the service to decorate. + * @param {function()} decorator This function will be invoked when the service needs to be + * instantiated and should return the decorated service instance. The function is called using + * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable. + * Local injection arguments: + * + * * `$delegate` - The original service instance, which can be monkey patched, configured, + * decorated or delegated to. + * + * @example + * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting + * calls to {@link ng.$log#error $log.warn()}. + * ```js + * $provide.decorator('$log', ['$delegate', function($delegate) { + * $delegate.warn = $delegate.error; + * return $delegate; + * }]); + * ``` + */ + + +function createInjector(modulesToLoad, strictDi) { + strictDi = (strictDi === true); + var INSTANTIATING = {}, + providerSuffix = 'Provider', + path = [], + loadedModules = new HashMap([], true), + providerCache = { + $provide: { + provider: supportObject(provider), + factory: supportObject(factory), + service: supportObject(service), + value: supportObject(value), + constant: supportObject(constant), + decorator: decorator + } + }, + providerInjector = (providerCache.$injector = + createInternalInjector(providerCache, function(serviceName, caller) { + if (angular.isString(caller)) { + path.push(caller); + } + throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); + })), + instanceCache = {}, + instanceInjector = (instanceCache.$injector = + createInternalInjector(instanceCache, function(serviceName, caller) { + var provider = providerInjector.get(serviceName + providerSuffix, caller); + return instanceInjector.invoke(provider.$get, provider, undefined, serviceName); + })); + + + forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); }); + + return instanceInjector; + + //////////////////////////////////// + // $provider + //////////////////////////////////// + + function supportObject(delegate) { + return function(key, value) { + if (isObject(key)) { + forEach(key, reverseParams(delegate)); + } else { + return delegate(key, value); + } + }; + } + + function provider(name, provider_) { + assertNotHasOwnProperty(name, 'service'); + if (isFunction(provider_) || isArray(provider_)) { + provider_ = providerInjector.instantiate(provider_); + } + if (!provider_.$get) { + throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); + } + return providerCache[name + providerSuffix] = provider_; + } + + function enforceReturnValue(name, factory) { + return function enforcedReturnValue() { + var result = instanceInjector.invoke(factory, this); + if (isUndefined(result)) { + throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name); + } + return result; + }; + } + + function factory(name, factoryFn, enforce) { + return provider(name, { + $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn + }); + } + + function service(name, constructor) { + return factory(name, ['$injector', function($injector) { + return $injector.instantiate(constructor); + }]); + } + + function value(name, val) { return factory(name, valueFn(val), false); } + + function constant(name, value) { + assertNotHasOwnProperty(name, 'constant'); + providerCache[name] = value; + instanceCache[name] = value; + } + + function decorator(serviceName, decorFn) { + var origProvider = providerInjector.get(serviceName + providerSuffix), + orig$get = origProvider.$get; + + origProvider.$get = function() { + var origInstance = instanceInjector.invoke(orig$get, origProvider); + return instanceInjector.invoke(decorFn, null, {$delegate: origInstance}); + }; + } + + //////////////////////////////////// + // Module Loading + //////////////////////////////////// + function loadModules(modulesToLoad) { + var runBlocks = [], moduleFn; + forEach(modulesToLoad, function(module) { + if (loadedModules.get(module)) return; + loadedModules.put(module, true); + + function runInvokeQueue(queue) { + var i, ii; + for (i = 0, ii = queue.length; i < ii; i++) { + var invokeArgs = queue[i], + provider = providerInjector.get(invokeArgs[0]); + + provider[invokeArgs[1]].apply(provider, invokeArgs[2]); + } + } + + try { + if (isString(module)) { + moduleFn = angularModule(module); + runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); + runInvokeQueue(moduleFn._invokeQueue); + runInvokeQueue(moduleFn._configBlocks); + } else if (isFunction(module)) { + runBlocks.push(providerInjector.invoke(module)); + } else if (isArray(module)) { + runBlocks.push(providerInjector.invoke(module)); + } else { + assertArgFn(module, 'module'); + } + } catch (e) { + if (isArray(module)) { + module = module[module.length - 1]; + } + if (e.message && e.stack && e.stack.indexOf(e.message) == -1) { + // Safari & FF's stack traces don't contain error.message content + // unlike those of Chrome and IE + // So if stack doesn't contain message, we create a new string that contains both. + // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here. + /* jshint -W022 */ + e = e.message + '\n' + e.stack; + } + throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", + module, e.stack || e.message || e); + } + }); + return runBlocks; + } + + //////////////////////////////////// + // internal Injector + //////////////////////////////////// + + function createInternalInjector(cache, factory) { + + function getService(serviceName, caller) { + if (cache.hasOwnProperty(serviceName)) { + if (cache[serviceName] === INSTANTIATING) { + throw $injectorMinErr('cdep', 'Circular dependency found: {0}', + serviceName + ' <- ' + path.join(' <- ')); + } + return cache[serviceName]; + } else { + try { + path.unshift(serviceName); + cache[serviceName] = INSTANTIATING; + return cache[serviceName] = factory(serviceName, caller); + } catch (err) { + if (cache[serviceName] === INSTANTIATING) { + delete cache[serviceName]; + } + throw err; + } finally { + path.shift(); + } + } + } + + function invoke(fn, self, locals, serviceName) { + if (typeof locals === 'string') { + serviceName = locals; + locals = null; + } + + var args = [], + $inject = createInjector.$$annotate(fn, strictDi, serviceName), + length, i, + key; + + for (i = 0, length = $inject.length; i < length; i++) { + key = $inject[i]; + if (typeof key !== 'string') { + throw $injectorMinErr('itkn', + 'Incorrect injection token! Expected service name as string, got {0}', key); + } + args.push( + locals && locals.hasOwnProperty(key) + ? locals[key] + : getService(key, serviceName) + ); + } + if (isArray(fn)) { + fn = fn[length]; + } + + // http://jsperf.com/angularjs-invoke-apply-vs-switch + // #5388 + return fn.apply(self, args); + } + + function instantiate(Type, locals, serviceName) { + // Check if Type is annotated and use just the given function at n-1 as parameter + // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); + // Object creation: http://jsperf.com/create-constructor/2 + var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null); + var returnedValue = invoke(Type, instance, locals, serviceName); + + return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance; + } + + return { + invoke: invoke, + instantiate: instantiate, + get: getService, + annotate: createInjector.$$annotate, + has: function(name) { + return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); + } + }; + } +} + +createInjector.$$annotate = annotate; + +/** + * @ngdoc provider + * @name $anchorScrollProvider + * + * @description + * Use `$anchorScrollProvider` to disable automatic scrolling whenever + * {@link ng.$location#hash $location.hash()} changes. + */ +function $AnchorScrollProvider() { + + var autoScrollingEnabled = true; + + /** + * @ngdoc method + * @name $anchorScrollProvider#disableAutoScrolling + * + * @description + * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to + * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.
    + * Use this method to disable automatic scrolling. + * + * If automatic scrolling is disabled, one must explicitly call + * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the + * current hash. + */ + this.disableAutoScrolling = function() { + autoScrollingEnabled = false; + }; + + /** + * @ngdoc service + * @name $anchorScroll + * @kind function + * @requires $window + * @requires $location + * @requires $rootScope + * + * @description + * When called, it checks the current value of {@link ng.$location#hash $location.hash()} and + * scrolls to the related element, according to the rules specified in the + * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document). + * + * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to + * match any anchor whenever it changes. This can be disabled by calling + * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}. + * + * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a + * vertical scroll-offset (either fixed or dynamic). + * + * @property {(number|function|jqLite)} yOffset + * If set, specifies a vertical scroll-offset. This is often useful when there are fixed + * positioned elements at the top of the page, such as navbars, headers etc. + * + * `yOffset` can be specified in various ways: + * - **number**: A fixed number of pixels to be used as offset.

    + * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return + * a number representing the offset (in pixels).

    + * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from + * the top of the page to the element's bottom will be used as offset.
    + * **Note**: The element will be taken into account only as long as its `position` is set to + * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust + * their height and/or positioning according to the viewport's size. + * + *
    + *
    + * In order for `yOffset` to work properly, scrolling should take place on the document's root and + * not some child element. + *
    + * + * @example + + +
    + Go to bottom + You're at the bottom! +
    +
    + + angular.module('anchorScrollExample', []) + .controller('ScrollController', ['$scope', '$location', '$anchorScroll', + function ($scope, $location, $anchorScroll) { + $scope.gotoBottom = function() { + // set the location.hash to the id of + // the element you wish to scroll to. + $location.hash('bottom'); + + // call $anchorScroll() + $anchorScroll(); + }; + }]); + + + #scrollArea { + height: 280px; + overflow: auto; + } + + #bottom { + display: block; + margin-top: 2000px; + } + +
    + * + *
    + * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value). + * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details. + * + * @example + + + +
    + Anchor {{x}} of 5 +
    +
    + + angular.module('anchorScrollOffsetExample', []) + .run(['$anchorScroll', function($anchorScroll) { + $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels + }]) + .controller('headerCtrl', ['$anchorScroll', '$location', '$scope', + function ($anchorScroll, $location, $scope) { + $scope.gotoAnchor = function(x) { + var newHash = 'anchor' + x; + if ($location.hash() !== newHash) { + // set the $location.hash to `newHash` and + // $anchorScroll will automatically scroll to it + $location.hash('anchor' + x); + } else { + // call $anchorScroll() explicitly, + // since $location.hash hasn't changed + $anchorScroll(); + } + }; + } + ]); + + + body { + padding-top: 50px; + } + + .anchor { + border: 2px dashed DarkOrchid; + padding: 10px 10px 200px 10px; + } + + .fixed-header { + background-color: rgba(0, 0, 0, 0.2); + height: 50px; + position: fixed; + top: 0; left: 0; right: 0; + } + + .fixed-header > a { + display: inline-block; + margin: 5px 15px; + } + +
    + */ + this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) { + var document = $window.document; + + // Helper function to get first anchor from a NodeList + // (using `Array#some()` instead of `angular#forEach()` since it's more performant + // and working in all supported browsers.) + function getFirstAnchor(list) { + var result = null; + Array.prototype.some.call(list, function(element) { + if (nodeName_(element) === 'a') { + result = element; + return true; + } + }); + return result; + } + + function getYOffset() { + + var offset = scroll.yOffset; + + if (isFunction(offset)) { + offset = offset(); + } else if (isElement(offset)) { + var elem = offset[0]; + var style = $window.getComputedStyle(elem); + if (style.position !== 'fixed') { + offset = 0; + } else { + offset = elem.getBoundingClientRect().bottom; + } + } else if (!isNumber(offset)) { + offset = 0; + } + + return offset; + } + + function scrollTo(elem) { + if (elem) { + elem.scrollIntoView(); + + var offset = getYOffset(); + + if (offset) { + // `offset` is the number of pixels we should scroll UP in order to align `elem` properly. + // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the + // top of the viewport. + // + // IF the number of pixels from the top of `elem` to the end of the page's content is less + // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some + // way down the page. + // + // This is often the case for elements near the bottom of the page. + // + // In such cases we do not need to scroll the whole `offset` up, just the difference between + // the top of the element and the offset, which is enough to align the top of `elem` at the + // desired position. + var elemTop = elem.getBoundingClientRect().top; + $window.scrollBy(0, elemTop - offset); + } + } else { + $window.scrollTo(0, 0); + } + } + + function scroll() { + var hash = $location.hash(), elm; + + // empty hash, scroll to the top of the page + if (!hash) scrollTo(null); + + // element with given id + else if ((elm = document.getElementById(hash))) scrollTo(elm); + + // first anchor with given name :-D + else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm); + + // no element and hash == 'top', scroll to the top of the page + else if (hash === 'top') scrollTo(null); + } + + // does not scroll when user clicks on anchor link that is currently on + // (no url change, no $location.hash() change), browser native does scroll + if (autoScrollingEnabled) { + $rootScope.$watch(function autoScrollWatch() {return $location.hash();}, + function autoScrollWatchAction(newVal, oldVal) { + // skip the initial scroll if $location.hash is empty + if (newVal === oldVal && newVal === '') return; + + jqLiteDocumentLoaded(function() { + $rootScope.$evalAsync(scroll); + }); + }); + } + + return scroll; + }]; +} + +var $animateMinErr = minErr('$animate'); + +/** + * @ngdoc provider + * @name $animateProvider + * + * @description + * Default implementation of $animate that doesn't perform any animations, instead just + * synchronously performs DOM + * updates and calls done() callbacks. + * + * In order to enable animations the ngAnimate module has to be loaded. + * + * To see the functional implementation check out src/ngAnimate/animate.js + */ +var $AnimateProvider = ['$provide', function($provide) { + + + this.$$selectors = {}; + + + /** + * @ngdoc method + * @name $animateProvider#register + * + * @description + * Registers a new injectable animation factory function. The factory function produces the + * animation object which contains callback functions for each event that is expected to be + * animated. + * + * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` + * must be called once the element animation is complete. If a function is returned then the + * animation service will use this function to cancel the animation whenever a cancel event is + * triggered. + * + * + * ```js + * return { + * eventFn : function(element, done) { + * //code to run the animation + * //once complete, then run done() + * return function cancellationFunction() { + * //code to cancel the animation + * } + * } + * } + * ``` + * + * @param {string} name The name of the animation. + * @param {Function} factory The factory function that will be executed to return the animation + * object. + */ + this.register = function(name, factory) { + var key = name + '-animation'; + if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel', + "Expecting class selector starting with '.' got '{0}'.", name); + this.$$selectors[name.substr(1)] = key; + $provide.factory(key, factory); + }; + + /** + * @ngdoc method + * @name $animateProvider#classNameFilter + * + * @description + * Sets and/or returns the CSS class regular expression that is checked when performing + * an animation. Upon bootstrap the classNameFilter value is not set at all and will + * therefore enable $animate to attempt to perform an animation on any element. + * When setting the classNameFilter value, animations will only be performed on elements + * that successfully match the filter expression. This in turn can boost performance + * for low-powered devices as well as applications containing a lot of structural operations. + * @param {RegExp=} expression The className expression which will be checked against all animations + * @return {RegExp} The current CSS className expression value. If null then there is no expression value + */ + this.classNameFilter = function(expression) { + if (arguments.length === 1) { + this.$$classNameFilter = (expression instanceof RegExp) ? expression : null; + } + return this.$$classNameFilter; + }; + + this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) { + + var currentDefer; + + function runAnimationPostDigest(fn) { + var cancelFn, defer = $$q.defer(); + defer.promise.$$cancelFn = function ngAnimateMaybeCancel() { + cancelFn && cancelFn(); + }; + + $rootScope.$$postDigest(function ngAnimatePostDigest() { + cancelFn = fn(function ngAnimateNotifyComplete() { + defer.resolve(); + }); + }); + + return defer.promise; + } + + function resolveElementClasses(element, classes) { + var toAdd = [], toRemove = []; + + var hasClasses = createMap(); + forEach((element.attr('class') || '').split(/\s+/), function(className) { + hasClasses[className] = true; + }); + + forEach(classes, function(status, className) { + var hasClass = hasClasses[className]; + + // If the most recent class manipulation (via $animate) was to remove the class, and the + // element currently has the class, the class is scheduled for removal. Otherwise, if + // the most recent class manipulation (via $animate) was to add the class, and the + // element does not currently have the class, the class is scheduled to be added. + if (status === false && hasClass) { + toRemove.push(className); + } else if (status === true && !hasClass) { + toAdd.push(className); + } + }); + + return (toAdd.length + toRemove.length) > 0 && + [toAdd.length ? toAdd : null, toRemove.length ? toRemove : null]; + } + + function cachedClassManipulation(cache, classes, op) { + for (var i=0, ii = classes.length; i < ii; ++i) { + var className = classes[i]; + cache[className] = op; + } + } + + function asyncPromise() { + // only serve one instance of a promise in order to save CPU cycles + if (!currentDefer) { + currentDefer = $$q.defer(); + $$asyncCallback(function() { + currentDefer.resolve(); + currentDefer = null; + }); + } + return currentDefer.promise; + } + + function applyStyles(element, options) { + if (angular.isObject(options)) { + var styles = extend(options.from || {}, options.to || {}); + element.css(styles); + } + } + + /** + * + * @ngdoc service + * @name $animate + * @description The $animate service provides rudimentary DOM manipulation functions to + * insert, remove and move elements within the DOM, as well as adding and removing classes. + * This service is the core service used by the ngAnimate $animator service which provides + * high-level animation hooks for CSS and JavaScript. + * + * $animate is available in the AngularJS core, however, the ngAnimate module must be included + * to enable full out animation support. Otherwise, $animate will only perform simple DOM + * manipulation operations. + * + * To learn more about enabling animation support, click here to visit the {@link ngAnimate + * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service + * page}. + */ + return { + animate: function(element, from, to) { + applyStyles(element, { from: from, to: to }); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#enter + * @kind function + * @description Inserts the element into the DOM either after the `after` element or + * as the first child within the `parent` element. When the function is called a promise + * is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will be inserted into the DOM + * @param {DOMElement} parent the parent element which will append the element as + * a child (if the after element is not present) + * @param {DOMElement} after the sibling element which will append the element + * after itself + * @param {object=} options an optional collection of styles that will be applied to the element. + * @return {Promise} the animation callback promise + */ + enter: function(element, parent, after, options) { + applyStyles(element, options); + after ? after.after(element) + : parent.prepend(element); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#leave + * @kind function + * @description Removes the element from the DOM. When the function is called a promise + * is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will be removed from the DOM + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + leave: function(element, options) { + element.remove(); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#move + * @kind function + * @description Moves the position of the provided element within the DOM to be placed + * either after the `after` element or inside of the `parent` element. When the function + * is called a promise is returned that will be resolved at a later time. + * + * @param {DOMElement} element the element which will be moved around within the + * DOM + * @param {DOMElement} parent the parent element where the element will be + * inserted into (if the after element is not present) + * @param {DOMElement} after the sibling element where the element will be + * positioned next to + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + move: function(element, parent, after, options) { + // Do not remove element before insert. Removing will cause data associated with the + // element to be dropped. Insert will implicitly do the remove. + return this.enter(element, parent, after, options); + }, + + /** + * + * @ngdoc method + * @name $animate#addClass + * @kind function + * @description Adds the provided className CSS class value to the provided element. + * When the function is called a promise is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will have the className value + * added to it + * @param {string} className the CSS class which will be added to the element + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + addClass: function(element, className, options) { + return this.setClass(element, className, [], options); + }, + + $$addClassImmediately: function(element, className, options) { + element = jqLite(element); + className = !isString(className) + ? (isArray(className) ? className.join(' ') : '') + : className; + forEach(element, function(element) { + jqLiteAddClass(element, className); + }); + applyStyles(element, options); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#removeClass + * @kind function + * @description Removes the provided className CSS class value from the provided element. + * When the function is called a promise is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will have the className value + * removed from it + * @param {string} className the CSS class which will be removed from the element + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + removeClass: function(element, className, options) { + return this.setClass(element, [], className, options); + }, + + $$removeClassImmediately: function(element, className, options) { + element = jqLite(element); + className = !isString(className) + ? (isArray(className) ? className.join(' ') : '') + : className; + forEach(element, function(element) { + jqLiteRemoveClass(element, className); + }); + applyStyles(element, options); + return asyncPromise(); + }, + + /** + * + * @ngdoc method + * @name $animate#setClass + * @kind function + * @description Adds and/or removes the given CSS classes to and from the element. + * When the function is called a promise is returned that will be resolved at a later time. + * @param {DOMElement} element the element which will have its CSS classes changed + * removed from it + * @param {string} add the CSS classes which will be added to the element + * @param {string} remove the CSS class which will be removed from the element + * @param {object=} options an optional collection of options that will be applied to the element. + * @return {Promise} the animation callback promise + */ + setClass: function(element, add, remove, options) { + var self = this; + var STORAGE_KEY = '$$animateClasses'; + var createdCache = false; + element = jqLite(element); + + var cache = element.data(STORAGE_KEY); + if (!cache) { + cache = { + classes: {}, + options: options + }; + createdCache = true; + } else if (options && cache.options) { + cache.options = angular.extend(cache.options || {}, options); + } + + var classes = cache.classes; + + add = isArray(add) ? add : add.split(' '); + remove = isArray(remove) ? remove : remove.split(' '); + cachedClassManipulation(classes, add, true); + cachedClassManipulation(classes, remove, false); + + if (createdCache) { + cache.promise = runAnimationPostDigest(function(done) { + var cache = element.data(STORAGE_KEY); + element.removeData(STORAGE_KEY); + + // in the event that the element is removed before postDigest + // is run then the cache will be undefined and there will be + // no need anymore to add or remove and of the element classes + if (cache) { + var classes = resolveElementClasses(element, cache.classes); + if (classes) { + self.$$setClassImmediately(element, classes[0], classes[1], cache.options); + } + } + + done(); + }); + element.data(STORAGE_KEY, cache); + } + + return cache.promise; + }, + + $$setClassImmediately: function(element, add, remove, options) { + add && this.$$addClassImmediately(element, add); + remove && this.$$removeClassImmediately(element, remove); + applyStyles(element, options); + return asyncPromise(); + }, + + enabled: noop, + cancel: noop + }; + }]; +}]; + +function $$AsyncCallbackProvider() { + this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) { + return $$rAF.supported + ? function(fn) { return $$rAF(fn); } + : function(fn) { + return $timeout(fn, 0, false); + }; + }]; +} + +/* global stripHash: true */ + +/** + * ! This is a private undocumented service ! + * + * @name $browser + * @requires $log + * @description + * This object has two goals: + * + * - hide all the global state in the browser caused by the window object + * - abstract away all the browser specific features and inconsistencies + * + * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser` + * service, which can be used for convenient testing of the application without the interaction with + * the real browser apis. + */ +/** + * @param {object} window The global window object. + * @param {object} document jQuery wrapped document. + * @param {object} $log window.console or an object with the same interface. + * @param {object} $sniffer $sniffer service + */ +function Browser(window, document, $log, $sniffer) { + var self = this, + rawDocument = document[0], + location = window.location, + history = window.history, + setTimeout = window.setTimeout, + clearTimeout = window.clearTimeout, + pendingDeferIds = {}; + + self.isMock = false; + + var outstandingRequestCount = 0; + var outstandingRequestCallbacks = []; + + // TODO(vojta): remove this temporary api + self.$$completeOutstandingRequest = completeOutstandingRequest; + self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; }; + + /** + * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks` + * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed. + */ + function completeOutstandingRequest(fn) { + try { + fn.apply(null, sliceArgs(arguments, 1)); + } finally { + outstandingRequestCount--; + if (outstandingRequestCount === 0) { + while (outstandingRequestCallbacks.length) { + try { + outstandingRequestCallbacks.pop()(); + } catch (e) { + $log.error(e); + } + } + } + } + } + + function getHash(url) { + var index = url.indexOf('#'); + return index === -1 ? '' : url.substr(index + 1); + } + + /** + * @private + * Note: this method is used only by scenario runner + * TODO(vojta): prefix this method with $$ ? + * @param {function()} callback Function that will be called when no outstanding request + */ + self.notifyWhenNoOutstandingRequests = function(callback) { + // force browser to execute all pollFns - this is needed so that cookies and other pollers fire + // at some deterministic time in respect to the test runner's actions. Leaving things up to the + // regular poller would result in flaky tests. + forEach(pollFns, function(pollFn) { pollFn(); }); + + if (outstandingRequestCount === 0) { + callback(); + } else { + outstandingRequestCallbacks.push(callback); + } + }; + + ////////////////////////////////////////////////////////////// + // Poll Watcher API + ////////////////////////////////////////////////////////////// + var pollFns = [], + pollTimeout; + + /** + * @name $browser#addPollFn + * + * @param {function()} fn Poll function to add + * + * @description + * Adds a function to the list of functions that poller periodically executes, + * and starts polling if not started yet. + * + * @returns {function()} the added function + */ + self.addPollFn = function(fn) { + if (isUndefined(pollTimeout)) startPoller(100, setTimeout); + pollFns.push(fn); + return fn; + }; + + /** + * @param {number} interval How often should browser call poll functions (ms) + * @param {function()} setTimeout Reference to a real or fake `setTimeout` function. + * + * @description + * Configures the poller to run in the specified intervals, using the specified + * setTimeout fn and kicks it off. + */ + function startPoller(interval, setTimeout) { + (function check() { + forEach(pollFns, function(pollFn) { pollFn(); }); + pollTimeout = setTimeout(check, interval); + })(); + } + + ////////////////////////////////////////////////////////////// + // URL API + ////////////////////////////////////////////////////////////// + + var cachedState, lastHistoryState, + lastBrowserUrl = location.href, + baseElement = document.find('base'), + reloadLocation = null; + + cacheState(); + lastHistoryState = cachedState; + + /** + * @name $browser#url + * + * @description + * GETTER: + * Without any argument, this method just returns current value of location.href. + * + * SETTER: + * With at least one argument, this method sets url to new value. + * If html5 history api supported, pushState/replaceState is used, otherwise + * location.href/location.replace is used. + * Returns its own instance to allow chaining + * + * NOTE: this api is intended for use only by the $location service. Please use the + * {@link ng.$location $location service} to change url. + * + * @param {string} url New url (when used as setter) + * @param {boolean=} replace Should new url replace current history record? + * @param {object=} state object to use with pushState/replaceState + */ + self.url = function(url, replace, state) { + // In modern browsers `history.state` is `null` by default; treating it separately + // from `undefined` would cause `$browser.url('/foo')` to change `history.state` + // to undefined via `pushState`. Instead, let's change `undefined` to `null` here. + if (isUndefined(state)) { + state = null; + } + + // Android Browser BFCache causes location, history reference to become stale. + if (location !== window.location) location = window.location; + if (history !== window.history) history = window.history; + + // setter + if (url) { + var sameState = lastHistoryState === state; + + // Don't change anything if previous and current URLs and states match. This also prevents + // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode. + // See https://github.com/angular/angular.js/commit/ffb2701 + if (lastBrowserUrl === url && (!$sniffer.history || sameState)) { + return self; + } + var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url); + lastBrowserUrl = url; + lastHistoryState = state; + // Don't use history API if only the hash changed + // due to a bug in IE10/IE11 which leads + // to not firing a `hashchange` nor `popstate` event + // in some cases (see #9143). + if ($sniffer.history && (!sameBase || !sameState)) { + history[replace ? 'replaceState' : 'pushState'](state, '', url); + cacheState(); + // Do the assignment again so that those two variables are referentially identical. + lastHistoryState = cachedState; + } else { + if (!sameBase) { + reloadLocation = url; + } + if (replace) { + location.replace(url); + } else if (!sameBase) { + location.href = url; + } else { + location.hash = getHash(url); + } + } + return self; + // getter + } else { + // - reloadLocation is needed as browsers don't allow to read out + // the new location.href if a reload happened. + // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 + return reloadLocation || location.href.replace(/%27/g,"'"); + } + }; + + /** + * @name $browser#state + * + * @description + * This method is a getter. + * + * Return history.state or null if history.state is undefined. + * + * @returns {object} state + */ + self.state = function() { + return cachedState; + }; + + var urlChangeListeners = [], + urlChangeInit = false; + + function cacheStateAndFireUrlChange() { + cacheState(); + fireUrlChange(); + } + + // This variable should be used *only* inside the cacheState function. + var lastCachedState = null; + function cacheState() { + // This should be the only place in $browser where `history.state` is read. + cachedState = window.history.state; + cachedState = isUndefined(cachedState) ? null : cachedState; + + // Prevent callbacks fo fire twice if both hashchange & popstate were fired. + if (equals(cachedState, lastCachedState)) { + cachedState = lastCachedState; + } + lastCachedState = cachedState; + } + + function fireUrlChange() { + if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) { + return; + } + + lastBrowserUrl = self.url(); + lastHistoryState = cachedState; + forEach(urlChangeListeners, function(listener) { + listener(self.url(), cachedState); + }); + } + + /** + * @name $browser#onUrlChange + * + * @description + * Register callback function that will be called, when url changes. + * + * It's only called when the url is changed from outside of angular: + * - user types different url into address bar + * - user clicks on history (forward/back) button + * - user clicks on a link + * + * It's not called when url is changed by $browser.url() method + * + * The listener gets called with new url as parameter. + * + * NOTE: this api is intended for use only by the $location service. Please use the + * {@link ng.$location $location service} to monitor url changes in angular apps. + * + * @param {function(string)} listener Listener function to be called when url changes. + * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous. + */ + self.onUrlChange = function(callback) { + // TODO(vojta): refactor to use node's syntax for events + if (!urlChangeInit) { + // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera) + // don't fire popstate when user change the address bar and don't fire hashchange when url + // changed by push/replaceState + + // html5 history api - popstate event + if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange); + // hashchange event + jqLite(window).on('hashchange', cacheStateAndFireUrlChange); + + urlChangeInit = true; + } + + urlChangeListeners.push(callback); + return callback; + }; + + /** + * Checks whether the url has changed outside of Angular. + * Needs to be exported to be able to check for changes that have been done in sync, + * as hashchange/popstate events fire in async. + */ + self.$$checkUrlChange = fireUrlChange; + + ////////////////////////////////////////////////////////////// + // Misc API + ////////////////////////////////////////////////////////////// + + /** + * @name $browser#baseHref + * + * @description + * Returns current + * (always relative - without domain) + * + * @returns {string} The current base href + */ + self.baseHref = function() { + var href = baseElement.attr('href'); + return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : ''; + }; + + ////////////////////////////////////////////////////////////// + // Cookies API + ////////////////////////////////////////////////////////////// + var lastCookies = {}; + var lastCookieString = ''; + var cookiePath = self.baseHref(); + + function safeDecodeURIComponent(str) { + try { + return decodeURIComponent(str); + } catch (e) { + return str; + } + } + + /** + * @name $browser#cookies + * + * @param {string=} name Cookie name + * @param {string=} value Cookie value + * + * @description + * The cookies method provides a 'private' low level access to browser cookies. + * It is not meant to be used directly, use the $cookie service instead. + * + * The return values vary depending on the arguments that the method was called with as follows: + * + * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify + * it + * - cookies(name, value) -> set name to value, if value is undefined delete the cookie + * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that + * way) + * + * @returns {Object} Hash of all cookies (if called without any parameter) + */ + self.cookies = function(name, value) { + var cookieLength, cookieArray, cookie, i, index; + + if (name) { + if (value === undefined) { + rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath + + ";expires=Thu, 01 Jan 1970 00:00:00 GMT"; + } else { + if (isString(value)) { + cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) + + ';path=' + cookiePath).length + 1; + + // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum: + // - 300 cookies + // - 20 cookies per unique domain + // - 4096 bytes per cookie + if (cookieLength > 4096) { + $log.warn("Cookie '" + name + + "' possibly not set or overflowed because it was too large (" + + cookieLength + " > 4096 bytes)!"); + } + } + } + } else { + if (rawDocument.cookie !== lastCookieString) { + lastCookieString = rawDocument.cookie; + cookieArray = lastCookieString.split("; "); + lastCookies = {}; + + for (i = 0; i < cookieArray.length; i++) { + cookie = cookieArray[i]; + index = cookie.indexOf('='); + if (index > 0) { //ignore nameless cookies + name = safeDecodeURIComponent(cookie.substring(0, index)); + // the first value that is seen for a cookie is the most + // specific one. values for the same cookie name that + // follow are for less specific paths. + if (lastCookies[name] === undefined) { + lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1)); + } + } + } + } + return lastCookies; + } + }; + + + /** + * @name $browser#defer + * @param {function()} fn A function, who's execution should be deferred. + * @param {number=} [delay=0] of milliseconds to defer the function execution. + * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`. + * + * @description + * Executes a fn asynchronously via `setTimeout(fn, delay)`. + * + * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using + * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed + * via `$browser.defer.flush()`. + * + */ + self.defer = function(fn, delay) { + var timeoutId; + outstandingRequestCount++; + timeoutId = setTimeout(function() { + delete pendingDeferIds[timeoutId]; + completeOutstandingRequest(fn); + }, delay || 0); + pendingDeferIds[timeoutId] = true; + return timeoutId; + }; + + + /** + * @name $browser#defer.cancel + * + * @description + * Cancels a deferred task identified with `deferId`. + * + * @param {*} deferId Token returned by the `$browser.defer` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ + self.defer.cancel = function(deferId) { + if (pendingDeferIds[deferId]) { + delete pendingDeferIds[deferId]; + clearTimeout(deferId); + completeOutstandingRequest(noop); + return true; + } + return false; + }; + +} + +function $BrowserProvider() { + this.$get = ['$window', '$log', '$sniffer', '$document', + function($window, $log, $sniffer, $document) { + return new Browser($window, $document, $log, $sniffer); + }]; +} + +/** + * @ngdoc service + * @name $cacheFactory + * + * @description + * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to + * them. + * + * ```js + * + * var cache = $cacheFactory('cacheId'); + * expect($cacheFactory.get('cacheId')).toBe(cache); + * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined(); + * + * cache.put("key", "value"); + * cache.put("another key", "another value"); + * + * // We've specified no options on creation + * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); + * + * ``` + * + * + * @param {string} cacheId Name or id of the newly created cache. + * @param {object=} options Options object that specifies the cache behavior. Properties: + * + * - `{number=}` `capacity` — turns the cache into LRU cache. + * + * @returns {object} Newly created cache object with the following set of methods: + * + * - `{object}` `info()` — Returns id, size, and options of cache. + * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns + * it. + * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss. + * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache. + * - `{void}` `removeAll()` — Removes all cached values. + * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory. + * + * @example + + +
    + + + + +

    Cached Values

    +
    + + : + +
    + +

    Cache Info

    +
    + + : + +
    +
    +
    + + angular.module('cacheExampleApp', []). + controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) { + $scope.keys = []; + $scope.cache = $cacheFactory('cacheId'); + $scope.put = function(key, value) { + if ($scope.cache.get(key) === undefined) { + $scope.keys.push(key); + } + $scope.cache.put(key, value === undefined ? null : value); + }; + }]); + + + p { + margin: 10px 0 3px; + } + +
    + */ +function $CacheFactoryProvider() { + + this.$get = function() { + var caches = {}; + + function cacheFactory(cacheId, options) { + if (cacheId in caches) { + throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId); + } + + var size = 0, + stats = extend({}, options, {id: cacheId}), + data = {}, + capacity = (options && options.capacity) || Number.MAX_VALUE, + lruHash = {}, + freshEnd = null, + staleEnd = null; + + /** + * @ngdoc type + * @name $cacheFactory.Cache + * + * @description + * A cache object used to store and retrieve data, primarily used by + * {@link $http $http} and the {@link ng.directive:script script} directive to cache + * templates and other data. + * + * ```js + * angular.module('superCache') + * .factory('superCache', ['$cacheFactory', function($cacheFactory) { + * return $cacheFactory('super-cache'); + * }]); + * ``` + * + * Example test: + * + * ```js + * it('should behave like a cache', inject(function(superCache) { + * superCache.put('key', 'value'); + * superCache.put('another key', 'another value'); + * + * expect(superCache.info()).toEqual({ + * id: 'super-cache', + * size: 2 + * }); + * + * superCache.remove('another key'); + * expect(superCache.get('another key')).toBeUndefined(); + * + * superCache.removeAll(); + * expect(superCache.info()).toEqual({ + * id: 'super-cache', + * size: 0 + * }); + * })); + * ``` + */ + return caches[cacheId] = { + + /** + * @ngdoc method + * @name $cacheFactory.Cache#put + * @kind function + * + * @description + * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be + * retrieved later, and incrementing the size of the cache if the key was not already + * present in the cache. If behaving like an LRU cache, it will also remove stale + * entries from the set. + * + * It will not insert undefined values into the cache. + * + * @param {string} key the key under which the cached data is stored. + * @param {*} value the value to store alongside the key. If it is undefined, the key + * will not be stored. + * @returns {*} the value stored. + */ + put: function(key, value) { + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key] || (lruHash[key] = {key: key}); + + refresh(lruEntry); + } + + if (isUndefined(value)) return; + if (!(key in data)) size++; + data[key] = value; + + if (size > capacity) { + this.remove(staleEnd.key); + } + + return value; + }, + + /** + * @ngdoc method + * @name $cacheFactory.Cache#get + * @kind function + * + * @description + * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object. + * + * @param {string} key the key of the data to be retrieved + * @returns {*} the value stored. + */ + get: function(key) { + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key]; + + if (!lruEntry) return; + + refresh(lruEntry); + } + + return data[key]; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#remove + * @kind function + * + * @description + * Removes an entry from the {@link $cacheFactory.Cache Cache} object. + * + * @param {string} key the key of the entry to be removed + */ + remove: function(key) { + if (capacity < Number.MAX_VALUE) { + var lruEntry = lruHash[key]; + + if (!lruEntry) return; + + if (lruEntry == freshEnd) freshEnd = lruEntry.p; + if (lruEntry == staleEnd) staleEnd = lruEntry.n; + link(lruEntry.n,lruEntry.p); + + delete lruHash[key]; + } + + delete data[key]; + size--; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#removeAll + * @kind function + * + * @description + * Clears the cache object of any entries. + */ + removeAll: function() { + data = {}; + size = 0; + lruHash = {}; + freshEnd = staleEnd = null; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#destroy + * @kind function + * + * @description + * Destroys the {@link $cacheFactory.Cache Cache} object entirely, + * removing it from the {@link $cacheFactory $cacheFactory} set. + */ + destroy: function() { + data = null; + stats = null; + lruHash = null; + delete caches[cacheId]; + }, + + + /** + * @ngdoc method + * @name $cacheFactory.Cache#info + * @kind function + * + * @description + * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}. + * + * @returns {object} an object with the following properties: + *
      + *
    • **id**: the id of the cache instance
    • + *
    • **size**: the number of entries kept in the cache instance
    • + *
    • **...**: any additional properties from the options object when creating the + * cache.
    • + *
    + */ + info: function() { + return extend({}, stats, {size: size}); + } + }; + + + /** + * makes the `entry` the freshEnd of the LRU linked list + */ + function refresh(entry) { + if (entry != freshEnd) { + if (!staleEnd) { + staleEnd = entry; + } else if (staleEnd == entry) { + staleEnd = entry.n; + } + + link(entry.n, entry.p); + link(entry, freshEnd); + freshEnd = entry; + freshEnd.n = null; + } + } + + + /** + * bidirectionally links two entries of the LRU linked list + */ + function link(nextEntry, prevEntry) { + if (nextEntry != prevEntry) { + if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify + if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify + } + } + } + + + /** + * @ngdoc method + * @name $cacheFactory#info + * + * @description + * Get information about all the caches that have been created + * + * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info` + */ + cacheFactory.info = function() { + var info = {}; + forEach(caches, function(cache, cacheId) { + info[cacheId] = cache.info(); + }); + return info; + }; + + + /** + * @ngdoc method + * @name $cacheFactory#get + * + * @description + * Get access to a cache object by the `cacheId` used when it was created. + * + * @param {string} cacheId Name or id of a cache to access. + * @returns {object} Cache object identified by the cacheId or undefined if no such cache. + */ + cacheFactory.get = function(cacheId) { + return caches[cacheId]; + }; + + + return cacheFactory; + }; +} + +/** + * @ngdoc service + * @name $templateCache + * + * @description + * The first time a template is used, it is loaded in the template cache for quick retrieval. You + * can load templates directly into the cache in a `script` tag, or by consuming the + * `$templateCache` service directly. + * + * Adding via the `script` tag: + * + * ```html + * + * ``` + * + * **Note:** the `script` tag containing the template does not need to be included in the `head` of + * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE, + * element with ng-app attribute), otherwise the template will be ignored. + * + * Adding via the $templateCache service: + * + * ```js + * var myApp = angular.module('myApp', []); + * myApp.run(function($templateCache) { + * $templateCache.put('templateId.html', 'This is the content of the template'); + * }); + * ``` + * + * To retrieve the template later, simply use it in your HTML: + * ```html + *
    + * ``` + * + * or get it via Javascript: + * ```js + * $templateCache.get('templateId.html') + * ``` + * + * See {@link ng.$cacheFactory $cacheFactory}. + * + */ +function $TemplateCacheProvider() { + this.$get = ['$cacheFactory', function($cacheFactory) { + return $cacheFactory('templates'); + }]; +} + +/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE! + * + * DOM-related variables: + * + * - "node" - DOM Node + * - "element" - DOM Element or Node + * - "$node" or "$element" - jqLite-wrapped node or element + * + * + * Compiler related stuff: + * + * - "linkFn" - linking fn of a single directive + * - "nodeLinkFn" - function that aggregates all linking fns for a particular node + * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node + * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList) + */ + + +/** + * @ngdoc service + * @name $compile + * @kind function + * + * @description + * Compiles an HTML string or DOM into a template and produces a template function, which + * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together. + * + * The compilation is a process of walking the DOM tree and matching DOM elements to + * {@link ng.$compileProvider#directive directives}. + * + *
    + * **Note:** This document is an in-depth reference of all directive options. + * For a gentle introduction to directives with examples of common use cases, + * see the {@link guide/directive directive guide}. + *
    + * + * ## Comprehensive Directive API + * + * There are many different options for a directive. + * + * The difference resides in the return value of the factory function. + * You can either return a "Directive Definition Object" (see below) that defines the directive properties, + * or just the `postLink` function (all other properties will have the default values). + * + *
    + * **Best Practice:** It's recommended to use the "directive definition object" form. + *
    + * + * Here's an example directive declared with a Directive Definition Object: + * + * ```js + * var myModule = angular.module(...); + * + * myModule.directive('directiveName', function factory(injectables) { + * var directiveDefinitionObject = { + * priority: 0, + * template: '
    ', // or // function(tElement, tAttrs) { ... }, + * // or + * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, + * transclude: false, + * restrict: 'A', + * templateNamespace: 'html', + * scope: false, + * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, + * controllerAs: 'stringAlias', + * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], + * compile: function compile(tElement, tAttrs, transclude) { + * return { + * pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + * post: function postLink(scope, iElement, iAttrs, controller) { ... } + * } + * // or + * // return function postLink( ... ) { ... } + * }, + * // or + * // link: { + * // pre: function preLink(scope, iElement, iAttrs, controller) { ... }, + * // post: function postLink(scope, iElement, iAttrs, controller) { ... } + * // } + * // or + * // link: function postLink( ... ) { ... } + * }; + * return directiveDefinitionObject; + * }); + * ``` + * + *
    + * **Note:** Any unspecified options will use the default value. You can see the default values below. + *
    + * + * Therefore the above can be simplified as: + * + * ```js + * var myModule = angular.module(...); + * + * myModule.directive('directiveName', function factory(injectables) { + * var directiveDefinitionObject = { + * link: function postLink(scope, iElement, iAttrs) { ... } + * }; + * return directiveDefinitionObject; + * // or + * // return function postLink(scope, iElement, iAttrs) { ... } + * }); + * ``` + * + * + * + * ### Directive Definition Object + * + * The directive definition object provides instructions to the {@link ng.$compile + * compiler}. The attributes are: + * + * #### `multiElement` + * When this property is set to true, the HTML compiler will collect DOM nodes between + * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them + * together as the directive elements. It is recommended that this feature be used on directives + * which are not strictly behavioural (such as {@link ngClick}), and which + * do not manipulate or replace child nodes (such as {@link ngInclude}). + * + * #### `priority` + * When there are multiple directives defined on a single DOM element, sometimes it + * is necessary to specify the order in which the directives are applied. The `priority` is used + * to sort the directives before their `compile` functions get called. Priority is defined as a + * number. Directives with greater numerical `priority` are compiled first. Pre-link functions + * are also run in priority order, but post-link functions are run in reverse order. The order + * of directives with the same priority is undefined. The default priority is `0`. + * + * #### `terminal` + * If set to true then the current `priority` will be the last set of directives + * which will execute (any directives at the current priority will still execute + * as the order of execution on same `priority` is undefined). Note that expressions + * and other directives used in the directive's template will also be excluded from execution. + * + * #### `scope` + * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the + * same element request a new scope, only one new scope is created. The new scope rule does not + * apply for the root of the template since the root of the template always gets a new scope. + * + * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from + * normal scope in that it does not prototypically inherit from the parent scope. This is useful + * when creating reusable components, which should not accidentally read or modify data in the + * parent scope. + * + * The 'isolate' scope takes an object hash which defines a set of local scope properties + * derived from the parent scope. These local properties are useful for aliasing values for + * templates. Locals definition is a hash of local scope property to its source: + * + * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is + * always a string since DOM attributes are strings. If no `attr` name is specified then the + * attribute name is assumed to be the same as the local name. + * Given `` and widget definition + * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect + * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the + * `localName` property on the widget scope. The `name` is read from the parent scope (not + * component scope). + * + * * `=` or `=attr` - set up bi-directional binding between a local scope property and the + * parent scope property of name defined via the value of the `attr` attribute. If no `attr` + * name is specified then the attribute name is assumed to be the same as the local name. + * Given `` and widget definition of + * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the + * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected + * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent + * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You + * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If + * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use + * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional). + * + * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. + * If no `attr` name is specified then the attribute name is assumed to be the same as the + * local name. Given `` and widget definition of + * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to + * a function wrapper for the `count = count + value` expression. Often it's desirable to + * pass data from the isolated scope via an expression to the parent scope, this can be + * done by passing a map of local variable names and values into the expression wrapper fn. + * For example, if the expression is `increment(amount)` then we can specify the amount value + * by calling the `localFn` as `localFn({amount: 22})`. + * + * + * #### `bindToController` + * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will + * allow a component to have its properties bound to the controller, rather than to scope. When the controller + * is instantiated, the initial values of the isolate scope bindings are already available. + * + * #### `controller` + * Controller constructor function. The controller is instantiated before the + * pre-linking phase and it is shared with other directives (see + * `require` attribute). This allows the directives to communicate with each other and augment + * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals: + * + * * `$scope` - Current scope associated with the element + * * `$element` - Current element + * * `$attrs` - Current attributes object for the element + * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: + * `function([scope], cloneLinkingFn, futureParentElement)`. + * * `scope`: optional argument to override the scope. + * * `cloneLinkingFn`: optional argument to create clones of the original transcluded content. + * * `futureParentElement`: + * * defines the parent to which the `cloneLinkingFn` will add the cloned elements. + * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`. + * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements) + * and when the `cloneLinkinFn` is passed, + * as those elements need to created and cloned in a special way when they are defined outside their + * usual containers (e.g. like ``). + * * See also the `directive.templateNamespace` property. + * + * + * #### `require` + * Require another directive and inject its controller as the fourth argument to the linking function. The + * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the + * injected argument will be an array in corresponding order. If no such directive can be + * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with: + * + * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. + * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. + * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found. + * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found. + * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass + * `null` to the `link` fn if not found. + * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass + * `null` to the `link` fn if not found. + * + * + * #### `controllerAs` + * Controller alias at the directive scope. An alias for the controller so it + * can be referenced at the directive template. The directive needs to define a scope for this + * configuration to be used. Useful in the case when directive is used as component. + * + * + * #### `restrict` + * String of subset of `EACM` which restricts the directive to a specific directive + * declaration style. If omitted, the defaults (elements and attributes) are used. + * + * * `E` - Element name (default): `` + * * `A` - Attribute (default): `
    ` + * * `C` - Class: `
    ` + * * `M` - Comment: `` + * + * + * #### `templateNamespace` + * String representing the document type used by the markup in the template. + * AngularJS needs this information as those elements need to be created and cloned + * in a special way when they are defined outside their usual containers like `` and ``. + * + * * `html` - All root nodes in the template are HTML. Root nodes may also be + * top-level elements such as `` or ``. + * * `svg` - The root nodes in the template are SVG elements (excluding ``). + * * `math` - The root nodes in the template are MathML elements (excluding ``). + * + * If no `templateNamespace` is specified, then the namespace is considered to be `html`. + * + * #### `template` + * HTML markup that may: + * * Replace the contents of the directive's element (default). + * * Replace the directive's element itself (if `replace` is true - DEPRECATED). + * * Wrap the contents of the directive's element (if `transclude` is true). + * + * Value may be: + * + * * A string. For example `
    {{delete_str}}
    `. + * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile` + * function api below) and returns a string value. + * + * + * #### `templateUrl` + * This is similar to `template` but the template is loaded from the specified URL, asynchronously. + * + * Because template loading is asynchronous the compiler will suspend compilation of directives on that element + * for later when the template has been resolved. In the meantime it will continue to compile and link + * sibling and parent elements as though this element had not contained any directives. + * + * The compiler does not suspend the entire compilation to wait for templates to be loaded because this + * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the + * case when only one deeply nested directive has `templateUrl`. + * + * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache} + * + * You can specify `templateUrl` as a string representing the URL or as a function which takes two + * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns + * a string value representing the url. In either case, the template URL is passed through {@link + * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}. + * + * + * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0) + * specify what the template should replace. Defaults to `false`. + * + * * `true` - the template will replace the directive's element. + * * `false` - the template will replace the contents of the directive's element. + * + * The replacement process migrates all of the attributes / classes from the old element to the new + * one. See the {@link guide/directive#template-expanding-directive + * Directives Guide} for an example. + * + * There are very few scenarios where element replacement is required for the application function, + * the main one being reusable custom components that are used within SVG contexts + * (because SVG doesn't work with custom elements in the DOM tree). + * + * #### `transclude` + * Extract the contents of the element where the directive appears and make it available to the directive. + * The contents are compiled and provided to the directive as a **transclusion function**. See the + * {@link $compile#transclusion Transclusion} section below. + * + * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the + * directive's element or the entire element: + * + * * `true` - transclude the content (i.e. the child nodes) of the directive's element. + * * `'element'` - transclude the whole of the directive's element including any directives on this + * element that defined at a lower priority than this directive. When used, the `template` + * property is ignored. + * + * + * #### `compile` + * + * ```js + * function compile(tElement, tAttrs, transclude) { ... } + * ``` + * + * The compile function deals with transforming the template DOM. Since most directives do not do + * template transformation, it is not used often. The compile function takes the following arguments: + * + * * `tElement` - template element - The element where the directive has been declared. It is + * safe to do template transformation on the element and child elements only. + * + * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared + * between all directive compile functions. + * + * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)` + * + *
    + * **Note:** The template instance and the link instance may be different objects if the template has + * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that + * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration + * should be done in a linking function rather than in a compile function. + *
    + + *
    + * **Note:** The compile function cannot handle directives that recursively use themselves in their + * own templates or compile functions. Compiling these directives results in an infinite loop and a + * stack overflow errors. + * + * This can be avoided by manually using $compile in the postLink function to imperatively compile + * a directive's template instead of relying on automatic template compilation via `template` or + * `templateUrl` declaration or manual compilation inside the compile function. + *
    + * + *
    + * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it + * e.g. does not know about the right outer scope. Please use the transclude function that is passed + * to the link function instead. + *
    + + * A compile function can have a return value which can be either a function or an object. + * + * * returning a (post-link) function - is equivalent to registering the linking function via the + * `link` property of the config object when the compile function is empty. + * + * * returning an object with function(s) registered via `pre` and `post` properties - allows you to + * control when a linking function should be called during the linking phase. See info about + * pre-linking and post-linking functions below. + * + * + * #### `link` + * This property is used only if the `compile` property is not defined. + * + * ```js + * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... } + * ``` + * + * The link function is responsible for registering DOM listeners as well as updating the DOM. It is + * executed after the template has been cloned. This is where most of the directive logic will be + * put. + * + * * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the + * directive for registering {@link ng.$rootScope.Scope#$watch watches}. + * + * * `iElement` - instance element - The element where the directive is to be used. It is safe to + * manipulate the children of the element only in `postLink` function since the children have + * already been linked. + * + * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared + * between all directive linking functions. + * + * * `controller` - a controller instance - A controller instance if at least one directive on the + * element defines a controller. The controller is shared among all the directives, which allows + * the directives to use the controllers as a communication channel. + * + * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope. + * This is the same as the `$transclude` + * parameter of directive controllers, see there for details. + * `function([scope], cloneLinkingFn, futureParentElement)`. + * + * #### Pre-linking function + * + * Executed before the child elements are linked. Not safe to do DOM transformation since the + * compiler linking function will fail to locate the correct elements for linking. + * + * #### Post-linking function + * + * Executed after the child elements are linked. + * + * Note that child elements that contain `templateUrl` directives will not have been compiled + * and linked since they are waiting for their template to load asynchronously and their own + * compilation and linking has been suspended until that occurs. + * + * It is safe to do DOM transformation in the post-linking function on elements that are not waiting + * for their async templates to be resolved. + * + * + * ### Transclusion + * + * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and + * copying them to another part of the DOM, while maintaining their connection to the original AngularJS + * scope from where they were taken. + * + * Transclusion is used (often with {@link ngTransclude}) to insert the + * original contents of a directive's element into a specified place in the template of the directive. + * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded + * content has access to the properties on the scope from which it was taken, even if the directive + * has isolated scope. + * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}. + * + * This makes it possible for the widget to have private state for its template, while the transcluded + * content has access to its originating scope. + * + *
    + * **Note:** When testing an element transclude directive you must not place the directive at the root of the + * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives + * Testing Transclusion Directives}. + *
    + * + * #### Transclusion Functions + * + * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion + * function** to the directive's `link` function and `controller`. This transclusion function is a special + * **linking function** that will return the compiled contents linked to a new transclusion scope. + * + *
    + * If you are just using {@link ngTransclude} then you don't need to worry about this function, since + * ngTransclude will deal with it for us. + *
    + * + * If you want to manually control the insertion and removal of the transcluded content in your directive + * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery + * object that contains the compiled DOM, which is linked to the correct transclusion scope. + * + * When you call a transclusion function you can pass in a **clone attach function**. This function accepts + * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded + * content and the `scope` is the newly created transclusion scope, to which the clone is bound. + * + *
    + * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function + * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope. + *
    + * + * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone + * attach function**: + * + * ```js + * var transcludedContent, transclusionScope; + * + * $transclude(function(clone, scope) { + * element.append(clone); + * transcludedContent = clone; + * transclusionScope = scope; + * }); + * ``` + * + * Later, if you want to remove the transcluded content from your DOM then you should also destroy the + * associated transclusion scope: + * + * ```js + * transcludedContent.remove(); + * transclusionScope.$destroy(); + * ``` + * + *
    + * **Best Practice**: if you intend to add and remove transcluded content manually in your directive + * (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it), + * then you are also responsible for calling `$destroy` on the transclusion scope. + *
    + * + * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat} + * automatically destroy their transluded clones as necessary so you do not need to worry about this if + * you are simply using {@link ngTransclude} to inject the transclusion into your directive. + * + * + * #### Transclusion Scopes + * + * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion + * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed + * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it + * was taken. + * + * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look + * like this: + * + * ```html + *
    + *
    + *
    + *
    + *
    + *
    + * ``` + * + * The `$parent` scope hierarchy will look like this: + * + * ``` + * - $rootScope + * - isolate + * - transclusion + * ``` + * + * but the scopes will inherit prototypically from different scopes to their `$parent`. + * + * ``` + * - $rootScope + * - transclusion + * - isolate + * ``` + * + * + * ### Attributes + * + * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the + * `link()` or `compile()` functions. It has a variety of uses. + * + * accessing *Normalized attribute names:* + * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. + * the attributes object allows for normalized access to + * the attributes. + * + * * *Directive inter-communication:* All directives share the same instance of the attributes + * object which allows the directives to use the attributes object as inter directive + * communication. + * + * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object + * allowing other directives to read the interpolated value. + * + * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes + * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also + * the only way to easily get the actual value because during the linking phase the interpolation + * hasn't been evaluated yet and so the value is at this time set to `undefined`. + * + * ```js + * function linkingFn(scope, elm, attrs, ctrl) { + * // get the attribute value + * console.log(attrs.ngModel); + * + * // change the attribute + * attrs.$set('ngModel', 'new value'); + * + * // observe changes to interpolated attribute + * attrs.$observe('ngModel', function(value) { + * console.log('ngModel has changed value to ' + value); + * }); + * } + * ``` + * + * ## Example + * + *
    + * **Note**: Typically directives are registered with `module.directive`. The example below is + * to illustrate how `$compile` works. + *
    + * + + + +
    +
    +
    +
    +
    +
    + + it('should auto compile', function() { + var textarea = $('textarea'); + var output = $('div[compile]'); + // The initial state reads 'Hello Angular'. + expect(output.getText()).toBe('Hello Angular'); + textarea.clear(); + textarea.sendKeys('{{name}}!'); + expect(output.getText()).toBe('Angular!'); + }); + +
    + + * + * + * @param {string|DOMElement} element Element or HTML string to compile into a template function. + * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED. + * + *
    + * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it + * e.g. will not use the right outer scope. Please pass the transclude function as a + * `parentBoundTranscludeFn` to the link function instead. + *
    + * + * @param {number} maxPriority only apply directives lower than given priority (Only effects the + * root element(s), not their children) + * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template + * (a DOM element/tree) to a scope. Where: + * + * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to. + * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the + * `template` and call the `cloneAttachFn` function allowing the caller to attach the + * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is + * called as:
    `cloneAttachFn(clonedElement, scope)` where: + * + * * `clonedElement` - is a clone of the original `element` passed into the compiler. + * * `scope` - is the current scope with which the linking function is working with. + * + * * `options` - An optional object hash with linking options. If `options` is provided, then the following + * keys may be used to control linking behavior: + * + * * `parentBoundTranscludeFn` - the transclude function made available to + * directives; if given, it will be passed through to the link functions of + * directives found in `element` during compilation. + * * `transcludeControllers` - an object hash with keys that map controller names + * to controller instances; if given, it will make the controllers + * available to directives. + * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add + * the cloned elements; only needed for transcludes that are allowed to contain non html + * elements (e.g. SVG elements). See also the directive.controller property. + * + * Calling the linking function returns the element of the template. It is either the original + * element passed in, or the clone of the element if the `cloneAttachFn` is provided. + * + * After linking the view is not updated until after a call to $digest which typically is done by + * Angular automatically. + * + * If you need access to the bound view, there are two ways to do it: + * + * - If you are not asking the linking function to clone the template, create the DOM element(s) + * before you send them to the compiler and keep this reference around. + * ```js + * var element = $compile('

    {{total}}

    ')(scope); + * ``` + * + * - if on the other hand, you need the element to be cloned, the view reference from the original + * example would not point to the clone, but rather to the original template that was cloned. In + * this case, you can access the clone via the cloneAttachFn: + * ```js + * var templateElement = angular.element('

    {{total}}

    '), + * scope = ....; + * + * var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) { + * //attach the clone to DOM document at the right place + * }); + * + * //now we have reference to the cloned DOM via `clonedElement` + * ``` + * + * + * For information on how the compiler works, see the + * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide. + */ + +var $compileMinErr = minErr('$compile'); + +/** + * @ngdoc provider + * @name $compileProvider + * + * @description + */ +$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider']; +function $CompileProvider($provide, $$sanitizeUriProvider) { + var hasDirectives = {}, + Suffix = 'Directive', + COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/, + CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/, + ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'), + REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/; + + // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes + // The assumption is that future DOM event attribute names will begin with + // 'on' and be composed of only English letters. + var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; + + function parseIsolateBindings(scope, directiveName) { + var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/; + + var bindings = {}; + + forEach(scope, function(definition, scopeName) { + var match = definition.match(LOCAL_REGEXP); + + if (!match) { + throw $compileMinErr('iscp', + "Invalid isolate scope definition for directive '{0}'." + + " Definition: {... {1}: '{2}' ...}", + directiveName, scopeName, definition); + } + + bindings[scopeName] = { + mode: match[1][0], + collection: match[2] === '*', + optional: match[3] === '?', + attrName: match[4] || scopeName + }; + }); + + return bindings; + } + + /** + * @ngdoc method + * @name $compileProvider#directive + * @kind function + * + * @description + * Register a new directive with the compiler. + * + * @param {string|Object} name Name of the directive in camel-case (i.e. ngBind which + * will match as ng-bind), or an object map of directives where the keys are the + * names and the values are the factories. + * @param {Function|Array} directiveFactory An injectable directive factory function. See + * {@link guide/directive} for more info. + * @returns {ng.$compileProvider} Self for chaining. + */ + this.directive = function registerDirective(name, directiveFactory) { + assertNotHasOwnProperty(name, 'directive'); + if (isString(name)) { + assertArg(directiveFactory, 'directiveFactory'); + if (!hasDirectives.hasOwnProperty(name)) { + hasDirectives[name] = []; + $provide.factory(name + Suffix, ['$injector', '$exceptionHandler', + function($injector, $exceptionHandler) { + var directives = []; + forEach(hasDirectives[name], function(directiveFactory, index) { + try { + var directive = $injector.invoke(directiveFactory); + if (isFunction(directive)) { + directive = { compile: valueFn(directive) }; + } else if (!directive.compile && directive.link) { + directive.compile = valueFn(directive.link); + } + directive.priority = directive.priority || 0; + directive.index = index; + directive.name = directive.name || name; + directive.require = directive.require || (directive.controller && directive.name); + directive.restrict = directive.restrict || 'EA'; + if (isObject(directive.scope)) { + directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name); + } + directives.push(directive); + } catch (e) { + $exceptionHandler(e); + } + }); + return directives; + }]); + } + hasDirectives[name].push(directiveFactory); + } else { + forEach(name, reverseParams(registerDirective)); + } + return this; + }; + + + /** + * @ngdoc method + * @name $compileProvider#aHrefSanitizationWhitelist + * @kind function + * + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during a[href] sanitization. + * + * The sanitization is a security measure aimed at preventing XSS attacks via html links. + * + * Any url about to be assigned to a[href] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.aHrefSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp); + return this; + } else { + return $$sanitizeUriProvider.aHrefSanitizationWhitelist(); + } + }; + + + /** + * @ngdoc method + * @name $compileProvider#imgSrcSanitizationWhitelist + * @kind function + * + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during img[src] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to img[src] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.imgSrcSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp); + return this; + } else { + return $$sanitizeUriProvider.imgSrcSanitizationWhitelist(); + } + }; + + /** + * @ngdoc method + * @name $compileProvider#debugInfoEnabled + * + * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the + * current debugInfoEnabled state + * @returns {*} current value if used as getter or itself (chaining) if used as setter + * + * @kind function + * + * @description + * Call this method to enable/disable various debug runtime information in the compiler such as adding + * binding information and a reference to the current scope on to DOM elements. + * If enabled, the compiler will add the following to DOM elements that have been bound to the scope + * * `ng-binding` CSS class + * * `$binding` data property containing an array of the binding expressions + * + * You may want to disable this in production for a significant performance boost. See + * {@link guide/production#disabling-debug-data Disabling Debug Data} for more. + * + * The default value is true. + */ + var debugInfoEnabled = true; + this.debugInfoEnabled = function(enabled) { + if (isDefined(enabled)) { + debugInfoEnabled = enabled; + return this; + } + return debugInfoEnabled; + }; + + this.$get = [ + '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse', + '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri', + function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse, + $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) { + + var Attributes = function(element, attributesToCopy) { + if (attributesToCopy) { + var keys = Object.keys(attributesToCopy); + var i, l, key; + + for (i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + this[key] = attributesToCopy[key]; + } + } else { + this.$attr = {}; + } + + this.$$element = element; + }; + + Attributes.prototype = { + /** + * @ngdoc method + * @name $compile.directive.Attributes#$normalize + * @kind function + * + * @description + * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or + * `data-`) to its normalized, camelCase form. + * + * Also there is special case for Moz prefix starting with upper case letter. + * + * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives} + * + * @param {string} name Name to normalize + */ + $normalize: directiveNormalize, + + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$addClass + * @kind function + * + * @description + * Adds the CSS class value specified by the classVal parameter to the element. If animations + * are enabled then an animation will be triggered for the class addition. + * + * @param {string} classVal The className value that will be added to the element + */ + $addClass: function(classVal) { + if (classVal && classVal.length > 0) { + $animate.addClass(this.$$element, classVal); + } + }, + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$removeClass + * @kind function + * + * @description + * Removes the CSS class value specified by the classVal parameter from the element. If + * animations are enabled then an animation will be triggered for the class removal. + * + * @param {string} classVal The className value that will be removed from the element + */ + $removeClass: function(classVal) { + if (classVal && classVal.length > 0) { + $animate.removeClass(this.$$element, classVal); + } + }, + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$updateClass + * @kind function + * + * @description + * Adds and removes the appropriate CSS class values to the element based on the difference + * between the new and old CSS class values (specified as newClasses and oldClasses). + * + * @param {string} newClasses The current CSS className value + * @param {string} oldClasses The former CSS className value + */ + $updateClass: function(newClasses, oldClasses) { + var toAdd = tokenDifference(newClasses, oldClasses); + if (toAdd && toAdd.length) { + $animate.addClass(this.$$element, toAdd); + } + + var toRemove = tokenDifference(oldClasses, newClasses); + if (toRemove && toRemove.length) { + $animate.removeClass(this.$$element, toRemove); + } + }, + + /** + * Set a normalized attribute on the element in a way such that all directives + * can share the attribute. This function properly handles boolean attributes. + * @param {string} key Normalized key. (ie ngAttribute) + * @param {string|boolean} value The value to set. If `null` attribute will be deleted. + * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute. + * Defaults to true. + * @param {string=} attrName Optional none normalized name. Defaults to key. + */ + $set: function(key, value, writeAttr, attrName) { + // TODO: decide whether or not to throw an error if "class" + //is set through this function since it may cause $updateClass to + //become unstable. + + var node = this.$$element[0], + booleanKey = getBooleanAttrName(node, key), + aliasedKey = getAliasedAttrName(node, key), + observer = key, + nodeName; + + if (booleanKey) { + this.$$element.prop(key, value); + attrName = booleanKey; + } else if (aliasedKey) { + this[aliasedKey] = value; + observer = aliasedKey; + } + + this[key] = value; + + // translate normalized key to actual key + if (attrName) { + this.$attr[key] = attrName; + } else { + attrName = this.$attr[key]; + if (!attrName) { + this.$attr[key] = attrName = snake_case(key, '-'); + } + } + + nodeName = nodeName_(this.$$element); + + if ((nodeName === 'a' && key === 'href') || + (nodeName === 'img' && key === 'src')) { + // sanitize a[href] and img[src] values + this[key] = value = $$sanitizeUri(value, key === 'src'); + } else if (nodeName === 'img' && key === 'srcset') { + // sanitize img[srcset] values + var result = ""; + + // first check if there are spaces because it's not the same pattern + var trimmedSrcset = trim(value); + // ( 999x ,| 999w ,| ,|, ) + var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/; + var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/; + + // split srcset into tuple of uri and descriptor except for the last item + var rawUris = trimmedSrcset.split(pattern); + + // for each tuples + var nbrUrisWith2parts = Math.floor(rawUris.length / 2); + for (var i = 0; i < nbrUrisWith2parts; i++) { + var innerIdx = i * 2; + // sanitize the uri + result += $$sanitizeUri(trim(rawUris[innerIdx]), true); + // add the descriptor + result += (" " + trim(rawUris[innerIdx + 1])); + } + + // split the last item into uri and descriptor + var lastTuple = trim(rawUris[i * 2]).split(/\s/); + + // sanitize the last uri + result += $$sanitizeUri(trim(lastTuple[0]), true); + + // and add the last descriptor if any + if (lastTuple.length === 2) { + result += (" " + trim(lastTuple[1])); + } + this[key] = value = result; + } + + if (writeAttr !== false) { + if (value === null || value === undefined) { + this.$$element.removeAttr(attrName); + } else { + this.$$element.attr(attrName, value); + } + } + + // fire observers + var $$observers = this.$$observers; + $$observers && forEach($$observers[observer], function(fn) { + try { + fn(value); + } catch (e) { + $exceptionHandler(e); + } + }); + }, + + + /** + * @ngdoc method + * @name $compile.directive.Attributes#$observe + * @kind function + * + * @description + * Observes an interpolated attribute. + * + * The observer function will be invoked once during the next `$digest` following + * compilation. The observer is then invoked whenever the interpolated value + * changes. + * + * @param {string} key Normalized key. (ie ngAttribute) . + * @param {function(interpolatedValue)} fn Function that will be called whenever + the interpolated value of the attribute changes. + * See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info. + * @returns {function()} Returns a deregistration function for this observer. + */ + $observe: function(key, fn) { + var attrs = this, + $$observers = (attrs.$$observers || (attrs.$$observers = createMap())), + listeners = ($$observers[key] || ($$observers[key] = [])); + + listeners.push(fn); + $rootScope.$evalAsync(function() { + if (!listeners.$$inter && attrs.hasOwnProperty(key)) { + // no one registered attribute interpolation function, so lets call it manually + fn(attrs[key]); + } + }); + + return function() { + arrayRemove(listeners, fn); + }; + } + }; + + + function safeAddClass($element, className) { + try { + $element.addClass(className); + } catch (e) { + // ignore, since it means that we are trying to set class on + // SVG element, where class name is read-only. + } + } + + + var startSymbol = $interpolate.startSymbol(), + endSymbol = $interpolate.endSymbol(), + denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}') + ? identity + : function denormalizeTemplate(template) { + return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol); + }, + NG_ATTR_BINDING = /^ngAttr[A-Z]/; + + compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) { + var bindings = $element.data('$binding') || []; + + if (isArray(binding)) { + bindings = bindings.concat(binding); + } else { + bindings.push(binding); + } + + $element.data('$binding', bindings); + } : noop; + + compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) { + safeAddClass($element, 'ng-binding'); + } : noop; + + compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) { + var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope'; + $element.data(dataName, scope); + } : noop; + + compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) { + safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope'); + } : noop; + + return compile; + + //================================ + + function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, + previousCompileContext) { + if (!($compileNodes instanceof jqLite)) { + // jquery always rewraps, whereas we need to preserve the original selector so that we can + // modify it. + $compileNodes = jqLite($compileNodes); + } + // We can not compile top level text elements since text nodes can be merged and we will + // not be able to attach scope data to them, so we will wrap them in + forEach($compileNodes, function(node, index) { + if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) { + $compileNodes[index] = jqLite(node).wrap('').parent()[0]; + } + }); + var compositeLinkFn = + compileNodes($compileNodes, transcludeFn, $compileNodes, + maxPriority, ignoreDirective, previousCompileContext); + compile.$$addScopeClass($compileNodes); + var namespace = null; + return function publicLinkFn(scope, cloneConnectFn, options) { + assertArg(scope, 'scope'); + + options = options || {}; + var parentBoundTranscludeFn = options.parentBoundTranscludeFn, + transcludeControllers = options.transcludeControllers, + futureParentElement = options.futureParentElement; + + // When `parentBoundTranscludeFn` is passed, it is a + // `controllersBoundTransclude` function (it was previously passed + // as `transclude` to directive.link) so we must unwrap it to get + // its `boundTranscludeFn` + if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) { + parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude; + } + + if (!namespace) { + namespace = detectNamespaceForChildElements(futureParentElement); + } + var $linkNode; + if (namespace !== 'html') { + // When using a directive with replace:true and templateUrl the $compileNodes + // (or a child element inside of them) + // might change, so we need to recreate the namespace adapted compileNodes + // for call to the link function. + // Note: This will already clone the nodes... + $linkNode = jqLite( + wrapTemplate(namespace, jqLite('
    ').append($compileNodes).html()) + ); + } else if (cloneConnectFn) { + // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart + // and sometimes changes the structure of the DOM. + $linkNode = JQLitePrototype.clone.call($compileNodes); + } else { + $linkNode = $compileNodes; + } + + if (transcludeControllers) { + for (var controllerName in transcludeControllers) { + $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance); + } + } + + compile.$$addScopeInfo($linkNode, scope); + + if (cloneConnectFn) cloneConnectFn($linkNode, scope); + if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn); + return $linkNode; + }; + } + + function detectNamespaceForChildElements(parentElement) { + // TODO: Make this detect MathML as well... + var node = parentElement && parentElement[0]; + if (!node) { + return 'html'; + } else { + return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html'; + } + } + + /** + * Compile function matches each node in nodeList against the directives. Once all directives + * for a particular node are collected their compile functions are executed. The compile + * functions return values - the linking functions - are combined into a composite linking + * function, which is the a linking function for the node. + * + * @param {NodeList} nodeList an array of nodes or NodeList to compile + * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the + * scope argument is auto-generated to the new child of the transcluded parent scope. + * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then + * the rootElement must be set the jqLite collection of the compile root. This is + * needed so that the jqLite collection items can be replaced with widgets. + * @param {number=} maxPriority Max directive priority. + * @returns {Function} A composite linking function of all of the matched directives or null. + */ + function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, + previousCompileContext) { + var linkFns = [], + attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound; + + for (var i = 0; i < nodeList.length; i++) { + attrs = new Attributes(); + + // we must always refer to nodeList[i] since the nodes can be replaced underneath us. + directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined, + ignoreDirective); + + nodeLinkFn = (directives.length) + ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement, + null, [], [], previousCompileContext) + : null; + + if (nodeLinkFn && nodeLinkFn.scope) { + compile.$$addScopeClass(attrs.$$element); + } + + childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || + !(childNodes = nodeList[i].childNodes) || + !childNodes.length) + ? null + : compileNodes(childNodes, + nodeLinkFn ? ( + (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement) + && nodeLinkFn.transclude) : transcludeFn); + + if (nodeLinkFn || childLinkFn) { + linkFns.push(i, nodeLinkFn, childLinkFn); + linkFnFound = true; + nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn; + } + + //use the previous context only for the first element in the virtual group + previousCompileContext = null; + } + + // return a linking function if we have found anything, null otherwise + return linkFnFound ? compositeLinkFn : null; + + function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) { + var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn; + var stableNodeList; + + + if (nodeLinkFnFound) { + // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our + // offsets don't get screwed up + var nodeListLength = nodeList.length; + stableNodeList = new Array(nodeListLength); + + // create a sparse array by only copying the elements which have a linkFn + for (i = 0; i < linkFns.length; i+=3) { + idx = linkFns[i]; + stableNodeList[idx] = nodeList[idx]; + } + } else { + stableNodeList = nodeList; + } + + for (i = 0, ii = linkFns.length; i < ii;) { + node = stableNodeList[linkFns[i++]]; + nodeLinkFn = linkFns[i++]; + childLinkFn = linkFns[i++]; + + if (nodeLinkFn) { + if (nodeLinkFn.scope) { + childScope = scope.$new(); + compile.$$addScopeInfo(jqLite(node), childScope); + } else { + childScope = scope; + } + + if (nodeLinkFn.transcludeOnThisElement) { + childBoundTranscludeFn = createBoundTranscludeFn( + scope, nodeLinkFn.transclude, parentBoundTranscludeFn, + nodeLinkFn.elementTranscludeOnThisElement); + + } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) { + childBoundTranscludeFn = parentBoundTranscludeFn; + + } else if (!parentBoundTranscludeFn && transcludeFn) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn); + + } else { + childBoundTranscludeFn = null; + } + + nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn); + + } else if (childLinkFn) { + childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn); + } + } + } + } + + function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) { + + var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) { + + if (!transcludedScope) { + transcludedScope = scope.$new(false, containingScope); + transcludedScope.$$transcluded = true; + } + + return transcludeFn(transcludedScope, cloneFn, { + parentBoundTranscludeFn: previousBoundTranscludeFn, + transcludeControllers: controllers, + futureParentElement: futureParentElement + }); + }; + + return boundTranscludeFn; + } + + /** + * Looks for directives on the given node and adds them to the directive collection which is + * sorted. + * + * @param node Node to search. + * @param directives An array to which the directives are added to. This array is sorted before + * the function returns. + * @param attrs The shared attrs object which is used to populate the normalized attributes. + * @param {number=} maxPriority Max directive priority. + */ + function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) { + var nodeType = node.nodeType, + attrsMap = attrs.$attr, + match, + className; + + switch (nodeType) { + case NODE_TYPE_ELEMENT: /* Element */ + // use the node name: + addDirective(directives, + directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective); + + // iterate over the attributes + for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes, + j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) { + var attrStartName = false; + var attrEndName = false; + + attr = nAttrs[j]; + name = attr.name; + value = trim(attr.value); + + // support ngAttr attribute binding + ngAttrName = directiveNormalize(name); + if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) { + name = name.replace(PREFIX_REGEXP, '') + .substr(8).replace(/_(.)/g, function(match, letter) { + return letter.toUpperCase(); + }); + } + + var directiveNName = ngAttrName.replace(/(Start|End)$/, ''); + if (directiveIsMultiElement(directiveNName)) { + if (ngAttrName === directiveNName + 'Start') { + attrStartName = name; + attrEndName = name.substr(0, name.length - 5) + 'end'; + name = name.substr(0, name.length - 6); + } + } + + nName = directiveNormalize(name.toLowerCase()); + attrsMap[nName] = name; + if (isNgAttr || !attrs.hasOwnProperty(nName)) { + attrs[nName] = value; + if (getBooleanAttrName(node, nName)) { + attrs[nName] = true; // presence means true + } + } + addAttrInterpolateDirective(node, directives, value, nName, isNgAttr); + addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, + attrEndName); + } + + // use class as directive + className = node.className; + if (isObject(className)) { + // Maybe SVGAnimatedString + className = className.animVal; + } + if (isString(className) && className !== '') { + while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) { + nName = directiveNormalize(match[2]); + if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) { + attrs[nName] = trim(match[3]); + } + className = className.substr(match.index + match[0].length); + } + } + break; + case NODE_TYPE_TEXT: /* Text Node */ + addTextInterpolateDirective(directives, node.nodeValue); + break; + case NODE_TYPE_COMMENT: /* Comment */ + try { + match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue); + if (match) { + nName = directiveNormalize(match[1]); + if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) { + attrs[nName] = trim(match[2]); + } + } + } catch (e) { + // turns out that under some circumstances IE9 throws errors when one attempts to read + // comment's node value. + // Just ignore it and continue. (Can't seem to reproduce in test case.) + } + break; + } + + directives.sort(byPriority); + return directives; + } + + /** + * Given a node with an directive-start it collects all of the siblings until it finds + * directive-end. + * @param node + * @param attrStart + * @param attrEnd + * @returns {*} + */ + function groupScan(node, attrStart, attrEnd) { + var nodes = []; + var depth = 0; + if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) { + do { + if (!node) { + throw $compileMinErr('uterdir', + "Unterminated attribute, found '{0}' but no matching '{1}' found.", + attrStart, attrEnd); + } + if (node.nodeType == NODE_TYPE_ELEMENT) { + if (node.hasAttribute(attrStart)) depth++; + if (node.hasAttribute(attrEnd)) depth--; + } + nodes.push(node); + node = node.nextSibling; + } while (depth > 0); + } else { + nodes.push(node); + } + + return jqLite(nodes); + } + + /** + * Wrapper for linking function which converts normal linking function into a grouped + * linking function. + * @param linkFn + * @param attrStart + * @param attrEnd + * @returns {Function} + */ + function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) { + return function(scope, element, attrs, controllers, transcludeFn) { + element = groupScan(element[0], attrStart, attrEnd); + return linkFn(scope, element, attrs, controllers, transcludeFn); + }; + } + + /** + * Once the directives have been collected, their compile functions are executed. This method + * is responsible for inlining directive templates as well as terminating the application + * of the directives if the terminal directive has been reached. + * + * @param {Array} directives Array of collected directives to execute their compile function. + * this needs to be pre-sorted by priority order. + * @param {Node} compileNode The raw DOM node to apply the compile functions to + * @param {Object} templateAttrs The shared attribute function + * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the + * scope argument is auto-generated to the new + * child of the transcluded parent scope. + * @param {JQLite} jqCollection If we are working on the root of the compile tree then this + * argument has the root jqLite array so that we can replace nodes + * on it. + * @param {Object=} originalReplaceDirective An optional directive that will be ignored when + * compiling the transclusion. + * @param {Array.} preLinkFns + * @param {Array.} postLinkFns + * @param {Object} previousCompileContext Context used for previous compilation of the current + * node + * @returns {Function} linkFn + */ + function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, + jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, + previousCompileContext) { + previousCompileContext = previousCompileContext || {}; + + var terminalPriority = -Number.MAX_VALUE, + newScopeDirective, + controllerDirectives = previousCompileContext.controllerDirectives, + controllers, + newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, + templateDirective = previousCompileContext.templateDirective, + nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, + hasTranscludeDirective = false, + hasTemplate = false, + hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective, + $compileNode = templateAttrs.$$element = jqLite(compileNode), + directive, + directiveName, + $template, + replaceDirective = originalReplaceDirective, + childTranscludeFn = transcludeFn, + linkFn, + directiveValue; + + // executes all directives on the current element + for (var i = 0, ii = directives.length; i < ii; i++) { + directive = directives[i]; + var attrStart = directive.$$start; + var attrEnd = directive.$$end; + + // collect multiblock sections + if (attrStart) { + $compileNode = groupScan(compileNode, attrStart, attrEnd); + } + $template = undefined; + + if (terminalPriority > directive.priority) { + break; // prevent further processing of directives + } + + if (directiveValue = directive.scope) { + + // skip the check for directives with async templates, we'll check the derived sync + // directive when the template arrives + if (!directive.templateUrl) { + if (isObject(directiveValue)) { + // This directive is trying to add an isolated scope. + // Check that there is no scope of any kind already + assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective, + directive, $compileNode); + newIsolateScopeDirective = directive; + } else { + // This directive is trying to add a child scope. + // Check that there is no isolated scope already + assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive, + $compileNode); + } + } + + newScopeDirective = newScopeDirective || directive; + } + + directiveName = directive.name; + + if (!directive.templateUrl && directive.controller) { + directiveValue = directive.controller; + controllerDirectives = controllerDirectives || {}; + assertNoDuplicate("'" + directiveName + "' controller", + controllerDirectives[directiveName], directive, $compileNode); + controllerDirectives[directiveName] = directive; + } + + if (directiveValue = directive.transclude) { + hasTranscludeDirective = true; + + // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion. + // This option should only be used by directives that know how to safely handle element transclusion, + // where the transcluded nodes are added or replaced after linking. + if (!directive.$$tlb) { + assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode); + nonTlbTranscludeDirective = directive; + } + + if (directiveValue == 'element') { + hasElementTranscludeDirective = true; + terminalPriority = directive.priority; + $template = $compileNode; + $compileNode = templateAttrs.$$element = + jqLite(document.createComment(' ' + directiveName + ': ' + + templateAttrs[directiveName] + ' ')); + compileNode = $compileNode[0]; + replaceWith(jqCollection, sliceArgs($template), compileNode); + + childTranscludeFn = compile($template, transcludeFn, terminalPriority, + replaceDirective && replaceDirective.name, { + // Don't pass in: + // - controllerDirectives - otherwise we'll create duplicates controllers + // - newIsolateScopeDirective or templateDirective - combining templates with + // element transclusion doesn't make sense. + // + // We need only nonTlbTranscludeDirective so that we prevent putting transclusion + // on the same element more than once. + nonTlbTranscludeDirective: nonTlbTranscludeDirective + }); + } else { + $template = jqLite(jqLiteClone(compileNode)).contents(); + $compileNode.empty(); // clear contents + childTranscludeFn = compile($template, transcludeFn); + } + } + + if (directive.template) { + hasTemplate = true; + assertNoDuplicate('template', templateDirective, directive, $compileNode); + templateDirective = directive; + + directiveValue = (isFunction(directive.template)) + ? directive.template($compileNode, templateAttrs) + : directive.template; + + directiveValue = denormalizeTemplate(directiveValue); + + if (directive.replace) { + replaceDirective = directive; + if (jqLiteIsTextNode(directiveValue)) { + $template = []; + } else { + $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue))); + } + compileNode = $template[0]; + + if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { + throw $compileMinErr('tplrt', + "Template for directive '{0}' must have exactly one root element. {1}", + directiveName, ''); + } + + replaceWith(jqCollection, $compileNode, compileNode); + + var newTemplateAttrs = {$attr: {}}; + + // combine directives from the original node and from the template: + // - take the array of directives for this element + // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed) + // - collect directives from the template and sort them by priority + // - combine directives as: processed + template + unprocessed + var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs); + var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1)); + + if (newIsolateScopeDirective) { + markDirectivesAsIsolate(templateDirectives); + } + directives = directives.concat(templateDirectives).concat(unprocessedDirectives); + mergeTemplateAttributes(templateAttrs, newTemplateAttrs); + + ii = directives.length; + } else { + $compileNode.html(directiveValue); + } + } + + if (directive.templateUrl) { + hasTemplate = true; + assertNoDuplicate('template', templateDirective, directive, $compileNode); + templateDirective = directive; + + if (directive.replace) { + replaceDirective = directive; + } + + nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode, + templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, { + controllerDirectives: controllerDirectives, + newIsolateScopeDirective: newIsolateScopeDirective, + templateDirective: templateDirective, + nonTlbTranscludeDirective: nonTlbTranscludeDirective + }); + ii = directives.length; + } else if (directive.compile) { + try { + linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn); + if (isFunction(linkFn)) { + addLinkFns(null, linkFn, attrStart, attrEnd); + } else if (linkFn) { + addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd); + } + } catch (e) { + $exceptionHandler(e, startingTag($compileNode)); + } + } + + if (directive.terminal) { + nodeLinkFn.terminal = true; + terminalPriority = Math.max(terminalPriority, directive.priority); + } + + } + + nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true; + nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective; + nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective; + nodeLinkFn.templateOnThisElement = hasTemplate; + nodeLinkFn.transclude = childTranscludeFn; + + previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective; + + // might be normal or delayed nodeLinkFn depending on if templateUrl is present + return nodeLinkFn; + + //////////////////// + + function addLinkFns(pre, post, attrStart, attrEnd) { + if (pre) { + if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd); + pre.require = directive.require; + pre.directiveName = directiveName; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + pre = cloneAndAnnotateFn(pre, {isolateScope: true}); + } + preLinkFns.push(pre); + } + if (post) { + if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd); + post.require = directive.require; + post.directiveName = directiveName; + if (newIsolateScopeDirective === directive || directive.$$isolateScope) { + post = cloneAndAnnotateFn(post, {isolateScope: true}); + } + postLinkFns.push(post); + } + } + + + function getControllers(directiveName, require, $element, elementControllers) { + var value, retrievalMethod = 'data', optional = false; + var $searchElement = $element; + var match; + if (isString(require)) { + match = require.match(REQUIRE_PREFIX_REGEXP); + require = require.substring(match[0].length); + + if (match[3]) { + if (match[1]) match[3] = null; + else match[1] = match[3]; + } + if (match[1] === '^') { + retrievalMethod = 'inheritedData'; + } else if (match[1] === '^^') { + retrievalMethod = 'inheritedData'; + $searchElement = $element.parent(); + } + if (match[2] === '?') { + optional = true; + } + + value = null; + + if (elementControllers && retrievalMethod === 'data') { + if (value = elementControllers[require]) { + value = value.instance; + } + } + value = value || $searchElement[retrievalMethod]('$' + require + 'Controller'); + + if (!value && !optional) { + throw $compileMinErr('ctreq', + "Controller '{0}', required by directive '{1}', can't be found!", + require, directiveName); + } + return value || null; + } else if (isArray(require)) { + value = []; + forEach(require, function(require) { + value.push(getControllers(directiveName, require, $element, elementControllers)); + }); + } + return value; + } + + + function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { + var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element, + attrs; + + if (compileNode === linkNode) { + attrs = templateAttrs; + $element = templateAttrs.$$element; + } else { + $element = jqLite(linkNode); + attrs = new Attributes($element, templateAttrs); + } + + if (newIsolateScopeDirective) { + isolateScope = scope.$new(true); + } + + if (boundTranscludeFn) { + // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn` + // is later passed as `parentBoundTranscludeFn` to `publicLinkFn` + transcludeFn = controllersBoundTransclude; + transcludeFn.$$boundTransclude = boundTranscludeFn; + } + + if (controllerDirectives) { + // TODO: merge `controllers` and `elementControllers` into single object. + controllers = {}; + elementControllers = {}; + forEach(controllerDirectives, function(directive) { + var locals = { + $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope, + $element: $element, + $attrs: attrs, + $transclude: transcludeFn + }, controllerInstance; + + controller = directive.controller; + if (controller == '@') { + controller = attrs[directive.name]; + } + + controllerInstance = $controller(controller, locals, true, directive.controllerAs); + + // For directives with element transclusion the element is a comment, + // but jQuery .data doesn't support attaching data to comment nodes as it's hard to + // clean up (http://bugs.jquery.com/ticket/8335). + // Instead, we save the controllers for the element in a local hash and attach to .data + // later, once we have the actual element. + elementControllers[directive.name] = controllerInstance; + if (!hasElementTranscludeDirective) { + $element.data('$' + directive.name + 'Controller', controllerInstance.instance); + } + + controllers[directive.name] = controllerInstance; + }); + } + + if (newIsolateScopeDirective) { + compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective || + templateDirective === newIsolateScopeDirective.$$originalDirective))); + compile.$$addScopeClass($element, true); + + var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name]; + var isolateBindingContext = isolateScope; + if (isolateScopeController && isolateScopeController.identifier && + newIsolateScopeDirective.bindToController === true) { + isolateBindingContext = isolateScopeController.instance; + } + + forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) { + var attrName = definition.attrName, + optional = definition.optional, + mode = definition.mode, // @, =, or & + lastValue, + parentGet, parentSet, compare; + + switch (mode) { + + case '@': + attrs.$observe(attrName, function(value) { + isolateBindingContext[scopeName] = value; + }); + attrs.$$observers[attrName].$$scope = scope; + if (attrs[attrName]) { + // If the attribute has been provided then we trigger an interpolation to ensure + // the value is there for use in the link fn + isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope); + } + break; + + case '=': + if (optional && !attrs[attrName]) { + return; + } + parentGet = $parse(attrs[attrName]); + if (parentGet.literal) { + compare = equals; + } else { + compare = function(a, b) { return a === b || (a !== a && b !== b); }; + } + parentSet = parentGet.assign || function() { + // reset the change, or we will throw this exception on every $digest + lastValue = isolateBindingContext[scopeName] = parentGet(scope); + throw $compileMinErr('nonassign', + "Expression '{0}' used with directive '{1}' is non-assignable!", + attrs[attrName], newIsolateScopeDirective.name); + }; + lastValue = isolateBindingContext[scopeName] = parentGet(scope); + var parentValueWatch = function parentValueWatch(parentValue) { + if (!compare(parentValue, isolateBindingContext[scopeName])) { + // we are out of sync and need to copy + if (!compare(parentValue, lastValue)) { + // parent changed and it has precedence + isolateBindingContext[scopeName] = parentValue; + } else { + // if the parent can be assigned then do so + parentSet(scope, parentValue = isolateBindingContext[scopeName]); + } + } + return lastValue = parentValue; + }; + parentValueWatch.$stateful = true; + var unwatch; + if (definition.collection) { + unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch); + } else { + unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal); + } + isolateScope.$on('$destroy', unwatch); + break; + + case '&': + parentGet = $parse(attrs[attrName]); + isolateBindingContext[scopeName] = function(locals) { + return parentGet(scope, locals); + }; + break; + } + }); + } + if (controllers) { + forEach(controllers, function(controller) { + controller(); + }); + controllers = null; + } + + // PRELINKING + for (i = 0, ii = preLinkFns.length; i < ii; i++) { + linkFn = preLinkFns[i]; + invokeLinkFn(linkFn, + linkFn.isolateScope ? isolateScope : scope, + $element, + attrs, + linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), + transcludeFn + ); + } + + // RECURSION + // We only pass the isolate scope, if the isolate directive has a template, + // otherwise the child elements do not belong to the isolate directive. + var scopeToChild = scope; + if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) { + scopeToChild = isolateScope; + } + childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn); + + // POSTLINKING + for (i = postLinkFns.length - 1; i >= 0; i--) { + linkFn = postLinkFns[i]; + invokeLinkFn(linkFn, + linkFn.isolateScope ? isolateScope : scope, + $element, + attrs, + linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), + transcludeFn + ); + } + + // This is the function that is injected as `$transclude`. + // Note: all arguments are optional! + function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) { + var transcludeControllers; + + // No scope passed in: + if (!isScope(scope)) { + futureParentElement = cloneAttachFn; + cloneAttachFn = scope; + scope = undefined; + } + + if (hasElementTranscludeDirective) { + transcludeControllers = elementControllers; + } + if (!futureParentElement) { + futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element; + } + return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild); + } + } + } + + function markDirectivesAsIsolate(directives) { + // mark all directives as needing isolate scope. + for (var j = 0, jj = directives.length; j < jj; j++) { + directives[j] = inherit(directives[j], {$$isolateScope: true}); + } + } + + /** + * looks up the directive and decorates it with exception handling and proper parameters. We + * call this the boundDirective. + * + * @param {string} name name of the directive to look up. + * @param {string} location The directive must be found in specific format. + * String containing any of theses characters: + * + * * `E`: element name + * * `A': attribute + * * `C`: class + * * `M`: comment + * @returns {boolean} true if directive was added. + */ + function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, + endAttrName) { + if (name === ignoreDirective) return null; + var match = null; + if (hasDirectives.hasOwnProperty(name)) { + for (var directive, directives = $injector.get(name + Suffix), + i = 0, ii = directives.length; i < ii; i++) { + try { + directive = directives[i]; + if ((maxPriority === undefined || maxPriority > directive.priority) && + directive.restrict.indexOf(location) != -1) { + if (startAttrName) { + directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName}); + } + tDirectives.push(directive); + match = directive; + } + } catch (e) { $exceptionHandler(e); } + } + } + return match; + } + + + /** + * looks up the directive and returns true if it is a multi-element directive, + * and therefore requires DOM nodes between -start and -end markers to be grouped + * together. + * + * @param {string} name name of the directive to look up. + * @returns true if directive was registered as multi-element. + */ + function directiveIsMultiElement(name) { + if (hasDirectives.hasOwnProperty(name)) { + for (var directive, directives = $injector.get(name + Suffix), + i = 0, ii = directives.length; i < ii; i++) { + directive = directives[i]; + if (directive.multiElement) { + return true; + } + } + } + return false; + } + + /** + * When the element is replaced with HTML template then the new attributes + * on the template need to be merged with the existing attributes in the DOM. + * The desired effect is to have both of the attributes present. + * + * @param {object} dst destination attributes (original DOM) + * @param {object} src source attributes (from the directive template) + */ + function mergeTemplateAttributes(dst, src) { + var srcAttr = src.$attr, + dstAttr = dst.$attr, + $element = dst.$$element; + + // reapply the old attributes to the new element + forEach(dst, function(value, key) { + if (key.charAt(0) != '$') { + if (src[key] && src[key] !== value) { + value += (key === 'style' ? ';' : ' ') + src[key]; + } + dst.$set(key, value, true, srcAttr[key]); + } + }); + + // copy the new attributes on the old attrs object + forEach(src, function(value, key) { + if (key == 'class') { + safeAddClass($element, value); + dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value; + } else if (key == 'style') { + $element.attr('style', $element.attr('style') + ';' + value); + dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value; + // `dst` will never contain hasOwnProperty as DOM parser won't let it. + // You will get an "InvalidCharacterError: DOM Exception 5" error if you + // have an attribute like "has-own-property" or "data-has-own-property", etc. + } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) { + dst[key] = value; + dstAttr[key] = srcAttr[key]; + } + }); + } + + + function compileTemplateUrl(directives, $compileNode, tAttrs, + $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) { + var linkQueue = [], + afterTemplateNodeLinkFn, + afterTemplateChildLinkFn, + beforeTemplateCompileNode = $compileNode[0], + origAsyncDirective = directives.shift(), + derivedSyncDirective = inherit(origAsyncDirective, { + templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective + }), + templateUrl = (isFunction(origAsyncDirective.templateUrl)) + ? origAsyncDirective.templateUrl($compileNode, tAttrs) + : origAsyncDirective.templateUrl, + templateNamespace = origAsyncDirective.templateNamespace; + + $compileNode.empty(); + + $templateRequest($sce.getTrustedResourceUrl(templateUrl)) + .then(function(content) { + var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn; + + content = denormalizeTemplate(content); + + if (origAsyncDirective.replace) { + if (jqLiteIsTextNode(content)) { + $template = []; + } else { + $template = removeComments(wrapTemplate(templateNamespace, trim(content))); + } + compileNode = $template[0]; + + if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) { + throw $compileMinErr('tplrt', + "Template for directive '{0}' must have exactly one root element. {1}", + origAsyncDirective.name, templateUrl); + } + + tempTemplateAttrs = {$attr: {}}; + replaceWith($rootElement, $compileNode, compileNode); + var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs); + + if (isObject(origAsyncDirective.scope)) { + markDirectivesAsIsolate(templateDirectives); + } + directives = templateDirectives.concat(directives); + mergeTemplateAttributes(tAttrs, tempTemplateAttrs); + } else { + compileNode = beforeTemplateCompileNode; + $compileNode.html(content); + } + + directives.unshift(derivedSyncDirective); + + afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, + childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns, + previousCompileContext); + forEach($rootElement, function(node, i) { + if (node == compileNode) { + $rootElement[i] = $compileNode[0]; + } + }); + afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn); + + while (linkQueue.length) { + var scope = linkQueue.shift(), + beforeTemplateLinkNode = linkQueue.shift(), + linkRootElement = linkQueue.shift(), + boundTranscludeFn = linkQueue.shift(), + linkNode = $compileNode[0]; + + if (scope.$$destroyed) continue; + + if (beforeTemplateLinkNode !== beforeTemplateCompileNode) { + var oldClasses = beforeTemplateLinkNode.className; + + if (!(previousCompileContext.hasElementTranscludeDirective && + origAsyncDirective.replace)) { + // it was cloned therefore we have to clone as well. + linkNode = jqLiteClone(compileNode); + } + replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode); + + // Copy in CSS classes from original node + safeAddClass(jqLite(linkNode), oldClasses); + } + if (afterTemplateNodeLinkFn.transcludeOnThisElement) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); + } else { + childBoundTranscludeFn = boundTranscludeFn; + } + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, + childBoundTranscludeFn); + } + linkQueue = null; + }); + + return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) { + var childBoundTranscludeFn = boundTranscludeFn; + if (scope.$$destroyed) return; + if (linkQueue) { + linkQueue.push(scope, + node, + rootElement, + childBoundTranscludeFn); + } else { + if (afterTemplateNodeLinkFn.transcludeOnThisElement) { + childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); + } + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn); + } + }; + } + + + /** + * Sorting function for bound directives. + */ + function byPriority(a, b) { + var diff = b.priority - a.priority; + if (diff !== 0) return diff; + if (a.name !== b.name) return (a.name < b.name) ? -1 : 1; + return a.index - b.index; + } + + + function assertNoDuplicate(what, previousDirective, directive, element) { + if (previousDirective) { + throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}', + previousDirective.name, directive.name, what, startingTag(element)); + } + } + + + function addTextInterpolateDirective(directives, text) { + var interpolateFn = $interpolate(text, true); + if (interpolateFn) { + directives.push({ + priority: 0, + compile: function textInterpolateCompileFn(templateNode) { + var templateNodeParent = templateNode.parent(), + hasCompileParent = !!templateNodeParent.length; + + // When transcluding a template that has bindings in the root + // we don't have a parent and thus need to add the class during linking fn. + if (hasCompileParent) compile.$$addBindingClass(templateNodeParent); + + return function textInterpolateLinkFn(scope, node) { + var parent = node.parent(); + if (!hasCompileParent) compile.$$addBindingClass(parent); + compile.$$addBindingInfo(parent, interpolateFn.expressions); + scope.$watch(interpolateFn, function interpolateFnWatchAction(value) { + node[0].nodeValue = value; + }); + }; + } + }); + } + } + + + function wrapTemplate(type, template) { + type = lowercase(type || 'html'); + switch (type) { + case 'svg': + case 'math': + var wrapper = document.createElement('div'); + wrapper.innerHTML = '<' + type + '>' + template + ''; + return wrapper.childNodes[0].childNodes; + default: + return template; + } + } + + + function getTrustedContext(node, attrNormalizedName) { + if (attrNormalizedName == "srcdoc") { + return $sce.HTML; + } + var tag = nodeName_(node); + // maction[xlink:href] can source SVG. It's not limited to . + if (attrNormalizedName == "xlinkHref" || + (tag == "form" && attrNormalizedName == "action") || + (tag != "img" && (attrNormalizedName == "src" || + attrNormalizedName == "ngSrc"))) { + return $sce.RESOURCE_URL; + } + } + + + function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) { + var trustedContext = getTrustedContext(node, name); + allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing; + + var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing); + + // no interpolation found -> ignore + if (!interpolateFn) return; + + + if (name === "multiple" && nodeName_(node) === "select") { + throw $compileMinErr("selmulti", + "Binding to the 'multiple' attribute is not supported. Element: {0}", + startingTag(node)); + } + + directives.push({ + priority: 100, + compile: function() { + return { + pre: function attrInterpolatePreLinkFn(scope, element, attr) { + var $$observers = (attr.$$observers || (attr.$$observers = {})); + + if (EVENT_HANDLER_ATTR_REGEXP.test(name)) { + throw $compileMinErr('nodomevents', + "Interpolations for HTML DOM event attributes are disallowed. Please use the " + + "ng- versions (such as ng-click instead of onclick) instead."); + } + + // If the attribute has changed since last $interpolate()ed + var newValue = attr[name]; + if (newValue !== value) { + // we need to interpolate again since the attribute value has been updated + // (e.g. by another directive's compile function) + // ensure unset/empty values make interpolateFn falsy + interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing); + value = newValue; + } + + // if attribute was updated so that there is no interpolation going on we don't want to + // register any observers + if (!interpolateFn) return; + + // initialize attr object so that it's ready in case we need the value for isolate + // scope initialization, otherwise the value would not be available from isolate + // directive's linking fn during linking phase + attr[name] = interpolateFn(scope); + + ($$observers[name] || ($$observers[name] = [])).$$inter = true; + (attr.$$observers && attr.$$observers[name].$$scope || scope). + $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) { + //special case for class attribute addition + removal + //so that class changes can tap into the animation + //hooks provided by the $animate service. Be sure to + //skip animations when the first digest occurs (when + //both the new and the old values are the same) since + //the CSS classes are the non-interpolated values + if (name === 'class' && newValue != oldValue) { + attr.$updateClass(newValue, oldValue); + } else { + attr.$set(name, newValue); + } + }); + } + }; + } + }); + } + + + /** + * This is a special jqLite.replaceWith, which can replace items which + * have no parents, provided that the containing jqLite collection is provided. + * + * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes + * in the root of the tree. + * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep + * the shell, but replace its DOM node reference. + * @param {Node} newNode The new DOM node. + */ + function replaceWith($rootElement, elementsToRemove, newNode) { + var firstElementToRemove = elementsToRemove[0], + removeCount = elementsToRemove.length, + parent = firstElementToRemove.parentNode, + i, ii; + + if ($rootElement) { + for (i = 0, ii = $rootElement.length; i < ii; i++) { + if ($rootElement[i] == firstElementToRemove) { + $rootElement[i++] = newNode; + for (var j = i, j2 = j + removeCount - 1, + jj = $rootElement.length; + j < jj; j++, j2++) { + if (j2 < jj) { + $rootElement[j] = $rootElement[j2]; + } else { + delete $rootElement[j]; + } + } + $rootElement.length -= removeCount - 1; + + // If the replaced element is also the jQuery .context then replace it + // .context is a deprecated jQuery api, so we should set it only when jQuery set it + // http://api.jquery.com/context/ + if ($rootElement.context === firstElementToRemove) { + $rootElement.context = newNode; + } + break; + } + } + } + + if (parent) { + parent.replaceChild(newNode, firstElementToRemove); + } + + // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it? + var fragment = document.createDocumentFragment(); + fragment.appendChild(firstElementToRemove); + + // Copy over user data (that includes Angular's $scope etc.). Don't copy private + // data here because there's no public interface in jQuery to do that and copying over + // event listeners (which is the main use of private data) wouldn't work anyway. + jqLite(newNode).data(jqLite(firstElementToRemove).data()); + + // Remove data of the replaced element. We cannot just call .remove() + // on the element it since that would deallocate scope that is needed + // for the new node. Instead, remove the data "manually". + if (!jQuery) { + delete jqLite.cache[firstElementToRemove[jqLite.expando]]; + } else { + // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after + // the replaced element. The cleanData version monkey-patched by Angular would cause + // the scope to be trashed and we do need the very same scope to work with the new + // element. However, we cannot just cache the non-patched version and use it here as + // that would break if another library patches the method after Angular does (one + // example is jQuery UI). Instead, set a flag indicating scope destroying should be + // skipped this one time. + skipDestroyOnNextJQueryCleanData = true; + jQuery.cleanData([firstElementToRemove]); + } + + for (var k = 1, kk = elementsToRemove.length; k < kk; k++) { + var element = elementsToRemove[k]; + jqLite(element).remove(); // must do this way to clean up expando + fragment.appendChild(element); + delete elementsToRemove[k]; + } + + elementsToRemove[0] = newNode; + elementsToRemove.length = 1; + } + + + function cloneAndAnnotateFn(fn, annotation) { + return extend(function() { return fn.apply(null, arguments); }, fn, annotation); + } + + + function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) { + try { + linkFn(scope, $element, attrs, controllers, transcludeFn); + } catch (e) { + $exceptionHandler(e, startingTag($element)); + } + } + }]; +} + +var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i; +/** + * Converts all accepted directives format into proper directive name. + * @param name Name to normalize + */ +function directiveNormalize(name) { + return camelCase(name.replace(PREFIX_REGEXP, '')); +} + +/** + * @ngdoc type + * @name $compile.directive.Attributes + * + * @description + * A shared object between directive compile / linking functions which contains normalized DOM + * element attributes. The values reflect current binding state `{{ }}`. The normalization is + * needed since all of these are treated as equivalent in Angular: + * + * ``` + * + * ``` + */ + +/** + * @ngdoc property + * @name $compile.directive.Attributes#$attr + * + * @description + * A map of DOM element attribute names to the normalized name. This is + * needed to do reverse lookup from normalized name back to actual name. + */ + + +/** + * @ngdoc method + * @name $compile.directive.Attributes#$set + * @kind function + * + * @description + * Set DOM element attribute value. + * + * + * @param {string} name Normalized element attribute name of the property to modify. The name is + * reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr} + * property to the original name. + * @param {string} value Value to set the attribute to. The value can be an interpolated string. + */ + + + +/** + * Closure compiler type information + */ + +function nodesetLinkingFn( + /* angular.Scope */ scope, + /* NodeList */ nodeList, + /* Element */ rootElement, + /* function(Function) */ boundTranscludeFn +) {} + +function directiveLinkingFn( + /* nodesetLinkingFn */ nodesetLinkingFn, + /* angular.Scope */ scope, + /* Node */ node, + /* Element */ rootElement, + /* function(Function) */ boundTranscludeFn +) {} + +function tokenDifference(str1, str2) { + var values = '', + tokens1 = str1.split(/\s+/), + tokens2 = str2.split(/\s+/); + + outer: + for (var i = 0; i < tokens1.length; i++) { + var token = tokens1[i]; + for (var j = 0; j < tokens2.length; j++) { + if (token == tokens2[j]) continue outer; + } + values += (values.length > 0 ? ' ' : '') + token; + } + return values; +} + +function removeComments(jqNodes) { + jqNodes = jqLite(jqNodes); + var i = jqNodes.length; + + if (i <= 1) { + return jqNodes; + } + + while (i--) { + var node = jqNodes[i]; + if (node.nodeType === NODE_TYPE_COMMENT) { + splice.call(jqNodes, i, 1); + } + } + return jqNodes; +} + +var $controllerMinErr = minErr('$controller'); + +/** + * @ngdoc provider + * @name $controllerProvider + * @description + * The {@link ng.$controller $controller service} is used by Angular to create new + * controllers. + * + * This provider allows controller registration via the + * {@link ng.$controllerProvider#register register} method. + */ +function $ControllerProvider() { + var controllers = {}, + globals = false, + CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/; + + + /** + * @ngdoc method + * @name $controllerProvider#register + * @param {string|Object} name Controller name, or an object map of controllers where the keys are + * the names and the values are the constructors. + * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI + * annotations in the array notation). + */ + this.register = function(name, constructor) { + assertNotHasOwnProperty(name, 'controller'); + if (isObject(name)) { + extend(controllers, name); + } else { + controllers[name] = constructor; + } + }; + + /** + * @ngdoc method + * @name $controllerProvider#allowGlobals + * @description If called, allows `$controller` to find controller constructors on `window` + */ + this.allowGlobals = function() { + globals = true; + }; + + + this.$get = ['$injector', '$window', function($injector, $window) { + + /** + * @ngdoc service + * @name $controller + * @requires $injector + * + * @param {Function|string} constructor If called with a function then it's considered to be the + * controller constructor function. Otherwise it's considered to be a string which is used + * to retrieve the controller constructor using the following steps: + * + * * check if a controller with given name is registered via `$controllerProvider` + * * check if evaluating the string on the current scope returns a constructor + * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global + * `window` object (not recommended) + * + * The string can use the `controller as property` syntax, where the controller instance is published + * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this + * to work correctly. + * + * @param {Object} locals Injection locals for Controller. + * @return {Object} Instance of given controller. + * + * @description + * `$controller` service is responsible for instantiating controllers. + * + * It's just a simple call to {@link auto.$injector $injector}, but extracted into + * a service, so that one can override this service with [BC version](https://gist.github.com/1649788). + */ + return function(expression, locals, later, ident) { + // PRIVATE API: + // param `later` --- indicates that the controller's constructor is invoked at a later time. + // If true, $controller will allocate the object with the correct + // prototype chain, but will not invoke the controller until a returned + // callback is invoked. + // param `ident` --- An optional label which overrides the label parsed from the controller + // expression, if any. + var instance, match, constructor, identifier; + later = later === true; + if (ident && isString(ident)) { + identifier = ident; + } + + if (isString(expression)) { + match = expression.match(CNTRL_REG); + if (!match) { + throw $controllerMinErr('ctrlfmt', + "Badly formed controller string '{0}'. " + + "Must match `__name__ as __id__` or `__name__`.", expression); + } + constructor = match[1], + identifier = identifier || match[3]; + expression = controllers.hasOwnProperty(constructor) + ? controllers[constructor] + : getter(locals.$scope, constructor, true) || + (globals ? getter($window, constructor, true) : undefined); + + assertArgFn(expression, constructor, true); + } + + if (later) { + // Instantiate controller later: + // This machinery is used to create an instance of the object before calling the + // controller's constructor itself. + // + // This allows properties to be added to the controller before the constructor is + // invoked. Primarily, this is used for isolate scope bindings in $compile. + // + // This feature is not intended for use by applications, and is thus not documented + // publicly. + // Object creation: http://jsperf.com/create-constructor/2 + var controllerPrototype = (isArray(expression) ? + expression[expression.length - 1] : expression).prototype; + instance = Object.create(controllerPrototype || null); + + if (identifier) { + addIdentifier(locals, identifier, instance, constructor || expression.name); + } + + return extend(function() { + $injector.invoke(expression, instance, locals, constructor); + return instance; + }, { + instance: instance, + identifier: identifier + }); + } + + instance = $injector.instantiate(expression, locals, constructor); + + if (identifier) { + addIdentifier(locals, identifier, instance, constructor || expression.name); + } + + return instance; + }; + + function addIdentifier(locals, identifier, instance, name) { + if (!(locals && isObject(locals.$scope))) { + throw minErr('$controller')('noscp', + "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", + name, identifier); + } + + locals.$scope[identifier] = instance; + } + }]; +} + +/** + * @ngdoc service + * @name $document + * @requires $window + * + * @description + * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object. + * + * @example + + +
    +

    $document title:

    +

    window.document title:

    +
    +
    + + angular.module('documentExample', []) + .controller('ExampleController', ['$scope', '$document', function($scope, $document) { + $scope.title = $document[0].title; + $scope.windowTitle = angular.element(window.document)[0].title; + }]); + +
    + */ +function $DocumentProvider() { + this.$get = ['$window', function(window) { + return jqLite(window.document); + }]; +} + +/** + * @ngdoc service + * @name $exceptionHandler + * @requires ng.$log + * + * @description + * Any uncaught exception in angular expressions is delegated to this service. + * The default implementation simply delegates to `$log.error` which logs it into + * the browser console. + * + * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by + * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing. + * + * ## Example: + * + * ```js + * angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { + * return function(exception, cause) { + * exception.message += ' (caused by "' + cause + '")'; + * throw exception; + * }; + * }); + * ``` + * + * This example will override the normal action of `$exceptionHandler`, to make angular + * exceptions fail hard when they happen, instead of just logging to the console. + * + *
    + * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind` + * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler} + * (unless executed during a digest). + * + * If you wish, you can manually delegate exceptions, e.g. + * `try { ... } catch(e) { $exceptionHandler(e); }` + * + * @param {Error} exception Exception associated with the error. + * @param {string=} cause optional information about the context in which + * the error was thrown. + * + */ +function $ExceptionHandlerProvider() { + this.$get = ['$log', function($log) { + return function(exception, cause) { + $log.error.apply($log, arguments); + }; + }]; +} + +var APPLICATION_JSON = 'application/json'; +var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'}; +var JSON_START = /^\[|^\{(?!\{)/; +var JSON_ENDS = { + '[': /]$/, + '{': /}$/ +}; +var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/; + +function defaultHttpResponseTransform(data, headers) { + if (isString(data)) { + // Strip json vulnerability protection prefix and trim whitespace + var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim(); + + if (tempData) { + var contentType = headers('Content-Type'); + if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) { + data = fromJson(tempData); + } + } + } + + return data; +} + +function isJsonLike(str) { + var jsonStart = str.match(JSON_START); + return jsonStart && JSON_ENDS[jsonStart[0]].test(str); +} + +/** + * Parse headers into key value object + * + * @param {string} headers Raw headers as a string + * @returns {Object} Parsed headers as key value object + */ +function parseHeaders(headers) { + var parsed = createMap(), key, val, i; + + if (!headers) return parsed; + + forEach(headers.split('\n'), function(line) { + i = line.indexOf(':'); + key = lowercase(trim(line.substr(0, i))); + val = trim(line.substr(i + 1)); + + if (key) { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + }); + + return parsed; +} + + +/** + * Returns a function that provides access to parsed headers. + * + * Headers are lazy parsed when first requested. + * @see parseHeaders + * + * @param {(string|Object)} headers Headers to provide access to. + * @returns {function(string=)} Returns a getter function which if called with: + * + * - if called with single an argument returns a single header value or null + * - if called with no arguments returns an object containing all headers. + */ +function headersGetter(headers) { + var headersObj = isObject(headers) ? headers : undefined; + + return function(name) { + if (!headersObj) headersObj = parseHeaders(headers); + + if (name) { + var value = headersObj[lowercase(name)]; + if (value === void 0) { + value = null; + } + return value; + } + + return headersObj; + }; +} + + +/** + * Chain all given functions + * + * This function is used for both request and response transforming + * + * @param {*} data Data to transform. + * @param {function(string=)} headers HTTP headers getter fn. + * @param {number} status HTTP status code of the response. + * @param {(Function|Array.)} fns Function or an array of functions. + * @returns {*} Transformed data. + */ +function transformData(data, headers, status, fns) { + if (isFunction(fns)) + return fns(data, headers, status); + + forEach(fns, function(fn) { + data = fn(data, headers, status); + }); + + return data; +} + + +function isSuccess(status) { + return 200 <= status && status < 300; +} + + +/** + * @ngdoc provider + * @name $httpProvider + * @description + * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service. + * */ +function $HttpProvider() { + /** + * @ngdoc property + * @name $httpProvider#defaults + * @description + * + * Object containing default values for all {@link ng.$http $http} requests. + * + * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`} + * that will provide the cache for all requests who set their `cache` property to `true`. + * If you set the `default.cache = false` then only requests that specify their own custom + * cache object will be cached. See {@link $http#caching $http Caching} for more information. + * + * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token. + * Defaults value is `'XSRF-TOKEN'`. + * + * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the + * XSRF token. Defaults value is `'X-XSRF-TOKEN'`. + * + * - **`defaults.headers`** - {Object} - Default headers for all $http requests. + * Refer to {@link ng.$http#setting-http-headers $http} for documentation on + * setting default headers. + * - **`defaults.headers.common`** + * - **`defaults.headers.post`** + * - **`defaults.headers.put`** + * - **`defaults.headers.patch`** + * + **/ + var defaults = this.defaults = { + // transform incoming response data + transformResponse: [defaultHttpResponseTransform], + + // transform outgoing request data + transformRequest: [function(d) { + return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d; + }], + + // default headers + headers: { + common: { + 'Accept': 'application/json, text/plain, */*' + }, + post: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), + put: shallowCopy(CONTENT_TYPE_APPLICATION_JSON), + patch: shallowCopy(CONTENT_TYPE_APPLICATION_JSON) + }, + + xsrfCookieName: 'XSRF-TOKEN', + xsrfHeaderName: 'X-XSRF-TOKEN' + }; + + var useApplyAsync = false; + /** + * @ngdoc method + * @name $httpProvider#useApplyAsync + * @description + * + * Configure $http service to combine processing of multiple http responses received at around + * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in + * significant performance improvement for bigger applications that make many HTTP requests + * concurrently (common during application bootstrap). + * + * Defaults to false. If no value is specifed, returns the current configured value. + * + * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred + * "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window + * to load and share the same digest cycle. + * + * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining. + * otherwise, returns the current configured value. + **/ + this.useApplyAsync = function(value) { + if (isDefined(value)) { + useApplyAsync = !!value; + return this; + } + return useApplyAsync; + }; + + /** + * @ngdoc property + * @name $httpProvider#interceptors + * @description + * + * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http} + * pre-processing of request or postprocessing of responses. + * + * These service factories are ordered by request, i.e. they are applied in the same order as the + * array, on request, but reverse order, on response. + * + * {@link ng.$http#interceptors Interceptors detailed info} + **/ + var interceptorFactories = this.interceptors = []; + + this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector', + function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) { + + var defaultCache = $cacheFactory('$http'); + + /** + * Interceptors stored in reverse order. Inner interceptors before outer interceptors. + * The reversal is needed so that we can build up the interception chain around the + * server request. + */ + var reversedInterceptors = []; + + forEach(interceptorFactories, function(interceptorFactory) { + reversedInterceptors.unshift(isString(interceptorFactory) + ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory)); + }); + + /** + * @ngdoc service + * @kind function + * @name $http + * @requires ng.$httpBackend + * @requires $cacheFactory + * @requires $rootScope + * @requires $q + * @requires $injector + * + * @description + * The `$http` service is a core Angular service that facilitates communication with the remote + * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest) + * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP). + * + * For unit testing applications that use `$http` service, see + * {@link ngMock.$httpBackend $httpBackend mock}. + * + * For a higher level of abstraction, please check out the {@link ngResource.$resource + * $resource} service. + * + * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by + * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage + * it is important to familiarize yourself with these APIs and the guarantees they provide. + * + * + * ## General usage + * The `$http` service is a function which takes a single argument — a configuration object — + * that is used to generate an HTTP request and returns a {@link ng.$q promise} + * with two $http specific methods: `success` and `error`. + * + * ```js + * // Simple GET request example : + * $http.get('/someUrl'). + * success(function(data, status, headers, config) { + * // this callback will be called asynchronously + * // when the response is available + * }). + * error(function(data, status, headers, config) { + * // called asynchronously if an error occurs + * // or server returns response with an error status. + * }); + * ``` + * + * ```js + * // Simple POST request example (passing data) : + * $http.post('/someUrl', {msg:'hello word!'}). + * success(function(data, status, headers, config) { + * // this callback will be called asynchronously + * // when the response is available + * }). + * error(function(data, status, headers, config) { + * // called asynchronously if an error occurs + * // or server returns response with an error status. + * }); + * ``` + * + * + * Since the returned value of calling the $http function is a `promise`, you can also use + * the `then` method to register callbacks, and these callbacks will receive a single argument – + * an object representing the response. See the API signature and type info below for more + * details. + * + * A response status code between 200 and 299 is considered a success status and + * will result in the success callback being called. Note that if the response is a redirect, + * XMLHttpRequest will transparently follow it, meaning that the error callback will not be + * called for such responses. + * + * ## Writing Unit Tests that use $http + * When unit testing (using {@link ngMock ngMock}), it is necessary to call + * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending + * request using trained responses. + * + * ``` + * $httpBackend.expectGET(...); + * $http.get(...); + * $httpBackend.flush(); + * ``` + * + * ## Shortcut methods + * + * Shortcut methods are also available. All shortcut methods require passing in the URL, and + * request data must be passed in for POST/PUT requests. + * + * ```js + * $http.get('/someUrl').success(successCallback); + * $http.post('/someUrl', data).success(successCallback); + * ``` + * + * Complete list of shortcut methods: + * + * - {@link ng.$http#get $http.get} + * - {@link ng.$http#head $http.head} + * - {@link ng.$http#post $http.post} + * - {@link ng.$http#put $http.put} + * - {@link ng.$http#delete $http.delete} + * - {@link ng.$http#jsonp $http.jsonp} + * - {@link ng.$http#patch $http.patch} + * + * + * ## Setting HTTP Headers + * + * The $http service will automatically add certain HTTP headers to all requests. These defaults + * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration + * object, which currently contains this default configuration: + * + * - `$httpProvider.defaults.headers.common` (headers that are common for all requests): + * - `Accept: application/json, text/plain, * / *` + * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests) + * - `Content-Type: application/json` + * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests) + * - `Content-Type: application/json` + * + * To add or overwrite these defaults, simply add or remove a property from these configuration + * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object + * with the lowercased HTTP method name as the key, e.g. + * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }. + * + * The defaults can also be set at runtime via the `$http.defaults` object in the same + * fashion. For example: + * + * ``` + * module.run(function($http) { + * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w' + * }); + * ``` + * + * In addition, you can supply a `headers` property in the config object passed when + * calling `$http(config)`, which overrides the defaults without changing them globally. + * + * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis, + * Use the `headers` property, setting the desired header to `undefined`. For example: + * + * ```js + * var req = { + * method: 'POST', + * url: 'http://example.com', + * headers: { + * 'Content-Type': undefined + * }, + * data: { test: 'test' }, + * } + * + * $http(req).success(function(){...}).error(function(){...}); + * ``` + * + * ## Transforming Requests and Responses + * + * Both requests and responses can be transformed using transformation functions: `transformRequest` + * and `transformResponse`. These properties can be a single function that returns + * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions, + * which allows you to `push` or `unshift` a new transformation function into the transformation chain. + * + * ### Default Transformations + * + * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and + * `defaults.transformResponse` properties. If a request does not provide its own transformations + * then these will be applied. + * + * You can augment or replace the default transformations by modifying these properties by adding to or + * replacing the array. + * + * Angular provides the following default transformations: + * + * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`): + * + * - If the `data` property of the request configuration object contains an object, serialize it + * into JSON format. + * + * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`): + * + * - If XSRF prefix is detected, strip it (see Security Considerations section below). + * - If JSON response is detected, deserialize it using a JSON parser. + * + * + * ### Overriding the Default Transformations Per Request + * + * If you wish override the request/response transformations only for a single request then provide + * `transformRequest` and/or `transformResponse` properties on the configuration object passed + * into `$http`. + * + * Note that if you provide these properties on the config object the default transformations will be + * overwritten. If you wish to augment the default transformations then you must include them in your + * local transformation array. + * + * The following code demonstrates adding a new response transformation to be run after the default response + * transformations have been run. + * + * ```js + * function appendTransform(defaults, transform) { + * + * // We can't guarantee that the default transformation is an array + * defaults = angular.isArray(defaults) ? defaults : [defaults]; + * + * // Append the new transformation to the defaults + * return defaults.concat(transform); + * } + * + * $http({ + * url: '...', + * method: 'GET', + * transformResponse: appendTransform($http.defaults.transformResponse, function(value) { + * return doTransform(value); + * }) + * }); + * ``` + * + * + * ## Caching + * + * To enable caching, set the request configuration `cache` property to `true` (to use default + * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}). + * When the cache is enabled, `$http` stores the response from the server in the specified + * cache. The next time the same request is made, the response is served from the cache without + * sending a request to the server. + * + * Note that even if the response is served from cache, delivery of the data is asynchronous in + * the same way that real requests are. + * + * If there are multiple GET requests for the same URL that should be cached using the same + * cache, but the cache is not populated yet, only one request to the server will be made and + * the remaining requests will be fulfilled using the response from the first request. + * + * You can change the default cache to a new object (built with + * {@link ng.$cacheFactory `$cacheFactory`}) by updating the + * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set + * their `cache` property to `true` will now use this cache object. + * + * If you set the default cache to `false` then only requests that specify their own custom + * cache object will be cached. + * + * ## Interceptors + * + * Before you start creating interceptors, be sure to understand the + * {@link ng.$q $q and deferred/promise APIs}. + * + * For purposes of global error handling, authentication, or any kind of synchronous or + * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be + * able to intercept requests before they are handed to the server and + * responses before they are handed over to the application code that + * initiated these requests. The interceptors leverage the {@link ng.$q + * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing. + * + * The interceptors are service factories that are registered with the `$httpProvider` by + * adding them to the `$httpProvider.interceptors` array. The factory is called and + * injected with dependencies (if specified) and returns the interceptor. + * + * There are two kinds of interceptors (and two kinds of rejection interceptors): + * + * * `request`: interceptors get called with a http `config` object. The function is free to + * modify the `config` object or create a new one. The function needs to return the `config` + * object directly, or a promise containing the `config` or a new `config` object. + * * `requestError`: interceptor gets called when a previous interceptor threw an error or + * resolved with a rejection. + * * `response`: interceptors get called with http `response` object. The function is free to + * modify the `response` object or create a new one. The function needs to return the `response` + * object directly, or as a promise containing the `response` or a new `response` object. + * * `responseError`: interceptor gets called when a previous interceptor threw an error or + * resolved with a rejection. + * + * + * ```js + * // register the interceptor as a service + * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) { + * return { + * // optional method + * 'request': function(config) { + * // do something on success + * return config; + * }, + * + * // optional method + * 'requestError': function(rejection) { + * // do something on error + * if (canRecover(rejection)) { + * return responseOrNewPromise + * } + * return $q.reject(rejection); + * }, + * + * + * + * // optional method + * 'response': function(response) { + * // do something on success + * return response; + * }, + * + * // optional method + * 'responseError': function(rejection) { + * // do something on error + * if (canRecover(rejection)) { + * return responseOrNewPromise + * } + * return $q.reject(rejection); + * } + * }; + * }); + * + * $httpProvider.interceptors.push('myHttpInterceptor'); + * + * + * // alternatively, register the interceptor via an anonymous factory + * $httpProvider.interceptors.push(function($q, dependency1, dependency2) { + * return { + * 'request': function(config) { + * // same as above + * }, + * + * 'response': function(response) { + * // same as above + * } + * }; + * }); + * ``` + * + * ## Security Considerations + * + * When designing web applications, consider security threats from: + * + * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) + * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) + * + * Both server and the client must cooperate in order to eliminate these threats. Angular comes + * pre-configured with strategies that address these issues, but for this to work backend server + * cooperation is required. + * + * ### JSON Vulnerability Protection + * + * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx) + * allows third party website to turn your JSON resource URL into + * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To + * counter this your server can prefix all JSON requests with following string `")]}',\n"`. + * Angular will automatically strip the prefix before processing it as JSON. + * + * For example if your server needs to return: + * ```js + * ['one','two'] + * ``` + * + * which is vulnerable to attack, your server can return: + * ```js + * )]}', + * ['one','two'] + * ``` + * + * Angular will strip the prefix, before processing the JSON. + * + * + * ### Cross Site Request Forgery (XSRF) Protection + * + * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which + * an unauthorized site can gain your user's private data. Angular provides a mechanism + * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie + * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only + * JavaScript that runs on your domain could read the cookie, your server can be assured that + * the XHR came from JavaScript running on your domain. The header will not be set for + * cross-domain requests. + * + * To take advantage of this, your server needs to set a token in a JavaScript readable session + * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the + * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure + * that only JavaScript running on your domain could have sent the request. The token must be + * unique for each user and must be verifiable by the server (to prevent the JavaScript from + * making up its own tokens). We recommend that the token is a digest of your site's + * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) + * for added security. + * + * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName + * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time, + * or the per-request config object. + * + * + * @param {object} config Object describing the request to be made and how it should be + * processed. The object has following properties: + * + * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc) + * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested. + * - **params** – `{Object.}` – Map of strings or objects which will be turned + * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be + * JSONified. + * - **data** – `{string|Object}` – Data to be sent as the request message data. + * - **headers** – `{Object}` – Map of strings or functions which return strings representing + * HTTP headers to send to the server. If the return value of a function is null, the + * header will not be sent. + * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token. + * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token. + * - **transformRequest** – + * `{function(data, headersGetter)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * request body and headers and returns its transformed (typically serialized) version. + * See {@link ng.$http#overriding-the-default-transformations-per-request + * Overriding the Default Transformations} + * - **transformResponse** – + * `{function(data, headersGetter, status)|Array.}` – + * transform function or an array of such functions. The transform function takes the http + * response body, headers and status and returns its transformed (typically deserialized) version. + * See {@link ng.$http#overriding-the-default-transformations-per-request + * Overriding the Default Transformations} + * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the + * GET request, otherwise if a cache instance built with + * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for + * caching. + * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} + * that should abort the request when resolved. + * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the + * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials) + * for more information. + * - **responseType** - `{string}` - see + * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). + * + * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the + * standard `then` method and two http specific methods: `success` and `error`. The `then` + * method takes two arguments a success and an error callback which will be called with a + * response object. The `success` and `error` methods take a single argument - a function that + * will be called when the request succeeds or fails respectively. The arguments passed into + * these functions are destructured representation of the response object passed into the + * `then` method. The response object has these properties: + * + * - **data** – `{string|Object}` – The response body transformed with the transform + * functions. + * - **status** – `{number}` – HTTP status code of the response. + * - **headers** – `{function([headerName])}` – Header getter function. + * - **config** – `{Object}` – The configuration object that was used to generate the request. + * - **statusText** – `{string}` – HTTP status text of the response. + * + * @property {Array.} pendingRequests Array of config objects for currently pending + * requests. This is primarily meant to be used for debugging purposes. + * + * + * @example + + +
    + + +
    + + + +
    http status code: {{status}}
    +
    http response data: {{data}}
    +
    +
    + + angular.module('httpExample', []) + .controller('FetchController', ['$scope', '$http', '$templateCache', + function($scope, $http, $templateCache) { + $scope.method = 'GET'; + $scope.url = 'http-hello.html'; + + $scope.fetch = function() { + $scope.code = null; + $scope.response = null; + + $http({method: $scope.method, url: $scope.url, cache: $templateCache}). + success(function(data, status) { + $scope.status = status; + $scope.data = data; + }). + error(function(data, status) { + $scope.data = data || "Request failed"; + $scope.status = status; + }); + }; + + $scope.updateModel = function(method, url) { + $scope.method = method; + $scope.url = url; + }; + }]); + + + Hello, $http! + + + var status = element(by.binding('status')); + var data = element(by.binding('data')); + var fetchBtn = element(by.id('fetchbtn')); + var sampleGetBtn = element(by.id('samplegetbtn')); + var sampleJsonpBtn = element(by.id('samplejsonpbtn')); + var invalidJsonpBtn = element(by.id('invalidjsonpbtn')); + + it('should make an xhr GET request', function() { + sampleGetBtn.click(); + fetchBtn.click(); + expect(status.getText()).toMatch('200'); + expect(data.getText()).toMatch(/Hello, \$http!/); + }); + +// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185 +// it('should make a JSONP request to angularjs.org', function() { +// sampleJsonpBtn.click(); +// fetchBtn.click(); +// expect(status.getText()).toMatch('200'); +// expect(data.getText()).toMatch(/Super Hero!/); +// }); + + it('should make JSONP request to invalid URL and invoke the error handler', + function() { + invalidJsonpBtn.click(); + fetchBtn.click(); + expect(status.getText()).toMatch('0'); + expect(data.getText()).toMatch('Request failed'); + }); + +
    + */ + function $http(requestConfig) { + + if (!angular.isObject(requestConfig)) { + throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig); + } + + var config = extend({ + method: 'get', + transformRequest: defaults.transformRequest, + transformResponse: defaults.transformResponse + }, requestConfig); + + config.headers = mergeHeaders(requestConfig); + config.method = uppercase(config.method); + + var serverRequest = function(config) { + var headers = config.headers; + var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest); + + // strip content-type if data is undefined + if (isUndefined(reqData)) { + forEach(headers, function(value, header) { + if (lowercase(header) === 'content-type') { + delete headers[header]; + } + }); + } + + if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) { + config.withCredentials = defaults.withCredentials; + } + + // send request + return sendReq(config, reqData).then(transformResponse, transformResponse); + }; + + var chain = [serverRequest, undefined]; + var promise = $q.when(config); + + // apply interceptors + forEach(reversedInterceptors, function(interceptor) { + if (interceptor.request || interceptor.requestError) { + chain.unshift(interceptor.request, interceptor.requestError); + } + if (interceptor.response || interceptor.responseError) { + chain.push(interceptor.response, interceptor.responseError); + } + }); + + while (chain.length) { + var thenFn = chain.shift(); + var rejectFn = chain.shift(); + + promise = promise.then(thenFn, rejectFn); + } + + promise.success = function(fn) { + promise.then(function(response) { + fn(response.data, response.status, response.headers, config); + }); + return promise; + }; + + promise.error = function(fn) { + promise.then(null, function(response) { + fn(response.data, response.status, response.headers, config); + }); + return promise; + }; + + return promise; + + function transformResponse(response) { + // make a copy since the response must be cacheable + var resp = extend({}, response); + if (!response.data) { + resp.data = response.data; + } else { + resp.data = transformData(response.data, response.headers, response.status, config.transformResponse); + } + return (isSuccess(response.status)) + ? resp + : $q.reject(resp); + } + + function executeHeaderFns(headers) { + var headerContent, processedHeaders = {}; + + forEach(headers, function(headerFn, header) { + if (isFunction(headerFn)) { + headerContent = headerFn(); + if (headerContent != null) { + processedHeaders[header] = headerContent; + } + } else { + processedHeaders[header] = headerFn; + } + }); + + return processedHeaders; + } + + function mergeHeaders(config) { + var defHeaders = defaults.headers, + reqHeaders = extend({}, config.headers), + defHeaderName, lowercaseDefHeaderName, reqHeaderName; + + defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]); + + // using for-in instead of forEach to avoid unecessary iteration after header has been found + defaultHeadersIteration: + for (defHeaderName in defHeaders) { + lowercaseDefHeaderName = lowercase(defHeaderName); + + for (reqHeaderName in reqHeaders) { + if (lowercase(reqHeaderName) === lowercaseDefHeaderName) { + continue defaultHeadersIteration; + } + } + + reqHeaders[defHeaderName] = defHeaders[defHeaderName]; + } + + // execute if header value is a function for merged headers + return executeHeaderFns(reqHeaders); + } + } + + $http.pendingRequests = []; + + /** + * @ngdoc method + * @name $http#get + * + * @description + * Shortcut method to perform `GET` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#delete + * + * @description + * Shortcut method to perform `DELETE` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#head + * + * @description + * Shortcut method to perform `HEAD` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#jsonp + * + * @description + * Shortcut method to perform `JSONP` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request. + * The name of the callback should be the string `JSON_CALLBACK`. + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + createShortMethods('get', 'delete', 'head', 'jsonp'); + + /** + * @ngdoc method + * @name $http#post + * + * @description + * Shortcut method to perform `POST` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#put + * + * @description + * Shortcut method to perform `PUT` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + + /** + * @ngdoc method + * @name $http#patch + * + * @description + * Shortcut method to perform `PATCH` request. + * + * @param {string} url Relative or absolute URL specifying the destination of the request + * @param {*} data Request content + * @param {Object=} config Optional configuration object + * @returns {HttpPromise} Future object + */ + createShortMethodsWithData('post', 'put', 'patch'); + + /** + * @ngdoc property + * @name $http#defaults + * + * @description + * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of + * default headers, withCredentials as well as request and response transformations. + * + * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above. + */ + $http.defaults = defaults; + + + return $http; + + + function createShortMethods(names) { + forEach(arguments, function(name) { + $http[name] = function(url, config) { + return $http(extend(config || {}, { + method: name, + url: url + })); + }; + }); + } + + + function createShortMethodsWithData(name) { + forEach(arguments, function(name) { + $http[name] = function(url, data, config) { + return $http(extend(config || {}, { + method: name, + url: url, + data: data + })); + }; + }); + } + + + /** + * Makes the request. + * + * !!! ACCESSES CLOSURE VARS: + * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests + */ + function sendReq(config, reqData) { + var deferred = $q.defer(), + promise = deferred.promise, + cache, + cachedResp, + reqHeaders = config.headers, + url = buildUrl(config.url, config.params); + + $http.pendingRequests.push(config); + promise.then(removePendingReq, removePendingReq); + + + if ((config.cache || defaults.cache) && config.cache !== false && + (config.method === 'GET' || config.method === 'JSONP')) { + cache = isObject(config.cache) ? config.cache + : isObject(defaults.cache) ? defaults.cache + : defaultCache; + } + + if (cache) { + cachedResp = cache.get(url); + if (isDefined(cachedResp)) { + if (isPromiseLike(cachedResp)) { + // cached request has already been sent, but there is no response yet + cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult); + } else { + // serving from cache + if (isArray(cachedResp)) { + resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]); + } else { + resolvePromise(cachedResp, 200, {}, 'OK'); + } + } + } else { + // put the promise for the non-transformed response into cache as a placeholder + cache.put(url, promise); + } + } + + + // if we won't have the response in cache, set the xsrf headers and + // send the request to the backend + if (isUndefined(cachedResp)) { + var xsrfValue = urlIsSameOrigin(config.url) + ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName] + : undefined; + if (xsrfValue) { + reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue; + } + + $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, + config.withCredentials, config.responseType); + } + + return promise; + + + /** + * Callback registered to $httpBackend(): + * - caches the response if desired + * - resolves the raw $http promise + * - calls $apply + */ + function done(status, response, headersString, statusText) { + if (cache) { + if (isSuccess(status)) { + cache.put(url, [status, response, parseHeaders(headersString), statusText]); + } else { + // remove promise from the cache + cache.remove(url); + } + } + + function resolveHttpPromise() { + resolvePromise(response, status, headersString, statusText); + } + + if (useApplyAsync) { + $rootScope.$applyAsync(resolveHttpPromise); + } else { + resolveHttpPromise(); + if (!$rootScope.$$phase) $rootScope.$apply(); + } + } + + + /** + * Resolves the raw $http promise. + */ + function resolvePromise(response, status, headers, statusText) { + // normalize internal statuses to 0 + status = Math.max(status, 0); + + (isSuccess(status) ? deferred.resolve : deferred.reject)({ + data: response, + status: status, + headers: headersGetter(headers), + config: config, + statusText: statusText + }); + } + + function resolvePromiseWithResult(result) { + resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText); + } + + function removePendingReq() { + var idx = $http.pendingRequests.indexOf(config); + if (idx !== -1) $http.pendingRequests.splice(idx, 1); + } + } + + + function buildUrl(url, params) { + if (!params) return url; + var parts = []; + forEachSorted(params, function(value, key) { + if (value === null || isUndefined(value)) return; + if (!isArray(value)) value = [value]; + + forEach(value, function(v) { + if (isObject(v)) { + if (isDate(v)) { + v = v.toISOString(); + } else { + v = toJson(v); + } + } + parts.push(encodeUriQuery(key) + '=' + + encodeUriQuery(v)); + }); + }); + if (parts.length > 0) { + url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&'); + } + return url; + } + }]; +} + +function createXhr() { + return new window.XMLHttpRequest(); +} + +/** + * @ngdoc service + * @name $httpBackend + * @requires $window + * @requires $document + * + * @description + * HTTP backend used by the {@link ng.$http service} that delegates to + * XMLHttpRequest object or JSONP and deals with browser incompatibilities. + * + * You should never need to use this service directly, instead use the higher-level abstractions: + * {@link ng.$http $http} or {@link ngResource.$resource $resource}. + * + * During testing this implementation is swapped with {@link ngMock.$httpBackend mock + * $httpBackend} which can be trained with responses. + */ +function $HttpBackendProvider() { + this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { + return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]); + }]; +} + +function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { + // TODO(vojta): fix the signature + return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { + $browser.$$incOutstandingRequestCount(); + url = url || $browser.url(); + + if (lowercase(method) == 'jsonp') { + var callbackId = '_' + (callbacks.counter++).toString(36); + callbacks[callbackId] = function(data) { + callbacks[callbackId].data = data; + callbacks[callbackId].called = true; + }; + + var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), + callbackId, function(status, text) { + completeRequest(callback, status, callbacks[callbackId].data, "", text); + callbacks[callbackId] = noop; + }); + } else { + + var xhr = createXhr(); + + xhr.open(method, url, true); + forEach(headers, function(value, key) { + if (isDefined(value)) { + xhr.setRequestHeader(key, value); + } + }); + + xhr.onload = function requestLoaded() { + var statusText = xhr.statusText || ''; + + // responseText is the old-school way of retrieving response (supported by IE8 & 9) + // response/responseType properties were introduced in XHR Level2 spec (supported by IE10) + var response = ('response' in xhr) ? xhr.response : xhr.responseText; + + // normalize IE9 bug (http://bugs.jquery.com/ticket/1450) + var status = xhr.status === 1223 ? 204 : xhr.status; + + // fix status code when it is 0 (0 status is undocumented). + // Occurs when accessing file resources or on Android 4.1 stock browser + // while retrieving files from application cache. + if (status === 0) { + status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0; + } + + completeRequest(callback, + status, + response, + xhr.getAllResponseHeaders(), + statusText); + }; + + var requestError = function() { + // The response is always empty + // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error + completeRequest(callback, -1, null, null, ''); + }; + + xhr.onerror = requestError; + xhr.onabort = requestError; + + if (withCredentials) { + xhr.withCredentials = true; + } + + if (responseType) { + try { + xhr.responseType = responseType; + } catch (e) { + // WebKit added support for the json responseType value on 09/03/2013 + // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are + // known to throw when setting the value "json" as the response type. Other older + // browsers implementing the responseType + // + // The json response type can be ignored if not supported, because JSON payloads are + // parsed on the client-side regardless. + if (responseType !== 'json') { + throw e; + } + } + } + + xhr.send(post || null); + } + + if (timeout > 0) { + var timeoutId = $browserDefer(timeoutRequest, timeout); + } else if (isPromiseLike(timeout)) { + timeout.then(timeoutRequest); + } + + + function timeoutRequest() { + jsonpDone && jsonpDone(); + xhr && xhr.abort(); + } + + function completeRequest(callback, status, response, headersString, statusText) { + // cancel timeout and subsequent timeout promise resolution + if (timeoutId !== undefined) { + $browserDefer.cancel(timeoutId); + } + jsonpDone = xhr = null; + + callback(status, response, headersString, statusText); + $browser.$$completeOutstandingRequest(noop); + } + }; + + function jsonpReq(url, callbackId, done) { + // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.: + // - fetches local scripts via XHR and evals them + // - adds and immediately removes script elements from the document + var script = rawDocument.createElement('script'), callback = null; + script.type = "text/javascript"; + script.src = url; + script.async = true; + + callback = function(event) { + removeEventListenerFn(script, "load", callback); + removeEventListenerFn(script, "error", callback); + rawDocument.body.removeChild(script); + script = null; + var status = -1; + var text = "unknown"; + + if (event) { + if (event.type === "load" && !callbacks[callbackId].called) { + event = { type: "error" }; + } + text = event.type; + status = event.type === "error" ? 404 : 200; + } + + if (done) { + done(status, text); + } + }; + + addEventListenerFn(script, "load", callback); + addEventListenerFn(script, "error", callback); + rawDocument.body.appendChild(script); + return callback; + } +} + +var $interpolateMinErr = minErr('$interpolate'); + +/** + * @ngdoc provider + * @name $interpolateProvider + * + * @description + * + * Used for configuring the interpolation markup. Defaults to `{{` and `}}`. + * + * @example + + + +
    + //demo.label// +
    +
    + + it('should interpolate binding with custom symbols', function() { + expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.'); + }); + +
    + */ +function $InterpolateProvider() { + var startSymbol = '{{'; + var endSymbol = '}}'; + + /** + * @ngdoc method + * @name $interpolateProvider#startSymbol + * @description + * Symbol to denote start of expression in the interpolated string. Defaults to `{{`. + * + * @param {string=} value new value to set the starting symbol to. + * @returns {string|self} Returns the symbol when used as getter and self if used as setter. + */ + this.startSymbol = function(value) { + if (value) { + startSymbol = value; + return this; + } else { + return startSymbol; + } + }; + + /** + * @ngdoc method + * @name $interpolateProvider#endSymbol + * @description + * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. + * + * @param {string=} value new value to set the ending symbol to. + * @returns {string|self} Returns the symbol when used as getter and self if used as setter. + */ + this.endSymbol = function(value) { + if (value) { + endSymbol = value; + return this; + } else { + return endSymbol; + } + }; + + + this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) { + var startSymbolLength = startSymbol.length, + endSymbolLength = endSymbol.length, + escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'), + escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g'); + + function escape(ch) { + return '\\\\\\' + ch; + } + + /** + * @ngdoc service + * @name $interpolate + * @kind function + * + * @requires $parse + * @requires $sce + * + * @description + * + * Compiles a string with markup into an interpolation function. This service is used by the + * HTML {@link ng.$compile $compile} service for data binding. See + * {@link ng.$interpolateProvider $interpolateProvider} for configuring the + * interpolation markup. + * + * + * ```js + * var $interpolate = ...; // injected + * var exp = $interpolate('Hello {{name | uppercase}}!'); + * expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!'); + * ``` + * + * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is + * `true`, the interpolation function will return `undefined` unless all embedded expressions + * evaluate to a value other than `undefined`. + * + * ```js + * var $interpolate = ...; // injected + * var context = {greeting: 'Hello', name: undefined }; + * + * // default "forgiving" mode + * var exp = $interpolate('{{greeting}} {{name}}!'); + * expect(exp(context)).toEqual('Hello !'); + * + * // "allOrNothing" mode + * exp = $interpolate('{{greeting}} {{name}}!', false, null, true); + * expect(exp(context)).toBeUndefined(); + * context.name = 'Angular'; + * expect(exp(context)).toEqual('Hello Angular!'); + * ``` + * + * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior. + * + * ####Escaped Interpolation + * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers + * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash). + * It will be rendered as a regular start/end marker, and will not be interpreted as an expression + * or binding. + * + * This enables web-servers to prevent script injection attacks and defacing attacks, to some + * degree, while also enabling code examples to work without relying on the + * {@link ng.directive:ngNonBindable ngNonBindable} directive. + * + * **For security purposes, it is strongly encouraged that web servers escape user-supplied data, + * replacing angle brackets (<, >) with &lt; and &gt; respectively, and replacing all + * interpolation start/end markers with their escaped counterparts.** + * + * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered + * output when the $interpolate service processes the text. So, for HTML elements interpolated + * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter + * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such, + * this is typically useful only when user-data is used in rendering a template from the server, or + * when otherwise untrusted data is used by a directive. + * + * + * + *
    + *

    {{apptitle}}: \{\{ username = "defaced value"; \}\} + *

    + *

    {{username}} attempts to inject code which will deface the + * application, but fails to accomplish their task, because the server has correctly + * escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash) + * characters.

    + *

    Instead, the result of the attempted script injection is visible, and can be removed + * from the database by an administrator.

    + *
    + *
    + *
    + * + * @param {string} text The text with markup to interpolate. + * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have + * embedded expression in order to return an interpolation function. Strings with no + * embedded expression will return null for the interpolation function. + * @param {string=} trustedContext when provided, the returned function passes the interpolated + * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult, + * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that + * provides Strict Contextual Escaping for details. + * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined + * unless all embedded expressions evaluate to a value other than `undefined`. + * @returns {function(context)} an interpolation function which is used to compute the + * interpolated string. The function has these parameters: + * + * - `context`: evaluation context for all expressions embedded in the interpolated text + */ + function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) { + allOrNothing = !!allOrNothing; + var startIndex, + endIndex, + index = 0, + expressions = [], + parseFns = [], + textLength = text.length, + exp, + concat = [], + expressionPositions = []; + + while (index < textLength) { + if (((startIndex = text.indexOf(startSymbol, index)) != -1) && + ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) { + if (index !== startIndex) { + concat.push(unescapeText(text.substring(index, startIndex))); + } + exp = text.substring(startIndex + startSymbolLength, endIndex); + expressions.push(exp); + parseFns.push($parse(exp, parseStringifyInterceptor)); + index = endIndex + endSymbolLength; + expressionPositions.push(concat.length); + concat.push(''); + } else { + // we did not find an interpolation, so we have to add the remainder to the separators array + if (index !== textLength) { + concat.push(unescapeText(text.substring(index))); + } + break; + } + } + + // Concatenating expressions makes it hard to reason about whether some combination of + // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a + // single expression be used for iframe[src], object[src], etc., we ensure that the value + // that's used is assigned or constructed by some JS code somewhere that is more testable or + // make it obvious that you bound the value to some user controlled value. This helps reduce + // the load when auditing for XSS issues. + if (trustedContext && concat.length > 1) { + throw $interpolateMinErr('noconcat', + "Error while interpolating: {0}\nStrict Contextual Escaping disallows " + + "interpolations that concatenate multiple expressions when a trusted value is " + + "required. See http://docs.angularjs.org/api/ng.$sce", text); + } + + if (!mustHaveExpression || expressions.length) { + var compute = function(values) { + for (var i = 0, ii = expressions.length; i < ii; i++) { + if (allOrNothing && isUndefined(values[i])) return; + concat[expressionPositions[i]] = values[i]; + } + return concat.join(''); + }; + + var getValue = function(value) { + return trustedContext ? + $sce.getTrusted(trustedContext, value) : + $sce.valueOf(value); + }; + + var stringify = function(value) { + if (value == null) { // null || undefined + return ''; + } + switch (typeof value) { + case 'string': + break; + case 'number': + value = '' + value; + break; + default: + value = toJson(value); + } + + return value; + }; + + return extend(function interpolationFn(context) { + var i = 0; + var ii = expressions.length; + var values = new Array(ii); + + try { + for (; i < ii; i++) { + values[i] = parseFns[i](context); + } + + return compute(values); + } catch (err) { + var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, + err.toString()); + $exceptionHandler(newErr); + } + + }, { + // all of these properties are undocumented for now + exp: text, //just for compatibility with regular watchers created via $watch + expressions: expressions, + $$watchDelegate: function(scope, listener, objectEquality) { + var lastValue; + return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) { + var currValue = compute(values); + if (isFunction(listener)) { + listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope); + } + lastValue = currValue; + }, objectEquality); + } + }); + } + + function unescapeText(text) { + return text.replace(escapedStartRegexp, startSymbol). + replace(escapedEndRegexp, endSymbol); + } + + function parseStringifyInterceptor(value) { + try { + value = getValue(value); + return allOrNothing && !isDefined(value) ? value : stringify(value); + } catch (err) { + var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, + err.toString()); + $exceptionHandler(newErr); + } + } + } + + + /** + * @ngdoc method + * @name $interpolate#startSymbol + * @description + * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`. + * + * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change + * the symbol. + * + * @returns {string} start symbol. + */ + $interpolate.startSymbol = function() { + return startSymbol; + }; + + + /** + * @ngdoc method + * @name $interpolate#endSymbol + * @description + * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`. + * + * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change + * the symbol. + * + * @returns {string} end symbol. + */ + $interpolate.endSymbol = function() { + return endSymbol; + }; + + return $interpolate; + }]; +} + +function $IntervalProvider() { + this.$get = ['$rootScope', '$window', '$q', '$$q', + function($rootScope, $window, $q, $$q) { + var intervals = {}; + + + /** + * @ngdoc service + * @name $interval + * + * @description + * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay` + * milliseconds. + * + * The return value of registering an interval function is a promise. This promise will be + * notified upon each tick of the interval, and will be resolved after `count` iterations, or + * run indefinitely if `count` is not defined. The value of the notification will be the + * number of iterations that have run. + * To cancel an interval, call `$interval.cancel(promise)`. + * + * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to + * move forward by `millis` milliseconds and trigger any functions scheduled to run in that + * time. + * + *
    + * **Note**: Intervals created by this service must be explicitly destroyed when you are finished + * with them. In particular they are not automatically destroyed when a controller's scope or a + * directive's element are destroyed. + * You should take this into consideration and make sure to always cancel the interval at the + * appropriate moment. See the example below for more details on how and when to do this. + *
    + * + * @param {function()} fn A function that should be called repeatedly. + * @param {number} delay Number of milliseconds between each function call. + * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat + * indefinitely. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @returns {promise} A promise which will be notified on each iteration. + * + * @example + * + * + * + * + *
    + *
    + * Date format:
    + * Current time is: + *
    + * Blood 1 : {{blood_1}} + * Blood 2 : {{blood_2}} + * + * + * + *
    + *
    + * + *
    + *
    + */ + function interval(fn, delay, count, invokeApply) { + var setInterval = $window.setInterval, + clearInterval = $window.clearInterval, + iteration = 0, + skipApply = (isDefined(invokeApply) && !invokeApply), + deferred = (skipApply ? $$q : $q).defer(), + promise = deferred.promise; + + count = isDefined(count) ? count : 0; + + promise.then(null, null, fn); + + promise.$$intervalId = setInterval(function tick() { + deferred.notify(iteration++); + + if (count > 0 && iteration >= count) { + deferred.resolve(iteration); + clearInterval(promise.$$intervalId); + delete intervals[promise.$$intervalId]; + } + + if (!skipApply) $rootScope.$apply(); + + }, delay); + + intervals[promise.$$intervalId] = deferred; + + return promise; + } + + + /** + * @ngdoc method + * @name $interval#cancel + * + * @description + * Cancels a task associated with the `promise`. + * + * @param {promise} promise returned by the `$interval` function. + * @returns {boolean} Returns `true` if the task was successfully canceled. + */ + interval.cancel = function(promise) { + if (promise && promise.$$intervalId in intervals) { + intervals[promise.$$intervalId].reject('canceled'); + $window.clearInterval(promise.$$intervalId); + delete intervals[promise.$$intervalId]; + return true; + } + return false; + }; + + return interval; + }]; +} + +/** + * @ngdoc service + * @name $locale + * + * @description + * $locale service provides localization rules for various Angular components. As of right now the + * only public api is: + * + * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`) + */ +function $LocaleProvider() { + this.$get = function() { + return { + id: 'en-us', + + NUMBER_FORMATS: { + DECIMAL_SEP: '.', + GROUP_SEP: ',', + PATTERNS: [ + { // Decimal Pattern + minInt: 1, + minFrac: 0, + maxFrac: 3, + posPre: '', + posSuf: '', + negPre: '-', + negSuf: '', + gSize: 3, + lgSize: 3 + },{ //Currency Pattern + minInt: 1, + minFrac: 2, + maxFrac: 2, + posPre: '\u00A4', + posSuf: '', + negPre: '(\u00A4', + negSuf: ')', + gSize: 3, + lgSize: 3 + } + ], + CURRENCY_SYM: '$' + }, + + DATETIME_FORMATS: { + MONTH: + 'January,February,March,April,May,June,July,August,September,October,November,December' + .split(','), + SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','), + DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','), + SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','), + AMPMS: ['AM','PM'], + medium: 'MMM d, y h:mm:ss a', + 'short': 'M/d/yy h:mm a', + fullDate: 'EEEE, MMMM d, y', + longDate: 'MMMM d, y', + mediumDate: 'MMM d, y', + shortDate: 'M/d/yy', + mediumTime: 'h:mm:ss a', + shortTime: 'h:mm a' + }, + + pluralCat: function(num) { + if (num === 1) { + return 'one'; + } + return 'other'; + } + }; + }; +} + +var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/, + DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21}; +var $locationMinErr = minErr('$location'); + + +/** + * Encode path using encodeUriSegment, ignoring forward slashes + * + * @param {string} path Path to encode + * @returns {string} + */ +function encodePath(path) { + var segments = path.split('/'), + i = segments.length; + + while (i--) { + segments[i] = encodeUriSegment(segments[i]); + } + + return segments.join('/'); +} + +function parseAbsoluteUrl(absoluteUrl, locationObj) { + var parsedUrl = urlResolve(absoluteUrl); + + locationObj.$$protocol = parsedUrl.protocol; + locationObj.$$host = parsedUrl.hostname; + locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null; +} + + +function parseAppUrl(relativeUrl, locationObj) { + var prefixed = (relativeUrl.charAt(0) !== '/'); + if (prefixed) { + relativeUrl = '/' + relativeUrl; + } + var match = urlResolve(relativeUrl); + locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? + match.pathname.substring(1) : match.pathname); + locationObj.$$search = parseKeyValue(match.search); + locationObj.$$hash = decodeURIComponent(match.hash); + + // make sure path starts with '/'; + if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') { + locationObj.$$path = '/' + locationObj.$$path; + } +} + + +/** + * + * @param {string} begin + * @param {string} whole + * @returns {string} returns text from whole after begin or undefined if it does not begin with + * expected string. + */ +function beginsWith(begin, whole) { + if (whole.indexOf(begin) === 0) { + return whole.substr(begin.length); + } +} + + +function stripHash(url) { + var index = url.indexOf('#'); + return index == -1 ? url : url.substr(0, index); +} + +function trimEmptyHash(url) { + return url.replace(/(#.+)|#$/, '$1'); +} + + +function stripFile(url) { + return url.substr(0, stripHash(url).lastIndexOf('/') + 1); +} + +/* return the server only (scheme://host:port) */ +function serverBase(url) { + return url.substring(0, url.indexOf('/', url.indexOf('//') + 2)); +} + + +/** + * LocationHtml5Url represents an url + * This object is exposed as $location service when HTML5 mode is enabled and supported + * + * @constructor + * @param {string} appBase application base URL + * @param {string} basePrefix url path prefix + */ +function LocationHtml5Url(appBase, basePrefix) { + this.$$html5 = true; + basePrefix = basePrefix || ''; + var appBaseNoFile = stripFile(appBase); + parseAbsoluteUrl(appBase, this); + + + /** + * Parse given html5 (regular) url string into properties + * @param {string} url HTML5 url + * @private + */ + this.$$parse = function(url) { + var pathUrl = beginsWith(appBaseNoFile, url); + if (!isString(pathUrl)) { + throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, + appBaseNoFile); + } + + parseAppUrl(pathUrl, this); + + if (!this.$$path) { + this.$$path = '/'; + } + + this.$$compose(); + }; + + /** + * Compose url and update `absUrl` property + * @private + */ + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/' + }; + + this.$$parseLinkUrl = function(url, relHref) { + if (relHref && relHref[0] === '#') { + // special case for links to hash fragments: + // keep the old url and only replace the hash fragment + this.hash(relHref.slice(1)); + return true; + } + var appUrl, prevAppUrl; + var rewrittenUrl; + + if ((appUrl = beginsWith(appBase, url)) !== undefined) { + prevAppUrl = appUrl; + if ((appUrl = beginsWith(basePrefix, appUrl)) !== undefined) { + rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl); + } else { + rewrittenUrl = appBase + prevAppUrl; + } + } else if ((appUrl = beginsWith(appBaseNoFile, url)) !== undefined) { + rewrittenUrl = appBaseNoFile + appUrl; + } else if (appBaseNoFile == url + '/') { + rewrittenUrl = appBaseNoFile; + } + if (rewrittenUrl) { + this.$$parse(rewrittenUrl); + } + return !!rewrittenUrl; + }; +} + + +/** + * LocationHashbangUrl represents url + * This object is exposed as $location service when developer doesn't opt into html5 mode. + * It also serves as the base class for html5 mode fallback on legacy browsers. + * + * @constructor + * @param {string} appBase application base URL + * @param {string} hashPrefix hashbang prefix + */ +function LocationHashbangUrl(appBase, hashPrefix) { + var appBaseNoFile = stripFile(appBase); + + parseAbsoluteUrl(appBase, this); + + + /** + * Parse given hashbang url into properties + * @param {string} url Hashbang url + * @private + */ + this.$$parse = function(url) { + var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url); + var withoutHashUrl; + + if (withoutBaseUrl.charAt(0) === '#') { + + // The rest of the url starts with a hash so we have + // got either a hashbang path or a plain hash fragment + withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl); + if (isUndefined(withoutHashUrl)) { + // There was no hashbang prefix so we just have a hash fragment + withoutHashUrl = withoutBaseUrl; + } + + } else { + // There was no hashbang path nor hash fragment: + // If we are in HTML5 mode we use what is left as the path; + // Otherwise we ignore what is left + withoutHashUrl = this.$$html5 ? withoutBaseUrl : ''; + } + + parseAppUrl(withoutHashUrl, this); + + this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); + + this.$$compose(); + + /* + * In Windows, on an anchor node on documents loaded from + * the filesystem, the browser will return a pathname + * prefixed with the drive name ('/C:/path') when a + * pathname without a drive is set: + * * a.setAttribute('href', '/foo') + * * a.pathname === '/C:/foo' //true + * + * Inside of Angular, we're always using pathnames that + * do not include drive names for routing. + */ + function removeWindowsDriveName(path, url, base) { + /* + Matches paths for file protocol on windows, + such as /C:/foo/bar, and captures only /foo/bar. + */ + var windowsFilePathExp = /^\/[A-Z]:(\/.*)/; + + var firstPathSegmentMatch; + + //Get the relative path from the input URL. + if (url.indexOf(base) === 0) { + url = url.replace(base, ''); + } + + // The input URL intentionally contains a first path segment that ends with a colon. + if (windowsFilePathExp.exec(url)) { + return path; + } + + firstPathSegmentMatch = windowsFilePathExp.exec(path); + return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path; + } + }; + + /** + * Compose hashbang url and update `absUrl` property + * @private + */ + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : ''); + }; + + this.$$parseLinkUrl = function(url, relHref) { + if (stripHash(appBase) == stripHash(url)) { + this.$$parse(url); + return true; + } + return false; + }; +} + + +/** + * LocationHashbangUrl represents url + * This object is exposed as $location service when html5 history api is enabled but the browser + * does not support it. + * + * @constructor + * @param {string} appBase application base URL + * @param {string} hashPrefix hashbang prefix + */ +function LocationHashbangInHtml5Url(appBase, hashPrefix) { + this.$$html5 = true; + LocationHashbangUrl.apply(this, arguments); + + var appBaseNoFile = stripFile(appBase); + + this.$$parseLinkUrl = function(url, relHref) { + if (relHref && relHref[0] === '#') { + // special case for links to hash fragments: + // keep the old url and only replace the hash fragment + this.hash(relHref.slice(1)); + return true; + } + + var rewrittenUrl; + var appUrl; + + if (appBase == stripHash(url)) { + rewrittenUrl = url; + } else if ((appUrl = beginsWith(appBaseNoFile, url))) { + rewrittenUrl = appBase + hashPrefix + appUrl; + } else if (appBaseNoFile === url + '/') { + rewrittenUrl = appBaseNoFile; + } + if (rewrittenUrl) { + this.$$parse(rewrittenUrl); + } + return !!rewrittenUrl; + }; + + this.$$compose = function() { + var search = toKeyValue(this.$$search), + hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : ''; + + this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash; + // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#' + this.$$absUrl = appBase + hashPrefix + this.$$url; + }; + +} + + +var locationPrototype = { + + /** + * Are we in html5 mode? + * @private + */ + $$html5: false, + + /** + * Has any change been replacing? + * @private + */ + $$replace: false, + + /** + * @ngdoc method + * @name $location#absUrl + * + * @description + * This method is getter only. + * + * Return full url representation with all segments encoded according to rules specified in + * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt). + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var absUrl = $location.absUrl(); + * // => "http://example.com/#/some/path?foo=bar&baz=xoxo" + * ``` + * + * @return {string} full url + */ + absUrl: locationGetter('$$absUrl'), + + /** + * @ngdoc method + * @name $location#url + * + * @description + * This method is getter / setter. + * + * Return url (e.g. `/path?a=b#hash`) when called without any parameter. + * + * Change path, search and hash, when called with parameter and return `$location`. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var url = $location.url(); + * // => "/some/path?foo=bar&baz=xoxo" + * ``` + * + * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`) + * @return {string} url + */ + url: function(url) { + if (isUndefined(url)) + return this.$$url; + + var match = PATH_MATCH.exec(url); + if (match[1] || url === '') this.path(decodeURIComponent(match[1])); + if (match[2] || match[1] || url === '') this.search(match[3] || ''); + this.hash(match[5] || ''); + + return this; + }, + + /** + * @ngdoc method + * @name $location#protocol + * + * @description + * This method is getter only. + * + * Return protocol of current url. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var protocol = $location.protocol(); + * // => "http" + * ``` + * + * @return {string} protocol of current url + */ + protocol: locationGetter('$$protocol'), + + /** + * @ngdoc method + * @name $location#host + * + * @description + * This method is getter only. + * + * Return host of current url. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var host = $location.host(); + * // => "example.com" + * ``` + * + * @return {string} host of current url. + */ + host: locationGetter('$$host'), + + /** + * @ngdoc method + * @name $location#port + * + * @description + * This method is getter only. + * + * Return port of current url. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var port = $location.port(); + * // => 80 + * ``` + * + * @return {Number} port + */ + port: locationGetter('$$port'), + + /** + * @ngdoc method + * @name $location#path + * + * @description + * This method is getter / setter. + * + * Return path of current url when called without any parameter. + * + * Change path when called with parameter and return `$location`. + * + * Note: Path should always begin with forward slash (/), this method will add the forward slash + * if it is missing. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var path = $location.path(); + * // => "/some/path" + * ``` + * + * @param {(string|number)=} path New path + * @return {string} path + */ + path: locationGetterSetter('$$path', function(path) { + path = path !== null ? path.toString() : ''; + return path.charAt(0) == '/' ? path : '/' + path; + }), + + /** + * @ngdoc method + * @name $location#search + * + * @description + * This method is getter / setter. + * + * Return search part (as object) of current url when called without any parameter. + * + * Change search part when called with parameter and return `$location`. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo + * var searchObject = $location.search(); + * // => {foo: 'bar', baz: 'xoxo'} + * + * // set foo to 'yipee' + * $location.search('foo', 'yipee'); + * // $location.search() => {foo: 'yipee', baz: 'xoxo'} + * ``` + * + * @param {string|Object.|Object.>} search New search params - string or + * hash object. + * + * When called with a single argument the method acts as a setter, setting the `search` component + * of `$location` to the specified value. + * + * If the argument is a hash object containing an array of values, these values will be encoded + * as duplicate search parameters in the url. + * + * @param {(string|Number|Array|boolean)=} paramValue If `search` is a string or number, then `paramValue` + * will override only a single search property. + * + * If `paramValue` is an array, it will override the property of the `search` component of + * `$location` specified via the first argument. + * + * If `paramValue` is `null`, the property specified via the first argument will be deleted. + * + * If `paramValue` is `true`, the property specified via the first argument will be added with no + * value nor trailing equal sign. + * + * @return {Object} If called with no arguments returns the parsed `search` object. If called with + * one or more arguments returns `$location` object itself. + */ + search: function(search, paramValue) { + switch (arguments.length) { + case 0: + return this.$$search; + case 1: + if (isString(search) || isNumber(search)) { + search = search.toString(); + this.$$search = parseKeyValue(search); + } else if (isObject(search)) { + search = copy(search, {}); + // remove object undefined or null properties + forEach(search, function(value, key) { + if (value == null) delete search[key]; + }); + + this.$$search = search; + } else { + throw $locationMinErr('isrcharg', + 'The first argument of the `$location#search()` call must be a string or an object.'); + } + break; + default: + if (isUndefined(paramValue) || paramValue === null) { + delete this.$$search[search]; + } else { + this.$$search[search] = paramValue; + } + } + + this.$$compose(); + return this; + }, + + /** + * @ngdoc method + * @name $location#hash + * + * @description + * This method is getter / setter. + * + * Return hash fragment when called without any parameter. + * + * Change hash fragment when called with parameter and return `$location`. + * + * + * ```js + * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue + * var hash = $location.hash(); + * // => "hashValue" + * ``` + * + * @param {(string|number)=} hash New hash fragment + * @return {string} hash + */ + hash: locationGetterSetter('$$hash', function(hash) { + return hash !== null ? hash.toString() : ''; + }), + + /** + * @ngdoc method + * @name $location#replace + * + * @description + * If called, all changes to $location during current `$digest` will be replacing current history + * record, instead of adding new one. + */ + replace: function() { + this.$$replace = true; + return this; + } +}; + +forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) { + Location.prototype = Object.create(locationPrototype); + + /** + * @ngdoc method + * @name $location#state + * + * @description + * This method is getter / setter. + * + * Return the history state object when called without any parameter. + * + * Change the history state object when called with one parameter and return `$location`. + * The state object is later passed to `pushState` or `replaceState`. + * + * NOTE: This method is supported only in HTML5 mode and only in browsers supporting + * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support + * older browsers (like IE9 or Android < 4.0), don't use this method. + * + * @param {object=} state State object for pushState or replaceState + * @return {object} state + */ + Location.prototype.state = function(state) { + if (!arguments.length) + return this.$$state; + + if (Location !== LocationHtml5Url || !this.$$html5) { + throw $locationMinErr('nostate', 'History API state support is available only ' + + 'in HTML5 mode and only in browsers supporting HTML5 History API'); + } + // The user might modify `stateObject` after invoking `$location.state(stateObject)` + // but we're changing the $$state reference to $browser.state() during the $digest + // so the modification window is narrow. + this.$$state = isUndefined(state) ? null : state; + + return this; + }; +}); + + +function locationGetter(property) { + return function() { + return this[property]; + }; +} + + +function locationGetterSetter(property, preprocess) { + return function(value) { + if (isUndefined(value)) + return this[property]; + + this[property] = preprocess(value); + this.$$compose(); + + return this; + }; +} + + +/** + * @ngdoc service + * @name $location + * + * @requires $rootElement + * + * @description + * The $location service parses the URL in the browser address bar (based on the + * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL + * available to your application. Changes to the URL in the address bar are reflected into + * $location service and changes to $location are reflected into the browser address bar. + * + * **The $location service:** + * + * - Exposes the current URL in the browser address bar, so you can + * - Watch and observe the URL. + * - Change the URL. + * - Synchronizes the URL with the browser when the user + * - Changes the address bar. + * - Clicks the back or forward button (or clicks a History link). + * - Clicks on a link. + * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash). + * + * For more information see {@link guide/$location Developer Guide: Using $location} + */ + +/** + * @ngdoc provider + * @name $locationProvider + * @description + * Use the `$locationProvider` to configure how the application deep linking paths are stored. + */ +function $LocationProvider() { + var hashPrefix = '', + html5Mode = { + enabled: false, + requireBase: true, + rewriteLinks: true + }; + + /** + * @ngdoc method + * @name $locationProvider#hashPrefix + * @description + * @param {string=} prefix Prefix for hash part (containing path and search) + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.hashPrefix = function(prefix) { + if (isDefined(prefix)) { + hashPrefix = prefix; + return this; + } else { + return hashPrefix; + } + }; + + /** + * @ngdoc method + * @name $locationProvider#html5Mode + * @description + * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value. + * If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported + * properties: + * - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to + * change urls where supported. Will fall back to hash-prefixed paths in browsers that do not + * support `pushState`. + * - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies + * whether or not a tag is required to be present. If `enabled` and `requireBase` are + * true, and a base tag is not present, an error will be thrown when `$location` is injected. + * See the {@link guide/$location $location guide for more information} + * - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled, + * enables/disables url rewriting for relative links. + * + * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter + */ + this.html5Mode = function(mode) { + if (isBoolean(mode)) { + html5Mode.enabled = mode; + return this; + } else if (isObject(mode)) { + + if (isBoolean(mode.enabled)) { + html5Mode.enabled = mode.enabled; + } + + if (isBoolean(mode.requireBase)) { + html5Mode.requireBase = mode.requireBase; + } + + if (isBoolean(mode.rewriteLinks)) { + html5Mode.rewriteLinks = mode.rewriteLinks; + } + + return this; + } else { + return html5Mode; + } + }; + + /** + * @ngdoc event + * @name $location#$locationChangeStart + * @eventType broadcast on root scope + * @description + * Broadcasted before a URL will change. + * + * This change can be prevented by calling + * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more + * details about event object. Upon successful change + * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired. + * + * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when + * the browser supports the HTML5 History API. + * + * @param {Object} angularEvent Synthetic event object. + * @param {string} newUrl New URL + * @param {string=} oldUrl URL that was before it was changed. + * @param {string=} newState New history state object + * @param {string=} oldState History state object that was before it was changed. + */ + + /** + * @ngdoc event + * @name $location#$locationChangeSuccess + * @eventType broadcast on root scope + * @description + * Broadcasted after a URL was changed. + * + * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when + * the browser supports the HTML5 History API. + * + * @param {Object} angularEvent Synthetic event object. + * @param {string} newUrl New URL + * @param {string=} oldUrl URL that was before it was changed. + * @param {string=} newState New history state object + * @param {string=} oldState History state object that was before it was changed. + */ + + this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window', + function($rootScope, $browser, $sniffer, $rootElement, $window) { + var $location, + LocationMode, + baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to '' + initialUrl = $browser.url(), + appBase; + + if (html5Mode.enabled) { + if (!baseHref && html5Mode.requireBase) { + throw $locationMinErr('nobase', + "$location in HTML5 mode requires a tag to be present!"); + } + appBase = serverBase(initialUrl) + (baseHref || '/'); + LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url; + } else { + appBase = stripHash(initialUrl); + LocationMode = LocationHashbangUrl; + } + $location = new LocationMode(appBase, '#' + hashPrefix); + $location.$$parseLinkUrl(initialUrl, initialUrl); + + $location.$$state = $browser.state(); + + var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i; + + function setBrowserUrlWithFallback(url, replace, state) { + var oldUrl = $location.url(); + var oldState = $location.$$state; + try { + $browser.url(url, replace, state); + + // Make sure $location.state() returns referentially identical (not just deeply equal) + // state object; this makes possible quick checking if the state changed in the digest + // loop. Checking deep equality would be too expensive. + $location.$$state = $browser.state(); + } catch (e) { + // Restore old values if pushState fails + $location.url(oldUrl); + $location.$$state = oldState; + + throw e; + } + } + + $rootElement.on('click', function(event) { + // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) + // currently we open nice url link and redirect then + + if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return; + + var elm = jqLite(event.target); + + // traverse the DOM up to find first A tag + while (nodeName_(elm[0]) !== 'a') { + // ignore rewriting if no A tag (reached root element, or no parent - removed from document) + if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return; + } + + var absHref = elm.prop('href'); + // get the actual href attribute - see + // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx + var relHref = elm.attr('href') || elm.attr('xlink:href'); + + if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') { + // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during + // an animation. + absHref = urlResolve(absHref.animVal).href; + } + + // Ignore when url is started with javascript: or mailto: + if (IGNORE_URI_REGEXP.test(absHref)) return; + + if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) { + if ($location.$$parseLinkUrl(absHref, relHref)) { + // We do a preventDefault for all urls that are part of the angular application, + // in html5mode and also without, so that we are able to abort navigation without + // getting double entries in the location history. + event.preventDefault(); + // update location manually + if ($location.absUrl() != $browser.url()) { + $rootScope.$apply(); + // hack to work around FF6 bug 684208 when scenario runner clicks on links + $window.angular['ff-684208-preventDefault'] = true; + } + } + } + }); + + + // rewrite hashbang url <> html5 url + if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) { + $browser.url($location.absUrl(), true); + } + + var initializing = true; + + // update $location when $browser url changes + $browser.onUrlChange(function(newUrl, newState) { + $rootScope.$evalAsync(function() { + var oldUrl = $location.absUrl(); + var oldState = $location.$$state; + var defaultPrevented; + + $location.$$parse(newUrl); + $location.$$state = newState; + + defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, + newState, oldState).defaultPrevented; + + // if the location was changed by a `$locationChangeStart` handler then stop + // processing this location change + if ($location.absUrl() !== newUrl) return; + + if (defaultPrevented) { + $location.$$parse(oldUrl); + $location.$$state = oldState; + setBrowserUrlWithFallback(oldUrl, false, oldState); + } else { + initializing = false; + afterLocationChange(oldUrl, oldState); + } + }); + if (!$rootScope.$$phase) $rootScope.$digest(); + }); + + // update browser + $rootScope.$watch(function $locationWatch() { + var oldUrl = trimEmptyHash($browser.url()); + var newUrl = trimEmptyHash($location.absUrl()); + var oldState = $browser.state(); + var currentReplace = $location.$$replace; + var urlOrStateChanged = oldUrl !== newUrl || + ($location.$$html5 && $sniffer.history && oldState !== $location.$$state); + + if (initializing || urlOrStateChanged) { + initializing = false; + + $rootScope.$evalAsync(function() { + var newUrl = $location.absUrl(); + var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl, + $location.$$state, oldState).defaultPrevented; + + // if the location was changed by a `$locationChangeStart` handler then stop + // processing this location change + if ($location.absUrl() !== newUrl) return; + + if (defaultPrevented) { + $location.$$parse(oldUrl); + $location.$$state = oldState; + } else { + if (urlOrStateChanged) { + setBrowserUrlWithFallback(newUrl, currentReplace, + oldState === $location.$$state ? null : $location.$$state); + } + afterLocationChange(oldUrl, oldState); + } + }); + } + + $location.$$replace = false; + + // we don't need to return anything because $evalAsync will make the digest loop dirty when + // there is a change + }); + + return $location; + + function afterLocationChange(oldUrl, oldState) { + $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl, + $location.$$state, oldState); + } +}]; +} + +/** + * @ngdoc service + * @name $log + * @requires $window + * + * @description + * Simple service for logging. Default implementation safely writes the message + * into the browser's console (if present). + * + * The main purpose of this service is to simplify debugging and troubleshooting. + * + * The default is to log `debug` messages. You can use + * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this. + * + * @example + + + angular.module('logExample', []) + .controller('LogController', ['$scope', '$log', function($scope, $log) { + $scope.$log = $log; + $scope.message = 'Hello World!'; + }]); + + +
    +

    Reload this page with open console, enter text and hit the log button...

    + Message: + + + + + +
    +
    +
    + */ + +/** + * @ngdoc provider + * @name $logProvider + * @description + * Use the `$logProvider` to configure how the application logs messages + */ +function $LogProvider() { + var debug = true, + self = this; + + /** + * @ngdoc method + * @name $logProvider#debugEnabled + * @description + * @param {boolean=} flag enable or disable debug level messages + * @returns {*} current value if used as getter or itself (chaining) if used as setter + */ + this.debugEnabled = function(flag) { + if (isDefined(flag)) { + debug = flag; + return this; + } else { + return debug; + } + }; + + this.$get = ['$window', function($window) { + return { + /** + * @ngdoc method + * @name $log#log + * + * @description + * Write a log message + */ + log: consoleLog('log'), + + /** + * @ngdoc method + * @name $log#info + * + * @description + * Write an information message + */ + info: consoleLog('info'), + + /** + * @ngdoc method + * @name $log#warn + * + * @description + * Write a warning message + */ + warn: consoleLog('warn'), + + /** + * @ngdoc method + * @name $log#error + * + * @description + * Write an error message + */ + error: consoleLog('error'), + + /** + * @ngdoc method + * @name $log#debug + * + * @description + * Write a debug message + */ + debug: (function() { + var fn = consoleLog('debug'); + + return function() { + if (debug) { + fn.apply(self, arguments); + } + }; + }()) + }; + + function formatError(arg) { + if (arg instanceof Error) { + if (arg.stack) { + arg = (arg.message && arg.stack.indexOf(arg.message) === -1) + ? 'Error: ' + arg.message + '\n' + arg.stack + : arg.stack; + } else if (arg.sourceURL) { + arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line; + } + } + return arg; + } + + function consoleLog(type) { + var console = $window.console || {}, + logFn = console[type] || console.log || noop, + hasApply = false; + + // Note: reading logFn.apply throws an error in IE11 in IE8 document mode. + // The reason behind this is that console.log has type "object" in IE8... + try { + hasApply = !!logFn.apply; + } catch (e) {} + + if (hasApply) { + return function() { + var args = []; + forEach(arguments, function(arg) { + args.push(formatError(arg)); + }); + return logFn.apply(console, args); + }; + } + + // we are IE which either doesn't have window.console => this is noop and we do nothing, + // or we are IE where console.log doesn't have apply so we log at least first 2 args + return function(arg1, arg2) { + logFn(arg1, arg2 == null ? '' : arg2); + }; + } + }]; +} + +var $parseMinErr = minErr('$parse'); + +// Sandboxing Angular Expressions +// ------------------------------ +// Angular expressions are generally considered safe because these expressions only have direct +// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by +// obtaining a reference to native JS functions such as the Function constructor. +// +// As an example, consider the following Angular expression: +// +// {}.toString.constructor('alert("evil JS code")') +// +// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits +// against the expression language, but not to prevent exploits that were enabled by exposing +// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good +// practice and therefore we are not even trying to protect against interaction with an object +// explicitly exposed in this way. +// +// In general, it is not possible to access a Window object from an angular expression unless a +// window or some DOM object that has a reference to window is published onto a Scope. +// Similarly we prevent invocations of function known to be dangerous, as well as assignments to +// native objects. +// +// See https://docs.angularjs.org/guide/security + + +function ensureSafeMemberName(name, fullExpression) { + if (name === "__defineGetter__" || name === "__defineSetter__" + || name === "__lookupGetter__" || name === "__lookupSetter__" + || name === "__proto__") { + throw $parseMinErr('isecfld', + 'Attempting to access a disallowed field in Angular expressions! ' + + 'Expression: {0}', fullExpression); + } + return name; +} + +function ensureSafeObject(obj, fullExpression) { + // nifty check if obj is Function that is fast and works across iframes and other contexts + if (obj) { + if (obj.constructor === obj) { + throw $parseMinErr('isecfn', + 'Referencing Function in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isWindow(obj) + obj.window === obj) { + throw $parseMinErr('isecwindow', + 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// isElement(obj) + obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) { + throw $parseMinErr('isecdom', + 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (// block Object so that we can't get hold of dangerous Object.* methods + obj === Object) { + throw $parseMinErr('isecobj', + 'Referencing Object in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } + } + return obj; +} + +var CALL = Function.prototype.call; +var APPLY = Function.prototype.apply; +var BIND = Function.prototype.bind; + +function ensureSafeFunction(obj, fullExpression) { + if (obj) { + if (obj.constructor === obj) { + throw $parseMinErr('isecfn', + 'Referencing Function in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } else if (obj === CALL || obj === APPLY || obj === BIND) { + throw $parseMinErr('isecff', + 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}', + fullExpression); + } + } +} + +//Keyword constants +var CONSTANTS = createMap(); +forEach({ + 'null': function() { return null; }, + 'true': function() { return true; }, + 'false': function() { return false; }, + 'undefined': function() {} +}, function(constantGetter, name) { + constantGetter.constant = constantGetter.literal = constantGetter.sharedGetter = true; + CONSTANTS[name] = constantGetter; +}); + +//Not quite a constant, but can be lex/parsed the same +CONSTANTS['this'] = function(self) { return self; }; +CONSTANTS['this'].sharedGetter = true; + + +//Operators - will be wrapped by binaryFn/unaryFn/assignment/filter +var OPERATORS = extend(createMap(), { + '+':function(self, locals, a, b) { + a=a(self, locals); b=b(self, locals); + if (isDefined(a)) { + if (isDefined(b)) { + return a + b; + } + return a; + } + return isDefined(b) ? b : undefined;}, + '-':function(self, locals, a, b) { + a=a(self, locals); b=b(self, locals); + return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0); + }, + '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);}, + '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);}, + '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);}, + '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);}, + '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);}, + '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);}, + '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);}, + '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);}, + '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);}, + '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);}, + '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);}, + '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);}, + '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);}, + '!':function(self, locals, a) {return !a(self, locals);}, + + //Tokenized as operators but parsed as assignment/filters + '=':true, + '|':true +}); +var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'}; + + +///////////////////////////////////////// + + +/** + * @constructor + */ +var Lexer = function(options) { + this.options = options; +}; + +Lexer.prototype = { + constructor: Lexer, + + lex: function(text) { + this.text = text; + this.index = 0; + this.tokens = []; + + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + if (ch === '"' || ch === "'") { + this.readString(ch); + } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) { + this.readNumber(); + } else if (this.isIdent(ch)) { + this.readIdent(); + } else if (this.is(ch, '(){}[].,;:?')) { + this.tokens.push({index: this.index, text: ch}); + this.index++; + } else if (this.isWhitespace(ch)) { + this.index++; + } else { + var ch2 = ch + this.peek(); + var ch3 = ch2 + this.peek(2); + var op1 = OPERATORS[ch]; + var op2 = OPERATORS[ch2]; + var op3 = OPERATORS[ch3]; + if (op1 || op2 || op3) { + var token = op3 ? ch3 : (op2 ? ch2 : ch); + this.tokens.push({index: this.index, text: token, operator: true}); + this.index += token.length; + } else { + this.throwError('Unexpected next character ', this.index, this.index + 1); + } + } + } + return this.tokens; + }, + + is: function(ch, chars) { + return chars.indexOf(ch) !== -1; + }, + + peek: function(i) { + var num = i || 1; + return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false; + }, + + isNumber: function(ch) { + return ('0' <= ch && ch <= '9') && typeof ch === "string"; + }, + + isWhitespace: function(ch) { + // IE treats non-breaking space as \u00A0 + return (ch === ' ' || ch === '\r' || ch === '\t' || + ch === '\n' || ch === '\v' || ch === '\u00A0'); + }, + + isIdent: function(ch) { + return ('a' <= ch && ch <= 'z' || + 'A' <= ch && ch <= 'Z' || + '_' === ch || ch === '$'); + }, + + isExpOperator: function(ch) { + return (ch === '-' || ch === '+' || this.isNumber(ch)); + }, + + throwError: function(error, start, end) { + end = end || this.index; + var colStr = (isDefined(start) + ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']' + : ' ' + end); + throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].', + error, colStr, this.text); + }, + + readNumber: function() { + var number = ''; + var start = this.index; + while (this.index < this.text.length) { + var ch = lowercase(this.text.charAt(this.index)); + if (ch == '.' || this.isNumber(ch)) { + number += ch; + } else { + var peekCh = this.peek(); + if (ch == 'e' && this.isExpOperator(peekCh)) { + number += ch; + } else if (this.isExpOperator(ch) && + peekCh && this.isNumber(peekCh) && + number.charAt(number.length - 1) == 'e') { + number += ch; + } else if (this.isExpOperator(ch) && + (!peekCh || !this.isNumber(peekCh)) && + number.charAt(number.length - 1) == 'e') { + this.throwError('Invalid exponent'); + } else { + break; + } + } + this.index++; + } + this.tokens.push({ + index: start, + text: number, + constant: true, + value: Number(number) + }); + }, + + readIdent: function() { + var start = this.index; + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + if (!(this.isIdent(ch) || this.isNumber(ch))) { + break; + } + this.index++; + } + this.tokens.push({ + index: start, + text: this.text.slice(start, this.index), + identifier: true + }); + }, + + readString: function(quote) { + var start = this.index; + this.index++; + var string = ''; + var rawString = quote; + var escape = false; + while (this.index < this.text.length) { + var ch = this.text.charAt(this.index); + rawString += ch; + if (escape) { + if (ch === 'u') { + var hex = this.text.substring(this.index + 1, this.index + 5); + if (!hex.match(/[\da-f]{4}/i)) + this.throwError('Invalid unicode escape [\\u' + hex + ']'); + this.index += 4; + string += String.fromCharCode(parseInt(hex, 16)); + } else { + var rep = ESCAPE[ch]; + string = string + (rep || ch); + } + escape = false; + } else if (ch === '\\') { + escape = true; + } else if (ch === quote) { + this.index++; + this.tokens.push({ + index: start, + text: rawString, + constant: true, + value: string + }); + return; + } else { + string += ch; + } + this.index++; + } + this.throwError('Unterminated quote', start); + } +}; + + +function isConstant(exp) { + return exp.constant; +} + +/** + * @constructor + */ +var Parser = function(lexer, $filter, options) { + this.lexer = lexer; + this.$filter = $filter; + this.options = options; +}; + +Parser.ZERO = extend(function() { + return 0; +}, { + sharedGetter: true, + constant: true +}); + +Parser.prototype = { + constructor: Parser, + + parse: function(text) { + this.text = text; + this.tokens = this.lexer.lex(text); + + var value = this.statements(); + + if (this.tokens.length !== 0) { + this.throwError('is an unexpected token', this.tokens[0]); + } + + value.literal = !!value.literal; + value.constant = !!value.constant; + + return value; + }, + + primary: function() { + var primary; + if (this.expect('(')) { + primary = this.filterChain(); + this.consume(')'); + } else if (this.expect('[')) { + primary = this.arrayDeclaration(); + } else if (this.expect('{')) { + primary = this.object(); + } else if (this.peek().identifier && this.peek().text in CONSTANTS) { + primary = CONSTANTS[this.consume().text]; + } else if (this.peek().identifier) { + primary = this.identifier(); + } else if (this.peek().constant) { + primary = this.constant(); + } else { + this.throwError('not a primary expression', this.peek()); + } + + var next, context; + while ((next = this.expect('(', '[', '.'))) { + if (next.text === '(') { + primary = this.functionCall(primary, context); + context = null; + } else if (next.text === '[') { + context = primary; + primary = this.objectIndex(primary); + } else if (next.text === '.') { + context = primary; + primary = this.fieldAccess(primary); + } else { + this.throwError('IMPOSSIBLE'); + } + } + return primary; + }, + + throwError: function(msg, token) { + throw $parseMinErr('syntax', + 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].', + token.text, msg, (token.index + 1), this.text, this.text.substring(token.index)); + }, + + peekToken: function() { + if (this.tokens.length === 0) + throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); + return this.tokens[0]; + }, + + peek: function(e1, e2, e3, e4) { + return this.peekAhead(0, e1, e2, e3, e4); + }, + peekAhead: function(i, e1, e2, e3, e4) { + if (this.tokens.length > i) { + var token = this.tokens[i]; + var t = token.text; + if (t === e1 || t === e2 || t === e3 || t === e4 || + (!e1 && !e2 && !e3 && !e4)) { + return token; + } + } + return false; + }, + + expect: function(e1, e2, e3, e4) { + var token = this.peek(e1, e2, e3, e4); + if (token) { + this.tokens.shift(); + return token; + } + return false; + }, + + consume: function(e1) { + if (this.tokens.length === 0) { + throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text); + } + + var token = this.expect(e1); + if (!token) { + this.throwError('is unexpected, expecting [' + e1 + ']', this.peek()); + } + return token; + }, + + unaryFn: function(op, right) { + var fn = OPERATORS[op]; + return extend(function $parseUnaryFn(self, locals) { + return fn(self, locals, right); + }, { + constant:right.constant, + inputs: [right] + }); + }, + + binaryFn: function(left, op, right, isBranching) { + var fn = OPERATORS[op]; + return extend(function $parseBinaryFn(self, locals) { + return fn(self, locals, left, right); + }, { + constant: left.constant && right.constant, + inputs: !isBranching && [left, right] + }); + }, + + identifier: function() { + var id = this.consume().text; + + //Continue reading each `.identifier` unless it is a method invocation + while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) { + id += this.consume().text + this.consume().text; + } + + return getterFn(id, this.options, this.text); + }, + + constant: function() { + var value = this.consume().value; + + return extend(function $parseConstant() { + return value; + }, { + constant: true, + literal: true + }); + }, + + statements: function() { + var statements = []; + while (true) { + if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']')) + statements.push(this.filterChain()); + if (!this.expect(';')) { + // optimize for the common case where there is only one statement. + // TODO(size): maybe we should not support multiple statements? + return (statements.length === 1) + ? statements[0] + : function $parseStatements(self, locals) { + var value; + for (var i = 0, ii = statements.length; i < ii; i++) { + value = statements[i](self, locals); + } + return value; + }; + } + } + }, + + filterChain: function() { + var left = this.expression(); + var token; + while ((token = this.expect('|'))) { + left = this.filter(left); + } + return left; + }, + + filter: function(inputFn) { + var fn = this.$filter(this.consume().text); + var argsFn; + var args; + + if (this.peek(':')) { + argsFn = []; + args = []; // we can safely reuse the array + while (this.expect(':')) { + argsFn.push(this.expression()); + } + } + + var inputs = [inputFn].concat(argsFn || []); + + return extend(function $parseFilter(self, locals) { + var input = inputFn(self, locals); + if (args) { + args[0] = input; + + var i = argsFn.length; + while (i--) { + args[i + 1] = argsFn[i](self, locals); + } + + return fn.apply(undefined, args); + } + + return fn(input); + }, { + constant: !fn.$stateful && inputs.every(isConstant), + inputs: !fn.$stateful && inputs + }); + }, + + expression: function() { + return this.assignment(); + }, + + assignment: function() { + var left = this.ternary(); + var right; + var token; + if ((token = this.expect('='))) { + if (!left.assign) { + this.throwError('implies assignment but [' + + this.text.substring(0, token.index) + '] can not be assigned to', token); + } + right = this.ternary(); + return extend(function $parseAssignment(scope, locals) { + return left.assign(scope, right(scope, locals), locals); + }, { + inputs: [left, right] + }); + } + return left; + }, + + ternary: function() { + var left = this.logicalOR(); + var middle; + var token; + if ((token = this.expect('?'))) { + middle = this.assignment(); + if (this.consume(':')) { + var right = this.assignment(); + + return extend(function $parseTernary(self, locals) { + return left(self, locals) ? middle(self, locals) : right(self, locals); + }, { + constant: left.constant && middle.constant && right.constant + }); + } + } + + return left; + }, + + logicalOR: function() { + var left = this.logicalAND(); + var token; + while ((token = this.expect('||'))) { + left = this.binaryFn(left, token.text, this.logicalAND(), true); + } + return left; + }, + + logicalAND: function() { + var left = this.equality(); + var token; + while ((token = this.expect('&&'))) { + left = this.binaryFn(left, token.text, this.equality(), true); + } + return left; + }, + + equality: function() { + var left = this.relational(); + var token; + while ((token = this.expect('==','!=','===','!=='))) { + left = this.binaryFn(left, token.text, this.relational()); + } + return left; + }, + + relational: function() { + var left = this.additive(); + var token; + while ((token = this.expect('<', '>', '<=', '>='))) { + left = this.binaryFn(left, token.text, this.additive()); + } + return left; + }, + + additive: function() { + var left = this.multiplicative(); + var token; + while ((token = this.expect('+','-'))) { + left = this.binaryFn(left, token.text, this.multiplicative()); + } + return left; + }, + + multiplicative: function() { + var left = this.unary(); + var token; + while ((token = this.expect('*','/','%'))) { + left = this.binaryFn(left, token.text, this.unary()); + } + return left; + }, + + unary: function() { + var token; + if (this.expect('+')) { + return this.primary(); + } else if ((token = this.expect('-'))) { + return this.binaryFn(Parser.ZERO, token.text, this.unary()); + } else if ((token = this.expect('!'))) { + return this.unaryFn(token.text, this.unary()); + } else { + return this.primary(); + } + }, + + fieldAccess: function(object) { + var getter = this.identifier(); + + return extend(function $parseFieldAccess(scope, locals, self) { + var o = self || object(scope, locals); + return (o == null) ? undefined : getter(o); + }, { + assign: function(scope, value, locals) { + var o = object(scope, locals); + if (!o) object.assign(scope, o = {}, locals); + return getter.assign(o, value); + } + }); + }, + + objectIndex: function(obj) { + var expression = this.text; + + var indexFn = this.expression(); + this.consume(']'); + + return extend(function $parseObjectIndex(self, locals) { + var o = obj(self, locals), + i = indexFn(self, locals), + v; + + ensureSafeMemberName(i, expression); + if (!o) return undefined; + v = ensureSafeObject(o[i], expression); + return v; + }, { + assign: function(self, value, locals) { + var key = ensureSafeMemberName(indexFn(self, locals), expression); + // prevent overwriting of Function.constructor which would break ensureSafeObject check + var o = ensureSafeObject(obj(self, locals), expression); + if (!o) obj.assign(self, o = {}, locals); + return o[key] = value; + } + }); + }, + + functionCall: function(fnGetter, contextGetter) { + var argsFn = []; + if (this.peekToken().text !== ')') { + do { + argsFn.push(this.expression()); + } while (this.expect(',')); + } + this.consume(')'); + + var expressionText = this.text; + // we can safely reuse the array across invocations + var args = argsFn.length ? [] : null; + + return function $parseFunctionCall(scope, locals) { + var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope; + var fn = fnGetter(scope, locals, context) || noop; + + if (args) { + var i = argsFn.length; + while (i--) { + args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText); + } + } + + ensureSafeObject(context, expressionText); + ensureSafeFunction(fn, expressionText); + + // IE doesn't have apply for some native functions + var v = fn.apply + ? fn.apply(context, args) + : fn(args[0], args[1], args[2], args[3], args[4]); + + if (args) { + // Free-up the memory (arguments of the last function call). + args.length = 0; + } + + return ensureSafeObject(v, expressionText); + }; + }, + + // This is used with json array declaration + arrayDeclaration: function() { + var elementFns = []; + if (this.peekToken().text !== ']') { + do { + if (this.peek(']')) { + // Support trailing commas per ES5.1. + break; + } + elementFns.push(this.expression()); + } while (this.expect(',')); + } + this.consume(']'); + + return extend(function $parseArrayLiteral(self, locals) { + var array = []; + for (var i = 0, ii = elementFns.length; i < ii; i++) { + array.push(elementFns[i](self, locals)); + } + return array; + }, { + literal: true, + constant: elementFns.every(isConstant), + inputs: elementFns + }); + }, + + object: function() { + var keys = [], valueFns = []; + if (this.peekToken().text !== '}') { + do { + if (this.peek('}')) { + // Support trailing commas per ES5.1. + break; + } + var token = this.consume(); + if (token.constant) { + keys.push(token.value); + } else if (token.identifier) { + keys.push(token.text); + } else { + this.throwError("invalid key", token); + } + this.consume(':'); + valueFns.push(this.expression()); + } while (this.expect(',')); + } + this.consume('}'); + + return extend(function $parseObjectLiteral(self, locals) { + var object = {}; + for (var i = 0, ii = valueFns.length; i < ii; i++) { + object[keys[i]] = valueFns[i](self, locals); + } + return object; + }, { + literal: true, + constant: valueFns.every(isConstant), + inputs: valueFns + }); + } +}; + + +////////////////////////////////////////////////// +// Parser helper functions +////////////////////////////////////////////////// + +function setter(obj, locals, path, setValue, fullExp) { + ensureSafeObject(obj, fullExp); + ensureSafeObject(locals, fullExp); + + var element = path.split('.'), key; + for (var i = 0; element.length > 1; i++) { + key = ensureSafeMemberName(element.shift(), fullExp); + var propertyObj = (i === 0 && locals && locals[key]) || obj[key]; + if (!propertyObj) { + propertyObj = {}; + obj[key] = propertyObj; + } + obj = ensureSafeObject(propertyObj, fullExp); + } + key = ensureSafeMemberName(element.shift(), fullExp); + ensureSafeObject(obj[key], fullExp); + obj[key] = setValue; + return setValue; +} + +var getterFnCacheDefault = createMap(); +var getterFnCacheExpensive = createMap(); + +function isPossiblyDangerousMemberName(name) { + return name == 'constructor'; +} + +/** + * Implementation of the "Black Hole" variant from: + * - http://jsperf.com/angularjs-parse-getter/4 + * - http://jsperf.com/path-evaluation-simplified/7 + */ +function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, expensiveChecks) { + ensureSafeMemberName(key0, fullExp); + ensureSafeMemberName(key1, fullExp); + ensureSafeMemberName(key2, fullExp); + ensureSafeMemberName(key3, fullExp); + ensureSafeMemberName(key4, fullExp); + var eso = function(o) { + return ensureSafeObject(o, fullExp); + }; + var eso0 = (expensiveChecks || isPossiblyDangerousMemberName(key0)) ? eso : identity; + var eso1 = (expensiveChecks || isPossiblyDangerousMemberName(key1)) ? eso : identity; + var eso2 = (expensiveChecks || isPossiblyDangerousMemberName(key2)) ? eso : identity; + var eso3 = (expensiveChecks || isPossiblyDangerousMemberName(key3)) ? eso : identity; + var eso4 = (expensiveChecks || isPossiblyDangerousMemberName(key4)) ? eso : identity; + + return function cspSafeGetter(scope, locals) { + var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope; + + if (pathVal == null) return pathVal; + pathVal = eso0(pathVal[key0]); + + if (!key1) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso1(pathVal[key1]); + + if (!key2) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso2(pathVal[key2]); + + if (!key3) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso3(pathVal[key3]); + + if (!key4) return pathVal; + if (pathVal == null) return undefined; + pathVal = eso4(pathVal[key4]); + + return pathVal; + }; +} + +function getterFnWithEnsureSafeObject(fn, fullExpression) { + return function(s, l) { + return fn(s, l, ensureSafeObject, fullExpression); + }; +} + +function getterFn(path, options, fullExp) { + var expensiveChecks = options.expensiveChecks; + var getterFnCache = (expensiveChecks ? getterFnCacheExpensive : getterFnCacheDefault); + var fn = getterFnCache[path]; + if (fn) return fn; + + + var pathKeys = path.split('.'), + pathKeysLength = pathKeys.length; + + // http://jsperf.com/angularjs-parse-getter/6 + if (options.csp) { + if (pathKeysLength < 6) { + fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, expensiveChecks); + } else { + fn = function cspSafeGetter(scope, locals) { + var i = 0, val; + do { + val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], + pathKeys[i++], fullExp, expensiveChecks)(scope, locals); + + locals = undefined; // clear after first iteration + scope = val; + } while (i < pathKeysLength); + return val; + }; + } + } else { + var code = ''; + if (expensiveChecks) { + code += 's = eso(s, fe);\nl = eso(l, fe);\n'; + } + var needsEnsureSafeObject = expensiveChecks; + forEach(pathKeys, function(key, index) { + ensureSafeMemberName(key, fullExp); + var lookupJs = (index + // we simply dereference 's' on any .dot notation + ? 's' + // but if we are first then we check locals first, and if so read it first + : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key; + if (expensiveChecks || isPossiblyDangerousMemberName(key)) { + lookupJs = 'eso(' + lookupJs + ', fe)'; + needsEnsureSafeObject = true; + } + code += 'if(s == null) return undefined;\n' + + 's=' + lookupJs + ';\n'; + }); + code += 'return s;'; + + /* jshint -W054 */ + var evaledFnGetter = new Function('s', 'l', 'eso', 'fe', code); // s=scope, l=locals, eso=ensureSafeObject + /* jshint +W054 */ + evaledFnGetter.toString = valueFn(code); + if (needsEnsureSafeObject) { + evaledFnGetter = getterFnWithEnsureSafeObject(evaledFnGetter, fullExp); + } + fn = evaledFnGetter; + } + + fn.sharedGetter = true; + fn.assign = function(self, value, locals) { + return setter(self, locals, path, value, path); + }; + getterFnCache[path] = fn; + return fn; +} + +var objectValueOf = Object.prototype.valueOf; + +function getValueOf(value) { + return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value); +} + +/////////////////////////////////// + +/** + * @ngdoc service + * @name $parse + * @kind function + * + * @description + * + * Converts Angular {@link guide/expression expression} into a function. + * + * ```js + * var getter = $parse('user.name'); + * var setter = getter.assign; + * var context = {user:{name:'angular'}}; + * var locals = {user:{name:'local'}}; + * + * expect(getter(context)).toEqual('angular'); + * setter(context, 'newValue'); + * expect(context.user.name).toEqual('newValue'); + * expect(getter(context, locals)).toEqual('local'); + * ``` + * + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + * + * The returned function also has the following properties: + * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript + * literal. + * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript + * constant literals. + * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be + * set to a function to change its value on the given context. + * + */ + + +/** + * @ngdoc provider + * @name $parseProvider + * + * @description + * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse} + * service. + */ +function $ParseProvider() { + var cacheDefault = createMap(); + var cacheExpensive = createMap(); + + + + this.$get = ['$filter', '$sniffer', function($filter, $sniffer) { + var $parseOptions = { + csp: $sniffer.csp, + expensiveChecks: false + }, + $parseOptionsExpensive = { + csp: $sniffer.csp, + expensiveChecks: true + }; + + function wrapSharedExpression(exp) { + var wrapped = exp; + + if (exp.sharedGetter) { + wrapped = function $parseWrapper(self, locals) { + return exp(self, locals); + }; + wrapped.literal = exp.literal; + wrapped.constant = exp.constant; + wrapped.assign = exp.assign; + } + + return wrapped; + } + + return function $parse(exp, interceptorFn, expensiveChecks) { + var parsedExpression, oneTime, cacheKey; + + switch (typeof exp) { + case 'string': + cacheKey = exp = exp.trim(); + + var cache = (expensiveChecks ? cacheExpensive : cacheDefault); + parsedExpression = cache[cacheKey]; + + if (!parsedExpression) { + if (exp.charAt(0) === ':' && exp.charAt(1) === ':') { + oneTime = true; + exp = exp.substring(2); + } + + var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions; + var lexer = new Lexer(parseOptions); + var parser = new Parser(lexer, $filter, parseOptions); + parsedExpression = parser.parse(exp); + + if (parsedExpression.constant) { + parsedExpression.$$watchDelegate = constantWatchDelegate; + } else if (oneTime) { + //oneTime is not part of the exp passed to the Parser so we may have to + //wrap the parsedExpression before adding a $$watchDelegate + parsedExpression = wrapSharedExpression(parsedExpression); + parsedExpression.$$watchDelegate = parsedExpression.literal ? + oneTimeLiteralWatchDelegate : oneTimeWatchDelegate; + } else if (parsedExpression.inputs) { + parsedExpression.$$watchDelegate = inputsWatchDelegate; + } + + cache[cacheKey] = parsedExpression; + } + return addInterceptor(parsedExpression, interceptorFn); + + case 'function': + return addInterceptor(exp, interceptorFn); + + default: + return addInterceptor(noop, interceptorFn); + } + }; + + function collectExpressionInputs(inputs, list) { + for (var i = 0, ii = inputs.length; i < ii; i++) { + var input = inputs[i]; + if (!input.constant) { + if (input.inputs) { + collectExpressionInputs(input.inputs, list); + } else if (list.indexOf(input) === -1) { // TODO(perf) can we do better? + list.push(input); + } + } + } + + return list; + } + + function expressionInputDirtyCheck(newValue, oldValueOfValue) { + + if (newValue == null || oldValueOfValue == null) { // null/undefined + return newValue === oldValueOfValue; + } + + if (typeof newValue === 'object') { + + // attempt to convert the value to a primitive type + // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can + // be cheaply dirty-checked + newValue = getValueOf(newValue); + + if (typeof newValue === 'object') { + // objects/arrays are not supported - deep-watching them would be too expensive + return false; + } + + // fall-through to the primitive equality check + } + + //Primitive or NaN + return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue); + } + + function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var inputExpressions = parsedExpression.$$inputs || + (parsedExpression.$$inputs = collectExpressionInputs(parsedExpression.inputs, [])); + + var lastResult; + + if (inputExpressions.length === 1) { + var oldInputValue = expressionInputDirtyCheck; // init to something unique so that equals check fails + inputExpressions = inputExpressions[0]; + return scope.$watch(function expressionInputWatch(scope) { + var newInputValue = inputExpressions(scope); + if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) { + lastResult = parsedExpression(scope); + oldInputValue = newInputValue && getValueOf(newInputValue); + } + return lastResult; + }, listener, objectEquality); + } + + var oldInputValueOfValues = []; + for (var i = 0, ii = inputExpressions.length; i < ii; i++) { + oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails + } + + return scope.$watch(function expressionInputsWatch(scope) { + var changed = false; + + for (var i = 0, ii = inputExpressions.length; i < ii; i++) { + var newInputValue = inputExpressions[i](scope); + if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) { + oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue); + } + } + + if (changed) { + lastResult = parsedExpression(scope); + } + + return lastResult; + }, listener, objectEquality); + } + + function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var unwatch, lastValue; + return unwatch = scope.$watch(function oneTimeWatch(scope) { + return parsedExpression(scope); + }, function oneTimeListener(value, old, scope) { + lastValue = value; + if (isFunction(listener)) { + listener.apply(this, arguments); + } + if (isDefined(value)) { + scope.$$postDigest(function() { + if (isDefined(lastValue)) { + unwatch(); + } + }); + } + }, objectEquality); + } + + function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var unwatch, lastValue; + return unwatch = scope.$watch(function oneTimeWatch(scope) { + return parsedExpression(scope); + }, function oneTimeListener(value, old, scope) { + lastValue = value; + if (isFunction(listener)) { + listener.call(this, value, old, scope); + } + if (isAllDefined(value)) { + scope.$$postDigest(function() { + if (isAllDefined(lastValue)) unwatch(); + }); + } + }, objectEquality); + + function isAllDefined(value) { + var allDefined = true; + forEach(value, function(val) { + if (!isDefined(val)) allDefined = false; + }); + return allDefined; + } + } + + function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) { + var unwatch; + return unwatch = scope.$watch(function constantWatch(scope) { + return parsedExpression(scope); + }, function constantListener(value, old, scope) { + if (isFunction(listener)) { + listener.apply(this, arguments); + } + unwatch(); + }, objectEquality); + } + + function addInterceptor(parsedExpression, interceptorFn) { + if (!interceptorFn) return parsedExpression; + var watchDelegate = parsedExpression.$$watchDelegate; + + var regularWatch = + watchDelegate !== oneTimeLiteralWatchDelegate && + watchDelegate !== oneTimeWatchDelegate; + + var fn = regularWatch ? function regularInterceptedExpression(scope, locals) { + var value = parsedExpression(scope, locals); + return interceptorFn(value, scope, locals); + } : function oneTimeInterceptedExpression(scope, locals) { + var value = parsedExpression(scope, locals); + var result = interceptorFn(value, scope, locals); + // we only return the interceptor's result if the + // initial value is defined (for bind-once) + return isDefined(value) ? result : value; + }; + + // Propagate $$watchDelegates other then inputsWatchDelegate + if (parsedExpression.$$watchDelegate && + parsedExpression.$$watchDelegate !== inputsWatchDelegate) { + fn.$$watchDelegate = parsedExpression.$$watchDelegate; + } else if (!interceptorFn.$stateful) { + // If there is an interceptor, but no watchDelegate then treat the interceptor like + // we treat filters - it is assumed to be a pure function unless flagged with $stateful + fn.$$watchDelegate = inputsWatchDelegate; + fn.inputs = [parsedExpression]; + } + + return fn; + } + }]; +} + +/** + * @ngdoc service + * @name $q + * @requires $rootScope + * + * @description + * A service that helps you run functions asynchronously, and use their return values (or exceptions) + * when they are done processing. + * + * This is an implementation of promises/deferred objects inspired by + * [Kris Kowal's Q](https://github.com/kriskowal/q). + * + * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred + * implementations, and the other which resembles ES6 promises to some degree. + * + * # $q constructor + * + * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver` + * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony, + * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). + * + * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are + * available yet. + * + * It can be used like so: + * + * ```js + * // for the purpose of this example let's assume that variables `$q` and `okToGreet` + * // are available in the current lexical scope (they could have been injected or passed in). + * + * function asyncGreet(name) { + * // perform some asynchronous operation, resolve or reject the promise when appropriate. + * return $q(function(resolve, reject) { + * setTimeout(function() { + * if (okToGreet(name)) { + * resolve('Hello, ' + name + '!'); + * } else { + * reject('Greeting ' + name + ' is not allowed.'); + * } + * }, 1000); + * }); + * } + * + * var promise = asyncGreet('Robin Hood'); + * promise.then(function(greeting) { + * alert('Success: ' + greeting); + * }, function(reason) { + * alert('Failed: ' + reason); + * }); + * ``` + * + * Note: progress/notify callbacks are not currently supported via the ES6-style interface. + * + * However, the more traditional CommonJS-style usage is still available, and documented below. + * + * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an + * interface for interacting with an object that represents the result of an action that is + * performed asynchronously, and may or may not be finished at any given point in time. + * + * From the perspective of dealing with error handling, deferred and promise APIs are to + * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming. + * + * ```js + * // for the purpose of this example let's assume that variables `$q` and `okToGreet` + * // are available in the current lexical scope (they could have been injected or passed in). + * + * function asyncGreet(name) { + * var deferred = $q.defer(); + * + * setTimeout(function() { + * deferred.notify('About to greet ' + name + '.'); + * + * if (okToGreet(name)) { + * deferred.resolve('Hello, ' + name + '!'); + * } else { + * deferred.reject('Greeting ' + name + ' is not allowed.'); + * } + * }, 1000); + * + * return deferred.promise; + * } + * + * var promise = asyncGreet('Robin Hood'); + * promise.then(function(greeting) { + * alert('Success: ' + greeting); + * }, function(reason) { + * alert('Failed: ' + reason); + * }, function(update) { + * alert('Got notification: ' + update); + * }); + * ``` + * + * At first it might not be obvious why this extra complexity is worth the trouble. The payoff + * comes in the way of guarantees that promise and deferred APIs make, see + * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md. + * + * Additionally the promise api allows for composition that is very hard to do with the + * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach. + * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the + * section on serial or parallel joining of promises. + * + * # The Deferred API + * + * A new instance of deferred is constructed by calling `$q.defer()`. + * + * The purpose of the deferred object is to expose the associated Promise instance as well as APIs + * that can be used for signaling the successful or unsuccessful completion, as well as the status + * of the task. + * + * **Methods** + * + * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection + * constructed via `$q.reject`, the promise will be rejected instead. + * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to + * resolving it with a rejection constructed via `$q.reject`. + * - `notify(value)` - provides updates on the status of the promise's execution. This may be called + * multiple times before the promise is either resolved or rejected. + * + * **Properties** + * + * - promise – `{Promise}` – promise object associated with this deferred. + * + * + * # The Promise API + * + * A new promise instance is created when a deferred instance is created and can be retrieved by + * calling `deferred.promise`. + * + * The purpose of the promise object is to allow for interested parties to get access to the result + * of the deferred task when it completes. + * + * **Methods** + * + * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or + * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously + * as soon as the result is available. The callbacks are called with a single argument: the result + * or rejection reason. Additionally, the notify callback may be called zero or more times to + * provide a progress indication, before the promise is resolved or rejected. + * + * This method *returns a new promise* which is resolved or rejected via the return value of the + * `successCallback`, `errorCallback`. It also notifies via the return value of the + * `notifyCallback` method. The promise cannot be resolved or rejected from the notifyCallback + * method. + * + * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)` + * + * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise, + * but to do so without modifying the final value. This is useful to release resources or do some + * clean-up that needs to be done whether the promise was rejected or resolved. See the [full + * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for + * more information. + * + * # Chaining promises + * + * Because calling the `then` method of a promise returns a new derived promise, it is easily + * possible to create a chain of promises: + * + * ```js + * promiseB = promiseA.then(function(result) { + * return result + 1; + * }); + * + * // promiseB will be resolved immediately after promiseA is resolved and its value + * // will be the result of promiseA incremented by 1 + * ``` + * + * It is possible to create chains of any length and since a promise can be resolved with another + * promise (which will defer its resolution further), it is possible to pause/defer resolution of + * the promises at any point in the chain. This makes it possible to implement powerful APIs like + * $http's response interceptors. + * + * + * # Differences between Kris Kowal's Q and $q + * + * There are two main differences: + * + * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation + * mechanism in angular, which means faster propagation of resolution or rejection into your + * models and avoiding unnecessary browser repaints, which would result in flickering UI. + * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains + * all the important functionality needed for common async tasks. + * + * # Testing + * + * ```js + * it('should simulate promise', inject(function($q, $rootScope) { + * var deferred = $q.defer(); + * var promise = deferred.promise; + * var resolvedValue; + * + * promise.then(function(value) { resolvedValue = value; }); + * expect(resolvedValue).toBeUndefined(); + * + * // Simulate resolving of promise + * deferred.resolve(123); + * // Note that the 'then' function does not get called synchronously. + * // This is because we want the promise API to always be async, whether or not + * // it got called synchronously or asynchronously. + * expect(resolvedValue).toBeUndefined(); + * + * // Propagate promise resolution to 'then' functions using $apply(). + * $rootScope.$apply(); + * expect(resolvedValue).toEqual(123); + * })); + * ``` + * + * @param {function(function, function)} resolver Function which is responsible for resolving or + * rejecting the newly created promise. The first parameter is a function which resolves the + * promise, the second parameter is a function which rejects the promise. + * + * @returns {Promise} The newly created promise. + */ +function $QProvider() { + + this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) { + return qFactory(function(callback) { + $rootScope.$evalAsync(callback); + }, $exceptionHandler); + }]; +} + +function $$QProvider() { + this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) { + return qFactory(function(callback) { + $browser.defer(callback); + }, $exceptionHandler); + }]; +} + +/** + * Constructs a promise manager. + * + * @param {function(function)} nextTick Function for executing functions in the next turn. + * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for + * debugging purposes. + * @returns {object} Promise manager. + */ +function qFactory(nextTick, exceptionHandler) { + var $qMinErr = minErr('$q', TypeError); + function callOnce(self, resolveFn, rejectFn) { + var called = false; + function wrap(fn) { + return function(value) { + if (called) return; + called = true; + fn.call(self, value); + }; + } + + return [wrap(resolveFn), wrap(rejectFn)]; + } + + /** + * @ngdoc method + * @name ng.$q#defer + * @kind function + * + * @description + * Creates a `Deferred` object which represents a task which will finish in the future. + * + * @returns {Deferred} Returns a new instance of deferred. + */ + var defer = function() { + return new Deferred(); + }; + + function Promise() { + this.$$state = { status: 0 }; + } + + Promise.prototype = { + then: function(onFulfilled, onRejected, progressBack) { + var result = new Deferred(); + + this.$$state.pending = this.$$state.pending || []; + this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]); + if (this.$$state.status > 0) scheduleProcessQueue(this.$$state); + + return result.promise; + }, + + "catch": function(callback) { + return this.then(null, callback); + }, + + "finally": function(callback, progressBack) { + return this.then(function(value) { + return handleCallback(value, true, callback); + }, function(error) { + return handleCallback(error, false, callback); + }, progressBack); + } + }; + + //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native + function simpleBind(context, fn) { + return function(value) { + fn.call(context, value); + }; + } + + function processQueue(state) { + var fn, promise, pending; + + pending = state.pending; + state.processScheduled = false; + state.pending = undefined; + for (var i = 0, ii = pending.length; i < ii; ++i) { + promise = pending[i][0]; + fn = pending[i][state.status]; + try { + if (isFunction(fn)) { + promise.resolve(fn(state.value)); + } else if (state.status === 1) { + promise.resolve(state.value); + } else { + promise.reject(state.value); + } + } catch (e) { + promise.reject(e); + exceptionHandler(e); + } + } + } + + function scheduleProcessQueue(state) { + if (state.processScheduled || !state.pending) return; + state.processScheduled = true; + nextTick(function() { processQueue(state); }); + } + + function Deferred() { + this.promise = new Promise(); + //Necessary to support unbound execution :/ + this.resolve = simpleBind(this, this.resolve); + this.reject = simpleBind(this, this.reject); + this.notify = simpleBind(this, this.notify); + } + + Deferred.prototype = { + resolve: function(val) { + if (this.promise.$$state.status) return; + if (val === this.promise) { + this.$$reject($qMinErr( + 'qcycle', + "Expected promise to be resolved with value other than itself '{0}'", + val)); + } else { + this.$$resolve(val); + } + + }, + + $$resolve: function(val) { + var then, fns; + + fns = callOnce(this, this.$$resolve, this.$$reject); + try { + if ((isObject(val) || isFunction(val))) then = val && val.then; + if (isFunction(then)) { + this.promise.$$state.status = -1; + then.call(val, fns[0], fns[1], this.notify); + } else { + this.promise.$$state.value = val; + this.promise.$$state.status = 1; + scheduleProcessQueue(this.promise.$$state); + } + } catch (e) { + fns[1](e); + exceptionHandler(e); + } + }, + + reject: function(reason) { + if (this.promise.$$state.status) return; + this.$$reject(reason); + }, + + $$reject: function(reason) { + this.promise.$$state.value = reason; + this.promise.$$state.status = 2; + scheduleProcessQueue(this.promise.$$state); + }, + + notify: function(progress) { + var callbacks = this.promise.$$state.pending; + + if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) { + nextTick(function() { + var callback, result; + for (var i = 0, ii = callbacks.length; i < ii; i++) { + result = callbacks[i][0]; + callback = callbacks[i][3]; + try { + result.notify(isFunction(callback) ? callback(progress) : progress); + } catch (e) { + exceptionHandler(e); + } + } + }); + } + } + }; + + /** + * @ngdoc method + * @name $q#reject + * @kind function + * + * @description + * Creates a promise that is resolved as rejected with the specified `reason`. This api should be + * used to forward rejection in a chain of promises. If you are dealing with the last promise in + * a promise chain, you don't need to worry about it. + * + * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of + * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via + * a promise error callback and you want to forward the error to the promise derived from the + * current promise, you have to "rethrow" the error by returning a rejection constructed via + * `reject`. + * + * ```js + * promiseB = promiseA.then(function(result) { + * // success: do something and resolve promiseB + * // with the old or a new result + * return result; + * }, function(reason) { + * // error: handle the error if possible and + * // resolve promiseB with newPromiseOrValue, + * // otherwise forward the rejection to promiseB + * if (canHandle(reason)) { + * // handle the error and recover + * return newPromiseOrValue; + * } + * return $q.reject(reason); + * }); + * ``` + * + * @param {*} reason Constant, message, exception or an object representing the rejection reason. + * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`. + */ + var reject = function(reason) { + var result = new Deferred(); + result.reject(reason); + return result.promise; + }; + + var makePromise = function makePromise(value, resolved) { + var result = new Deferred(); + if (resolved) { + result.resolve(value); + } else { + result.reject(value); + } + return result.promise; + }; + + var handleCallback = function handleCallback(value, isResolved, callback) { + var callbackOutput = null; + try { + if (isFunction(callback)) callbackOutput = callback(); + } catch (e) { + return makePromise(e, false); + } + if (isPromiseLike(callbackOutput)) { + return callbackOutput.then(function() { + return makePromise(value, isResolved); + }, function(error) { + return makePromise(error, false); + }); + } else { + return makePromise(value, isResolved); + } + }; + + /** + * @ngdoc method + * @name $q#when + * @kind function + * + * @description + * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. + * This is useful when you are dealing with an object that might or might not be a promise, or if + * the promise comes from a source that can't be trusted. + * + * @param {*} value Value or a promise + * @returns {Promise} Returns a promise of the passed value or promise + */ + + + var when = function(value, callback, errback, progressBack) { + var result = new Deferred(); + result.resolve(value); + return result.promise.then(callback, errback, progressBack); + }; + + /** + * @ngdoc method + * @name $q#all + * @kind function + * + * @description + * Combines multiple promises into a single promise that is resolved when all of the input + * promises are resolved. + * + * @param {Array.|Object.} promises An array or hash of promises. + * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values, + * each value corresponding to the promise at the same index/key in the `promises` array/hash. + * If any of the promises is resolved with a rejection, this resulting promise will be rejected + * with the same rejection value. + */ + + function all(promises) { + var deferred = new Deferred(), + counter = 0, + results = isArray(promises) ? [] : {}; + + forEach(promises, function(promise, key) { + counter++; + when(promise).then(function(value) { + if (results.hasOwnProperty(key)) return; + results[key] = value; + if (!(--counter)) deferred.resolve(results); + }, function(reason) { + if (results.hasOwnProperty(key)) return; + deferred.reject(reason); + }); + }); + + if (counter === 0) { + deferred.resolve(results); + } + + return deferred.promise; + } + + var $Q = function Q(resolver) { + if (!isFunction(resolver)) { + throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver); + } + + if (!(this instanceof Q)) { + // More useful when $Q is the Promise itself. + return new Q(resolver); + } + + var deferred = new Deferred(); + + function resolveFn(value) { + deferred.resolve(value); + } + + function rejectFn(reason) { + deferred.reject(reason); + } + + resolver(resolveFn, rejectFn); + + return deferred.promise; + }; + + $Q.defer = defer; + $Q.reject = reject; + $Q.when = when; + $Q.all = all; + + return $Q; +} + +function $$RAFProvider() { //rAF + this.$get = ['$window', '$timeout', function($window, $timeout) { + var requestAnimationFrame = $window.requestAnimationFrame || + $window.webkitRequestAnimationFrame; + + var cancelAnimationFrame = $window.cancelAnimationFrame || + $window.webkitCancelAnimationFrame || + $window.webkitCancelRequestAnimationFrame; + + var rafSupported = !!requestAnimationFrame; + var raf = rafSupported + ? function(fn) { + var id = requestAnimationFrame(fn); + return function() { + cancelAnimationFrame(id); + }; + } + : function(fn) { + var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666 + return function() { + $timeout.cancel(timer); + }; + }; + + raf.supported = rafSupported; + + return raf; + }]; +} + +/** + * DESIGN NOTES + * + * The design decisions behind the scope are heavily favored for speed and memory consumption. + * + * The typical use of scope is to watch the expressions, which most of the time return the same + * value as last time so we optimize the operation. + * + * Closures construction is expensive in terms of speed as well as memory: + * - No closures, instead use prototypical inheritance for API + * - Internal state needs to be stored on scope directly, which means that private state is + * exposed as $$____ properties + * + * Loop operations are optimized by using while(count--) { ... } + * - this means that in order to keep the same order of execution as addition we have to add + * items to the array at the beginning (unshift) instead of at the end (push) + * + * Child scopes are created and removed often + * - Using an array would be slow since inserts in middle are expensive so we use linked list + * + * There are few watches then a lot of observers. This is why you don't want the observer to be + * implemented in the same way as watch. Watch requires return of initialization function which + * are expensive to construct. + */ + + +/** + * @ngdoc provider + * @name $rootScopeProvider + * @description + * + * Provider for the $rootScope service. + */ + +/** + * @ngdoc method + * @name $rootScopeProvider#digestTtl + * @description + * + * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and + * assuming that the model is unstable. + * + * The current default is 10 iterations. + * + * In complex applications it's possible that the dependencies between `$watch`s will result in + * several digest iterations. However if an application needs more than the default 10 digest + * iterations for its model to stabilize then you should investigate what is causing the model to + * continuously change during the digest. + * + * Increasing the TTL could have performance implications, so you should not change it without + * proper justification. + * + * @param {number} limit The number of digest iterations. + */ + + +/** + * @ngdoc service + * @name $rootScope + * @description + * + * Every application has a single root {@link ng.$rootScope.Scope scope}. + * All other scopes are descendant scopes of the root scope. Scopes provide separation + * between the model and the view, via a mechanism for watching the model for changes. + * They also provide an event emission/broadcast and subscription facility. See the + * {@link guide/scope developer guide on scopes}. + */ +function $RootScopeProvider() { + var TTL = 10; + var $rootScopeMinErr = minErr('$rootScope'); + var lastDirtyWatch = null; + var applyAsyncId = null; + + this.digestTtl = function(value) { + if (arguments.length) { + TTL = value; + } + return TTL; + }; + + this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser', + function($injector, $exceptionHandler, $parse, $browser) { + + /** + * @ngdoc type + * @name $rootScope.Scope + * + * @description + * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the + * {@link auto.$injector $injector}. Child scopes are created using the + * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when + * compiled HTML template is executed.) + * + * Here is a simple scope snippet to show how you can interact with the scope. + * ```html + * + * ``` + * + * # Inheritance + * A scope can inherit from a parent scope, as in this example: + * ```js + var parent = $rootScope; + var child = parent.$new(); + + parent.salutation = "Hello"; + expect(child.salutation).toEqual('Hello'); + + child.salutation = "Welcome"; + expect(child.salutation).toEqual('Welcome'); + expect(parent.salutation).toEqual('Hello'); + * ``` + * + * When interacting with `Scope` in tests, additional helper methods are available on the + * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional + * details. + * + * + * @param {Object.=} providers Map of service factory which need to be + * provided for the current scope. Defaults to {@link ng}. + * @param {Object.=} instanceCache Provides pre-instantiated services which should + * append/override services provided by `providers`. This is handy + * when unit-testing and having the need to override a default + * service. + * @returns {Object} Newly created scope. + * + */ + function Scope() { + this.$id = nextUid(); + this.$$phase = this.$parent = this.$$watchers = + this.$$nextSibling = this.$$prevSibling = + this.$$childHead = this.$$childTail = null; + this.$root = this; + this.$$destroyed = false; + this.$$listeners = {}; + this.$$listenerCount = {}; + this.$$isolateBindings = null; + } + + /** + * @ngdoc property + * @name $rootScope.Scope#$id + * + * @description + * Unique scope ID (monotonically increasing) useful for debugging. + */ + + /** + * @ngdoc property + * @name $rootScope.Scope#$parent + * + * @description + * Reference to the parent scope. + */ + + /** + * @ngdoc property + * @name $rootScope.Scope#$root + * + * @description + * Reference to the root scope. + */ + + Scope.prototype = { + constructor: Scope, + /** + * @ngdoc method + * @name $rootScope.Scope#$new + * @kind function + * + * @description + * Creates a new child {@link ng.$rootScope.Scope scope}. + * + * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event. + * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}. + * + * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is + * desired for the scope and its child scopes to be permanently detached from the parent and + * thus stop participating in model change detection and listener notification by invoking. + * + * @param {boolean} isolate If true, then the scope does not prototypically inherit from the + * parent scope. The scope is isolated, as it can not see parent scope properties. + * When creating widgets, it is useful for the widget to not accidentally read parent + * state. + * + * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent` + * of the newly created scope. Defaults to `this` scope if not provided. + * This is used when creating a transclude scope to correctly place it + * in the scope hierarchy while maintaining the correct prototypical + * inheritance. + * + * @returns {Object} The newly created child scope. + * + */ + $new: function(isolate, parent) { + var child; + + parent = parent || this; + + if (isolate) { + child = new Scope(); + child.$root = this.$root; + } else { + // Only create a child scope class if somebody asks for one, + // but cache it to allow the VM to optimize lookups. + if (!this.$$ChildScope) { + this.$$ChildScope = function ChildScope() { + this.$$watchers = this.$$nextSibling = + this.$$childHead = this.$$childTail = null; + this.$$listeners = {}; + this.$$listenerCount = {}; + this.$id = nextUid(); + this.$$ChildScope = null; + }; + this.$$ChildScope.prototype = this; + } + child = new this.$$ChildScope(); + } + child.$parent = parent; + child.$$prevSibling = parent.$$childTail; + if (parent.$$childHead) { + parent.$$childTail.$$nextSibling = child; + parent.$$childTail = child; + } else { + parent.$$childHead = parent.$$childTail = child; + } + + // When the new scope is not isolated or we inherit from `this`, and + // the parent scope is destroyed, the property `$$destroyed` is inherited + // prototypically. In all other cases, this property needs to be set + // when the parent scope is destroyed. + // The listener needs to be added after the parent is set + if (isolate || parent != this) child.$on('$destroy', destroyChild); + + return child; + + function destroyChild() { + child.$$destroyed = true; + } + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$watch + * @kind function + * + * @description + * Registers a `listener` callback to be executed whenever the `watchExpression` changes. + * + * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest + * $digest()} and should return the value that will be watched. (Since + * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the + * `watchExpression` can execute multiple times per + * {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.) + * - The `listener` is called only when the value from the current `watchExpression` and the + * previous call to `watchExpression` are not equal (with the exception of the initial run, + * see below). Inequality is determined according to reference inequality, + * [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators) + * via the `!==` Javascript operator, unless `objectEquality == true` + * (see next point) + * - When `objectEquality == true`, inequality of the `watchExpression` is determined + * according to the {@link angular.equals} function. To save the value of the object for + * later comparison, the {@link angular.copy} function is used. This therefore means that + * watching complex objects will have adverse memory and performance implications. + * - The watch `listener` may change the model, which may trigger other `listener`s to fire. + * This is achieved by rerunning the watchers until no changes are detected. The rerun + * iteration limit is 10 to prevent an infinite loop deadlock. + * + * + * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called, + * you can register a `watchExpression` function with no `listener`. (Since `watchExpression` + * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a + * change is detected, be prepared for multiple calls to your listener.) + * + * After a watcher is registered with the scope, the `listener` fn is called asynchronously + * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the + * watcher. In rare cases, this is undesirable because the listener is called when the result + * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you + * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the + * listener was called due to initialization. + * + * + * + * # Example + * ```js + // let's assume that scope was dependency injected as the $rootScope + var scope = $rootScope; + scope.name = 'misko'; + scope.counter = 0; + + expect(scope.counter).toEqual(0); + scope.$watch('name', function(newValue, oldValue) { + scope.counter = scope.counter + 1; + }); + expect(scope.counter).toEqual(0); + + scope.$digest(); + // the listener is always called during the first $digest loop after it was registered + expect(scope.counter).toEqual(1); + + scope.$digest(); + // but now it will not be called unless the value changes + expect(scope.counter).toEqual(1); + + scope.name = 'adam'; + scope.$digest(); + expect(scope.counter).toEqual(2); + + + + // Using a function as a watchExpression + var food; + scope.foodCounter = 0; + expect(scope.foodCounter).toEqual(0); + scope.$watch( + // This function returns the value being watched. It is called for each turn of the $digest loop + function() { return food; }, + // This is the change listener, called when the value returned from the above function changes + function(newValue, oldValue) { + if ( newValue !== oldValue ) { + // Only increment the counter if the value changed + scope.foodCounter = scope.foodCounter + 1; + } + } + ); + // No digest has been run so the counter will be zero + expect(scope.foodCounter).toEqual(0); + + // Run the digest but since food has not changed count will still be zero + scope.$digest(); + expect(scope.foodCounter).toEqual(0); + + // Update food and run digest. Now the counter will increment + food = 'cheeseburger'; + scope.$digest(); + expect(scope.foodCounter).toEqual(1); + + * ``` + * + * + * + * @param {(function()|string)} watchExpression Expression that is evaluated on each + * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers + * a call to the `listener`. + * + * - `string`: Evaluated as {@link guide/expression expression} + * - `function(scope)`: called with current `scope` as a parameter. + * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value + * of `watchExpression` changes. + * + * - `newVal` contains the current value of the `watchExpression` + * - `oldVal` contains the previous value of the `watchExpression` + * - `scope` refers to the current scope + * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of + * comparing for reference equality. + * @returns {function()} Returns a deregistration function for this listener. + */ + $watch: function(watchExp, listener, objectEquality) { + var get = $parse(watchExp); + + if (get.$$watchDelegate) { + return get.$$watchDelegate(this, listener, objectEquality, get); + } + var scope = this, + array = scope.$$watchers, + watcher = { + fn: listener, + last: initWatchVal, + get: get, + exp: watchExp, + eq: !!objectEquality + }; + + lastDirtyWatch = null; + + if (!isFunction(listener)) { + watcher.fn = noop; + } + + if (!array) { + array = scope.$$watchers = []; + } + // we use unshift since we use a while loop in $digest for speed. + // the while loop reads in reverse order. + array.unshift(watcher); + + return function deregisterWatch() { + arrayRemove(array, watcher); + lastDirtyWatch = null; + }; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$watchGroup + * @kind function + * + * @description + * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`. + * If any one expression in the collection changes the `listener` is executed. + * + * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every + * call to $digest() to see if any items changes. + * - The `listener` is called whenever any expression in the `watchExpressions` array changes. + * + * @param {Array.} watchExpressions Array of expressions that will be individually + * watched using {@link ng.$rootScope.Scope#$watch $watch()} + * + * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any + * expression in `watchExpressions` changes + * The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching + * those of `watchExpression` + * and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching + * those of `watchExpression` + * The `scope` refers to the current scope. + * @returns {function()} Returns a de-registration function for all listeners. + */ + $watchGroup: function(watchExpressions, listener) { + var oldValues = new Array(watchExpressions.length); + var newValues = new Array(watchExpressions.length); + var deregisterFns = []; + var self = this; + var changeReactionScheduled = false; + var firstRun = true; + + if (!watchExpressions.length) { + // No expressions means we call the listener ASAP + var shouldCall = true; + self.$evalAsync(function() { + if (shouldCall) listener(newValues, newValues, self); + }); + return function deregisterWatchGroup() { + shouldCall = false; + }; + } + + if (watchExpressions.length === 1) { + // Special case size of one + return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) { + newValues[0] = value; + oldValues[0] = oldValue; + listener(newValues, (value === oldValue) ? newValues : oldValues, scope); + }); + } + + forEach(watchExpressions, function(expr, i) { + var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) { + newValues[i] = value; + oldValues[i] = oldValue; + if (!changeReactionScheduled) { + changeReactionScheduled = true; + self.$evalAsync(watchGroupAction); + } + }); + deregisterFns.push(unwatchFn); + }); + + function watchGroupAction() { + changeReactionScheduled = false; + + if (firstRun) { + firstRun = false; + listener(newValues, newValues, self); + } else { + listener(newValues, oldValues, self); + } + } + + return function deregisterWatchGroup() { + while (deregisterFns.length) { + deregisterFns.shift()(); + } + }; + }, + + + /** + * @ngdoc method + * @name $rootScope.Scope#$watchCollection + * @kind function + * + * @description + * Shallow watches the properties of an object and fires whenever any of the properties change + * (for arrays, this implies watching the array items; for object maps, this implies watching + * the properties). If a change is detected, the `listener` callback is fired. + * + * - The `obj` collection is observed via standard $watch operation and is examined on every + * call to $digest() to see if any items have been added, removed, or moved. + * - The `listener` is called whenever anything within the `obj` has changed. Examples include + * adding, removing, and moving items belonging to an object or array. + * + * + * # Example + * ```js + $scope.names = ['igor', 'matias', 'misko', 'james']; + $scope.dataCount = 4; + + $scope.$watchCollection('names', function(newNames, oldNames) { + $scope.dataCount = newNames.length; + }); + + expect($scope.dataCount).toEqual(4); + $scope.$digest(); + + //still at 4 ... no changes + expect($scope.dataCount).toEqual(4); + + $scope.names.pop(); + $scope.$digest(); + + //now there's been a change + expect($scope.dataCount).toEqual(3); + * ``` + * + * + * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The + * expression value should evaluate to an object or an array which is observed on each + * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the + * collection will trigger a call to the `listener`. + * + * @param {function(newCollection, oldCollection, scope)} listener a callback function called + * when a change is detected. + * - The `newCollection` object is the newly modified data obtained from the `obj` expression + * - The `oldCollection` object is a copy of the former collection data. + * Due to performance considerations, the`oldCollection` value is computed only if the + * `listener` function declares two or more arguments. + * - The `scope` argument refers to the current scope. + * + * @returns {function()} Returns a de-registration function for this listener. When the + * de-registration function is executed, the internal watch operation is terminated. + */ + $watchCollection: function(obj, listener) { + $watchCollectionInterceptor.$stateful = true; + + var self = this; + // the current value, updated on each dirty-check run + var newValue; + // a shallow copy of the newValue from the last dirty-check run, + // updated to match newValue during dirty-check run + var oldValue; + // a shallow copy of the newValue from when the last change happened + var veryOldValue; + // only track veryOldValue if the listener is asking for it + var trackVeryOldValue = (listener.length > 1); + var changeDetected = 0; + var changeDetector = $parse(obj, $watchCollectionInterceptor); + var internalArray = []; + var internalObject = {}; + var initRun = true; + var oldLength = 0; + + function $watchCollectionInterceptor(_value) { + newValue = _value; + var newLength, key, bothNaN, newItem, oldItem; + + // If the new value is undefined, then return undefined as the watch may be a one-time watch + if (isUndefined(newValue)) return; + + if (!isObject(newValue)) { // if primitive + if (oldValue !== newValue) { + oldValue = newValue; + changeDetected++; + } + } else if (isArrayLike(newValue)) { + if (oldValue !== internalArray) { + // we are transitioning from something which was not an array into array. + oldValue = internalArray; + oldLength = oldValue.length = 0; + changeDetected++; + } + + newLength = newValue.length; + + if (oldLength !== newLength) { + // if lengths do not match we need to trigger change notification + changeDetected++; + oldValue.length = oldLength = newLength; + } + // copy the items to oldValue and look for changes. + for (var i = 0; i < newLength; i++) { + oldItem = oldValue[i]; + newItem = newValue[i]; + + bothNaN = (oldItem !== oldItem) && (newItem !== newItem); + if (!bothNaN && (oldItem !== newItem)) { + changeDetected++; + oldValue[i] = newItem; + } + } + } else { + if (oldValue !== internalObject) { + // we are transitioning from something which was not an object into object. + oldValue = internalObject = {}; + oldLength = 0; + changeDetected++; + } + // copy the items to oldValue and look for changes. + newLength = 0; + for (key in newValue) { + if (newValue.hasOwnProperty(key)) { + newLength++; + newItem = newValue[key]; + oldItem = oldValue[key]; + + if (key in oldValue) { + bothNaN = (oldItem !== oldItem) && (newItem !== newItem); + if (!bothNaN && (oldItem !== newItem)) { + changeDetected++; + oldValue[key] = newItem; + } + } else { + oldLength++; + oldValue[key] = newItem; + changeDetected++; + } + } + } + if (oldLength > newLength) { + // we used to have more keys, need to find them and destroy them. + changeDetected++; + for (key in oldValue) { + if (!newValue.hasOwnProperty(key)) { + oldLength--; + delete oldValue[key]; + } + } + } + } + return changeDetected; + } + + function $watchCollectionAction() { + if (initRun) { + initRun = false; + listener(newValue, newValue, self); + } else { + listener(newValue, veryOldValue, self); + } + + // make a copy for the next time a collection is changed + if (trackVeryOldValue) { + if (!isObject(newValue)) { + //primitive + veryOldValue = newValue; + } else if (isArrayLike(newValue)) { + veryOldValue = new Array(newValue.length); + for (var i = 0; i < newValue.length; i++) { + veryOldValue[i] = newValue[i]; + } + } else { // if object + veryOldValue = {}; + for (var key in newValue) { + if (hasOwnProperty.call(newValue, key)) { + veryOldValue[key] = newValue[key]; + } + } + } + } + } + + return this.$watch(changeDetector, $watchCollectionAction); + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$digest + * @kind function + * + * @description + * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and + * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change + * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} + * until no more listeners are firing. This means that it is possible to get into an infinite + * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of + * iterations exceeds 10. + * + * Usually, you don't call `$digest()` directly in + * {@link ng.directive:ngController controllers} or in + * {@link ng.$compileProvider#directive directives}. + * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within + * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`. + * + * If you want to be notified whenever `$digest()` is called, + * you can register a `watchExpression` function with + * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`. + * + * In unit tests, you may need to call `$digest()` to simulate the scope life cycle. + * + * # Example + * ```js + var scope = ...; + scope.name = 'misko'; + scope.counter = 0; + + expect(scope.counter).toEqual(0); + scope.$watch('name', function(newValue, oldValue) { + scope.counter = scope.counter + 1; + }); + expect(scope.counter).toEqual(0); + + scope.$digest(); + // the listener is always called during the first $digest loop after it was registered + expect(scope.counter).toEqual(1); + + scope.$digest(); + // but now it will not be called unless the value changes + expect(scope.counter).toEqual(1); + + scope.name = 'adam'; + scope.$digest(); + expect(scope.counter).toEqual(2); + * ``` + * + */ + $digest: function() { + var watch, value, last, + watchers, + length, + dirty, ttl = TTL, + next, current, target = this, + watchLog = [], + logIdx, logMsg, asyncTask; + + beginPhase('$digest'); + // Check for changes to browser url that happened in sync before the call to $digest + $browser.$$checkUrlChange(); + + if (this === $rootScope && applyAsyncId !== null) { + // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then + // cancel the scheduled $apply and flush the queue of expressions to be evaluated. + $browser.defer.cancel(applyAsyncId); + flushApplyAsync(); + } + + lastDirtyWatch = null; + + do { // "while dirty" loop + dirty = false; + current = target; + + while (asyncQueue.length) { + try { + asyncTask = asyncQueue.shift(); + asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals); + } catch (e) { + $exceptionHandler(e); + } + lastDirtyWatch = null; + } + + traverseScopesLoop: + do { // "traverse the scopes" loop + if ((watchers = current.$$watchers)) { + // process our watches + length = watchers.length; + while (length--) { + try { + watch = watchers[length]; + // Most common watches are on primitives, in which case we can short + // circuit it with === operator, only when === fails do we use .equals + if (watch) { + if ((value = watch.get(current)) !== (last = watch.last) && + !(watch.eq + ? equals(value, last) + : (typeof value === 'number' && typeof last === 'number' + && isNaN(value) && isNaN(last)))) { + dirty = true; + lastDirtyWatch = watch; + watch.last = watch.eq ? copy(value, null) : value; + watch.fn(value, ((last === initWatchVal) ? value : last), current); + if (ttl < 5) { + logIdx = 4 - ttl; + if (!watchLog[logIdx]) watchLog[logIdx] = []; + watchLog[logIdx].push({ + msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp, + newVal: value, + oldVal: last + }); + } + } else if (watch === lastDirtyWatch) { + // If the most recently dirty watcher is now clean, short circuit since the remaining watchers + // have already been tested. + dirty = false; + break traverseScopesLoop; + } + } + } catch (e) { + $exceptionHandler(e); + } + } + } + + // Insanity Warning: scope depth-first traversal + // yes, this code is a bit crazy, but it works and we have tests to prove it! + // this piece should be kept in sync with the traversal in $broadcast + if (!(next = (current.$$childHead || + (current !== target && current.$$nextSibling)))) { + while (current !== target && !(next = current.$$nextSibling)) { + current = current.$parent; + } + } + } while ((current = next)); + + // `break traverseScopesLoop;` takes us to here + + if ((dirty || asyncQueue.length) && !(ttl--)) { + clearPhase(); + throw $rootScopeMinErr('infdig', + '{0} $digest() iterations reached. Aborting!\n' + + 'Watchers fired in the last 5 iterations: {1}', + TTL, watchLog); + } + + } while (dirty || asyncQueue.length); + + clearPhase(); + + while (postDigestQueue.length) { + try { + postDigestQueue.shift()(); + } catch (e) { + $exceptionHandler(e); + } + } + }, + + + /** + * @ngdoc event + * @name $rootScope.Scope#$destroy + * @eventType broadcast on scope being destroyed + * + * @description + * Broadcasted when a scope and its children are being destroyed. + * + * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to + * clean up DOM bindings before an element is removed from the DOM. + */ + + /** + * @ngdoc method + * @name $rootScope.Scope#$destroy + * @kind function + * + * @description + * Removes the current scope (and all of its children) from the parent scope. Removal implies + * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer + * propagate to the current scope and its children. Removal also implies that the current + * scope is eligible for garbage collection. + * + * The `$destroy()` is usually used by directives such as + * {@link ng.directive:ngRepeat ngRepeat} for managing the + * unrolling of the loop. + * + * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope. + * Application code can register a `$destroy` event handler that will give it a chance to + * perform any necessary cleanup. + * + * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to + * clean up DOM bindings before an element is removed from the DOM. + */ + $destroy: function() { + // we can't destroy the root scope or a scope that has been already destroyed + if (this.$$destroyed) return; + var parent = this.$parent; + + this.$broadcast('$destroy'); + this.$$destroyed = true; + if (this === $rootScope) return; + + for (var eventName in this.$$listenerCount) { + decrementListenerCount(this, this.$$listenerCount[eventName], eventName); + } + + // sever all the references to parent scopes (after this cleanup, the current scope should + // not be retained by any of our references and should be eligible for garbage collection) + if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling; + if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling; + if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; + if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; + + // Disable listeners, watchers and apply/digest methods + this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop; + this.$on = this.$watch = this.$watchGroup = function() { return noop; }; + this.$$listeners = {}; + + // All of the code below is bogus code that works around V8's memory leak via optimized code + // and inline caches. + // + // see: + // - https://code.google.com/p/v8/issues/detail?id=2073#c26 + // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909 + // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 + + this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead = + this.$$childTail = this.$root = this.$$watchers = null; + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$eval + * @kind function + * + * @description + * Executes the `expression` on the current scope and returns the result. Any exceptions in + * the expression are propagated (uncaught). This is useful when evaluating Angular + * expressions. + * + * # Example + * ```js + var scope = ng.$rootScope.Scope(); + scope.a = 1; + scope.b = 2; + + expect(scope.$eval('a+b')).toEqual(3); + expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3); + * ``` + * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + * @param {(object)=} locals Local variables object, useful for overriding values in scope. + * @returns {*} The result of evaluating the expression. + */ + $eval: function(expr, locals) { + return $parse(expr)(this, locals); + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$evalAsync + * @kind function + * + * @description + * Executes the expression on the current scope at a later point in time. + * + * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only + * that: + * + * - it will execute after the function that scheduled the evaluation (preferably before DOM + * rendering). + * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after + * `expression` execution. + * + * Any exceptions from the execution of the expression are forwarded to the + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle + * will be scheduled. However, it is encouraged to always call code that changes the model + * from within an `$apply` call. That includes code evaluated via `$evalAsync`. + * + * @param {(string|function())=} expression An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with the current `scope` parameter. + * + * @param {(object)=} locals Local variables object, useful for overriding values in scope. + */ + $evalAsync: function(expr, locals) { + // if we are outside of an $digest loop and this is the first time we are scheduling async + // task also schedule async auto-flush + if (!$rootScope.$$phase && !asyncQueue.length) { + $browser.defer(function() { + if (asyncQueue.length) { + $rootScope.$digest(); + } + }); + } + + asyncQueue.push({scope: this, expression: expr, locals: locals}); + }, + + $$postDigest: function(fn) { + postDigestQueue.push(fn); + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$apply + * @kind function + * + * @description + * `$apply()` is used to execute an expression in angular from outside of the angular + * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries). + * Because we are calling into the angular framework we need to perform proper scope life + * cycle of {@link ng.$exceptionHandler exception handling}, + * {@link ng.$rootScope.Scope#$digest executing watches}. + * + * ## Life cycle + * + * # Pseudo-Code of `$apply()` + * ```js + function $apply(expr) { + try { + return $eval(expr); + } catch (e) { + $exceptionHandler(e); + } finally { + $root.$digest(); + } + } + * ``` + * + * + * Scope's `$apply()` method transitions through the following stages: + * + * 1. The {@link guide/expression expression} is executed using the + * {@link ng.$rootScope.Scope#$eval $eval()} method. + * 2. Any exceptions from the execution of the expression are forwarded to the + * {@link ng.$exceptionHandler $exceptionHandler} service. + * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the + * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method. + * + * + * @param {(string|function())=} exp An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with current `scope` parameter. + * + * @returns {*} The result of evaluating the expression. + */ + $apply: function(expr) { + try { + beginPhase('$apply'); + return this.$eval(expr); + } catch (e) { + $exceptionHandler(e); + } finally { + clearPhase(); + try { + $rootScope.$digest(); + } catch (e) { + $exceptionHandler(e); + throw e; + } + } + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$applyAsync + * @kind function + * + * @description + * Schedule the invocation of $apply to occur at a later time. The actual time difference + * varies across browsers, but is typically around ~10 milliseconds. + * + * This can be used to queue up multiple expressions which need to be evaluated in the same + * digest. + * + * @param {(string|function())=} exp An angular expression to be executed. + * + * - `string`: execute using the rules as defined in {@link guide/expression expression}. + * - `function(scope)`: execute the function with current `scope` parameter. + */ + $applyAsync: function(expr) { + var scope = this; + expr && applyAsyncQueue.push($applyAsyncExpression); + scheduleApplyAsync(); + + function $applyAsyncExpression() { + scope.$eval(expr); + } + }, + + /** + * @ngdoc method + * @name $rootScope.Scope#$on + * @kind function + * + * @description + * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for + * discussion of event life cycle. + * + * The event listener function format is: `function(event, args...)`. The `event` object + * passed into the listener has the following attributes: + * + * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or + * `$broadcast`-ed. + * - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the + * event propagates through the scope hierarchy, this property is set to null. + * - `name` - `{string}`: name of the event. + * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel + * further event propagation (available only for events that were `$emit`-ed). + * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag + * to true. + * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called. + * + * @param {string} name Event name to listen on. + * @param {function(event, ...args)} listener Function to call when the event is emitted. + * @returns {function()} Returns a deregistration function for this listener. + */ + $on: function(name, listener) { + var namedListeners = this.$$listeners[name]; + if (!namedListeners) { + this.$$listeners[name] = namedListeners = []; + } + namedListeners.push(listener); + + var current = this; + do { + if (!current.$$listenerCount[name]) { + current.$$listenerCount[name] = 0; + } + current.$$listenerCount[name]++; + } while ((current = current.$parent)); + + var self = this; + return function() { + var indexOfListener = namedListeners.indexOf(listener); + if (indexOfListener !== -1) { + namedListeners[indexOfListener] = null; + decrementListenerCount(self, 1, name); + } + }; + }, + + + /** + * @ngdoc method + * @name $rootScope.Scope#$emit + * @kind function + * + * @description + * Dispatches an event `name` upwards through the scope hierarchy notifying the + * registered {@link ng.$rootScope.Scope#$on} listeners. + * + * The event life cycle starts at the scope on which `$emit` was called. All + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get + * notified. Afterwards, the event traverses upwards toward the root scope and calls all + * registered listeners along the way. The event will stop propagating if one of the listeners + * cancels it. + * + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * onto the {@link ng.$exceptionHandler $exceptionHandler} service. + * + * @param {string} name Event name to emit. + * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. + * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}). + */ + $emit: function(name, args) { + var empty = [], + namedListeners, + scope = this, + stopPropagation = false, + event = { + name: name, + targetScope: scope, + stopPropagation: function() {stopPropagation = true;}, + preventDefault: function() { + event.defaultPrevented = true; + }, + defaultPrevented: false + }, + listenerArgs = concat([event], arguments, 1), + i, length; + + do { + namedListeners = scope.$$listeners[name] || empty; + event.currentScope = scope; + for (i = 0, length = namedListeners.length; i < length; i++) { + + // if listeners were deregistered, defragment the array + if (!namedListeners[i]) { + namedListeners.splice(i, 1); + i--; + length--; + continue; + } + try { + //allow all listeners attached to the current scope to run + namedListeners[i].apply(null, listenerArgs); + } catch (e) { + $exceptionHandler(e); + } + } + //if any listener on the current scope stops propagation, prevent bubbling + if (stopPropagation) { + event.currentScope = null; + return event; + } + //traverse upwards + scope = scope.$parent; + } while (scope); + + event.currentScope = null; + + return event; + }, + + + /** + * @ngdoc method + * @name $rootScope.Scope#$broadcast + * @kind function + * + * @description + * Dispatches an event `name` downwards to all child scopes (and their children) notifying the + * registered {@link ng.$rootScope.Scope#$on} listeners. + * + * The event life cycle starts at the scope on which `$broadcast` was called. All + * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get + * notified. Afterwards, the event propagates to all direct and indirect scopes of the current + * scope and calls all registered listeners along the way. The event cannot be canceled. + * + * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed + * onto the {@link ng.$exceptionHandler $exceptionHandler} service. + * + * @param {string} name Event name to broadcast. + * @param {...*} args Optional one or more arguments which will be passed onto the event listeners. + * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on} + */ + $broadcast: function(name, args) { + var target = this, + current = target, + next = target, + event = { + name: name, + targetScope: target, + preventDefault: function() { + event.defaultPrevented = true; + }, + defaultPrevented: false + }; + + if (!target.$$listenerCount[name]) return event; + + var listenerArgs = concat([event], arguments, 1), + listeners, i, length; + + //down while you can, then up and next sibling or up and next sibling until back at root + while ((current = next)) { + event.currentScope = current; + listeners = current.$$listeners[name] || []; + for (i = 0, length = listeners.length; i < length; i++) { + // if listeners were deregistered, defragment the array + if (!listeners[i]) { + listeners.splice(i, 1); + i--; + length--; + continue; + } + + try { + listeners[i].apply(null, listenerArgs); + } catch (e) { + $exceptionHandler(e); + } + } + + // Insanity Warning: scope depth-first traversal + // yes, this code is a bit crazy, but it works and we have tests to prove it! + // this piece should be kept in sync with the traversal in $digest + // (though it differs due to having the extra check for $$listenerCount) + if (!(next = ((current.$$listenerCount[name] && current.$$childHead) || + (current !== target && current.$$nextSibling)))) { + while (current !== target && !(next = current.$$nextSibling)) { + current = current.$parent; + } + } + } + + event.currentScope = null; + return event; + } + }; + + var $rootScope = new Scope(); + + //The internal queues. Expose them on the $rootScope for debugging/testing purposes. + var asyncQueue = $rootScope.$$asyncQueue = []; + var postDigestQueue = $rootScope.$$postDigestQueue = []; + var applyAsyncQueue = $rootScope.$$applyAsyncQueue = []; + + return $rootScope; + + + function beginPhase(phase) { + if ($rootScope.$$phase) { + throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase); + } + + $rootScope.$$phase = phase; + } + + function clearPhase() { + $rootScope.$$phase = null; + } + + + function decrementListenerCount(current, count, name) { + do { + current.$$listenerCount[name] -= count; + + if (current.$$listenerCount[name] === 0) { + delete current.$$listenerCount[name]; + } + } while ((current = current.$parent)); + } + + /** + * function used as an initial value for watchers. + * because it's unique we can easily tell it apart from other values + */ + function initWatchVal() {} + + function flushApplyAsync() { + while (applyAsyncQueue.length) { + try { + applyAsyncQueue.shift()(); + } catch (e) { + $exceptionHandler(e); + } + } + applyAsyncId = null; + } + + function scheduleApplyAsync() { + if (applyAsyncId === null) { + applyAsyncId = $browser.defer(function() { + $rootScope.$apply(flushApplyAsync); + }); + } + } + }]; +} + +/** + * @description + * Private service to sanitize uris for links and images. Used by $compile and $sanitize. + */ +function $$SanitizeUriProvider() { + var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, + imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; + + /** + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during a[href] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to a[href] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.aHrefSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + aHrefSanitizationWhitelist = regexp; + return this; + } + return aHrefSanitizationWhitelist; + }; + + + /** + * @description + * Retrieves or overrides the default regular expression that is used for whitelisting of safe + * urls during img[src] sanitization. + * + * The sanitization is a security measure aimed at prevent XSS attacks via html links. + * + * Any url about to be assigned to img[src] via data-binding is first normalized and turned into + * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` + * regular expression. If a match is found, the original url is written into the dom. Otherwise, + * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. + * + * @param {RegExp=} regexp New regexp to whitelist urls with. + * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for + * chaining otherwise. + */ + this.imgSrcSanitizationWhitelist = function(regexp) { + if (isDefined(regexp)) { + imgSrcSanitizationWhitelist = regexp; + return this; + } + return imgSrcSanitizationWhitelist; + }; + + this.$get = function() { + return function sanitizeUri(uri, isImage) { + var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; + var normalizedVal; + normalizedVal = urlResolve(uri).href; + if (normalizedVal !== '' && !normalizedVal.match(regex)) { + return 'unsafe:' + normalizedVal; + } + return uri; + }; + }; +} + +var $sceMinErr = minErr('$sce'); + +var SCE_CONTEXTS = { + HTML: 'html', + CSS: 'css', + URL: 'url', + // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a + // url. (e.g. ng-include, script src, templateUrl) + RESOURCE_URL: 'resourceUrl', + JS: 'js' +}; + +// Helper functions follow. + +function adjustMatcher(matcher) { + if (matcher === 'self') { + return matcher; + } else if (isString(matcher)) { + // Strings match exactly except for 2 wildcards - '*' and '**'. + // '*' matches any character except those from the set ':/.?&'. + // '**' matches any character (like .* in a RegExp). + // More than 2 *'s raises an error as it's ill defined. + if (matcher.indexOf('***') > -1) { + throw $sceMinErr('iwcard', + 'Illegal sequence *** in string matcher. String: {0}', matcher); + } + matcher = escapeForRegexp(matcher). + replace('\\*\\*', '.*'). + replace('\\*', '[^:/.?&;]*'); + return new RegExp('^' + matcher + '$'); + } else if (isRegExp(matcher)) { + // The only other type of matcher allowed is a Regexp. + // Match entire URL / disallow partial matches. + // Flags are reset (i.e. no global, ignoreCase or multiline) + return new RegExp('^' + matcher.source + '$'); + } else { + throw $sceMinErr('imatcher', + 'Matchers may only be "self", string patterns or RegExp objects'); + } +} + + +function adjustMatchers(matchers) { + var adjustedMatchers = []; + if (isDefined(matchers)) { + forEach(matchers, function(matcher) { + adjustedMatchers.push(adjustMatcher(matcher)); + }); + } + return adjustedMatchers; +} + + +/** + * @ngdoc service + * @name $sceDelegate + * @kind function + * + * @description + * + * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict + * Contextual Escaping (SCE)} services to AngularJS. + * + * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of + * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is + * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to + * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things + * work because `$sce` delegates to `$sceDelegate` for these operations. + * + * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service. + * + * The default instance of `$sceDelegate` should work out of the box with little pain. While you + * can override it completely to change the behavior of `$sce`, the common case would + * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting + * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as + * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist + * $sceDelegateProvider.resourceUrlWhitelist} and {@link + * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + */ + +/** + * @ngdoc provider + * @name $sceDelegateProvider + * @description + * + * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate + * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure + * that the URLs used for sourcing Angular templates are safe. Refer {@link + * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and + * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist} + * + * For the general details about this service in Angular, read the main page for {@link ng.$sce + * Strict Contextual Escaping (SCE)}. + * + * **Example**: Consider the following case. + * + * - your app is hosted at url `http://myapp.example.com/` + * - but some of your templates are hosted on other domains you control such as + * `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc. + * - and you have an open redirect at `http://myapp.example.com/clickThru?...`. + * + * Here is what a secure configuration for this scenario might look like: + * + * ``` + * angular.module('myApp', []).config(function($sceDelegateProvider) { + * $sceDelegateProvider.resourceUrlWhitelist([ + * // Allow same origin resource loads. + * 'self', + * // Allow loading from our assets domain. Notice the difference between * and **. + * 'http://srv*.assets.example.com/**' + * ]); + * + * // The blacklist overrides the whitelist so the open redirect here is blocked. + * $sceDelegateProvider.resourceUrlBlacklist([ + * 'http://myapp.example.com/clickThru**' + * ]); + * }); + * ``` + */ + +function $SceDelegateProvider() { + this.SCE_CONTEXTS = SCE_CONTEXTS; + + // Resource URLs can also be trusted by policy. + var resourceUrlWhitelist = ['self'], + resourceUrlBlacklist = []; + + /** + * @ngdoc method + * @name $sceDelegateProvider#resourceUrlWhitelist + * @kind function + * + * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value + * provided. This must be an array or null. A snapshot of this array is used so further + * changes to the array are ignored. + * + * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items + * allowed in this array. + * + * Note: **an empty whitelist array will block all URLs**! + * + * @return {Array} the currently set whitelist array. + * + * The **default value** when no whitelist has been explicitly set is `['self']` allowing only + * same origin resource requests. + * + * @description + * Sets/Gets the whitelist of trusted resource URLs. + */ + this.resourceUrlWhitelist = function(value) { + if (arguments.length) { + resourceUrlWhitelist = adjustMatchers(value); + } + return resourceUrlWhitelist; + }; + + /** + * @ngdoc method + * @name $sceDelegateProvider#resourceUrlBlacklist + * @kind function + * + * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value + * provided. This must be an array or null. A snapshot of this array is used so further + * changes to the array are ignored. + * + * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items + * allowed in this array. + * + * The typical usage for the blacklist is to **block + * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as + * these would otherwise be trusted but actually return content from the redirected domain. + * + * Finally, **the blacklist overrides the whitelist** and has the final say. + * + * @return {Array} the currently set blacklist array. + * + * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there + * is no blacklist.) + * + * @description + * Sets/Gets the blacklist of trusted resource URLs. + */ + + this.resourceUrlBlacklist = function(value) { + if (arguments.length) { + resourceUrlBlacklist = adjustMatchers(value); + } + return resourceUrlBlacklist; + }; + + this.$get = ['$injector', function($injector) { + + var htmlSanitizer = function htmlSanitizer(html) { + throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); + }; + + if ($injector.has('$sanitize')) { + htmlSanitizer = $injector.get('$sanitize'); + } + + + function matchUrl(matcher, parsedUrl) { + if (matcher === 'self') { + return urlIsSameOrigin(parsedUrl); + } else { + // definitely a regex. See adjustMatchers() + return !!matcher.exec(parsedUrl.href); + } + } + + function isResourceUrlAllowedByPolicy(url) { + var parsedUrl = urlResolve(url.toString()); + var i, n, allowed = false; + // Ensure that at least one item from the whitelist allows this url. + for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) { + if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) { + allowed = true; + break; + } + } + if (allowed) { + // Ensure that no item from the blacklist blocked this url. + for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) { + if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) { + allowed = false; + break; + } + } + } + return allowed; + } + + function generateHolderType(Base) { + var holderType = function TrustedValueHolderType(trustedValue) { + this.$$unwrapTrustedValue = function() { + return trustedValue; + }; + }; + if (Base) { + holderType.prototype = new Base(); + } + holderType.prototype.valueOf = function sceValueOf() { + return this.$$unwrapTrustedValue(); + }; + holderType.prototype.toString = function sceToString() { + return this.$$unwrapTrustedValue().toString(); + }; + return holderType; + } + + var trustedValueHolderBase = generateHolderType(), + byType = {}; + + byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase); + byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]); + + /** + * @ngdoc method + * @name $sceDelegate#trustAs + * + * @description + * Returns an object that is trusted by angular for use in specified strict + * contextual escaping contexts (such as ng-bind-html, ng-include, any src + * attribute interpolation, any dom event binding attribute interpolation + * such as for onclick, etc.) that uses the provided value. + * See {@link ng.$sce $sce} for enabling strict contextual escaping. + * + * @param {string} type The kind of context in which this value is safe for use. e.g. url, + * resourceUrl, html, js and css. + * @param {*} value The value that that should be considered trusted/safe. + * @returns {*} A value that can be used to stand in for the provided `value` in places + * where Angular expects a $sce.trustAs() return value. + */ + function trustAs(type, trustedValue) { + var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null); + if (!Constructor) { + throw $sceMinErr('icontext', + 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}', + type, trustedValue); + } + if (trustedValue === null || trustedValue === undefined || trustedValue === '') { + return trustedValue; + } + // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting + // mutable objects, we ensure here that the value passed in is actually a string. + if (typeof trustedValue !== 'string') { + throw $sceMinErr('itype', + 'Attempted to trust a non-string value in a content requiring a string: Context: {0}', + type); + } + return new Constructor(trustedValue); + } + + /** + * @ngdoc method + * @name $sceDelegate#valueOf + * + * @description + * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link + * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. + * + * If the passed parameter is not a value that had been returned by {@link + * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is. + * + * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} + * call or anything else. + * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns + * `value` unchanged. + */ + function valueOf(maybeTrusted) { + if (maybeTrusted instanceof trustedValueHolderBase) { + return maybeTrusted.$$unwrapTrustedValue(); + } else { + return maybeTrusted; + } + } + + /** + * @ngdoc method + * @name $sceDelegate#getTrusted + * + * @description + * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and + * returns the originally supplied value if the queried context type is a supertype of the + * created type. If this condition isn't satisfied, throws an exception. + * + * @param {string} type The kind of context in which this value is to be used. + * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`} call. + * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs + * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception. + */ + function getTrusted(type, maybeTrusted) { + if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') { + return maybeTrusted; + } + var constructor = (byType.hasOwnProperty(type) ? byType[type] : null); + if (constructor && maybeTrusted instanceof constructor) { + return maybeTrusted.$$unwrapTrustedValue(); + } + // If we get here, then we may only take one of two actions. + // 1. sanitize the value for the requested type, or + // 2. throw an exception. + if (type === SCE_CONTEXTS.RESOURCE_URL) { + if (isResourceUrlAllowedByPolicy(maybeTrusted)) { + return maybeTrusted; + } else { + throw $sceMinErr('insecurl', + 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', + maybeTrusted.toString()); + } + } else if (type === SCE_CONTEXTS.HTML) { + return htmlSanitizer(maybeTrusted); + } + throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); + } + + return { trustAs: trustAs, + getTrusted: getTrusted, + valueOf: valueOf }; + }]; +} + + +/** + * @ngdoc provider + * @name $sceProvider + * @description + * + * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service. + * - enable/disable Strict Contextual Escaping (SCE) in a module + * - override the default implementation with a custom delegate + * + * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}. + */ + +/* jshint maxlen: false*/ + +/** + * @ngdoc service + * @name $sce + * @kind function + * + * @description + * + * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS. + * + * # Strict Contextual Escaping + * + * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain + * contexts to result in a value that is marked as safe to use for that context. One example of + * such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer + * to these contexts as privileged or SCE contexts. + * + * As of version 1.2, Angular ships with SCE enabled by default. + * + * Note: When enabled (the default), IE<11 in quirks mode is not supported. In this mode, IE<11 allow + * one to execute arbitrary javascript by the use of the expression() syntax. Refer + * to learn more about them. + * You can ensure your document is in standards mode and not quirks mode by adding `` + * to the top of your HTML document. + * + * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for + * security vulnerabilities such as XSS, clickjacking, etc. a lot easier. + * + * Here's an example of a binding in a privileged context: + * + * ``` + * + *
    + * ``` + * + * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE + * disabled, this application allows the user to render arbitrary HTML into the DIV. + * In a more realistic example, one may be rendering user comments, blog articles, etc. via + * bindings. (HTML is just one example of a context where rendering user controlled input creates + * security vulnerabilities.) + * + * For the case of HTML, you might use a library, either on the client side, or on the server side, + * to sanitize unsafe HTML before binding to the value and rendering it in the document. + * + * How would you ensure that every place that used these types of bindings was bound to a value that + * was sanitized by your library (or returned as safe for rendering by your server?) How can you + * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some + * properties/fields and forgot to update the binding to the sanitized value? + * + * To be secure by default, you want to ensure that any such bindings are disallowed unless you can + * determine that something explicitly says it's safe to use a value for binding in that + * context. You can then audit your code (a simple grep would do) to ensure that this is only done + * for those values that you can easily tell are safe - because they were received from your server, + * sanitized by your library, etc. You can organize your codebase to help with this - perhaps + * allowing only the files in a specific directory to do this. Ensuring that the internal API + * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task. + * + * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} + * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to + * obtain values that will be accepted by SCE / privileged contexts. + * + * + * ## How does it work? + * + * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted + * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link + * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the + * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals. + * + * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link + * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly + * simplified): + * + * ``` + * var ngBindHtmlDirective = ['$sce', function($sce) { + * return function(scope, element, attr) { + * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) { + * element.html(value || ''); + * }); + * }; + * }]; + * ``` + * + * ## Impact on loading templates + * + * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as + * `templateUrl`'s specified by {@link guide/directive directives}. + * + * By default, Angular only loads templates from the same domain and protocol as the application + * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl + * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or + * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist + * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value. + * + * *Please note*: + * The browser's + * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest) + * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/) + * policy apply in addition to this and may further restrict whether the template is successfully + * loaded. This means that without the right CORS policy, loading templates from a different domain + * won't work on all browsers. Also, loading templates from `file://` URL does not work on some + * browsers. + * + * ## This feels like too much overhead + * + * It's important to remember that SCE only applies to interpolation expressions. + * + * If your expressions are constant literals, they're automatically trusted and you don't need to + * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g. + * `
    `) just works. + * + * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them + * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here. + * + * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load + * templates in `ng-include` from your application's domain without having to even know about SCE. + * It blocks loading templates from other domains or loading templates over http from an https + * served document. You can change these by setting your own custom {@link + * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link + * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs. + * + * This significantly reduces the overhead. It is far easier to pay the small overhead and have an + * application that's secure and can be audited to verify that with much more ease than bolting + * security onto an application later. + * + * + * ## What trusted context types are supported? + * + * | Context | Notes | + * |---------------------|----------------| + * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. If an unsafe value is encountered and the {@link ngSanitize $sanitize} module is present this will sanitize the value instead of throwing an error. | + * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. | + * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`
    Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. | + * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. | + * + * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist}
    + * + * Each element in these arrays must be one of the following: + * + * - **'self'** + * - The special **string**, `'self'`, can be used to match against all URLs of the **same + * domain** as the application document using the **same protocol**. + * - **String** (except the special value `'self'`) + * - The string is matched against the full *normalized / absolute URL* of the resource + * being tested (substring matches are not good enough.) + * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters + * match themselves. + * - `*`: matches zero or more occurrences of any character other than one of the following 6 + * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use + * in a whitelist. + * - `**`: matches zero or more occurrences of *any* character. As such, it's not + * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g. + * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might + * not have been the intention.) Its usage at the very end of the path is ok. (e.g. + * http://foo.example.com/templates/**). + * - **RegExp** (*see caveat below*) + * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax + * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to + * accidentally introduce a bug when one updates a complex expression (imho, all regexes should + * have good test coverage.). For instance, the use of `.` in the regex is correct only in a + * small number of cases. A `.` character in the regex used when matching the scheme or a + * subdomain could be matched against a `:` or literal `.` that was likely not intended. It + * is highly recommended to use the string patterns and only fall back to regular expressions + * if they as a last resort. + * - The regular expression must be an instance of RegExp (i.e. not a string.) It is + * matched against the **entire** *normalized / absolute URL* of the resource being tested + * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags + * present on the RegExp (such as multiline, global, ignoreCase) are ignored. + * - If you are generating your JavaScript from some other templating engine (not + * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)), + * remember to escape your regular expression (and be aware that you might need more than + * one level of escaping depending on your templating engine and the way you interpolated + * the value.) Do make use of your platform's escaping mechanism as it might be good + * enough before coding your own. e.g. Ruby has + * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape) + * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape). + * Javascript lacks a similar built in function for escaping. Take a look at Google + * Closure library's [goog.string.regExpEscape(s)]( + * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962). + * + * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example. + * + * ## Show me an example using SCE. + * + * + * + *
    + *

    + * User comments
    + * By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when + * $sanitize is available. If $sanitize isn't available, this results in an error instead of an + * exploit. + *
    + *
    + * {{userComment.name}}: + * + *
    + *
    + *
    + *
    + *
    + * + * + * angular.module('mySceApp', ['ngSanitize']) + * .controller('AppController', ['$http', '$templateCache', '$sce', + * function($http, $templateCache, $sce) { + * var self = this; + * $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) { + * self.userComments = userComments; + * }); + * self.explicitlyTrustedHtml = $sce.trustAsHtml( + * 'Hover over this text.'); + * }]); + * + * + * + * [ + * { "name": "Alice", + * "htmlComment": + * "Is anyone reading this?" + * }, + * { "name": "Bob", + * "htmlComment": "Yes! Am I the only other one?" + * } + * ] + * + * + * + * describe('SCE doc demo', function() { + * it('should sanitize untrusted values', function() { + * expect(element.all(by.css('.htmlComment')).first().getInnerHtml()) + * .toBe('Is anyone reading this?'); + * }); + * + * it('should NOT sanitize explicitly trusted values', function() { + * expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe( + * 'Hover over this text.'); + * }); + * }); + * + *
    + * + * + * + * ## Can I disable SCE completely? + * + * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits + * for little coding overhead. It will be much harder to take an SCE disabled application and + * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE + * for cases where you have a lot of existing code that was written before SCE was introduced and + * you're migrating them a module at a time. + * + * That said, here's how you can completely disable SCE: + * + * ``` + * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) { + * // Completely disable SCE. For demonstration purposes only! + * // Do not use in new projects. + * $sceProvider.enabled(false); + * }); + * ``` + * + */ +/* jshint maxlen: 100 */ + +function $SceProvider() { + var enabled = true; + + /** + * @ngdoc method + * @name $sceProvider#enabled + * @kind function + * + * @param {boolean=} value If provided, then enables/disables SCE. + * @return {boolean} true if SCE is enabled, false otherwise. + * + * @description + * Enables/disables SCE and returns the current value. + */ + this.enabled = function(value) { + if (arguments.length) { + enabled = !!value; + } + return enabled; + }; + + + /* Design notes on the default implementation for SCE. + * + * The API contract for the SCE delegate + * ------------------------------------- + * The SCE delegate object must provide the following 3 methods: + * + * - trustAs(contextEnum, value) + * This method is used to tell the SCE service that the provided value is OK to use in the + * contexts specified by contextEnum. It must return an object that will be accepted by + * getTrusted() for a compatible contextEnum and return this value. + * + * - valueOf(value) + * For values that were not produced by trustAs(), return them as is. For values that were + * produced by trustAs(), return the corresponding input value to trustAs. Basically, if + * trustAs is wrapping the given values into some type, this operation unwraps it when given + * such a value. + * + * - getTrusted(contextEnum, value) + * This function should return the a value that is safe to use in the context specified by + * contextEnum or throw and exception otherwise. + * + * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be + * opaque or wrapped in some holder object. That happens to be an implementation detail. For + * instance, an implementation could maintain a registry of all trusted objects by context. In + * such a case, trustAs() would return the same object that was passed in. getTrusted() would + * return the same object passed in if it was found in the registry under a compatible context or + * throw an exception otherwise. An implementation might only wrap values some of the time based + * on some criteria. getTrusted() might return a value and not throw an exception for special + * constants or objects even if not wrapped. All such implementations fulfill this contract. + * + * + * A note on the inheritance model for SCE contexts + * ------------------------------------------------ + * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This + * is purely an implementation details. + * + * The contract is simply this: + * + * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value) + * will also succeed. + * + * Inheritance happens to capture this in a natural way. In some future, we + * may not use inheritance anymore. That is OK because no code outside of + * sce.js and sceSpecs.js would need to be aware of this detail. + */ + + this.$get = ['$parse', '$sceDelegate', function( + $parse, $sceDelegate) { + // Prereq: Ensure that we're not running in IE<11 quirks mode. In that mode, IE < 11 allow + // the "expression(javascript expression)" syntax which is insecure. + if (enabled && msie < 8) { + throw $sceMinErr('iequirks', + 'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' + + 'mode. You can fix this by adding the text to the top of your HTML ' + + 'document. See http://docs.angularjs.org/api/ng.$sce for more information.'); + } + + var sce = shallowCopy(SCE_CONTEXTS); + + /** + * @ngdoc method + * @name $sce#isEnabled + * @kind function + * + * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you + * have to do it at module config time on {@link ng.$sceProvider $sceProvider}. + * + * @description + * Returns a boolean indicating if SCE is enabled. + */ + sce.isEnabled = function() { + return enabled; + }; + sce.trustAs = $sceDelegate.trustAs; + sce.getTrusted = $sceDelegate.getTrusted; + sce.valueOf = $sceDelegate.valueOf; + + if (!enabled) { + sce.trustAs = sce.getTrusted = function(type, value) { return value; }; + sce.valueOf = identity; + } + + /** + * @ngdoc method + * @name $sce#parseAs + * + * @description + * Converts Angular {@link guide/expression expression} into a function. This is like {@link + * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it + * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*, + * *result*)} + * + * @param {string} type The kind of SCE context in which this result will be used. + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + sce.parseAs = function sceParseAs(type, expr) { + var parsed = $parse(expr); + if (parsed.literal && parsed.constant) { + return parsed; + } else { + return $parse(expr, function(value) { + return sce.getTrusted(type, value); + }); + } + }; + + /** + * @ngdoc method + * @name $sce#trustAs + * + * @description + * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, + * returns an object that is trusted by angular for use in specified strict contextual + * escaping contexts (such as ng-bind-html, ng-include, any src attribute + * interpolation, any dom event binding attribute interpolation such as for onclick, etc.) + * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual + * escaping. + * + * @param {string} type The kind of context in which this value is safe for use. e.g. url, + * resource_url, html, js and css. + * @param {*} value The value that that should be considered trusted/safe. + * @returns {*} A value that can be used to stand in for the provided `value` in places + * where Angular expects a $sce.trustAs() return value. + */ + + /** + * @ngdoc method + * @name $sce#trustAsHtml + * + * @description + * Shorthand method. `$sce.trustAsHtml(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml + * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#trustAsUrl + * + * @description + * Shorthand method. `$sce.trustAsUrl(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl + * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#trustAsResourceUrl + * + * @description + * Shorthand method. `$sce.trustAsResourceUrl(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl + * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the return + * value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#trustAsJs + * + * @description + * Shorthand method. `$sce.trustAsJs(value)` → + * {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`} + * + * @param {*} value The value to trustAs. + * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs + * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives + * only accept expressions that are either literal constants or are the + * return value of {@link ng.$sce#trustAs $sce.trustAs}.) + */ + + /** + * @ngdoc method + * @name $sce#getTrusted + * + * @description + * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, + * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the + * originally supplied value if the queried context type is a supertype of the created type. + * If this condition isn't satisfied, throws an exception. + * + * @param {string} type The kind of context in which this value is to be used. + * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} + * call. + * @returns {*} The value the was originally provided to + * {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context. + * Otherwise, throws an exception. + */ + + /** + * @ngdoc method + * @name $sce#getTrustedHtml + * + * @description + * Shorthand method. `$sce.getTrustedHtml(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedCss + * + * @description + * Shorthand method. `$sce.getTrustedCss(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedUrl + * + * @description + * Shorthand method. `$sce.getTrustedUrl(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedResourceUrl + * + * @description + * Shorthand method. `$sce.getTrustedResourceUrl(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`} + * + * @param {*} value The value to pass to `$sceDelegate.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)` + */ + + /** + * @ngdoc method + * @name $sce#getTrustedJs + * + * @description + * Shorthand method. `$sce.getTrustedJs(value)` → + * {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`} + * + * @param {*} value The value to pass to `$sce.getTrusted`. + * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)` + */ + + /** + * @ngdoc method + * @name $sce#parseAsHtml + * + * @description + * Shorthand method. `$sce.parseAsHtml(expression string)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsCss + * + * @description + * Shorthand method. `$sce.parseAsCss(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsUrl + * + * @description + * Shorthand method. `$sce.parseAsUrl(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsResourceUrl + * + * @description + * Shorthand method. `$sce.parseAsResourceUrl(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + /** + * @ngdoc method + * @name $sce#parseAsJs + * + * @description + * Shorthand method. `$sce.parseAsJs(value)` → + * {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`} + * + * @param {string} expression String expression to compile. + * @returns {function(context, locals)} a function which represents the compiled expression: + * + * * `context` – `{object}` – an object against which any expressions embedded in the strings + * are evaluated against (typically a scope object). + * * `locals` – `{object=}` – local variables context object, useful for overriding values in + * `context`. + */ + + // Shorthand delegations. + var parse = sce.parseAs, + getTrusted = sce.getTrusted, + trustAs = sce.trustAs; + + forEach(SCE_CONTEXTS, function(enumValue, name) { + var lName = lowercase(name); + sce[camelCase("parse_as_" + lName)] = function(expr) { + return parse(enumValue, expr); + }; + sce[camelCase("get_trusted_" + lName)] = function(value) { + return getTrusted(enumValue, value); + }; + sce[camelCase("trust_as_" + lName)] = function(value) { + return trustAs(enumValue, value); + }; + }); + + return sce; + }]; +} + +/** + * !!! This is an undocumented "private" service !!! + * + * @name $sniffer + * @requires $window + * @requires $document + * + * @property {boolean} history Does the browser support html5 history api ? + * @property {boolean} transitions Does the browser support CSS transition events ? + * @property {boolean} animations Does the browser support CSS animation events ? + * + * @description + * This is very simple implementation of testing browser's features. + */ +function $SnifferProvider() { + this.$get = ['$window', '$document', function($window, $document) { + var eventSupport = {}, + android = + int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), + boxee = /Boxee/i.test(($window.navigator || {}).userAgent), + document = $document[0] || {}, + vendorPrefix, + vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/, + bodyStyle = document.body && document.body.style, + transitions = false, + animations = false, + match; + + if (bodyStyle) { + for (var prop in bodyStyle) { + if (match = vendorRegex.exec(prop)) { + vendorPrefix = match[0]; + vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1); + break; + } + } + + if (!vendorPrefix) { + vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit'; + } + + transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle)); + animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle)); + + if (android && (!transitions || !animations)) { + transitions = isString(document.body.style.webkitTransition); + animations = isString(document.body.style.webkitAnimation); + } + } + + + return { + // Android has history.pushState, but it does not update location correctly + // so let's not use the history API at all. + // http://code.google.com/p/android/issues/detail?id=17471 + // https://github.com/angular/angular.js/issues/904 + + // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has + // so let's not use the history API also + // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined + // jshint -W018 + history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee), + // jshint +W018 + hasEvent: function(event) { + // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have + // it. In particular the event is not fired when backspace or delete key are pressed or + // when cut operation is performed. + // IE10+ implements 'input' event but it erroneously fires under various situations, + // e.g. when placeholder changes, or a form is focused. + if (event === 'input' && msie <= 11) return false; + + if (isUndefined(eventSupport[event])) { + var divElm = document.createElement('div'); + eventSupport[event] = 'on' + event in divElm; + } + + return eventSupport[event]; + }, + csp: csp(), + vendorPrefix: vendorPrefix, + transitions: transitions, + animations: animations, + android: android + }; + }]; +} + +var $compileMinErr = minErr('$compile'); + +/** + * @ngdoc service + * @name $templateRequest + * + * @description + * The `$templateRequest` service downloads the provided template using `$http` and, upon success, + * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data + * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted + * by setting the 2nd parameter of the function to true). + * + * @param {string} tpl The HTTP request template URL + * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty + * + * @return {Promise} the HTTP Promise for the given. + * + * @property {number} totalPendingRequests total amount of pending template requests being downloaded. + */ +function $TemplateRequestProvider() { + this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) { + function handleRequestFn(tpl, ignoreRequestError) { + handleRequestFn.totalPendingRequests++; + + var transformResponse = $http.defaults && $http.defaults.transformResponse; + + if (isArray(transformResponse)) { + transformResponse = transformResponse.filter(function(transformer) { + return transformer !== defaultHttpResponseTransform; + }); + } else if (transformResponse === defaultHttpResponseTransform) { + transformResponse = null; + } + + var httpOptions = { + cache: $templateCache, + transformResponse: transformResponse + }; + + return $http.get(tpl, httpOptions) + .finally(function() { + handleRequestFn.totalPendingRequests--; + }) + .then(function(response) { + return response.data; + }, handleError); + + function handleError(resp) { + if (!ignoreRequestError) { + throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl); + } + return $q.reject(resp); + } + } + + handleRequestFn.totalPendingRequests = 0; + + return handleRequestFn; + }]; +} + +function $$TestabilityProvider() { + this.$get = ['$rootScope', '$browser', '$location', + function($rootScope, $browser, $location) { + + /** + * @name $testability + * + * @description + * The private $$testability service provides a collection of methods for use when debugging + * or by automated test and debugging tools. + */ + var testability = {}; + + /** + * @name $$testability#findBindings + * + * @description + * Returns an array of elements that are bound (via ng-bind or {{}}) + * to expressions matching the input. + * + * @param {Element} element The element root to search from. + * @param {string} expression The binding expression to match. + * @param {boolean} opt_exactMatch If true, only returns exact matches + * for the expression. Filters and whitespace are ignored. + */ + testability.findBindings = function(element, expression, opt_exactMatch) { + var bindings = element.getElementsByClassName('ng-binding'); + var matches = []; + forEach(bindings, function(binding) { + var dataBinding = angular.element(binding).data('$binding'); + if (dataBinding) { + forEach(dataBinding, function(bindingName) { + if (opt_exactMatch) { + var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)'); + if (matcher.test(bindingName)) { + matches.push(binding); + } + } else { + if (bindingName.indexOf(expression) != -1) { + matches.push(binding); + } + } + }); + } + }); + return matches; + }; + + /** + * @name $$testability#findModels + * + * @description + * Returns an array of elements that are two-way found via ng-model to + * expressions matching the input. + * + * @param {Element} element The element root to search from. + * @param {string} expression The model expression to match. + * @param {boolean} opt_exactMatch If true, only returns exact matches + * for the expression. + */ + testability.findModels = function(element, expression, opt_exactMatch) { + var prefixes = ['ng-', 'data-ng-', 'ng\\:']; + for (var p = 0; p < prefixes.length; ++p) { + var attributeEquals = opt_exactMatch ? '=' : '*='; + var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]'; + var elements = element.querySelectorAll(selector); + if (elements.length) { + return elements; + } + } + }; + + /** + * @name $$testability#getLocation + * + * @description + * Shortcut for getting the location in a browser agnostic way. Returns + * the path, search, and hash. (e.g. /path?a=b#hash) + */ + testability.getLocation = function() { + return $location.url(); + }; + + /** + * @name $$testability#setLocation + * + * @description + * Shortcut for navigating to a location without doing a full page reload. + * + * @param {string} url The location url (path, search and hash, + * e.g. /path?a=b#hash) to go to. + */ + testability.setLocation = function(url) { + if (url !== $location.url()) { + $location.url(url); + $rootScope.$digest(); + } + }; + + /** + * @name $$testability#whenStable + * + * @description + * Calls the callback when $timeout and $http requests are completed. + * + * @param {function} callback + */ + testability.whenStable = function(callback) { + $browser.notifyWhenNoOutstandingRequests(callback); + }; + + return testability; + }]; +} + +function $TimeoutProvider() { + this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler', + function($rootScope, $browser, $q, $$q, $exceptionHandler) { + var deferreds = {}; + + + /** + * @ngdoc service + * @name $timeout + * + * @description + * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch + * block and delegates any exceptions to + * {@link ng.$exceptionHandler $exceptionHandler} service. + * + * The return value of registering a timeout function is a promise, which will be resolved when + * the timeout is reached and the timeout function is executed. + * + * To cancel a timeout request, call `$timeout.cancel(promise)`. + * + * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to + * synchronously flush the queue of deferred functions. + * + * @param {function()} fn A function, whose execution should be delayed. + * @param {number=} [delay=0] Delay in milliseconds. + * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise + * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block. + * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this + * promise will be resolved with is the return value of the `fn` function. + * + */ + function timeout(fn, delay, invokeApply) { + var skipApply = (isDefined(invokeApply) && !invokeApply), + deferred = (skipApply ? $$q : $q).defer(), + promise = deferred.promise, + timeoutId; + + timeoutId = $browser.defer(function() { + try { + deferred.resolve(fn()); + } catch (e) { + deferred.reject(e); + $exceptionHandler(e); + } + finally { + delete deferreds[promise.$$timeoutId]; + } + + if (!skipApply) $rootScope.$apply(); + }, delay); + + promise.$$timeoutId = timeoutId; + deferreds[timeoutId] = deferred; + + return promise; + } + + + /** + * @ngdoc method + * @name $timeout#cancel + * + * @description + * Cancels a task associated with the `promise`. As a result of this, the promise will be + * resolved with a rejection. + * + * @param {Promise=} promise Promise returned by the `$timeout` function. + * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully + * canceled. + */ + timeout.cancel = function(promise) { + if (promise && promise.$$timeoutId in deferreds) { + deferreds[promise.$$timeoutId].reject('canceled'); + delete deferreds[promise.$$timeoutId]; + return $browser.defer.cancel(promise.$$timeoutId); + } + return false; + }; + + return timeout; + }]; +} + +// NOTE: The usage of window and document instead of $window and $document here is +// deliberate. This service depends on the specific behavior of anchor nodes created by the +// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and +// cause us to break tests. In addition, when the browser resolves a URL for XHR, it +// doesn't know about mocked locations and resolves URLs to the real document - which is +// exactly the behavior needed here. There is little value is mocking these out for this +// service. +var urlParsingNode = document.createElement("a"); +var originUrl = urlResolve(window.location.href); + + +/** + * + * Implementation Notes for non-IE browsers + * ---------------------------------------- + * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM, + * results both in the normalizing and parsing of the URL. Normalizing means that a relative + * URL will be resolved into an absolute URL in the context of the application document. + * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related + * properties are all populated to reflect the normalized URL. This approach has wide + * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See + * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html + * + * Implementation Notes for IE + * --------------------------- + * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other + * browsers. However, the parsed components will not be set if the URL assigned did not specify + * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We + * work around that by performing the parsing in a 2nd step by taking a previously normalized + * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the + * properties such as protocol, hostname, port, etc. + * + * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one + * uses the inner HTML approach to assign the URL as part of an HTML snippet - + * http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL. + * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception. + * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that + * method and IE < 8 is unsupported. + * + * References: + * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement + * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html + * http://url.spec.whatwg.org/#urlutils + * https://github.com/angular/angular.js/pull/2902 + * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ + * + * @kind function + * @param {string} url The URL to be parsed. + * @description Normalizes and parses a URL. + * @returns {object} Returns the normalized URL as a dictionary. + * + * | member name | Description | + * |---------------|----------------| + * | href | A normalized version of the provided URL if it was not an absolute URL | + * | protocol | The protocol including the trailing colon | + * | host | The host and port (if the port is non-default) of the normalizedUrl | + * | search | The search params, minus the question mark | + * | hash | The hash string, minus the hash symbol + * | hostname | The hostname + * | port | The port, without ":" + * | pathname | The pathname, beginning with "/" + * + */ +function urlResolve(url) { + var href = url; + + if (msie) { + // Normalize before parse. Refer Implementation Notes on why this is + // done in two steps on IE. + urlParsingNode.setAttribute("href", href); + href = urlParsingNode.href; + } + + urlParsingNode.setAttribute('href', href); + + // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils + return { + href: urlParsingNode.href, + protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', + host: urlParsingNode.host, + search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', + hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', + hostname: urlParsingNode.hostname, + port: urlParsingNode.port, + pathname: (urlParsingNode.pathname.charAt(0) === '/') + ? urlParsingNode.pathname + : '/' + urlParsingNode.pathname + }; +} + +/** + * Parse a request URL and determine whether this is a same-origin request as the application document. + * + * @param {string|object} requestUrl The url of the request as a string that will be resolved + * or a parsed URL object. + * @returns {boolean} Whether the request is for the same origin as the application document. + */ +function urlIsSameOrigin(requestUrl) { + var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; + return (parsed.protocol === originUrl.protocol && + parsed.host === originUrl.host); +} + +/** + * @ngdoc service + * @name $window + * + * @description + * A reference to the browser's `window` object. While `window` + * is globally available in JavaScript, it causes testability problems, because + * it is a global variable. In angular we always refer to it through the + * `$window` service, so it may be overridden, removed or mocked for testing. + * + * Expressions, like the one defined for the `ngClick` directive in the example + * below, are evaluated with respect to the current scope. Therefore, there is + * no risk of inadvertently coding in a dependency on a global value in such an + * expression. + * + * @example + + + +
    + + +
    +
    + + it('should display the greeting in the input box', function() { + element(by.model('greeting')).sendKeys('Hello, E2E Tests'); + // If we click the button it will block the test runner + // element(':button').click(); + }); + +
    + */ +function $WindowProvider() { + this.$get = valueFn(window); +} + +/* global currencyFilter: true, + dateFilter: true, + filterFilter: true, + jsonFilter: true, + limitToFilter: true, + lowercaseFilter: true, + numberFilter: true, + orderByFilter: true, + uppercaseFilter: true, + */ + +/** + * @ngdoc provider + * @name $filterProvider + * @description + * + * Filters are just functions which transform input to an output. However filters need to be + * Dependency Injected. To achieve this a filter definition consists of a factory function which is + * annotated with dependencies and is responsible for creating a filter function. + * + * ```js + * // Filter registration + * function MyModule($provide, $filterProvider) { + * // create a service to demonstrate injection (not always needed) + * $provide.value('greet', function(name){ + * return 'Hello ' + name + '!'; + * }); + * + * // register a filter factory which uses the + * // greet service to demonstrate DI. + * $filterProvider.register('greet', function(greet){ + * // return the filter function which uses the greet service + * // to generate salutation + * return function(text) { + * // filters need to be forgiving so check input validity + * return text && greet(text) || text; + * }; + * }); + * } + * ``` + * + * The filter function is registered with the `$injector` under the filter name suffix with + * `Filter`. + * + * ```js + * it('should be the same instance', inject( + * function($filterProvider) { + * $filterProvider.register('reverse', function(){ + * return ...; + * }); + * }, + * function($filter, reverseFilter) { + * expect($filter('reverse')).toBe(reverseFilter); + * }); + * ``` + * + * + * For more information about how angular filters work, and how to create your own filters, see + * {@link guide/filter Filters} in the Angular Developer Guide. + */ + +/** + * @ngdoc service + * @name $filter + * @kind function + * @description + * Filters are used for formatting data displayed to the user. + * + * The general syntax in templates is as follows: + * + * {{ expression [| filter_name[:parameter_value] ... ] }} + * + * @param {String} name Name of the filter function to retrieve + * @return {Function} the filter function + * @example + + +
    +

    {{ originalText }}

    +

    {{ filteredText }}

    +
    +
    + + + angular.module('filterExample', []) + .controller('MainCtrl', function($scope, $filter) { + $scope.originalText = 'hello'; + $scope.filteredText = $filter('uppercase')($scope.originalText); + }); + +
    + */ +$FilterProvider.$inject = ['$provide']; +function $FilterProvider($provide) { + var suffix = 'Filter'; + + /** + * @ngdoc method + * @name $filterProvider#register + * @param {string|Object} name Name of the filter function, or an object map of filters where + * the keys are the filter names and the values are the filter factories. + * @returns {Object} Registered filter instance, or if a map of filters was provided then a map + * of the registered filter instances. + */ + function register(name, factory) { + if (isObject(name)) { + var filters = {}; + forEach(name, function(filter, key) { + filters[key] = register(key, filter); + }); + return filters; + } else { + return $provide.factory(name + suffix, factory); + } + } + this.register = register; + + this.$get = ['$injector', function($injector) { + return function(name) { + return $injector.get(name + suffix); + }; + }]; + + //////////////////////////////////////// + + /* global + currencyFilter: false, + dateFilter: false, + filterFilter: false, + jsonFilter: false, + limitToFilter: false, + lowercaseFilter: false, + numberFilter: false, + orderByFilter: false, + uppercaseFilter: false, + */ + + register('currency', currencyFilter); + register('date', dateFilter); + register('filter', filterFilter); + register('json', jsonFilter); + register('limitTo', limitToFilter); + register('lowercase', lowercaseFilter); + register('number', numberFilter); + register('orderBy', orderByFilter); + register('uppercase', uppercaseFilter); +} + +/** + * @ngdoc filter + * @name filter + * @kind function + * + * @description + * Selects a subset of items from `array` and returns it as a new array. + * + * @param {Array} array The source array. + * @param {string|Object|function()} expression The predicate to be used for selecting items from + * `array`. + * + * Can be one of: + * + * - `string`: The string is used for matching against the contents of the `array`. All strings or + * objects with string properties in `array` that match this string will be returned. This also + * applies to nested object properties. + * The predicate can be negated by prefixing the string with `!`. + * + * - `Object`: A pattern object can be used to filter specific properties on objects contained + * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items + * which have property `name` containing "M" and property `phone` containing "1". A special + * property name `$` can be used (as in `{$:"text"}`) to accept a match against any + * property of the object or its nested object properties. That's equivalent to the simple + * substring match with a `string` as described above. The predicate can be negated by prefixing + * the string with `!`. + * For example `{name: "!M"}` predicate will return an array of items which have property `name` + * not containing "M". + * + * Note that a named property will match properties on the same level only, while the special + * `$` property will match properties on the same level or deeper. E.g. an array item like + * `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but + * **will** be matched by `{$: 'John'}`. + * + * - `function(value, index)`: A predicate function can be used to write arbitrary filters. The + * function is called for each element of `array`. The final result is an array of those + * elements that the predicate returned true for. + * + * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in + * determining if the expected value (from the filter expression) and actual value (from + * the object in the array) should be considered a match. + * + * Can be one of: + * + * - `function(actual, expected)`: + * The function will be given the object value and the predicate value to compare and + * should return true if both values should be considered equal. + * + * - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`. + * This is essentially strict comparison of expected and actual. + * + * - `false|undefined`: A short hand for a function which will look for a substring match in case + * insensitive way. + * + * @example + + +
    + + Search: + + + + + + +
    NamePhone
    {{friend.name}}{{friend.phone}}
    +
    + Any:
    + Name only
    + Phone only
    + Equality
    + + + + + + +
    NamePhone
    {{friendObj.name}}{{friendObj.phone}}
    +
    + + var expectFriendNames = function(expectedNames, key) { + element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) { + arr.forEach(function(wd, i) { + expect(wd.getText()).toMatch(expectedNames[i]); + }); + }); + }; + + it('should search across all fields when filtering with a string', function() { + var searchText = element(by.model('searchText')); + searchText.clear(); + searchText.sendKeys('m'); + expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend'); + + searchText.clear(); + searchText.sendKeys('76'); + expectFriendNames(['John', 'Julie'], 'friend'); + }); + + it('should search in specific fields when filtering with a predicate object', function() { + var searchAny = element(by.model('search.$')); + searchAny.clear(); + searchAny.sendKeys('i'); + expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj'); + }); + it('should use a equal comparison when comparator is true', function() { + var searchName = element(by.model('search.name')); + var strict = element(by.model('strict')); + searchName.clear(); + searchName.sendKeys('Julie'); + strict.click(); + expectFriendNames(['Julie'], 'friendObj'); + }); + +
    + */ +function filterFilter() { + return function(array, expression, comparator) { + if (!isArray(array)) return array; + + var predicateFn; + var matchAgainstAnyProp; + + switch (typeof expression) { + case 'function': + predicateFn = expression; + break; + case 'boolean': + case 'number': + case 'string': + matchAgainstAnyProp = true; + //jshint -W086 + case 'object': + //jshint +W086 + predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp); + break; + default: + return array; + } + + return array.filter(predicateFn); + }; +} + +// Helper functions for `filterFilter` +function createPredicateFn(expression, comparator, matchAgainstAnyProp) { + var shouldMatchPrimitives = isObject(expression) && ('$' in expression); + var predicateFn; + + if (comparator === true) { + comparator = equals; + } else if (!isFunction(comparator)) { + comparator = function(actual, expected) { + if (isObject(actual) || isObject(expected)) { + // Prevent an object to be considered equal to a string like `'[object'` + return false; + } + + actual = lowercase('' + actual); + expected = lowercase('' + expected); + return actual.indexOf(expected) !== -1; + }; + } + + predicateFn = function(item) { + if (shouldMatchPrimitives && !isObject(item)) { + return deepCompare(item, expression.$, comparator, false); + } + return deepCompare(item, expression, comparator, matchAgainstAnyProp); + }; + + return predicateFn; +} + +function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) { + var actualType = typeof actual; + var expectedType = typeof expected; + + if ((expectedType === 'string') && (expected.charAt(0) === '!')) { + return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp); + } else if (isArray(actual)) { + // In case `actual` is an array, consider it a match + // if ANY of it's items matches `expected` + return actual.some(function(item) { + return deepCompare(item, expected, comparator, matchAgainstAnyProp); + }); + } + + switch (actualType) { + case 'object': + var key; + if (matchAgainstAnyProp) { + for (key in actual) { + if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) { + return true; + } + } + return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false); + } else if (expectedType === 'object') { + for (key in expected) { + var expectedVal = expected[key]; + if (isFunction(expectedVal)) { + continue; + } + + var matchAnyProperty = key === '$'; + var actualVal = matchAnyProperty ? actual : actual[key]; + if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) { + return false; + } + } + return true; + } else { + return comparator(actual, expected); + } + break; + case 'function': + return false; + default: + return comparator(actual, expected); + } +} + +/** + * @ngdoc filter + * @name currency + * @kind function + * + * @description + * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default + * symbol for current locale is used. + * + * @param {number} amount Input to filter. + * @param {string=} symbol Currency symbol or identifier to be displayed. + * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale + * @returns {string} Formatted number. + * + * + * @example + + + +
    +
    + default currency symbol ($): {{amount | currency}}
    + custom currency identifier (USD$): {{amount | currency:"USD$"}} + no fractions (0): {{amount | currency:"USD$":0}} +
    +
    + + it('should init with 1234.56', function() { + expect(element(by.id('currency-default')).getText()).toBe('$1,234.56'); + expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56'); + expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235'); + }); + it('should update', function() { + if (browser.params.browser == 'safari') { + // Safari does not understand the minus key. See + // https://github.com/angular/protractor/issues/481 + return; + } + element(by.model('amount')).clear(); + element(by.model('amount')).sendKeys('-1234'); + expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)'); + expect(element(by.id('currency-custom')).getText()).toBe('(USD$1,234.00)'); + expect(element(by.id('currency-no-fractions')).getText()).toBe('(USD$1,234)'); + }); + +
    + */ +currencyFilter.$inject = ['$locale']; +function currencyFilter($locale) { + var formats = $locale.NUMBER_FORMATS; + return function(amount, currencySymbol, fractionSize) { + if (isUndefined(currencySymbol)) { + currencySymbol = formats.CURRENCY_SYM; + } + + if (isUndefined(fractionSize)) { + fractionSize = formats.PATTERNS[1].maxFrac; + } + + // if null or undefined pass it through + return (amount == null) + ? amount + : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize). + replace(/\u00A4/g, currencySymbol); + }; +} + +/** + * @ngdoc filter + * @name number + * @kind function + * + * @description + * Formats a number as text. + * + * If the input is not a number an empty string is returned. + * + * @param {number|string} number Number to format. + * @param {(number|string)=} fractionSize Number of decimal places to round the number to. + * If this is not provided then the fraction size is computed from the current locale's number + * formatting pattern. In the case of the default locale, it will be 3. + * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit. + * + * @example + + + +
    + Enter number:
    + Default formatting: {{val | number}}
    + No fractions: {{val | number:0}}
    + Negative number: {{-val | number:4}} +
    +
    + + it('should format numbers', function() { + expect(element(by.id('number-default')).getText()).toBe('1,234.568'); + expect(element(by.binding('val | number:0')).getText()).toBe('1,235'); + expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679'); + }); + + it('should update', function() { + element(by.model('val')).clear(); + element(by.model('val')).sendKeys('3374.333'); + expect(element(by.id('number-default')).getText()).toBe('3,374.333'); + expect(element(by.binding('val | number:0')).getText()).toBe('3,374'); + expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330'); + }); + +
    + */ + + +numberFilter.$inject = ['$locale']; +function numberFilter($locale) { + var formats = $locale.NUMBER_FORMATS; + return function(number, fractionSize) { + + // if null or undefined pass it through + return (number == null) + ? number + : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP, + fractionSize); + }; +} + +var DECIMAL_SEP = '.'; +function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { + if (!isFinite(number) || isObject(number)) return ''; + + var isNegative = number < 0; + number = Math.abs(number); + var numStr = number + '', + formatedText = '', + parts = []; + + var hasExponent = false; + if (numStr.indexOf('e') !== -1) { + var match = numStr.match(/([\d\.]+)e(-?)(\d+)/); + if (match && match[2] == '-' && match[3] > fractionSize + 1) { + number = 0; + } else { + formatedText = numStr; + hasExponent = true; + } + } + + if (!hasExponent) { + var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length; + + // determine fractionSize if it is not specified + if (isUndefined(fractionSize)) { + fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac); + } + + // safely round numbers in JS without hitting imprecisions of floating-point arithmetics + // inspired by: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round + number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize); + + var fraction = ('' + number).split(DECIMAL_SEP); + var whole = fraction[0]; + fraction = fraction[1] || ''; + + var i, pos = 0, + lgroup = pattern.lgSize, + group = pattern.gSize; + + if (whole.length >= (lgroup + group)) { + pos = whole.length - lgroup; + for (i = 0; i < pos; i++) { + if ((pos - i) % group === 0 && i !== 0) { + formatedText += groupSep; + } + formatedText += whole.charAt(i); + } + } + + for (i = pos; i < whole.length; i++) { + if ((whole.length - i) % lgroup === 0 && i !== 0) { + formatedText += groupSep; + } + formatedText += whole.charAt(i); + } + + // format fraction part. + while (fraction.length < fractionSize) { + fraction += '0'; + } + + if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize); + } else { + if (fractionSize > 0 && number < 1) { + formatedText = number.toFixed(fractionSize); + number = parseFloat(formatedText); + } + } + + if (number === 0) { + isNegative = false; + } + + parts.push(isNegative ? pattern.negPre : pattern.posPre, + formatedText, + isNegative ? pattern.negSuf : pattern.posSuf); + return parts.join(''); +} + +function padNumber(num, digits, trim) { + var neg = ''; + if (num < 0) { + neg = '-'; + num = -num; + } + num = '' + num; + while (num.length < digits) num = '0' + num; + if (trim) + num = num.substr(num.length - digits); + return neg + num; +} + + +function dateGetter(name, size, offset, trim) { + offset = offset || 0; + return function(date) { + var value = date['get' + name](); + if (offset > 0 || value > -offset) + value += offset; + if (value === 0 && offset == -12) value = 12; + return padNumber(value, size, trim); + }; +} + +function dateStrGetter(name, shortForm) { + return function(date, formats) { + var value = date['get' + name](); + var get = uppercase(shortForm ? ('SHORT' + name) : name); + + return formats[get][value]; + }; +} + +function timeZoneGetter(date) { + var zone = -1 * date.getTimezoneOffset(); + var paddedZone = (zone >= 0) ? "+" : ""; + + paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + + padNumber(Math.abs(zone % 60), 2); + + return paddedZone; +} + +function getFirstThursdayOfYear(year) { + // 0 = index of January + var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay(); + // 4 = index of Thursday (+1 to account for 1st = 5) + // 11 = index of *next* Thursday (+1 account for 1st = 12) + return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst); +} + +function getThursdayThisWeek(datetime) { + return new Date(datetime.getFullYear(), datetime.getMonth(), + // 4 = index of Thursday + datetime.getDate() + (4 - datetime.getDay())); +} + +function weekGetter(size) { + return function(date) { + var firstThurs = getFirstThursdayOfYear(date.getFullYear()), + thisThurs = getThursdayThisWeek(date); + + var diff = +thisThurs - +firstThurs, + result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week + + return padNumber(result, size); + }; +} + +function ampmGetter(date, formats) { + return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]; +} + +var DATE_FORMATS = { + yyyy: dateGetter('FullYear', 4), + yy: dateGetter('FullYear', 2, 0, true), + y: dateGetter('FullYear', 1), + MMMM: dateStrGetter('Month'), + MMM: dateStrGetter('Month', true), + MM: dateGetter('Month', 2, 1), + M: dateGetter('Month', 1, 1), + dd: dateGetter('Date', 2), + d: dateGetter('Date', 1), + HH: dateGetter('Hours', 2), + H: dateGetter('Hours', 1), + hh: dateGetter('Hours', 2, -12), + h: dateGetter('Hours', 1, -12), + mm: dateGetter('Minutes', 2), + m: dateGetter('Minutes', 1), + ss: dateGetter('Seconds', 2), + s: dateGetter('Seconds', 1), + // while ISO 8601 requires fractions to be prefixed with `.` or `,` + // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions + sss: dateGetter('Milliseconds', 3), + EEEE: dateStrGetter('Day'), + EEE: dateStrGetter('Day', true), + a: ampmGetter, + Z: timeZoneGetter, + ww: weekGetter(2), + w: weekGetter(1) +}; + +var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/, + NUMBER_STRING = /^\-?\d+$/; + +/** + * @ngdoc filter + * @name date + * @kind function + * + * @description + * Formats `date` to a string based on the requested `format`. + * + * `format` string can be composed of the following elements: + * + * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010) + * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) + * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199) + * * `'MMMM'`: Month in year (January-December) + * * `'MMM'`: Month in year (Jan-Dec) + * * `'MM'`: Month in year, padded (01-12) + * * `'M'`: Month in year (1-12) + * * `'dd'`: Day in month, padded (01-31) + * * `'d'`: Day in month (1-31) + * * `'EEEE'`: Day in Week,(Sunday-Saturday) + * * `'EEE'`: Day in Week, (Sun-Sat) + * * `'HH'`: Hour in day, padded (00-23) + * * `'H'`: Hour in day (0-23) + * * `'hh'`: Hour in AM/PM, padded (01-12) + * * `'h'`: Hour in AM/PM, (1-12) + * * `'mm'`: Minute in hour, padded (00-59) + * * `'m'`: Minute in hour (0-59) + * * `'ss'`: Second in minute, padded (00-59) + * * `'s'`: Second in minute (0-59) + * * `'sss'`: Millisecond in second, padded (000-999) + * * `'a'`: AM/PM marker + * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) + * * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year + * * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year + * + * `format` string can also be one of the following predefined + * {@link guide/i18n localizable formats}: + * + * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale + * (e.g. Sep 3, 2010 12:05:08 PM) + * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 PM) + * * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US locale + * (e.g. Friday, September 3, 2010) + * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010) + * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010) + * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10) + * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM) + * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM) + * + * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g. + * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence + * (e.g. `"h 'o''clock'"`). + * + * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or + * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its + * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is + * specified in the string input, the time is considered to be in the local timezone. + * @param {string=} format Formatting rules (see Description). If not specified, + * `mediumDate` is used. + * @param {string=} timezone Timezone to be used for formatting. Right now, only `'UTC'` is supported. + * If not specified, the timezone of the browser will be used. + * @returns {string} Formatted string or the input if input is not recognized as date/millis. + * + * @example + + + {{1288323623006 | date:'medium'}}: + {{1288323623006 | date:'medium'}}
    + {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}: + {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}
    + {{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}: + {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}
    + {{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}: + {{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}
    +
    + + it('should format date', function() { + expect(element(by.binding("1288323623006 | date:'medium'")).getText()). + toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/); + expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()). + toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/); + expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()). + toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/); + expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()). + toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/); + }); + +
    + */ +dateFilter.$inject = ['$locale']; +function dateFilter($locale) { + + + var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; + // 1 2 3 4 5 6 7 8 9 10 11 + function jsonStringToDate(string) { + var match; + if (match = string.match(R_ISO8601_STR)) { + var date = new Date(0), + tzHour = 0, + tzMin = 0, + dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear, + timeSetter = match[8] ? date.setUTCHours : date.setHours; + + if (match[9]) { + tzHour = int(match[9] + match[10]); + tzMin = int(match[9] + match[11]); + } + dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3])); + var h = int(match[4] || 0) - tzHour; + var m = int(match[5] || 0) - tzMin; + var s = int(match[6] || 0); + var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000); + timeSetter.call(date, h, m, s, ms); + return date; + } + return string; + } + + + return function(date, format, timezone) { + var text = '', + parts = [], + fn, match; + + format = format || 'mediumDate'; + format = $locale.DATETIME_FORMATS[format] || format; + if (isString(date)) { + date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date); + } + + if (isNumber(date)) { + date = new Date(date); + } + + if (!isDate(date)) { + return date; + } + + while (format) { + match = DATE_FORMATS_SPLIT.exec(format); + if (match) { + parts = concat(parts, match, 1); + format = parts.pop(); + } else { + parts.push(format); + format = null; + } + } + + if (timezone && timezone === 'UTC') { + date = new Date(date.getTime()); + date.setMinutes(date.getMinutes() + date.getTimezoneOffset()); + } + forEach(parts, function(value) { + fn = DATE_FORMATS[value]; + text += fn ? fn(date, $locale.DATETIME_FORMATS) + : value.replace(/(^'|'$)/g, '').replace(/''/g, "'"); + }); + + return text; + }; +} + + +/** + * @ngdoc filter + * @name json + * @kind function + * + * @description + * Allows you to convert a JavaScript object into JSON string. + * + * This filter is mostly useful for debugging. When using the double curly {{value}} notation + * the binding is automatically converted to JSON. + * + * @param {*} object Any JavaScript object (including arrays and primitive types) to filter. + * @param {number=} spacing The number of spaces to use per indentation, defaults to 2. + * @returns {string} JSON string. + * + * + * @example + + +
    {{ {'name':'value'} | json }}
    +
    {{ {'name':'value'} | json:4 }}
    +
    + + it('should jsonify filtered objects', function() { + expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/); + expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/); + }); + +
    + * + */ +function jsonFilter() { + return function(object, spacing) { + if (isUndefined(spacing)) { + spacing = 2; + } + return toJson(object, spacing); + }; +} + + +/** + * @ngdoc filter + * @name lowercase + * @kind function + * @description + * Converts string to lowercase. + * @see angular.lowercase + */ +var lowercaseFilter = valueFn(lowercase); + + +/** + * @ngdoc filter + * @name uppercase + * @kind function + * @description + * Converts string to uppercase. + * @see angular.uppercase + */ +var uppercaseFilter = valueFn(uppercase); + +/** + * @ngdoc filter + * @name limitTo + * @kind function + * + * @description + * Creates a new array or string containing only a specified number of elements. The elements + * are taken from either the beginning or the end of the source array, string or number, as specified by + * the value and sign (positive or negative) of `limit`. If a number is used as input, it is + * converted to a string. + * + * @param {Array|string|number} input Source array, string or number to be limited. + * @param {string|number} limit The length of the returned array or string. If the `limit` number + * is positive, `limit` number of items from the beginning of the source array/string are copied. + * If the number is negative, `limit` number of items from the end of the source array/string + * are copied. The `limit` will be trimmed if it exceeds `array.length` + * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array + * had less than `limit` elements. + * + * @example + + + +
    + Limit {{numbers}} to: +

    Output numbers: {{ numbers | limitTo:numLimit }}

    + Limit {{letters}} to: +

    Output letters: {{ letters | limitTo:letterLimit }}

    + Limit {{longNumber}} to: +

    Output long number: {{ longNumber | limitTo:longNumberLimit }}

    +
    +
    + + var numLimitInput = element(by.model('numLimit')); + var letterLimitInput = element(by.model('letterLimit')); + var longNumberLimitInput = element(by.model('longNumberLimit')); + var limitedNumbers = element(by.binding('numbers | limitTo:numLimit')); + var limitedLetters = element(by.binding('letters | limitTo:letterLimit')); + var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit')); + + it('should limit the number array to first three items', function() { + expect(numLimitInput.getAttribute('value')).toBe('3'); + expect(letterLimitInput.getAttribute('value')).toBe('3'); + expect(longNumberLimitInput.getAttribute('value')).toBe('3'); + expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]'); + expect(limitedLetters.getText()).toEqual('Output letters: abc'); + expect(limitedLongNumber.getText()).toEqual('Output long number: 234'); + }); + + // There is a bug in safari and protractor that doesn't like the minus key + // it('should update the output when -3 is entered', function() { + // numLimitInput.clear(); + // numLimitInput.sendKeys('-3'); + // letterLimitInput.clear(); + // letterLimitInput.sendKeys('-3'); + // longNumberLimitInput.clear(); + // longNumberLimitInput.sendKeys('-3'); + // expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]'); + // expect(limitedLetters.getText()).toEqual('Output letters: ghi'); + // expect(limitedLongNumber.getText()).toEqual('Output long number: 342'); + // }); + + it('should not exceed the maximum size of input array', function() { + numLimitInput.clear(); + numLimitInput.sendKeys('100'); + letterLimitInput.clear(); + letterLimitInput.sendKeys('100'); + longNumberLimitInput.clear(); + longNumberLimitInput.sendKeys('100'); + expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]'); + expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi'); + expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342'); + }); + +
    +*/ +function limitToFilter() { + return function(input, limit) { + if (isNumber(input)) input = input.toString(); + if (!isArray(input) && !isString(input)) return input; + + if (Math.abs(Number(limit)) === Infinity) { + limit = Number(limit); + } else { + limit = int(limit); + } + + //NaN check on limit + if (limit) { + return limit > 0 ? input.slice(0, limit) : input.slice(limit); + } else { + return isString(input) ? "" : []; + } + }; +} + +/** + * @ngdoc filter + * @name orderBy + * @kind function + * + * @description + * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically + * for strings and numerically for numbers. Note: if you notice numbers are not being sorted + * correctly, make sure they are actually being saved as numbers and not strings. + * + * @param {Array} array The array to sort. + * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be + * used by the comparator to determine the order of elements. + * + * Can be one of: + * + * - `function`: Getter function. The result of this function will be sorted using the + * `<`, `=`, `>` operator. + * - `string`: An Angular expression. The result of this expression is used to compare elements + * (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by + * 3 first characters of a property called `name`). The result of a constant expression + * is interpreted as a property name to be used in comparisons (for example `"special name"` + * to sort object by the value of their `special name` property). An expression can be + * optionally prefixed with `+` or `-` to control ascending or descending sort order + * (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array + * element itself is used to compare where sorting. + * - `Array`: An array of function or string predicates. The first predicate in the array + * is used for sorting, but when two items are equivalent, the next predicate is used. + * + * If the predicate is missing or empty then it defaults to `'+'`. + * + * @param {boolean=} reverse Reverse the order of the array. + * @returns {Array} Sorted copy of the source array. + * + * @example + + + +
    +
    Sorting predicate = {{predicate}}; reverse = {{reverse}}
    +
    + [ unsorted ] + + + + + + + + + + + +
    Name + (^)Phone NumberAge
    {{friend.name}}{{friend.phone}}{{friend.age}}
    +
    +
    +
    + * + * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the + * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the + * desired parameters. + * + * Example: + * + * @example + + +
    + + + + + + + + + + + +
    Name + (^)Phone NumberAge
    {{friend.name}}{{friend.phone}}{{friend.age}}
    +
    +
    + + + angular.module('orderByExample', []) + .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) { + var orderBy = $filter('orderBy'); + $scope.friends = [ + { name: 'John', phone: '555-1212', age: 10 }, + { name: 'Mary', phone: '555-9876', age: 19 }, + { name: 'Mike', phone: '555-4321', age: 21 }, + { name: 'Adam', phone: '555-5678', age: 35 }, + { name: 'Julie', phone: '555-8765', age: 29 } + ]; + $scope.order = function(predicate, reverse) { + $scope.friends = orderBy($scope.friends, predicate, reverse); + }; + $scope.order('-age',false); + }]); + +
    + */ +orderByFilter.$inject = ['$parse']; +function orderByFilter($parse) { + return function(array, sortPredicate, reverseOrder) { + if (!(isArrayLike(array))) return array; + sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate]; + if (sortPredicate.length === 0) { sortPredicate = ['+']; } + sortPredicate = sortPredicate.map(function(predicate) { + var descending = false, get = predicate || identity; + if (isString(predicate)) { + if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) { + descending = predicate.charAt(0) == '-'; + predicate = predicate.substring(1); + } + if (predicate === '') { + // Effectively no predicate was passed so we compare identity + return reverseComparator(compare, descending); + } + get = $parse(predicate); + if (get.constant) { + var key = get(); + return reverseComparator(function(a, b) { + return compare(a[key], b[key]); + }, descending); + } + } + return reverseComparator(function(a, b) { + return compare(get(a),get(b)); + }, descending); + }); + return slice.call(array).sort(reverseComparator(comparator, reverseOrder)); + + function comparator(o1, o2) { + for (var i = 0; i < sortPredicate.length; i++) { + var comp = sortPredicate[i](o1, o2); + if (comp !== 0) return comp; + } + return 0; + } + function reverseComparator(comp, descending) { + return descending + ? function(a, b) {return comp(b,a);} + : comp; + } + + function isPrimitive(value) { + switch (typeof value) { + case 'number': /* falls through */ + case 'boolean': /* falls through */ + case 'string': + return true; + default: + return false; + } + } + + function objectToString(value) { + if (value === null) return 'null'; + if (typeof value.valueOf === 'function') { + value = value.valueOf(); + if (isPrimitive(value)) return value; + } + if (typeof value.toString === 'function') { + value = value.toString(); + if (isPrimitive(value)) return value; + } + return ''; + } + + function compare(v1, v2) { + var t1 = typeof v1; + var t2 = typeof v2; + if (t1 === t2 && t1 === "object") { + v1 = objectToString(v1); + v2 = objectToString(v2); + } + if (t1 === t2) { + if (t1 === "string") { + v1 = v1.toLowerCase(); + v2 = v2.toLowerCase(); + } + if (v1 === v2) return 0; + return v1 < v2 ? -1 : 1; + } else { + return t1 < t2 ? -1 : 1; + } + } + }; +} + +function ngDirective(directive) { + if (isFunction(directive)) { + directive = { + link: directive + }; + } + directive.restrict = directive.restrict || 'AC'; + return valueFn(directive); +} + +/** + * @ngdoc directive + * @name a + * @restrict E + * + * @description + * Modifies the default behavior of the html A tag so that the default action is prevented when + * the href attribute is empty. + * + * This change permits the easy creation of action links with the `ngClick` directive + * without changing the location or causing page reloads, e.g.: + * `Add Item` + */ +var htmlAnchorDirective = valueFn({ + restrict: 'E', + compile: function(element, attr) { + if (!attr.href && !attr.xlinkHref && !attr.name) { + return function(scope, element) { + // If the linked element is not an anchor tag anymore, do nothing + if (element[0].nodeName.toLowerCase() !== 'a') return; + + // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute. + var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ? + 'xlink:href' : 'href'; + element.on('click', function(event) { + // if we have no href url, then don't navigate anywhere. + if (!element.attr(href)) { + event.preventDefault(); + } + }); + }; + } + } +}); + +/** + * @ngdoc directive + * @name ngHref + * @restrict A + * @priority 99 + * + * @description + * Using Angular markup like `{{hash}}` in an href attribute will + * make the link go to the wrong URL if the user clicks it before + * Angular has a chance to replace the `{{hash}}` markup with its + * value. Until Angular replaces the markup the link will be broken + * and will most likely return a 404 error. The `ngHref` directive + * solves this problem. + * + * The wrong way to write it: + * ```html + * link1 + * ``` + * + * The correct way to write it: + * ```html + * link1 + * ``` + * + * @element A + * @param {template} ngHref any string which can contain `{{}}` markup. + * + * @example + * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes + * in links and their different behaviors: + + +
    + link 1 (link, don't reload)
    + link 2 (link, don't reload)
    + link 3 (link, reload!)
    + anchor (link, don't reload)
    + anchor (no link)
    + link (link, change location) +
    + + it('should execute ng-click but not reload when href without value', function() { + element(by.id('link-1')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('1'); + expect(element(by.id('link-1')).getAttribute('href')).toBe(''); + }); + + it('should execute ng-click but not reload when href empty string', function() { + element(by.id('link-2')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('2'); + expect(element(by.id('link-2')).getAttribute('href')).toBe(''); + }); + + it('should execute ng-click and change url when ng-href specified', function() { + expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/); + + element(by.id('link-3')).click(); + + // At this point, we navigate away from an Angular page, so we need + // to use browser.driver to get the base webdriver. + + browser.wait(function() { + return browser.driver.getCurrentUrl().then(function(url) { + return url.match(/\/123$/); + }); + }, 5000, 'page should navigate to /123'); + }); + + xit('should execute ng-click but not reload when href empty string and name specified', function() { + element(by.id('link-4')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('4'); + expect(element(by.id('link-4')).getAttribute('href')).toBe(''); + }); + + it('should execute ng-click but not reload when no href but name specified', function() { + element(by.id('link-5')).click(); + expect(element(by.model('value')).getAttribute('value')).toEqual('5'); + expect(element(by.id('link-5')).getAttribute('href')).toBe(null); + }); + + it('should only change url when only ng-href', function() { + element(by.model('value')).clear(); + element(by.model('value')).sendKeys('6'); + expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/); + + element(by.id('link-6')).click(); + + // At this point, we navigate away from an Angular page, so we need + // to use browser.driver to get the base webdriver. + browser.wait(function() { + return browser.driver.getCurrentUrl().then(function(url) { + return url.match(/\/6$/); + }); + }, 5000, 'page should navigate to /6'); + }); + +
    + */ + +/** + * @ngdoc directive + * @name ngSrc + * @restrict A + * @priority 99 + * + * @description + * Using Angular markup like `{{hash}}` in a `src` attribute doesn't + * work right: The browser will fetch from the URL with the literal + * text `{{hash}}` until Angular replaces the expression inside + * `{{hash}}`. The `ngSrc` directive solves this problem. + * + * The buggy way to write it: + * ```html + * + * ``` + * + * The correct way to write it: + * ```html + * + * ``` + * + * @element IMG + * @param {template} ngSrc any string which can contain `{{}}` markup. + */ + +/** + * @ngdoc directive + * @name ngSrcset + * @restrict A + * @priority 99 + * + * @description + * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't + * work right: The browser will fetch from the URL with the literal + * text `{{hash}}` until Angular replaces the expression inside + * `{{hash}}`. The `ngSrcset` directive solves this problem. + * + * The buggy way to write it: + * ```html + * + * ``` + * + * The correct way to write it: + * ```html + * + * ``` + * + * @element IMG + * @param {template} ngSrcset any string which can contain `{{}}` markup. + */ + +/** + * @ngdoc directive + * @name ngDisabled + * @restrict A + * @priority 100 + * + * @description + * + * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs: + * ```html + *
    + * + *
    + * ``` + * + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as disabled. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngDisabled` directive solves this problem for the `disabled` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * + * @example + + + Click me to toggle:
    + +
    + + it('should toggle button', function() { + expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy(); + element(by.model('checked')).click(); + expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy(); + }); + +
    + * + * @element INPUT + * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy, + * then special attribute "disabled" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ngChecked + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as checked. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngChecked` directive solves this problem for the `checked` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me to check both:
    + +
    + + it('should check both checkBoxes', function() { + expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy(); + element(by.model('master')).click(); + expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy(); + }); + +
    + * + * @element INPUT + * @param {expression} ngChecked If the {@link guide/expression expression} is truthy, + * then special attribute "checked" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ngReadonly + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as readonly. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngReadonly` directive solves this problem for the `readonly` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me to make text readonly:
    + +
    + + it('should toggle readonly attr', function() { + expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy(); + element(by.model('checked')).click(); + expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy(); + }); + +
    + * + * @element INPUT + * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy, + * then special attribute "readonly" will be set on the element + */ + + +/** + * @ngdoc directive + * @name ngSelected + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as selected. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngSelected` directive solves this problem for the `selected` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * + * @example + + + Check me to select:
    + +
    + + it('should select Greetings!', function() { + expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy(); + element(by.model('selected')).click(); + expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy(); + }); + +
    + * + * @element OPTION + * @param {expression} ngSelected If the {@link guide/expression expression} is truthy, + * then special attribute "selected" will be set on the element + */ + +/** + * @ngdoc directive + * @name ngOpen + * @restrict A + * @priority 100 + * + * @description + * The HTML specification does not require browsers to preserve the values of boolean attributes + * such as open. (Their presence means true and their absence means false.) + * If we put an Angular interpolation expression into such an attribute then the + * binding information would be lost when the browser removes the attribute. + * The `ngOpen` directive solves this problem for the `open` attribute. + * This complementary directive is not removed by the browser and so provides + * a permanent reliable place to store the binding information. + * @example + + + Check me check multiple:
    +
    + Show/Hide me +
    +
    + + it('should toggle open', function() { + expect(element(by.id('details')).getAttribute('open')).toBeFalsy(); + element(by.model('open')).click(); + expect(element(by.id('details')).getAttribute('open')).toBeTruthy(); + }); + +
    + * + * @element DETAILS + * @param {expression} ngOpen If the {@link guide/expression expression} is truthy, + * then special attribute "open" will be set on the element + */ + +var ngAttributeAliasDirectives = {}; + + +// boolean attrs are evaluated +forEach(BOOLEAN_ATTR, function(propName, attrName) { + // binding to multiple is not supported + if (propName == "multiple") return; + + var normalized = directiveNormalize('ng-' + attrName); + ngAttributeAliasDirectives[normalized] = function() { + return { + restrict: 'A', + priority: 100, + link: function(scope, element, attr) { + scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) { + attr.$set(attrName, !!value); + }); + } + }; + }; +}); + +// aliased input attrs are evaluated +forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) { + ngAttributeAliasDirectives[ngAttr] = function() { + return { + priority: 100, + link: function(scope, element, attr) { + //special case ngPattern when a literal regular expression value + //is used as the expression (this way we don't have to watch anything). + if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") { + var match = attr.ngPattern.match(REGEX_STRING_REGEXP); + if (match) { + attr.$set("ngPattern", new RegExp(match[1], match[2])); + return; + } + } + + scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) { + attr.$set(ngAttr, value); + }); + } + }; + }; +}); + +// ng-src, ng-srcset, ng-href are interpolated +forEach(['src', 'srcset', 'href'], function(attrName) { + var normalized = directiveNormalize('ng-' + attrName); + ngAttributeAliasDirectives[normalized] = function() { + return { + priority: 99, // it needs to run after the attributes are interpolated + link: function(scope, element, attr) { + var propName = attrName, + name = attrName; + + if (attrName === 'href' && + toString.call(element.prop('href')) === '[object SVGAnimatedString]') { + name = 'xlinkHref'; + attr.$attr[name] = 'xlink:href'; + propName = null; + } + + attr.$observe(normalized, function(value) { + if (!value) { + if (attrName === 'href') { + attr.$set(name, null); + } + return; + } + + attr.$set(name, value); + + // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist + // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need + // to set the property as well to achieve the desired effect. + // we use attr[attrName] value since $set can sanitize the url. + if (msie && propName) element.prop(propName, attr[name]); + }); + } + }; + }; +}); + +/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true + */ +var nullFormCtrl = { + $addControl: noop, + $$renameControl: nullFormRenameControl, + $removeControl: noop, + $setValidity: noop, + $setDirty: noop, + $setPristine: noop, + $setSubmitted: noop +}, +SUBMITTED_CLASS = 'ng-submitted'; + +function nullFormRenameControl(control, name) { + control.$name = name; +} + +/** + * @ngdoc type + * @name form.FormController + * + * @property {boolean} $pristine True if user has not interacted with the form yet. + * @property {boolean} $dirty True if user has already interacted with the form. + * @property {boolean} $valid True if all of the containing forms and controls are valid. + * @property {boolean} $invalid True if at least one containing control or form is invalid. + * @property {boolean} $submitted True if user has submitted the form even if its invalid. + * + * @property {Object} $error Is an object hash, containing references to controls or + * forms with failing validators, where: + * + * - keys are validation tokens (error names), + * - values are arrays of controls or forms that have a failing validator for given error name. + * + * Built-in validation tokens: + * + * - `email` + * - `max` + * - `maxlength` + * - `min` + * - `minlength` + * - `number` + * - `pattern` + * - `required` + * - `url` + * - `date` + * - `datetimelocal` + * - `time` + * - `week` + * - `month` + * + * @description + * `FormController` keeps track of all its controls and nested forms as well as the state of them, + * such as being valid/invalid or dirty/pristine. + * + * Each {@link ng.directive:form form} directive creates an instance + * of `FormController`. + * + */ +//asks for $scope to fool the BC controller module +FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate']; +function FormController(element, attrs, $scope, $animate, $interpolate) { + var form = this, + controls = []; + + var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl; + + // init state + form.$error = {}; + form.$$success = {}; + form.$pending = undefined; + form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope); + form.$dirty = false; + form.$pristine = true; + form.$valid = true; + form.$invalid = false; + form.$submitted = false; + + parentForm.$addControl(form); + + /** + * @ngdoc method + * @name form.FormController#$rollbackViewValue + * + * @description + * Rollback all form controls pending updates to the `$modelValue`. + * + * Updates may be pending by a debounced event or because the input is waiting for a some future + * event defined in `ng-model-options`. This method is typically needed by the reset button of + * a form that uses `ng-model-options` to pend updates. + */ + form.$rollbackViewValue = function() { + forEach(controls, function(control) { + control.$rollbackViewValue(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$commitViewValue + * + * @description + * Commit all form controls pending updates to the `$modelValue`. + * + * Updates may be pending by a debounced event or because the input is waiting for a some future + * event defined in `ng-model-options`. This method is rarely needed as `NgModelController` + * usually handles calling this in response to input events. + */ + form.$commitViewValue = function() { + forEach(controls, function(control) { + control.$commitViewValue(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$addControl + * + * @description + * Register a control with the form. + * + * Input elements using ngModelController do this automatically when they are linked. + */ + form.$addControl = function(control) { + // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored + // and not added to the scope. Now we throw an error. + assertNotHasOwnProperty(control.$name, 'input'); + controls.push(control); + + if (control.$name) { + form[control.$name] = control; + } + }; + + // Private API: rename a form control + form.$$renameControl = function(control, newName) { + var oldName = control.$name; + + if (form[oldName] === control) { + delete form[oldName]; + } + form[newName] = control; + control.$name = newName; + }; + + /** + * @ngdoc method + * @name form.FormController#$removeControl + * + * @description + * Deregister a control from the form. + * + * Input elements using ngModelController do this automatically when they are destroyed. + */ + form.$removeControl = function(control) { + if (control.$name && form[control.$name] === control) { + delete form[control.$name]; + } + forEach(form.$pending, function(value, name) { + form.$setValidity(name, null, control); + }); + forEach(form.$error, function(value, name) { + form.$setValidity(name, null, control); + }); + forEach(form.$$success, function(value, name) { + form.$setValidity(name, null, control); + }); + + arrayRemove(controls, control); + }; + + + /** + * @ngdoc method + * @name form.FormController#$setValidity + * + * @description + * Sets the validity of a form control. + * + * This method will also propagate to parent forms. + */ + addSetValidityMethod({ + ctrl: this, + $element: element, + set: function(object, property, controller) { + var list = object[property]; + if (!list) { + object[property] = [controller]; + } else { + var index = list.indexOf(controller); + if (index === -1) { + list.push(controller); + } + } + }, + unset: function(object, property, controller) { + var list = object[property]; + if (!list) { + return; + } + arrayRemove(list, controller); + if (list.length === 0) { + delete object[property]; + } + }, + parentForm: parentForm, + $animate: $animate + }); + + /** + * @ngdoc method + * @name form.FormController#$setDirty + * + * @description + * Sets the form to a dirty state. + * + * This method can be called to add the 'ng-dirty' class and set the form to a dirty + * state (ng-dirty class). This method will also propagate to parent forms. + */ + form.$setDirty = function() { + $animate.removeClass(element, PRISTINE_CLASS); + $animate.addClass(element, DIRTY_CLASS); + form.$dirty = true; + form.$pristine = false; + parentForm.$setDirty(); + }; + + /** + * @ngdoc method + * @name form.FormController#$setPristine + * + * @description + * Sets the form to its pristine state. + * + * This method can be called to remove the 'ng-dirty' class and set the form to its pristine + * state (ng-pristine class). This method will also propagate to all the controls contained + * in this form. + * + * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after + * saving or resetting it. + */ + form.$setPristine = function() { + $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS); + form.$dirty = false; + form.$pristine = true; + form.$submitted = false; + forEach(controls, function(control) { + control.$setPristine(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$setUntouched + * + * @description + * Sets the form to its untouched state. + * + * This method can be called to remove the 'ng-touched' class and set the form controls to their + * untouched state (ng-untouched class). + * + * Setting a form controls back to their untouched state is often useful when setting the form + * back to its pristine state. + */ + form.$setUntouched = function() { + forEach(controls, function(control) { + control.$setUntouched(); + }); + }; + + /** + * @ngdoc method + * @name form.FormController#$setSubmitted + * + * @description + * Sets the form to its submitted state. + */ + form.$setSubmitted = function() { + $animate.addClass(element, SUBMITTED_CLASS); + form.$submitted = true; + parentForm.$setSubmitted(); + }; +} + +/** + * @ngdoc directive + * @name ngForm + * @restrict EAC + * + * @description + * Nestable alias of {@link ng.directive:form `form`} directive. HTML + * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a + * sub-group of controls needs to be determined. + * + * Note: the purpose of `ngForm` is to group controls, + * but not to be a replacement for the `
    ` tag with all of its capabilities + * (e.g. posting to the server, ...). + * + * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + * + */ + + /** + * @ngdoc directive + * @name form + * @restrict E + * + * @description + * Directive that instantiates + * {@link form.FormController FormController}. + * + * If the `name` attribute is specified, the form controller is published onto the current scope under + * this name. + * + * # Alias: {@link ng.directive:ngForm `ngForm`} + * + * In Angular forms can be nested. This means that the outer form is valid when all of the child + * forms are valid as well. However, browsers do not allow nesting of `` elements, so + * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to + * `` but can be nested. This allows you to have nested forms, which is very useful when + * using Angular validation directives in forms that are dynamically generated using the + * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name` + * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an + * `ngForm` directive and nest these in an outer `form` element. + * + * + * # CSS classes + * - `ng-valid` is set if the form is valid. + * - `ng-invalid` is set if the form is invalid. + * - `ng-pristine` is set if the form is pristine. + * - `ng-dirty` is set if the form is dirty. + * - `ng-submitted` is set if the form was submitted. + * + * Keep in mind that ngAnimate can detect each of these classes when added and removed. + * + * + * # Submitting a form and preventing the default action + * + * Since the role of forms in client-side Angular applications is different than in classical + * roundtrip apps, it is desirable for the browser not to translate the form submission into a full + * page reload that sends the data to the server. Instead some javascript logic should be triggered + * to handle the form submission in an application-specific way. + * + * For this reason, Angular prevents the default action (form submission to the server) unless the + * `` element has an `action` attribute specified. + * + * You can use one of the following two ways to specify what javascript method should be called when + * a form is submitted: + * + * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element + * - {@link ng.directive:ngClick ngClick} directive on the first + * button or input field of type submit (input[type=submit]) + * + * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit} + * or {@link ng.directive:ngClick ngClick} directives. + * This is because of the following form submission rules in the HTML specification: + * + * - If a form has only one input field then hitting enter in this field triggers form submit + * (`ngSubmit`) + * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter + * doesn't trigger submit + * - if a form has one or more input fields and one or more buttons or input[type=submit] then + * hitting enter in any of the input fields will trigger the click handler on the *first* button or + * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`) + * + * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is + * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit` + * to have access to the updated model. + * + * ## Animation Hooks + * + * Animations in ngForm are triggered when any of the associated CSS classes are added and removed. + * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any + * other validations that are performed within the form. Animations in ngForm are similar to how + * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well + * as JS animations. + * + * The following example shows a simple way to utilize CSS transitions to style a form element + * that has been rendered as invalid after it has been validated: + * + *
    + * //be sure to include ngAnimate as a module to hook into more
    + * //advanced animations
    + * .my-form {
    + *   transition:0.5s linear all;
    + *   background: white;
    + * }
    + * .my-form.ng-invalid {
    + *   background: red;
    + *   color:white;
    + * }
    + * 
    + * + * @example + + + + + + userType: + Required!
    + userType = {{userType}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + +
    + + it('should initialize to model', function() { + var userType = element(by.binding('userType')); + var valid = element(by.binding('myForm.input.$valid')); + + expect(userType.getText()).toContain('guest'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + var userType = element(by.binding('userType')); + var valid = element(by.binding('myForm.input.$valid')); + var userInput = element(by.model('userType')); + + userInput.clear(); + userInput.sendKeys(''); + + expect(userType.getText()).toEqual('userType ='); + expect(valid.getText()).toContain('false'); + }); + +
    + * + * @param {string=} name Name of the form. If specified, the form controller will be published into + * related scope, under this name. + */ +var formDirectiveFactory = function(isNgForm) { + return ['$timeout', function($timeout) { + var formDirective = { + name: 'form', + restrict: isNgForm ? 'EAC' : 'E', + controller: FormController, + compile: function ngFormCompile(formElement) { + // Setup initial state of the control + formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS); + + return { + pre: function ngFormPreLink(scope, formElement, attr, controller) { + // if `action` attr is not present on the form, prevent the default action (submission) + if (!('action' in attr)) { + // we can't use jq events because if a form is destroyed during submission the default + // action is not prevented. see #1238 + // + // IE 9 is not affected because it doesn't fire a submit event and try to do a full + // page reload if the form was destroyed by submission of the form via a click handler + // on a button in the form. Looks like an IE9 specific bug. + var handleFormSubmission = function(event) { + scope.$apply(function() { + controller.$commitViewValue(); + controller.$setSubmitted(); + }); + + event.preventDefault(); + }; + + addEventListenerFn(formElement[0], 'submit', handleFormSubmission); + + // unregister the preventDefault listener so that we don't not leak memory but in a + // way that will achieve the prevention of the default action. + formElement.on('$destroy', function() { + $timeout(function() { + removeEventListenerFn(formElement[0], 'submit', handleFormSubmission); + }, 0, false); + }); + } + + var parentFormCtrl = controller.$$parentForm, + alias = controller.$name; + + if (alias) { + setter(scope, null, alias, controller, alias); + attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) { + if (alias === newValue) return; + setter(scope, null, alias, undefined, alias); + alias = newValue; + setter(scope, null, alias, controller, alias); + parentFormCtrl.$$renameControl(controller, alias); + }); + } + formElement.on('$destroy', function() { + parentFormCtrl.$removeControl(controller); + if (alias) { + setter(scope, null, alias, undefined, alias); + } + extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards + }); + } + }; + } + }; + + return formDirective; + }]; +}; + +var formDirective = formDirectiveFactory(); +var ngFormDirective = formDirectiveFactory(true); + +/* global VALID_CLASS: false, + INVALID_CLASS: false, + PRISTINE_CLASS: false, + DIRTY_CLASS: false, + UNTOUCHED_CLASS: false, + TOUCHED_CLASS: false, + $ngModelMinErr: false, +*/ + +// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231 +var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/; +var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; +var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i; +var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/; +var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/; +var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; +var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/; +var MONTH_REGEXP = /^(\d{4})-(\d\d)$/; +var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/; + +var inputType = { + + /** + * @ngdoc input + * @name input[text] + * + * @description + * Standard HTML text input with angular data binding, inherited by most of the `input` elements. + * + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Adds `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + * This parameter is ignored for input[type=password] controls, which will never trim the + * input. + * + * @example + + + +
    + Single word: + + Required! + + Single word only! + + text = {{example.text}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var text = element(by.binding('example.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('guest'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if multi word', function() { + input.clear(); + input.sendKeys('hello world'); + + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'text': textInputType, + + /** + * @ngdoc input + * @name input[date] + * + * @description + * Input with date validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601 + * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many + * modern browsers do not yet support this input type, it is important to provide cues to users on the + * expected input format via a placeholder or label. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO date string (yyyy-MM-dd). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO date string (yyyy-MM-dd). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a date in 2013: + + + Required! + + Not a valid date! + value = {{example.value | date: "yyyy-MM-dd"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-MM-dd"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (see https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10-22'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'date': createDateInputType('date', DATE_REGEXP, + createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']), + 'yyyy-MM-dd'), + + /** + * @ngdoc input + * @name input[datetime-local] + * + * @description + * Input with datetime validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2010-12-28T14:57:00'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01-01T23:59:00'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP, + createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']), + 'yyyy-MM-ddTHH:mm:ss.sss'), + + /** + * @ngdoc input + * @name input[time] + * + * @description + * Input with time validation and transformation. In browsers that do not yet support + * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a + * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO time format (HH:mm:ss). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a + * valid ISO time format (HH:mm:ss). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a between 8am and 5pm: + + + Required! + + Not a valid date! + value = {{example.value | date: "HH:mm:ss"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "HH:mm:ss"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('14:57:00'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('23:59:00'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'time': createDateInputType('time', TIME_REGEXP, + createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']), + 'HH:mm:ss.sss'), + + /** + * @ngdoc input + * @name input[week] + * + * @description + * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support + * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * week format (yyyy-W##), for example: `2013-W02`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a + * valid ISO week format (yyyy-W##). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be + * a valid ISO week format (yyyy-W##). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a date between in 2013: + + + Required! + + Not a valid date! + value = {{example.value | date: "yyyy-Www"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-Www"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-W01'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-W01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'), + + /** + * @ngdoc input + * @name input[month] + * + * @description + * Input with month validation and transformation. In browsers that do not yet support + * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 + * month format (yyyy-MM), for example: `2009-01`. + * + * The model must always be a Date object, otherwise Angular will throw an error. + * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string. + * If the model is not set to the first of the month, the next view to model update will set it + * to the first of the month. + * + * The timezone to be used to read/write the `Date` instance in the model can be defined using + * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be + * a valid ISO month format (yyyy-MM). + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must + * be a valid ISO month format (yyyy-MM). + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Pick a month in 2013: + + + Required! + + Not a valid month! + value = {{example.value | date: "yyyy-MM"}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value | date: "yyyy-MM"')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + // currently protractor/webdriver does not support + // sending keys to all known HTML5 input controls + // for various browsers (https://github.com/angular/protractor/issues/562). + function setInput(val) { + // set the value of the element and force validation. + var scr = "var ipt = document.getElementById('exampleInput'); " + + "ipt.value = '" + val + "';" + + "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; + browser.executeScript(scr); + } + + it('should initialize to model', function() { + expect(value.getText()).toContain('2013-10'); + expect(valid.getText()).toContain('myForm.input.$valid = true'); + }); + + it('should be invalid if empty', function() { + setInput(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + + it('should be invalid if over max', function() { + setInput('2015-01'); + expect(value.getText()).toContain(''); + expect(valid.getText()).toContain('myForm.input.$valid = false'); + }); + +
    + */ + 'month': createDateInputType('month', MONTH_REGEXP, + createDateParser(MONTH_REGEXP, ['yyyy', 'MM']), + 'yyyy-MM'), + + /** + * @ngdoc input + * @name input[number] + * + * @description + * Text input with number validation and transformation. Sets the `number` validation + * error if not a valid number. + * + * The model must always be a number, otherwise Angular will throw an error. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. + * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Number: + + Required! + + Not valid number! + value = {{example.value}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    +
    +
    + + var value = element(by.binding('example.value')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('example.value')); + + it('should initialize to model', function() { + expect(value.getText()).toContain('12'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if over max', function() { + input.clear(); + input.sendKeys('123'); + expect(value.getText()).toEqual('value ='); + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'number': numberInputType, + + + /** + * @ngdoc input + * @name input[url] + * + * @description + * Text input with URL validation. Sets the `url` validation error key if the content is not a + * valid URL. + * + *
    + * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex + * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify + * the built-in validators (see the {@link guide/forms Forms guide}) + *
    + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + URL: + + Required! + + Not valid url! + text = {{url.text}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + myForm.$error.url = {{!!myForm.$error.url}}
    +
    +
    + + var text = element(by.binding('url.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('url.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('http://google.com'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if not url', function() { + input.clear(); + input.sendKeys('box'); + + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'url': urlInputType, + + + /** + * @ngdoc input + * @name input[email] + * + * @description + * Text input with email validation. Sets the `email` validation error key if not a valid email + * address. + * + *
    + * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex + * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can + * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide}) + *
    + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of + * any length. + * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string + * that contains the regular expression body that will be converted to a regular expression + * as in the ngPattern directive. + * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match + * a RegExp found by evaluating the Angular expression given in the attribute value. + * If the expression evaluates to a RegExp object then this is used directly. + * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$` + * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Email: + + Required! + + Not valid email! + text = {{email.text}}
    + myForm.input.$valid = {{myForm.input.$valid}}
    + myForm.input.$error = {{myForm.input.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + myForm.$error.email = {{!!myForm.$error.email}}
    +
    +
    + + var text = element(by.binding('email.text')); + var valid = element(by.binding('myForm.input.$valid')); + var input = element(by.model('email.text')); + + it('should initialize to model', function() { + expect(text.getText()).toContain('me@example.com'); + expect(valid.getText()).toContain('true'); + }); + + it('should be invalid if empty', function() { + input.clear(); + input.sendKeys(''); + expect(text.getText()).toEqual('text ='); + expect(valid.getText()).toContain('false'); + }); + + it('should be invalid if not email', function() { + input.clear(); + input.sendKeys('xxx'); + + expect(valid.getText()).toContain('false'); + }); + +
    + */ + 'email': emailInputType, + + + /** + * @ngdoc input + * @name input[radio] + * + * @description + * HTML radio button. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string} value The value to which the expression should be set when selected. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {string} ngValue Angular expression which sets the value to which the expression should + * be set when selected. + * + * @example + + + +
    + Red
    + Green
    + Blue
    + color = {{color.name | json}}
    +
    + Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`. +
    + + it('should change state', function() { + var color = element(by.binding('color.name')); + + expect(color.getText()).toContain('blue'); + + element.all(by.model('color.name')).get(0).click(); + + expect(color.getText()).toContain('red'); + }); + +
    + */ + 'radio': radioInputType, + + + /** + * @ngdoc input + * @name input[checkbox] + * + * @description + * HTML checkbox. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {expression=} ngTrueValue The value to which the expression should be set when selected. + * @param {expression=} ngFalseValue The value to which the expression should be set when not selected. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * + * @example + + + +
    + Value1:
    + Value2:
    + value1 = {{checkboxModel.value1}}
    + value2 = {{checkboxModel.value2}}
    +
    +
    + + it('should change state', function() { + var value1 = element(by.binding('checkboxModel.value1')); + var value2 = element(by.binding('checkboxModel.value2')); + + expect(value1.getText()).toContain('true'); + expect(value2.getText()).toContain('YES'); + + element(by.model('checkboxModel.value1')).click(); + element(by.model('checkboxModel.value2')).click(); + + expect(value1.getText()).toContain('false'); + expect(value2.getText()).toContain('NO'); + }); + +
    + */ + 'checkbox': checkboxInputType, + + 'hidden': noop, + 'button': noop, + 'submit': noop, + 'reset': noop, + 'file': noop +}; + +function stringBasedInputType(ctrl) { + ctrl.$formatters.push(function(value) { + return ctrl.$isEmpty(value) ? value : value.toString(); + }); +} + +function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); +} + +function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { + var type = lowercase(element[0].type); + + // In composition mode, users are still inputing intermediate text buffer, + // hold the listener until composition is done. + // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent + if (!$sniffer.android) { + var composing = false; + + element.on('compositionstart', function(data) { + composing = true; + }); + + element.on('compositionend', function() { + composing = false; + listener(); + }); + } + + var listener = function(ev) { + if (timeout) { + $browser.defer.cancel(timeout); + timeout = null; + } + if (composing) return; + var value = element.val(), + event = ev && ev.type; + + // By default we will trim the value + // If the attribute ng-trim exists we will avoid trimming + // If input type is 'password', the value is never trimmed + if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) { + value = trim(value); + } + + // If a control is suffering from bad input (due to native validators), browsers discard its + // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the + // control's value is the same empty value twice in a row. + if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) { + ctrl.$setViewValue(value, event); + } + }; + + // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the + // input event on backspace, delete or cut + if ($sniffer.hasEvent('input')) { + element.on('input', listener); + } else { + var timeout; + + var deferListener = function(ev, input, origValue) { + if (!timeout) { + timeout = $browser.defer(function() { + timeout = null; + if (!input || input.value !== origValue) { + listener(ev); + } + }); + } + }; + + element.on('keydown', function(event) { + var key = event.keyCode; + + // ignore + // command modifiers arrows + if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; + + deferListener(event, this, this.value); + }); + + // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it + if ($sniffer.hasEvent('paste')) { + element.on('paste cut', deferListener); + } + } + + // if user paste into input using mouse on older browser + // or form autocomplete on newer browser, we need "change" event to catch it + element.on('change', listener); + + ctrl.$render = function() { + element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue); + }; +} + +function weekParser(isoWeek, existingDate) { + if (isDate(isoWeek)) { + return isoWeek; + } + + if (isString(isoWeek)) { + WEEK_REGEXP.lastIndex = 0; + var parts = WEEK_REGEXP.exec(isoWeek); + if (parts) { + var year = +parts[1], + week = +parts[2], + hours = 0, + minutes = 0, + seconds = 0, + milliseconds = 0, + firstThurs = getFirstThursdayOfYear(year), + addDays = (week - 1) * 7; + + if (existingDate) { + hours = existingDate.getHours(); + minutes = existingDate.getMinutes(); + seconds = existingDate.getSeconds(); + milliseconds = existingDate.getMilliseconds(); + } + + return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds); + } + } + + return NaN; +} + +function createDateParser(regexp, mapping) { + return function(iso, date) { + var parts, map; + + if (isDate(iso)) { + return iso; + } + + if (isString(iso)) { + // When a date is JSON'ified to wraps itself inside of an extra + // set of double quotes. This makes the date parsing code unable + // to match the date string and parse it as a date. + if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') { + iso = iso.substring(1, iso.length - 1); + } + if (ISO_DATE_REGEXP.test(iso)) { + return new Date(iso); + } + regexp.lastIndex = 0; + parts = regexp.exec(iso); + + if (parts) { + parts.shift(); + if (date) { + map = { + yyyy: date.getFullYear(), + MM: date.getMonth() + 1, + dd: date.getDate(), + HH: date.getHours(), + mm: date.getMinutes(), + ss: date.getSeconds(), + sss: date.getMilliseconds() / 1000 + }; + } else { + map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 }; + } + + forEach(parts, function(part, index) { + if (index < mapping.length) { + map[mapping[index]] = +part; + } + }); + return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0); + } + } + + return NaN; + }; +} + +function createDateInputType(type, regexp, parseDate, format) { + return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) { + badInputChecker(scope, element, attr, ctrl); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + var timezone = ctrl && ctrl.$options && ctrl.$options.timezone; + var previousDate; + + ctrl.$$parserName = type; + ctrl.$parsers.push(function(value) { + if (ctrl.$isEmpty(value)) return null; + if (regexp.test(value)) { + // Note: We cannot read ctrl.$modelValue, as there might be a different + // parser/formatter in the processing chain so that the model + // contains some different data format! + var parsedDate = parseDate(value, previousDate); + if (timezone === 'UTC') { + parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset()); + } + return parsedDate; + } + return undefined; + }); + + ctrl.$formatters.push(function(value) { + if (value && !isDate(value)) { + throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value); + } + if (isValidDate(value)) { + previousDate = value; + if (previousDate && timezone === 'UTC') { + var timezoneOffset = 60000 * previousDate.getTimezoneOffset(); + previousDate = new Date(previousDate.getTime() + timezoneOffset); + } + return $filter('date')(value, format, timezone); + } else { + previousDate = null; + return ''; + } + }); + + if (isDefined(attr.min) || attr.ngMin) { + var minVal; + ctrl.$validators.min = function(value) { + return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal; + }; + attr.$observe('min', function(val) { + minVal = parseObservedDateValue(val); + ctrl.$validate(); + }); + } + + if (isDefined(attr.max) || attr.ngMax) { + var maxVal; + ctrl.$validators.max = function(value) { + return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal; + }; + attr.$observe('max', function(val) { + maxVal = parseObservedDateValue(val); + ctrl.$validate(); + }); + } + + function isValidDate(value) { + // Invalid Date: getTime() returns NaN + return value && !(value.getTime && value.getTime() !== value.getTime()); + } + + function parseObservedDateValue(val) { + return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined; + } + }; +} + +function badInputChecker(scope, element, attr, ctrl) { + var node = element[0]; + var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity); + if (nativeValidation) { + ctrl.$parsers.push(function(value) { + var validity = element.prop(VALIDITY_STATE_PROPERTY) || {}; + // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430): + // - also sets validity.badInput (should only be validity.typeMismatch). + // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email) + // - can ignore this case as we can still read out the erroneous email... + return validity.badInput && !validity.typeMismatch ? undefined : value; + }); + } +} + +function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) { + badInputChecker(scope, element, attr, ctrl); + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + + ctrl.$$parserName = 'number'; + ctrl.$parsers.push(function(value) { + if (ctrl.$isEmpty(value)) return null; + if (NUMBER_REGEXP.test(value)) return parseFloat(value); + return undefined; + }); + + ctrl.$formatters.push(function(value) { + if (!ctrl.$isEmpty(value)) { + if (!isNumber(value)) { + throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value); + } + value = value.toString(); + } + return value; + }); + + if (attr.min || attr.ngMin) { + var minVal; + ctrl.$validators.min = function(value) { + return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal; + }; + + attr.$observe('min', function(val) { + if (isDefined(val) && !isNumber(val)) { + val = parseFloat(val, 10); + } + minVal = isNumber(val) && !isNaN(val) ? val : undefined; + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + }); + } + + if (attr.max || attr.ngMax) { + var maxVal; + ctrl.$validators.max = function(value) { + return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal; + }; + + attr.$observe('max', function(val) { + if (isDefined(val) && !isNumber(val)) { + val = parseFloat(val, 10); + } + maxVal = isNumber(val) && !isNaN(val) ? val : undefined; + // TODO(matsko): implement validateLater to reduce number of validations + ctrl.$validate(); + }); + } +} + +function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // Note: no badInputChecker here by purpose as `url` is only a validation + // in browsers, i.e. we can always read out input.value even if it is not valid! + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); + + ctrl.$$parserName = 'url'; + ctrl.$validators.url = function(modelValue, viewValue) { + var value = modelValue || viewValue; + return ctrl.$isEmpty(value) || URL_REGEXP.test(value); + }; +} + +function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) { + // Note: no badInputChecker here by purpose as `url` is only a validation + // in browsers, i.e. we can always read out input.value even if it is not valid! + baseInputType(scope, element, attr, ctrl, $sniffer, $browser); + stringBasedInputType(ctrl); + + ctrl.$$parserName = 'email'; + ctrl.$validators.email = function(modelValue, viewValue) { + var value = modelValue || viewValue; + return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value); + }; +} + +function radioInputType(scope, element, attr, ctrl) { + // make the name unique, if not defined + if (isUndefined(attr.name)) { + element.attr('name', nextUid()); + } + + var listener = function(ev) { + if (element[0].checked) { + ctrl.$setViewValue(attr.value, ev && ev.type); + } + }; + + element.on('click', listener); + + ctrl.$render = function() { + var value = attr.value; + element[0].checked = (value == ctrl.$viewValue); + }; + + attr.$observe('value', ctrl.$render); +} + +function parseConstantExpr($parse, context, name, expression, fallback) { + var parseFn; + if (isDefined(expression)) { + parseFn = $parse(expression); + if (!parseFn.constant) { + throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' + + '`{1}`.', name, expression); + } + return parseFn(context); + } + return fallback; +} + +function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) { + var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true); + var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false); + + var listener = function(ev) { + ctrl.$setViewValue(element[0].checked, ev && ev.type); + }; + + element.on('click', listener); + + ctrl.$render = function() { + element[0].checked = ctrl.$viewValue; + }; + + // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false` + // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert + // it to a boolean. + ctrl.$isEmpty = function(value) { + return value === false; + }; + + ctrl.$formatters.push(function(value) { + return equals(value, trueValue); + }); + + ctrl.$parsers.push(function(value) { + return value ? trueValue : falseValue; + }); +} + + +/** + * @ngdoc directive + * @name textarea + * @restrict E + * + * @description + * HTML textarea element control with angular data-binding. The data-binding and validation + * properties of this element are exactly the same as those of the + * {@link ng.directive:input input element}. + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to + * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of + * `required` when you want to data-bind to the `required` attribute. + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any + * length. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + */ + + +/** + * @ngdoc directive + * @name input + * @restrict E + * + * @description + * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding, + * input state control, and validation. + * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers. + * + *
    + * **Note:** Not every feature offered is available for all input types. + * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`. + *
    + * + * @param {string} ngModel Assignable angular expression to data-bind to. + * @param {string=} name Property name of the form under which the control is published. + * @param {string=} required Sets `required` validation error key if the value is not entered. + * @param {boolean=} ngRequired Sets `required` attribute if set to true + * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than + * minlength. + * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than + * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any + * length. + * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the + * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for + * patterns defined as scope expressions. + * @param {string=} ngChange Angular expression to be executed when input changes due to user + * interaction with the input element. + * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input. + * This parameter is ignored for input[type=password] controls, which will never trim the + * input. + * + * @example + + + +
    +
    + User name: + + Required!
    + Last name: + + Too short! + + Too long!
    +
    +
    + user = {{user}}
    + myForm.userName.$valid = {{myForm.userName.$valid}}
    + myForm.userName.$error = {{myForm.userName.$error}}
    + myForm.lastName.$valid = {{myForm.lastName.$valid}}
    + myForm.lastName.$error = {{myForm.lastName.$error}}
    + myForm.$valid = {{myForm.$valid}}
    + myForm.$error.required = {{!!myForm.$error.required}}
    + myForm.$error.minlength = {{!!myForm.$error.minlength}}
    + myForm.$error.maxlength = {{!!myForm.$error.maxlength}}
    +
    +
    + + var user = element(by.exactBinding('user')); + var userNameValid = element(by.binding('myForm.userName.$valid')); + var lastNameValid = element(by.binding('myForm.lastName.$valid')); + var lastNameError = element(by.binding('myForm.lastName.$error')); + var formValid = element(by.binding('myForm.$valid')); + var userNameInput = element(by.model('user.name')); + var userLastInput = element(by.model('user.last')); + + it('should initialize to model', function() { + expect(user.getText()).toContain('{"name":"guest","last":"visitor"}'); + expect(userNameValid.getText()).toContain('true'); + expect(formValid.getText()).toContain('true'); + }); + + it('should be invalid if empty when required', function() { + userNameInput.clear(); + userNameInput.sendKeys(''); + + expect(user.getText()).toContain('{"last":"visitor"}'); + expect(userNameValid.getText()).toContain('false'); + expect(formValid.getText()).toContain('false'); + }); + + it('should be valid if empty when min length is set', function() { + userLastInput.clear(); + userLastInput.sendKeys(''); + + expect(user.getText()).toContain('{"name":"guest","last":""}'); + expect(lastNameValid.getText()).toContain('true'); + expect(formValid.getText()).toContain('true'); + }); + + it('should be invalid if less than required min length', function() { + userLastInput.clear(); + userLastInput.sendKeys('xx'); + + expect(user.getText()).toContain('{"name":"guest"}'); + expect(lastNameValid.getText()).toContain('false'); + expect(lastNameError.getText()).toContain('minlength'); + expect(formValid.getText()).toContain('false'); + }); + + it('should be invalid if longer than max length', function() { + userLastInput.clear(); + userLastInput.sendKeys('some ridiculously long name'); + + expect(user.getText()).toContain('{"name":"guest"}'); + expect(lastNameValid.getText()).toContain('false'); + expect(lastNameError.getText()).toContain('maxlength'); + expect(formValid.getText()).toContain('false'); + }); + +
    + */ +var inputDirective = ['$browser', '$sniffer', '$filter', '$parse', + function($browser, $sniffer, $filter, $parse) { + return { + restrict: 'E', + require: ['?ngModel'], + link: { + pre: function(scope, element, attr, ctrls) { + if (ctrls[0]) { + (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer, + $browser, $filter, $parse); + } + } + } + }; +}]; + + + +var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; +/** + * @ngdoc directive + * @name ngValue + * + * @description + * Binds the given expression to the value of `
    + + it('should load template defined inside script tag', function() { + element(by.css('#tpl-link')).click(); + expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/); + }); + + + */ +var scriptDirective = ['$templateCache', function($templateCache) { + return { + restrict: 'E', + terminal: true, + compile: function(element, attr) { + if (attr.type == 'text/ng-template') { + var templateUrl = attr.id, + text = element[0].text; + + $templateCache.put(templateUrl, text); + } + } + }; +}]; + +var ngOptionsMinErr = minErr('ngOptions'); +/** + * @ngdoc directive + * @name select + * @restrict E + * + * @description + * HTML `SELECT` element with angular data-binding. + * + * # `ngOptions` + * + * The `ngOptions` attribute can be used to dynamically generate a list of `