1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Allow typedInputs to have options plus value

This commit is contained in:
Nick O'Leary 2018-06-21 10:46:07 +01:00
parent a467fe5ed7
commit 461e6562ca
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
2 changed files with 179 additions and 72 deletions

View File

@ -98,14 +98,17 @@
var that = this;
this.disarmClick = false;
this.input = $('<input type="text"></input>');
this.input.insertAfter(this.element);
this.input.val(this.element.val());
this.element.addClass('red-ui-typedInput');
this.uiWidth = this.element.outerWidth();
this.elementDiv = this.element.wrap("<div>").parent().addClass('red-ui-typedInput-input');
this.elementDiv = this.input.wrap("<div>").parent().addClass('red-ui-typedInput-input');
this.uiSelect = this.elementDiv.wrap( "<div>" ).parent();
var attrStyle = this.element.attr('style');
var m;
if ((m = /width\s*:\s*(calc\s*\(.*\)|\d+(%|px))/i.exec(attrStyle)) !== null) {
this.element.css('width','100%');
this.input.css('width','100%');
this.uiSelect.width(m[1]);
this.uiWidth = null;
} else {
@ -114,17 +117,19 @@
["Right","Left"].forEach(function(d) {
var m = that.element.css("margin"+d);
that.uiSelect.css("margin"+d,m);
that.element.css("margin"+d,0);
that.input.css("margin"+d,0);
});
this.uiSelect.addClass("red-ui-typedInput-container");
this.element.attr('type','hidden');
this.options.types = this.options.types||Object.keys(allOptions);
this.selectTrigger = $('<button tabindex="0"></button>').prependTo(this.uiSelect);
if (this.options.types.length > 1) {
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
}
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
$('<i class="red-ui-typedInput-icon fa fa-sort-desc"></i>').toggle(this.options.types.length > 1).appendTo(this.selectTrigger);
this.selectLabel = $('<span class="red-ui-typedInput-type-label"></span>').appendTo(this.selectTrigger);
this.types(this.options.types);
@ -138,14 +143,16 @@
this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect);
}
this.element.on('focus', function() {
this.input.on('focus', function() {
that.uiSelect.addClass('red-ui-typedInput-focus');
});
this.element.on('blur', function() {
this.input.on('blur', function() {
that.uiSelect.removeClass('red-ui-typedInput-focus');
});
this.element.on('change', function() {
this.input.on('change', function() {
that.validate();
that.element.val(that.value());
that.element.trigger('change',that.propertyType,that.value());
})
this.selectTrigger.click(function(event) {
event.preventDefault();
@ -161,7 +168,7 @@
})
// explicitly set optionSelectTrigger display to inline-block otherwise jQ sets it to 'inline'
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectTrigger = $('<button tabindex="0" class="red-ui-typedInput-option-trigger" style="display:inline-block"><span class="red-ui-typedInput-option-caret"><i class="red-ui-typedInput-icon fa fa-sort-desc"></i></span></button>').appendTo(this.uiSelect);
this.optionSelectLabel = $('<span class="red-ui-typedInput-option-label"></span>').prependTo(this.optionSelectTrigger);
this.optionSelectTrigger.click(function(event) {
event.preventDefault();
@ -177,9 +184,7 @@
that.uiSelect.addClass('red-ui-typedInput-focus');
});
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect);
this.optionExpandButton = $('<button tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block"><i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i></button>').appendTo(this.uiSelect);
this.type(this.options.default||this.typeList[0].value);
},
_showTypeMenu: function() {
@ -187,7 +192,7 @@
this._showMenu(this.menu,this.selectTrigger);
this.menu.find("[value='"+this.propertyType+"']").focus();
} else {
this.element.focus();
this.input.focus();
}
},
_showOptionSelectMenu: function() {
@ -196,8 +201,8 @@
minWidth:this.optionSelectLabel.width()
});
this._showMenu(this.optionMenu,this.optionSelectLabel);
var selectedOption = this.optionMenu.find("[value='"+this.value()+"']");
this._showMenu(this.optionMenu,this.optionSelectTrigger);
var selectedOption = this.optionMenu.find("[value='"+this.optionValue+"']");
if (selectedOption.length === 0) {
selectedOption = this.optionMenu.children(":first");
}
@ -209,7 +214,7 @@
$(document).off("mousedown.close-property-select");
menu.hide();
if (this.elementDiv.is(":visible")) {
this.element.focus();
this.input.focus();
} else if (this.optionSelectTrigger.is(":visible")){
this.optionSelectTrigger.focus();
} else {
@ -228,10 +233,19 @@
op.text(opt.label);
}
if (opt.icon) {
$('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op);
if (opt.icon.indexOf("<") === 0) {
$(opt.icon).prependTo(op);
} else if (opt.icon.indexOf("/") !== -1) {
$('<img>',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op);
} else {
$('<i>',{class:"red-ui-typedInput-icon "+opt.icon}).prependTo(op);
}
} else {
op.css({paddingLeft: "18px"});
}
if (!opt.icon && !opt.label) {
op.text(opt.value);
}
op.click(function(event) {
event.preventDefault();
@ -310,7 +324,8 @@
if (this.uiWidth !== null) {
this.uiSelect.width(this.uiWidth);
}
if (this.typeMap[this.propertyType] && this.typeMap[this.propertyType].hasValue === false) {
var type = this.typeMap[this.propertyType];
if (type && type.hasValue === false) {
this.selectTrigger.addClass("red-ui-typedInput-full-width");
} else {
this.selectTrigger.removeClass("red-ui-typedInput-full-width");
@ -320,12 +335,64 @@
this.elementDiv.css('right',"22px");
} else {
this.elementDiv.css('right','0');
this.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
// if (this.optionSelectTrigger) {
// this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
// }
if (this.optionSelectTrigger) {
this.optionSelectTrigger.css({'left':(labelWidth)+"px",'width':'calc( 100% - '+labelWidth+'px )'});
if (type && type.options && type.hasValue === true) {
this.optionSelectLabel.css({'left':'auto'})
var lw = this._getLabelWidth(this.optionSelectLabel);
this.optionSelectTrigger.css({'width':(23+lw)+"px"});
this.elementDiv.css('right',(23+lw)+"px");
this.input.css({
'border-top-right-radius': 0,
'border-bottom-right-radius': 0
});
} else {
this.optionSelectLabel.css({'left':'0'})
this.optionSelectTrigger.css({'width':'calc( 100% - '+labelWidth+'px )'});
if (!this.optionExpandButton.is(":visible")) {
this.elementDiv.css({'right':0});
this.input.css({
'border-top-right-radius': '4px',
'border-bottom-right-radius': '4px'
});
}
}
}
}
},
_updateOptionSelectLabel: function(o) {
var opt = this.typeMap[this.propertyType];
this.optionSelectLabel.empty();
if (o.icon) {
if (o.icon.indexOf("<") === 0) {
$(o.icon).prependTo(this.optionSelectLabel);
} else if (o.icon.indexOf("/") !== -1) {
// url
$('<img>',{src:o.icon,style:"height: 18px;"}).prependTo(this.optionSelectLabel);
} else {
// icon class
$('<i>',{class:"red-ui-typedInput-icon "+o.icon}).prependTo(this.optionSelectLabel);
}
} else if (o.label) {
this.optionSelectLabel.text(o.label);
} else {
this.optionSelectLabel.text(o.value);
}
if (opt.hasValue) {
this.optionValue = o.value;
this._resize();
this.input.trigger('change',this.propertyType,this.value());
}
},
_destroy: function() {
this.menu.remove();
},
@ -344,6 +411,7 @@
return result;
});
this.selectTrigger.toggleClass("disabled", this.typeList.length === 1);
this.selectTrigger.find(".fa-sort-desc").toggle(this.typeList.length > 1)
if (this.menu) {
this.menu.remove();
}
@ -351,6 +419,7 @@
if (currentType && !this.typeMap.hasOwnProperty(currentType)) {
this.type(this.typeList[0].value);
}
setTimeout(function() {that._resize();},0);
},
width: function(desiredWidth) {
this.uiWidth = desiredWidth;
@ -358,33 +427,33 @@
},
value: function(value) {
if (!arguments.length) {
return this.element.val();
var v = this.input.val();
if (this.typeMap[this.propertyType].export) {
v = this.typeMap[this.propertyType].export(v,this.optionValue)
}
return v;
} else {
var selectedOption;
if (this.typeMap[this.propertyType].options) {
var validValue = false;
var label;
for (var i=0;i<this.typeMap[this.propertyType].options.length;i++) {
var op = this.typeMap[this.propertyType].options[i];
if (typeof op === "string") {
if (op === value) {
label = value;
validValue = true;
selectedOption = this.activeOptions[op];
break;
}
} else if (op.value === value) {
label = op.label||op.value;
validValue = true;
selectedOption = op;
break;
}
}
if (!validValue) {
value = "";
label = "";
if (!selectedOption) {
selectedOption = {value:""}
}
this.optionSelectLabel.text(label);
this._updateOptionSelectLabel(selectedOption)
}
this.element.val(value);
this.element.trigger('change',this.type(),value);
this.input.val(value);
this.input.trigger('change',this.type(),value);
}
},
type: function(type) {
@ -412,37 +481,72 @@
}
if (this.optionSelectTrigger) {
this.optionSelectTrigger.show();
this.elementDiv.hide();
if (!opt.hasValue) {
this.elementDiv.hide();
} else {
this.elementDiv.show();
}
this.activeOptions = {};
opt.options.forEach(function(o) {
if (typeof o === 'string') {
that.activeOptions[o] = {label:o,value:o};
} else {
that.activeOptions[o.value] = o;
}
})
this.optionMenu = this._createMenu(opt.options,function(v){
that.optionSelectLabel.text(v);
that.value(v);
that._updateOptionSelectLabel(that.activeOptions[v]);
if (!opt.hasValue) {
that.value(that.activeOptions[v].value)
}
});
var currentVal = this.element.val();
var validValue = false;
var op;
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
if (typeof op === "string") {
if (op === currentVal) {
this.optionSelectLabel.text(currentVal);
if (!opt.hasValue) {
var currentVal = this.input.val();
var validValue = false;
for (var i=0;i<opt.options.length;i++) {
op = opt.options[i];
if (typeof op === "string" && op === currentVal) {
that._updateOptionSelectLabel({value:currentVal});
validValue = true;
break;
} else if (op.value === currentVal) {
that._updateOptionSelectLabel(op);
validValue = true;
break;
}
} else if (op.value === currentVal) {
this.optionSelectLabel.text(op.label||op.value);
validValue = true;
break;
}
}
if (!validValue) {
op = opt.options[0];
if (typeof op === "string") {
this.value(op);
if (!validValue) {
op = opt.options[0];
if (typeof op === "string") {
this.value(op);
that._updateOptionSelectLabel({value:op});
} else {
this.value(op.value);
that._updateOptionSelectLabel(op);
}
}
} else {
var selectedOption = this.optionValue||opt.options[0];
if (opt.parse) {
var parts = opt.parse(this.input.val());
if (parts.option) {
selectedOption = parts.option;
}
this.input.val(parts.value);
if (opt.export) {
this.element.val(opt.export(parts.value,parts.option||selectedOption));
}
}
if (typeof selectedOption === "string") {
this.optionValue = selectedOption;
this._updateOptionSelectLabel(this.activeOptions[selectedOption]);
} else {
this.value(op.value);
this.optionValue = selectedOption.value;
this._updateOptionSelectLabel(selectedOption);
}
}
console.log(validValue);
}
} else {
if (this.optionMenu) {
@ -453,12 +557,12 @@
this.optionSelectTrigger.hide();
}
if (opt.hasValue === false) {
this.oldValue = this.element.val();
this.element.val("");
this.oldValue = this.input.val();
this.input.val("");
this.elementDiv.hide();
} else {
if (this.oldValue !== undefined) {
this.element.val(this.oldValue);
this.input.val(this.oldValue);
delete this.oldValue;
}
this.elementDiv.show();
@ -473,7 +577,7 @@
} else {
this.optionExpandButton.hide();
}
this.element.trigger('change',this.propertyType,this.value());
this.input.trigger('change',this.propertyType,this.value());
}
if (image) {
image.onload = function() { that._resize(); }

View File

@ -23,7 +23,7 @@
margin: 0;
vertical-align: middle;
box-sizing: border-box;
overflow:hidden;
overflow:visible;
position: relative;
.red-ui-typedInput-input {
position: absolute;
@ -43,6 +43,7 @@
border-bottom-left-radius: 0;
box-shadow: none;
vertical-align: middle;
// backgroun/d: #f0fff0;
}
&.red-ui-typedInput-focus:not(.input-error) {
@ -63,7 +64,7 @@
line-height: 32px;
vertical-align: middle;
color: #555;
i {
i.red-ui-typedInput-icon {
position: relative;
top: -3px;
margin-left: 1px;
@ -76,11 +77,11 @@
}
&.disabled {
cursor: default;
i {
i.red-ui-typedInput-icon {
color: #bbb;
}
}
span {
.red-ui-typedInput-type-label,.red-ui-typedInput-option-label {
display: inline-block;
height: 100%;
padding: 0 1px 0 5px;
@ -121,26 +122,25 @@
border-bottom-right-radius: 4px;
padding: 0 0 0 0;
position:absolute;
width: calc( 100% );
i {
position:absolute;
right: 4px;
top: 7px;
}
right: 0;
.red-ui-typedInput-option-label {
background:#fff;
background:$typedInput-button-background;
position:absolute;
left:0;
right:23px;
top: 0;
padding: 0 5px 0 5px;
padding: 0 5px 0 8px;
i.red-ui-typedInput-icon {
margin-right: 4px;
margin-top: 4px;
}
}
.red-ui-typedInput-option-caret {
top: 0;
position: absolute;
right: 0;
width: 17px;
padding-left: 6px;
}
&:focus {
box-shadow: none;
@ -175,4 +175,7 @@
background: $typedInput-button-background-active;
}
}
.red-ui-typedInput-icon {
margin-right: 4px;
}
}