Apply CSS Repeatedly to Specific Words - javascript

I'm trying to apply CSS repeatedly and automatically to specific words.
For example, for the word "Twitter" I want the colour of the text to be #00ACED.
At present I am manually applying these colours around specific brand terms using span classes:
<span class="twitter">Twitter</span>
With the CSS:
.twitter {
color: #00ACED;
}
However, this is a process and I would prefer a method which completes this styling automatically. I have about 20 brand words with an associated colour styling.
Can anyone assist me with this problem. I am using WordPress if that makes any difference.

I think the most straight-forward way to do it is by using a smart jQuery highlight plugin I came across. After applying it, you'll be able to do what you're after. Below is an example, with a link to a live fiddle at the end:
HTML
<p>Some examples of how to highlight words with the jQuery Highlight plugin. First an example to demonstrate the default behavior and then others to demonstrate how to highlight the words Facebook and Twitter with their own class names. Words will be highlighted anywhere in the DOM, one needs only to be specific on where the script should look for the words. It supports case-sensitivity and other options, like in the case of YouTube.</p>
CSS
p { line-height: 30px; }
span { padding: 4px; }
.highlight { background-color: yellow; }
.facebook { background-color: #3c528f; color: white; }
.twitter { background-color: #1e9ae9; color: white; }
.youtube { background-color: #be0017; color: white; }
Highlight Plugin (needs to be loaded after jQuery and before the JavaScript below)
<script type="text/javascript" src="http://github.com/bartaz/sandbox.js/raw/master/jquery.highlight.js"></script>
JS
// default
$("body p").highlight("default");
// specify class name (not case sensitive)
$("body p").highlight("twitter", { className: 'twitter' });
$("body p").highlight("facebook", { className: 'facebook' });
// specify class name (case sensitive)
$("body p").highlight("YouTube", { className: 'youtube', caseSensitive: true });
Include this JavaScript at the bottom of the page (before the body closing tag so that you don't need to use the function below:
$(document).ready(function() {
// unnecessary if you load all your scripts at the bottom of your page
});
Fiddle for the win! :)

Something like this may work. You would have to loop through your search terms and this might not be the most effective way to do it.
function add_class (search, replacement) {
var all = document.getElementsByTagName("*");
for (var i=0, max=all.length; i < max; i++) {
var text = all[i].textContent || all[i].innerText;
if (text.indexOf(search) !== -1 && ! all[i].hasChildNodes()) {
all[i].className = all[i].className + " " + replacement;
}
}
}
var replacements = [
["Twitter","twitter"],
//
]
for (var i = replacements.length - 1; i >= 0; i--) {
add_class(replacements[i][0],replacements[i][1]);
};
Note: I didn't test this at all.

If you know minimum among of JavaScript, this JavaScript library can make your life much easier. it will convert all the letter in the string into a span tag. http://daverupert.com/2010/09/lettering-js/

For those of you interested in the answer, I've created a solution using WordPress functionality:
function replace_custom_word($text){
$replace = array(
'Twitter' => '<span class="twitter"><a title="Twitter" target="_blank" href="http://www.twitter.com/">Twitter</a></span>',
'Facebook' => '<span class="facebook"><a title="Facebook" target="_blank" href="http://www.facebook.com/">Facebook</a></span>'
);
$text = str_replace(array_keys($replace), $replace, $text);
return $text;}

Related

Deleting <style> elements when adding new ones with JS

I'm trying to make a page that has 3 buttons that make the background change color. I know how to do this, theoretically. I've been trying to build the methods for changing the background color but whenever I change the color, it's because the new style element overlaps the old one(s), so I'm looking for a way to delete the previous one when the new one is created but I've yet to find it.
var backgroundColor = {
red: function backgroundRed() {
var sheet = document.createElement('style');
sheet.setAttribute('id', 'redBG');
sheet.innerHTML = "body {background-color: red;}";
document.body.appendChild(sheet);
},
blue: function backgroundBlue() {
var sheet = document.createElement('style');
sheet.setAttribute('id', 'blueBG');
sheet.innerHTML = "body {background-color: blue;}";
document.body.appendChild(sheet);
},
green: function backgroundGreen() {
var sheet = document.createElement('style');
sheet.setAttribute('id', 'greenBG');
sheet.innerHTML = "body {background-color: limegreen;}";
document.body.appendChild(sheet);
},
deletePrevious: function() {
// ???
},
};
var applyColor = {
applyRed: function() {
//a method that when applying a new background color deletes the previous one
backgroundColor.red();
},
applyBlue: function() {
backgroundColor.blue();
},
applyGreen: function() {
backgroundColor.green();
}
}
This is the code I've written so far. The thing is, when I run it, this is what happens: Overlapping elements
How can I make a method that deletes the previous elements? Should I nest the elements within a div?
Edit: Turns out I'm wildly overthinking this. I'm been learning JS for about 2 months now, still have a long way to go. Andrew Lohr's comment effectively replaces all the backgroundColor functions I created. I'm also new to StackOverflow so I haven't found a way to upvote his comment yet. I need to get more acquainted with the DOM and easier ways to modify it.
Thank you all for your responses and your help.
You look like you're familiar with JS, so tell me if you need a example.
Make a style tag with the 'themeCSS'. Then, every time you want to add/replace the CSS, use:
themeCSS.innerHTML = "so { and: so; }";
That way, it'll always replace the previous CSS :)
Instead of changing the entire CSS <style> tag just set a value in the class` attribute that sets the overall theme and all of your CSS is based on that theme.
body.theme-red {
background-color: red;
}
body.theme-blue {
background-color: blue;
}
body.theme-green {
background-color: green;
}
.theme-red h1 {
color: black
}
.theme-blue h1 {
color: yellow;
}
.theme-green h1 {
color: red;
}
Or, break your CSS into three files and only load the correct one based on the theme.
Or, break you CSS into three files and use Alternate Style Sheets.

How to dynamically change a class css styling?

Goal
In my program I want to do both things with jquery/javascript:
Change styling of css classes dynamically
Add/remove classes to elements
Problem
To do the first thing I use $(".className").css() method, but it changes style only for those elements that already have className class, i.e. if I later add className to an element its style won't be new. How can I solve this?
Example
See it also at jsfiddle.
$("p").addClass("redclass");
$(".redclass").css("color", "darkRed");
$("span").addClass("redclass");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>I want to be red! And I am.</p>
<span>I want to be red too but I'm not :'(</span>
Result:
A more shorten format:
$("<style/>", {text: ".redclass {color: darkRed;}"}).appendTo('head');
The snippet:
$("<style/>", {text: ".redclass {color: darkRed;}"}).appendTo('head');
$("p").addClass("redclass");
$("span").addClass("redclass");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>I want to be red! And I am.</p>
<span>I want to be red too but I'm not :'(</span>
While other (working) answers have been supplied, they don't actually answer your question - namely, they don't change the specified css class, but instead override it by adding another rule later in the document.
They achieve this, basically:
Before
.someClass
{
color: red;
}
After
.someClass
{
color: red;
}
.someClass
{
color: white;
}
When in many cases, a better option would see the color attribute of the existing rule altered.
Well, as it turns out - the browser maintains a collection of style-sheets, style-sheet rules and attributes of said rules. We may prefer instead, to find the existing rule and alter it. (We would certainly prefer a method that performed error checking over the one I present!)
The first console msg comes from the 1 instance of a #coords rule.
The next three come from the 3 instances of the .that rule
function byId(id){return document.getElementById(id)}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
byId('goBtn').addEventListener('click', onGoBtnClicked, false);
}
function onGoBtnClicked(evt)
{
alterExistingCSSRuleAttrib('#coords', 'background-color', 'blue');
alterExistingCSSRuleAttrib('.that', 'color', 'red');
}
// useful for HtmlCollection, NodeList, String types (array-like types)
function forEach(array, callback, scope){for (var i=0,n=array.length; i<n; i++)callback.call(scope, array[i], i, array);} // passes back stuff we need
function alterExistingCSSRuleAttrib(selectorText, tgtAttribName, newValue)
{
var styleSheets = document.styleSheets;
forEach(styleSheets, styleSheetFunc);
function styleSheetFunc(CSSStyleSheet)
{
forEach(CSSStyleSheet.cssRules, cssRuleFunc);
}
function cssRuleFunc(rule)
{
if (selectorText.indexOf(rule.selectorText) != -1)
forEach(rule.style, cssRuleAttributeFunc);
function cssRuleAttributeFunc(attribName)
{
if (attribName == tgtAttribName)
{
rule.style[attribName] = newValue;
console.log('attribute replaced');
}
}
}
}
#coords
{
font-size: 0.75em;
width: 10em;
background-color: red;
}
.that
{
color: blue;
}
<style>.that{color: green;font-size: 3em;font-weight: bold;}</style>
<button id='goBtn'>Change css rules</button>
<div id='coords' class='that'>Test div</div>
<style>.that{color: blue;font-size: 2em;font-weight: bold;}</style>
#synthet1c has described the problem. My solution is:
$("head").append('<style></style>');
var element = $("head").children(':last');
element.html('.redclass{color: darkred;}');
What you are having issue with is that when you use the jQuery selector $('.redclass').css('color', 'darkRed') you are getting all the elements that currently have that class and using javascript to loop over the collection and set the style property.
You then set the class on the span after. Which was not included in the collection at the time of setting the color
You should set the class in your css file so it is distributed to all elements that have that class
console.log($('.redclass').length)
$("p").addClass("redclass");
console.log($('.redclass').length)
// $(".redclass").css("color", "darkRed");
$("span").addClass("redclass");
console.log($('.redclass').length)
.redclass {
color: darkRed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>I want to be red! And I am.</p>
<span>I want to be red too but I'm not :'(</span>

Jquery adding and removing elements dynamically

I am trying to add and remove a span element dynamically. it's throwing syntax errors like
expected ')' and expected ';'
please help me to fix it.
<script type="text/javascript">
$(document).ready(function () {
$("input[data-required='true']").focus(function () {
$(this).css({ 'background-color': 'red' }).after("<span class="label_error;"style="color:red;font-size:10pt">This field is required</span>");
});
$("input[data-required='true']").blur(function () {
$(this).css({ 'background-color': 'white' }).remove("<span class="label_error;"style="color:red;font-size:10pt">This field is required</span>") ;
});
});
</script>
The way that you are concatenating the values in your HTML string is wrong,
.after("<span class='label_error' style='color:red;font-size:10pt;'>" +
"This field is required" +
"</span>");
To fix this issue either you can use single quote in your string wrapped by double quotes or try to escape the double quote by using \ like "avi\"s code is wrong".
On top of all, the best approach would be creating element by using jquery,
.after($("<span>", {class : 'label_error',
style : 'color:red;font-size:10pt;',
text : 'This field is required'
}));
This would be more readable and maintainable. And I forgot to spot another one error that you made in your code. You are using .remove() in a wrong way,
$("input[data-required='true']").blur(function () {
$(this).css({ 'background-color': 'white' }).next("span.label_error").remove();
});
You have to select the relevant element from your $(this) object and invoke remove over it.
And the best approach for finishing up your task is, allot the styling works to be done to the css by writing rules with relevant selectors (said by #rory)
input[data-required='true'] {
background-color: white;
}
input[data-required='true']:focus {
background-color: red;
}
span.label_error {
color: red;
font-size: 10pt;
}
And the js would be,
var errorMsg = $("<span>", {class: 'label_error',text: 'This field is required'});
$("input[data-required='true']").focus(function() {
$(this).after(errorMsg);
}).blur(function() {
$(this).next("span.label_error").remove();
});
DEMO
You have two issues. Firstly you need to use different quotes to delimit the string to those you use within the string. Helpfully, in JS you can use either single (') or double (") quotes to achieve the same purpose. Also, the class attribute should not have a trailing ;. It can be helpful to use a text editor which has syntax highlighting as it makes it nearly impossible to miss mistakes like that.
Your second problem is that the remove() method expects a selector, not a whole HTML string. To remove the span which was appended in the focus event, use next() to select it, then remove(). Try this:
$("input[data-required='true']").focus(function () {
$(this).css({ 'background-color': 'red' }).after('<span class="label_error" style="color: red; font-size: 10pt">This field is required</span>');
});
$("input[data-required='true']").blur(function () {
$(this).css({ 'background-color': 'white' }).next('span').remove();
});
Finally, note that it is much better practice to define your styles in CSS as it separates the HTML/JS from the styling rules, and helps make the JS shorter as well. Try this:
input[data-required='true'] {
background-color: white; /* transparent may work here too */
}
input[data-required='true']:focus {
background-color: red;
}
span.label_error {
color: red;
font-size: 10pt;
}
$("input[data-required='true']").focus(function () {
$(this).after('<span class="label_error">This field is required</span>');
}).blur(function () {
$(this).next('span').remove();
});
Working example

Dynamically add <wbr> tag before punctuation

I'm trying to figure out how to add a <wbr> tag before punctuation in an email address, dynamically using jQuery.
I imagine there must be a way to scan the string for a "." or "#" sign and place this tag right before it, but I haven't been able to figure it out.
I've attempted two different methods which were the only solutions I was able to come up with after searching for solutions:
HTML:
<div class="container">
<span class="some-special-classname">
verylongfirstname.verylonglastname#prettylongemailaddress.com
</span>
<br /> <br />
<button class="test">Test Button</button>
</div>
CSS
wbr:after {
content:"\00200B";
}
.container {
margin: 0 auto;
max-width: 400px;
padding : 10px;
border: 1px solid #bbb;
}
Javascript: (1st. attempt)
$( ".test" ).click(function() {
$('.some-special-classname').html().replace(/#/g,"<wbr>#");
$('.some-special-classname').html().replace(/./g,"<wbr>.");
});
Javascript: (2nd. attempt)
var str = $('.some-special-classname').val();
str.replace(/#/g,'<wbr>#');
function myFunction() {
var str = $('.some-special-classname').val();
var n = str.indexOf(".");
document.getElementById("demo").innerHTML = n;
}
Can use html(function(index, oldhtml) to parse and update existing content
$('.some-special-classname').html(function(_, oldhtml){
return oldhtml.replace(/([#.])/g,"<wbr>$1");
});
This will also loop over a collection and treat them as instance specific if there are more than one matching elements in selector
Reference: html(fn) docs
You are almost doing the replacement correctly but actually not editing the DOM.
var $elem = $('.some-special-classname');
var formattedString = $elem.html().replace(/([#.])/g,"<wbr>$1");
$elem.html(formattedString); //this is what you are missing!
Also note the regular expression change to /([#.])/g so you don't need to write 2 separate lines for replacing. (thanks #DJDavid98 for the edit)

CKEditor 4 shortcode replacement

I'm trying to make a shortcode "plugin" - similar to what Wordpress uses with TinyMce. I'd like user to be able to insert a shortcode (like [gallery id="3"] or [image id="9"]) via a button and then show a placeholder instead of the actual shortcode. I'll put all the code to github once I get it to work.
Current setup
I have a button which inserts html to the editor using insertHtml() like this:
// Custom button code
CKEDITOR.instances['editor_instance_name'].insertHtml '<div class="media-library-gallery">[gallery id=' + gallery_id + ']</div>'
and I've added extraAllowedContent to allow div with the classes I need:
// CKEditor configuration (config.js)
config.extraAllowedContent = 'div(media-library-image,media-library-gallery)';
I managed to replace div.media-library-gallery with an image using the code below:
(function() {
CKEDITOR.plugins.add('media_gallery', {
init: function(editor) {
CKEDITOR.addCss('.media_gallery{background: #f2f8ff url("/assets/gallery.png") no-repeat scroll center center; border: 1px dashed #888; display: block; width:100%; height: 250px;}');
},
afterInit: function( editor ) {
var dataProcessor = editor.dataProcessor;
var dataFilter = dataProcessor && dataProcessor.dataFilter;
dataFilter.addRules({
elements: {
'div': function(element) {
if (element.attributes.class == "media-library-gallery") {
var fakeElement = editor.createFakeParserElement(element, 'media_gallery', 'div', false);
return fakeElement;
}
}
}
})
}
})
})();
The problem
Currently the replacement nests a div inside the paragraph tag:
<p>
<div class="media-library-gallery">[gallery id="5"]</div>
</p>
I don't want to change the enterMode from the default CKEDITOR.ENTER_P but I want to get rid of the surrounding p. Can I do this using insertHtml or write a rule that would do that for me? Any other suggestions are welcome.
I've been digging around http://docs.ckeditor.com/ for a solution/inspiration but had little luck.
A bit late, but try to insert your div as an element:
var element = CKEDITOR.dom.element.createFromHtml('<div class="media-library-gallery">[gallery id=' + gallery_id + ']</div>');
CKEDITOR.instances['editor_instance_name'].insertElement(element);

Categories

Resources