2019-06-23 03:35:23 -07:00
< template >
< div @ keydown.stop :class ="parameterInputClasses" >
< expression -edit :dialogVisible ="expressionEditDialogVisible" :value ="value" :parameter ="parameter" :path ="path" @closeDialog ="closeExpressionEditDialog" @valueChanged ="expressionUpdated" > < / expression -edit >
2021-08-29 04:36:17 -07:00
< div class = "parameter-input ignore-key-press" :style ="parameterInputWrapperStyle" @click ="openExpressionEdit" >
< n8n -input
v - if = "isValueExpression && showExpressionAsTextInput"
: size = "inputSize"
: value = "expressionDisplayValue"
: disabled = "isReadOnly"
: title = "displayTitle"
@ keydown . stop
/ >
< div v -else -if = " [ ' json ' , ' string ' ] .includes ( parameter.type ) | | remoteParameterOptionsLoadingIssues ! = = null " >
2019-09-04 09:22:06 -07:00
< code -edit :dialogVisible ="codeEditDialogVisible" :value ="value" :parameter ="parameter" @closeDialog ="closeCodeEditDialog" @valueChanged ="expressionUpdated" > < / code -edit >
< text -edit :dialogVisible ="textEditDialogVisible" :value ="value" :parameter ="parameter" @closeDialog ="closeTextEditDialog" @valueChanged ="expressionUpdated" > < / text -edit >
2019-06-23 03:35:23 -07:00
2019-09-04 09:22:06 -07:00
< div v-if ="isEditor === true" class="clickable" @click="displayEditDialog()" >
< prism -editor v-if ="!codeEditDialogVisible" :lineNumbers="true" :readonly="true" :code="displayValue" language="js" > < / prism -editor >
< / div >
2021-08-29 04:36:17 -07:00
< n8n -input
v - else
2019-06-23 03:35:23 -07:00
v - model = "tempValue"
ref = "inputField"
2021-08-29 04:36:17 -07:00
: size = "inputSize"
: type = "getStringInputType"
: rows = "getArgument('rows')"
2019-06-23 03:35:23 -07:00
: value = "displayValue"
: disabled = "isReadOnly"
2021-09-11 01:15:36 -07:00
@ input = "onTextInputChange"
2019-06-23 03:35:23 -07:00
@ change = "valueChanged"
@ keydown . stop
2021-08-29 04:36:17 -07:00
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2021-08-29 04:36:17 -07:00
: title = "displayTitle"
: placeholder = "isValueExpression?'':parameter.placeholder"
2019-06-23 03:35:23 -07:00
>
2021-08-29 04:36:17 -07:00
< div slot = "suffix" class = "expand-input-icon-container" >
< font -awesome -icon v -if = " ! isValueExpression & & ! isReadOnly " icon = "external-link-alt" class = "edit-window-button clickable" title = "Open Edit Window" @click ="displayEditDialog()" / >
< / div >
< / n 8 n - i n p u t >
2019-06-23 03:35:23 -07:00
< / div >
2021-08-29 04:36:17 -07:00
< div v -else -if = " parameter.type = = = ' color ' " ref = "inputField" class = "color-input" >
< el -color -picker
size = "small"
class = "color-picker"
: value = "displayValue"
: disabled = "isReadOnly"
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2021-08-29 04:36:17 -07:00
@ change = "valueChanged"
: title = "displayTitle"
: show - alpha = "getArgument('showAlpha')"
/ >
< n8n -input
v - model = "tempValue"
: size = "inputSize"
type = "text"
: value = "tempValue"
: disabled = "isReadOnly"
@ change = "valueChanged"
@ keydown . stop
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2021-08-29 04:36:17 -07:00
: title = "displayTitle"
/ >
2019-06-23 03:35:23 -07:00
< / div >
2021-08-29 04:36:17 -07:00
< el -date -picker
v - else - if = "parameter.type === 'dateTime'"
v - model = "tempValue"
ref = "inputField"
type = "datetime"
: size = "inputSize"
: value = "displayValue"
: title = "displayTitle"
: disabled = "isReadOnly"
: placeholder = "parameter.placeholder?parameter.placeholder:'Select date and time'"
: picker - options = "dateTimePickerOptions"
@ change = "valueChanged"
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2021-08-29 04:36:17 -07:00
@ keydown . stop
/ >
< n8n -input -number
v - else - if = "parameter.type === 'number'"
ref = "inputField" : size = "inputSize"
: value = "displayValue"
: controls = "false"
: max = "getArgument('maxValue')"
: min = "getArgument('minValue')"
: precision = "getArgument('numberPrecision')"
: step = "getArgument('numberStepSize')"
: disabled = "isReadOnly"
@ change = "valueChanged"
2021-09-11 01:15:36 -07:00
@ input = "onTextInputChange"
2021-08-29 04:36:17 -07:00
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2021-08-29 04:36:17 -07:00
@ keydown . stop
: title = "displayTitle"
: placeholder = "parameter.placeholder"
/ >
< n8n -select
2019-06-23 03:35:23 -07:00
v - else - if = "parameter.type === 'options'"
ref = "inputField"
2021-08-29 04:36:17 -07:00
: size = "inputSize"
2019-06-23 03:35:23 -07:00
filterable
: value = "displayValue"
: loading = "remoteParameterOptionsLoading"
: disabled = "isReadOnly || remoteParameterOptionsLoading"
: title = "displayTitle"
2021-09-11 01:15:36 -07:00
: popper - append - to - body = "true"
2019-06-23 03:35:23 -07:00
@ change = "valueChanged"
@ keydown . stop
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2019-06-23 03:35:23 -07:00
>
2021-08-29 04:36:17 -07:00
< n8n -option
2019-06-23 03:35:23 -07:00
v - for = "option in parameterOptions"
: value = "option.value"
: key = "option.value"
: label = "option.name"
>
2021-08-29 04:36:17 -07:00
< div class = "list-option" >
< div class = "option-headline" > { { option . name } } < / div >
< div v-if ="option.description" class="option-description" v-html="option.description" > < / div >
< / div >
< / n 8 n - o p t i o n >
< / n 8 n - s e l e c t >
< n8n -select
2019-11-05 11:49:04 -08:00
v - else - if = "parameter.type === 'multiOptions'"
ref = "inputField"
2021-08-29 04:36:17 -07:00
: size = "inputSize"
2019-11-05 11:49:04 -08:00
filterable
multiple
: value = "displayValue"
: loading = "remoteParameterOptionsLoading"
: disabled = "isReadOnly || remoteParameterOptionsLoading"
@ change = "valueChanged"
@ keydown . stop
@ focus = "setFocus"
2021-09-11 01:15:36 -07:00
@ blur = "onBlur"
2019-11-05 11:49:04 -08:00
: title = "displayTitle"
>
2021-08-29 04:36:17 -07:00
< n8n -option v -for = " option in parameterOptions " :value ="option.value" :key ="option.value" :label ="option.name" >
< div class = "list-option" >
< div class = "option-headline" > { { option . name } } < / div >
< div v-if ="option.description" class="option-description" v-html="option.description" > < / div >
< / div >
< / n 8 n - o p t i o n >
< / n 8 n - s e l e c t >
< el -switch
v - else - if = "parameter.type === 'boolean'"
class = "switch-input"
ref = "inputField"
active - color = "#13ce66"
: value = "displayValue"
: disabled = "isReadOnly"
@ change = "valueChanged"
/ >
< / div >
2019-06-23 03:35:23 -07:00
2021-08-29 04:36:17 -07:00
< div class = "parameter-issues" v-if ="getIssues.length" >
< n8n -tooltip placement = "top" >
< div slot = "content" v-html ="'Issues:<br /> - ' + getIssues.join('<br /> - ')" > < / div >
< font -awesome -icon icon = "exclamation-triangle" / >
< / n 8 n - t o o l t i p >
2019-06-23 03:35:23 -07:00
< / div >
2021-08-29 04:36:17 -07:00
2019-06-23 03:35:23 -07:00
< div class = "parameter-options" v-if ="displayOptionsComputed" >
< el -dropdown trigger = "click" @command ="optionSelected" size = "mini" >
< span class = "el-dropdown-link" >
< font -awesome -icon icon = "cogs" class = "reset-icon clickable" title = "Parameter Options" / >
< / span >
< el -dropdown -menu slot = "dropdown" >
2019-07-18 10:26:16 -07:00
< el -dropdown -item command = "addExpression" v-if ="parameter.noDataExpression !== true && !isValueExpression" > Add Expression < / el -dropdown -item >
< el -dropdown -item command = "removeExpression" v-if ="parameter.noDataExpression !== true && isValueExpression" > Remove Expression < / el -dropdown -item >
2021-07-23 08:52:25 -07:00
< el -dropdown -item command = "refreshOptions" v-if ="Boolean(remoteMethod)" > Refresh List < / el -dropdown -item >
2019-06-23 03:35:23 -07:00
< el -dropdown -item command = "resetValue" :disabled ="isDefault" divided > Reset Value < / e l - d r o p d o w n - i t e m >
< / e l - d r o p d o w n - m e n u >
< / e l - d r o p d o w n >
< / div >
< / div >
< / template >
< script lang = "ts" >
2020-01-04 20:28:09 -08:00
import { get } from 'lodash' ;
2019-06-23 03:35:23 -07:00
import {
INodeUi ,
} from '@/Interface' ;
import {
NodeHelpers ,
NodeParameterValue ,
2019-12-16 18:27:56 -08:00
INodeParameters ,
2019-06-23 03:35:23 -07:00
INodePropertyOptions ,
Workflow ,
} from 'n8n-workflow' ;
2019-09-04 09:22:06 -07:00
import CodeEdit from '@/components/CodeEdit.vue' ;
2019-06-23 03:35:23 -07:00
import ExpressionEdit from '@/components/ExpressionEdit.vue' ;
2019-09-04 09:22:06 -07:00
// @ts-ignore
import PrismEditor from 'vue-prism-editor' ;
2019-06-23 03:35:23 -07:00
import TextEdit from '@/components/TextEdit.vue' ;
2021-08-13 03:01:12 -07:00
import { externalHooks } from '@/components/mixins/externalHooks' ;
2019-06-23 03:35:23 -07:00
import { nodeHelpers } from '@/components/mixins/nodeHelpers' ;
import { showMessage } from '@/components/mixins/showMessage' ;
import { workflowHelpers } from '@/components/mixins/workflowHelpers' ;
import mixins from 'vue-typed-mixins' ;
export default mixins (
2021-08-13 03:01:12 -07:00
externalHooks ,
2019-06-23 03:35:23 -07:00
nodeHelpers ,
showMessage ,
workflowHelpers ,
)
. extend ( {
name : 'ParameterInput' ,
components : {
2019-09-04 09:22:06 -07:00
CodeEdit ,
2019-06-23 03:35:23 -07:00
ExpressionEdit ,
2019-09-04 09:22:06 -07:00
PrismEditor ,
2019-06-23 03:35:23 -07:00
TextEdit ,
} ,
props : [
'displayOptions' , // boolean
2021-09-11 01:15:36 -07:00
'inputSize' ,
'isReadOnly' ,
'documentationUrl' ,
2019-06-23 03:35:23 -07:00
'parameter' , // NodeProperties
'path' , // string
'value' ,
2021-09-11 01:15:36 -07:00
'hideIssues' , // boolean
'errorHighlight' ,
2019-06-23 03:35:23 -07:00
] ,
data ( ) {
return {
2019-09-04 09:22:06 -07:00
codeEditDialogVisible : false ,
2019-06-23 03:35:23 -07:00
nodeName : '' ,
expressionAddOperation : 'set' as 'add' | 'set' ,
expressionEditDialogVisible : false ,
remoteParameterOptions : [ ] as INodePropertyOptions [ ] ,
remoteParameterOptionsLoading : false ,
remoteParameterOptionsLoadingIssues : null as string | null ,
textEditDialogVisible : false ,
2019-12-29 21:04:51 -08:00
tempValue : '' , // el-date-picker and el-input does not seem to work without v-model so add one
2019-06-23 03:35:23 -07:00
dateTimePickerOptions : {
shortcuts : [
{
text : 'Today' ,
// tslint:disable-next-line:no-any
onClick ( picker : any ) {
picker . $emit ( 'pick' , new Date ( ) ) ;
} ,
} ,
{
text : 'Yesterday' ,
// tslint:disable-next-line:no-any
onClick ( picker : any ) {
const date = new Date ( ) ;
date . setTime ( date . getTime ( ) - 3600 * 1000 * 24 ) ;
picker . $emit ( 'pick' , date ) ;
} ,
} ,
{
text : 'A week ago' ,
// tslint:disable-next-line:no-any
onClick ( picker : any ) {
const date = new Date ( ) ;
date . setTime ( date . getTime ( ) - 3600 * 1000 * 24 * 7 ) ;
picker . $emit ( 'pick' , date ) ;
} ,
} ,
] ,
} ,
} ;
} ,
watch : {
2020-01-04 20:28:09 -08:00
dependentParametersValues ( ) {
// Reload the remote parameters whenever a parameter
// on which the current field depends on changes
this . loadRemoteParameterOptions ( ) ;
} ,
2019-06-23 03:35:23 -07:00
value ( ) {
2020-11-09 02:26:46 -08:00
if ( this . parameter . type === 'color' && this . getArgument ( 'showAlpha' ) === true ) {
// Do not set for color with alpha else wrong value gets displayed in field
return ;
}
2019-06-23 03:35:23 -07:00
this . tempValue = this . displayValue as string ;
} ,
} ,
computed : {
2021-08-29 04:36:17 -07:00
showExpressionAsTextInput ( ) : boolean {
const types = [ 'number' , 'boolean' , 'dateTime' , 'options' , 'multiOptions' ] ;
return types . includes ( this . parameter . type ) ;
} ,
2020-01-04 20:28:09 -08:00
dependentParametersValues ( ) : string | null {
const loadOptionsDependsOn = this . getArgument ( 'loadOptionsDependsOn' ) as string [ ] | undefined ;
if ( loadOptionsDependsOn === undefined ) {
return null ;
}
// Get the resolved parameter values of the current node
const currentNodeParameters = this . $store . getters . activeNode . parameters ;
2021-05-16 17:25:04 -07:00
const resolvedNodeParameters = this . resolveParameter ( currentNodeParameters ) ;
2020-01-04 20:28:09 -08:00
2020-01-04 20:54:16 -08:00
const returnValues : string [ ] = [ ] ;
2020-01-04 20:28:09 -08:00
for ( const parameterPath of loadOptionsDependsOn ) {
2020-01-04 20:54:16 -08:00
returnValues . push ( get ( resolvedNodeParameters , parameterPath ) as string ) ;
2020-01-04 20:28:09 -08:00
}
return returnValues . join ( '|' ) ;
} ,
2019-06-23 03:35:23 -07:00
node ( ) : INodeUi | null {
return this . $store . getters . activeNode ;
} ,
displayTitle ( ) : string {
let title = ` Parameter: " ${ this . shortPath } " ` ;
if ( this . getIssues . length ) {
title += ` has issues ` ;
if ( this . isValueExpression === true ) {
title += ` and expression ` ;
}
title += ` ! ` ;
} else {
if ( this . isValueExpression === true ) {
title += ` has expression ` ;
}
}
return title ;
} ,
displayValue ( ) : string | number | boolean | null {
2020-04-06 01:15:46 -07:00
if ( this . remoteParameterOptionsLoading === true ) {
2019-06-23 03:35:23 -07:00
// If it is loading options from server display
// to user that the data is loading. If not it would
// display the user the key instead of the value it
// represents
return 'Loading options...' ;
}
let returnValue ;
if ( this . isValueExpression === false ) {
returnValue = this . value ;
} else {
returnValue = this . expressionValueComputed ;
}
2020-11-09 02:26:46 -08:00
if ( this . parameter . type === 'color' && this . getArgument ( 'showAlpha' ) === true && returnValue . charAt ( 0 ) === '#' ) {
// Convert the value to rgba that el-color-picker can display it correctly
const bigint = parseInt ( returnValue . slice ( 1 ) , 16 ) ;
const h = [ ] ;
h . push ( ( bigint >> 24 ) & 255 ) ;
h . push ( ( bigint >> 16 ) & 255 ) ;
h . push ( ( bigint >> 8 ) & 255 ) ;
h . push ( ( 255 - bigint & 255 ) / 255 ) ;
returnValue = 'rgba(' + h . join ( ) + ')' ;
}
2020-02-07 17:06:36 -08:00
if ( returnValue !== undefined && returnValue !== null && this . parameter . type === 'string' ) {
2019-06-23 03:35:23 -07:00
const rows = this . getArgument ( 'rows' ) ;
if ( rows === undefined || rows === 1 ) {
returnValue = returnValue . toString ( ) . replace ( /\n/ , '|' ) ;
}
}
return returnValue ;
} ,
2021-08-29 04:36:17 -07:00
expressionDisplayValue ( ) : string {
const value = this . displayValue ;
// address type errors for text input
if ( typeof value === 'number' || typeof value === 'boolean' ) {
return JSON . stringify ( value ) ;
}
if ( value === null ) {
return '' ;
}
return value ;
} ,
2019-06-23 03:35:23 -07:00
displayOptionsComputed ( ) : boolean {
if ( this . isReadOnly === true ) {
return false ;
}
if ( this . parameter . type === 'collection' ) {
return false ;
}
if ( this . displayOptions === true ) {
return true ;
}
return false ;
} ,
expressionValueComputed ( ) : NodeParameterValue | null {
2021-01-24 04:33:57 -08:00
if ( this . node === null ) {
2019-06-23 03:35:23 -07:00
return null ;
}
let computedValue : NodeParameterValue ;
try {
computedValue = this . resolveExpression ( this . value ) as NodeParameterValue ;
} catch ( error ) {
computedValue = ` [ERROR: ${ error . message } ] ` ;
}
// Try to convert it into the corret type
if ( this . parameter . type === 'number' ) {
computedValue = parseInt ( computedValue as string , 10 ) ;
if ( isNaN ( computedValue ) ) {
return null ;
}
}
return computedValue ;
} ,
getStringInputType ( ) {
if ( this . getArgument ( 'password' ) === true ) {
return 'password' ;
}
const rows = this . getArgument ( 'rows' ) ;
if ( rows !== undefined && rows > 1 ) {
return 'textarea' ;
}
return 'text' ;
} ,
getIssues ( ) : string [ ] {
2021-09-11 01:15:36 -07:00
if ( this . hideIssues === true || this . node === null ) {
2019-06-23 03:35:23 -07:00
return [ ] ;
}
const newPath = this . shortPath . split ( '.' ) ;
newPath . pop ( ) ;
const issues = NodeHelpers . getParameterIssues ( this . parameter , this . node . parameters , newPath . join ( '.' ) ) ;
2019-11-05 11:49:04 -08:00
if ( [ 'options' , 'multiOptions' ] . includes ( this . parameter . type ) && this . remoteParameterOptionsLoading === false && this . remoteParameterOptionsLoadingIssues === null ) {
2019-06-23 03:35:23 -07:00
// Check if the value resolves to a valid option
// Currently it only displays an error in the node itself in
// case the value is not valid. The workflow can still be executed
// and the error is not displayed on the node in the workflow
const validOptions = this . parameterOptions ! . map ( ( options : INodePropertyOptions ) => options . value ) ;
2019-11-21 15:07:38 -08:00
const checkValues : string [ ] = [ ] ;
if ( Array . isArray ( this . displayValue ) ) {
checkValues . push . apply ( checkValues , this . displayValue ) ;
} else {
checkValues . push ( this . displayValue as string ) ;
}
for ( const checkValue of checkValues ) {
if ( checkValue === null || ! validOptions . includes ( checkValue ) ) {
if ( issues . parameters === undefined ) {
issues . parameters = { } ;
}
issues . parameters [ this . parameter . name ] = [ ` The value " ${ checkValue } " is not supported! ` ] ;
2019-06-23 03:35:23 -07:00
}
}
} else if ( this . remoteParameterOptionsLoadingIssues !== null ) {
if ( issues . parameters === undefined ) {
issues . parameters = { } ;
}
issues . parameters [ this . parameter . name ] = [ ` There was a problem loading the parameter options from server: " ${ this . remoteParameterOptionsLoadingIssues } " ` ] ;
}
if ( issues !== undefined &&
issues . parameters !== undefined &&
issues . parameters [ this . parameter . name ] !== undefined ) {
return issues . parameters [ this . parameter . name ] ;
}
return [ ] ;
} ,
isDefault ( ) : boolean {
return this . parameter . default === this . value ;
} ,
2019-09-04 09:22:06 -07:00
isEditor ( ) : boolean {
return this . getArgument ( 'editor' ) === 'code' ;
} ,
2019-06-23 03:35:23 -07:00
isValueExpression ( ) {
2019-07-18 10:26:16 -07:00
if ( this . parameter . noDataExpression === true ) {
return false ;
}
2019-06-23 03:35:23 -07:00
if ( typeof this . value === 'string' && this . value . charAt ( 0 ) === '=' ) {
return true ;
}
return false ;
} ,
parameterOptions ( ) : INodePropertyOptions [ ] {
if ( this . remoteMethod === undefined ) {
// Options are already given
return this . parameter . options ;
}
// Options get loaded from server
return this . remoteParameterOptions ;
} ,
parameterInputClasses ( ) {
const classes = [ ] ;
2021-08-29 04:36:17 -07:00
const rows = this . getArgument ( 'rows' ) ;
const isTextarea = this . parameter . type === 'string' && rows !== undefined ;
if ( ! isTextarea ) {
classes . push ( 'parameter-value-container' ) ;
}
2019-06-23 03:35:23 -07:00
if ( this . isValueExpression ) {
classes . push ( 'expression' ) ;
}
2021-09-11 01:15:36 -07:00
if ( this . getIssues . length || this . errorHighlight ) {
2019-06-23 03:35:23 -07:00
classes . push ( 'has-issues' ) ;
}
return classes ;
} ,
parameterInputWrapperStyle ( ) {
let deductWidth = 0 ;
const styles = {
width : '100%' ,
} ;
if ( this . displayOptionsComputed === true ) {
deductWidth += 25 ;
}
if ( this . getIssues . length ) {
deductWidth += 20 ;
}
if ( deductWidth !== 0 ) {
styles . width = ` calc(100% - ${ deductWidth } px) ` ;
}
return styles ;
} ,
remoteMethod ( ) : string | undefined {
return this . getArgument ( 'loadOptionsMethod' ) as string | undefined ;
} ,
shortPath ( ) : string {
const shortPath = this . path . split ( '.' ) ;
shortPath . shift ( ) ;
return shortPath . join ( '.' ) ;
} ,
workflow ( ) : Workflow {
return this . getWorkflow ( ) ;
} ,
} ,
methods : {
async loadRemoteParameterOptions ( ) {
2019-10-20 11:55:49 -07:00
if ( this . node === null || this . remoteMethod === undefined || this . remoteParameterOptionsLoading ) {
2019-06-23 03:35:23 -07:00
return ;
}
this . remoteParameterOptionsLoadingIssues = null ;
this . remoteParameterOptionsLoading = true ;
this . remoteParameterOptions . length = 0 ;
2019-12-16 18:27:56 -08:00
// Get the resolved parameter values of the current node
const currentNodeParameters = this . $store . getters . activeNode . parameters ;
2021-05-16 17:25:04 -07:00
const resolvedNodeParameters = this . resolveParameter ( currentNodeParameters ) as INodeParameters ;
2019-12-16 18:27:56 -08:00
2019-06-23 03:35:23 -07:00
try {
2021-09-21 10:38:24 -07:00
const options = await this . restApi ( ) . getNodeParameterOptions ( { name : this . node . type , version : this . node . typeVersion } , this . path , this . remoteMethod , resolvedNodeParameters , this . node . credentials ) ;
2019-06-23 03:35:23 -07:00
this . remoteParameterOptions . push . apply ( this . remoteParameterOptions , options ) ;
} catch ( error ) {
this . remoteParameterOptionsLoadingIssues = error . message ;
}
this . remoteParameterOptionsLoading = false ;
} ,
2019-09-04 09:22:06 -07:00
closeCodeEditDialog ( ) {
this . codeEditDialogVisible = false ;
} ,
2019-06-23 03:35:23 -07:00
closeExpressionEditDialog ( ) {
this . expressionEditDialogVisible = false ;
} ,
closeTextEditDialog ( ) {
this . textEditDialogVisible = false ;
} ,
2019-09-04 09:22:06 -07:00
displayEditDialog ( ) {
if ( this . isEditor ) {
this . codeEditDialogVisible = true ;
} else {
this . textEditDialogVisible = true ;
}
} ,
2019-06-23 03:35:23 -07:00
getArgument ( argumentName : string ) : string | number | boolean | undefined {
if ( this . parameter . typeOptions === undefined ) {
return undefined ;
}
if ( this . parameter . typeOptions [ argumentName ] === undefined ) {
return undefined ;
}
return this . parameter . typeOptions [ argumentName ] ;
} ,
expressionUpdated ( value : string ) {
this . valueChanged ( value ) ;
} ,
2021-08-29 04:36:17 -07:00
openExpressionEdit ( ) {
if ( this . isValueExpression ) {
this . expressionEditDialogVisible = true ;
2021-09-11 01:15:36 -07:00
return ;
2021-08-29 04:36:17 -07:00
}
} ,
2021-09-11 01:15:36 -07:00
onBlur ( ) {
this . $emit ( 'blur' ) ;
} ,
2019-06-23 03:35:23 -07:00
setFocus ( ) {
if ( this . isValueExpression ) {
this . expressionEditDialogVisible = true ;
return ;
}
2019-11-03 13:06:03 -08:00
if ( [ 'json' , 'string' ] . includes ( this . parameter . type ) && this . getArgument ( 'alwaysOpenEditWindow' ) ) {
2019-09-04 09:22:06 -07:00
this . displayEditDialog ( ) ;
2019-06-23 03:35:23 -07:00
return ;
}
if ( this . node !== null ) {
// When an event like mouse-click removes the active node while
// editing is active it does not know where to save the value to.
// For that reason do we save the node-name here. We could probably
// also just do that once on load but if Vue decides for some reason to
// reuse the input it could have the wrong value so lets set it everytime
// just to be sure
this . nodeName = this . node . name ;
}
// Set focus on field
setTimeout ( ( ) => {
2019-10-15 14:19:20 -07:00
// @ts-ignore
2020-11-09 02:26:46 -08:00
if ( this . $refs . inputField . $el ) {
// @ts-ignore
2021-06-02 18:48:07 -07:00
( this . $refs . inputField . $el . querySelector ( this . getStringInputType === 'textarea' ? 'textarea' : 'input' ) as HTMLInputElement ) . focus ( ) ;
2020-11-09 02:26:46 -08:00
}
2019-06-23 03:35:23 -07:00
} ) ;
} ,
2020-11-09 02:26:46 -08:00
rgbaToHex ( value : string ) : string | null {
// Convert rgba to hex from: https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
const valueMatch = ( value as string ) . match ( /^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)$/ ) ;
if ( valueMatch === null ) {
// TODO: Display something if value is not valid
return null ;
}
const [ r , g , b , a ] = valueMatch . splice ( 1 , 4 ) . map ( v => Number ( v ) ) ;
return "#" + ( ( 1 << 24 ) + ( r << 16 ) + ( g << 8 ) + b ) . toString ( 16 ) . slice ( 1 ) + ( ( 1 << 8 ) + Math . floor ( ( 1 - a ) * 255 ) ) . toString ( 16 ) . slice ( 1 ) ;
} ,
2021-09-11 01:15:36 -07:00
onTextInputChange ( value : string ) {
const parameterData = {
node : this . node !== null ? this . node . name : this . nodeName ,
name : this . path ,
value ,
} ;
this . $emit ( 'textInput' , parameterData ) ;
} ,
2019-06-23 03:35:23 -07:00
valueChanged ( value : string | number | boolean | Date | null ) {
if ( value instanceof Date ) {
value = value . toISOString ( ) ;
}
2020-11-09 02:26:46 -08:00
if ( this . parameter . type === 'color' && this . getArgument ( 'showAlpha' ) === true && value !== null && value . toString ( ) . charAt ( 0 ) !== '#' ) {
const newValue = this . rgbaToHex ( value as string ) ;
if ( newValue !== null ) {
this . tempValue = newValue ;
value = newValue ;
}
}
2019-06-23 03:35:23 -07:00
const parameterData = {
node : this . node !== null ? this . node . name : this . nodeName ,
name : this . path ,
value ,
} ;
this . $emit ( 'valueChanged' , parameterData ) ;
} ,
optionSelected ( command : string ) {
if ( command === 'resetValue' ) {
this . valueChanged ( this . parameter . default ) ;
} else if ( command === 'addExpression' ) {
2021-08-29 04:36:17 -07:00
if ( this . parameter . type === 'number' || this . parameter . type === 'boolean' ) {
this . valueChanged ( ` ={{ ${ this . value } }} ` ) ;
}
else {
this . valueChanged ( ` = ${ this . value } ` ) ;
}
2019-06-23 03:35:23 -07:00
this . expressionEditDialogVisible = true ;
} else if ( command === 'removeExpression' ) {
2021-08-29 04:36:17 -07:00
this . valueChanged ( this . expressionValueComputed !== undefined ? this . expressionValueComputed : null ) ;
2021-07-23 08:52:25 -07:00
} else if ( command === 'refreshOptions' ) {
2021-08-29 04:36:17 -07:00
this . loadRemoteParameterOptions ( ) ;
2019-06-23 03:35:23 -07:00
}
} ,
} ,
mounted ( ) {
this . tempValue = this . displayValue as string ;
if ( this . node !== null ) {
this . nodeName = this . node . name ;
}
2020-11-09 02:26:46 -08:00
if ( this . parameter . type === 'color' && this . getArgument ( 'showAlpha' ) === true && this . displayValue !== null && this . displayValue . toString ( ) . charAt ( 0 ) !== '#' ) {
const newValue = this . rgbaToHex ( this . displayValue as string ) ;
if ( newValue !== null ) {
this . tempValue = newValue ;
}
}
2019-06-23 03:35:23 -07:00
if ( this . remoteMethod !== undefined && this . node !== null ) {
// Make sure to load the parameter options
// directly and whenever the credentials change
this . $watch ( ( ) => this . node ! . credentials , ( ) => {
this . loadRemoteParameterOptions ( ) ;
} , { deep : true , immediate : true } ) ;
2019-10-20 11:55:49 -07:00
// Reload function on change element from
// displayOptions.typeOptions.reloadOnChange parameters
if ( this . parameter . typeOptions && this . parameter . typeOptions . reloadOnChange ) {
// Get all paramter in reloadOnChange property
// This reload when parameters in reloadOnChange is updated
const paramtersOnChange : string [ ] = this . parameter . typeOptions . reloadOnChange ;
for ( let i = 0 ; i < paramtersOnChange . length ; i ++ ) {
const parameter = paramtersOnChange [ i ] as string ;
if ( parameter in this . node . parameters ) {
this . $watch ( ( ) => {
if ( this . node && this . node . parameters && this . node . parameters [ parameter ] ) {
return this . node . parameters ! [ parameter ] ;
} else {
return null ;
}
} , ( ) => {
this . loadRemoteParameterOptions ( ) ;
} , { deep : true , immediate : true } ) ;
}
}
}
2019-06-23 03:35:23 -07:00
}
2021-08-13 03:01:12 -07:00
this . $externalHooks ( ) . run ( 'parameterInput.mount' , { parameter : this . parameter , inputFieldRef : this . $refs [ 'inputField' ] } ) ;
2019-06-23 03:35:23 -07:00
} ,
} ) ;
< / script >
< style scoped lang = "scss" >
2021-08-29 04:36:17 -07:00
. switch - input {
margin : 5 px 0 ;
}
. parameter - value - container {
display : flex ;
align - items : center ;
}
. parameter - actions {
display : inline - flex ;
align - items : center ;
}
2019-06-23 03:35:23 -07:00
. parameter - input {
display : inline - block ;
}
. parameter - options {
width : 25 px ;
text - align : right ;
float : right ;
}
. parameter - issues {
width : 20 px ;
text - align : right ;
float : right ;
color : # ff8080 ;
font - size : 1.2 em ;
}
2021-08-29 04:36:17 -07:00
: : v - deep . color - input {
display : flex ;
2019-06-23 03:35:23 -07:00
2021-08-29 04:36:17 -07:00
. el - color - picker _ _trigger {
border : none ;
2019-06-23 03:35:23 -07:00
}
}
< / style >
< style lang = "scss" >
. ql - editor {
padding : 6 px ;
line - height : 26 px ;
2021-08-29 04:36:17 -07:00
background - color : # f0f0f0 ;
2019-06-23 03:35:23 -07:00
}
. expression {
2021-08-29 04:36:17 -07:00
textarea [ disabled ] , input [ disabled ] {
cursor : pointer ! important ;
2019-06-23 03:35:23 -07:00
}
. el - switch _ _core {
border : 1 px dashed $ -- custom - expression - text ;
}
2021-08-29 04:36:17 -07:00
-- input - border - color : # { $ -- custom - expression - text } ;
-- input - border - style : dashed ;
-- input - background - color : # { $ -- custom - expression - background } ;
-- disabled - border : # { $ -- custom - expression - text } ;
2019-06-23 03:35:23 -07:00
}
. has - issues {
2021-08-29 04:36:17 -07:00
-- input - border - color : var ( -- color - danger ) ;
2019-06-23 03:35:23 -07:00
}
. el - dropdown {
color : # 999 ;
}
2021-08-29 04:36:17 -07:00
. list - option {
max - width : 340 px ;
margin : 6 px 0 ;
2019-06-23 03:35:23 -07:00
white - space : normal ;
2021-08-29 04:36:17 -07:00
. option - headline {
font - weight : var ( -- font - weight - bold ) ;
line - height : var ( -- font - line - height - regular ) ;
overflow - wrap : break - word ;
}
. option - description {
margin - top : 2 px ;
font - size : var ( -- font - size - 2 xs ) ;
font - weight : var ( -- font - weight - regular ) ;
line - height : var ( -- font - line - height - xloose ) ;
color : $ -- custom - font - very - light ;
}
2019-06-23 03:35:23 -07:00
}
. edit - window - button {
display : none ;
}
. parameter - input : hover . edit - window - button {
display : inline ;
}
2021-08-29 04:36:17 -07:00
. expand - input - icon - container {
display : flex ;
height : 100 % ;
align - items : center ;
}
2021-09-11 01:15:36 -07:00
. errors {
margin - top : var ( -- spacing - 2 xs ) ;
color : var ( -- color - danger ) ;
font - size : var ( -- font - size - 2 xs ) ;
font - weight : var ( -- font - weight - regular ) ;
a {
color : var ( -- color - danger ) ;
text - decoration : underline ;
}
}
2019-06-23 03:35:23 -07:00
< / style >