A JavaScript function selects a certain word in a textarea using .setSelectionRange().
In Firefox, the textarea automatically scrolls down to show the selected text. In Chrome (v14), it does not. Is there a way to get Chrome to scroll the textarea down to the newly selected text?
jQuery solutions are welcome.
Here is a simple and efficient solution in pure JavaScript:
// Get the textarea
var textArea = document.getElementById('myTextArea');
// Define your selection
var selectionStart = 50;
var selectionEnd = 60;
textArea.setSelectionRange(selectionStart, selectionEnd);
// Mow let’s do some math.
// We need the number of characters in a row
var charsPerRow = textArea.cols;
// We need to know at which row our selection starts
var selectionRow = (selectionStart - (selectionStart % charsPerRow)) / charsPerRow;
// We need to scroll to this row but scrolls are in pixels,
// so we need to know a row's height, in pixels
var lineHeight = textArea.clientHeight / textArea.rows;
// Scroll!!
textArea.scrollTop = lineHeight * selectionRow;
Put this in a function, extend the prototype of JavaScript's Element object with it, and you're good.
A lot of answers, but the accepted one doesn't consider line breaks, Matthew Flaschen didn't add the solution code, and naXa answer has a mistake. The simplest solution code is:
textArea.focus();
const fullText = textArea.value;
textArea.value = fullText.substring(0, selectionEnd);
textArea.scrollTop = textArea.scrollHeight;
textArea.value = fullText;
textArea.setSelectionRange(selectionStart, selectionEnd);
You can see how we solved the problem in ProveIt (see highlightLengthAtIndex). Basically, the trick is to truncate the textarea, scroll to the end, then restore the second part of the text. We also used the textSelection plugin for consistent cross-browser behavior.
Valeriy Katkov's elegant solution works great but has two problems:
It does not work for long strings
Selected contents are scrolled to the bottom of the textarea, making it hard to see the context which surrounds the selection
Here's my improved version that works for long strings (tested with at least 50,000 words) and scroll selection to the center of the textarea:
function setSelectionRange(textarea, selectionStart, selectionEnd) {
// First scroll selection region to view
const fullText = textarea.value;
textarea.value = fullText.substring(0, selectionEnd);
// For some unknown reason, you must store the scollHeight to a variable
// before setting the textarea value. Otherwise it won't work for long strings
const scrollHeight = textarea.scrollHeight
textarea.value = fullText;
let scrollTop = scrollHeight;
const textareaHeight = textarea.clientHeight;
if (scrollTop > textareaHeight){
// scroll selection to center of textarea
scrollTop -= textareaHeight / 2;
} else{
scrollTop = 0;
}
textarea.scrollTop = scrollTop;
// Continue to set selection range
textarea.setSelectionRange(selectionStart, selectionEnd);
}
It works in Chrome 72, Firefox 65, Opera 58, and Edge 42.
For an example of using this function, see my GitHub project SmartTextarea.
This is a code inspired by the Matthew Flaschen's answer.
/**
* Scroll textarea to position.
*
* #param {HTMLInputElement} textarea
* #param {Number} position
*/
function scrollTo(textarea, position) {
if (!textarea) { return; }
if (position < 0) { return; }
var body = textarea.value;
if (body) {
textarea.value = body.substring(0, position);
textarea.scrollTop = position;
textarea.value = body;
}
}
Basically, the trick is to truncate the textarea, scroll to the end, then restore the second part of the text.
Use it as follows
var textarea, start, end;
/* ... */
scrollTo(textarea, end);
textarea.focus();
textarea.setSelectionRange(start, end);
Based on the idea from naXa and Valeriy Katkov, I refined the function with fewer bugs. It should work out of the box (It's written with TypeScript. For JavaScript, just remove the type declaration):
function scrollTo(textarea: HTMLTextAreaElement, offset: number) {
const txt = textarea.value;
if (offset >= txt.length || offset < 0)
return;
// Important, so that scrollHeight will be adjusted
textarea.scrollTop = 0;
textarea.value = txt.substring(0, offset);
const height = textarea.scrollHeight;
textarea.value = txt;
// Margin between selection and top of viewport
textarea.scrollTop = height - 40;
}
Usage:
let textarea, start, end;
/* ... */
scrollTo(textarea, start);
textarea.focus();
textarea.setSelectionRange(start, end);
Complete code for Chrome:
<script type="text/javascript">
var SAR = {};
SAR.find = function () {
debugger;
var parola_cercata = $("#text_box_1").val(); // The searched word
// Make text lowercase if search is
// supposed to be case insensitive
var txt = $('#remarks').val().toLowerCase();
parola_cercata = parola_cercata.toLowerCase();
// Take the position of the word in the text
var posi = jQuery('#remarks').getCursorPosEnd();
var termPos = txt.indexOf(parola_cercata, posi);
if (termPos !== -1) {
debugger;
var target = document.getElementById("remarks");
var parola_cercata2 = $("#text_box_1").val();
// Select the textarea and the word
if (target.setSelectionRange) {
if ('selectionStart' in target) {
target.selectionStart = termPos;
target.selectionEnd = termPos;
this.selectionStart = this.selectionEnd = target.value.indexOf(parola_cercata2);
target.blur();
target.focus();
target.setSelectionRange(termPos, termPos + parola_cercata.length);
}
} else {
var r = target.createTextRange();
r.collapse(true);
r.moveEnd('character', termPos + parola_cercata);
r.moveStart('character', termPos);
r.select();
}
} else {
// Not found from cursor pos, so start from beginning
termPos = txt.indexOf(parola_cercata);
if (termPos !== -1) {
var target = document.getElementById("remarks");
var parola_cercata2 = $("#text_box_1").val();
// Select the textarea and the word
if (target.setSelectionRange) {
if ('selectionStart' in target) {
target.selectionStart = termPos;
target.selectionEnd = termPos;
this.selectionStart = this.selectionEnd = target.value.indexOf(parola_cercata2);
target.blur();
target.focus();
target.setSelectionRange(termPos, termPos + parola_cercata.length);
}
} else {
var r = target.createTextRange();
r.collapse(true);
r.moveEnd('character', termPos + parola_cercata);
r.moveStart('character', termPos);
r.select();
}
} else {
alert("not found");
}
}
};
$.fn.getCursorPosEnd = function () {
var pos = 0;
var input = this.get(0);
// IE support
if (document.selection) {
input.focus();
var sel = document.selection.createRange();
pos = sel.text.length;
}
// Firefox support
else if (input.selectionStart || input.selectionStart === '0')
pos = input.selectionEnd;
return pos;
};
</script>
I published an answer here:
http://blog.blupixelit.eu/scroll-textarea-to-selected-word-using-javascript-jquery/
It works perfectly with just one needed rule: Set a line-height in the CSS content of the textarea!
It calculate the position of the word to scroll to just by doing some simple mathematical calculation and it worked perfectly in all my experiments!
Related
In a HTML/JavaScript/React/Redux web application, I have a long string (around 300kb) of natural language. It is a transcript of a recording being played back.
I need
to highlight the currently uttered word,
to recognize a word that's clicked on,
to extract selected ranges
and to replace parts of the string (when a correction to the transcript is submitted by the user).
Everything is easy when I wrap each word in its own <span>. However, this makes the number of elements unbearable for the browser and the page gets very slow.
I can think of two ways to approach this:
I could wrap each sentence in a <span> and only wrap each word of the currently played-back sentence.
I could leave the text without HTML tags, handle clicks via document.caretPositionFromPoint, but I don't know how to highlight a word.
I would welcome more ideas and thoughts on the balance between difficulty and speed.
"to recognize a word that's clicked on"
New answer
I figure that, the code in my previous answer actually had to split the huge string of text into an huge array on every on click event. After that, a linear search is performed on the array to locate the matching string.
However, this could be improved by precomputing the word array and use binary search instead of linear searching.
Now every highlighting will run in O(log n) instead of O(n)
See: http://jsfiddle.net/amoshydra/vq8y8h19/
// Build character to text map
var text = content.innerText;
var counter = 1;
textMap = text.split(' ').map((word) => {
result = {
word: word,
start: counter,
end: counter + word.length,
}
counter += word.length + 1;
return result;
});
content.addEventListener('click', function (e) {
var selection = window.getSelection();
var result = binarySearch(textMap, selection.focusOffset, compare_word);
var textNode = e.target.childNodes[0];
if (textNode) {
var range = document.createRange();
range.setStart(textNode, textMap[result].start);
range.setEnd(textNode, textMap[result].end);
var r = range.getClientRects()[0];
console.log(r.top, r.left, textMap[result].word);
// Update overlay
var scrollOffset = e.offsetY - e.clientY; // To accomondate scrolling
overlay.innerHTML = textMap[result].word;
overlay.style.top = r.top + scrollOffset + 'px';
overlay.style.left = r.left + 'px';
}
});
// Slightly modified binary search algorithm
function binarySearch(ar, el, compare_fn) {
var m = 0;
var n = ar.length - 1;
while (m <= n) {
var k = (n + m) >> 1;
var cmp = compare_fn(el, ar[k]);
if (cmp > 0) {
m = k + 1;
} else if(cmp < 0) {
n = k - 1;
} else {
return k;
}
}
return m - 1;
}
function compare_word(a, b) {
return a - b.start;
}
Original answer
I took a fork of code from this answer from aaron and implemented this:
Instead of setting a span tag on the paragraph, we could put an overlay on top of the word.
And resize and reposition the overlay when travelling to a word.
Snippet
JavaScript
// Update overlay
overlayDom.innerHTML = word;
overlayDom.style.top = r.top + 'px';
overlayDom.style.left = r.left + 'px';
CSS
Use an overlay with transparent color text, so that we can get the overlay to be of the same width with the word.
#overlay {
background-color: yellow;
opacity: 0.4;
display: block;
position: absolute;
color: transparent;
}
Full forked JavaScript code below
var overlayDom = document.getElementById('overlay');
function findClickedWord(parentElt, x, y) {
if (parentElt.nodeName !== '#text') {
console.log('didn\'t click on text node');
return null;
}
var range = document.createRange();
var words = parentElt.textContent.split(' ');
var start = 0;
var end = 0;
for (var i = 0; i < words.length; i++) {
var word = words[i];
end = start+word.length;
range.setStart(parentElt, start);
range.setEnd(parentElt, end);
// not getBoundingClientRect as word could wrap
var rects = range.getClientRects();
var clickedRect = isClickInRects(rects);
if (clickedRect) {
return [word, start, clickedRect];
}
start = end + 1;
}
function isClickInRects(rects) {
for (var i = 0; i < rects.length; ++i) {
var r = rects[i]
if (r.left<x && r.right>x && r.top<y && r.bottom>y) {
return r;
}
}
return false;
}
return null;
}
function onClick(e) {
var elt = document.getElementById('info');
// Get clicked status
var clicked = findClickedWord(e.target.childNodes[0], e.clientX, e.clientY);
// Update status bar
elt.innerHTML = 'Nothing Clicked';
if (clicked) {
var word = clicked[0];
var start = clicked[1];
var r = clicked[2];
elt.innerHTML = 'Clicked: ('+r.top+','+r.left+') word:'+word+' at offset '+start;
// Update overlay
overlayDom.innerHTML = word;
overlayDom.style.top = r.top + 'px';
overlayDom.style.left = r.left + 'px';
}
}
document.addEventListener('click', onClick);
See the forked demo: https://jsfiddle.net/amoshydra/pntzdpff/
This implementation uses the createRange API
I don't think the number of <span> elements is unbearable once they have been positioned. You might just need to minimize reflow by avoiding layout changes.
Small experiment: ~3kb of text highlighted via background-color
// Create ~3kb of text:
let text = document.getElementById("text");
for (let i = 0; i < 100000; ++i) {
let word = document.createElement("span");
word.id = "word_" + i;
word.textContent = "bla ";
text.appendChild(word);
}
document.body.appendChild(text);
// Highlight text:
let i = 0;
let word;
setInterval(function() {
if (word) word.style.backgroundColor = "transparent";
word = document.getElementById("word_" + i);
word.style.backgroundColor = "red";
i++;
}, 100)
<div id="text"></div>
Once the initial layout has finished, this renders smoothly for me in FF/Ubuntu/4+ years old laptop.
Now, if you where to change font-weight instead of background-color, the above would become unbearably slow due to the constant layout changes triggering a reflow.
Here is a simple editor that can easily handle very large string. I tried to use minimum DOM for performance.
It can
recognize a word that's clicked on
highlight the currently clicked word, or drag selection
extract selected ranges
replace parts of the string (when a correction to the transcript is submitted by the user).
See this jsFiddle
var editor = document.getElementById("editor");
var highlighter = document.createElement("span");
highlighter.className = "rename";
var replaceBox = document.createElement("input");
replaceBox.className = "replace";
replaceBox.onclick = function() {
event.stopPropagation();
};
editor.parentElement.appendChild(replaceBox);
editor.onclick = function() {
var sel = window.getSelection();
if (sel.anchorNode.parentElement === highlighter) {
clearSelection();
return;
}
var range = sel.getRangeAt(0);
if (range.collapsed) {
var idx = sel.anchorNode.nodeValue.lastIndexOf(" ", range.startOffset);
range.setStart(sel.anchorNode, idx + 1);
var idx = sel.anchorNode.nodeValue.indexOf(" ", range.endOffset);
if (idx == -1) {
idx = sel.anchorNode.nodeValue.length;
}
range.setEnd(sel.anchorNode, idx);
}
clearSelection();
range.surroundContents(highlighter);
range.detach();
showReplaceBox();
event.stopPropagation();
};
document.onclick = function(){
clearSelection();
};
function clearSelection() {
if (!!highlighter.parentNode) {
replaceBox.style.display = "none";
highlighter.parentNode.insertBefore(document.createTextNode(replaceBox.value), highlighter.nextSibling);
highlighter.parentNode.removeChild(highlighter);
}
editor.normalize(); // comment this line in case of any performance issue after an edit
}
function showReplaceBox() {
if (!!highlighter.parentNode) {
replaceBox.style.display = "block";
replaceBox.style.top = (highlighter.offsetTop + highlighter.offsetHeight) + "px";
replaceBox.style.left = highlighter.offsetLeft + "px";
replaceBox.value = highlighter.textContent;
replaceBox.focus();
replaceBox.selectionStart = 0;
replaceBox.selectionEnd = replaceBox.value.length;
}
}
.rename {
background: yellow;
}
.replace {
position: absolute;
display: none;
}
<div id="editor">
Your very large text goes here...
</div>
I would first find the clicked word via some annoying logic (Try looking here )
Then you can highlight the word simply by wrapping the exact word with a styled span as you suggested above :)
Well, I'm not really sure how you could recognise words. You may need a 3rd party software. To highlight a word, you can use CSS and span as you said.
CSS
span {
background-color: #B6B6B4;
}
To add the 'span' tags, you could use a find and replace thing. Like this one.
Find: all spaces
Replace: <span>
I'm working on a rich text editor for iOS and have most of it working but running into endless problems ensuring that the cursor is visible in the viewport when the user starts typing.
I came up with a novel approach: insert a span at the cursor position, scroll to the span, and then remove it. (I haven't gotten to only scrolling if the span is on-screen.) Here's what I wrote:
document.addEventListener('keypress', function(e) {
jumpToID();
}, false);
function jumpToID() {
var id = "jumphere2374657";
var text = "<span id='" + id + "'> </span>"
document.execCommand('insertHTML', false, text);
var element = document.getElementById(id);
element.scrollIntoView();
element.parentNode.removeChild(element);
}
In some cases this works just fine and in some cases it leaves a non-break space between every key press, removing the <span></span> tags only. Any ideas? I'm open to better ways of doing this if someone has suggestions. I'm a little shocked at how hard it is to make the cursor appear but then JS is new to me.
EDIT
This is the code that works:
var viewportHeight = 0;
function setViewportHeight(vph) {
viewportHeight = vph;
if(viewportHeight == 0 && vph != 0)
viewportHeight = window.innerHeight;
}
function getViewportHeight() {
if(viewportHeight == 0)
return window.innerHeight;
return viewportHeight;
}
function makeCursorVisible() {
var sel = document.getSelection(); // change the selection
var ran = sel.getRangeAt(0); // into a range
var rec = ran.getClientRects()[0]; // that we can get coordinates from
if (rec == null) {
// Can't get coords at start of blank line, so we
// insert a char at the cursor, get the coords of that,
// then delete it again. Happens too fast to see.
ran.insertNode( document.createTextNode(".") );
rec = ran.getClientRects()[0]; // try again now that there's text
ran.deleteContents();
}
var top = rec.top; // Y coord of selection top edge
var bottom = rec.bottom; // Y coord of selection bottom edge
var vph = getViewportHeight();
if (top < 0) // if selection top edge is above viewport top,
window.scrollBy(0, top); // scroll up by enough to make the selection top visible
if (bottom >= vph) // if selection bottom edge is below viewport bottom,
window.scrollBy(0, bottom-vph + 1); // scroll down by enough to make the selection bottom visible
}
The viewportHeight is more complicated than need be for a web app. For a mobile app we need to account for the keyboard so offer a method for setting the viewportHeight manually as well as the automatic setting from the window.innerHeight.
I don't know if this will work on iOS, but if the position of the cursor means that there is a Selection at that point..
function moveToSelection(){
var sel = document.getSelection(), // change the selection
ran = sel.getRangeAt(0), // into a range
rec = ran.getClientRects()[0], // that we can get co-ordinates from
dy = rec.top; // distance to move down/up
window.scrollBy( 0, dy ); // actual move
// console.log( sel, ran, rec, y ); // help debug
}
moveToSelection();
Relevant links
getSelection
getRangeAt
getClientRects
scrollBy
How do I get the index of the text caret in an input?
-> selectionStart
<!doctype html>
<html>
<head>
<meta charset = "utf-8">
<script type = "text/javascript">
window.addEventListener ("load", function () {
var input = document.getElementsByTagName ("input");
input[0].addEventListener ("keydown", function () {
alert ("Caret position: " + this.selectionStart);
// You can also set the caret: this.selectionStart = 2;
});
});
</script>
<title>Test</title>
</head>
<body>
<input type = "text">
</body>
</html>
The following will get you the start and end of the selection as character indices. It works for text inputs and textareas, and is slightly complicated because of IE's strange handling of line breaks.
function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();
if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");
// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());
// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}
return {
start: start,
end: end
};
}
var textBox = document.getElementById("textBoxId");
textBox.focus();
alert( getInputSelection(textBox).start );
There is now a nice jQuery plugin for this: Caret plugin
Then you can just call $("#myTextBox").caret();
We had used something like this for an old javascript application, but I haven't tested it in a couple years:
function getCaretPos(input) {
// Internet Explorer Caret Position (TextArea)
if (document.selection && document.selection.createRange) {
var range = document.selection.createRange();
var bookmark = range.getBookmark();
var caret_pos = bookmark.charCodeAt(2) - 2;
} else {
// Firefox Caret Position (TextArea)
if (input.setSelectionRange)
var caret_pos = input.selectionStart;
}
return caret_pos;
}
Get coordinates (css: left:x , top:y) of the current caret position in order to position an element (e.g. show tooltip at caret position)
function getCaretCoordinates() {
let x = 0,
y = 0;
const isSupported = typeof window.getSelection !== "undefined";
if (isSupported) {
const selection = window.getSelection();
// Check if there is a selection (i.e. cursor in place)
if (selection.rangeCount !== 0) {
// Clone the range
const range = selection.getRangeAt(0).cloneRange();
// Collapse the range to the start, so there are not multiple chars selected
range.collapse(true);
// getCientRects returns all the positioning information we need
const rect = range.getClientRects()[0];
if (rect) {
x = rect.left; // since the caret is only 1px wide, left == right
y = rect.top; // top edge of the caret
}
}
}
return { x, y };
}
demo: https://codesandbox.io/s/caret-coordinates-index-contenteditable-9tq3o?from-embed
ref: https://javascript.plainenglish.io/how-to-find-the-caret-inside-a-contenteditable-element-955a5ad9bf81
Working example of getting cursor point in text box:
function textbox()
{
var ctl = document.getElementById('Javascript_example');
var startPos = ctl.selectionStart;
var endPos = ctl.selectionEnd;
alert(startPos + ", " + endPos);
}
I need to insert some text into a textarea at the place where the cursor is, how can i do this without jquery?
You may want to check the small code sample at:
Inserting at the cursor using JavaScript
Code from the above article:
function insertAtCursor(myField, myValue) {
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
}
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;
myField.value = myField.value.substring(0, startPos)
+ myValue
+ myField.value.substring(endPos, myField.value.length);
} else {
myField.value += myValue;
}
}
// calling the function
insertAtCursor(document.getElementById('textarea_id'), 'sometext');
Please see this person's code here. This code uses the selection property of the document object to get the cursor position, and then builds a new string and stuffs it into the textarea. It also has a specialized routine for IE which has much more cumbersome logic for finding the cursor position.
Use an HTML title attribute? That will place tooltip text next to the cursor when it's over a particular element.
Or you could create a <div> with position: fixed, then position it at event.screenX, event.screenY:
<div id="tip" style="position: fixed; visibility: hidden;"></div>
<textarea onmousemove="position();" onmouseout="hide();"></texarea>
<script type="text/javascript">
function position() {
var d = document.getElementById('tip');
d.style.visibility = 'visible';
d.style.left = event.screenX + 'px';
d.style.top = event.screenX + 'py';
}
function hide() {
document.getElementById('tip').style.visibility = 'hidden';
}
</script>
I've built jQuery function that takes a text string and a width as inputs, then shrinks that piece of text until it's no larger than the width, like so:
function constrain(text, ideal_width){
var temp = $('.temp_item');
temp.html(text);
var item_width = temp.width();
var ideal = parseInt(ideal_width);
var smaller_text = text;
var original = text.length;
while (item_width > ideal) {
smaller_text = smaller_text.substr(0, (smaller_text.length-1));
temp.html(smaller_text);
item_width = temp.width();
}
var final_length = smaller_text.length;
if (final_length != original) {
return (smaller_text + '…');
} else {
return text;
}
}
This works fine, but because I'm calling the function on many pieces of texts, on any browser except Safari 4 and Chrome, it's really slow.
I've tried using a binary search method to make this more efficient, but what I have so far brings up a slow script dialog in my browser:
function constrain(text, ideal_width){
var temp = $('.temp_item');
temp.html(text);
var item_width = temp.width();
var ideal = parseInt(ideal_width);
var lower = 0;
var original = text.length;
var higher = text.length;
while (item_width != ideal) {
var mid = parseInt((lower + higher) / 2);
var smaller_text = text.substr(0, mid);
temp.html(smaller_text);
item_width = temp.width();
if (item_width > ideal) {
// make smaller to the mean of "lower" and this
higher = mid - 1;
} else {
// make larger to the mean of "higher" and this
lower = mid + 1;
}
}
var final_length = smaller_text.length;
if (final_length != original) {
return (smaller_text + '…');
} else {
return text;
}
}
Does anyone have an idea of what I should be doing to make this function as efficient as possible?
Thanks! Simon
The problem with your script is probably that the while condition (item_width != ideal) possibly will never abort the loop. It might not be possible to trim the input text to the exact width ideal. In this case your function will loop forever, which will trigger the slow script dialog.
To circumvent this you should stop looping if the displayed text is just small enough (aka. adding more characters would make it too big).
I used 2 divs
<div class="englober">
<div class="title"></div>
</div>
the .englober has a fixed with and overflow:hidden, white-space:nowarp.
Then using jQuery, i resize the text from the .title to fit the .englober with :
while ($(".title").width() > $(".englober").width())
{
var dFontsize = parseFloat($(".title").css("font-size"), 10);
$(".title").css("font-size", dFontsize - 1);
}