Keep cursor pos when editing a div which has contenteditable - javascript

I am making a text editor which is formatted, not based on buttons. I have the following JS:
function titleFocus() {
$(".title").css("border", "1px solid #666666");
}
function titleBlur() {
$(".title").css("border", "none");
}
$(document).ready(function() {
$('.input').bind('input propertychange', function() {
var inputString = $(".input").html();
var newInputString= inputString.replace(/:strong:(.*?):strong:/g, ':strong:<strong class="written">$1</strong>:strong:');
var newInputString= newInputString.replace(/:b:(.*?):b:/g, ':b:<strong class="written">$1</strong>:b:');
var newInputString= newInputString.replace(/:italic:(.*?):italic:/g, ':italic:<strong class="written">$1</strong>:italic:');
var newInputString= newInputString.replace(/:i:(.*?):i:/g, ':i:<strong class="written">$1</strong>:i:');
if (newInputString !== inputString) {
console.log (newInputString);
$(".input").html(newInputString);
}
});
});
The thing is, after I have done a formatting que (:strong: or italic) then every time I type a character the cursor goes to the start. It also does this after you initially write a formatting que. How can I prevent this? Also, is there a more efficient way of achieving what I'm doing? I feal that having a chunk of JS run every time someone types a character will cause lag.
EDIT: Apparently, this code causes formatted things to duplicate.
E.G::strong:<strong class="written"><strong class="written">TEXT</strong></strong>:strong:

Related

Does html textarea support cyclic display of text?

What I am trying to get is a text field of a fixed size (with a height of exactly one row) where you can type some text. If the text is short enough to fit in the text field it should just be displayed. But if the text is too long it should be displayed in a cycle, e.g. it constantly moves across the field and starts over. Like a continues sideways scroll of an infinite cyclic string, like you may have seen on news television. This should happen immediately after the user stops typing.
My question:
Is it possible to achieve this with just using html-textarea/css/js?
Maybe there is a way to smoothly scroll sideways through the typed text and seemlessly jump back to the beginning?
I can create a html textarea with all of properties that I need (like hidden scrollbar, fixed size, only horizontal scrolling) but I do not know how to make the text move in the above described way.
I am not limited to using the bulit-in textarea from html so if you have any other implementation ideas that can be done in html/css/js - they are welcomed.
Thank you!
No there isn't something native for that. This is a hacky solution. First detecting the overflow, but it's possible to hack it. For simplicity I'll assume length of string. Then when it "overflows" I shall rotate the string. It's important to reset when keydown again.
All in all, Maybe a more robust solution would be to rotate on blur and stop on focus.
var input = document.querySelector("input");
var int_id;
function debounce(func, timeout = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, timeout);
};
}
function is_overflow(input) {
// for now:
return input.value.length >= 14
}
input.addEventListener('keydown', function() {
stop(input)
})
function stop(input) {
if (int_id) {
clearInterval(int_id)
input.value = input.getAttribute("data-value") || input.value
int_id = null;
}
}
input.addEventListener('input', debounce(function(ev) {
if (is_overflow(input)) {
input.setAttribute("data-value", input.value);
int_id = setInterval(function() {
rotate(input)
}, 100);
} else {
stop(input)
}
}))
function rotate(input) {
var str = input.value
var num = 1;
input.value = str.substr(num) + str.substr(0, num);
}
<input style="width:100px">

javascript slider change call function sequence

Following are some code for explaining
$("#upperBound").on('input',function(){
console.log("1");
loadAndViewImagethresholding(imageId);
console.log("4");
});
function loadAndViewImagethresholding(imageId) {
_("thresholdingdicomImage").style.opacity = "0.3";
var elementthresh = $('#thresholdingdicomImage').get(0);
cornerstone.enable(elementthresh);
var imageIdpro="wadouri:"+"http://localhost:8888/dicomread/temp/"+loadfileName;
cornerstone.loadImage(imageId).then(function(image) {
cornerstone.loadImage(imageIdpro).then(function(imagepro) {
upper=_("upperBound").value;
lower=_("lowerBound").value;
for (var i = 0;i<image.getPixelData().length;i++) {
if(imagepro.getPixelData()[i]<lower||imagepro.getPixelData()[i]>upper)
{
imagepro.getPixelData()[i]=image.minPixelValue;
// console.log("imageproCopyaftercompare:"+imagepro.getPixelData()[436512]);
}
else{imagepro.getPixelData()[i]=image.maxPixelValue;
//console.log("imageproCopyaftercompare:"+imagepro.getPixelData()[436512]);
}
}
console.log("imageproCopyaftercompare:"+imagepro.getPixelData()[436512]);
var viewportthresh = cornerstone.getDefaultViewportForImage(elementthresh, imagepro);
console.log("2");
cornerstone.displayImage(elementthresh, imagepro);
});
});
}
So the basic idea is to use slideupperBound to change upper (lower) value to threshold image, but it seems nothing changed after I change slider. I make a console.log for 436512th pixel, It seems after give slider input that imagepro(which is a raw data array) has been changed, but next displayImage is not implemented.
Then I make a console.log("1 to 4") to see how that slider event implement, the result is 1,4,2,3 rather than 1,2,3,4 as I expect.
So my question is how does this slider implement? Will it implements 1,4 first then calling the function(loadAndViewImagethresholding(imageId);) inside?
If possible, give me some idea to fix that problem, any help appreciated.
BTW, cornerstone is the js I used.

Get pasted text DataTransferItem size

I have a panel that accepts text paste events, this is how it works for Chrome, after some simplifications:
var event = e.browserEvent;
if (event.clipboardData) {
if (event.clipboardData.items) {
var item = event.clipboardData.items[0]
item.getAsString(function (e) {
if (e) {
me.showText(e);
}
});
}
}
}
The problem is that if I'll try to paste some large amount of text, like 100MB, the browser will freeze on item.getAsString(). So I want to add some size limit, but I couldn't find the way to do it, since item (typeof = DataTransferItem) seems to doesn't have anything like 'size', and the callback for item.getAsString() is never called. Could you please suggest a way to do it?

display message javascript while a calculation is being made

I have been looking around and I cannot seem to figure out how to do this, although it seems like it would be very simple.(mobile development)
What I am trying to do is display a message (kind of like an alert, but not an alert, more like a dialog) while a calculation is being made. Simply like a Loading please wait. I want the message to appear and stay there while the calculation is being done and then be removed. I just cannot seem to find a proper way of doing this.
The submit button is pressed and first checks to make sure all the forms are filled out then it should show the message, it does the calculation, then hides the message.
Here is the Calculation function.
function scpdResults(form) {
//call all of the "choice" functions here
//otherwise, when the page is refreshed, the pulldown might not match the variable
//this shouldn't be a problem, but this is the defensive way to code it
choiceVoltage(form);
choiceMotorRatingVal(form);
getMotorRatingType();
getProduct();
getConnection();
getDisconnect();
getDisclaimer();
getMotorType();
//restore these fields to their default values every time submit is clicked
//this puts the results table into a known state
//it is also used in error checking in the populateResults function
document.getElementById('results').innerHTML = "Results:";
document.getElementById('fuse_cb_sel').innerHTML = "Fuse/CB 1:";
document.getElementById('fuse_cb_sel_2').innerHTML = "Fuse/CB 2:";
document.getElementById('fuse_cb_result').innerHTML = "(result1)";
document.getElementById('fuse_cb_res_2').innerHTML = "(result2)";
document.getElementById('sccr_2').innerHTML = "<b>Fault Rating:</b>";
document.getElementById('sccr_result').innerHTML = "(result)";
document.getElementById('sccr_result_2').innerHTML = "(result)";
document.getElementById('contactor_result').innerHTML = "(result)";
document.getElementById('controller_result').innerHTML = "(result)";
//Make sure something has been selected for each variable
if (product === "Choose an Option." || product === "") {
alert("You must select a value for every field. Select a Value for Product");
**************BLAH************
} else {
//valid entries, so jump to results table
document.location.href = '#results_a';
******This is where the message should start being displayed***********
document.getElementById('motor_result').innerHTML = motorRatingVal + " " + motorRatingType;
document.getElementById('voltage_res_2').innerHTML = voltage + " V";
document.getElementById('product_res_2').innerHTML = product;
document.getElementById('connection_res_2').innerHTML = connection;
document.getElementById('disconnect_res_2').innerHTML = disconnect;
if (BLAH) {
}
else {
}
populateResults();
document.getElementById('CalculatedResults').style.display = "block";
} //end massive else statement that ensures all fields have values
*****Close out of the Loading message********
} //scpd results
Thank you all for your time, it is greatly appreciated
It is a good idea to separate your display code from the calculation code. It should roughly look like this
displayDialog();
makeCalculation();
closeDialog();
If you are having trouble with any of those steps, please add it to your question.
Computers are fast. Really fast. Most modern computers can do several billion instructions per second. Therefore, I'm fairly certain you can rely on a a setTimeout function to fire around 1000ms to be sufficient to show a loading message.
if (product === "Choose an Option." || product === "") {
/* ... */
} else {
/* ... */
var loader = document.getElementById('loader');
loader.style.display = 'block';
window.setTimeout(function() {
loader.style.display = 'none';
document.getElementById('CalculatedResults').style.display = "block";
}, 1000);
}
<div id="loader" style="display: none;">Please wait while we calculate.</div>
You need to give the UI main thread a chance to render your message before starting your calculation.
This is often done like this:
showMessage();
setTimeout(function() {
doCalculation();
cleanUp()
}, 0);
Using the timer allows the code to fall through into the event loop, update the UI, and then start up the calculation.
You're already using a section to pop up a "results" page -- why not pop up a "calculating" page?
Really, there are 4,000,000 different ways of tackling this problem, but why not try writing a "displayCalculatingMessage" function and a "removeCalculatingMessage" function, if you don't want to get all object-oriented on such a simple thing.
function displayCalculatingMessage () {
var submit_button = getSubmitButton();
submit_button.disabled = true;
// optionally get all inputs and disable those, as well
// now, you can either do something like pop up another hidden div,
// that has the loading message in it...
// or you could do something like:
var loading_span = document.createElement("span");
loading_span.id = "loading-message";
loading_span.innerText = "working...";
submit_button.parentElement.replaceChild(loading_span, submit_button);
}
function removeCalculatingMessage () {
var submit_button = getSubmitButton(),
loading_span = document.getElementById("loading-message");
submit_button.disabled = false;
loading_span.parentElement.replaceChild(submit_button, loading_span);
// and then reenable any other disabled elements, et cetera.
// then bring up your results div...
// ...or bring up your results div and do this after
}
There are a billion ways of accomplishing this, it all comes down to how you want it to appear to the user -- WHAT you want to have happen.

javascript (jquery) script perfomance synchronous vs asynchronous

I have a javascript function that filter dom elements based on a input text changes, so:
$(".input").keyup(function(e) {
filter();
});
var cache = $(".dom");
var filter = function() {
cache.each(function() {
// if field contains some text show else hide
}
};
My problem happens when there are many dom elements to filter, the whole pages gets inaccessible because of the synchronous processing (like the example above). Im trying to come out with a solution that dont locks the entire page with synchronous processing.
The problem is NOT related to the filter logic (it's completely trivial), it's NOT related to the jquery or javascript itslef, it's related to the synchronous processing and the quantity of dom elements.
As JavaScript is single threaded, the only real way to sort this out is to split the long-running job into a series of shorter jobs, and use setTimeout() with a short time delay at the end of each section to kick off the next one. This gives your UI and other JavaScript events a chance to update.
You can update large set of dom nodes by placing them in a queue and process only a few elements on each setTimeout "tick". In pseudo-code:
on(event):
queue = DOM nodes to be updated
setTimeout(update)
update:
queue.slice(0, limit).each(...update a node...)
queue = queue.slice(limit) // remove processed nodes
if (queue.length > 0) setTimeout(update) // repeat...
See http://jsfiddle.net/Etsmm/2/ for a complete working example.
Upd: The first version had problems with Chrome (related to its' "display" bug), adding a fix as per this answer appears to have done the trick.
Or doing it elsewhere through an ajax request if's really too long ?
And, maybe, some kind of: first step, select all IDs to be hidden in an array, then, settimeout, then in a second step, hiding them like 50 per 50 ?
Also, maybe processing that having the container of all those elements himself hidden, and then, once done, reshowing it may be faster ?
For this kind of purposes I generally prefer Ben Alman's message queuing library. It has also different alternatives. This one is quite successful on throttling.
https://github.com/cowboy/jquery-message-queuing/
Here below a throttling sample
http://benalman.com/code/projects/jquery-message-queuing/examples/throttling/
thank you all for your help. I came up with a solution based on Ben Clayton response, but Im still looking for ideas and investigating the thg435 solution. Any comments will be apreciated.
<script type="text/javascript">
$(document).ready(function () {
var cache = $(".whatever");
var wait = 0;
var input = $("#input");
var regex = null;
input.keyup(function (e) {
go.index = 0;
clearTimeout(wait);
wait = setTimeout(go.start, 500);
});
var filter = function (i) {
var one = cache.eq(i - 1);
one.text().match(regex) ? one.show() : one.hide();
go.index++;
setTimeout(go.filter, 10);
};
go = {
index: 0,
filter: function () {
go.index == 0 || go.index > cache.length ? null : filter(go.index);
},
start: function () {
go.index = 1;
var search = input.val();
search = search.replace(new RegExp("[a]", "gi"), "[aàáâã]");
search = search.replace(new RegExp("[e]", "gi"), "[eéê]");
search = search.replace(new RegExp("[i]", "gi"), "[ií]");
search = search.replace(new RegExp("[o]", "gi"), "[oóô]");
search = search.replace(new RegExp("[u]", "gi"), "[uú]");
search = search.replace(new RegExp("[c]", "gi"), "[cç]");
regex = new RegExp(search, "gi");
go.filter();
}
}
});
</script>
<input type="text" id="input" />
<span class="whatever">lalala</span>
<span class="whatever">leléLÉ</span>
<span class="whatever">lololo</span>
<span class="whatever">lululu</span>

Categories