I have to restrict user from deleting such words that are in a particular HTML tag (consider I have a custom tag) in a textarea.
<div>
You can Delete Me
<t>
DontDeleteMe
</t>
</div>
The words which are not in a t tag can be deleted.
I tried few logics nothing helps.
Is there any possibilities to get the selection range of ctrl+del keywords do?
case 46:
{ //DEL
if (range.startOffset == startNode.getLength()) {
var ancestor = endNode.$;
while (ancestor != null) {
var next = ancestor.nextSibling;
if (next != null) {
console.log("Next = " + next);
var node = new CKEDITOR.dom.node(next);
cancelEvent = node.isReadOnly();
break;
}
ancestor = ancestor.parentNode;
}
}
break;
}
Unfortunately, your description is quite poor when it comes to describing exactly what you need with examples so nobody really knows what you want to happen to the text.
Here's my Fiddle I just made.
It notes selected text and the ID of the first highlighted text container.
Select the text and press CTRL + Del.
If you use a text area, you can just let the user delete it but then copy it inside again. But why use a text area if the user shouldnt interfere with it? Did i misunderstand the feature you want?
$(document).on('keydown', function(evt) {
if (evt.ctrlKey && evt.keyCode == 46) { // Ctrl + Del key pressed
if (evt.target.id == 'customTextArea') { // Custom tag selected
$('#customTextArea').text('Don't delete me!'); // Copy old text in text area
}
}
});
Related
Using Selectize.js in an Angular 9 application for selecting multiple values. Please see links to my UI at the end
https://selectize.github.io/selectize.js/
https://github.com/selectize/selectize.js
I'm trying enable the user to edit the already selected values by simply clicking on the selected item. Selectize has the concept of Plugins by which "features can be added to Selectize without modifying the main library." I'm making use of this concept to override onMouseDown event, where I'm attempting to make the clicked item editable. I have successfully used this method to override onKeyDown to implement editing of the last selected value by clicking on backspace. Please see code pasted at the bottom. this.onKeyDown = (function() {...
https://github.com/selectize/selectize.js/blob/master/docs/plugins.md
The already selected items are shown as a layer of div elements over the underlying input. To make a selected item editable, I'm removing the selected element div from the DOM, populating the underlying input element with the text from the div. That way that particular item becomes a input from a div and is editable.
There are a few issues im running into:
Its not possible to determine the caret position from the div that was clicked. I am able to get the div text and pre-populate the input element but not put the caret at the right place in input. By default the caret shows at the end and the user can move it around.
Corer cases around when a name is already being edited and the user clicks on another item to edit. The selectize library is giving api to insert selections only at the end of the already selected items. For me to keep deleting the div's and populating the input to mimic the editing effect I need to be able to insert at different positions but the library doesnt seem to have the capability for it.
Trying to see if anyone has worked on something similar or has any suggestions. Thanks in advance!
var Selectize = require('./selectize-standalone');
(function () {
Selectize.define('break_on_backspace_custom_plugin', function(options) {
var self = this;
options.text = options.text || function(option) {
return option[this.settings.labelField];
};
this.onMouseDown = (function() {
var original = self.onMouseDown;
return function(e) {
var index, option;
if (!this.$control_input.val().length && this.$activeItems.length > 0) {
index = this.caretPos - 1;
var toBeEdited = this.$activeItems[0];
var toBeEditedText = toBeEdited.textContent;
var text = toBeEditedText.substring(0, toBeEditedText.length - 1);
var prevEdit = localStorage.getItem("currentEdit");
if (index >= 0 && index < this.items.length) {
if (this.deleteSelection(e)) {
localStorage.setItem("currentEdit", text);
this.setTextboxValue(text);
this.refreshOptions(true);
if (prevEdit && prevEdit !== text) {
this.addItem(prevEdit);
}
}
//e.preventDefault();
//return;
}
}
//e.preventDefault();
return original.apply(this, arguments);
};
})();
this.onKeyDown = (function() {
var original = self.onKeyDown;
return function(e) {
var index, option;
if (e.keyCode === 8 && this.$control_input.val() === '' && !this.$activeItems.length) {
index = this.caretPos - 1;
if (index >= 0 && index < this.items.length) {
option = this.options[this.items[index]];
if (this.deleteSelection(e)) {
//option.value = option.value.substring(0, option.value.length - 1);
this.setTextboxValue(options.text.apply(this, [option]));
this.refreshOptions(true);
}
e.preventDefault();
return;
}
}
return original.apply(this, arguments);
};
})();
});
return Selectize;
})();
Pictures of UI and work in progress
Editing last element by clicking backspace
https://i.stack.imgur.com/wULcT.png
Editing middle element by clicking on it
https://i.stack.imgur.com/U5hxd.png
The jquery highlight that I have created works well, but for some reason when I type something in the input field and hit the next button it doesn't highlight the terms. It only displays "1 of 0 mathches". I'm not sure why it won't highlight it.
Below is my script:
<script>
$("[data-search=next]").click(function() {
if (variableCounter < totalCount) variableCounter = variableCounter + 1;
else variableCounter = 1;
$(".kwt-count").html(variableCounter + " of " + totalCount + " Matches");
});
</script>
Also when the term is in the field and I hit the enter key it highlights the verbiage, but when I hit the delete key it unmarks the content, but the full string is removed along with the highlight. I want it to remove "all" highlights on delete or backspace key, but not remove the full string from the input field. Not sure why its removing everything in the input field.
<script>
$input.keydown("input", function(e) {
if (e.keyCode === 46 || e.keyCode === 8) {
$content.unmark();
$input.val(" ").focus();
}
});
</script>
I have created a codepen of my code here: https://codepen.io/dude12go8/pen/PoYbdXd
I previously had a requirement to always prepend (to put at the beginning) some static text to whatever was entered in a text input field, and to never allow that static text to be deleted. I found a solution that works really well.
Not my requirement has changed, and I need to append (to put at the end) some static text, to whatever is entered in a text box. I'd like the static text to be displayed in the text box at all times, and for any text entered to be placed before the static text. Ideally, the cursor would automatically be placed at "position zero" in the text input whenever a user clicks on the input, or tabs into it.
Here's a Fiddle that shows first the working example of the text being prepended, and then the non-working example of the appending:
https://jsfiddle.net/dsdavis/x9d36veu/25/
When one starts typing in the second example, you'll see that only the last character typed is displaying at the beginning of the box.
A slight difference between how I implemented them that is worth pointing out, is that in the working example, I use the "indexOf":
$(document).ready(function() {
$('#prepend').keyup(function(e) {
if (this.value.length < 16) {
this.value = 'Student Worker - ';
} else if (this.value.indexOf('Student Worker - ') !== 0) {
this.value = 'Student Worker - ' + String.fromCharCode(e.which);
}
});
});
and in the non-working example, I use "lastIndexOf":
$(document).ready(function() {
$('#append').keyup(function(e) {
if (this.value.length < 17) {
this.value = ' - Student Worker';
} else if (this.value.lastIndexOf(' - Student Worker') !== 17) {
this.value = String.fromCharCode(e.which) + ' - Student Worker';
}
});
});
Maybe using "lastIndexOf" is totally wrong, but it seemed like the right way to go.
Can anyone help me come up with a way to do this? To always display the static text " - Student Worker" in the text box, and to put any text that is entered before that static text?
Thank you!
Doug
another approach entirely:
$(document).ready(function() {
$('#append').on("input", function(e) {
var s = this.value.replace(" - Student Worker", "");
this.value = s + " - Student Worker";
});
});
The idea is this -
There is a contenteditable element with some text in it. Am trying to build out a tagging mechanism (kind of like twitter's people tagging when you type '#'). Whenever a user types '#', it shows up a popover with suggestions and filters when they continue typing. Until here it's easy and I have got it figured out. The problem comes when I need to show the popover if/only if the caret is over the element containing the tag.
<div contenteditable="">
<p>Some random text before
<a href="javascript:;"
class="name-suggest"
style="color:inherit !important;text-decoration:inherit !important">#samadams</a>
Some random text after</p>
</div>
Now, whenever the user moves the caret over the a tag / clicks on it, I want to trigger an event that shows the popover, and remove it whenever the caret leaves the a tag. (kind of like focus / blur but they don't seem to work). onmousedown works but there is no way to tell if the cursor has been moved into the anchor tag with the keyboard.
Also, am doing this in angularjs, so, any solution targeted towards that would be preferable but not necessary.
Have been trying to get this to work for a day and any help is greatly appreciated.
This will let you know when your caret position is in an anchor node containing an #
$('#content').on('mouseup keydown keyup', function (event) {
var sel = getSelection();
if (sel.type === "Caret") {
var anchorNodeVal = sel.anchorNode.nodeValue;
if ( anchorNodeVal.indexOf('#') >= 0) {
$('#pop').show()
} else {
$('#pop').hide()
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content" contenteditable="">
<p>Some random text before
<a href="javascript:;"
class="name-suggest"
style="color:inherit !important;text-decoration:inherit !important">#samadams</a>
Some random text after</p>
</div>
<div id="pop" style="display:none">Twitter node found</div>
You could add some regex to further validate the selection.
There is a weird move with RegExps and offset calculation in the code below, but let me explain why it's a better solution.
I've been building a complicated editor using contenteditable about a year ago. It wasn't just a disaster. It was a fucking disaster. There is no cover-all-the-cases spec. Browsers behave differently in every possible detail and it changes frequently. Put a caret before # char and you will get this is Gecko:
<a href="#">|#name
And this in WebKit:
|<a href="#">#name
Well, unless <a> is paragraph's first child. Then result would be the same as in Gecko. Try to put caret after the nickname and both will tell it's inside the link. Start typing, and caret will pop out the element - a year ago Gecko wasn't doing it.
I've used native Selection & Range APIs in this example, they are IE9+. You may want to use Rangy instead.
$el = $('#content');
var showTip = function (nickname) {
// ...
console.log('Show: ' + nickname);
};
var dismissTip = function () {
// ...
console.log('Hide');
};
// I'm sure there is a better RegExp for this :)
var nicknameRegexp = /(^|\b|\s)\#(\w+)(\s|\b|$)/g;
var trackSelection = function () {
var selection = window.getSelection(),
range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
if (range == null || $el[0].contains(range.commonAncestorContainer) == false) {
return dismissTip();
}
var comparer = range.cloneRange();
comparer.setStart($el[0], 0);
var offset = comparer.toString().length;
var match, from, to;
while (match = nicknameRegexp.exec($el[0].textContent)) {
from = match.index + match[1].length;
to = match.index + match[1].length + match[2].length + 1;
if (offset >= from && offset <= to) {
// Force rewind, otherwise next time result might be incorrect
nicknameRegexp.lastIndex = 0;
return showTip(match[2]);
}
}
return dismissTip();
};
$el.on({
// `mousedown` can happen outside #content
'mousedown': function (e) {
$(document).one('mouseup', function (e) {
// Calling function without a tiny delay will lead to a wrong selection info
setTimeout(trackSelection, 5);
});
},
'keyup': trackSelection
});
Just looked at Fire event when caret enters span element which led me here, pretending your case was quite similar except finding if current word is specifically beginning with # for the modal to show...
The thing you need is a way to get the word we're on at the moment we move or type, then check the first character and hide/show the modal pane accordingly will be pretty easy.
function getSelectedWord(grab=document.getSelection()) {
var i = grab.focusOffset, node = grab.focusNode, // find cursor
text = node.data || node.innerText, // get focus-node text
a = text.substr(0, i), p = text.substr(i); // split on caret
return a.split(/\s/).pop() + p.split(/\s/)[0]} // cut-out at spaces
Now you can listen for keydown or selectionchange events and show your pane knowning what have already been written of the current/selected word.
editor.addEventListener('keydown', ev => {
if (ev.key.substr(0, 5) != 'Arrow') // react when we move caret or
if (ev.key != '#') return; // react when we type an '#' or quit
var word = getSelectedWord(); // <-- checking value
if (word[0] == '#') showModal(word.substr(1)); // pass without '#'
});
Note that social networks and code completion usually stops at caret position while I did check for word tail... You can go usual by removing p off of getSelectedWord function definition if desired.
Hope this still helps; Happy coding ! ;)
How can get the selected text from a textbox/textarea if I don't know which one active (focused). I am trying to create a small bookmarklet that will correct the selected text in any type of input on a page.
For the selection, you want selectionStart and selectionEnd.
As for the currently focused element, use document.activeElement.
So as a combination you can use: http://jsfiddle.net/rBPte/1/.
As Tim Down pointed out, you'd need a more complex solution for Internet Explorer version 8 or lower: Caret position in textarea, in characters from the start
function getText(elem) { // only allow input[type=text]/textarea
if(elem.tagName === "TEXTAREA" ||
(elem.tagName === "INPUT" && elem.type === "text")) {
return elem.value.substring(elem.selectionStart,
elem.selectionEnd);
// or return the return value of Tim Down's selection code here
}
return null;
}
setInterval(function() {
var txt = getText(document.activeElement);
document.getElementById('div').innerHTML =
txt === null ? 'no input selected' : txt;
}, 100);