Commit 87c2574acde4408b2b9cd3b9fa857f56c9f16f70

Authored by Igor Kulikov
1 parent 81ccdf7b

TB-70: Keep dashboard state as base64 url parameter.

... ... @@ -45,6 +45,7 @@
45 45 "angular-ui-ace": "^0.2.3",
46 46 "angular-ui-router": "^0.3.1",
47 47 "angular-websocket": "^2.0.1",
  48 + "base64-js": "^1.2.1",
48 49 "brace": "^0.8.0",
49 50 "canvas-gauges": "^2.0.9",
50 51 "clipboard": "^1.5.15",
... ...
  1 +/*
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +export function utf8Encode(str) {
  18 + var result;
  19 +
  20 + if (angular.isUndefined(Uint8Array)) { // eslint-disable-line no-undef
  21 + result = utf8ToBytes(str);
  22 + } else {
  23 + result = new Uint8Array(utf8ToBytes(str)); // eslint-disable-line no-undef
  24 + }
  25 +
  26 + return result;
  27 +}
  28 +
  29 +export function utf8Decode(bytes) {
  30 + return utf8Slice(bytes, 0, bytes.length);
  31 +}
  32 +
  33 +function utf8Slice (buf, start, end) {
  34 + var res = ''
  35 + var tmp = ''
  36 + end = Math.min(buf.length, end || Infinity)
  37 + start = start || 0;
  38 +
  39 + for (var i = start; i < end; i++) {
  40 + if (buf[i] <= 0x7F) {
  41 + res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
  42 + tmp = ''
  43 + } else {
  44 + tmp += '%' + buf[i].toString(16)
  45 + }
  46 + }
  47 +
  48 + return res + decodeUtf8Char(tmp)
  49 +}
  50 +
  51 +function decodeUtf8Char (str) {
  52 + try {
  53 + return decodeURIComponent(str)
  54 + } catch (err) {
  55 + return String.fromCharCode(0xFFFD) // UTF 8 invalid char
  56 + }
  57 +}
  58 +
  59 +function utf8ToBytes (string, units) {
  60 + units = units || Infinity
  61 + var codePoint
  62 + var length = string.length
  63 + var leadSurrogate = null
  64 + var bytes = []
  65 + var i = 0
  66 +
  67 + for (; i < length; i++) {
  68 + codePoint = string.charCodeAt(i)
  69 +
  70 + // is surrogate component
  71 + if (codePoint > 0xD7FF && codePoint < 0xE000) {
  72 + // last char was a lead
  73 + if (leadSurrogate) {
  74 + // 2 leads in a row
  75 + if (codePoint < 0xDC00) {
  76 + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
  77 + leadSurrogate = codePoint
  78 + continue
  79 + } else {
  80 + // valid surrogate pair
  81 + codePoint = leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00 | 0x10000
  82 + leadSurrogate = null
  83 + }
  84 + } else {
  85 + // no lead yet
  86 +
  87 + if (codePoint > 0xDBFF) {
  88 + // unexpected trail
  89 + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
  90 + continue
  91 + } else if (i + 1 === length) {
  92 + // unpaired lead
  93 + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
  94 + continue
  95 + } else {
  96 + // valid lead
  97 + leadSurrogate = codePoint
  98 + continue
  99 + }
  100 + }
  101 + } else if (leadSurrogate) {
  102 + // valid bmp char, but last char was a lead
  103 + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
  104 + leadSurrogate = null
  105 + }
  106 +
  107 + // encode utf8
  108 + if (codePoint < 0x80) {
  109 + if ((units -= 1) < 0) break
  110 + bytes.push(codePoint)
  111 + } else if (codePoint < 0x800) {
  112 + if ((units -= 2) < 0) break
  113 + bytes.push(
  114 + codePoint >> 0x6 | 0xC0,
  115 + codePoint & 0x3F | 0x80
  116 + )
  117 + } else if (codePoint < 0x10000) {
  118 + if ((units -= 3) < 0) break
  119 + bytes.push(
  120 + codePoint >> 0xC | 0xE0,
  121 + codePoint >> 0x6 & 0x3F | 0x80,
  122 + codePoint & 0x3F | 0x80
  123 + )
  124 + } else if (codePoint < 0x200000) {
  125 + if ((units -= 4) < 0) break
  126 + bytes.push(
  127 + codePoint >> 0x12 | 0xF0,
  128 + codePoint >> 0xC & 0x3F | 0x80,
  129 + codePoint >> 0x6 & 0x3F | 0x80,
  130 + codePoint & 0x3F | 0x80
  131 + )
  132 + } else {
  133 + throw new Error('Invalid code point')
  134 + }
  135 + }
  136 +
  137 + return bytes
  138 +}
\ No newline at end of file
... ...
... ... @@ -20,9 +20,12 @@ import materialIconsCodepoints from 'raw-loader!material-design-icons/iconfont/c
20 20
21 21 /* eslint-enable import/no-unresolved, import/default */
22 22
23   -import tinycolor from "tinycolor2";
24   -import jsonSchemaDefaults from "json-schema-defaults";
25   -import thingsboardTypes from "./types.constant";
  23 +import tinycolor from 'tinycolor2';
  24 +import jsonSchemaDefaults from 'json-schema-defaults';
  25 +import base64js from 'base64-js';
  26 +import {utf8Encode, utf8Decode} from './utf8-support';
  27 +
  28 +import thingsboardTypes from './types.constant';
26 29
27 30 export default angular.module('thingsboard.utils', [thingsboardTypes])
28 31 .factory('utils', Utils)
... ... @@ -153,7 +156,9 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
153 156 createKey: createKey,
154 157 createLabelFromDatasource: createLabelFromDatasource,
155 158 insertVariable: insertVariable,
156   - customTranslation: customTranslation
  159 + customTranslation: customTranslation,
  160 + objToBase64: objToBase64,
  161 + base64toObj: base64toObj
157 162 }
158 163
159 164 return service;
... ... @@ -486,4 +491,18 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
486 491 return result;
487 492 }
488 493
  494 + function objToBase64(obj) {
  495 + var json = angular.toJson(obj);
  496 + var encoded = utf8Encode(json);
  497 + var b64Encoded = base64js.fromByteArray(encoded);
  498 + return b64Encoded;
  499 + }
  500 +
  501 + function base64toObj(b64Encoded) {
  502 + var encoded = base64js.toByteArray(b64Encoded);
  503 + var json = utf8Decode(encoded);
  504 + var obj = angular.fromJson(json);
  505 + return obj;
  506 + }
  507 +
489 508 }
... ...
... ... @@ -473,7 +473,7 @@ export default function WidgetController($scope, $state, $timeout, $window, $ele
473 473 }
474 474 var stateParams = {
475 475 dashboardId: targetDashboardId,
476   - state: angular.toJson([ stateObject ])
  476 + state: utils.objToBase64([ stateObject ])
477 477 }
478 478 $state.go('home.dashboards.dashboard', stateParams);
479 479 break;
... ...
... ... @@ -121,11 +121,11 @@ export default function DefaultStateController($scope, $location, $state, $state
121 121 return utils.customTranslation(state.name, id);
122 122 }
123 123
124   - function parseState(stateJson) {
  124 + function parseState(stateBase64) {
125 125 var result;
126   - if (stateJson) {
  126 + if (stateBase64) {
127 127 try {
128   - result = angular.fromJson(stateJson);
  128 + result = utils.base64toObj(stateBase64);
129 129 } catch (e) {
130 130 result = [ { id: null, params: {} } ];
131 131 }
... ... @@ -205,7 +205,7 @@ export default function DefaultStateController($scope, $location, $state, $state
205 205
206 206 function updateLocation() {
207 207 if (vm.stateObject[0].id) {
208   - $location.search({state : angular.toJson(vm.stateObject)});
  208 + $location.search({state : utils.objToBase64(vm.stateObject)});
209 209 }
210 210 }
211 211 }
... ...
... ... @@ -168,11 +168,11 @@ export default function EntityStateController($scope, $location, $state, $stateP
168 168 return deferred.promise;
169 169 }
170 170
171   - function parseState(stateJson) {
  171 + function parseState(stateBase64) {
172 172 var result;
173   - if (stateJson) {
  173 + if (stateBase64) {
174 174 try {
175   - result = angular.fromJson(stateJson);
  175 + result = utils.base64toObj(stateBase64);
176 176 } catch (e) {
177 177 result = [ { id: null, params: {} } ];
178 178 }
... ... @@ -278,7 +278,7 @@ export default function EntityStateController($scope, $location, $state, $stateP
278 278
279 279 function updateLocation() {
280 280 if (vm.stateObject[vm.stateObject.length-1].id) {
281   - $location.search({state : angular.toJson(vm.stateObject)});
  281 + $location.search({state : utils.objToBase64(vm.stateObject)});
282 282 }
283 283 }
284 284
... ...
... ... @@ -23,7 +23,7 @@ import selectTargetLayoutTemplate from '../../dashboard/layouts/select-target-la
23 23
24 24 /*@ngInject*/
25 25 export default function AddWidgetToDashboardDialogController($scope, $mdDialog, $state, $q, $document, dashboardUtils,
26   - types, itembuffer, dashboardService, entityId, entityType, entityName, widget) {
  26 + utils, types, itembuffer, dashboardService, entityId, entityType, entityName, widget) {
27 27
28 28 var vm = this;
29 29
... ... @@ -143,7 +143,7 @@ export default function AddWidgetToDashboardDialogController($scope, $mdDialog,
143 143 var stateIds = Object.keys(dashboard.configuration.states);
144 144 var stateIndex = stateIds.indexOf(targetState);
145 145 if (stateIndex > 0) {
146   - stateParams.state = angular.toJson([ {id: targetState, params: {}} ]);
  146 + stateParams.state = utils.objToBase64([ {id: targetState, params: {}} ]);
147 147 }
148 148 $state.go('home.dashboards.dashboard', stateParams);
149 149 }
... ...