2016-11-03 00:20:48 +01:00
/ * *
2017-01-11 16:24:33 +01:00
* Copyright JS Foundation and other contributors , http : //js.foundation
2016-11-03 00:20:48 +01:00
*
* 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 .
* * /
RED . utils = ( function ( ) {
2020-02-24 12:22:47 +01:00
window . _marked = window . marked ;
window . marked = function ( txt ) {
console . warn ( "Use of 'marked()' is deprecated. Use RED.utils.renderMarkdown() instead" ) ;
return renderMarkdown ( txt ) ;
}
2021-10-04 23:59:34 +02:00
const descriptionList = {
name : 'descriptionList' ,
level : 'block' , // Is this a block-level or inline-level tokenizer?
start ( src ) {
2021-10-05 00:52:55 +02:00
if ( ! src ) { return null ; }
2021-10-22 17:05:37 +02:00
let m = src . match ( /:[^:\n]/g ) ;
2021-10-05 00:52:55 +02:00
return m && m . index ; // Hint to Marked.js to stop and check for a match
2021-10-04 23:59:34 +02:00
} ,
tokenizer ( src , tokens ) {
2021-10-05 00:52:55 +02:00
if ( ! src ) { return null ; }
2021-10-04 23:59:34 +02:00
const rule = /^(?::[^:\n]+:[^:\n]*(?:\n|$))+/ ; // Regex for the complete token
const match = rule . exec ( src ) ;
if ( match ) {
return { // Token to generate
type : 'descriptionList' , // Should match "name" above
raw : match [ 0 ] , // Text to consume from the source
text : match [ 0 ] . trim ( ) , // Additional custom properties
2021-10-08 18:56:24 +02:00
tokens : this . lexer . inlineTokens ( match [ 0 ] . trim ( ) ) // inlineTokens to process **bold**, *italics*, etc.
2021-10-04 23:59:34 +02:00
} ;
}
} ,
renderer ( token ) {
2021-10-08 18:56:24 +02:00
return ` <dl class="message-properties"> ${ this . parser . parseInline ( token . tokens ) } \n </dl> ` ; // parseInline to turn child tokens into HTML
2021-10-04 23:59:34 +02:00
}
} ;
const description = {
name : 'description' ,
level : 'inline' , // Is this a block-level or inline-level tokenizer?
start ( src ) {
2021-10-05 00:52:55 +02:00
if ( ! src ) { return null ; }
2021-10-22 17:05:37 +02:00
let m = src . match ( /:/g ) ;
2021-10-05 01:06:25 +02:00
return m && m . index ; // Hint to Marked.js to stop and check for a match
2021-10-04 23:59:34 +02:00
} ,
tokenizer ( src , tokens ) {
2021-10-05 00:52:55 +02:00
if ( ! src ) { return null ; }
2021-10-04 23:59:34 +02:00
const rule = /^:([^:\n]+)\(([^:\n]+)\).*?:([^:\n]*)(?:\n|$)/ ; // Regex for the complete token
const match = rule . exec ( src ) ;
if ( match ) {
return { // Token to generate
type : 'description' , // Should match "name" above
raw : match [ 0 ] , // Text to consume from the source
2021-10-08 18:56:24 +02:00
dt : this . lexer . inlineTokens ( match [ 1 ] . trim ( ) ) , // Additional custom properties
types : this . lexer . inlineTokens ( match [ 2 ] . trim ( ) ) ,
dd : this . lexer . inlineTokens ( match [ 3 ] . trim ( ) ) ,
2021-10-04 23:59:34 +02:00
} ;
}
} ,
renderer ( token ) {
2021-10-08 18:56:24 +02:00
return ` \n <dt> ${ this . parser . parseInline ( token . dt ) } <span class="property-type"> ${ this . parser . parseInline ( token . types ) } </span></dt><dd> ${ this . parser . parseInline ( token . dd ) } </dd> ` ;
2021-10-04 23:59:34 +02:00
} ,
childTokens : [ 'dt' , 'dd' ] , // Any child tokens to be visited by walkTokens
walkTokens ( token ) { // Post-processing on the completed token tree
if ( token . type === 'strong' ) {
token . text += ' walked' ;
}
}
} ;
const renderer = new window . _marked . Renderer ( ) ;
//override list creation - add node-ports to order lists
renderer . list = function ( body , ordered , start ) {
2021-10-05 00:36:22 +02:00
let addClass = /dl.*?class.*?message-properties.*/ . test ( body ) ;
if ( addClass && ordered ) {
return '<ol class="node-ports">' + body + '</ol>' ;
2021-10-04 23:59:34 +02:00
} else if ( ordered ) {
2021-10-05 00:36:22 +02:00
return '<ol>' + body + '</ol>' ;
2021-10-04 23:59:34 +02:00
} else {
2021-10-05 00:36:22 +02:00
return '<ul>' + body + '</ul>'
2021-10-04 23:59:34 +02:00
}
}
window . _marked . setOptions ( {
renderer : renderer ,
2020-02-24 12:22:47 +01:00
gfm : true ,
tables : true ,
breaks : false ,
pedantic : false ,
smartLists : true ,
smartypants : false
} ) ;
2021-10-04 23:59:34 +02:00
window . _marked . use ( { extensions : [ descriptionList , description ] } ) ;
2020-02-24 12:22:47 +01:00
function renderMarkdown ( txt ) {
var rendered = _marked ( txt ) ;
var cleaned = DOMPurify . sanitize ( rendered , { SAFE _FOR _JQUERY : true } )
return cleaned ;
}
2016-11-03 00:20:48 +01:00
function formatString ( str ) {
return str . replace ( /\r?\n/g , "↵" ) . replace ( /\t/g , "→" ) ;
}
2016-11-27 22:51:34 +01:00
function sanitize ( m ) {
return m . replace ( /&/g , "&" ) . replace ( /</g , "<" ) . replace ( />/g , ">" ) ;
}
2016-11-03 00:20:48 +01:00
function buildMessageSummaryValue ( value ) {
var result ;
if ( Array . isArray ( value ) ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>' ) . text ( 'array[' + value . length + ']' ) ;
2016-11-03 00:20:48 +01:00
} else if ( value === null ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-null">null</span>' ) ;
2016-11-03 00:20:48 +01:00
} else if ( typeof value === 'object' ) {
2020-09-07 22:05:27 +02:00
if ( value . hasOwnProperty ( 'type' ) && value . type === 'undefined' ) {
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-null">undefined</span>' ) ;
} else if ( value . hasOwnProperty ( 'type' ) && value . type === 'Buffer' && value . hasOwnProperty ( 'data' ) ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>' ) . text ( 'buffer[' + value . length + ']' ) ;
2016-11-03 00:20:48 +01:00
} else if ( value . hasOwnProperty ( 'type' ) && value . type === 'array' && value . hasOwnProperty ( 'data' ) ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>' ) . text ( 'array[' + value . length + ']' ) ;
2021-06-29 12:09:30 +02:00
} else if ( value . hasOwnProperty ( 'type' ) && value . type === 'set' && value . hasOwnProperty ( 'data' ) ) {
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>' ) . text ( 'set[' + value . length + ']' ) ;
} else if ( value . hasOwnProperty ( 'type' ) && value . type === 'map' && value . hasOwnProperty ( 'data' ) ) {
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>' ) . text ( 'map' ) ;
2018-06-25 23:31:11 +02:00
} else if ( value . hasOwnProperty ( 'type' ) && value . type === 'function' ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta"></span>' ) . text ( 'function' ) ;
2020-11-17 21:50:29 +01:00
} else if ( value . hasOwnProperty ( 'type' ) && ( value . type === 'number' || value . type === 'bigint' ) ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>' ) . text ( value . data ) ;
2021-11-08 21:24:10 +01:00
} else if ( value . hasOwnProperty ( 'type' ) && value . type === 'regexp' ) {
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>' ) . text ( value . data ) ;
2016-11-03 00:20:48 +01:00
} else {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-meta">object</span>' ) ;
2016-11-03 00:20:48 +01:00
}
} else if ( typeof value === 'string' ) {
2016-11-27 22:51:34 +01:00
var subvalue ;
if ( value . length > 30 ) {
subvalue = sanitize ( value . substring ( 0 , 30 ) ) + "…" ;
} else {
subvalue = sanitize ( value ) ;
2016-11-03 00:20:48 +01:00
}
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-string"></span>' ) . html ( '"' + formatString ( subvalue ) + '"' ) ;
2018-06-29 11:50:07 +02:00
} else if ( typeof value === 'number' ) {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-number"></span>' ) . text ( "" + value ) ;
2016-11-03 00:20:48 +01:00
} else {
2019-05-02 23:33:29 +02:00
result = $ ( '<span class="red-ui-debug-msg-object-value red-ui-debug-msg-type-other"></span>' ) . text ( "" + value ) ;
2016-11-03 00:20:48 +01:00
}
return result ;
}
2017-08-01 00:29:36 +02:00
function makeExpandable ( el , onbuild , ontoggle , expand ) {
2019-05-02 23:33:29 +02:00
el . addClass ( "red-ui-debug-msg-expandable" ) ;
2017-08-01 00:29:36 +02:00
el . prop ( 'toggle' , function ( ) {
return function ( state ) {
var parent = el . parent ( ) ;
if ( parent . hasClass ( 'collapsed' ) ) {
if ( state ) {
if ( onbuild && ! parent . hasClass ( 'built' ) ) {
onbuild ( ) ;
parent . addClass ( 'built' ) ;
}
parent . removeClass ( 'collapsed' ) ;
return true ;
}
} else {
if ( ! state ) {
parent . addClass ( 'collapsed' ) ;
return true ;
}
}
return false ;
}
} ) ;
2019-04-29 12:50:15 +02:00
el . on ( "click" , function ( e ) {
2016-11-03 00:20:48 +01:00
var parent = $ ( this ) . parent ( ) ;
2017-08-01 00:29:36 +02:00
var currentState = ! parent . hasClass ( 'collapsed' ) ;
if ( $ ( this ) . prop ( 'toggle' ) ( ! currentState ) ) {
if ( ontoggle ) {
ontoggle ( ! currentState ) ;
2016-11-03 00:20:48 +01:00
}
}
2017-08-01 00:29:36 +02:00
// if (parent.hasClass('collapsed')) {
// if (onbuild && !parent.hasClass('built')) {
// onbuild();
// parent.addClass('built');
// }
// if (ontoggle) {
// ontoggle(true);
// }
// parent.removeClass('collapsed');
// } else {
// parent.addClass('collapsed');
// if (ontoggle) {
// ontoggle(false);
// }
// }
2016-11-03 00:20:48 +01:00
e . preventDefault ( ) ;
} ) ;
2017-05-11 16:08:10 +02:00
if ( expand ) {
2019-04-29 12:50:15 +02:00
el . trigger ( "click" ) ;
2017-05-11 16:08:10 +02:00
}
2017-08-01 00:29:36 +02:00
2016-11-03 00:20:48 +01:00
}
2017-05-11 16:08:10 +02:00
var pinnedPaths = { } ;
2017-05-11 18:00:49 +02:00
var formattedPaths = { } ;
2017-05-11 16:08:10 +02:00
2018-11-12 18:04:22 +01:00
function addMessageControls ( obj , sourceId , key , msg , rootPath , strippedKey , extraTools ) {
2017-05-11 16:08:10 +02:00
if ( ! pinnedPaths . hasOwnProperty ( sourceId ) ) {
pinnedPaths [ sourceId ] = { }
}
2019-05-02 23:33:29 +02:00
var tools = $ ( '<span class="red-ui-debug-msg-tools"></span>' ) . appendTo ( obj ) ;
var copyTools = $ ( '<span class="red-ui-debug-msg-tools-copy button-group"></span>' ) . appendTo ( tools ) ;
2017-05-12 11:19:50 +02:00
if ( ! ! key ) {
2019-05-17 11:42:43 +02:00
var copyPath = $ ( '<button class="red-ui-button red-ui-button-small"><i class="fa fa-terminal"></i></button>' ) . appendTo ( copyTools ) . on ( "click" , function ( e ) {
2017-05-12 11:19:50 +02:00
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
RED . clipboard . copyText ( key , copyPath , "clipboard.copyMessagePath" ) ;
} )
2019-05-28 22:43:21 +02:00
RED . popover . tooltip ( copyPath , RED . _ ( "node-red:debug.sidebar.copyPath" ) ) ;
2017-05-12 11:19:50 +02:00
}
2019-05-17 11:42:43 +02:00
var copyPayload = $ ( '<button class="red-ui-button red-ui-button-small"><i class="fa fa-clipboard"></i></button>' ) . appendTo ( copyTools ) . on ( "click" , function ( e ) {
2017-05-10 16:49:12 +02:00
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
RED . clipboard . copyText ( msg , copyPayload , "clipboard.copyMessageValue" ) ;
} )
2019-05-27 16:48:06 +02:00
RED . popover . tooltip ( copyPayload , RED . _ ( "node-red:debug.sidebar.copyPayload" ) ) ;
2018-06-25 23:31:11 +02:00
if ( strippedKey !== undefined && strippedKey !== '' ) {
2017-05-11 16:08:10 +02:00
var isPinned = pinnedPaths [ sourceId ] . hasOwnProperty ( strippedKey ) ;
2017-05-10 16:49:12 +02:00
2019-05-17 11:42:43 +02:00
var pinPath = $ ( '<button class="red-ui-button red-ui-button-small red-ui-debug-msg-tools-pin"><i class="fa fa-map-pin"></i></button>' ) . appendTo ( tools ) . on ( "click" , function ( e ) {
2017-05-11 16:08:10 +02:00
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
if ( pinnedPaths [ sourceId ] . hasOwnProperty ( strippedKey ) ) {
delete pinnedPaths [ sourceId ] [ strippedKey ] ;
$ ( this ) . removeClass ( "selected" ) ;
2019-05-02 23:33:29 +02:00
obj . removeClass ( "red-ui-debug-msg-row-pinned" ) ;
2017-05-11 16:08:10 +02:00
} else {
var rootedPath = "$" + ( strippedKey [ 0 ] === '[' ? "" : "." ) + strippedKey ;
pinnedPaths [ sourceId ] [ strippedKey ] = normalisePropertyExpression ( rootedPath ) ;
$ ( this ) . addClass ( "selected" ) ;
2019-05-02 23:33:29 +02:00
obj . addClass ( "red-ui-debug-msg-row-pinned" ) ;
2017-05-11 16:08:10 +02:00
}
} ) . toggleClass ( "selected" , isPinned ) ;
2019-05-02 23:33:29 +02:00
obj . toggleClass ( "red-ui-debug-msg-row-pinned" , isPinned ) ;
2019-05-27 16:48:06 +02:00
RED . popover . tooltip ( pinPath , RED . _ ( "node-red:debug.sidebar.pinPath" ) ) ;
2017-05-11 16:08:10 +02:00
}
2018-11-12 18:04:22 +01:00
if ( extraTools ) {
2021-05-13 14:38:34 +02:00
var t = extraTools ;
if ( typeof t === 'function' ) {
t = t ( key , msg ) ;
}
if ( t ) {
t . addClass ( "red-ui-debug-msg-tools-other" ) ;
t . appendTo ( tools ) ;
}
2018-11-12 18:04:22 +01:00
}
2017-05-10 16:49:12 +02:00
}
2017-05-11 16:08:10 +02:00
function checkExpanded ( strippedKey , expandPaths , minRange , maxRange ) {
if ( expandPaths && expandPaths . length > 0 ) {
if ( strippedKey === '' && minRange === undefined ) {
return true ;
}
for ( var i = 0 ; i < expandPaths . length ; i ++ ) {
var p = expandPaths [ i ] ;
if ( p . indexOf ( strippedKey ) === 0 && ( p [ strippedKey . length ] === "." || p [ strippedKey . length ] === "[" ) ) {
2016-11-03 00:20:48 +01:00
2017-05-11 16:08:10 +02:00
if ( minRange !== undefined && p [ strippedKey . length ] === "[" ) {
var subkey = p . substring ( strippedKey . length ) ;
var m = ( /\[(\d+)\]/ . exec ( subkey ) ) ;
if ( m ) {
var index = parseInt ( m [ 1 ] ) ;
return minRange <= index && index <= maxRange ;
}
} else {
return true ;
}
}
}
}
return false ;
}
2017-05-11 22:15:16 +02:00
function formatNumber ( element , obj , sourceId , path , cycle , initialFormat ) {
2017-11-02 17:50:35 +01:00
var format = ( formattedPaths [ sourceId ] && formattedPaths [ sourceId ] [ path ] && formattedPaths [ sourceId ] [ path ] [ 'number' ] ) || initialFormat || "dec" ;
2017-05-11 18:00:49 +02:00
if ( cycle ) {
if ( format === 'dec' ) {
if ( ( obj . toString ( ) . length === 13 ) && ( obj <= 2147483647000 ) ) {
format = 'dateMS' ;
} else if ( ( obj . toString ( ) . length === 10 ) && ( obj <= 2147483647 ) ) {
format = 'dateS' ;
} else {
format = 'hex'
}
} else if ( format === 'dateMS' || format == 'dateS' ) {
2019-02-04 16:51:42 +01:00
if ( ( obj . toString ( ) . length === 13 ) && ( obj <= 2147483647000 ) ) {
format = 'dateML' ;
} else if ( ( obj . toString ( ) . length === 10 ) && ( obj <= 2147483647 ) ) {
format = 'dateL' ;
} else {
format = 'hex'
}
} else if ( format === 'dateML' || format == 'dateL' ) {
2017-05-11 18:00:49 +02:00
format = 'hex' ;
} else {
format = 'dec' ;
}
formattedPaths [ sourceId ] = formattedPaths [ sourceId ] || { } ;
2017-11-02 17:50:35 +01:00
formattedPaths [ sourceId ] [ path ] = formattedPaths [ sourceId ] [ path ] || { } ;
formattedPaths [ sourceId ] [ path ] [ 'number' ] = format ;
2017-05-11 22:15:16 +02:00
} else if ( initialFormat !== undefined ) {
formattedPaths [ sourceId ] = formattedPaths [ sourceId ] || { } ;
2017-11-02 17:50:35 +01:00
formattedPaths [ sourceId ] [ path ] = formattedPaths [ sourceId ] [ path ] || { } ;
formattedPaths [ sourceId ] [ path ] [ 'number' ] = format ;
2017-05-11 18:00:49 +02:00
}
if ( format === 'dec' ) {
element . text ( "" + obj ) ;
} else if ( format === 'dateMS' ) {
element . text ( ( new Date ( obj ) ) . toISOString ( ) ) ;
} else if ( format === 'dateS' ) {
element . text ( ( new Date ( obj * 1000 ) ) . toISOString ( ) ) ;
2019-02-04 16:51:42 +01:00
} else if ( format === 'dateML' ) {
var dd = new Date ( obj ) ;
element . text ( dd . toLocaleString ( ) + " [UTC" + ( dd . getTimezoneOffset ( ) / - 60 <= 0 ? "" : "+" ) + dd . getTimezoneOffset ( ) / - 60 + "]" ) ;
} else if ( format === 'dateL' ) {
var ddl = new Date ( obj * 1000 ) ;
element . text ( ddl . toLocaleString ( ) + " [UTC" + ( ddl . getTimezoneOffset ( ) / - 60 <= 0 ? "" : "+" ) + ddl . getTimezoneOffset ( ) / - 60 + "]" ) ;
2017-05-11 18:00:49 +02:00
} else if ( format === 'hex' ) {
element . text ( "0x" + ( obj ) . toString ( 16 ) ) ;
}
}
function formatBuffer ( element , button , sourceId , path , cycle ) {
2017-11-02 17:50:35 +01:00
var format = ( formattedPaths [ sourceId ] && formattedPaths [ sourceId ] [ path ] && formattedPaths [ sourceId ] [ path ] [ 'buffer' ] ) || "raw" ;
2017-05-11 18:00:49 +02:00
if ( cycle ) {
if ( format === 'raw' ) {
format = 'string' ;
} else {
format = 'raw' ;
}
formattedPaths [ sourceId ] = formattedPaths [ sourceId ] || { } ;
2017-11-02 17:50:35 +01:00
formattedPaths [ sourceId ] [ path ] = formattedPaths [ sourceId ] [ path ] || { } ;
formattedPaths [ sourceId ] [ path ] [ 'buffer' ] = format ;
2017-05-11 18:00:49 +02:00
}
if ( format === 'raw' ) {
button . text ( 'raw' ) ;
2019-05-02 23:33:29 +02:00
element . removeClass ( 'red-ui-debug-msg-buffer-string' ) . addClass ( 'red-ui-debug-msg-buffer-raw' ) ;
2017-05-11 18:00:49 +02:00
} else if ( format === 'string' ) {
button . text ( 'string' ) ;
2019-05-02 23:33:29 +02:00
element . addClass ( 'red-ui-debug-msg-buffer-string' ) . removeClass ( 'red-ui-debug-msg-buffer-raw' ) ;
2017-05-11 18:00:49 +02:00
}
}
2017-08-01 00:29:36 +02:00
function buildMessageElement ( obj , options ) {
options = options || { } ;
var key = options . key ;
var typeHint = options . typeHint ;
var hideKey = options . hideKey ;
var path = options . path ;
var sourceId = options . sourceId ;
var rootPath = options . rootPath ;
var expandPaths = options . expandPaths ;
var ontoggle = options . ontoggle ;
var exposeApi = options . exposeApi ;
2018-11-12 18:04:22 +01:00
var tools = options . tools ;
2017-08-01 00:29:36 +02:00
var subElements = { } ;
2016-11-03 00:20:48 +01:00
var i ;
var e ;
var entryObj ;
2017-08-01 00:29:36 +02:00
var expandableHeader ;
2016-11-03 00:20:48 +01:00
var header ;
var headerHead ;
2016-11-27 22:51:34 +01:00
var value ;
2017-05-11 16:08:10 +02:00
var strippedKey ;
2017-05-12 11:19:50 +02:00
if ( path !== undefined && rootPath !== undefined ) {
2017-05-11 16:08:10 +02:00
strippedKey = path . substring ( rootPath . length + ( path [ rootPath . length ] === "." ? 1 : 0 ) ) ;
}
2019-05-02 23:33:29 +02:00
var element = $ ( '<span class="red-ui-debug-msg-element"></span>' ) ;
2017-05-12 23:12:55 +02:00
element . collapse = function ( ) {
2019-05-02 23:33:29 +02:00
element . find ( ".red-ui-debug-msg-expandable" ) . parent ( ) . addClass ( "collapsed" ) ;
2017-05-12 23:12:55 +02:00
}
2019-05-02 23:33:29 +02:00
header = $ ( '<span class="red-ui-debug-msg-row"></span>' ) . appendTo ( element ) ;
2017-05-11 16:08:10 +02:00
if ( sourceId ) {
2018-11-12 18:04:22 +01:00
addMessageControls ( header , sourceId , path , obj , rootPath , strippedKey , tools ) ;
2017-05-11 16:08:10 +02:00
}
2016-11-03 00:20:48 +01:00
if ( ! key ) {
2019-05-02 23:33:29 +02:00
element . addClass ( "red-ui-debug-msg-top-level" ) ;
2017-05-11 16:08:10 +02:00
if ( sourceId ) {
var pinned = pinnedPaths [ sourceId ] ;
expandPaths = [ ] ;
if ( pinned ) {
for ( var pinnedPath in pinned ) {
if ( pinned . hasOwnProperty ( pinnedPath ) ) {
try {
var res = getMessageProperty ( { $ : obj } , pinned [ pinnedPath ] ) ;
if ( res !== undefined ) {
expandPaths . push ( pinnedPath ) ;
}
} catch ( err ) {
}
}
}
expandPaths . sort ( ) ;
}
2017-05-12 23:12:55 +02:00
element . clearPinned = function ( ) {
2019-05-02 23:33:29 +02:00
element . find ( ".red-ui-debug-msg-row-pinned" ) . removeClass ( "red-ui-debug-msg-row-pinned" ) ;
2017-05-12 23:12:55 +02:00
pinnedPaths [ sourceId ] = { } ;
}
2017-05-11 16:08:10 +02:00
}
2017-05-10 16:49:12 +02:00
} else {
if ( ! hideKey ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-object-key"></span>' ) . text ( key ) . appendTo ( header ) ;
2017-05-10 16:49:12 +02:00
$ ( '<span>: </span>' ) . appendTo ( header ) ;
}
2016-11-03 00:20:48 +01:00
}
2019-05-02 23:33:29 +02:00
entryObj = $ ( '<span class="red-ui-debug-msg-object-value"></span>' ) . appendTo ( header ) ;
2016-11-03 00:20:48 +01:00
var isArray = Array . isArray ( obj ) ;
var isArrayObject = false ;
2021-06-29 12:09:30 +02:00
if ( obj && typeof obj === 'object' && obj . hasOwnProperty ( 'type' ) && obj . hasOwnProperty ( 'data' ) && ( ( obj . _ _enc _ _ && obj . type === 'set' ) || ( obj . _ _enc _ _ && obj . type === 'array' ) || obj . type === 'Buffer' ) ) {
2016-11-03 00:20:48 +01:00
isArray = true ;
isArrayObject = true ;
}
if ( obj === null || obj === undefined ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-type-null">' + obj + '</span>' ) . appendTo ( entryObj ) ;
2020-09-07 22:05:27 +02:00
} else if ( obj . _ _enc _ _ && obj . type === 'undefined' ) {
$ ( '<span class="red-ui-debug-msg-type-null">undefined</span>' ) . appendTo ( entryObj ) ;
2020-11-17 21:50:29 +01:00
} else if ( obj . _ _enc _ _ && ( obj . type === 'number' || obj . type === 'bigint' ) ) {
2019-05-02 23:33:29 +02:00
e = $ ( '<span class="red-ui-debug-msg-type-number red-ui-debug-msg-object-header"></span>' ) . text ( obj . data ) . appendTo ( entryObj ) ;
2021-11-08 21:24:10 +01:00
} else if ( typeHint === "regexp" || ( obj . _ _enc _ _ && obj . type === 'regexp' ) ) {
e = $ ( '<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>' ) . text ( ( typeof obj === "string" ) ? obj : obj . data ) . appendTo ( entryObj ) ;
2018-07-15 00:06:15 +02:00
} else if ( typeHint === "function" || ( obj . _ _enc _ _ && obj . type === 'function' ) ) {
2019-05-02 23:33:29 +02:00
e = $ ( '<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>' ) . text ( "function" ) . appendTo ( entryObj ) ;
2018-07-15 00:06:15 +02:00
} else if ( typeHint === "internal" || ( obj . _ _enc _ _ && obj . type === 'internal' ) ) {
2019-05-02 23:33:29 +02:00
e = $ ( '<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-header"></span>' ) . text ( "[internal]" ) . appendTo ( entryObj ) ;
2016-11-03 00:20:48 +01:00
} else if ( typeof obj === 'string' ) {
2016-11-03 00:40:17 +01:00
if ( /[\t\n\r]/ . test ( obj ) ) {
element . addClass ( 'collapsed' ) ;
2019-05-02 23:33:29 +02:00
$ ( '<i class="fa fa-caret-right red-ui-debug-msg-object-handle"></i> ' ) . prependTo ( header ) ;
2016-11-03 00:40:17 +01:00
makeExpandable ( header , function ( ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-type-header"></span>' ) . text ( typeHint || 'string' ) . appendTo ( header ) ;
var row = $ ( '<div class="red-ui-debug-msg-object-entry collapsed"></div>' ) . appendTo ( element ) ;
$ ( '<pre class="red-ui-debug-msg-type-string"></pre>' ) . text ( obj ) . appendTo ( row ) ;
2017-08-01 00:29:36 +02:00
} , function ( state ) { if ( ontoggle ) { ontoggle ( path , state ) ; } } , checkExpanded ( strippedKey , expandPaths ) ) ;
2016-11-03 00:40:17 +01:00
}
2019-05-02 23:33:29 +02:00
e = $ ( '<span class="red-ui-debug-msg-type-string red-ui-debug-msg-object-header"></span>' ) . html ( '"' + formatString ( sanitize ( obj ) ) + '"' ) . appendTo ( entryObj ) ;
2017-01-16 11:29:00 +01:00
if ( /^#[0-9a-f]{6}$/i . test ( obj ) ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-type-string-swatch"></span>' ) . css ( 'backgroundColor' , obj ) . appendTo ( e ) ;
2017-01-16 11:29:00 +01:00
}
2016-11-03 00:20:48 +01:00
} else if ( typeof obj === 'number' ) {
2019-05-02 23:33:29 +02:00
e = $ ( '<span class="red-ui-debug-msg-type-number"></span>' ) . appendTo ( entryObj ) ;
2017-05-11 18:00:49 +02:00
2016-11-28 18:28:49 +01:00
if ( Number . isInteger ( obj ) && ( obj >= 0 ) ) { // if it's a +ve integer
2019-05-02 23:33:29 +02:00
e . addClass ( "red-ui-debug-msg-type-number-toggle" ) ;
2019-04-29 12:50:15 +02:00
e . on ( "click" , function ( evt ) {
2016-11-27 22:51:34 +01:00
evt . preventDefault ( ) ;
2017-05-11 18:00:49 +02:00
formatNumber ( $ ( this ) , obj , sourceId , path , true ) ;
2016-11-27 22:51:34 +01:00
} ) ;
}
2017-05-11 22:15:16 +02:00
formatNumber ( e , obj , sourceId , path , false , typeHint === 'hex' ? 'hex' : undefined ) ;
2017-05-11 18:00:49 +02:00
2016-11-03 00:20:48 +01:00
} else if ( isArray ) {
element . addClass ( 'collapsed' ) ;
var originalLength = obj . length ;
if ( typeHint ) {
var m = /\[(\d+)\]/ . exec ( typeHint ) ;
if ( m ) {
originalLength = parseInt ( m [ 1 ] ) ;
}
}
var data = obj ;
var type = 'array' ;
if ( isArrayObject ) {
data = obj . data ;
if ( originalLength === undefined ) {
originalLength = data . length ;
}
2018-07-15 00:06:15 +02:00
if ( data . _ _enc _ _ ) {
2017-01-16 18:43:39 +01:00
data = data . data ;
}
2016-11-03 00:20:48 +01:00
type = obj . type . toLowerCase ( ) ;
} else if ( /buffer/ . test ( typeHint ) ) {
type = 'buffer' ;
}
var fullLength = data . length ;
2021-06-29 12:09:30 +02:00
if ( originalLength > 0 ) {
2019-05-02 23:33:29 +02:00
$ ( '<i class="fa fa-caret-right red-ui-debug-msg-object-handle"></i> ' ) . prependTo ( header ) ;
var arrayRows = $ ( '<div class="red-ui-debug-msg-array-rows"></div>' ) . appendTo ( element ) ;
element . addClass ( 'red-ui-debug-msg-buffer-raw' ) ;
2017-05-22 21:13:39 +02:00
}
if ( key ) {
2019-05-02 23:33:29 +02:00
headerHead = $ ( '<span class="red-ui-debug-msg-type-meta"></span>' ) . text ( typeHint || ( type + '[' + originalLength + ']' ) ) . appendTo ( entryObj ) ;
2017-05-22 21:13:39 +02:00
} else {
2019-05-02 23:33:29 +02:00
headerHead = $ ( '<span class="red-ui-debug-msg-object-header"></span>' ) . appendTo ( entryObj ) ;
2017-05-22 21:13:39 +02:00
$ ( '<span>[ </span>' ) . appendTo ( headerHead ) ;
var arrayLength = Math . min ( originalLength , 10 ) ;
for ( i = 0 ; i < arrayLength ; i ++ ) {
buildMessageSummaryValue ( data [ i ] ) . appendTo ( headerHead ) ;
if ( i < arrayLength - 1 ) {
$ ( '<span>, </span>' ) . appendTo ( headerHead ) ;
2017-05-11 18:00:49 +02:00
}
}
2017-05-22 21:13:39 +02:00
if ( originalLength > arrayLength ) {
$ ( '<span> …</span>' ) . appendTo ( headerHead ) ;
}
if ( arrayLength === 0 ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-type-meta">empty</span>' ) . appendTo ( headerHead ) ;
2017-05-22 21:13:39 +02:00
}
$ ( '<span> ]</span>' ) . appendTo ( headerHead ) ;
}
if ( originalLength > 0 ) {
2017-05-11 18:00:49 +02:00
2016-11-03 00:20:48 +01:00
makeExpandable ( header , function ( ) {
if ( ! key ) {
2019-05-02 23:33:29 +02:00
headerHead = $ ( '<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-type-header"></span>' ) . text ( typeHint || ( type + '[' + originalLength + ']' ) ) . appendTo ( header ) ;
2016-11-03 00:20:48 +01:00
}
if ( type === 'buffer' ) {
2019-05-02 23:33:29 +02:00
var stringRow = $ ( '<div class="red-ui-debug-msg-string-rows"></div>' ) . appendTo ( element ) ;
var sr = $ ( '<div class="red-ui-debug-msg-object-entry collapsed"></div>' ) . appendTo ( stringRow ) ;
2016-11-03 00:20:48 +01:00
var stringEncoding = "" ;
try {
stringEncoding = String . fromCharCode . apply ( null , new Uint16Array ( data ) )
} catch ( err ) {
console . log ( err ) ;
}
2019-05-02 23:33:29 +02:00
$ ( '<pre class="red-ui-debug-msg-type-string"></pre>' ) . text ( stringEncoding ) . appendTo ( sr ) ;
var bufferOpts = $ ( '<span class="red-ui-debug-msg-buffer-opts"></span>' ) . appendTo ( headerHead ) ;
2019-05-17 11:42:43 +02:00
var switchFormat = $ ( '<a class="red-ui-button red-ui-button-small" href="#"></a>' ) . text ( 'raw' ) . appendTo ( bufferOpts ) . on ( "click" , function ( e ) {
2016-11-03 00:20:48 +01:00
e . preventDefault ( ) ;
e . stopPropagation ( ) ;
2017-05-11 18:00:49 +02:00
formatBuffer ( element , $ ( this ) , sourceId , path , true ) ;
} ) ;
formatBuffer ( element , switchFormat , sourceId , path , false ) ;
2016-11-03 00:20:48 +01:00
}
var row ;
if ( fullLength <= 10 ) {
for ( i = 0 ; i < fullLength ; i ++ ) {
2019-05-02 23:33:29 +02:00
row = $ ( '<div class="red-ui-debug-msg-object-entry collapsed"></div>' ) . appendTo ( arrayRows ) ;
2017-08-01 00:29:36 +02:00
subElements [ path + "[" + i + "]" ] = buildMessageElement (
data [ i ] ,
{
key : "" + i ,
typeHint : type === 'buffer' ? 'hex' : false ,
hideKey : false ,
path : path + "[" + i + "]" ,
sourceId : sourceId ,
rootPath : rootPath ,
expandPaths : expandPaths ,
ontoggle : ontoggle ,
2021-05-13 14:38:34 +02:00
exposeApi : exposeApi ,
2021-10-12 22:11:20 +02:00
// tools: tools // Do not pass tools down as we
// keep them attached to the top-level header
2017-08-01 00:29:36 +02:00
}
) . appendTo ( row ) ;
2016-11-03 00:20:48 +01:00
}
} else {
for ( i = 0 ; i < fullLength ; i += 10 ) {
var minRange = i ;
2019-05-02 23:33:29 +02:00
row = $ ( '<div class="red-ui-debug-msg-object-entry collapsed"></div>' ) . appendTo ( arrayRows ) ;
2016-11-03 00:20:48 +01:00
header = $ ( '<span></span>' ) . appendTo ( row ) ;
2019-05-02 23:33:29 +02:00
$ ( '<i class="fa fa-caret-right red-ui-debug-msg-object-handle"></i> ' ) . appendTo ( header ) ;
2016-11-03 00:20:48 +01:00
makeExpandable ( header , ( function ( ) {
var min = minRange ;
var max = Math . min ( fullLength - 1 , ( minRange + 9 ) ) ;
var parent = row ;
return function ( ) {
for ( var i = min ; i <= max ; i ++ ) {
2019-05-02 23:33:29 +02:00
var row = $ ( '<div class="red-ui-debug-msg-object-entry collapsed"></div>' ) . appendTo ( parent ) ;
2017-08-01 00:29:36 +02:00
subElements [ path + "[" + i + "]" ] = buildMessageElement (
data [ i ] ,
{
key : "" + i ,
typeHint : type === 'buffer' ? 'hex' : false ,
hideKey : false ,
path : path + "[" + i + "]" ,
sourceId : sourceId ,
rootPath : rootPath ,
expandPaths : expandPaths ,
ontoggle : ontoggle ,
2021-05-13 14:38:34 +02:00
exposeApi : exposeApi ,
2021-10-12 22:11:20 +02:00
// tools: tools // Do not pass tools down as we
// keep them attached to the top-level header
2017-08-01 00:29:36 +02:00
}
) . appendTo ( row ) ;
2016-11-03 00:20:48 +01:00
}
}
2017-08-01 00:29:36 +02:00
} ) ( ) ,
( function ( ) { var path = path + "[" + i + "]" ; return function ( state ) { if ( ontoggle ) { ontoggle ( path , state ) ; } } } ) ( ) ,
checkExpanded ( strippedKey , expandPaths , minRange , Math . min ( fullLength - 1 , ( minRange + 9 ) ) ) ) ;
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-object-key"></span>' ) . html ( "[" + minRange + " … " + Math . min ( fullLength - 1 , ( minRange + 9 ) ) + "]" ) . appendTo ( header ) ;
2016-11-03 00:20:48 +01:00
}
if ( fullLength < originalLength ) {
2019-05-02 23:33:29 +02:00
$ ( '<div class="red-ui-debug-msg-object-entry collapsed"><span class="red-ui-debug-msg-object-key">[' + fullLength + ' … ' + originalLength + ']</span></div>' ) . appendTo ( arrayRows ) ;
2016-11-03 00:20:48 +01:00
}
}
2017-08-01 00:29:36 +02:00
} ,
function ( state ) { if ( ontoggle ) { ontoggle ( path , state ) ; } } ,
checkExpanded ( strippedKey , expandPaths ) ) ;
2016-11-03 00:20:48 +01:00
}
} else if ( typeof obj === 'object' ) {
element . addClass ( 'collapsed' ) ;
2021-06-29 12:09:30 +02:00
var data = obj ;
var type = "object" ;
if ( data . _ _enc _ _ ) {
data = data . data ;
type = obj . type . toLowerCase ( ) ;
}
var keys = Object . keys ( data ) ;
2016-11-03 00:20:48 +01:00
if ( key || keys . length > 0 ) {
2019-05-02 23:33:29 +02:00
$ ( '<i class="fa fa-caret-right red-ui-debug-msg-object-handle"></i> ' ) . prependTo ( header ) ;
2016-11-03 00:20:48 +01:00
makeExpandable ( header , function ( ) {
if ( ! key ) {
2021-06-29 12:09:30 +02:00
$ ( '<span class="red-ui-debug-msg-type-meta red-ui-debug-msg-object-type-header"></span>' ) . text ( type ) . appendTo ( header ) ;
2016-11-03 00:20:48 +01:00
}
for ( i = 0 ; i < keys . length ; i ++ ) {
2019-05-02 23:33:29 +02:00
var row = $ ( '<div class="red-ui-debug-msg-object-entry collapsed"></div>' ) . appendTo ( element ) ;
2017-05-10 16:49:12 +02:00
var newPath = path ;
2018-02-14 00:42:22 +01:00
if ( newPath !== undefined ) {
2017-07-26 16:47:19 +02:00
if ( /^[a-zA-Z_$][0-9a-zA-Z_$]*$/ . test ( keys [ i ] ) ) {
newPath += ( newPath . length > 0 ? "." : "" ) + keys [ i ] ;
} else {
newPath += "[\"" + keys [ i ] . replace ( /"/ , "\\\"" ) + "\"]"
}
2017-05-10 16:49:12 +02:00
}
2017-08-01 00:29:36 +02:00
subElements [ newPath ] = buildMessageElement (
2021-06-29 12:09:30 +02:00
data [ keys [ i ] ] ,
2017-08-01 00:29:36 +02:00
{
key : keys [ i ] ,
typeHint : false ,
hideKey : false ,
path : newPath ,
sourceId : sourceId ,
rootPath : rootPath ,
expandPaths : expandPaths ,
ontoggle : ontoggle ,
2021-05-13 14:38:34 +02:00
exposeApi : exposeApi ,
2021-10-12 22:11:20 +02:00
// tools: tools // Do not pass tools down as we
// keep them attached to the top-level header
2017-08-01 00:29:36 +02:00
}
) . appendTo ( row ) ;
2016-11-03 00:20:48 +01:00
}
if ( keys . length === 0 ) {
2019-05-02 23:33:29 +02:00
$ ( '<div class="red-ui-debug-msg-object-entry red-ui-debug-msg-type-meta collapsed"></div>' ) . text ( "empty" ) . appendTo ( element ) ;
2016-11-03 00:20:48 +01:00
}
2017-08-01 00:29:36 +02:00
} ,
function ( state ) { if ( ontoggle ) { ontoggle ( path , state ) ; } } ,
checkExpanded ( strippedKey , expandPaths ) ) ;
2016-11-03 00:20:48 +01:00
}
if ( key ) {
2021-06-29 12:09:30 +02:00
$ ( '<span class="red-ui-debug-msg-type-meta"></span>' ) . text ( type ) . appendTo ( entryObj ) ;
2016-11-03 00:20:48 +01:00
} else {
2019-05-02 23:33:29 +02:00
headerHead = $ ( '<span class="red-ui-debug-msg-object-header"></span>' ) . appendTo ( entryObj ) ;
2016-11-03 00:20:48 +01:00
$ ( '<span>{ </span>' ) . appendTo ( headerHead ) ;
var keysLength = Math . min ( keys . length , 5 ) ;
for ( i = 0 ; i < keysLength ; i ++ ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-object-key"></span>' ) . text ( keys [ i ] ) . appendTo ( headerHead ) ;
2016-11-03 00:20:48 +01:00
$ ( '<span>: </span>' ) . appendTo ( headerHead ) ;
2021-06-29 12:09:30 +02:00
buildMessageSummaryValue ( data [ keys [ i ] ] ) . appendTo ( headerHead ) ;
2016-11-03 00:20:48 +01:00
if ( i < keysLength - 1 ) {
$ ( '<span>, </span>' ) . appendTo ( headerHead ) ;
}
}
if ( keys . length > keysLength ) {
$ ( '<span> …</span>' ) . appendTo ( headerHead ) ;
}
if ( keysLength === 0 ) {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-type-meta">empty</span>' ) . appendTo ( headerHead ) ;
2016-11-03 00:20:48 +01:00
}
$ ( '<span> }</span>' ) . appendTo ( headerHead ) ;
}
} else {
2019-05-02 23:33:29 +02:00
$ ( '<span class="red-ui-debug-msg-type-other"></span>' ) . text ( "" + obj ) . appendTo ( entryObj ) ;
2016-11-03 00:20:48 +01:00
}
2017-08-01 00:29:36 +02:00
if ( exposeApi ) {
element . prop ( 'expand' , function ( ) { return function ( targetPath , state ) {
if ( path === targetPath ) {
2017-08-03 10:58:25 +02:00
if ( header . prop ( 'toggle' ) ) {
header . prop ( 'toggle' ) ( state ) ;
}
} else if ( subElements [ targetPath ] && subElements [ targetPath ] . prop ( 'expand' ) ) {
2017-08-01 00:29:36 +02:00
subElements [ targetPath ] . prop ( 'expand' ) ( targetPath , state ) ;
2017-08-04 15:23:28 +02:00
} else {
for ( var p in subElements ) {
if ( subElements . hasOwnProperty ( p ) ) {
if ( targetPath . indexOf ( p ) === 0 ) {
if ( subElements [ p ] . prop ( 'expand' ) ) {
subElements [ p ] . prop ( 'expand' ) ( targetPath , state ) ;
}
break ;
}
}
}
2017-08-01 00:29:36 +02:00
}
} } ) ;
}
2016-11-03 00:20:48 +01:00
return element ;
}
2021-01-27 21:32:52 +01:00
function createError ( code , message ) {
var e = new Error ( message ) ;
e . code = code ;
return e ;
}
function normalisePropertyExpression ( str , msg ) {
2017-05-11 16:08:10 +02:00
// This must be kept in sync with validatePropertyExpression
// in editor/js/ui/utils.js
2017-01-06 12:23:19 +01:00
var length = str . length ;
2017-01-06 22:58:17 +01:00
if ( length === 0 ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: zero-length" ) ;
2017-01-06 22:58:17 +01:00
}
2017-05-11 16:08:10 +02:00
var parts = [ ] ;
2017-01-06 12:23:19 +01:00
var start = 0 ;
var inString = false ;
var inBox = false ;
2021-01-27 21:32:52 +01:00
var boxExpression = false ;
2017-01-06 12:23:19 +01:00
var quoteChar ;
var v ;
for ( var i = 0 ; i < length ; i ++ ) {
var c = str [ i ] ;
if ( ! inString ) {
if ( c === "'" || c === '"' ) {
if ( i != start ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected " + c + " at position " + i ) ;
2017-01-06 12:23:19 +01:00
}
inString = true ;
quoteChar = c ;
start = i + 1 ;
} else if ( c === '.' ) {
2017-05-11 16:08:10 +02:00
if ( i === 0 ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected . at position 0" ) ;
2017-05-11 16:08:10 +02:00
}
if ( start != i ) {
v = str . substring ( start , i ) ;
if ( /^\d+$/ . test ( v ) ) {
parts . push ( parseInt ( v ) ) ;
} else {
parts . push ( v ) ;
}
}
if ( i === length - 1 ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unterminated expression" ) ;
2017-01-06 12:23:19 +01:00
}
2017-01-06 15:32:37 +01:00
// Next char is first char of an identifier: a-z 0-9 $ _
if ( ! /[a-z0-9\$\_]/i . test ( str [ i + 1 ] ) ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected " + str [ i + 1 ] + " at position " + ( i + 1 ) ) ;
2017-01-06 12:23:19 +01:00
}
start = i + 1 ;
} else if ( c === '[' ) {
if ( i === 0 ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected " + c + " at position " + i ) ;
2017-05-11 16:08:10 +02:00
}
if ( start != i ) {
parts . push ( str . substring ( start , i ) ) ;
2017-01-06 12:23:19 +01:00
}
if ( i === length - 1 ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unterminated expression" ) ;
2017-01-06 12:23:19 +01:00
}
2021-01-27 21:32:52 +01:00
// Start of a new expression. If it starts with msg it is a nested expression
// Need to scan ahead to find the closing bracket
if ( /^msg[.\[]/ . test ( str . substring ( i + 1 ) ) ) {
var depth = 1 ;
var inLocalString = false ;
var localStringQuote ;
for ( var j = i + 1 ; j < length ; j ++ ) {
if ( /["']/ . test ( str [ j ] ) ) {
if ( inLocalString ) {
if ( str [ j ] === localStringQuote ) {
inLocalString = false
}
} else {
inLocalString = true ;
localStringQuote = str [ j ]
}
}
if ( str [ j ] === '[' ) {
depth ++ ;
} else if ( str [ j ] === ']' ) {
depth -- ;
}
if ( depth === 0 ) {
try {
if ( msg ) {
parts . push ( getMessageProperty ( msg , str . substring ( i + 1 , j ) ) )
} else {
parts . push ( normalisePropertyExpression ( str . substring ( i + 1 , j ) , msg ) ) ;
}
inBox = false ;
i = j ;
start = j + 1 ;
break ;
} catch ( err ) {
throw createError ( "INVALID_EXPR" , "Invalid expression started at position " + ( i + 1 ) )
}
}
}
if ( depth > 0 ) {
throw createError ( "INVALID_EXPR" , "Invalid property expression: unmatched '[' at position " + i ) ;
}
continue ;
} else if ( ! /["'\d]/ . test ( str [ i + 1 ] ) ) {
// Next char is either a quote or a number
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected " + str [ i + 1 ] + " at position " + ( i + 1 ) ) ;
2017-01-06 12:23:19 +01:00
}
start = i + 1 ;
inBox = true ;
} else if ( c === ']' ) {
if ( ! inBox ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected " + c + " at position " + i ) ;
2017-01-06 12:23:19 +01:00
}
if ( start != i ) {
v = str . substring ( start , i ) ;
2017-05-11 16:08:10 +02:00
if ( /^\d+$/ . test ( v ) ) {
parts . push ( parseInt ( v ) ) ;
} else {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected array expression at position " + start ) ;
2017-01-06 12:23:19 +01:00
}
}
start = i + 1 ;
inBox = false ;
} else if ( c === ' ' ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected ' ' at position " + i ) ;
2017-01-06 12:23:19 +01:00
}
} else {
if ( c === quoteChar ) {
if ( i - start === 0 ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: zero-length string at position " + start ) ;
2017-01-06 12:23:19 +01:00
}
2017-05-11 16:08:10 +02:00
parts . push ( str . substring ( start , i ) ) ;
// If inBox, next char must be a ]. Otherwise it may be [ or .
2017-01-06 12:23:19 +01:00
if ( inBox && ! /\]/ . test ( str [ i + 1 ] ) ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected array expression at position " + start ) ;
2017-01-06 12:23:19 +01:00
} else if ( ! inBox && i + 1 !== length && ! /[\[\.]/ . test ( str [ i + 1 ] ) ) {
2021-01-27 21:32:52 +01:00
throw createError ( "INVALID_EXPR" , "Invalid property expression: unexpected " + str [ i + 1 ] + " expression at position " + ( i + 1 ) ) ;
2017-01-06 12:23:19 +01:00
}
start = i + 1 ;
inString = false ;
}
}
}
if ( inBox || inString ) {
2021-01-27 21:32:52 +01:00
throw new createError ( "INVALID_EXPR" , "Invalid property expression: unterminated expression" ) ;
2017-05-11 16:08:10 +02:00
}
if ( start < length ) {
parts . push ( str . substring ( start ) ) ;
}
return parts ;
}
function validatePropertyExpression ( str ) {
try {
var parts = normalisePropertyExpression ( str ) ;
return true ;
} catch ( err ) {
2017-01-06 12:23:19 +01:00
return false ;
}
2017-05-11 16:08:10 +02:00
}
function getMessageProperty ( msg , expr ) {
var result = null ;
var msgPropParts ;
if ( typeof expr === 'string' ) {
if ( expr . indexOf ( 'msg.' ) === 0 ) {
expr = expr . substring ( 4 ) ;
}
msgPropParts = normalisePropertyExpression ( expr ) ;
} else {
msgPropParts = expr ;
}
var m ;
msgPropParts . reduce ( function ( obj , key ) {
result = ( typeof obj [ key ] !== "undefined" ? obj [ key ] : undefined ) ;
if ( result === undefined && obj . hasOwnProperty ( 'type' ) && obj . hasOwnProperty ( 'data' ) && obj . hasOwnProperty ( 'length' ) ) {
result = ( typeof obj . data [ key ] !== "undefined" ? obj . data [ key ] : undefined ) ;
}
return result ;
} , msg ) ;
return result ;
2017-01-06 12:23:19 +01:00
}
2019-05-21 18:19:12 +02:00
function setMessageProperty ( msg , prop , value , createMissing ) {
if ( typeof createMissing === 'undefined' ) {
createMissing = ( typeof value !== 'undefined' ) ;
}
if ( prop . indexOf ( 'msg.' ) === 0 ) {
prop = prop . substring ( 4 ) ;
}
var msgPropParts = normalisePropertyExpression ( prop ) ;
var depth = 0 ;
var length = msgPropParts . length ;
var obj = msg ;
var key ;
for ( var i = 0 ; i < length - 1 ; i ++ ) {
key = msgPropParts [ i ] ;
if ( typeof key === 'string' || ( typeof key === 'number' && ! Array . isArray ( obj ) ) ) {
if ( obj . hasOwnProperty ( key ) ) {
obj = obj [ key ] ;
} else if ( createMissing ) {
if ( typeof msgPropParts [ i + 1 ] === 'string' ) {
obj [ key ] = { } ;
} else {
obj [ key ] = [ ] ;
}
obj = obj [ key ] ;
} else {
return null ;
}
} else if ( typeof key === 'number' ) {
// obj is an array
if ( obj [ key ] === undefined ) {
if ( createMissing ) {
if ( typeof msgPropParts [ i + 1 ] === 'string' ) {
obj [ key ] = { } ;
} else {
obj [ key ] = [ ] ;
}
obj = obj [ key ] ;
} else {
return null ;
}
} else {
obj = obj [ key ] ;
}
}
}
key = msgPropParts [ length - 1 ] ;
if ( typeof value === "undefined" ) {
if ( typeof key === 'number' && Array . isArray ( obj ) ) {
obj . splice ( key , 1 ) ;
} else {
delete obj [ key ]
}
} else {
obj [ key ] = value ;
}
}
2021-06-10 15:15:43 +02:00
2017-11-30 14:13:35 +01:00
function separateIconPath ( icon ) {
var result = { module : "" , file : "" } ;
if ( icon ) {
2020-05-01 18:37:15 +02:00
var index = icon . indexOf ( RED . settings . apiRootUrl + 'icons/' ) ;
if ( index === 0 ) {
icon = icon . substring ( ( RED . settings . apiRootUrl + 'icons/' ) . length ) ;
2018-09-26 02:16:15 +02:00
}
2021-06-10 15:15:43 +02:00
var match = /^((?:@[^/]+\/)?[^/]+)\/(.*)$/ . exec ( icon ) ;
if ( match ) {
result . module = match [ 1 ] ;
result . file = match [ 2 ] ;
2017-11-30 14:13:35 +01:00
} else {
result . file = icon ;
}
2017-01-18 14:06:22 +01:00
}
2017-11-30 14:13:35 +01:00
return result ;
}
function getDefaultNodeIcon ( def , node ) {
2021-05-13 15:28:01 +02:00
def = def || { } ;
2017-01-18 14:06:22 +01:00
var icon _url ;
2018-03-22 06:14:09 +01:00
if ( node && node . type === "subflow" ) {
2019-06-21 13:36:20 +02:00
icon _url = "node-red/subflow.svg" ;
2018-03-22 06:14:09 +01:00
} else if ( typeof def . icon === "function" ) {
2017-01-18 14:06:22 +01:00
try {
icon _url = def . icon . call ( node ) ;
} catch ( err ) {
console . log ( "Definition error: " + def . type + ".icon" , err ) ;
2019-06-21 13:36:20 +02:00
icon _url = "arrow-in.svg" ;
2017-01-18 14:06:22 +01:00
}
} else {
icon _url = def . icon ;
}
2017-11-30 14:13:35 +01:00
var iconPath = separateIconPath ( icon _url ) ;
if ( ! iconPath . module ) {
2018-02-15 16:33:19 +01:00
if ( def . set ) {
iconPath . module = def . set . module ;
} else {
// Handle subflow instance nodes that don't have def.set
iconPath . module = "node-red" ;
}
2017-11-30 14:13:35 +01:00
}
return iconPath ;
}
2018-03-14 05:51:50 +01:00
function isIconExists ( iconPath ) {
var iconSets = RED . nodes . getIconSets ( ) ;
var iconFileList = iconSets [ iconPath . module ] ;
if ( iconFileList && iconFileList . indexOf ( iconPath . file ) !== - 1 ) {
return true ;
} else {
return false ;
}
}
2017-11-30 14:13:35 +01:00
function getNodeIcon ( def , node ) {
2021-05-13 15:28:01 +02:00
def = def || { } ;
2020-05-01 18:37:15 +02:00
if ( node && node . type === '_selection_' ) {
return "font-awesome/fa-object-ungroup" ;
} else if ( node && node . type === 'group' ) {
2020-04-27 12:17:19 +02:00
return "font-awesome/fa-object-group"
} else if ( def . category === 'config' ) {
2019-06-21 13:36:20 +02:00
return RED . settings . apiRootUrl + "icons/node-red/cog.svg"
2017-11-30 14:13:35 +01:00
} else if ( node && node . type === 'tab' ) {
2020-05-01 18:37:15 +02:00
return "red-ui-icons/red-ui-icons-flow"
// return RED.settings.apiRootUrl+"images/subflow_tab.svg"
2017-11-30 14:13:35 +01:00
} else if ( node && node . type === 'unknown' ) {
2019-06-21 13:36:20 +02:00
return RED . settings . apiRootUrl + "icons/node-red/alert.svg"
2017-11-30 14:13:35 +01:00
} else if ( node && node . icon ) {
var iconPath = separateIconPath ( node . icon ) ;
2018-10-23 09:30:56 +02:00
if ( isIconExists ( iconPath ) ) {
if ( iconPath . module === "font-awesome" ) {
return node . icon ;
} else {
return RED . settings . apiRootUrl + "icons/" + node . icon ;
}
2019-06-21 13:36:20 +02:00
} else if ( iconPath . module !== "font-awesome" && /.png$/i . test ( iconPath . file ) ) {
iconPath . file = iconPath . file . replace ( /.png$/ , ".svg" ) ;
if ( isIconExists ( iconPath ) ) {
return RED . settings . apiRootUrl + "icons/" + node . icon . replace ( /.png$/ , ".svg" ) ;
}
2017-11-30 14:13:35 +01:00
}
}
var iconPath = getDefaultNodeIcon ( def , node ) ;
2018-11-29 17:57:39 +01:00
if ( isIconExists ( iconPath ) ) {
if ( iconPath . module === "font-awesome" ) {
return iconPath . module + "/" + iconPath . file ;
} else {
return RED . settings . apiRootUrl + "icons/" + iconPath . module + "/" + iconPath . file ;
2018-03-14 05:51:50 +01:00
}
2019-06-21 16:41:17 +02:00
}
if ( /.png$/i . test ( iconPath . file ) ) {
var originalFile = iconPath . file ;
iconPath . file = iconPath . file . replace ( /.png$/ , ".svg" ) ;
if ( isIconExists ( iconPath ) ) {
return RED . settings . apiRootUrl + "icons/" + iconPath . module + "/" + iconPath . file ;
}
iconPath . file = originalFile ;
}
// This could be a non-core node trying to use a core icon.
iconPath . module = 'node-red' ;
if ( isIconExists ( iconPath ) ) {
return RED . settings . apiRootUrl + "icons/" + iconPath . module + "/" + iconPath . file ;
}
if ( /.png$/i . test ( iconPath . file ) ) {
iconPath . file = iconPath . file . replace ( /.png$/ , ".svg" ) ;
2018-12-07 17:43:06 +01:00
if ( isIconExists ( iconPath ) ) {
return RED . settings . apiRootUrl + "icons/" + iconPath . module + "/" + iconPath . file ;
2018-11-29 17:57:39 +01:00
}
2018-09-26 02:16:15 +02:00
}
2019-06-21 16:41:17 +02:00
if ( def . category === 'subflows' ) {
return RED . settings . apiRootUrl + "icons/node-red/subflow.svg" ;
}
return RED . settings . apiRootUrl + "icons/node-red/arrow-in.svg" ;
2017-01-18 14:06:22 +01:00
}
2016-11-22 13:57:08 +01:00
function getNodeLabel ( node , defaultLabel ) {
defaultLabel = defaultLabel || "" ;
2017-05-22 12:35:45 +02:00
var l ;
if ( node . type === 'tab' ) {
l = node . label || defaultLabel
2020-05-01 18:37:15 +02:00
} else if ( node . type === 'group' ) {
l = node . name || defaultLabel
2017-05-22 12:35:45 +02:00
} else {
l = node . _def . label ;
try {
l = ( typeof l === "function" ? l . call ( node ) : l ) || defaultLabel ;
} catch ( err ) {
console . log ( "Definition error: " + node . type + ".label" , err ) ;
l = defaultLabel ;
}
2016-11-22 13:57:08 +01:00
}
return RED . text . bidi . enforceTextDirectionWithUCC ( l ) ;
}
2018-07-27 23:05:28 +02:00
var nodeColorCache = { } ;
2019-07-11 01:22:31 +02:00
function clearNodeColorCache ( ) {
nodeColorCache = { } ;
}
2018-07-27 23:05:28 +02:00
function getNodeColor ( type , def ) {
2021-05-13 15:28:01 +02:00
def = def || { } ;
2018-07-27 23:05:28 +02:00
var result = def . color ;
var paletteTheme = RED . settings . theme ( 'palette.theme' ) || [ ] ;
if ( paletteTheme . length > 0 ) {
if ( ! nodeColorCache . hasOwnProperty ( type ) ) {
2018-08-24 14:08:49 +02:00
nodeColorCache [ type ] = def . color ;
2018-07-27 23:05:28 +02:00
var l = paletteTheme . length ;
2018-08-24 14:08:49 +02:00
for ( var i = 0 ; i < l ; i ++ ) {
2018-07-27 23:05:28 +02:00
var themeRule = paletteTheme [ i ] ;
if ( themeRule . hasOwnProperty ( 'category' ) ) {
if ( ! themeRule . hasOwnProperty ( '_category' ) ) {
themeRule . _category = new RegExp ( themeRule . category ) ;
}
if ( ! themeRule . _category . test ( def . category ) ) {
continue ;
}
}
if ( themeRule . hasOwnProperty ( 'type' ) ) {
if ( ! themeRule . hasOwnProperty ( '_type' ) ) {
themeRule . _type = new RegExp ( themeRule . type ) ;
}
if ( ! themeRule . _type . test ( type ) ) {
continue ;
}
}
nodeColorCache [ type ] = themeRule . color || def . color ;
break ;
}
}
result = nodeColorCache [ type ] ;
}
2018-09-08 23:41:38 +02:00
if ( result ) {
return result ;
} else {
return "#ddd" ;
}
2018-07-27 23:05:28 +02:00
}
2018-01-22 14:46:11 +01:00
function addSpinnerOverlay ( container , contain ) {
2019-05-07 16:47:33 +02:00
var spinner = $ ( '<div class="red-ui-component-spinner "><img src="red/images/spin.svg"/></div>' ) . appendTo ( container ) ;
2018-01-22 14:46:11 +01:00
if ( contain ) {
2019-05-07 16:47:33 +02:00
spinner . addClass ( 'red-ui-component-spinner-contain' ) ;
2018-01-22 14:46:11 +01:00
}
return spinner ;
}
2018-06-25 23:31:11 +02:00
function decodeObject ( payload , format ) {
if ( ( format === 'number' ) && ( payload === "NaN" ) ) {
payload = Number . NaN ;
2018-06-29 11:50:07 +02:00
} else if ( ( format === 'number' ) && ( payload === "Infinity" ) ) {
payload = Infinity ;
} else if ( ( format === 'number' ) && ( payload === "-Infinity" ) ) {
payload = - Infinity ;
2021-06-29 12:09:30 +02:00
} else if ( format === 'Object' || /^(array|set|map)/ . test ( format ) || format === 'boolean' || format === 'number' ) {
2018-06-25 23:31:11 +02:00
payload = JSON . parse ( payload ) ;
} else if ( /error/i . test ( format ) ) {
payload = JSON . parse ( payload ) ;
payload = ( payload . name ? payload . name + ": " : "" ) + payload . message ;
} else if ( format === 'null' ) {
payload = null ;
} else if ( format === 'undefined' ) {
payload = undefined ;
} else if ( /^buffer/ . test ( format ) ) {
var buffer = payload ;
payload = [ ] ;
for ( var c = 0 ; c < buffer . length ; c += 2 ) {
payload . push ( parseInt ( buffer . substr ( c , 2 ) , 16 ) ) ;
}
}
return payload ;
}
2021-03-10 18:50:46 +01:00
function parseContextKey ( key , defaultStore ) {
2018-07-10 12:41:46 +02:00
var parts = { } ;
var m = /^#:\((\S+?)\)::(.*)$/ . exec ( key ) ;
if ( m ) {
parts . store = m [ 1 ] ;
parts . key = m [ 2 ] ;
} else {
parts . key = key ;
2021-03-10 18:50:46 +01:00
if ( defaultStore ) {
parts . store = defaultStore ;
} else if ( RED . settings . context ) {
2018-07-10 12:41:46 +02:00
parts . store = RED . settings . context . default ;
}
}
return parts ;
}
2018-06-25 23:31:11 +02:00
2018-09-28 10:07:55 +02:00
/ * *
* Create or update an icon element and append it to iconContainer .
* @ param iconUrl - Url of icon .
2019-04-29 23:38:14 +02:00
* @ param iconContainer - Icon container element with red - ui - palette - icon - container class .
2018-10-23 09:30:56 +02:00
* @ param isLarge - Whether the icon size is large .
2018-09-28 10:07:55 +02:00
* /
2018-11-29 17:57:39 +01:00
function createIconElement ( iconUrl , iconContainer , isLarge ) {
2018-09-28 10:07:55 +02:00
// Removes the previous icon when icon was changed.
2019-04-29 23:38:14 +02:00
var iconElement = iconContainer . find ( ".red-ui-palette-icon" ) ;
2018-09-28 10:07:55 +02:00
if ( iconElement . length !== 0 ) {
iconElement . remove ( ) ;
}
var faIconElement = iconContainer . find ( "i" ) ;
if ( faIconElement . length !== 0 ) {
faIconElement . remove ( ) ;
}
// Show either icon image or font-awesome icon
2018-09-26 02:16:15 +02:00
var iconPath = separateIconPath ( iconUrl ) ;
if ( iconPath . module === "font-awesome" ) {
2018-10-23 09:30:56 +02:00
var fontAwesomeUnicode = RED . nodes . fontAwesome . getIconUnicode ( iconPath . file ) ;
if ( fontAwesomeUnicode ) {
var faIconElement = $ ( '<i/>' ) . appendTo ( iconContainer ) ;
var faLarge = isLarge ? "fa-lg " : "" ;
2019-04-29 23:38:14 +02:00
faIconElement . addClass ( "red-ui-palette-icon-fa fa fa-fw " + faLarge + iconPath . file ) ;
2018-10-23 09:30:56 +02:00
return ;
}
2018-11-29 17:57:39 +01:00
// If the specified name is not defined in font-awesome, show arrow-in icon.
2019-06-21 13:36:20 +02:00
iconUrl = RED . settings . apiRootUrl + "icons/node-red/arrow-in.svg"
2020-05-01 18:37:15 +02:00
} else if ( iconPath . module === "red-ui-icons" ) {
var redIconElement = $ ( '<i/>' ) . appendTo ( iconContainer ) ;
redIconElement . addClass ( "red-ui-palette-icon red-ui-icons " + iconPath . file ) ;
return ;
2018-09-26 02:16:15 +02:00
}
2019-04-29 23:38:14 +02:00
var imageIconElement = $ ( '<div/>' , { class : "red-ui-palette-icon" } ) . appendTo ( iconContainer ) ;
2018-10-23 09:30:56 +02:00
imageIconElement . css ( "backgroundImage" , "url(" + iconUrl + ")" ) ;
2018-09-26 02:16:15 +02:00
}
2021-05-04 12:12:55 +02:00
function createNodeIcon ( node , includeLabel ) {
2021-05-13 14:39:29 +02:00
var container = $ ( '<span class="red-ui-node-icon-container">' ) ;
2020-05-01 18:37:15 +02:00
var def = node . _def ;
2021-05-04 12:12:55 +02:00
var nodeDiv = $ ( '<div>' , { class : "red-ui-node-icon" } )
2020-05-01 18:37:15 +02:00
if ( node . type === "_selection_" ) {
nodeDiv . addClass ( "red-ui-palette-icon-selection" ) ;
} else if ( node . type === "group" ) {
nodeDiv . addClass ( "red-ui-palette-icon-group" ) ;
} else if ( node . type === 'tab' ) {
nodeDiv . addClass ( "red-ui-palette-icon-flow" ) ;
} else {
var colour = RED . utils . getNodeColor ( node . type , def ) ;
// if (node.type === 'tab') {
// colour = "#C0DEED";
// }
nodeDiv . css ( 'backgroundColor' , colour ) ;
var borderColor = getDarkerColor ( colour ) ;
if ( borderColor !== colour ) {
nodeDiv . css ( 'border-color' , borderColor )
}
}
var icon _url = RED . utils . getNodeIcon ( def , node ) ;
2021-05-04 12:12:55 +02:00
RED . utils . createIconElement ( icon _url , nodeDiv , true ) ;
2021-05-13 14:39:29 +02:00
nodeDiv . appendTo ( container ) ;
2021-05-04 12:12:55 +02:00
if ( includeLabel ) {
var labelText = RED . utils . getNodeLabel ( node , node . name || ( node . type + ": " + node . id ) ) ;
var label = $ ( '<div>' , { class : "red-ui-node-label" } ) . appendTo ( container ) ;
if ( labelText ) {
label . text ( labelText )
} else {
label . html ( " " )
}
}
2021-05-13 14:39:29 +02:00
return container ;
2020-05-01 18:37:15 +02:00
}
function getDarkerColor ( c ) {
var r , g , b ;
if ( /^#[a-f0-9]{6}$/i . test ( c ) ) {
r = parseInt ( c . substring ( 1 , 3 ) , 16 ) ;
g = parseInt ( c . substring ( 3 , 5 ) , 16 ) ;
b = parseInt ( c . substring ( 5 , 7 ) , 16 ) ;
} else if ( /^#[a-f0-9]{3}$/i . test ( c ) ) {
r = parseInt ( c . substring ( 1 , 2 ) + c . substring ( 1 , 2 ) , 16 ) ;
g = parseInt ( c . substring ( 2 , 3 ) + c . substring ( 2 , 3 ) , 16 ) ;
b = parseInt ( c . substring ( 3 , 4 ) + c . substring ( 3 , 4 ) , 16 ) ;
} else {
return c ;
}
var l = 0.3 * r / 255 + 0.59 * g / 255 + 0.11 * b / 255 ;
r = Math . max ( 0 , r - 50 ) ;
g = Math . max ( 0 , g - 50 ) ;
b = Math . max ( 0 , b - 50 ) ;
var s = ( ( r << 16 ) + ( g << 8 ) + b ) . toString ( 16 ) ;
return '#' + '000000' . slice ( 0 , 6 - s . length ) + s ;
}
2021-02-12 19:14:13 +01:00
function parseModuleList ( list ) {
list = list || [ "*" ] ;
return list . map ( function ( rule ) {
var m = /^(.+?)(?:@(.*))?$/ . exec ( rule ) ;
var wildcardPos = m [ 1 ] . indexOf ( "*" ) ;
wildcardPos = wildcardPos === - 1 ? Infinity : wildcardPos ;
return {
module : new RegExp ( "^" + m [ 1 ] . replace ( /\*/g , ".*" ) + "$" ) ,
version : m [ 2 ] ,
wildcardPos : wildcardPos
}
} )
}
function checkAgainstList ( module , version , list ) {
for ( var i = 0 ; i < list . length ; i ++ ) {
var rule = list [ i ] ;
if ( rule . module . test ( module ) ) {
// Without a full semver library in the editor,
// we skip the version check.
// Not ideal - but will get caught in the runtime
// if the user tries to install.
return rule ;
}
}
}
function checkModuleAllowed ( module , version , allowList , denyList ) {
if ( ! allowList && ! denyList ) {
// Default to allow
return true ;
}
if ( allowList . length === 0 && denyList . length === 0 ) {
return true ;
}
var allowedRule = checkAgainstList ( module , version , allowList ) ;
var deniedRule = checkAgainstList ( module , version , denyList ) ;
// console.log("A",allowedRule)
// console.log("D",deniedRule)
if ( allowedRule && ! deniedRule ) {
return true ;
}
if ( ! allowedRule && deniedRule ) {
return false ;
}
if ( ! allowedRule && ! deniedRule ) {
return true ;
}
if ( allowedRule . wildcardPos !== deniedRule . wildcardPos ) {
return allowedRule . wildcardPos > deniedRule . wildcardPos
} else {
// First wildcard in same position.
// Go with the longer matching rule. This isn't going to be 100%
// right, but we are deep into edge cases at this point.
return allowedRule . module . toString ( ) . length > deniedRule . module . toString ( ) . length
}
return false ;
}
2021-04-29 18:35:11 +02:00
function getBrowserInfo ( ) {
var r = { }
try {
var ua = navigator . userAgent ;
r . ua = ua ;
r . browser = /Edge\/\d+/ . test ( ua ) ? 'ed' : /MSIE 9/ . test ( ua ) ? 'ie9' : /MSIE 10/ . test ( ua ) ? 'ie10' : /MSIE 11/ . test ( ua ) ? 'ie11' : /MSIE\s\d/ . test ( ua ) ? 'ie?' : /rv\:11/ . test ( ua ) ? 'ie11' : /Firefox\W\d/ . test ( ua ) ? 'ff' : /Chrom(e|ium)\W\d|CriOS\W\d/ . test ( ua ) ? 'gc' : /\bSafari\W\d/ . test ( ua ) ? 'sa' : /\bOpera\W\d/ . test ( ua ) ? 'op' : /\bOPR\W\d/i . test ( ua ) ? 'op' : typeof MSPointerEvent !== 'undefined' ? 'ie?' : '' ;
r . os = /Windows NT 10/ . test ( ua ) ? "win10" : /Windows NT 6\.0/ . test ( ua ) ? "winvista" : /Windows NT 6\.1/ . test ( ua ) ? "win7" : /Windows NT 6\.\d/ . test ( ua ) ? "win8" : /Windows NT 5\.1/ . test ( ua ) ? "winxp" : /Windows NT [1-5]\./ . test ( ua ) ? "winnt" : /Mac/ . test ( ua ) ? "mac" : /Linux/ . test ( ua ) ? "linux" : /X11/ . test ( ua ) ? "nix" : "" ;
r . touch = 'ontouchstart' in document . documentElement ;
r . mobile = /IEMobile|Windows Phone|Lumia/i . test ( ua ) ? 'w' : /iPhone|iP[oa]d/ . test ( ua ) ? 'i' : /Android/ . test ( ua ) ? 'a' : /BlackBerry|PlayBook|BB10/ . test ( ua ) ? 'b' : /Mobile Safari/ . test ( ua ) ? 's' : /webOS|Mobile|Tablet|Opera Mini|\bCrMo\/|Opera Mobi/i . test ( ua ) ? 1 : 0 ;
2021-06-29 12:09:30 +02:00
r . tablet = /Tablet|iPad/i . test ( ua ) ;
2021-04-29 18:35:11 +02:00
r . ie = /MSIE \d|Trident.*rv:/ . test ( navigator . userAgent ) ;
r . android = /android/i . test ( navigator . userAgent ) ;
} catch ( error ) { }
return r ;
}
2021-06-29 12:09:30 +02:00
2016-11-03 00:20:48 +01:00
return {
createObjectElement : buildMessageElement ,
2017-05-11 16:08:10 +02:00
getMessageProperty : getMessageProperty ,
2019-05-21 18:19:12 +02:00
setMessageProperty : setMessageProperty ,
2017-05-11 16:08:10 +02:00
normalisePropertyExpression : normalisePropertyExpression ,
2017-01-18 14:06:22 +01:00
validatePropertyExpression : validatePropertyExpression ,
2017-11-30 14:13:35 +01:00
separateIconPath : separateIconPath ,
getDefaultNodeIcon : getDefaultNodeIcon ,
2016-11-22 13:57:08 +01:00
getNodeIcon : getNodeIcon ,
2017-05-10 16:49:12 +02:00
getNodeLabel : getNodeLabel ,
2018-07-27 23:05:28 +02:00
getNodeColor : getNodeColor ,
2019-07-11 01:22:31 +02:00
clearNodeColorCache : clearNodeColorCache ,
2018-06-25 23:31:11 +02:00
addSpinnerOverlay : addSpinnerOverlay ,
2018-07-10 12:41:46 +02:00
decodeObject : decodeObject ,
2018-09-26 02:16:15 +02:00
parseContextKey : parseContextKey ,
2019-02-15 22:53:27 +01:00
createIconElement : createIconElement ,
2020-02-24 12:22:47 +01:00
sanitize : sanitize ,
2020-05-01 18:37:15 +02:00
renderMarkdown : renderMarkdown ,
createNodeIcon : createNodeIcon ,
2021-02-12 19:14:13 +01:00
getDarkerColor : getDarkerColor ,
parseModuleList : parseModuleList ,
2021-04-29 18:35:11 +02:00
checkModuleAllowed : checkModuleAllowed ,
getBrowserInfo : getBrowserInfo
2016-11-03 00:20:48 +01:00
}
} ) ( ) ;