Highlight text inside of a textarea - javascript

Is it possible to highlight text inside of a textarea using javascript? Either changing the background of just a portion of the text area or making a portion of the text selected?

Try this piece of code I wrote this morning, it will highlight a defined set of words:
<html>
<head>
<title></title>
<!-- Load jQuery -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<!-- The javascript xontaining the plugin and the code to init the plugin -->
<script type="text/javascript">
$(function() {
// let's init the plugin, that we called "highlight".
// We will highlight the words "hello" and "world",
// and set the input area to a widht and height of 500 and 250 respectively.
$("#container").highlight({
words: ["hello","world"],
width: 500,
height: 250
});
});
// the plugin that would do the trick
(function($){
$.fn.extend({
highlight: function() {
// the main class
var pluginClass = function() {};
// init the class
// Bootloader
pluginClass.prototype.__init = function (element) {
try {
this.element = element;
} catch (err) {
this.error(err);
}
};
// centralized error handler
pluginClass.prototype.error = function (e) {
// manage error and exceptions here
//console.info("error!",e);
};
// Centralized routing function
pluginClass.prototype.execute = function (fn, options) {
try {
options = $.extend({},options);
if (typeof(this[fn]) == "function") {
var output = this[fn].apply(this, [options]);
} else {
this.error("undefined_function");
}
} catch (err) {
this.error(err);
}
};
// **********************
// Plugin Class starts here
// **********************
// init the component
pluginClass.prototype.init = function (options) {
try {
// the element's reference ( $("#container") ) is stored into "this.element"
var scope = this;
this.options = options;
// just find the different elements we'll need
this.highlighterContainer = this.element.find('#highlighterContainer');
this.inputContainer = this.element.find('#inputContainer');
this.textarea = this.inputContainer.find('textarea');
this.highlighter = this.highlighterContainer.find('#highlighter');
// apply the css
this.element.css('position','relative');
// place both the highlight container and the textarea container
// on the same coordonate to superpose them.
this.highlighterContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px dashed #ff0000',
'width': this.options.width,
'height': this.options.height,
'cursor': 'text'
});
this.inputContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px solid #000000'
});
// now let's make sure the highlit div and the textarea will superpose,
// by applying the same font size and stuffs.
// the highlighter must have a white text so it will be invisible
this.highlighter.css({
'padding': '7px',
'color': '#eeeeee',
'background-color': '#ffffff',
'margin': '0px',
'font-size': '11px',
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// the textarea must have a transparent background so we can see the highlight div behind it
this.textarea.css({
'background-color': 'transparent',
'padding': '5px',
'margin': '0px',
'font-size': '11px',
'width': this.options.width,
'height': this.options.height,
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// apply the hooks
this.highlighterContainer.bind('click', function() {
scope.textarea.focus();
});
this.textarea.bind('keyup', function() {
// when we type in the textarea,
// we want the text to be processed and re-injected into the div behind it.
scope.applyText($(this).val());
});
} catch (err) {
this.error(err);
}
return true;
};
pluginClass.prototype.applyText = function (text) {
try {
var scope = this;
// parse the text:
// replace all the line braks by <br/>, and all the double spaces by the html version
text = this.replaceAll(text,'\n','<br/>');
text = this.replaceAll(text,' ',' ');
// replace the words by a highlighted version of the words
for (var i=0;i<this.options.words.length;i++) {
text = this.replaceAll(text,this.options.words[i],'<span style="background-color: #D8DFEA;">'+this.options.words[i]+'</span>');
}
// re-inject the processed text into the div
this.highlighter.html(text);
} catch (err) {
this.error(err);
}
return true;
};
// "replace all" function
pluginClass.prototype.replaceAll = function(txt, replace, with_this) {
return txt.replace(new RegExp(replace, 'g'),with_this);
}
// don't worry about this part, it's just the required code for the plugin to hadle the methods and stuffs. Not relevant here.
//**********************
// process
var fn;
var options;
if (arguments.length == 0) {
fn = "init";
options = {};
} else if (arguments.length == 1 && typeof(arguments[0]) == 'object') {
fn = "init";
options = $.extend({},arguments[0]);
} else {
fn = arguments[0];
options = $.extend({},arguments[1]);
}
$.each(this, function(idx, item) {
// if the component is not yet existing, create it.
if ($(item).data('highlightPlugin') == null) {
$(item).data('highlightPlugin', new pluginClass());
$(item).data('highlightPlugin').__init($(item));
}
$(item).data('highlightPlugin').execute(fn, options);
});
return this;
}
});
})(jQuery);
</script>
</head>
<body>
<div id="container">
<div id="highlighterContainer">
<div id="highlighter">
</div>
</div>
<div id="inputContainer">
<textarea cols="30" rows="10">
</textarea>
</div>
</div>
</body>
</html>
This was written for another post (http://facebook.stackoverflow.com/questions/7497824/how-to-highlight-friends-name-in-facebook-status-update-box-textarea/7597420#7597420), but it seems to be what you're searching for.

Easy script I wrote for this: Jsfiddle
OPTIONS:
Optional char counter.
Highlight several patterns with different colors.
Regex.
Collect matches to other containers.
Easy styling: fonts color and face, backgrounds, border radius and lineheight.
Ctrl+Shift for direction change.
//include function like in the fiddle!
//CREATE ELEMENT:
create_bind_textarea_highlight({
eleId:"wrap_all_highlighter",
width:400,
height:110,
padding:5,
background:'white',
backgroundControls:'#585858',
radius:5,
fontFamilly:'Arial',
fontSize:13,
lineHeight:18,
counterlettres:true,
counterFont:'red',
matchpatterns:[["(#[0-9A-Za-z]{0,})","$1"],["(#[0-9A-Za-z]{0,})","$1"]],
hightlightsColor:['#00d2ff','#FFBF00'],
objectsCopy:["copy_hashes","copy_at"]
//PRESS Ctrl + SHIFT for direction swip!
});
//HTML EXAMPLE:
<div id="wrap_all_highlighter" placer='1'></div>
<div id='copy_hashes'></div><!--Optional-->
<div id='copy_at'></div><!--Optional-->
Have Fun!

Improved version from above, also works with Regex and more TextArea fields:
<html>
<head>
<title></title>
<!-- Load jQuery -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<!-- The javascript xontaining the plugin and the code to init the plugin -->
<script type="text/javascript">
$(function() {
// let's init the plugin, that we called "highlight".
// We will highlight the words "hello" and "world",
// and set the input area to a widht and height of 500 and 250 respectively.
$("#container0").highlight({
words: [["hello","hello"],["world","world"],["(\\[b])(.+?)(\\[/b])","$1$2$3"]],
width: 500,
height: 125,
count:0
});
$("#container1").highlight({
words: [["hello","hello"],["world","world"],["(\\[b])(.+?)(\\[/b])","$1$2$3"]],
width: 500,
height: 125,
count: 1
});
});
// the plugin that would do the trick
(function($){
$.fn.extend({
highlight: function() {
// the main class
var pluginClass = function() {};
// init the class
// Bootloader
pluginClass.prototype.__init = function (element) {
try {
this.element = element;
} catch (err) {
this.error(err);
}
};
// centralized error handler
pluginClass.prototype.error = function (e) {
// manage error and exceptions here
//console.info("error!",e);
};
// Centralized routing function
pluginClass.prototype.execute = function (fn, options) {
try {
options = $.extend({},options);
if (typeof(this[fn]) == "function") {
var output = this[fn].apply(this, [options]);
} else {
this.error("undefined_function");
}
} catch (err) {
this.error(err);
}
};
// **********************
// Plugin Class starts here
// **********************
// init the component
pluginClass.prototype.init = function (options) {
try {
// the element's reference ( $("#container") ) is stored into "this.element"
var scope = this;
this.options = options;
// just find the different elements we'll need
this.highlighterContainer = this.element.find('#highlighterContainer'+this.options.count);
this.inputContainer = this.element.find('#inputContainer'+this.options.count);
this.textarea = this.inputContainer.find('textarea');
this.highlighter = this.highlighterContainer.find('#highlighter'+this.options.count);
// apply the css
this.element.css({'position':'relative',
'overflow':'auto',
'background':'none repeat scroll 0 0 #FFFFFF',
'height':this.options.height+2,
'width':this.options.width+19,
'border':'1px solid'
});
// place both the highlight container and the textarea container
// on the same coordonate to superpose them.
this.highlighterContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '1px dashed #ff0000',
'width': this.options.width,
'height': this.options.height,
'cursor': 'text',
'z-index': '1'
});
this.inputContainer.css({
'position': 'absolute',
'left': '0',
'top': '0',
'border': '0px solid #000000',
'z-index': '2',
'background': 'none repeat scroll 0 0 transparent'
});
// now let's make sure the highlit div and the textarea will superpose,
// by applying the same font size and stuffs.
// the highlighter must have a white text so it will be invisible
var isWebKit = navigator.userAgent.indexOf("WebKit") > -1,
isOpera = navigator.userAgent.indexOf("Opera") > -1,
isIE /*#cc_on = true #*/,
isIE6 = isIE && !window.XMLHttpRequest; // Despite the variable name, this means if IE lower than v7
if (isIE || isOpera){
var padding = '6px 5px';
}
else {
var padding = '5px 6px';
}
this.highlighter.css({
'padding': padding,
'color': '#eeeeee',
'background-color': '#ffffff',
'margin': '0px',
'font-size': '11px' ,
'line-height': '12px' ,
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif'
});
// the textarea must have a transparent background so we can see the highlight div behind it
this.textarea.css({
'background-color': 'transparent',
'padding': '5px',
'margin': '0px',
'width': this.options.width,
'height': this.options.height,
'font-size': '11px',
'line-height': '12px' ,
'font-family': '"lucida grande",tahoma,verdana,arial,sans-serif',
'overflow': 'hidden',
'border': '0px solid #000000'
});
// apply the hooks
this.highlighterContainer.bind('click', function() {
scope.textarea.focus();
});
this.textarea.bind('keyup', function() {
// when we type in the textarea,
// we want the text to be processed and re-injected into the div behind it.
scope.applyText($(this).val());
});
scope.applyText(this.textarea.val());
} catch (err) {
this.error(err)
}
return true;
};
pluginClass.prototype.applyText = function (text) {
try {
var scope = this;
// parse the text:
// replace all the line braks by <br/>, and all the double spaces by the html version
text = this.replaceAll(text,'\n','<br/>');
text = this.replaceAll(text,' ',' ');
text = this.replaceAll(text,' ',' ');
// replace the words by a highlighted version of the words
for (var i=0;i<this.options.words.length;i++) {
text = this.replaceAll(text,this.options.words[i][0],'<span style="background-color: #D8DFEA;">'+this.options.words[i][1]+'</span>');
//text = this.replaceAll(text,'(\\[b])(.+?)(\\[/b])','<span style="font-weight:bold;background-color: #D8DFEA;">$1$2$3</span>');
}
// re-inject the processed text into the div
this.highlighter.html(text);
if (this.highlighter[0].clientHeight > this.options.height) {
// document.getElementById("highlighter0")
this.textarea[0].style.height=this.highlighter[0].clientHeight +19+"px";
}
else {
this.textarea[0].style.height=this.options.height;
}
} catch (err) {
this.error(err);
}
return true;
};
// "replace all" function
pluginClass.prototype.replaceAll = function(txt, replace, with_this) {
return txt.replace(new RegExp(replace, 'g'),with_this);
}
// don't worry about this part, it's just the required code for the plugin to hadle the methods and stuffs. Not relevant here.
//**********************
// process
var fn;
var options;
if (arguments.length == 0) {
fn = "init";
options = {};
} else if (arguments.length == 1 && typeof(arguments[0]) == 'object') {
fn = "init";
options = $.extend({},arguments[0]);
} else {
fn = arguments[0];
options = $.extend({},arguments[1]);
}
$.each(this, function(idx, item) {
// if the component is not yet existing, create it.
if ($(item).data('highlightPlugin') == null) {
$(item).data('highlightPlugin', new pluginClass());
$(item).data('highlightPlugin').__init($(item));
}
$(item).data('highlightPlugin').execute(fn, options);
});
return this;
}
});
})(jQuery);
</script>
</head>
<body>
<div id="container0">
<div id="highlighterContainer0">
<div id="highlighter0"></div>
</div>
<div id="inputContainer0">
<textarea id="text1" cols="30" rows="15">hello world</textarea>
</div>
</div>
<h1> haus </h1>
<div id="container1">
<div id="highlighterContainer1">
<div id="highlighter1"></div>
</div>
<div id="inputContainer1">
<textarea cols="30" rows="15">hipp hipp
hurra,
[b]ich hab es jetzt![/b]</textarea>
</div>
</div>
</body>

Related

Highlight images on page when the user clicks on them

I want to add CSS style with JavaScript: "padding", "background", and "border" to the image clicked by the user, when the user clicks again on that image, the highlight effect is removed.
var imagesProp = {
'padding': '3px',
'backgroundColor': '#eded01',
'borderSize': '1ps',
'borderStyle': 'dashed',
'borderColor': '#0001fe'
};
function highlightimages() {
var allimages = document.getElementsByid('images');
//How do i start from here
}
var imagesProp = {
'padding': '3px',
'backgroundColor': '#eded01',
'borderSize': '1ps',
'borderStyle': 'dashed',
'borderColor': '#0001fe'
};
function highlightImages() {
//You do not use getElementsByid but getElementsByTagName
var allimages = document.getElementsByTagName('img');
var nrallimgs = allimages.length;
// traverses the <img> elements, and register onclick to each one
// else, apply the properties defined in $imagesProp
for(i=0; i<nrallimgs; i++) {
allimages[i].onclick=function() {
if(this.style.borderStyle == imagesProp.borderStyle) {
this.style.padding = 'auto';
this.style.background = 'none';
this.style.border = 'none';
}
else {
this.style.padding = imagesProp.padding;
this.style.backgroundColor = imagesProp.backgroundColor;
this.style.borderSize = imagesProp.borderSize;
this.style.borderStyle = imagesProp.borderStyle;
this.style.borderColor = imagesProp.borderColor;
}
}
}
}
// calls the highlightImages() function to apply the effect
highlightImages();
Create a css class
highlighted {
padding: '3px';
backgroundColor: '#eded01';
borderSize: '1ps';
borderStyle: 'dashed';
borderColor: '#0001fe'
}
Using jQuery:
var $element = $('#elementid');
$element.click(function () {
$(this).toogleClass('highligted');
});

Access written Text in QuillJS

I am using Quill JS as a rich text editor. I want to be able to highlight specific words in the text, if the user clicks a button. But it seems as Quill JS does not give permission to edit its contents by another plugin (?)
I tried Mark.js and Highlight.js, but they will only work on elements which are not in the Quill JS editor. The trigger seems to work though, since the line with the correct keyword flashes in Firefox Inspector, like there is something accessing that line, but in the browser there is no real change.
I posted a little example code (please ignore the first part of the Javascript since it is just the highlight.js plugin I had to put there. My custom code is at the very end):
$( document ).ready(function() {
// My custom code is at the very end. This is the highlight.js plugin code:
// Copyright (c) 2009 Bartek Szopka
jQuery.extend({
highlight: function (node, re, nodeName, className) {
if (node.nodeType === 3) {
var match = node.data.match(re);
if (match) {
var highlight = document.createElement(nodeName || 'span');
highlight.className = className || 'highlight';
var wordNode = node.splitText(match.index);
wordNode.splitText(match[0].length);
var wordClone = wordNode.cloneNode(true);
highlight.appendChild(wordClone);
wordNode.parentNode.replaceChild(highlight, wordNode);
return 1; //skip added node in parent
}
} else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
!/(script|style)/i.test(node.tagName) && // ignore script and style nodes
!(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
for (var i = 0; i < node.childNodes.length; i++) {
i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
}
}
return 0;
}
});
jQuery.fn.unhighlight = function (options) {
var settings = { className: 'highlight', element: 'span' };
jQuery.extend(settings, options);
return this.find(settings.element + "." + settings.className).each(function () {
var parent = this.parentNode;
parent.replaceChild(this.firstChild, this);
parent.normalize();
}).end();
};
jQuery.fn.highlight = function (words, options) {
var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
jQuery.extend(settings, options);
if (words.constructor === String) {
words = [words];
}
words = jQuery.grep(words, function(word, i){
return word != '';
});
words = jQuery.map(words, function(word, i) {
return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
});
if (words.length == 0) { return this; };
var flag = settings.caseSensitive ? "" : "i";
var pattern = "(" + words.join("|") + ")";
if (settings.wordsOnly) {
pattern = "\\b" + pattern + "\\b";
}
var re = new RegExp(pattern, flag);
return this.each(function () {
jQuery.highlight(this, re, settings.element, settings.className);
});
};
// -------------------------------------------------------------------------
// My custom code
// -------------------------------------------------------------------------
// Initialize Quill editor options
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
];
// Setup Quill editor
var options = {
modules: {
toolbar: toolbarOptions
},
placeholder: 'Start writing demo and another word then hit the green div...',
theme: 'snow'
};
var editor = new Quill('#editor', options);
// Use highlight js to highlight every "demo" in the text
$("#clicker").on("click", function() {
$("p").highlight("demo");
});
});
#clicker {
background-color: #ddffdd;
display: block;
padding: 32px;
text-align: center;
}
.highlight {
background-color: #FFFF88;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Prototype</title>
<meta name="description" content="This is a demo page.">
<link href="https://cdn.quilljs.com/1.1.5/quill.snow.css" rel="stylesheet">
<script type="text/javascript" src="https://cdn.quilljs.com/1.1.5/quill.js"></script>
</head>
<body>
<div id="clicker" style="cursor: pointer">Mark "demo" in Text by clicking here</div>
<main>
<div id="editor"></div>
<div>
<p>demo outside of editor</p>
</div>
</main>
</body>
</html>
Arbitrary changes through DOM APIs are not supported. To make changes to Quill's editor contents, you have to use its API. This Cloning Medium with Parchment guide is useful for creating new formats like what you are describing.

Select box to appear inside jQuery Dialog on image click

I am trying to modify this example http://waynegm.github.io/imgNotes/examples/basic_interactive.html#
in order to get a select option to appear inside the dialog box when user clicks on the image. Currently the code places a marker on the area the user selects when in edit mode and opens a dialog box allowing them to enter text, with the options to save / cancel.
Inside the dialog box I want to change the textarea to a select list like:
<select>
<option value="head">Head</option>
<option value="leftarm">Left Arm</option>
<option value="rightarm">Right Arm</option>
<option value="leg">Leg</option>
</select>
It seems like it should be a simple change, I have made others samples where simple on image click makes the drop down appear. But this example has everything else I need like the options to delete and recording the co-ords of the place marker.
The current HTML:
<html>
<head>
<title>jQuery imgNotes - Interactive Base</title>
<style type="text/css" media="all">#import "css/marker.css";</style>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" media="screen">
<script type="text/javascript" src="src/imgNotes.js"></script>
</head>
<body>
<div id="imgdiv" style="text-align: center">
<img id="image" src="image/personsit.jpg" style="border: 30px solid #ccc; padding:20px;" width=400/>
<br/>
<button id="toggleEdit">Edit</button> <button id="export">Export</button>
</div>
<div id=txt></div>
<script type="text/javascript">
;(function($) {
$(document).ready(function() {
var $img = $("#image").imgNotes();
//$img.imgNotes("import", [ {x: "0.5", y:"0.5", note:"AFL Grand Final Trophy"},
// {x: "0.4", y:"0.269", note: "Shoulder"},
// {x: "0.824", y: "0.593", note: "Fluffy microphone"}]);
var $toggle = $("#toggleEdit");
if ($img.imgNotes("option","canEdit")) {
$toggle.text("View");
} else {
$toggle.text("Edit");
}
$toggle.on("click", function() {
var $this = $(this);
if ($this.text()=="Edit") {
$this.text("View");
$img.imgNotes("option", "canEdit", true);
} else {
$this.text('Edit');
$img.imgNotes('option', 'canEdit', false);
}
});
var $export = $("#export");
$export.on("click", function() {
var $table = $("<table/>").addClass("gridtable");
var notes = $img.imgNotes('export');
$table.append("<th>X</th><th>Y</th><th>NOTE</th>");
$.each(notes, function(index, item) {
$table.append("<tr><td>" + item.x + "</td><td>" + item.y + "</td><td>" + item.note + "</td></tr>");
});
$('#txt').html($table);
});
});
})(jQuery);
</script>
</body>
</html>
imgNotes.js file
;(function($) {
$.widget("wgm.imgNotes", {
options: {
zoom: 1,
zoomStep: 0.1,
zoomable: true,
canEdit: false,
vAll: "middle",
hAll: "middle",
/*
* Default callback to create a marker indicating a note location
* See the examples for more elaborate alternatives.
*/
onAdd: function() {
this.options.vAll = "bottom";
this.options.hAll = "middle";
return $(document.createElement('span')).addClass("marker black").html(this.noteCount);
},
/*
* Default callback when the marker is clicked and the widget has canEdit = true
* Opens a dialog with a textarea to write a note.
* See the examples for a more elaborate alternative that includes a WYSIWYG editor
*/
onEdit: function(ev, elem) {
var $elem = $(elem);
$("#dialog-2").remove();
return $('<div id="dialog-2"></div>').dialog({
title: "Body Parts",
resizable: false,
modal: true,
height: "300",
width: "450",
position: { my: "left bottom", at: "right top", of: elem},
buttons: {
"Save": function() {
var txt = $('textarea', this).val();
// Put the editied note back into the data area of the element
// Very important that this step is included in custom callback implementations
$elem.data("note", txt);
$(this).dialog("close");
},
"Delete": function() {
$elem.trigger("remove");
$(this).dialog("close");
},
Cancel: function() {
$(this).dialog("close");
}
},
open: function() {
$(this).css("overflow", "hidden");
var textarea = $('<textarea id="txt" style="height:100%; width:100%;">');
$(this).html(textarea);
// Get the note text and put it into the textarea for editing
textarea.val($elem.data("note"));
}
})
},
/*
* Default callback when the marker is clicked and the widget has canEdit = false
* Opens a dialog displaying the contents of the marker's note
* See examples for alternatives such as using tooltips.
*/
onShow: function(ev, elem) {
var $elem = $(elem);
$('#NoteDialog').remove();
return $('<div id="NoteDialog"></div>').dialog({
modal: false,
resizable: false,
height: 300,
width: 250,
position: { my: "left bottom", at: "right top", of: elem},
buttons: {
"Close" : function() {
$(this).dialog("close");
}
},
open: function() {
// Get the note text and put it into the textarea for editing
$(this).html($elem.data("note"));
$(this).closest(".ui-dialog").find(".ui-dialog-titlebar:first").hide();
},
close: function() {
$(this).dialog("destroy");
}
});
},
/*
* Default callback when the markers are repainted
*/
onUpdateMarker: function(elem) {
var $elem = $(elem);
var $img = $(this.img);
var pos = $img.imgViewer("imgToView", $elem.data("relx"), $elem.data("rely"));
if (pos) {
$elem.css({
left: (pos.x - $elem.data("xOffset")),
top: (pos.y - $elem.data("yOffset")),
position: "absolute"
});
}
},
/*
* Default callback when the image view is repainted
*/
onUpdate: function() {
var self = this;
$.each(this.notes, function() {
self.options.onUpdateMarker.call(self, this);
});
}
},
_create: function() {
var self = this;
if (!this.element.is("img")) {
$.error('imgNotes plugin can only be applied to img elements');
}
// the note/marker elements
self.notes = [];
// the number of notes
self.noteCount = 0;
// the original img element
self.img = self.element[0];
var $img = $(self.img);
// attach the imgViewer plugin for zooming and panning with a custon click and update callbacks
$img.imgViewer({
onClick: function(ev, imgv) {
if (self.options.canEdit) {
ev.preventDefault();
var rpos = imgv.cursorToImg(ev.pageX, ev.pageY);
if (rpos) {
var elem = self.addNote(rpos.x, rpos.y);
self._trigger("onEdit", ev, elem);
}
}
},
onUpdate: function(ev, imgv) {
self.options.zoom = imgv.options.zoom;
self.options.onUpdate.call(self);
},
zoom: self.options.zoom,
zoomStep: self.options.zoomStep,
zoomable: self.options.zoomable
});
$img.imgViewer("update");
},
/*
* Remove the plugin
*/
destroy: function() {
this.clear();
$(this.img).imgViewer("destroy");
$.Widget.prototype.destroy.call(this);
},
_setOption: function(key, value) {
switch(key) {
case 'vAll':
switch(value) {
case 'top': break;
case 'bottom': break;
default: value = 'middle';
}
break;
case 'hAll':
switch(value) {
case 'left': break;
case 'right': break;
default: value = 'middle';
}
break;
}
var version = $.ui.version.split('.');
if (version[0] > 1 || version[1] > 8) {
this._super(key, value);
} else {
$.Widget.prototype._setOption.apply(this, arguments);
}
switch(key) {
case 'zoom':
$(this.img).imgViewer("option", "zoom", value);
break;
case 'zoomStep':
$(this.img).imgViewer("option", "zoomStep", value);
break;
case 'zoomable':
$(this.img).imgViewer("option", "zoomable", value);
break;
}
},
/*
* Pan the view to be centred at the given relative image location
*/
panTo: function(relx, rely) {
return $(this.img).imgViewer("panTo", relx, rely);
},
/*
* Add a note
*/
addNote: function(relx, rely, text) {
var self = this;
this.noteCount++;
var elem = this.options.onAdd.call(this);
var $elem = $(elem);
$(this.img).imgViewer("addElem",elem);
$elem.data("relx", relx).data("rely", rely).data("note", text);
switch (this.options.vAll) {
case "top": $elem.data("yOffset", 0); break;
case "bottom": $elem.data("yOffset", $elem.height()); break;
default: $elem.data("yOffset", Math.round($elem.height()/2));
}
switch (this.options.hAll) {
case "left": $elem.data("xOffset", 0); break;
case "right": $elem.data("xOffset", $elem.width()); break;
default: $elem.data("xOffset", Math.round($elem.width()/2));
}
$elem.click(function(ev) {
ev.preventDefault();
if (self.options.canEdit) {
self._trigger("onEdit", ev, elem);
} else {
self._trigger("onShow", ev, elem);
}
});
$elem.on("remove", function() {
self._delete(elem);
});
this.notes.push(elem);
$(this.img).imgViewer("update");
return elem;
},
/*
* Number of notes
*/
count: function() {
return this.noteCount;
},
/*
* Delete a note
*/
_delete: function(elem) {
this.notes = this.notes.filter(function(v) { return v!== elem; });
$(elem).off();
$(elem).remove();
$(this.img).imgViewer("update");
},
/*
* Clear all notes
*/
clear: function() {
var self = this;
var total = self.notes.length;
for ( var i = 0; i < total; i++ ){
var $this = self.notes[i];
$this.off();
$this.remove();
}
self.notes=[];
self.noteCount = 0;
},
/*
* Add notes from a javascript array
*/
import: function(notes) {
var self = this;
$.each(notes, function() {
self.addNote(this.x, this.y, this.note);
});
$(this.img).imgViewer("update");
},
/*
* Export notes to an array
*/
export: function() {
var notes = [];
$.each(this.notes, function() {
var $elem = $(this);
notes.push({
x: $elem.data("relx"),
y: $elem.data("rely"),
note: $elem.data("note")
});
});
return notes;
}
});
})(jQuery);
I would really appreciate if anyone could help me out.

JqvMap onRegionClick (bootstrap) PopOver fires only clicking twice

I am using JqvMap and I want to click on a region and this shall prompt a (bootstrap) popover with the name of the country as title, and the content should be some html links. This is my code:
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#vmap').vectorMap({
map: 'world_en',
backgroundColor: '#333333',
color: '#ffffff',
hoverOpacity: 0.7,
selectedColor: '#666666',
enableZoom: true,
showTooltip: false,
values: sample_data,
scaleColors: ['#C8EEFF', '#006491'],
normalizeFunction: 'polynomial',
regionsSelectableOne: 'true',
onRegionClick: function(element, code, region) {
$(".popover-title").html(region);
jQuery('.jvectormap-region').popover({
placement: 'top',
container: '#vmap',
content: 'page 1</br>page 2</br>page 3</br>page 4</br>',
trigger: 'click',
html: 'true',
title: ' '
});
},
onRegionOver: function (event, code, region) {
document.body.style.cursor = "pointer";
},
onRegionOut: function (element, code, region) {
document.body.style.cursor = "default";
$('.jvectormap-region').popover('destroy');
// $('#vmap').vectorMap('deselect', code);
}
});
});
</script>
My problem at the moment is that I need to click twice on the map to make popover show up. I read it may be due to the fact that it is not initialized, but I can't seem to initialize it (where? how?)!
Can someone help me with these issues? I can't seem to figure out what the problem is..
So I kinda fixed it (probably in a nasty way but it does the trick).
Hope it will help someone else.
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#vmap').vectorMap({
map: 'world_en',
backgroundColor: '#333333',
color: '#ffffff',
hoverOpacity: 0.7,
selectedColor: '#666666',
enableZoom: true,
showTooltip: false,
values: sample_data,
scaleColors: ['#C8EEFF', '#006491'],
normalizeFunction: 'polynomial',
regionsSelectableOne: true,
});
runPopOver();
});
</script>
<script type="text/javascript">
function runPopOver() {
var currentRegion;
jQuery('#vmap').bind('regionMouseOver.jqvmap',
function(event, code, region) {
document.body.style.cursor = "pointer";
currentRegion = region;
}
);
jQuery('#vmap').bind('regionMouseOut.jqvmap',
function(event, code, region) {
document.body.style.cursor = "default";
}
);
jQuery('#vmap').bind('regionClick.jqvmap',
function(event, code, region) {
if ($('#vmap [id^="popover"]').length > 1) {
$('#vmap [id^="popover"]').first().remove();
}
var snapshot_url = "http://www.business-anti-corruption.com/country-profiles/europe-central-asia/" + region + "/snapshot.aspx";
$(".popover-title").html(region);
$(".popover-content").html('Snapshot</br>page 2</br>page 3</br>page 4</br>');
}
);
jQuery('.jvectormap-region').popover({
placement: 'left',
container: '#vmap',
html: 'true',
title: ' '
});
}
</script>
So basically when I click on a region if there is more than 1 popover (even to be opened) I get a list of all the popover (2), take the first and remove it from the DOM (.first().remove()).
Here's a more permanent fix:
in the jquery.vmap.js find this bit of code:
jQuery(params.container).delegate(this.canvas.mode == 'svg' ? 'path' : 'shape', 'click', function (e) {
if (!params.multiSelectRegion) {
for (var key in mapData.pathes) {
map.countries[key].currentFillColor = map.countries[key].getOriginalFill();
map.countries[key].setFill(map.countries[key].getOriginalFill());
}
}
var path = e.target;
var code = e.target.id.split('_').pop();
jQuery(params.container).trigger('regionClick.jqvmap', [code, mapData.pathes[code].name]);
if (!regionClickEvent.isDefaultPrevented()) {
if (map.selectedRegions.indexOf(code) !== -1) {
map.deselect(code, path);
} else {
map.select(code, path);
}
}
//console.log(selectedRegions);
});
Replace it with this:
jQuery(params.container).delegate(this.canvas.mode == 'svg' ? 'path' : 'shape', 'mousedown mouseup', function (e) {
var PageCoords;
if (e.type == 'mousedown') {
pageCoords = event.pageX + "." + event.pageY;
}
if (e.type == 'mouseup') {
var pageCoords2 = event.pageX + "." + event.pageY;
if (pageCoords == pageCoords2) {
//we have a click. Do the ClickEvent
if (!params.multiSelectRegion) {
for (var key in mapData.pathes) {
map.countries[key].currentFillColor = map.countries[key].getOriginalFill();
map.countries[key].setFill(map.countries[key].getOriginalFill());
}
}
var path = e.target;
var code = e.target.id.split('_').pop();
regionClickEvent = $.Event('regionClick.jqvmap');
jQuery(params.container).trigger('regionClick.jqvmap', [code, mapData.pathes[code].name]);
if (!regionClickEvent.isDefaultPrevented()) {
if (map.selectedRegions.indexOf(code) !== -1) {
map.deselect(code, path);
} else {
map.select(code, path);
}
}
}
}
Instead of triggering a click immediately, the script now checks if it's a click or a drag. If it's a click, it fires the code you put in our onRegionClick.

textarea autogrow functionality jitters with every keystroke

I was playing around with the jquery autogrow plugin, which expands the height of the text automatically as the text needs it. The problem is that with every key down, the bottom border of the textarea jitters in a noticeable way. I'm not sure what the problem could be, so I'm going to go out on a limb and post the 132 lines of this GPL plugin here. Any hints where the problem could be or how to circumvent it?
/*
Auto Expanding Text Area (1.2.2) by Chrys Bader */
(function(jQuery) {
var self = null;
jQuery.fn.autogrow = function(o){
return this.each(function() {
new jQuery.autogrow(this, o);
});
};
/**
* The autogrow object.
*
* #constructor
* #name jQuery.autogrow
* #param Object e The textarea to create the autogrow for.
* #param Hash o A set of key/value pairs to set as configuration properties.
* #cat Plugins/autogrow
*/
jQuery.autogrow = function (e, o) {
this.options = o || {};
this.dummy = null;
this.interval = null;
this.line_height = this.options.lineHeight || parseInt(jQuery(e).css('line-height'));
this.min_height = this.options.minHeight || parseInt(jQuery(e).css('min-height'));
this.max_height = this.options.maxHeight || parseInt(jQuery(e).css('max-height'));;
this.textarea = jQuery(e);
if(this.line_height == NaN) this.line_height = 0;
// Only one textarea activated at a time, the one being used
this.init();
};
jQuery.autogrow.fn = jQuery.autogrow.prototype = { autogrow: '1.2.2' };
jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend;
jQuery.autogrow.fn.extend({ init: function(){
var self = this;
this.textarea.css({overflow: 'hidden', display: 'block'});
this.textarea.bind('focus', function(){ self.startExpand() }).bind('blur', function() { self.stopExpand() });
this.checkExpand();
},
startExpand: function() {
var self = this;
this.interval = window.setInterval(function() { self.checkExpand()}, 400); },
stopExpand: function() { clearInterval(this.interval); },
checkExpand: function() {
if (this.dummy == null) {
this.dummy = jQuery('<div></div>');
this.dummy.css({
'font-size' : this.textarea.css('font-size'),
'font-family': this.textarea.css('font-family'),
'width' : this.textarea.css('width'),
'padding' : this.textarea.css('padding'),
'line-height': this.line_height + 'px',
'overflow-x' : 'hidden',
'position' : 'absolute',
'top' : 0,
'left' : -9999
}).appendTo('body');
}
// Strip HTML tags
var html = this.textarea.val().replace(/(<|>)/g,'');
// IE is different, as per usual
if ($.browser.msie){
html = html.replace(/\n/g, '<BR>new');
} else {
html = html.replace(/\n/g, '<br>new');
}
if (this.dummy.html() != html){
this.dummy.html(html);
if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height)){
this.textarea.css('overflow-y', 'auto');
} else {
this.textarea.css('overflow-y', 'hidden');
if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height())) {
this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100);
}
}
}
}
});
})(jQuery);
In regard to jeerose's comment:
http://www.aclevercookie.com/aclevercookiecom-breached-problem-resolved/
It has been brought to my attention by
visitors that their virus protection
goes off when they come to this blog.
I investigated the matter and found
that harmful code had been injected
into the source of the site.
This has been resolved and measures
have been taken to increase the
security of the site.
Thanks for the report, and I apologize
for the alarm.
Which doesn't seem to be true. As my antivirus still fires when opening that site

Categories

Resources