Vue
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-classapplier.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-highlighter.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-serializer.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-textrange.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-selectionsaverestore.js"></script>
<div id="app">
<div class="input__label-wrap">
<span class="input__label">Cauta</span>
<div style="user-select: none">
<span readonly v-on:click="addBooleanTag(b_button)" v-for="b_button in boolean_buttons" class="boolean-buttons">{{b_button.label}}</span>
</div>
</div>
<div class="input__boolean input__boolean--no-focus">
<div
@keydown.enter.prevent
@blur="addPlaceholder"
@keyup="saveCursorLocation($event); fixDelete(); clearHtmlElem($event);"
@input="updateBooleanInput($event); clearHtmlElem($event);"
@paste="pasted"
v-on:click="clearPlaceholder(); saveCursorLocation($event);"
class="input__boolean-content"
ref="divInput"
contenteditable="true">Cuvinte cheie, cautare booleana..</div>
</div>
</div>
CSS
.filters__toggler
{
cursor: pointer;
padding: 2px;
transition: all 0.2s ease-in-out;
margin-left: 10px;
}
.filters__toggler path
{
fill: #314964;
}
.filters__toggler-collapsed
{
transform: rotate(-180deg);
}
.input__label
{
font-family: $roboto;
font-size: 14px;
color: #314964;
letter-spacing: -0.13px;
text-align: justify;
}
.input__boolean
{
width: 100%;
background: #FFFFFF;
border: 1px solid #AFB0C3;
border-radius: 5px;
padding: 7px 15px 7px;
font-family: $opensans;
font-size: 14px;
color: #082341;
min-height: 40px;
box-sizing: border-box;
margin-top: 15px;
display: flex;
flex-direction: row;
align-items: center;
line-height: 22px;
overflow: hidden;
}
.input__boolean-content
{
width: 100%;
height: 100%;
outline: none;
border: none;
position: relative;
padding: 0px;
word-break: break-word;
}
.input__boolean img
{
cursor: pointer;
margin-bottom: -6px;
}
.input__boolean--no-focus
{
color: #9A9AA6
}
.input__label-wrap
{
display: flex;
justify-content: space-between;
width: 100%;
position: relative;
}
.boolean-buttons
{
background-color: #007AFF;
padding: 3px 15px;
border-radius: 50px;
color: #fff;
font-family: $roboto;
font-size: 14px;
font-weight: 300;
cursor: pointer;
margin-left: 10px;
}
.boolean-button--img
{
height: 22px;
margin-left: 10px;
}
.boolean-button--no-margin
{
margin: 0;
}
.popper
{
background-color: $darkbg;
font-family: $opensans;
font-size: 12px;
line-height: 14px;
color: #fff;
padding: 4px 12px;
border-color: $darkbg;
box-shadow: 0 5px 12px 0 rgba(49,73,100,0.14);
border-radius: 8px;
}
.filters__helper
{
cursor: pointer;
margin-left: 10px;
margin-bottom: -3px;
}
.popper[x-placement^="top"] .popper__arrow
{
border-color: #082341 transparent transparent transparent;
}
Vue
new Vue({
el: "#app",
data(){
return {
filters_toggled: false,
fake_input_content: '',
input_length: 0,
typed: false,
boolean_buttons: [{
type: '1',
label: 'ȘI',
tag: 'ȘI',
img: 'https://i.imgur.com/feHin0S.png'
}, {
type: '2',
label: 'SAU',
tag: 'SAU',
img: 'https://i.imgur.com/vWJeJwb.png'
}, {
type: '3',
label: 'NU',
tag: 'NU',
img: 'https://i.imgur.com/NNg1spZ.png'
}],
saved_sel: 0,
value: null,
options: ['list', 'of', 'options']
}
},
name: 'boolean-input',
methods: {
inputLength($event){
this.input_length = $event.target.innerText.length;
if(this.input_length == 0)
this.typed = false;
},
addPlaceholder(){
if(this.input_length == 0 && this.typed == false){
this.$refs.divInput.innerHTML = 'Cuvinte cheie, cautare booleana..'
}
},
clearPlaceholder(){
if(this.input_length == 0 && this.typed == false){
this.$refs.divInput.innerHTML = '';
}
},
updateBooleanInput($event){
this.typed = true;
this.inputLength($event);
},
saveCursorLocation($event){
/*
if($event.which != 8){
if(this.saved_sel)
rangy.removeMarkers(this.saved_sel)
this.saved_sel = rangy.saveSelection();
}
*/
// if(this.input_length == 0 && this.typed == false){
// var div = this.$refs.divInput;
// var sel = rangy.getSelection();
// sel.collapse(div, 0);
// }
},
insertNode: function(node){
var selection = rangy.getSelection();
var range = selection.getRangeAt(0);
range.insertNode(node);
range.setStartAfter(node);
range.setEndAfter(node);
selection.removeAllRanges();
selection.addRange(range);
},
addBooleanTag($event){
// return this.$refs.ChatInput.insertEmoji($event.img);
if (!this.$refs.divInput.contains(document.activeElement))...