Emulate SO tag editor - javascript

I'm trying to implement a 'Tag Editor' field in my app, the same way as SO does.
Right now i got this:
EDIT: I have coded this into a jQuery plugin at:
https://github.com/fernandotenorio/tagme.git
Fiddle
http://jsfiddle.net/FernandoTen/PnYuF/
html
<div style="margin-left: auto; margin-right: auto; width: 400px;">
<span style='color: #333; font-size: small'>
Tags [a-z A-Z 0-9 # + . -]
</span>
<div id='tags_container'>
<span id='tags_queue'></span>
<input type='text' id='tf' />
</div>
</div>
js
$(document).ready(function () {
var rexp = /[^a-zA-Z0-9#+\.\-]/
var left = 37;
var right = 39;
var del = 8;
var space = 32;
var comma = 188;
var minlen = 3;
var maxlen = 15;
var current_tag = null
$('#tf').focus().attr('maxlength', maxlen)
$('#tags_container').click(function () {
$('#tf').focus()
})
$('#tf').keydown(function (e) {
var code = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
var txt = $(this).val().trim()
// handle navigation between tags
if ((code === left || code === right) && txt.length === 0) {
if (!current_tag)
{
if (code === left)
current_tag = $('#tags_queue span').last()
else
current_tag = $('#tags_queue span').first()
if (current_tag.length > 0) current_tag.css('background-color', '#9FC2D6')
} else //current tag exists
{
if (code === left)
current_tag = current_tag.css('background-color', '#B8D0DE').prev()
else
current_tag = current_tag.css('background-color', '#B8D0DE').next()
if (current_tag.length > 0)
current_tag.css('background-color', '#9FC2D6')
// hit last/first, clean current_tag
else
{
current_tag.css('background-color', '#B8D0DE')
current_tag = null
}
}
}
});
$('#tf').keypress(function (e) {
var token = String.fromCharCode(e.which)
var code = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
if (token.match(rexp) && (code !== del) && (code !== left) && (code !== right))
return false;
});
$('#tf').keyup(function (e) {
var code = e.keyCode ? e.keyCode : e.which ? e.which : e.charCode;
var txt = $(this).val().trim()
if (code === del && txt.length === 0 && current_tag) {
current_tag.remove()
current_tag = null
return
}
// clean current_tag, user is typing
if (current_tag && (code !== left) && (code != right))
{
current_tag.css('background-color', '#B8D0DE')
current_tag = null
}
if (txt.length > maxlen) txt = txt.substring(0, maxlen)
if (txt.match(rexp)) {-
$(this).val("")
return
} else if (code === space || code === comma) {
if (txt.length < minlen) return;
var tag = $('<span></span>', {
'class': 'tag'
}).html(txt).append($('<a></a>', {
'class': 'close_tag',
html: '&times',
click: function () {
$(this).parent().fadeOut(function(){
$(this).remove()
current_tag.css('background-color', '#B8D0DE')
current_tag = null
})
}
}))
$('#tags_queue').append(tag)
$(this).val("")
}
});
})
css
div#tags_container {
border: 1px solid #ccc;
padding-bottom: 5px;
border-radius: 5px;
background-color: beige;
overflow: hidden;
}
input#tf {
border: 1px solid orange !important;
outline: none !important;
background-color: transparent !important;
height: 30px;
margin-top: 2px;
padding-left: 5px;
}
a.close_tag {
margin-left: 5px;
color: #fff;
}
a.close_tag:hover {
cursor: pointer;
}
span.tag {
background-color: #B8D0DE;
color: #111;
margin-left: 5px;
margin-top: 5px;
padding: 5px;
float: left;
border-radius: 5px;
}
span.tag:hover {
background-color: #9FC2D6;
}
span#tags_queue {
margin-right: 5px;
vertical-align: middle;
}
The problem is, how can i handle the 'hidden' content using the arrows keys, the way SO does? It looks like i have to handle the cursor position inside the text-fields, and watch for arrow-left and arrow-right events...and there's also the click on the completed tags.
I can think of the following (anti-SO design) solutions:
remove white-space: nowrap from the tags_container div, and let
the div 'grow' as the user add more tags.
Add overflow: scroll to the tags_container div (very ugly!)
So, i appreciate any new ideas on how to approximate the SO tag-editor behaviour.
Thanks!

Reinvent the wheel is a bad practice : take a look at the excellent Tag-it jQuery plugin code, it implements the stuff you are working on.

Related

How to check whether inputs are words, space and newLine?

let msgInpt = document.getElementById("message");
msgInpt.addEventListener("keydown", function(entEvt){
if (!msgInpt.innerText === ' ') {
if (entEvt.code === 'Enter' && !entEvt.shiftKey) {
entEvt.preventDefault();
postChat();
}
} else {
if (entEvt.code === 'Enter' && !entEvt.shiftKey) {
entEvt.preventDefault();
return false;
} else if(entEvt.code === 'Enter' && entEvt.shiftKey) {
entEvt.preventDefault();
return false;
} else if (entEvt.code === 'Space') {
entEvt.preventDefault();
return false;
}
}
});
div{
background-color: #f2f2f4;
padding: 12px;
height: 150px;
border: 2px solid #333;
border-radius: 10px;
box-shadow: 0px 0px 12px 4px rgba(0,0,0,0.18);
}
<div contenteditable="true" id="message"></div>
After that I tried this
msgInpt.addEventListener("keydown", function(entEvt){
if (msgInpt.innerText) {
if (entEvt.code === 'Enter' && !entEvt.shiftKey) {
entEvt.preventDefault();
if (!msgInpt.innerText === ' ') {
postChat();
}
}
} else {
if (entEvt.code === 'Enter' && !entEvt.shiftKey) {
entEvt.preventDefault();
return false;
} else if(entEvt.code === 'Enter' && entEvt.shiftKey) {
entEvt.preventDefault();
return false;
} else if (entEvt.code === 'Space') {
entEvt.preventDefault();
return false;
}
}
});
I want to validate whether the user is giving input as word only.
When user First gives input of or \n only, then user must not be able to send messages.
Why Both the codes are not working?
Please can anybody tell me what is the logic behind this
You can always use Regular Expression for this kind of query. It helps you to overcome the space and newline input problem easily.
Refer this article for using RegEx in javascript.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

Why isn't my restart button working? (Tic tac toe game)

So I want to make a tic tac toe game with html and script javascript, and my reset button doesn't seem to work, everything else seems to be working well, can anyone tell me what's wrong here?
I've tried moving the restart() function into the body, right after the button, and anywhere else I think possible, and changed the codes in the restart function to almost everything I think works and could be possible, but when I click the button nothing happens
<!DOCTYPE html>
<html>
<head>
<title>Tictactoe Game</title>
<style type="text/css">
[v-cloak] {
display: none;
}
td {
background: #DDD;
width: 50px;
height: 50px;
}
.piece-o {
margin: auto;
width: 30px;
height: 30px;
border: 3px solid #ff8080;
border-radius: 50%;
}
.piece-x {
margin: auto;
width: 30px;
height: 30px;
background: linear-gradient(45deg, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 43%,#0099ff 45%,#0099ff 55%,rgba(0,0,0,0) 57%,rgba(0,0,0,0) 100%), linear-gradient(135deg, rgba(0,0,0,0) 0%,rgba(0,0,0,0) 43%,#0099ff 45%,#0099ff 55%,rgba(0,0,0,0) 57%,rgba(0,0,0,0) 100%);
}
</style>
<script type="text/javascript">
function restart() {
for (i = 0; i <= 2; i++){
for (j = 0; j <= 2; j++){
this.game[i][j] = ' '
}
}
}
</script>
</head>
<body>
<div id="app" v-cloak>
<p>Current Player: <i :class="turn == 'O' ? 'far fa-circle' : 'fas fa-times'"></i></p>
<table>
<tr v-for="(row, rowKey, index) in game" :key="rowKey">
<td v-for="(col, colKey, index) in row" :key="colKey" #click="click(rowKey, colKey)">
<div v-if="col" :class="'piece-'+col.toLowerCase()"></div>
</td>
</tr>
</table>
</div>
<input type="button" onclick=restart() value="Restart">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
turn: 'O',
game: [
['', '', ''],
['', '', ''],
['', '', '']
]
},
methods: {
click(row, col) {
if (this.game[row][col] != '') {
alert('Please select empty slot.')
return
}
this.game[row].splice(col, 1, this.turn);
this.calcResult()
},
calcResult() {
var game = this.game
var turn = this.turn
// Victory Condition
if ((this.game[0][0] == this.game[0][1] && this.game[0][0] == this.game[0][2] && this.game[0][0] != '')
|| (this.game[1][0] == this.game[1][1] && this.game[1][0] == this.game[1][2] && this.game[1][0] != '')
|| (this.game[2][0] == this.game[2][1] && this.game[2][0] == this.game[2][2] && this.game[2][0] != '')
|| (this.game[0][0] == this.game[1][0] && this.game[0][0] == this.game[2][0] && this.game[0][0] != '')
|| (this.game[0][1] == this.game[1][1] && this.game[0][1] == this.game[2][1] && this.game[0][1] != '')
|| (this.game[0][2] == this.game[1][2] && this.game[0][2] == this.game[2][2] && this.game[0][2] != '')
|| (this.game[0][0] == this.game[1][1] && this.game[0][0] == this.game[2][2] && this.game[0][0] != '')
|| (this.game[0][2] == this.game[1][1] && this.game[0][2] == this.game[2][0] && this.game[0][2] != '')
) {
alert('Player ' + this.turn + ' is the winner!');
return;
}
// Draw condition
if (this.game[0][0] != '' && this.game[0][1] && this.game[0][2] && this.game[1][0] && this.game[1][1]
&& this.game[1][2] && this.game[2][0] && this.game[2][1] && this.game[2][2]) {
alert('Draw!');
return;
}
// Next player turn
this.turn = this.turn == 'O' ? 'X' : 'O'
}
}
})
</script>
</body>
</html>
You can change code like this.
<div id="app" v-cloak>
...
</table>
<input type="button" #click="restart()" value="Restart">
</div>
And add restart function to Vue methods because you have to use "game" data of Vue.
...
},
restart() {
for (i = 0; i <= 2; i++){
for (j = 0; j <= 2; j++){
this.game[i][j] = ''
}
}
turn = 'O';
alert("Restart");
}
I imagine it's because your restart() function is outside of the scope of your Vue application. I'm not familiar with Vue, but you probably need to have restart() be a function within app.methods, and call it just like you're calling the other Vue methods. Which also means you'd probably have to have your restart button within the <div id="app" v-cloak> element. You've placed it outside of the parent Vue element at the moment.

Restrict Users to type only numers in an input field with type=number

I was building a website and came across a problem.
The problem is, when users are asked to enter a price, they can type not only numbers but whatever they want. I want to restrict users to type numbers only in that input field. I've tried type=number and pattern="[0-9]+" attributes and gave it a style of appearence: textfield (Because it shows an uparrow and a downarrow when shown in browser) but it doesn't seem to work. I suppose there is a solution for this with javascript.
HTML :
<input class="input-price" type="number">
CSS:
input[type="number"] {
appearance: textfield;
}
input[type="number"] {
appearance: textfield;
}
<input class="input-price" type="number">
Hopefully, someone will give me a solution. Thanks in advance!
type="number" is only available to HTML5 compliant browsers. There is an answer available in an overflow already, for getting the result you are after using Javascript here.
I don't know what browser your users use that can bypass restrictions in the numerical input, but in the days when not all browsers supported type="number" I've used something like this:
const inputs = document.querySelectorAll('input[data-type="number"]');
for(let i = 0; i < inputs.length; i++)
{
inputs[i].addEventListener("input", onInput);
inputs[i].addEventListener("keydown", onKeydown);
inputs[i].nextSibling.addEventListener("mousedown", onMousedown);
inputs[i].nextSibling.addEventListener("mouseup", onMouseup);
}
function onInput(e)
{
clearTimeout(this._timer);
const input = e.target,
min = input.min === "" ? null : Number(input.min),
max = input.max === "" ? null : Number(input.max),
canMinus = min === null || min < 0,
canPoint = input.hasAttribute("nopoint") ? false : true;
let curStart = input.selectionStart,
dot = 0,
minus = 0,
i = 0,
timeout = null,
val = input.value;
val = val.replace(/[^0-9]/g, (char, pos) =>
{
if ( (char == "-" && canMinus && !(pos-i) && --minus)
|| ((char == "." || char == ",") && canPoint && pos && (pos-i > 1 || !minus) && !dot++))
{
return char;
}
if (i < curStart)
curStart--;
i++;
return "";
});
if (curStart < 0)
curStart = 0;
const isNumber = val.match(/[0-9]/);
if (isNumber && min !== null && val < min)
val = timeout = min;
if (isNumber && max !== null && val > max)
val = timeout = max;
const exec = () =>
{
input.value = val
input.selectionStart = curStart;
input.selectionEnd = curStart;
}
if (timeout === null)
return exec();
this._timer = setTimeout(exec, 1000);
}
function onKeydown(e)
{
const input = e.target,
min = input.min === "" ? null : Number(input.min),
max = input.max === "" ? null : Number(input.max),
step = input.step === "" ? 1 : Number(input.step),
keys = {ArrowUp: step, ArrowDown: -step};
if (keys[e.key])
{
let val = (keys[e.key] == ~~keys[e.key] ? ~~input.value : Number(input.value)) + keys[e.key];
if (min !== null && val < min)
val = min;
if (max !== null && val > max)
val = max;
input.value = val;
return e.preventDefault();
}
}
function onMousedown(e)
{
if (e.target.parentNode.previousSibling.tagName != "INPUT")
return;
const that = this,
obj = {
target: e.target.parentNode.previousSibling,
key: (e.target.previousSibling === null) ? "ArrowUp" : "ArrowDown",
preventDefault: ()=>{}
};
let time = 300;
!function loop()
{
onKeydown(obj);
that._timer = setTimeout(loop, time);
time = 30;
}();
}
function onMouseup(e)
{
clearTimeout(this._timer);
}
input[data-type="number"] {
appearance: textfield;
padding-right: 1.2em;
}
input[data-type="number"]:not(:focus):not(:hover) ~ span:not(:focus):not(:hover)
{
visibility: hidden;
}
input[data-type="number"] ~ span
{
float:right;
position: relative;
right: 1.8em;
top: 0.2em;
height: 1.8em;
width: 1.5em;
line-height: 1em;
font-size: 0.6em;
cursor: default;
display: grid;
background-color: #F1F1F1;
user-select: none;
}
input[data-type="number"] ~ span > span:nth-child(1):before,
input[data-type="number"] ~ span > span:nth-child(2):before
{
transform: scaleY(0.6);
display: block;
}
input[data-type="number"] ~ span > span:nth-child(1):before
{
content: "▲";
}
input[data-type="number"] ~ span > span:nth-child(2):before
{
content: "▼";
}
input[data-type="number"] ~ span > span:nth-child(1),
input[data-type="number"] ~ span > span:nth-child(2)
{
color: #505050;
width: 100%;
text-align: center;
}
input[data-type="number"] ~ span > span:nth-child(1):hover,
input[data-type="number"] ~ span > span:nth-child(2):hover
{
background-color: #D2D2D2;
}
input[data-type="number"] ~ span > span:nth-child(1):active,
input[data-type="number"] ~ span > span:nth-child(2):active
{
color: white;
background-color: #787878;
}
input[data-type="number"] ~ span > span:nth-child(1)
{
top: 0;
}
input[data-type="number"] ~ span > span:nth-child(2)
{
bottom: 0;
}
<table>
<tr>
<td>Native type="number"</td>
<td><input class="input-price" type="number"></td>
</tr>
<tr>
<td>Any number</td>
<td><input class="input-price" data-type="number"><span><span></span><span></span></span></td>
</tr>
<tr>
<td>Min 11 / max 123</td>
<td><input class="input-price" data-type="number" min="11" max="123"><span><span></span><span></span></span></td>
</tr>
<tr>
<td>No decimal point</td>
<td><input class="input-price" data-type="number" nopoint=""><span><span></span><span></span></span></td>
</tr>
</table>

jQuery simulate one input event to another input

I have two text input id: input1 and input2. I would like to simulate keypress on input1 to input2. I cannot copy values onblur because after simulation I shall change the value of input1. Could you please let me know how to do this in jQuery 1.6 or Javascript? I tried below, but this isn't working and changing the value i.e. $('#'+origid).val() returns blank.
$(".maskedinput").keyup(function (e) {
var value = $.trim($(this).val());
var origid = $(this).attr('origid');
var originalelemevt = jQuery.Event( "keypress" );
originalelemevt.which = e.which;
originalelemevt.keycode = e.keycode;
$('#'+origid).trigger( originalelemevt );
var newval = '';
if(value.length >=4){
var orignal = value.substring(0,value.length-4);
for(var i=0;i<orignal.length;i++)
newval +='*';
newval +=value.substring(orignal.length);
$(this).val(newval);
}
});
$(document).ready(function() {
$("#I1").keyup(function (e) {
var value = $.trim($(this).val());
var newval = '';
if(value.length >=4){
var orignal = value.substring(0,value.length-4);
for(var i=0;i<orignal.length;i++)
newval +='*';
newval +=value.substring(orignal.length);
$(this).val(newval);
}
$('#I2').val(e.target.value);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<form id='F1'>
<input id='I1'>
<input id='I2'>
</form>
This what I was looking for, keypress event on id1.
$("#id1").keypress(function(e) {
var inputkey = e.which || e.keyCode;
var result = getInputSelection(document.getElementById("id1"));
$("#id2").trigger("keypress")
.val(function(i, val) {
var key = e.which || e.keyCode;
// return this.value + String.fromCharCode(key);
return this.value.substr(0, result.start) + String.fromCharCode(key) + this.value.substr(result.end)
});
});
$("#id1").keyup(function(e) {
mask('id1');
});
$("#id1").keydown(function(e) {
var inputkey = e.which || e.keyCode;
//alert(inputkey);
if (inputkey == 8) {
e.preventDefault();
var new_val = replaceValue(inputkey);
//alert(new_val);
$("#id1").val(new_val);
$("#id2").val(new_val);
// mask('id1');
} else if (inputkey == 46) {
e.preventDefault();
var new_val = replaceValue(inputkey);
//alert(new_val);
$("#id1").val(new_val);
$("#id2").val(new_val);
// mask('id1');
}
});
function mask(elid) {
var $this = $('#' + elid);
$this.val($this.val().replace(/.(?=.{4})/g, '*'));
}
function replaceValue(inputkey) {
var result = getInputSelection(document.getElementById("id1"));
// alert("Backspace "+result.start +","+result.end);
var new_val = $("#id1").val();
if (result.start == result.end) {
if (inputkey == 8) {
new_val = $("#id2").val().substr(0, result.start - 1) + $("#id2").val().substr(result.end);
} else if (inputkey == 46) {
new_val = $("#id2").val().substr(0, result.start) + $("#id2").val().substr(result.end + 1);
}
} else {
new_val = $("#id2").val().substr(0, result.start) + $("#id2").val().substr(result.end);
}
return new_val;
}
function getInputSelection(el) {
var start = 0,
end = 0,
normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner-message {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="banner-message">
SSN:
<input type="text" id="id1" />
<input type="text" id="id2" style="display:none" />
</div>

The deletion of span in the content editable in mobile does not works

There are spans in the content editable div which needs to be deleted all at once. Now this works fine on the chrome desktop but when I try to delete it on the following devices this does not works.I am testing it on following
Chrome on Android
Safari on Mac, iOS
Firefox on Windows
When I try to delete the box looses focus and span does not delete.
This is the fiddle link to what I have tried so far.
var EditableDiv = document.getElementById('EditableDiv');
EditableDiv.onkeydown = function(event) {
var ignoreKey;
var key = event.keyCode || event.charCode;
if (!window.getSelection) return;
var selection = window.getSelection();
var focusNode = selection.focusNode,
anchorNode = selection.anchorNode;
var anchorOffset = selection.anchorOffset;
if (!anchorNode) return
if (anchorNode.nodeName.toLowerCase() != '#text') {
if (anchorOffset < anchorNode.childNodes.length)
anchorNode = anchorNode.childNodes[anchorOffset]
else {
while (!anchorNode.nextSibling) anchorNode = anchorNode.parentNode // this might step out of EditableDiv to "justincase" comment node
anchorNode = anchorNode.nextSibling
}
anchorOffset = 0
}
function backseek() {
while ((anchorOffset == 0) && (anchorNode != EditableDiv)) {
if (anchorNode.previousSibling) {
if (anchorNode.previousSibling.nodeName.toLowerCase() == '#text') {
if (anchorNode.previousSibling.nodeValue.length == 0)
anchorNode.parentNode.removeChild(anchorNode.previousSibling)
else {
anchorNode = anchorNode.previousSibling
anchorOffset = anchorNode.nodeValue.length
}
} else if ((anchorNode.previousSibling.offsetWidth == 0) && (anchorNode.previousSibling.offsetHeight == 0))
anchorNode.parentNode.removeChild(anchorNode.previousSibling)
else {
anchorNode = anchorNode.previousSibling
while ((anchorNode.lastChild) && (anchorNode.nodeName.toUpperCase() != 'SPAN')) {
if ((anchorNode.lastChild.offsetWidth == 0) && (anchorNode.lastChild.offsetHeight == 0))
anchorNode.removeChild(anchorNode.lastChild)
else if (anchorNode.lastChild.nodeName.toLowerCase() != '#text')
anchorNode = anchorNode.lastChild
else if (anchorNode.lastChild.nodeValue.length == 0)
anchorNode.removeChild(anchorNode.lastChild)
else {
anchorNode = anchorNode.lastChild
anchorOffset = anchorNode.nodeValue.length
//break //don't need to break, textnode has no children
}
}
break
}
} else
while (((anchorNode = anchorNode.parentNode) != EditableDiv) && !anchorNode.previousSibling) {}
}
}
if (key == 8) { //backspace
if (!selection.isCollapsed) {
try {
document.createElement("select").size = -1
} catch (e) { //kludge for IE when 2+ SPANs are back-to-back adjacent
if (anchorNode.nodeName.toUpperCase() == 'SPAN') {
backseek()
if (anchorNode.nodeName.toUpperCase() == 'SPAN') {
var k = document.createTextNode(" ") // doesn't work here between two spans. IE makes TWO EMPTY textnodes instead !
anchorNode.parentNode.insertBefore(k, anchorNode) // this works
anchorNode.parentNode.insertBefore(anchorNode, k) // simulate "insertAfter"
}
}
}
} else {
backseek()
if (anchorNode == EditableDiv)
ignoreKey = true
else if (anchorNode.nodeName.toUpperCase() == 'SPAN') {
SelectText(event, anchorNode)
ignoreKey = true
} else if ((anchorNode.nodeName.toLowerCase() == '#text') && (anchorOffset <= 1)) {
var prev, anchorNodeSave = anchorNode,
anchorOffsetSave = anchorOffset
anchorOffset = 0
backseek()
if (anchorNode.nodeName.toUpperCase() == 'SPAN') prev = anchorNode
anchorNode = anchorNodeSave
anchorOffset = anchorOffsetSave
if (prev) {
if (anchorOffset == 0)
SelectEvent(prev)
else {
var r = document.createRange()
selection.removeAllRanges()
if (anchorNode.nodeValue.length > 1) {
r.setStart(anchorNode, 0)
selection.addRange(r)
anchorNode.deleteData(0, 1)
}
else {
for (var i = 0, p = prev.parentNode; true; i++)
if (p.childNodes[i] == prev) break
r.setStart(p, ++i)
selection.addRange(r)
anchorNode.parentNode.removeChild(anchorNode)
}
}
ignoreKey = true
}
}
}
}
if (ignoreKey) {
var evt = event || window.event;
if (evt.stopPropagation) evt.stopPropagation();
evt.preventDefault();
return false;
}
}
function SelectText(event, element) {
var range, selection;
EditableDiv.focus();
if (window.getSelection) {
selection = window.getSelection();
range = document.createRange();
range.selectNode(element)
selection.removeAllRanges();
selection.addRange(range);
} else {
range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
}
var evt = (event) ? event : window.event;
if (evt.stopPropagation) evt.stopPropagation();
if (evt.cancelBubble != null) evt.cancelBubble = true;
return false;
}
#EditableDiv {
height: 75px;
width: 500px;
font-family: Consolas;
font-size: 10pt;
font-weight: normal;
letter-spacing: 1px;
background-color: white;
overflow-y: scroll;
overflow-x: hidden;
border: 1px solid black;
padding: 5px;
}
#EditableDiv span {
color: brown;
font-family: Verdana;
font-size: 8.5pt;
min-width: 10px;
/*_width: 10px;*/
/* what is this? */
}
#EditableDiv p,
#EditableDiv br {
display: inline;
}
<div id="EditableDiv" contenteditable="true">
(<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field1</span> < 500) <span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>OR</span> (<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field2</span> > 100 <span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>AND</span> (<span contenteditable='false' onclick='SelectText(event, this);' unselectable='on'>Field3</span> <= 200) )
</div>
I am using javascript for this.
I am developing a solution for a app using meteor and blaze UI for templates which will run on iOS.
Try to put the css cursor:pointer; on the div that you want to click on and delete.
Sometimes mobile browser, esp. Safari doesnt allow click event on the element unless it has cursor:pointer. It will trigger that this div is link or clickable.

Categories