Is there a way to subscribe to changes in window.getSelection? - javascript

We are able to get a selection range via window.getSelection().
I'm wondering whether there is a way to subscribe to window.getSelection changes.
The only way which came to me is to use timeouts (which is obviously bad) or subscribe to each user's key \ mouse press event and track changes manually.
ANSWER UPD: You are able to use this library, I've published it, as there are no more suitable ones: https://github.com/xnimorz/selection-range-enhancer

Use the onselect event.
function logSelection(event) {
const log = document.getElementById('log');
const selection = event.target.value.substring(event.target.selectionStart, event.target.selectionEnd);
log.textContent = `You selected: ${selection}`;
}
const textarea = document.querySelector('textarea');
textarea.onselect = logSelection;
<textarea>Try selecting some text in this element.</textarea>
<p id="log"></p>
For specific cases such as span contenteditable, you can make a polyfill:
function logSelection() {
const log = document.getElementById('log');
const selection = window.getSelection();
log.textContent = `You selected: ${selection}`;
}
const span = document.querySelector('span');
var down = false;
span.onmousedown = () => { down = true };
span.onmouseup = () => { down = false };
span.onmousemove = () => {
if (down == true) {
logSelection();
}
};
<span contenteditable="true">Try selecting some text in this element.</span>
<p id="log"></p>

if Im undesrting in right way you want to know when user start selection on page you can use DOM onselectstart.
document.onselectstart = function() {
console.log("Selection started!");
};
more info MDN

Related

How to mark as selected the default text of multiple textarea on tabindex?

I have few textarea on which I want to get the default text selected when I tabbing upon it.
For a single textarea I've found a script which I adapted to my situation but is not an elegant solution.
How can I shorten it.
<script type="text/javascript">
var textBox1 = document.getElementById("textarea_1");
var textBox2 = document.getElementById("textarea_2");
var textBox3 = document.getElementById("textarea_3");
textBox1.onfocus = function() {
textBox1.select();
// Work around Chrome's little problem
textBox1.onmouseup = function() {
// Prevent further mouseup intervention
textBox1.onmouseup = null;
return false;
};
};
textBox2.onfocus = function() {
textBox2.select();
textBox2.onmouseup = function() {
textBox2.onmouseup = null;
return false;
};
};
textBox3.onfocus = function() {
textBox3.select();
textBox3.onmouseup = function() {
textBox3.onmouseup = null;
return false;
};
};
</script>
You can add a dedicated class name and refactor the code to be more generic using class name as selector an make it work for multiple textareas like this:
// Add the class 'auto-selectable' to the desired <texarea/> elements
var textBoxes = document.getElementByClassName('auto-selectable');
for(var i = 0; i < textBoxes.length; i++) {
var textBox = textBoxes[i];
textBox.select();
// Work around Chrome's little problem
textBox.onmouseup = function() {
// Prevent further mouseup intervention
textBox.onmouseup = null;
return false;
};
}
a small correction to Plamen's answer: Elements not Element
var textBoxes = document.getElementsByClassName('auto-selectable');
instead of:
var textBoxes = document.getElementByClassName('auto-selectable');

.js alert(); when text in span change

I got this Code:
const odleglosc = parseFloat(document.getElementsByClassName("dystans")[0].innerText);
const daleko = "za daleko";
if (odleglosc > 200) {
alert(daleko);
}
<span data-pafe-form-builder-live-preview="lechnarlok" class="dystans" id="dystans">500</span>
It runs fine, because at starting point there is number higher than 200 in it.
But when i change it, alert don't trigger again..
How can i solve that? :(
Im not sure about how the span value will change, so this example works with an input. The same idea could also be applied to a span tho.
<input onchange="theFunction()" data-pafe-form-builder-live-preview="lechnarlok" class="dystans" id="dystans" value="500"></input>
<script>
function theFunction() {
var odleglosc = parseFloat(document.getElementsByClassName("dystans")[0].value);
var daleko = "za daleko";
if (odleglosc > 200)
{
alert(daleko);
}
}
</script>
Here, onChange calls the function whenever the value in the input field changes.
Do You want to show alert after each change of the value? If yes, use event listener for input (not for span).
Update:
Use MutationObserver for this case.
let span = document.getElementById('dystans');
function updateValue(value) {
var daleko = "za daleko";
if (parseFloat(value) > 200)
{
alert(daleko);
}
}
// create a new instance of 'MutationObserver' named 'observer',
// passing it a callback function
observer = new MutationObserver(function(mutationsList, observer) {
let value = mutationsList.filter(x => x.target.id =='dystans')[0].target.innerHTML;
updateValue(value);
});
// call 'observe' on that MutationObserver instance,
// passing it the element to observe, and the options object
observer.observe(span, {characterData: true, childList: true, attributes: true});
span.innerHTML = '3000';
<span data-pafe-form-builder-live-preview="lechnarlok" class="dystans" id="dystans">500</span>
Source:
Detect changes in the DOM
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

Saving and adding back storage value when page is refreshed

I have this to-do list where the to-Do list is saved in local storage, but I do not know how to add the storage value back in the page where it was before when the page is refreshed.
JS:
let inputField = document.querySelector('#inputField');
let submitBtn = document.querySelector('#submit-btn');
let toDoList = document.querySelector('#toDoList');
let toDoItems = document.querySelector('.toDoItems');
submitBtn.addEventListener('click', function(){
event.preventDefault();
let newLi = document.createElement('li');
newLi.className = 'toDoItems';
toDoList.appendChild(newLi);
newLi.textContent = inputField.value;
localStorage.setItem(inputField.value, inputField.value);
inputField.value = "";
});
toDoList.addEventListener('click', function(e){
e.target.remove();
});
What I have accomplished right now
So you have everything saved successfully, so now its just a matter of retrieving on load.
This documentation outlines how to use the window's load event. From there, inside that listener you can retrieve the data and display it using something like this:
for (let i = 0; i < localStorage.length; i++) {
let toDoString = localStorage.key(i)
// Do something similar to submitBtn.addEventListener('click', function(){})
// to create the list item and add it to the page
}
You want to store all the todoes in a single array, rather than as individual values. There are two reasons for this.
First, you can easily get and set the storage by using the same key.
Second, you can easily loop through and add them back, since they are already an array.
The example below won't work with local storage, as it's seen as not safe...
However, you should be able to copy the code and try it yourself.
const inputField = document.querySelector('#inputField');
const submitBtn = document.querySelector('#submitBtn');
const toDoList = document.querySelector('#toDoList');
const todoes = [];
function addTodo(todo) {
event.preventDefault();
let newLi = document.createElement('li');
newLi.className = 'toDoItems';
toDoList.appendChild(newLi);
newLi.textContent = inputField.value;
todoes.push(inputField.value)
//! -- commented out to not cause an error in stackoverflow --
// localStorage.setItem("todoes", JSON.stringify(todoes));
inputField.value = "";
}
submitBtn.addEventListener('click', addTodo);
toDoList.addEventListener('click', function(e) {
e.target.remove();
});
window.addEventListener('load', (event) => {
console.log('page is fully loaded');
//! -- commented out to not cause an error in stackoverflow --
// todoes = JSON.parse(localStorage.getitem("todoes"));
// todoes.forEach(todo => addTodo(todo));
});
<input id="inputField" type="text" placeholder="What to do?" />
<button id="submitBtn">ADD</button>
<ul id="toDoList"></ul>

Copy default value to clipboard

I want to copy a default value to clipboard, without using input. Thats something wrong with my function, but I don't know what it is.
var copyText = "Default value";
const showText = document.querySelector(".copied");
const copyMeOnClipboard = () => {
copyText;
document.execCommand("copy")
showText.innerHTML = `Copied!`
setTimeout(() => {
showText.innerHTML = ""
}, 1000)
}
<button class="submitBtn" onclick="copyMeOnClipboard();">Copy link</button>
<p class="copied"></p>
From MDN's page on execCommand, emphasis added:
Copies the current selection to the clipboard. Conditions of having this behavior enabled vary from one browser to another, and have evolved over time.
You'll want to use the Clipboard API's writeText instead, like so:
var copyText = "Default value";
const showText = document.querySelector(".copied");
const copyMeOnClipboard = () => {
navigator.clipboard.writeText(copyText).then(() => {
showText.innerHTML = `Copied!`
setTimeout(() => {
showText.innerHTML = ""
}, 1000)
})
}
<button class="submitBtn" onclick="copyMeOnClipboard();">Copy</button>
<p class="copied"></p>

Liferay/AlloyUI: Overriding util.js or disabling scrolling on form focus

How can I override (or hook) the function Liferay.Util.focusFormField in Liferay 7.0?
The method is defined in frontend-js-aui-web (portal-src\modules\apps\foundation\frontend-js\frontend-js-aui-web\src\main\resources\META-INF\resources\liferay\util.js).
The only way I could think of is to just overwrite it somewhere in a js-file, like so:
Liferay.Util.focusFormField = function(el) {
var doc = $(document);
var interacting = false;
el = Util.getDOM(el);
el = $(el);
doc.on(
'click.focusFormField',
function (event) {
interacting = true;
doc.off('click.focusFormField');
}
);
if (!interacting && Util.inBrowserView(el)) {
var form = el.closest('form');
var focusable = !el.is(':disabled') && !el.is(':hidden') && !el.parents(':disabled').length;
if (!form.length || focusable) {
el.focus(false); // modified
}
else {
var portletName = form.data('fm-namespace');
Liferay.once(
portletName + 'formReady',
function () {
el.focus(false); // modified
}
);
}
}
}
All I actually want is to disable the scrolling that happens whenever a form is submitted.
Does someone know what to do best to achieve this?
Another thing I found on the web is this: https://alloyui.com/api/files/alloy-ui_src_aui-form-validator_js_aui-form-validator.js.html#l216
But I cannot find it in liferay-7.0-source-files and no explanation how to override it.

Categories