Changing text color in Greasemonkey - javascript

I want to write a Greasemonkey script that will change the color of the text on any page while leaving the structure as it is. I would like to change the first 10 visible characters to be red, the next 10 to be blue, the next to be red again and so on.
I see two possible ways of going about this:
iterating through every element on the page, checking if it has text that is displayed and changing the text color. I guess this can be done by getting all elements using document.getElementsByTagName('html')[0].innerHTML and then calling elements[i].textContent to get the text but I do not know how to determine if the text is visible or not. This will return the text inside <script> elements and adding color attributes to those elements will break the page.
selecting the text on the page with something like window.getSelection().addRange(WholePage) but then I don't know of any way of changing the text color.
If you think of any other method please feel free to suggest it.

Try this (use jQuery).
$('p, li').each(function(){
var length = $(this).text().length;
var newStr = "";
for (var i = 0; i < length; i+=20) {
newStr += '<span style="color:red">' + $(this).text().substring(i, i + 10) + '</span>';
newStr += '<span style="color:blue">' + $(this).text().substring(i + 10, i + 20) + '</span>';
}
$(this).html(newStr);
});

Related

Highlight slices of text with Javascript

Problem
Suppose that in the backend of my Web application I have a generic string of letters:
seq = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
and an array of positions in such a string:
pos = [(0, 2), (4, 8)]
I need to render this sequence in the frontend by splitting it every n characters. Then when a user clicks a button I need to highlight the sequence between two parameters (taken from pos) for which the button refers to.
My solution
I solve this by implementing a Javascript function formatSequence which splits seq every n characters and iterates through the pos array in order to wrap each substring inside a span tag. The result is something like this:
<pre>
<span class="A">AA</span>AA<span class="B">A</span>
<span class="B">AAA</span>AA
AAAAA
</pre>
When the user clicks the button referring to the class A I simply change the CSS background rule for class A.
It works :) But the function formatSequence is way too complicated imho. It was a pain dealing with multiple lines. I prefer not posting the code since I am looking for other approaches not changing the code of such function.
A better solution?
I think that a (better?) solution would be to implement a function that given two parameters start and end it dynamically highlights the text between them. But it appears to be even more complicated than the previous one (remember that the sequence must be split every n characters and thus the highlight must be multilines).
Any suggestions? Better approach to solve this?
One simple solution would be just to print the full seq multiple times into the HTML and hide every row you don't need at the time. When a user clicks on a button, another row would be displayed (and the first one would be hidden).
HTML:
<div class="rows"></div>
<div class="buttons"></div>
JavaScript (depending on jQuery):
(function generateRowsAndButtons() {
var sequence = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
var position = [ [0,2], [4,8] ];
var $rows = $('.rows');
var $buttons = $('.buttons');
for(var i = 0; i < position.length; i++) {
if(position[i].length !== 2 || position[i][0] > position[i][1]) {
console.log("every position array needs exactly two values with the second larger than the first one");
continue;
}
// the index is used for mapping the button the highlight position
var row = '<div class="row" data-index="' + i + '" style="display: none;">';
// you should add some checks here, if position larger then the length of the string to avoid some misbehaviors. this is of course only necessary if you aren't validating the values on another place.
row += sequence.substring(0, position[i][0]);
row += '<span class="highlighted">';
row += sequence.substring(position[i][0], position[i][1]);
row += '</span>';
row += sequence.substring(position[i][1]);
row += '</div>';
var $row = $(row);
$rows.append($row);
// a button needs the index to find the link the highlighted value
var $button = $('<button data-index="' + i + '">' + position[i] + '</button>');
$buttons.append($button);
}
$buttons.find('button').click(function() {
var index = $(this).data('index');
// hide every row, except the one with the correct index
$rows.find('.row').hide().filter('[data-index="' + index + '"]').show();
});
})();
CSS:
.row .highlighted {
background: yellow;
}
Here is a jsFiddle: https://jsfiddle.net/y8uoou1L/2

Add HTML Value To JavaScript Variable

Ok.. So i have a html element that displays a current value, value is changed via range slider, i change the value of the html element using javascript with the following code:
hex_out = document.querySelector('#hex');
hex_out.value=rangeValue;
Which the above works fine, but recently I've needed to be able to add a bit of html code into hex_out.value
for example if i try
hex_out.value="<font color='red'>"+rangeValue+"</font>"
it will change hex_out.value to the code shown below
<font color='red'>Range slider value</font>"
which is obviously not what i'm trying to accomplish. How would i add html code to hex_out.value and have it display correctly?
Before anyone trys to say "This is a duplicate question", realize i've tried nearly ALL solutions shown on stack overflow with no luck
You'll need to modify the color via the element's style property. Try the following:
hex_out.style.color = 'red';
If you need to add any HTML, then (assuming that the hex_out element is a container element, and not an <input> tag), you can assign the HTML to its innerHTML property like so:
hex_out.innerHTML = '<strong>This is a <em>formatted</em> value.</strong>';
Another edit: It looks like you're using an <output> element, which doesn't accept child elements as far as I know. In this case, you'll likely want to use a regular <div> or <span> tag instead of <output> and then update its value manually as your sliders move using the innerHTML property described above.
I think you are looking for something like this:
var hex_out = document.querySelector('#hex'),
rangeValue = document.querySelector('#val');
rangeValue .addEventListener('input', function () {
hex_out.innerHTML = "<font color='red'>"+rangeValue .value+"</font>";
}, false);
<input type=range id=val>
<span id=hex>50</span>
Your difficulty arose because you put an obsolete font tag in the output tag which only accepts "phrasing content". The font tag is not supported in HTML5 and not on the list of phrasing content elements.
As #Mark said, a simple div will do if you require HTML to be rendered.
The example you gave is the thing normally expecting from javascript. I consider you want to change html of an existing element not value. If it is you can use below code:
hex_out. innerHTML ="<font color='red'>"+rangeValue+"</font>"
Existing fiddle link JSFiddle
Tested and works:
function setColor() { debugger;
Rval = parseFloat((r_out.value / 255.00).toFixed(3));
Gval = parseFloat((g_out.value / 255.00).toFixed(3));
Bval = parseFloat((b_out.value / 255.00).toFixed(3));
hex = "R: " + Rval + " " + "G: " + Gval + " " + "B: " + Bval;
var r_hex = parseInt(r.value, 10).toString(16),
g_hex = parseInt(g.value, 10).toString(16),
b_hex = parseInt(b.value, 10).toString(16),
hex1 = "#" + pad(r_hex) + pad(g_hex) + pad(b_hex);
body.style.backgroundColor = hex1;
hex_out.innerHtml = hex + [
'<br/><font size="1px">GSC RGB Selector</font>'
].join('#hex');
}

How to insert image node between text using javascript?

I need to insert image between the text where mouse click occurs such that the image inserts itself between the text and not overlap the text as can be seen in this jsfilddle.
$('#box').click(function(ev){
$('img.mover').clone()
.removeClass('mover')
.appendTo('body')
.css('left', ev.pageX-20)
.css('top', ev.pageY-20);
});
After the change basically it should look like mbmnB/img/Nmnbbmn if I click between B and N.
You can convert the text into nodes (span) and then detect the mouse click event on the nodes. Than split the text from that node and insert your image in between :
To convert in text node :
function wrapCharacters(element) {
$(element).contents().each(function() {
if(this.nodeType === 1) {
wrapCharacters(this);
}
else if(this.nodeType === 3) {
$(this).replaceWith($.map(this.nodeValue.split(''), function(c) {
return '<span>' + c + '</span>';
}).join(''));
}
});
}
wrapCharacters($('#box')[0]);
check this fiddle hope it helps:
Fiddle
Put every single letter into a span so that you can detect over which one the mouse is when the click event happens.
You should split your text in two inline parts. So best it would be to use span elements as they are inline and do not introduce newlines.
Later on you should get caret position. You can use this answer to get it: get caret position. Lets say you have your position inside var pos;
Then you can split:
function span(text) {
return '<span>'+text+'</span>';
}
var content = $('#box').html();
var left = span(content.substring(0, pos));
var right = span(content.substring(pos, content.length));
var img = '<img src="your_image.ext"></img>';
$('#box').html(left + img + right);
Note that this code is not tested but just displayes the mechanics.

Directing animation to correct place

In my word game there is a grid with 3 letter words.
The aim of the game is to spell the words by clicking on the corresponding letters on the side.
When an area in the grid is highlighted it indicates to the user the word to spell. The user clicks the letters on the side of the grid and they should move to the highlighted area.
I have recently changed "drop-box" to a div in the following piece of code and now the animation takes the letter to the top corner of the grid before taking it to the correct position.
var row = '<tr>';
var spaceAvailInRow = numLetters;
while (spaceAvailInRow) {
var word = getWordToFitIn(spaceAvailInRow, unusedShuffledWords);
guesses[word] = [];
spaceAvailInRow -= word.length;
for (var k = 0; k < word.length; ++k) {
row += '<td data-letter="' + word[k] + '" data-word="' + word + '"><div class="drop-box"></div></td>';
}
}
row += '</tr>';
tbl.append(row);
}
$(".container").append(tbl);
Can someone tell me why the animation has broke now I have changed this?
Fiddle: http://jsfiddle.net/7Y7A5/27/
The problem is that position() gets an element's position relative to its (offset) parent - in your case, each drop-box div is positioned at 0,0 releative to its containing td. What you need is the containing td's position(), not the drop-box's.
I've changed things around a little, and the fiddle can be seen here: http://jsfiddle.net/mHDkV/1/
I've changed the targetPos variable to refer to the position of the parent td, and applied the occupied class to that td as well. Take a look though the code in the jsFiddle - it should hopefully make sense.

showing context menu in contentEditable div

I have a contentEditable div with following text for example:
<div contentEditable='true'> This document is classified</div>
Now for example if user clicks on 'm' in word document I want to show a context menu containing few text choices. That context menu will be contained in a div element. I want to replace the word "document" with the option(text) selected by user from context menu. In my view I have to find absolute position of click to show context menu and then I have to find space elements before and after the caret position and then replace the selection with option selected from context menu. Any idea how I can do it using JavaScript and jQuery?
Edit:
one part of my question is about context menu and other the more important is how i can detect the word on wchich user has clicked on in contentEditable div or in text area on the other hand. my goal is something like in below picture
actually i want to make a similar transliteration application. the process of script conversion from roman to Urdu has been done however i m facing lot of problems in user interface development on the web. google transliteration application can be found here. i hope someone can help me in getting word under user's mouse and display a context menu containing few choices.
You may want to have a look at some of the existing context menu plugins
http://www.trendskitchens.co.nz/jquery/contextmenu/
http://labs.abeautifulsite.net/projects/js/jquery/contextMenu/demo/
http://plugins.jquery.com/plugin-tags/context-menu
To get the currently selected word in a text area, have a look at the fieldSelection plugin.
So using the second plugin and fieldSelection (Disclaimer: I think the indexing regarding string replacement is slightly off - have not fully tested)
Javascript
$(document).ready(function () {
//replace
$("#tx").contextMenu({
menu: 'replace'
}, function (action, el, pos) {
update(action, el)
});
function update(action, el) {
var range = $("#tx").getSelection();
var textLength = $("#tx").val().length;
var firstPart = $("#tx").val().substring(0, range.start);
var secondPart = $("#tx").val().substring(range.start, textLength);
var lastIndexofSpaceInfirstPart = firstPart.lastIndexOf(" ");
var firstIndexofSpaceInSecondPart = secondPart.indexOf(" ");
var startOfWord = 0
var endOfWord = 0
if (lastIndexofSpaceInfirstPart < 0) {
// start of string
startOfWord = 0;
} else {
startOfWord = lastIndexofSpaceInfirstPart;
}
if (firstIndexofSpaceInSecondPart < 0) {
// end of textArea
endOfWord = textLength
} else {
endOfWord = firstIndexofSpaceInSecondPart + range.start;
}
var word = $.trim($("#tx").val().substring(startOfWord, endOfWord));
var replaceMent = $("#tx").val().substr(0, startOfWord)
+ action.toString()
+ $("#tx").val().substr(endOfWord, textLength);
alert(
"rangeStart: " + range.start +
"\n\nrangeEnd: " + range.end +
"\n\nrangeLength: " + range.length +
+"\n\nfirstPart: " + firstPart
+ "\n\n secondPart: " + secondPart
+ "\n\n lastIndexofSpaceInfirstPart: " + lastIndexofSpaceInfirstPart
+ "\n\n firstIndexofSpaceInSecondPart:" + firstIndexofSpaceInSecondPart
+ "\n\nWordStart: " + startOfWord
+ "\n\nEndofWord: " + endOfWord
+ "\n\nWord: '" + word + "'"
+ "\n\nNew Text: '" + replaceMent + "'"
);
}
});
Html
<textarea id="tx">
Some text
</textarea>
<ul id="replace" class="contextMenu">
<li class="edit">youwordhere1</li>
<li class="cut separator">youwordhere2</li>
<li class="copy">youwordhere3</li>
<li class="paste">youwordhere4</li>
<li class="delete">youwordhere5</li>
<li class="quit separator">youwordhere6</li>
</ul>
To detect a word under the mouse cursor rock solid reliable: Just wrap every word you want to detect in a separate container, span for example. It is not difficult to do with javascript. Just parse the words in a loop and create span element for every one, then set its innerHTML = word. Then you can read the click event target and it will give you the span with the word.
To show a context menu on the spot is a trivial task:
Create a div with your content menu and make it positiion:absolute and display:none. When you want to show it, set its top and left styles (for example) equal to the target span element offset from the parent container and make its style display = "box". You are all set ;)

Categories

Resources