/* * Copyright © 2016-2019 The Thingsboard Authors * * 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. */ import './js-func.scss'; import ace from 'brace'; import 'brace/ext/language_tools'; import 'brace/ext/searchbox'; import $ from 'jquery'; import thingsboardToast from '../services/toast'; import thingsboardUtils from '../common/utils.service'; import thingsboardExpandFullscreen from './expand-fullscreen.directive'; import fixAceEditor from './ace-editor-fix'; /* eslint-disable import/no-unresolved, import/default */ import jsFuncTemplate from './js-func.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ import beautify from 'js-beautify'; const js_beautify = beautify.js; /* eslint-disable angular/angularelement */ export default angular.module('thingsboard.directives.jsFunc', [thingsboardToast, thingsboardUtils, thingsboardExpandFullscreen]) .directive('tbJsFunc', JsFunc) .name; /*@ngInject*/ function JsFunc($compile, $templateCache, toast, utils, $translate) { var linker = function (scope, element, attrs, ngModelCtrl) { var template = $templateCache.get(jsFuncTemplate); element.html(template); scope.functionName = attrs.functionName; scope.functionArgs = scope.$eval(attrs.functionArgs); scope.validationArgs = scope.$eval(attrs.validationArgs); scope.resultType = attrs.resultType; if (!scope.resultType || scope.resultType.length === 0) { scope.resultType = "nocheck"; } scope.validationTriggerArg = attrs.validationTriggerArg; scope.functionValid = true; var Range = ace.acequire("ace/range").Range; scope.js_editor; scope.errorMarkers = []; scope.functionArgsString = ''; for (var i = 0; i < scope.functionArgs.length; i++) { if (scope.functionArgsString.length > 0) { scope.functionArgsString += ', '; } scope.functionArgsString += scope.functionArgs[i]; } scope.onFullscreenChanged = function () { updateEditorSize(); }; scope.beautifyJs = function () { var res = js_beautify(scope.functionBody, {indent_size: 4, wrap_line_length: 60}); scope.functionBody = res; }; function updateEditorSize() { if (scope.js_editor) { scope.js_editor.resize(); scope.js_editor.renderer.updateFull(); } } scope.jsEditorOptions = { useWrapMode: true, mode: 'javascript', advanced: { enableSnippets: true, enableBasicAutocompletion: true, enableLiveAutocompletion: true }, onLoad: function (_ace) { scope.js_editor = _ace; scope.js_editor.session.on("change", function () { scope.cleanupJsErrors(); }); fixAceEditor(_ace); } }; scope.cleanupJsErrors = function () { toast.hide(); for (var i = 0; i < scope.errorMarkers.length; i++) { scope.js_editor.session.removeMarker(scope.errorMarkers[i]); } scope.errorMarkers = []; if (scope.errorAnnotationId && scope.errorAnnotationId > -1) { var annotations = scope.js_editor.session.getAnnotations(); annotations.splice(scope.errorAnnotationId, 1); scope.js_editor.session.setAnnotations(annotations); scope.errorAnnotationId = -1; } } scope.updateValidity = function () { ngModelCtrl.$setValidity('functionBody', scope.functionValid); }; scope.$watch('functionBody', function (newFunctionBody, oldFunctionBody) { ngModelCtrl.$setViewValue(scope.functionBody); if (!angular.equals(newFunctionBody, oldFunctionBody)) { scope.functionValid = true; } scope.updateValidity(); }); ngModelCtrl.$render = function () { scope.functionBody = ngModelCtrl.$viewValue; }; scope.showError = function (error) { var toastParent = $('#tb-javascript-panel', element); var dialogContent = toastParent.closest('md-dialog-content'); if (dialogContent.length > 0) { toastParent = dialogContent; } toast.showError(error, toastParent, 'bottom left'); } scope.validate = function () { try { var toValidate = new Function(scope.functionArgsString, scope.functionBody); if (scope.noValidate) { return true; } var res; var validationError; for (var i=0;i