JqvMap onRegionClick (bootstrap) PopOver fires only clicking twice - javascript

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.

Related

Select multiple classes with attr. with jQuery

I have a function that I use for an interactive map, where I hover an element to show a specific region based on class that matches a country suffix. Im trying to figure out how to select multiple classes to show multiple regions.
Code:
var mapObj = jQuery('#vmap').data('mapObject');
jQuery('#countries').on('mouseover mouseout', 'a:first-child', function (event) {
// event.preventDefault();
var elem = event.target,
evtype = event.type;
if (evtype === 'mouseover') {
mapObj.select(jQuery(elem).attr('class'));
} else {
mapObj.deselect(jQuery(elem).attr('class'));
};
});
};
<ul id="countries">
<li><a class="SE" href="">Sweden</a></li>
<li><a class="DK" href="">Denmark</a></li>
</ul>
I might going this the wrong way, but I would like to target mutiple regions by using several classes:
<li><a class="SE DK" href="">Sweden and Denmark</a></li>
This of course doesn't work but illustrates what I want to do. whats the best approach here?
Example:
jQuery('#vmap').vectorMap({
map: 'world_en',
onLabelShow: function (event, label, code) {
if (code == 'se') {
var countryName = label[0].innerHTML;
var html = ['<span class="tooltip-up arrow-down-center">',
countryName,
': 50% of production',
'</span>'
].join("");
label[0].innerHTML = html;
}
},
backgroundColor: '#fff',
enableZoom: false,
color: '#ffffff',
hoverOpacity: 0.7,
selectedColor: '#666666',
showTooltip: true,
values: sample_data,
scaleColors: ['#C8EEFF', '#006491'],
normalizeFunction: 'polynomial',
pinMode: 'content',
regionsSelectableOne: false,
regionsSelectable: false,
series: {
regions: [{
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial'
}]
}
});
var mapObj = jQuery('#vmap').data('mapObject');
jQuery('#countries').on('mouseover mouseout', 'a:first-child', function (event) {
// event.preventDefault();
var elem = event.target,
evtype = event.type;
if (evtype === 'mouseover') {
mapObj.select(jQuery(elem).attr('class'));
} else {
mapObj.deselect(jQuery(elem).attr('class'));
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://www.10bestdesign.com/jqvmap/assets/jqvmaps/jqvmap.css" media="screen" rel="stylesheet" type="text/css">
<script src="https://www.10bestdesign.com/jqvmap/assets/jqvmaps/jquery.vmap.js"></script>
<script src="https://www.10bestdesign.com/jqvmap/assets/jqvmaps/maps/jquery.vmap.world.js"></script>
<script src="https://www.10bestdesign.com/jqvmap/assets/jqvmaps/jquery.vmap.sampledata.js"></script>
<div id="vmap" style="width: 800px; height: 400px;"></div>
<ul id="countries">
<li><a class="SE" href="">Sweden</a></li>
<li><a class="DK" href="">Denmark</a></li>
<li><a class="SE DK" href="">Sweden and Denmark</a></li>
</ul>
You can modify your select/deselect function to accept array of classes, or instead loop the classes and invoke select/deselect for each class name:
var mapObj = jQuery('#vmap').data('mapObject');
jQuery('#countries').on('mouseover mouseout', 'a:first-child', function (event) {
var elem = event.target;
var countryCodes = jQuery(elem).attr('class').split(/\s+/);
evtype = event.type;
if (evtype === 'mouseover') {
jQuery.each(countryCodes, function(index, code) {
mapObj.select(code);
});
} else {
jQuery.each(countryCodes, function(index, code) {
if (mapObj.isSelected(code)) {
mapObj.deselect(code);
} else {
mapObj.select(code);
mapObj.deselect(code);
}
});
};
});
you can split each class and put in foreach loop so all element will target where that class is exist
var mapObj = jQuery('#vmap').data('mapObject');
jQuery('#countries').on('mouseover mouseout', 'a:first-child', function (event) {
// event.preventDefault();
var elem = event.target,
evtype = event.type;
var attrClass = jQuery(elem).attr('class');
var claArr = attrClass.slit(" ");
jQuery(claArr).each(function(index,values){
if (evtype === 'mouseover') {
mapObj.select(values);
} else {
mapObj.deselect(values);
};
});
if (evtype === 'mouseover') {
mapObj.select(jQuery(elem).attr('class'));
} else {
mapObj.deselect(jQuery(elem).attr('class'));
};
});
};

Positioning of jQuery tooltip

I´m using the jQuery UI tooltip plugin.
How can I change the tooltip position depending on the windows´ resolution?
At the moment I still need to reload the browser so the script takes effect. It can´t adjust the position in real time when changing the browser windows´ size
var res = $(window).width();
var arr = {};
if(res < 960){
arr = {my: "left+3 bottom-3", of: event, collision:"fit"};
}else{
arr = {my: "left+153 top+20", collision: "flipfit" };
}
init_tooltip(arr);
function init_tooltip(param){
$('*[data-id]').tooltip({
tooltipClass: "tooltipitem",
content: '<div class="loading">Laden...</p>',
hide: {
effect: "slideData",
delay: 0
},
position: arr,
});
}
$('*[data-id]').hover(function (event, ui) {
let $tooltip = $(this);
let id = $tooltip.attr("data-id");
ajaxManager.add({
url: "../datenbank/itemscript.php",
type: "GET",
cache: "true",
data: {
"var": id
},
success: function (data) {
console.log(data);
$tooltip.tooltip({
content: data
});
}
});
});
You could use ternary operator:
var res = $(window).width();
$('*[data-id]').tooltip({
tooltipClass: "tooltipitem",
content: '<div class="loading">Laden...</p>',
hide: {
effect: "slideData",
delay: 0
},
position: (res < 960 ? {my: "left+3 bottom-3", of: event, collision:"fit"} : { my: "left+153 top+20", collision: "flipfit" }),
});
or classic if else
var res = $(window).width();
function init_tooltip(param){
$('*[data-id]').tooltip({
tooltipClass: "tooltipitem",
content: '<div class="loading">Laden...</p>',
hide: {
effect: "slideData",
delay: 0
},
position: param,
});
}
to trap the change of window width:
$(window).resize(checkWidth);
checkWidth();
function init_tooltip(param){
$('*[data-id]').tooltip({
tooltipClass: "tooltipitem",
content: '<div class="loading">Laden...</p>',
hide: {
effect: "slideData",
delay: 0
},
position: param,
});
}
function checkWidth(){
var res = $(window).width()
var arr = {};
if(res < 960){
arr = {my: "left+3 bottom-3", of: event, collision:"fit"};
}else{
arr = {my: "left+153 top+20", collision: "flipfit" };
}
init_tooltip(arr);
}

Script doesn't work on elements loaded with infinite scrolling

I'm using this script on my tumblr page, which gives posts different random text colors:
function get_random_color() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;}
$(function() {
$(".post").each(function() {
$(this).css("color", get_random_color());
}); });
The thing is the script isn't working for elements loaded with infinite scrolling. Can anyone help me rewrite this code? I don't know how to write javascript sadly.
Take a look at your blog's main.js script. You can call your custom function when you grab the new elements from another page. This is my proposed revision of your main.js file.
$(window).load(function () {
var $wall = $('#content');
$wall.imagesLoaded(function () {
$wall.masonry({
itemSelector: '.post',
isAnimated: false
});
});
$wall.infinitescroll({
navSelector: '#pagination',
nextSelector: '#pagination li a.pagination_nextlink',
itemSelector: '.post',
loadingImg: "http://static.tumblr.com/kwz90l7/bIdlst7ub/transparent.png",
loadingText: " ",
donetext: " ",
bufferPx: 100,
debug: false,
errorCallback: function () {
$('#infscr-loading').animate({
opacity: .8
}, 2000).fadeOut('normal');
}
}, function (newElements) {
var $newElems = $(newElements);
$newElems.hide();
$newElems.each(function(value){
value.css("color", get_random_color());
});
$newElems.imagesLoaded(function () {
$wall.masonry('appended', $newElems, {
isAnimated: false,
animationOptions: {
duration: 900,
easing: 'linear',
queue: false
}
}, function () {
$newElems.fadeIn('slow');
});
});
$(document).ready(function () {
$("a[rel^='prettyPhoto']").prettyPhoto({
deeplinking: false,
default_width: 600,
default_height: 550,
allow_resize: true,
});
});
});
$('#content').show(500);
});
function get_random_color() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
What I've done is add your get_random_color function and called it from within the Infinite Scroll call to add a custom color to each of the elements in $newElems so really, all I've done is taken your code and integrated it differently than what you were trying to do, which wasn't working. This should, theoretically, work. If it doesn't or you have questions, let me know.

Flot Stacked Bar Chart and displaying bar values on mouse over

I'm trying to understand the tooltip functionality of Flot but not really getting my head around it!
I am trying to achieve a tooltip that displays the label and value of each section of a stacked bar chart
Would someone be able to point my towards an example of this or provide code for doing so?
The following code works for my Flot stacked bar chart, based on the Flot example that shows data point hover. The trick is that the 'item' values in the stacked chart are cumulative, so the 'y' value displayed in the tool tip has to first subtract the datapoint for the bars underneath.
var previousPoint = null;
$("#chart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint != item.datapoint) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY, y + " " + item.series.label);
}
}
else {
$("#tooltip").remove();
previousPoint = null;
}
});
I did not find this in the Flot documentation, but the item.datapoint array seemed to contain what I needed in practice.
The code above caused redraw-issues for me.
Here is an improved code:
var previousPoint = [0,0,0];
$("#regionsChart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint[0] != item.datapoint[0]
|| previousPoint[1] != item.datapoint[1]
|| previousPoint[2] != item.datapoint[2]
) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY, item.series.label + " " + y.toFixed(0) );
}
}
else {
$("#tooltip").remove();
previousPoint = [0,0,0];
}
});
This is the same as Thomas above, except that I shifted the tooltip up to prevent it blocking the hover action.
var previousPoint = [0,0,0];
$("#regionsChart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint[0] != item.datapoint[0]
|| previousPoint[1] != item.datapoint[1]
|| previousPoint[2] != item.datapoint[2]
) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY - 35, item.series.label + " " + y.toFixed(0) );
}
}
else {
$("#tooltip").remove();
previousPoint = [0,0,0];
}
});
The solution is using tooltipOpts -> content method with a callback function to properly return dynamic data to the label.
I figured out that passing a 4th argument to the callback function of the "tooltipOpts" actually gives you the whole data object from which the chart/graph is constructed from.
From here, you can easily extract the X axis labels, using the second argument of this same function as the index of the label to extract.
EXAMPLE:
Data object I'm passing to the plot function:
[
{ data: [[1,137],[2,194],[3,376],[4,145],[5,145],[6,145],[7,146]] }
],
{
bars: { show: true, fill: true, barWidth: 0.3, lineWidth: 1, fillColor: { colors: [{ opacity: 0.8 }, { opacity: 1}] }, align: 'center' },
colors: ['#fcc100'],
series: { shadowSize: 3 },
xaxis: {
show: true,
font: { color: '#ccc' },
position: 'bottom',
ticks: [[1,'Thursday'],[2,'Friday'],[3,'Saturday'],[4,'Sunday'],[5,'Monday'],[6,'Tuesday'],[7,'Wednesday']]
},
yaxis:{ show: true, font: { color: '#ccc' }},
grid: { hoverable: true, clickable: true, borderWidth: 0, color: 'rgba(120,120,120,0.5)' },
tooltip: true,
tooltipOpts: {
content: function(data, x, y, dataObject) {
var XdataIndex = dataObject.dataIndex;
var XdataLabel = dataObject.series.xaxis.ticks[XdataIndex].label;
return y + ' stories created about your page on ' + XdataLabel
},
defaultTheme: false,
shifts: { x: 0, y: -40 }
}
}
Bar chart rendered from the above data object:
As you can see on the image preview, the logic used to render the label's content dynamically form the actual data is this:
tooltipOpts: {
content: function(data, x, y, dataObject) {
var XdataIndex = dataObject.dataIndex;
var XdataLabel = dataObject.series.xaxis.ticks[XdataIndex].label;
return y + ' stories created about your page on ' + XdataLabel;
},
defaultTheme: false,
shifts: { x: 0, y: -40 }
}

Highlight text inside of a textarea

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>

Categories

Resources