Archive for the ‘javascript’ Category
SMF 2.0 RC3: Flickr HTML code to BBCode mod [working]
We are developing a photographic website (with an SMF 2.0 RC3 forum) and most of our users have their photos hosted in Flickr.
(Note: I have installed WYSIWYG Quick Reply v2 RC3 package)
So I’d like to make their lifes easier when sharing their photos by adding a custom button (here in the post wysiwyg editor) which converts this html structure (the code snippet flickr shows to the user):
<a href="URL1" title="this_is_the_title"><img src="IMGURL" width="342" height="500" alt="alt_text" /></a>
To something like:
[url=URL1][img]IMGURL[/img][/url]
How to do this?
* Edit your Themes/default/GenericControls.template.php
* Locate:
function template_control_richedit($editor_id, $smileyContainer = null, $bbcContainer = null) { global $context, $settings, $options, $txt, $modSettings, $scripturl; $editor_context = &$context['controls']['richedit'][$editor_id];
* Add after:
?>
<script language="javascript">
function convierteCode(){
// dado un codigo tipo flickr lo convierte a BBCode (def en GenericControls.template.php)
var flickr = document.getElementById("flickrcodeinput").value;
flickr = flickr.replace('<a href="','[url=');
flickr = flickr.replace('" /></a>','[/img][/url]');
flickr = flickr.replace(/"(.)+title(.)*><img(.)+src="/,'][img]');
flickr = flickr.replace(/"(.)+width(.)*\[/,'[');
flickr = flickr.replace('[/url]','[/img][/url]');
document.getElementById("message").value += flickr;
window.frames[0].document.write(flickr);
}
</script>
<?php*Locate:
echo ' <div> <div> <textarea class="editor"
* Replace with:
echo ' <div> <div> <!-- flickr input and button--> <input type="text" id="flickrcodeinput" width="100px"></input> <input type="button" value="Inserta IMG flickr" onClick="convierteCode();"></input> <br /><br /> <!--flickr input and button end --> <textarea class="editor"
* Upload the new GenericControls.template.php
(Note for curious people: I also tried this by adding a custom button which would produce a new bbcode like [flickr][/flickr] and blahblahblah, but I could not make it work. More details here)
Javascript – sort tables (by column values) [easy and opensource]
If you see a table in a client-side application, you’ll expect to be able to click on the headers and have the table sort, would you not? I know it always annoys me when you can’t. A fair few web applications do allow this; most of them, which are pulling this data by submitting a SQL query to a relational database (an environment eminently suited to tabular data) implement this by resubmitting the whole page with something like ordercolumn=4 in the URL, and then adding an ORDER BY clause to their SQL query to return the data from the DB ordered by the specified column.
Resubmit the page? Just to sort data we already have? I’m sure we can do better than that: just using javascript!
Take a look at sorrtable javascript library and follow the simple steps to have a sortable table.
1. Download the Javascript library
2. Include the Javascript library, by putting a link to it in the HEAD of your page, like so:
<script src="sorttable.js"></script>
3. Mark your table as a sortable one by giving it a class of “sortable”:
<table class="sortable">
Note that the library’s JavaScript file is called sorttable (two Ts), but the class you add to the table is sortable (one T).
Easy, isn’t it?
W3C validator issues with ampersand (&) in javascript location.href
When I tried to validate the code for http://www.hyips.es (one of my freelance projects) the validator kept complaining:
cannot generate system identifier for general entity langpair.This error is caused by the validator parsing the code inside of a <script> tag. Below are the lines which were producing the error (related to a function which translates the page from spanish to english using google translator):
<script type="text/javascript">
function es2eng(){
location.href = "http://translate.google.com/translate?u=" + this.location.href + "&langpair=es|en&h1=es&ie=UTF-8";
}
</script>
<a href="#" onclick="es2eng();"><img style="border: medium none; margin:1px;" src="/images/banderas/england-flag.gif" alt="translate to english" height="20" width="30" /></a>After reading a lot of confussing comments (like Try to change ‘&’ to ‘&’ or to ‘%26′), and just when I was about to define the function in an external js file (not a big fan of this, because the function was only one line long…), I came to this revealing post in webmasterworld.com.
The problem can be solved as easy as this: change
<script type="text/javascript"> your script is here </script>
To:
<script type="text/javascript"> // <![CDATA[ your script is here // ]]> </script>
The change stops W3C’s validator from parsing the code inside the script tags, therefore the error disappears!
Browser detection with javascript
In a perfect world, all the major browsers would co-exist happily together, supporting the same set of objects and features. But then again, in that world, I’d be on an island enjoying the sun.
Before we reach that place, this tutorial looks at how to detect support for a particular JavaScript property or method before attempting to invoke it. It serves as an alternate, in many cases, superior way to strict browser detection for creating cross browser friendly scripts.
Here is an small example of how to detect the browser & version:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <html>
<body>
<script type="text/javascript">
var browser=navigator.appName;
var b_version=navigator.appVersion;
var version=parseFloat(b_version);
document.write("Browser name: "+ browser);
document.write("<br />");
document.write("Browser version: "+ version);
</script>
</body>
</html> |
Another (more practical) way to discriminate the browser can be done like this:
1 2 3 4 5 6 7 | var browser=navigator.appName; if (browser=="Netscape"){ // mozilla, netscape, chrome, ... } else if (browser=="Microsoft Internet Explorer"){ // Internet Explorer 4 or Opera with IE user agent } |
Have fun
DeepZoom & SEADragon (IV)
IMHO SEADragon should include some controls to go to next/previous image and not restrict the navigation between images to clicking the thumnails. So I decided to build these new custom buttons.
Documentation
Before you continue reading these post you should be familiar with SEADragon, DeepZoom and jCarousel. If you are not, please read the following posts:
[1] DeepZoom & SEADragon part one (build basic html page with the viewer)
[2] DeepZoom & SEADragon part two (use jCarousel to display thumbs)
[3] DeepZoom & SEADragon part three (remove SEADragon logo).
Adding custom controls to the viewer: some “easy” example
Before changing my code I decided to ask google if someone had added custom buttons to the viewer, and google, as usual, answered my question. In ajaxdaddy.com I found this -great- example of how to do it. It’s quite well explained there. Please read it carefully.
Adding custom controls to the viewer: integration with jCarousel
The example shown above is great. But I had a slightly diferent problem: I had to integrate the next/previous button behaviour with my thumbs carousel, so it moved forwards and backwards when necessary.
We well part from the previous example code to explain all the modifications.
- Change
doOpenfunction: this function had two parameters, the first one was theitemto show. I changed this parameter so it was the index to read, and not the item itself.
I also defined a new global variable (I know, it is not the best choice, but it works) calledselectedIndexto know what is the index corresponding to the shown image at any time. I did all this in order to make easier the next steps
This was my code *before* the modifications:
function doOpen(item, anchor) { if(selectedItem) selectedItem.button.src = thumbsPath + selectedItem.thumb + '_rest.png'; if(item){ viewer.openDzi(item.dzi, item.xml); titleDiv.innerHTML = item.title; descDiv.innerHTML = item.desc; item.button.src = thumbsPath + item.thumb + '_selected.png'; selectedItem = item; if (anchor) { window.location.hash = "#" + item.thumb; } } }
*After* the mods, my code is:
var selectedIndex = null; function doOpen(index, anchor){ item = data[index]; if(selectedItem) selectedItem.button.src = thumbsPath + selectedItem.thumb + '_rest.png'; if(item){ viewer.openDzi(item.dzi, item.xml); titleDiv.innerHTML = item.title; descDiv.innerHTML = item.desc; item.button.src = thumbsPath + item.thumb + '_selected.png'; selectedItem = item; selectedIndex = index; if (anchor) { window.location.hash = "#" + item.thumb; } } }
Of course the way of calling these functions also changes. Again, a before&after:
*before*:doOpen(dataMap[hash] || data[0], false);
*after*:doOpen(hash || 0, false);
- Download two images for the buttons. For instance, you can take this two:
Next
PreviousPlace them in
./imgfolder and name themload_next_image.pngandload_prev_image.png. - Now, we have to add the new buttons and their behaviour, which is done by the following code (i show only the part for the “next” button, since the “prev” is pretty similar):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
var nextControl = makeControlNEXT(); nextControl.style.marginLeft="4px"; nextControl.style.marginBottom="4px"; viewer.addControl(nextControl, Seadragon.ControlAnchor.TOP_RIGHT); /* * Creates the new "next" button which does: * (1) Show -if available- the next image in the SeaDragon viewer * (2) Moves forwards -if necessary- the JCarousel so the */ function makeControlNEXT() { var controlNEXT = document.createElement("a"); var controlImg = document.createElement('img'); controlImg.src="./img/load_next_image.png"; controlImg.className="thumb"; controlImg.title="next"; controlNEXT.href = "#"; // so browser shows it as link controlNEXT.id = "controlNEXT2"; // this is QUITE important for the next part!! (jCarousel) controlNEXT.className = "controlNEXT"; controlNEXT.appendChild(controlImg); Seadragon.Utils.addEvent(controlNEXT, "click", doOpenNEXT); return controlNEXT; } function doOpenNEXT(event) { Seadragon.Utils.cancelEvent(event); // so link isn't processed if (!viewer.isOpen()) { return; } if ( (selectedIndex+1) < count){ // if there is a next image to show...show it! doOpen(selectedIndex+1,true); } }
Note the
controlNEXT.id = "controlNEXT2";in line 18. We will use this in next section to “connect” this to the function that must be executed in jCarousel. - At this point you should have both buttons working with SEADragon. This is, when you click next button the viewer will show the next image. But there still remains something: notice the jCarousel in the bottom, it does not move forwards nor backwards when the displayed image changes! This is not a problem if you only have three images, but I’ll assume you’ll have more than three. So lets get to work.
- Modify the way jCarousel is built. Again, a before&after is shown:
*before:
<script type="text/javascript"> jQuery(document).ready(function() { jQuery('#mycarousel').jcarousel(); }); </script>
*after:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
<script type="text/javascript"> function mycarousel_initCallback(carousel) { jQuery('.jcarousel-control a').bind('click', function() { carousel.scroll(jQuery.jcarousel.intval(jQuery(this).text())); return false; }); jQuery('#controlNEXT2').bind('click', function() { $.balance = selectedIndex% 3; $.bloquear = selectedIndex; if ($.balance == 0 && $.bloquear!=0){ // must the carousel be moved? carousel.next(); } return false; }); jQuery('#controlPREV2').bind('click', function() { $.balance = selectedIndex% 3; $.bloquear = selectedIndex; if ($.balance == 2 && $.bloquear!=0){ carousel.prev(); } return false; }); }; jQuery(document).ready(function() { if ($.balance === undefined) $.balance = -1; jQuery('#mycarousel').jcarousel( { scroll: 3, initCallback: mycarousel_initCallback } ); }); </script>
Notice the
controNEXT2in line 17? It is the same id that we had in section 3, line 18.
So, the behaviour when clicking “next” or “previous” buttons in the top of the viewer is:
- First, call doOpenNEXT or doOpenPREV which makes SEADragon viewer to show the next / previous image.
- Second, call the function defined in section 5, line 18 which makes jCarousel to move forwards or backwards if necesary.
- We use selectedIndex variable to decide if the jCarousel must or mustn’t move.
You can see a FULL EXAMPLE HERE.
Solving the browser issues: IE8 vs Mozilla
If you run the example above in a Mozilla/Netscape browser it will work fine. But if you try to do it in a Internet Explorer browser, the jCarousel will not move when it has to.
This is related with the order of execution of functions:
- Mozilla: it executes first doOpenNEXT / doOpenPREV and then the function next of jCarousel.
- IE8: the order of execution is first the function of jCarousel and then the others.
So selectedIndex is not updated when it has to be in IE8 and it fails to move the jCarousel when it has to.
Please read my browser detection with javascript post before doing anything. Then modify the jCarousel functions as in:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /* browser detection! */ var browser=navigator.appName; var b_version=navigator.appVersion; var version=parseFloat(b_version); jQuery('#controlNEXT2').bind('click', function() { if (browser=="Netscape"){ // mozilla, netscape, ... $.balance = selectedIndex% 3; $.bloquear = selectedIndex; } else if (browser=="Microsoft Internet Explorer"){ // Internet Explorer 4 or Opera with IE user agent $.balance = (selectedIndex+1)% 3; $.bloquear = (selectedIndex+1); } if ($.balance == 0 && $.bloquear!=0){ carousel.next(); } return false; }); jQuery('#controlPREV2').bind('click', function() { if (browser=="Netscape"){ $.balance = selectedIndex% 3; $.bloquear = selectedIndex; } else if (browser=="Microsoft Internet Explorer"){ $.balance = (selectedIndex-1)% 3; $.bloquear = (selectedIndex-1); } if ($.balance == 2 && $.bloquear!=0){ carousel.prev(); } return false; }); |
Now it works fine!
Visit the FULL FINAL EXAMPLE!
DeepZoom & SEADragon (III)
These days we were talking about DeepZoom, SeaDragon and jCarousel. Refer to
[1] DeepZoom & SEADragon part one and
[2] DeepZoom & SEADragon part two.
How to remove the SEADragon logo from the viewer?
Well, that is REALLY simple indeed
- First, open your
seadragon-branded.js(in my examples it is located underajax/0.8/. - Go to line 275. It should be something like
1
function init(){self.addControl(logoControl,Seadragon.ControlAnchor.BOTTOM_LEFT);logoControl.style.marginLeft="4px";logoControl.style.marginBottom="4px";self.addEventListener("open",introAnimationSetup);}
- Just comment the adding of the
logoControl. The final code should be like this:
1
function init(){/*self.addControl(logoControl,Seadragon.ControlAnchor.BOTTOM_LEFT);logoControl.style.marginLeft="4px";logoControl.style.marginBottom="4px";self.addEventListener("open",introAnimationSetup);*/}
That’s all folks!
DeepZoom & SEADragon (II)
In my previous DeepZoom & SeaDragon post I explained how to build a web gallery using SEADragon.
Show thumbs in JCarousel
I dont like the thumbs to be displayed all at once, so I decided to use a jCarousel instead. jCarousel is a jQuery plugin for controlling a list of items in horizontal or vertical order. The items, which can be static HTML content or loaded with (or without) AJAX, can be scrolled back and forth (with or without animation).
jCarousel is quite simple to use. In order to have a carousel you include the JCarousel libraries (available for download in ) and build a code like the following.
1 2 3 4 5 6 7 8 | <ul id="mycarousel" class="jcarousel-skin-tango">
<li><img src="http://static.flickr.com/66/199481236_dc98b5abb3_s.jpg" width="75" height="75" alt="" /></li>
<li><img src="http://static.flickr.com/75/199481072_b4a0d09597_s.jpg" width="75" height="75" alt="" /></li>
<li><img src="http://static.flickr.com/57/199481087_33ae73a8de_s.jpg" width="75" height="75" alt="" /></li>
<li><img src="http://static.flickr.com/77/199481108_4359e6b971_s.jpg" width="75" height="75" alt="" /></li>
<li><img src="http://static.flickr.com/58/199481143_3c148d9dd3_s.jpg" width="75" height="75" alt="" /></li>
<li><img src="http://static.flickr.com/72/199481203_ad4cdcf109_s.jpg" width="75" height="75" alt="" /></li>
</ul> |
Its very simple: an <il> for each <img>, everything wrapped in an <ul> called, for instance, mycarousel.
You can see a super-simple example of JCarousel HERE.
JCarousel & SEADragon
Before you continue reading you should understand the code shown in
my first DeepZoom & SeaDragon post. You can see it working HERE.
The modifications to show the thumbs in a JCarousel are quite simple (I will only show the relevant part of the new code):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | <script type="text/javascript" src="ajax/0.8/seadragon-branded.js"></script>
<script type="text/javascript" src="data2.js"></script>
<script type="text/javascript">
var viewerDiv = document.getElementById('viewer');
var thumbsDiv = document.getElementById('thumbs');
var titleDiv = document.getElementById('title');
var descDiv = document.getElementById('desc');
var botonesDiv = document.getElementById('botones');
viewerDiv.innerHTML = ""; // for the CMS
var viewer = new Seadragon.BrandedViewer(viewerDiv);
var selectedItem = null;
var thumbsPath = 'http://155.210.85.31/dzi/miguel/mini/';
function doOpen(item, anchor)
{
if(selectedItem)
selectedItem.button.src = thumbsPath + selectedItem.thumb + '_rest.png';
if(item)
{
viewer.openDzi(item.dzi, item.xml);
titleDiv.innerHTML = item.title;
descDiv.innerHTML = item.desc;
item.button.src = thumbsPath + item.thumb + '_selected.png';
selectedItem = item;
if (anchor) {
window.location.hash = "#" + item.thumb;
}
}
}
/* here begins the IMPORTANT PART... */
var ul = document.createElement('ul');
ul.id = "mycarousel";
ul.className = "jcarousel-skin-tango";
thumbsDiv.appendChild(ul);
var count = data.length;
var dataMap = {};
var a;
for (a = 0; a < count; a++)
{
var item = data[a];
var image = document.createElement('img');
// index item by its thumb name
dataMap[item.thumb] = item;
image.src = thumbsPath + item.thumb + '_rest.png';
image.className = "thumb";
image.title = item.title;
image.id = a;
image.name = a;
Seadragon.Utils.addEvent(image, "click",
Seadragon.Utils.createCallback(null, doOpen, item, true));
thumbsDiv.appendChild(image);
item.button = image;
var li = document.createElement('li');
li.appendChild(image);
ul.appendChild(li);
}
// if the page's hash is set, open image with that hash
// if there is one. otherwise, just open the first image.
// note that if there's a hash, it'll begin with #.
var hash = (window.location.hash || " ").substr(1);
doOpen(dataMap[hash] || data[0], false); // don't anchor
</script>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('#mycarousel').jcarousel();
});
</script>
</div> |
- Lines 36 to 40 create the new
<ul>and append it to thethumbsDiv - Lines 68 to 71 create every
<li>element and append it to the recently created<ul> - Lines 81 to 85 create the jCarousel using jQuery
- Note1: in the previous version of the code we used
xandyvariables (defined in lines 134, 135 and used to set the thumbs position -lines 147, 148- so the thumbs where shown in rows of ten elements). These variables are no longer needed, as the thums are managed by jCarousel.Now you can see a full working example HERE.
In my next article I will explain how to remove the annoying SEADragon logo in the bottom left of the viewer
DeepZoom & SEADragon (I)
There are plenty of times when you want to see something closer, to get a good look at the texture of a sculpture, or find out if that’s a reflection or a scratch on that used car you’re looking at.
Seadragon, implemented as the Deep Zoom feature of Silverlight, allows you to do that. But what if you’re not using the Silverlight platform? That’s what Seadragon Ajax is for.
Seadragon Ajax, written from the ground up in JavaScript, gives you the ability to add a Deep Zoom viewer into your blog, web site, or even your eBay listing.
Let’s see an example of how this works.
First of all, you should be confortable with the DZI (deep zoom image) Schema definition and you should download Microsoft’s DeepZoom composer and, of course, read its manual.
The DeepZoom generated files
Lets suppose you have done all this and generated a new dzi image. Now you should have a directory (I call it ./pagina1) which looks like this:

Let’s take a closer look at this files:
- dzc_output.xml: this is just a file which shows the XSD used and the image-related data, such as width, height, tilesize, etc…
<?xml version="1.0" encoding="utf-8"?><Image TileSize="256" Overlap="1" Format="jpg" xmlns="http://schemas.microsoft.com/deepzoom/2008"><Size Width="1820" Height="2312" /></Image> - SparseSceneImageGraph: this file contains information related to generation of the image tile.
1 2 3 4 5 6 7 8 9 10 11 12
<?xml version="1.0"?> <SceneGraph version="1"> <AspectRatio>0,78719723183391</AspectRatio> <SceneNode> <FileName>C:\Documents and Settings\jrey\Mis documentos\Expression\Deep Zoom Composer Projects\ANTIFON2\Source Images\ms00418_0001.jpg</FileName> <x>0</x> <y>0</y> <Width>1</Width> <Height>1</Height> <ZOrder>1</ZOrder> </SceneNode> </SceneGraph>
- scene.xml: this file indicates how the tiles are composed to obtain complete images. The composed image takes into account the zoom level.
- dzc_output_files: it contains the tiles in a directory structure like this:

Aditional and necessary files
First of all, download and unzip the seadragon viewer and some other files to the parent directory.
You must create the thumbnails for the page too. The parent directory of thumnails must be called mini. For each image we will have two images: for instance, for thumb called pagina1 we will generate the thumbnails pagina1_rest.png and pagina1 _selected.png.
Now, you must build a file (I call it data2.js) which contains a directory structure like the one showed above for each image.
Here is an example of data2.js file which tells SEADragon the title of the image, the thumb, which points to the folder containing the structure (this is, pagina1), the description for that image and where to find the dzi file and the xml contents of that dzi file.
1 2 3 4 5 6 7 8 9 | var data = [ { title: 'Antifonario mozárabe', thumb: 'pagina1', desc: 'Antifonario mozárabe: página 1. Procede del Monasterio de San Juan de la Peña', dzi: 'pagina1/dzc_output.xml', xml: '<?xml version="1.0" encoding="utf-8"?><Image TileSize="256" Overlap="1" Format="jpg" xmlns="http://schemas.microsoft.com/deepzoom/2008"><Size Width="1820" Height="2312" /></Image>' } ] |
How to use it in a web page
Now that are familiar to the directory structure and the generated files, lets face the problem of generating an html page which shows the files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script>
<title>Gallery : Microsoft Live Labs</title>
<link rel="stylesheet" href="/files/themes/labs/styles.css" type="text/css" media="screen" />
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://livelabs.com/api/rsd.ashx" />
<link rel="wlwmanifest" type="application/wlwmanifest+xml" title="WLWManifest" href="http://livelabs.com/api/wlwmanifest.ashx" />
</head>
<body>
<div id="wrapper">
<div id="content_box">
<div id="content_area" >
<div id="middle_column" class="content_double_column">
<!-- CMS Start -->
<p><style type="text/css">
#viewer
{
width: 640px;
height: 480px;
background-color: black;
color: white; /* for error messages, etc. */
/* border -- on all sides */
border: 1px solid black
}
#metadata
{
/* dimensions */
/*width: 564px; /* plus (1px border + 7px padding) on each side */
width: 626px;
height: 80px;
padding: 7px;
/* color */
background-color: #888888;
color: white;
/* border -- don't duplicate border with viewer */
border-bottom: 1px solid black;
border-left: 1px solid black;
border-right: 1px solid black;
}
#metadata #title
{
font-size: large;
}
#metadata #desc
{
font-size: small;
}
#desc a:link,
#desc a:visited,
#desc a:hover,
#desc a:active
{
color:#ffffff;
text-decoration:underline;
}
#thumbs
{
width: 580px;
margin-top: 20px;
}
.thumb
{
position: relative;
cursor: pointer;
}
</style></p>
<div id="viewer"> </div>
<div id="metadata">
<div>
<div id="title"> </div>
<div id="desc"> </div>
</div>
</div>
<div id="thumbs"> </div>
<script type="text/javascript" src="ajax/0.8/seadragon-branded.js"></script>
<script type="text/javascript" src="data2.js"></script>
<script type="text/javascript">
var viewerDiv = document.getElementById('viewer');
var thumbsDiv = document.getElementById('thumbs');
var titleDiv = document.getElementById('title');
var descDiv = document.getElementById('desc');
viewerDiv.innerHTML = ""; // for the CMS
var viewer = new Seadragon.BrandedViewer(viewerDiv);
var selectedItem = null;
var thumbsPath = './mini/';
function doOpen(item, anchor)
{
if(selectedItem)
selectedItem.button.src = thumbsPath + selectedItem.thumb + '_rest.png';
if(item)
{
viewer.openDzi(item.dzi, item.xml);
titleDiv.innerHTML = item.title;
descDiv.innerHTML = item.desc;
item.button.src = thumbsPath + item.thumb + '_selected.png';
selectedItem = item;
if (anchor) {
window.location.hash = "#" + item.thumb;
}
}
}
var count = data.length;
var dataMap = {};
var a;
var x = 0;
var y = 0;
for (a = 0; a < count; a++)
{
var item = data[a];
var image = document.createElement('img');
// index item by its thumb name
dataMap[item.thumb] = item;
image.src = thumbsPath + item.thumb + '_rest.png';
image.className = "thumb";
image.style.left = (16 * x) + 'px';
image.style.top = (16 * y) + 'px';
image.title = item.title;
Seadragon.Utils.addEvent(image, "click",
Seadragon.Utils.createCallback(null, doOpen, item, true));
thumbsDiv.appendChild(image);
item.button = image;
x++;
if(x >= 9)
{
x = 0;
y++;
var br = document.createElement('br');
thumbsDiv.appendChild(br);
}
}
// if the page's hash is set, open image with that hash
// if there is one. otherwise, just open the first image.
// note that if there's a hash, it'll begin with #.
var hash = (window.location.hash || " ").substr(1);
doOpen(dataMap[hash] || data[0], false); // don't anchor
</script><!-- CMS End -->
</div>
</div>
</div>
<div id="cap_bottom"></div>
</div>
</div><!-- END wrapper -->
<!-- SiteCatalyst code version: H.1. Copyright 1997-2005 Omniture, Inc. More info available at http://www.omniture.com -->
<script language="JavaScript">var s_account="msnportallivelabs";</script>
<script language="JavaScript" src="http://stj.msn.com/br/om/js/s_code.js"></script>
<script language="JavaScript">
<!--
s.linkInternalFilters="javascript:,.live.,.livelabs.";s.trackExternalLinks=true;
s.server="livelabs.com";s.channel="livelabs.com";
s.prop1="livelabs.com";s.prop2="en-us";
/************* DO NOT ALTER ANYTHING BELOW THIS LINE ! **************/
var s_code=s.t();if(s_code)document.write(s_code)//-->
</script>
<script language="JavaScript"> <!-- if(navigator.appVersion.indexOf('MSIE')>=0)document.write(unescape('%3C')+'\!-'+'-')//--> </script>
<noscript>
<img src="http://msnportallivelabs.112.2O7.net/b/ss/msnportallivelabs/1/H.1--NS/0" height="1" width="1" border="0" alt="" />
</noscript>
<!--/DO NOT REMOVE/-->
<!-- End SiteCatalyst code version: H.1. -->
</body>
</html> |
If you are familiar with javascript and html the code shown is quite self-explainable.
You can see a working example here.
IMHO the thumnails visualization quite ugly, so I decided to add a JCarousel to view these thumnails. This process is quite simple. I will show it how to do it in a subsequent post
Want to know more about Deep Zoom images?
Visit the following links:
[1] Detailed mathematical explanation on how the tile algorithm works
[2] Python implementation of Deep Zoom tile images
More interesting info
Peticiones AJAX a SERVIDORES EXTERNOS
El otro día os hablaba de cómo invocar servicios de nuestro propio servidor usando request’s de Ajax.
Podéis ver un ejemplo de código que realiza peticiones Ajax [AQUI]. Como véis, NO FUNCIONA. Si utilizáis firebug veréis que la ejecución llega hasta la línea 27.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | function makeRequest(url,param){ url = url + param; http_request = false; if(window.XMLHttpRequest){ // Mozilla, Safari,... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType){ http_request.overrideMimeType('text/html'); } } else if (window.ActiveXObject){// IE try{ http_request = new ActiveXObject("Msxml2.XMLHTTP");} catch (e){ try{ http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e2) {} } } if (!http_request){ // uncomment next line if you want to show any error messages alert('Cannot create XMLHTTP instance'); return false; } //alert("makeRequest(): url='"+url+"'"); http_request.onreadystatechange = fromServer; <b>http_request.open('GET', url, false); // En este punto URL contiene una URL EXTERNA //(fuera de nuestro servidor)</b> http_request.send(param); return http_request; } |
Además, si abrimos la consola de errores de Firefox, veremos algo parecido a
Error de seguridad: el contenido en
http://www.leccionespracticas.com/trabajo/buscador_zaguan.php
no puede cargar datos de http://olmo.unizar.es/search?ln=es&sc=1&p=water.
Error: uncaught exception:
[Exception... "Access to restricted URI denied"
code: "1012" nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)"
location: "http://www.leccionespracticas.com/trabajo/buscador_zaguan.php Line: 110"]
Buscando encontré el manual para hacer proxy desde javascript.
Ésto me dio la pista definitiva para solucionar el problema. Os cuento cómo lo he resuelto:
1. Creo el archivo php_proxy2.php con [éste código fuente] y MODIFICAMOS $vfileañadiendo la url BASE del sitio web al que queremos invocar mediante Ajax, esto es:
<?php <font color="red"> $vfile = "http://olmo.unizar.es"; // Esta línea tiene la URL base del sitio </font> if (isset($_GET['dst'])){ $vfile = $vfile.$_GET['dst']; } header("Content-type: text/xml"); readfile($vfile); ?>
Nota: Además, por motivos de seguridad es IMPRESCINDIBLE que utilicéis este parámetro base, ya que sino vuestra máquina se podría convertir en un proxy -desde el que se podrían hacer cosas malas, you know what I mean-
2. Hago el encode de la URL que deseo invocar y se la paso como parámetro al proxy ANTES de invocar a http_request.open (mira la línea 26). Ésto es, modificamos la funcion makeRequest, que quedará asi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function makeRequest(url,param){ url = url + param; http_request = false; if(window.XMLHttpRequest){ // Mozilla, Safari,... http_request = new XMLHttpRequest(); if (http_request.overrideMimeType){ http_request.overrideMimeType('text/html'); } } else if (window.ActiveXObject){// IE try{ http_request = new ActiveXObject("Msxml2.XMLHTTP");} catch (e){ try{ http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e2) {} } } if (!http_request){ // uncomment next line if you want to show any error messages alert('Cannot create XMLHTTP instance'); return false; } http_request.onreadystatechange = fromServer; var url_mod ='http://www.leccionespracticas.com/trabajo/php_proxy2.php?dst=' + encodeURIComponent(param); http_request.open('GET', url_mod, false); http_request.send(param); return http_request; } |
El resultado podéis verlo [EN ESTE LINK]
Ficheros utilizados en este tutorial:
[1] Proxy PHP: php_proxy2.php
[2] Fichero ORIGINAL desde el que hago los Ajax Requests: buscador_zaguan_bueno.php