Background
jQuery provides many handy functions to speed up the development, for example
document.ready()
, element.toggle()
, element.hide()
, etc.
My math editor used some of them. However, I replaced them with
Vanilla JavaScript at commit 4a35c45b
.
Goal
Some users complained about the white background in the past versions of my editor. That had motivated me to refactor the code, so that it would be easier to maintain and to add in new features.
HTML5 input types used
Actual appearance might vary across browsers.
<input type="color" id="bgcolor" value="#424549">
for selecting color.<input type="range" min="9" max="24" value="20" class="slider" id="fontSize">
for sliders.
JavaScript skills used
Replace $("{cssSelector}")
with document.querySelector("{cssSelector}")
.
Replace getter and setters .text()
, .value()
and .html()
with
.innerText
, .value
and .innerHTML
respectively.
Replace jQuery event functions like elt.click()
with event listeners
elt.addEventListener("click", (event) => {...})
.
Replce jQuery’s elt.css("css-prop", val)
with elt.style.cssProp = val
. The
cssProp
in camelCase doesn’t has to be quoted, like elt.style.width = "80%"
.
Document loaded
We add a listener to the document (or other target tag) for DOMContentLoaded
event with a(n anonymous) handler, which is a function
.
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(preview, myKaTeXOptions);
});
Button click detection
Instead of jQuery’s button.click(handler)
, we listen to the click
event.
/* print button */
const prBtn = .querySelector("#prBtn");
prBtn.addEventListener("click", (event) => {
window.print();
return false;
});
Get input from input fields and selection lists
To access the element on the left of .addEventListener
, use event.target
.
Here’s one example usage in my script. The folloiwng HTML code gives a
<select>
ion list. The default <option>
has selected value
.
<select id="fontList" name="font-family">
<option value="Arial">Arial</option>
<option selected value="Times New Roman">Times New Roman</option>
<option value="Courier New">Courier New</option>
<!-- other fonts omitted -->
</select>
The same query selector [attr="val"]
also works for CSS.
/* font */
const ffList = document.querySelector('select[name="font-family"]');
ffList.addEventListener("input", (event) => {
previewTag.style.fontFamily = event.target.value;
});
For changing colors, I have to change the CSS property color
for
document.body
, input text area srcTag
and font selection list ffList
separately. I’ve replaced repeated .css('color', fs)
with a forEach
loop.
/* foreground color */
const fgColorBtn = document.querySelector('#fgcolor');
fgColorBtn.addEventListener("input", (event) => {
[document.body, srcTag, ffList].forEach(tag => {
tag.style.color = event.target.value;
});
});
Text area input detection
Vicky Chijwani has provided the following code block for text area input detection in his answer on text area input event.
var area = container.querySelector('textarea');
if (area.addEventListener) {
area.addEventListener('input', function() {
// event handling code for sane browsers
}, false);
} else if (area.attachEvent) {
area.attachEvent('onpropertychange', function() {
// IE-specific event handling code
});
}
Some claimed that pasting won’t trigger the input
event. That’s not what I
have observed from W3 Schools oninput
demo.
I’ve loaded the source and target tags as const
ants, and used a custom
function taHandler
to handle the input.
const srcTag = document.querySelector("#userInput");
const previewTag = document.querySelector("#preview");
// detect textarea event
if (srcTag.addEventListener) {
srcTag.addEventListener("input", taHandler, false);
} else if (srcTag.attachEvent) {
srcTag.attachEvent("onpropertychange", taHandler);
}
let oldVal = srcTag.value;
function taHandler(event) {
let currentVal = .target.value;
if (currentVal === oldVal) return;
oldVal = currentVal;
previewTag.innerHTML = converter.makeHtml(currentVal);
}
The converter
comes from Showdown. Since it’s also a const
ant, it should be
declared at the top.
Async clipboard API
Thanks to Dean Taylor’s “async + fallback” Javascript clipboard
solution, I’ve wrapped the origninal anonymous handler inside
cpFallBack()
because document.execCommand("copy")
is deprecated.
/* copy button */
const cpBtn = document.querySelector("#cpBtn");
cpBtn.addEventListener("click", (event) => {
copyTextToClipboard(srcTag.value);
});
function cpFallBack(){
try {
srcTag.select();
document.execCommand("copy");
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
}
}
function copyTextToClipboard(text) {
if (!navigator.clipboard) {
cpFallBack();
return;
}
navigator.clipboard.writeText(text).then(() => {}, () => {});
}
The .then(success, fail)
method accepts two functions success
and fail
.