How can I change all text to Americanized spelling using Javascript/jQuery? - javascript

I have two websites, one for the UK and one for the US, both of which use the same text in some places, spelled in the British way - e.g. "I specialise in optimising stuff"
Is there a Javascript/JQuery package/solution to automatically replace all the British spelling that it finds in the DOM, to American spelling? E.g. change the above to "I specialize in optimizing stuff"
So I suppose I could loop through the DOM elements and replace them, eg
$('p').each(function() {
var text = $(this).text();
text = text.replace('ise', 'ize');
$(this).text(text);
});
But this won't work in all cases, e.g. "wise" should not be changed to "wize". Are there any known regex or similar solutions to solve this?

Here is a solution that uses a translation table and some jQuery and native JavaScript to traverse the DOM and to change text, excluding tag attributes. Click on the Switch to USA Spelling button:
const translations = {
colour: 'color',
colours: 'colors',
Colour: 'Color',
Colours: 'Colors',
optimising: 'optimizing',
specialise: 'specialize'
};
const regex = new RegExp('\\b(' + Object.keys(translations).join('|') + ')\\b', 'g');
console.log('regex', regex);
$(document).ready(function() {
$('.switchSpelling button').click(function() {
$('#mainContent *').contents().each(function() {
if(this.nodeType == 3) {
this.nodeValue = this.nodeValue.replace(regex, m => {
return translations[m];
});
}
});
})
});
.switchSpelling {
float: right;
margin-right: 70px;
}
.grayBackgroundColour {
background-color: #f0f0f0;
padding: 3px 10px;
}
.yellowBackgroundColour {
background-color: #fffff0;
padding: 3px 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mainContent">
<div class="switchSpelling">
<button>Switch to USA Spelling</button>
</div>
<h1>The history of Colour</h1>
<div class="grayBackgroundColour">
<h2>Colours in Renaissance</h2>
<p>We specialise in optimising and restoring colours</p>
</div>
<div class="yellowBackgroundColour">
<h2>Colours in Cubism</h2>
<p>We specialise in optimising and restoring colours</p>
</div>
</div>

Related

Dynamically Display Multiple Currency Prices for Different Locales On Same Page

I am trying to display different prices for a single product on a generic /eu/ webpage. The prices are fixed so I am hoping this can be done using a simple query but I am very new to JS/JQuery.
Currently the price is displayed in div with the class price-block
and users can toggle their locale with a data-locale="{country code}" div.
Using these two IDs, can I create a script that says e.g. data-locale="UK" then price is £1000?
I think I need to be looking into "if this selected, var equals this value" solutions - any help much appreciated.
Here's one way of achieving it by using a simple key/val object for locale/price respectively:
$(function() {
var prices = {
"UK": "£1000",
"US": "$1500",
"DE": "€1250"
}
$("[data-locale]").click(function() {
var locale = $(this).attr("data-locale");
// ensure the locale value is valid
if (prices[locale]) {
$(".price-block").text(prices[locale]);
} else {
$(".price-block").text("Invalid locale: " + locale);
}
})
})
[data-locale] {
border: 2px solid;
cursor: pointer;
display: inline-block;
padding: 5px;
}
.price-block {
font-size: 20px;
margin-top: 10px;
}
<div class="locale-block">
<div data-locale="UK">UK</div>
<div data-locale="US">US</div>
<div data-locale="DE">DE</div>
</div>
<div class="price-block"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Limit selectable divs in a parent div

I'd like to create a product feature selection page where the user needs to select 3 features out of 6. Now, I got to a point where I can limit the number of selectable elements so if 3 elements are selected, the user wont be able to select a 4th one.
I need to modify this so when the user is attempting to select the 4th element, the 1st element they selected becomes unselected and the 4th element becomes selected. I hope it makes sense.
$('div').click(function(e) {
var $et = $(e.target);
if ($et.hasClass('fill')) {
$et.removeClass('fill');
} else {
if ($('.fill').length < 2) {
$et.addClass('fill');
}
}
});
div {
border: 1px solid blue;
height: 25px;
margin-bottom: 5px;
}
.fill {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<div id="1">one</div>
<div id="2">two</div>
<div id="3">three</div>
<div id="4">four</div>
This fiddle shows where I'm at with my code: http://jsfiddle.net/MarKP/32/
This fiddle is not mine, but this is exactly what I have right now in my project.
I'm trying to get this done using jQuery or plain JavaScript.
Thank you in advance!
To achieve this you can maintain an array which holds the order in which the elements were clicked. Then, when the limit is hit, you can remove the class from the element which was selected first. Try this:
var selections = [];
var $div = $('div').click(function(e) {
selections.push(this.id);
if (selections.length > 3)
selections.shift(); // remove first item
setState();
});
function setState() {
$div.removeClass('fill');
$div.filter(`#${selections.join(',#')}`).addClass('fill');
}
div {
border: 1px solid blue;
height: 25px;
margin-bottom: 5px;
}
.fill {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="1">one</div>
<div id="2">two</div>
<div id="3">three</div>
<div id="4">four</div>
<div id="5">five</div>
<div id="6">six</div>
Finally, note that jQuery 1.4.4 is massively outdated; nearly 10 years in fact. You need to update it.

HTML Elements inside Contenteditable?

I have a contenteditable tag, and I want my users to be able to type code into it. However, when I type into the contenteditable tag, my code shows up as text rather than an actual element. Is there a way for a user to create a full, working HTML element in a contenteditable box? I know it is possible for the client to insert code using javascript, but what about users who do not have access to javascript? How could users get code such as buttons inside a contenteditable box?
<p contenteditable="true">Try typing code in here as user, code will only be text...</p>
Is there a javascript way to accomplish this without JQUERY?
EDIT
I spent a long time searching for answers on Google, but nothing came up. The best solution I've gotten at this point has been #Dekel's comment on CKEditor. If there is another solution, I want to hear it. If there isn't, I'm sticking to CKEditor. I don't have much time, so I need a solution fast.
MORE EDIT =D
I recently developed my own answer to my question by looking at #Brandon's .replace answer (which only worked for client-coding, not user-coding) and modifying it to work with user-coding.
This isn't pretty, but you could make it work if you are looking to add HTML only. Otherwise an inline editor might work best.
var el = document.querySelector('p')
el.addEventListener('blur', function() {
var map = {amp: '&', lt: '<', gt: '>', quot: '"', '#039': "'"}
var html = this.innerHTML.replace(/&([^;]+);/g, (m, c) => map[c]);
this.innerHTML = html;
});
<p contenteditable="true">Try typing <b>code</b> in here as user, code will only be text...</p>
This answer is similar to #Brandon's idea, but is much more simple.
https://jsfiddle.net/azopqLe4/
<iframe width="100%" height="300" src="//jsfiddle.net/azopqLe4/embedded/js,html,result/dark/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
function convertit() {
var convet = document.getElementById("convet");
var text = convet.innerHTML;
var newtext;
newtext = text.replace(/</g, "<").replace(/>/g, ">");
convet.innerHTML = newtext;
}
//this version runs onrightclick =D
<p contenteditable="true" oncontextmenu="convertit();" id="convet">
Type some code here, then right-click... =D
</p>
In the second snippet, I typed <b>Test</b>, right-clicked it, and it became Test! My answer works through simple array replacement methods, although it is frustrating and time-wasting to keep right-clicking all the time. To prevent the actual contextmenu from popping up, just add .preventDefault().
You can't insert code, but you can insert DOMElements with JS. No need for jQuery.
var element=document.createElement("button");
element.innerHTML="Hello";
document.getElementById("yourContentEditable").append(element);
The idea with this would be to have a button to prompt for the code and insert it. Something like this:
(It is very ugly and buggy but it's just an example I just wrote)
var editorSelection=null;
function openCodePopup() {
//Store cursor position before editor loses focus
editorSelection=getEditorSelection();
//Open the popup
document.querySelector("#codePopup").style.display="block";
var ta=document.querySelector("#userCode");
ta.value="";
ta.focus();
}
function closeCodePopup() {
document.querySelector("#codePopup").style.display="none";
}
function insertCode() {
var code=document.querySelector("#userCode").value;
closeCodePopup();
if(code=="") return;
insertIntoEditor(html2dom(code));
}
function getEditorSelection() {
//TODO make crossbrowser
//TODO (VERY IMPORTANT) validate if selection is whitin the editor
var sel=window.getSelection();
if(sel.rangeCount) return sel.getRangeAt(0);
return null;
}
function insertIntoEditor(dom) {
if(editorSelection) {
editorSelection.deleteContents();
editorSelection.insertNode(dom);
} else {
//Insert at the end
document.querySelector("#editor").append(dom);
}
}
function html2dom(code) {
//A lazy way to convert html to DOMElements, you can use jQuery or any other
var foo=document.createElement('div'); //or you could use an inline element
foo.contentEditable=false;
foo.innerHTML=code;
return foo;
}
#editor {
height: 180px;
overflow: auto;
border: 1px solid #ccc;
}
#toolbar {
position: relative;
}
#codePopup {
position: absolute;
left: 10px;
top: 15px;
background-color: #fff;
border: 1px solid #ccc;
padding: 5px;
display: none;
}
#userCode {
display: block;
width: 200px;
height: 100px;
}
<div id="toolbar">
<button onclick="openCodePopup()"></></button>
<div id="codePopup">
<textarea id="userCode" placeholder="Type code here"></textarea>
<button onclick="insertCode()">Ok</button>
<button onclick="closeCodePopup()">Cancel</button>
</div>
</div>
<div contenteditable="true" id="editor"></div>
With the same idea you could create other options to convert element (example, text->link, etc.).

Run through multiple data types using jQuery

Background Info
Hi, im not sure if its possible however Im trying to work out a way that run through a bunch of data-types and change text based on it. I know you can do it by writing every data-type and then editing the related class. However I plan to have loads of data-types and therefore looking for a time saving solution.
So my plan is to have lots of information linked to a certain div, this is so when click it can update a information section based on the data. All of the data-types will have the same data-test-
<div class="box" data-test-1="1.1" data-test-2="1.2" data-test-3="1.3"></div>
<div class="box" data-test-1="2.1" data-test-2="2.2" data-test-3="2.3"></div>
<div class="box" data-test-1="3.1" data-test-2="3.2" data-test-3="3.3"></div>
The question
Is the away I can use jQuery to run through all of the data-test-"" when the box is clicked and then link them to a match ID.
Simplified version - https://jsfiddle.net/gaLLms9b/2/
You can loop all your dataset properties,
once you match that the dataset is in this format:
^ // start of string
test- // has "test-"
\d+ // one or more numbers
$ // end of string
if you're only interested that the data is in the format of:
data-static-variable
than you can simply use this RegExp: /^static-/
You can use the actual data-key and val like:
$(".box").click(function() {
$.each(this.dataset, function(key, val) {
if(/^test-\d+$/.test( key )){ // make sure the data is "test-N(N..)"
$("#data-"+ key).html( val );
}
});
});
.box {
width: 100px;
height: 100px;
border: solid black 1px;
background-color: #f3f3f3;
cursor: pointer;
}
.box:hover {
background-color: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-foo="bar" data-test-1="1.1" data-test-2="1.2" data-test-3="1.3"></div>
<div class="box" data-test-1="2.1" data-test-2="2.2" data-test-3="2.3"></div>
<div class="box" data-test-1="3.1" data-test-2="3.2" data-test-3="3.3"></div>
<p id="data-test-1">Click on the boxes to change information</p>
<p id="data-test-2">Infor 2</p>
<p id="data-test-3">Infor 3</p>
<p id="data-foo">This should be left unchanged cause does
not matches the needed data test-N(N..) format </p>
UPDATE: If you're only interested that the data is in the format of:
data-static-(mustbeanumber)
See answer this answer.
Otherwise you can use this one.
You can loop through all the elements and match for data-test-. In that way you can add more attributes and it will still work. Here is an working example.
$(".box").click(function() {
$.each(this.attributes, function() {
if (this.specified) {
if (this.name.indexOf('data-test-')>-1) {
$('#' + this.name).html(this.value);
}
}
});
})
.box {
width: 100px;
height: 100px;
border: solid black 1px;
background-color: #f3f3f3;
cursor: pointer;
}
.box:hover {
background-color: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box" data-test-1="1.1" data-test-2="1.2" data-test-3="1.3"></div>
<div class="box" data-test-1="2.1" data-test-2="2.2" data-test-3="2.3"></div>
<div class="box" data-test-1="3.1" data-test-2="3.2" data-test-3="3.3"></div>
<p id="data-test-1">Click on the boxes to change information</p>
<p id="data-test-2">Infor 2</p>
<p id="data-test-3">Infor 3</p>
You can use Element.dataset , for..in loop . Interestingly, both $(this).data("test-1") and $(this).data("test1") return undefined ?
$(".box").click(function() {
var data = this.dataset;
for (var prop in data) {
$("#data-" + prop).html(data[prop])
}
})
jsfiddle https://jsfiddle.net/gaLLms9b/3/
.data() apparently does not recognize digits separated by - as a valid property name.
You could adjust html to set each data-* as an object containing property names corresponding to id of elements, use $.each() to iterate property names, values and set .html() on matched element that passed .is() condition at if
html
<div class="box"
data-test='{"test":1.1,"test-2":1.2,"test-3":1.3}'
data-other='{"other-1":7.0}'></div>
<div class="box"
data-test='{"test-1":2.1,"test-2":2.2,"test-3":2.3}'></div>
<div class="box"
data-test='{"test-1":3.1,"test-2":2.2,"test-3":2.3}'></div>
<p id="data-test-1">Click on the boxes to change information</p>
<p id="data-test-2">Infor 2</p>
<p id="data-test-3">Infor 3</p>
<p id="data-other-1">Infor 3</p>
javascript
$(".box").click(function() {
$.each($(this).data(), function(prop, value) {
$.each(value, function(key, val) {
var el = $("#data-" + key);
if (el.is("*")) el.html(val)
})
})
})
jsfiddle https://jsfiddle.net/gaLLms9b/5/

In the ordered sequence of words: "Word1, Word2, Word3": how to have 1 and only 1 hyperlink on "Word1" & "Word3"? Thus, skip a word in a single link?

How to skip a word in a hyperlink?
Imagine a random ordered sequence of words:
... Word 1 Word 2 Word3 ...
How would it be possible to have 1 unifying (i.e. not 2 seperate links) hyperlink on Word 1 & Word 3?
I.e.: when one hovers either Word 1 or Word 3, the spectator can immediately notice that the hyperlink will lead to a page that covers the meaning of both these words (visible by whatever the CSS of a:hover is in a particular document).
The result would be:
... Word 1 Word 2 Word3 ...
CRUCIAL REMARK: But then instead of having 2 seperate (in this case bold-formatted hyperlinks), they would be unified into 1 single hyperlink. Again: this could e.g. be visualised in CSS by having a text-decoraiton:underline on a:hover, covering Word 1 and Word 3 simultaneously.
Optionally:
It would be good to also have the possibility to add a second, other hyperlink to Word 2.
Use-case example:
In the sentence:
"This does not need any open (Word 1) bladder (Word 2) surgeries (Word 3)."
It would be nice to have 1 unifying hyperlink on Word 1 and Word3. This example clarifies the usefulness of such a word-skipping-hyperlink: Word 2 certainly shouldn't be included in the first unifying link, since the urinary bladder-Wikipedia han't got much to do with the open surgeries-Wikipedia.
The result would be:
"This does not need any open bladder surgeries."
CRUCIAL REMARK: Instead that the hyperlink on open and surgeries should be unified into one single hyperlink.
Optionally:
It would be good to also have the possibility to add a second, other hyperlink to Word 2:
"This does not need any open bladder surgeries."
The CRUCIAL REMARK from above, also applies here.
You cannot have one link that spans two separate words.
You can have one link on each of the words point to the same location and use a little bit of JavaScript to highlight all the links that have the same destination when the user hovers over one.
For convenience I'm using jQuery here, but the same thing isn't difficult to do without it.
$(function () {
function getKey(element) {
return element.href;
}
function sameGroupAs(element) {
var key = getKey(element);
return function () {
return getKey(this) === key;
}
}
$(document)
.on("mouseenter", "a", function () {
$("a").filter(sameGroupAs(this)).addClass("active");
})
.on("mouseleave", "a", function () {
$("a").filter(sameGroupAs(this)).removeClass("active");
});
});
a.active {
background-color: #A8C5FF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>"This does not need any open bladder surgeries."</p>
I've used the href as a grouping key, but you can use any other method of groping. Just modify the getKey() function.
Here's a pure HTML + CSS method. The trick is applying a negative z-index to the second word. That makes it unclickable:
a {
text-decoration: none;
}
a span:nth-child(1), a span:nth-child(3) {
font-weight: bold;
}
a:hover span:nth-child(1), a:hover span:nth-child(3) {
text-decoration: underline;
}
a span:nth-child(2) {
position: relative;
z-index: -1;
}
This does not need any
<a href="">
<span>open</span>
<span>bladder</span>
<span>surgeries</span>
</a>
.
If you want the second word to have a different link, I think you need to duplicate the HTML, making the first instance position: absolute, and the second word of the second instance position: relative. You can then change formatting based on hover:
a {
text-decoration: none;
font-weight: bold;
}
#a1 {
position: absolute;
}
#a2 span:nth-child(2) {
position: relative;
}
#a1:hover span:nth-child(1), #a1:hover span:nth-child(3) {
text-decoration: underline;
}
#a2:hover span:nth-child(2) {
text-decoration: underline;
}
This does not need any
<a id="a1" href="http://en.wikipedia.org/wiki/Invasiveness_of_surgical_procedures#Open_surgery">
<span>open</span>
<span>bladder</span>
<span>surgeries</span>
</a>
<a id="a2" href="http://en.wikipedia.org/wiki/Urinary_bladder">
<span>open</span>
<span>bladder</span>
<span>surgeries</span>
</a>
.
With Javascript it's easy - create a span for each word, style the two outer spans to look like links, and attach a single click function to both spans.
HTML
<span id = "one">one,</span>
<span id = "two">two,</span>
<span id = "three">three</span>
CSS
#one, #three {
cursor:pointer;
}
jQuery
$('#one, #three').click(function() {
location.href = 'http://www.google.com';
});
$('#one, #three').hover(function() {
$('#one, #three').css('text-decoration', 'underline');}, function(){
$('#one, #three').css('text-decoration', 'none');
});
using pure CSS, you can have one link that spans multiple words, and have only some of them clickable.
(and you can make it look nicer than my demo using some more CSS)
This answer doesn't fully meet the OP needs because it doesn't allow a different link within the context of the first link, but it's still worth mentioning.
In order to have one link only that spans multiple words, and also have a nested element that points to another link, we'd have to allow anchor tag nesting, but it's not supported, the best way to achieve the same behavior is to split the "big" anchor tag to pieces (manually or with JS like suggested in other answers)].
a span
{
color: black;
pointer-events: none;
}
first <span>second</span> third
The simplest way to go is maybe this css rule:
a {
text-decoration:none;
color:red;
}
span {
color:black;
cursor:default;
}
and a short inline js onclick event where you don't want the event propagated:
<span onclick="return false;"> Word2 </span>
jsFiddle example
But don't do that in production.
It's pointless and ugly.
If you want the second link inside the first one, for the sake of simplicity, i would do this:
<span onclick="document.location.href = 'YOUR_2ND_LINK_HERE'; return false;"> Word2 </span>
updated jsFiddle
Here you go then
new fiddle with visual hint
If this is what you want to achieve then:
Html:
<a href="http://www.wikipedia.org">
<span class="d">Link 1</span>
<span class="b">Link 2</span>
<span class="d">Link 1</span>
<span class="b">Link 2</span>
<span class="d">Link 1</span>
<span class="b">Link 2</span>
</a>
Css
a {
text-decoration:none;
}
.d {
color:blue;
text-decoration:underline;
}
.d.fake-hover {
background:blue;
color:#fff;
text-decoration:none;
}
.b {
color:darkRed;
text-decoration:underline;
}
.b.fake-hover {
background:darkRed;
color:#fff;
text-decoration:none;
}
Javascript:
var elems = document.getElementsByClassName('d');
var otherElems = document.getElementsByClassName('b');
var allElems = document.getElementsByTagName('span');
var _href = 'http://stackoverflow.com';
function fakeIt(what, el) {
var els = (el.classList.contains('d')) ? elems : otherElems;
for (var i = 0, x = els.length; i < x; i++) {
(what == 'hover') ? els[i].classList.add('fake-hover') : els[i].classList.remove('fake-hover');
}
}
function addCustomLink(e) {
e.preventDefault();
location.href = _href;
}
for (var i = 0, x = allElems.length; i < x; i++) {
var el = allElems[i];
el.addEventListener('mouseover', function(e) {
fakeIt('hover', e.target);
});
el.addEventListener('mouseout', function(e) {
fakeIt('out', e.target);
});
if (el.className == 'b') {
el.addEventListener('click', function(e) {
addCustomLink(e);
});
}
};
In jsFiddle apparently I can't use document.location.href so you have to manually edit the addCustomLink function.
Fiddle here

Categories