From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001
From: mensonge
Date: Thu, 13 Nov 2008 09:49:11 +0000
Subject: New feature: basic Ajax suggestion for tags and implementation of
Dojo toolkit
git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f
---
includes/js/dojox/image/Gallery.js | 182 +++++++
includes/js/dojox/image/Lightbox.js | 451 ++++++++++++++++
includes/js/dojox/image/Magnifier.js | 75 +++
includes/js/dojox/image/MagnifierLite.js | 126 +++++
includes/js/dojox/image/README | 66 +++
includes/js/dojox/image/SlideShow.js | 598 +++++++++++++++++++++
includes/js/dojox/image/ThumbnailPicker.js | 535 ++++++++++++++++++
includes/js/dojox/image/resources/Gallery.html | 4 +
includes/js/dojox/image/resources/Lightbox.html | 15 +
includes/js/dojox/image/resources/Magnifier.css | 5 +
.../image/resources/Magnifier.css.commented.css | 5 +
includes/js/dojox/image/resources/SlideShow.html | 14 +
.../js/dojox/image/resources/ThumbnailPicker.html | 11 +
includes/js/dojox/image/resources/image.css | 283 ++++++++++
.../dojox/image/resources/image.css.commented.css | 345 ++++++++++++
.../js/dojox/image/resources/images/buttons.gif | Bin 0 -> 4620 bytes
.../js/dojox/image/resources/images/buttons.png | Bin 0 -> 9259 bytes
includes/js/dojox/image/resources/images/close.png | Bin 0 -> 675 bytes
.../js/dojox/image/resources/images/close_dark.png | Bin 0 -> 711 bytes
includes/js/dojox/image/resources/images/left.png | Bin 0 -> 626 bytes
.../js/dojox/image/resources/images/loading.gif | Bin 0 -> 4178 bytes
includes/js/dojox/image/resources/images/right.png | Bin 0 -> 621 bytes
.../js/dojox/image/resources/images/warning.png | Bin 0 -> 995 bytes
includes/js/dojox/image/tests/images.json | 32 ++
includes/js/dojox/image/tests/images/extraWide.jpg | Bin 0 -> 49250 bytes
includes/js/dojox/image/tests/images/huuuge.png | Bin 0 -> 37958 bytes
.../js/dojox/image/tests/images/imageHoriz.jpg | Bin 0 -> 47693 bytes
.../js/dojox/image/tests/images/imageHoriz2.jpg | Bin 0 -> 77176 bytes
includes/js/dojox/image/tests/images/imageVert.jpg | Bin 0 -> 71533 bytes
includes/js/dojox/image/tests/images/spanke.jpg | Bin 0 -> 302741 bytes
includes/js/dojox/image/tests/images/square.jpg | Bin 0 -> 82010 bytes
includes/js/dojox/image/tests/test_Gallery.html | 67 +++
includes/js/dojox/image/tests/test_Lightbox.html | 105 ++++
includes/js/dojox/image/tests/test_Magnifier.html | 98 ++++
.../js/dojox/image/tests/test_MagnifierLite.html | 91 ++++
includes/js/dojox/image/tests/test_SlideShow.html | 68 +++
.../js/dojox/image/tests/test_ThumbnailPicker.html | 134 +++++
37 files changed, 3310 insertions(+)
create mode 100644 includes/js/dojox/image/Gallery.js
create mode 100644 includes/js/dojox/image/Lightbox.js
create mode 100644 includes/js/dojox/image/Magnifier.js
create mode 100644 includes/js/dojox/image/MagnifierLite.js
create mode 100644 includes/js/dojox/image/README
create mode 100644 includes/js/dojox/image/SlideShow.js
create mode 100644 includes/js/dojox/image/ThumbnailPicker.js
create mode 100644 includes/js/dojox/image/resources/Gallery.html
create mode 100644 includes/js/dojox/image/resources/Lightbox.html
create mode 100644 includes/js/dojox/image/resources/Magnifier.css
create mode 100644 includes/js/dojox/image/resources/Magnifier.css.commented.css
create mode 100644 includes/js/dojox/image/resources/SlideShow.html
create mode 100644 includes/js/dojox/image/resources/ThumbnailPicker.html
create mode 100644 includes/js/dojox/image/resources/image.css
create mode 100644 includes/js/dojox/image/resources/image.css.commented.css
create mode 100644 includes/js/dojox/image/resources/images/buttons.gif
create mode 100644 includes/js/dojox/image/resources/images/buttons.png
create mode 100644 includes/js/dojox/image/resources/images/close.png
create mode 100644 includes/js/dojox/image/resources/images/close_dark.png
create mode 100644 includes/js/dojox/image/resources/images/left.png
create mode 100644 includes/js/dojox/image/resources/images/loading.gif
create mode 100644 includes/js/dojox/image/resources/images/right.png
create mode 100644 includes/js/dojox/image/resources/images/warning.png
create mode 100644 includes/js/dojox/image/tests/images.json
create mode 100644 includes/js/dojox/image/tests/images/extraWide.jpg
create mode 100644 includes/js/dojox/image/tests/images/huuuge.png
create mode 100644 includes/js/dojox/image/tests/images/imageHoriz.jpg
create mode 100644 includes/js/dojox/image/tests/images/imageHoriz2.jpg
create mode 100644 includes/js/dojox/image/tests/images/imageVert.jpg
create mode 100644 includes/js/dojox/image/tests/images/spanke.jpg
create mode 100644 includes/js/dojox/image/tests/images/square.jpg
create mode 100644 includes/js/dojox/image/tests/test_Gallery.html
create mode 100644 includes/js/dojox/image/tests/test_Lightbox.html
create mode 100644 includes/js/dojox/image/tests/test_Magnifier.html
create mode 100644 includes/js/dojox/image/tests/test_MagnifierLite.html
create mode 100644 includes/js/dojox/image/tests/test_SlideShow.html
create mode 100644 includes/js/dojox/image/tests/test_ThumbnailPicker.html
(limited to 'includes/js/dojox/image')
diff --git a/includes/js/dojox/image/Gallery.js b/includes/js/dojox/image/Gallery.js
new file mode 100644
index 0000000..d29ae22
--- /dev/null
+++ b/includes/js/dojox/image/Gallery.js
@@ -0,0 +1,182 @@
+if(!dojo._hasResource["dojox.image.Gallery"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.image.Gallery"] = true;
+dojo.provide("dojox.image.Gallery");
+dojo.experimental("dojox.image.Gallery");
+//
+// dojox.image.Gallery courtesy Shane O Sullivan, licensed under a Dojo CLA
+// @author Copyright 2007 Shane O Sullivan (shaneosullivan1@gmail.com)
+//
+// For a sample usage, see http://www.skynet.ie/~sos/photos.php
+//
+// TODO: Make public, document params and privitize non-API conformant methods.
+// document topics.
+
+dojo.require("dojo.fx");
+dojo.require("dijit._Widget");
+dojo.require("dijit._Templated");
+dojo.require("dojox.image.ThumbnailPicker");
+dojo.require("dojox.image.SlideShow");
+
+dojo.declare("dojox.image.Gallery",
+ [dijit._Widget, dijit._Templated],
+ {
+ // summary:
+ // Gallery widget that wraps a dojox.image.ThumbnailPicker and dojox.image.SlideShow widget
+ //
+ // imageHeight: Number
+ // Maximum height of an image in the SlideShow widget
+ imageHeight: 375,
+
+ // imageWidth: Number
+ // Maximum width of an image in the SlideShow widget
+ imageWidth: 500,
+
+ // pageSize: Number
+ // The number of records to retrieve from the data store per request.
+ pageSize: dojox.image.SlideShow.prototype.pageSize,
+
+ // autoLoad: Boolean
+ // If true, images are loaded before the user views them. If false, an
+ // image is loaded when the user displays it.
+ autoLoad: true,
+
+ // linkAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // URL to link to from an image, if any.
+ linkAttr: "link",
+
+ // imageThumbAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // URL to the thumbnail image.
+ imageThumbAttr: "imageUrlThumb",
+
+ // imageLargeAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // URL to the image.
+ imageLargeAttr: "imageUrl",
+
+ // titleAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // title of the picture, if any.
+ titleAttr: "title",
+
+ // slideshowInterval: Integer
+ // time in seconds, between image changes in the slide show.
+ slideshowInterval: 3,
+
+ templateString:"
\n\t\n\t\n
\n",
+
+ postCreate: function(){
+ // summary: Initializes the widget, creates the ThumbnailPicker and SlideShow widgets
+ this.widgetid = this.id;
+ this.inherited(arguments)
+
+ this.thumbPicker = new dojox.image.ThumbnailPicker({
+ linkAttr: this.linkAttr,
+ imageLargeAttr: this.imageLargeAttr,
+ titleAttr: this.titleAttr,
+ useLoadNotifier: true,
+ size: this.imageWidth
+ }, this.thumbPickerNode);
+
+
+ this.slideShow = new dojox.image.SlideShow({
+ imageHeight: this.imageHeight,
+ imageWidth: this.imageWidth,
+ autoLoad: this.autoLoad,
+ linkAttr: this.linkAttr,
+ imageLargeAttr: this.imageLargeAttr,
+ titleAttr: this.titleAttr,
+ slideshowInterval: this.slideshowInterval,
+ pageSize: this.pageSize
+ }, this.slideShowNode);
+
+ var _this = this;
+ //When an image is shown in the Slideshow, make sure it is visible
+ //in the ThumbnailPicker
+ dojo.subscribe(this.slideShow.getShowTopicName(), function(packet){
+ //if(packet.index < _this.thumbPicker._thumbIndex
+ // || packet.index > _this.thumbPicker._thumbIndex + _this.thumbPicker.numberThumbs -1){
+ //if(!_this.thumbPicker.isVisible(packet.index)){
+ //var index = packet.index - (packet.index % _this.thumbPicker.numberThumbs);
+ _this.thumbPicker._showThumbs(packet.index);
+ //}
+ });
+ //When the user clicks a thumbnail, show that image
+ dojo.subscribe(this.thumbPicker.getClickTopicName(), function(evt){
+ _this.slideShow.showImage(evt.index);
+ });
+ //When the ThumbnailPicker moves to show a new set of pictures,
+ //make the Slideshow start loading those pictures first.
+ dojo.subscribe(this.thumbPicker.getShowTopicName(), function(evt){
+ _this.slideShow.moveImageLoadingPointer(evt.index);
+ });
+ //When an image finished loading in the slideshow, update the loading
+ //notification in the ThumbnailPicker
+ dojo.subscribe(this.slideShow.getLoadTopicName(), function(index){
+ _this.thumbPicker.markImageLoaded(index);
+ });
+ this._centerChildren();
+ },
+
+ setDataStore: function(dataStore, request, /*optional*/paramNames){
+ // summary: Sets the data store and request objects to read data from.
+ // dataStore:
+ // An implementation of the dojo.data.api.Read API. This accesses the image
+ // data.
+ // request:
+ // An implementation of the dojo.data.api.Request API. This specifies the
+ // query and paging information to be used by the data store
+ // paramNames:
+ // An object defining the names of the item attributes to fetch from the
+ // data store. The four attributes allowed are 'linkAttr', 'imageLargeAttr',
+ // 'imageThumbAttr' and 'titleAttr'
+ this.thumbPicker.setDataStore(dataStore, request, paramNames);
+ this.slideShow.setDataStore(dataStore, request, paramNames);
+ },
+
+ reset: function(){
+ // summary: Resets the widget to its initial state
+ this.slideShow.reset();
+ this.thumbPicker.reset();
+ },
+
+ showNextImage: function(inTimer){
+ // summary: Changes the image being displayed in the SlideShow to the next
+ // image in the data store
+ // inTimer: Boolean
+ // If true, a slideshow is active, otherwise the slideshow is inactive.
+ this.slideShow.showNextImage();
+ },
+
+ toggleSlideshow: function(){
+ // summary: Switches the slideshow mode on and off.
+ this.slideShow.toggleSlideshow();
+ },
+
+ showImage: function(index, /*optional*/callback){
+ // summary: Shows the image at index 'idx'.
+ // idx: Number
+ // The position of the image in the data store to display
+ // callback: Function
+ // Optional callback function to call when the image has finished displaying.
+ this.slideShow.showImage(index, callback);
+ },
+
+ _centerChildren: function() {
+ // summary: Ensures that the ThumbnailPicker and the SlideShow widgets
+ // are centered.
+ var thumbSize = dojo.marginBox(this.thumbPicker.outerNode);
+ var slideSize = dojo.marginBox(this.slideShow.outerNode);
+
+ var diff = (thumbSize.w - slideSize.w) / 2;
+
+ if(diff > 0) {
+ dojo.style(this.slideShow.outerNode, "marginLeft", diff + "px");
+ } else if(diff < 0) {
+ dojo.style(this.thumbPicker.outerNode, "marginLeft", (diff * -1) + "px");
+ }
+ }
+});
+
+}
diff --git a/includes/js/dojox/image/Lightbox.js b/includes/js/dojox/image/Lightbox.js
new file mode 100644
index 0000000..79056d3
--- /dev/null
+++ b/includes/js/dojox/image/Lightbox.js
@@ -0,0 +1,451 @@
+if(!dojo._hasResource["dojox.image.Lightbox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.image.Lightbox"] = true;
+dojo.provide("dojox.image.Lightbox");
+dojo.experimental("dojox.image.Lightbox");
+
+dojo.require("dijit.Dialog");
+dojo.require("dojox.fx._base");
+
+dojo.declare("dojox.image.Lightbox",
+ dijit._Widget,{
+ // summary:
+ // A dojo-based Lightbox implementation.
+ //
+ // description:
+ // An Elegant, keyboard accessible, markup and store capable Lightbox widget to show images
+ // in a modal dialog-esque format. Can show individual images as Modal dialog, or can group
+ // images with multiple entry points, all using a single "master" Dialog for visualization
+ //
+ // key controls:
+ // ESC - close
+ // Down Arrow / Rt Arrow / N - Next Image
+ // Up Arrow / Lf Arrow / P - Previous Image
+ //
+ // example:
+ // | show lightbox
+ //
+ // example:
+ // | show group lightbox
+ // | show group lightbox
+ //
+ // example:
+ // | not implemented fully yet, though works with basic datastore access. need to manually call
+ // | widget._attachedDialog.addImage(item,"fromStore") for each item in a store result set.
+ // |
+ //
+ // group: String
+ // Grouping images in a page with similar tags will provide a 'slideshow' like grouping of images
+ group: "",
+
+ // title: String
+ // A string of text to be shown in the Lightbox beneath the image (empty if using a store)
+ title: "",
+
+ // href; String
+ // Link to image to use for this Lightbox node (empty if using a store).
+ href: "",
+
+ // duration: Integer
+ // Generic time in MS to adjust the feel of widget. could possibly add various
+ // durations for the various actions (dialog fadein, sizeing, img fadein ...)
+ duration: 500,
+
+ // _allowPassthru: Boolean
+ // Privately set this to disable/enable natural link of anchor tags
+ _allowPassthru: false,
+
+ // _attachedDialg: dojox.image._LightboxDialog
+ // The pointer to the global lightbox dialog for this widget
+ _attachedDialog: null, // try to share a single underlay per page?
+
+ startup: function(){
+ this.inherited(arguments);
+ // setup an attachment to the masterDialog (or create the masterDialog)
+ var tmp = dijit.byId('dojoxLightboxDialog');
+ if(tmp){
+ this._attachedDialog = tmp;
+ }else{
+ // this is the first instance to start, so we make the masterDialog
+ this._attachedDialog = new dojox.image._LightboxDialog({ id: "dojoxLightboxDialog" });
+ this._attachedDialog.startup();
+ }
+ if(!this.store){
+ // FIXME: full store support lacking, have to manually call this._attachedDialog.addImage(imgage,group) as it stands
+ this._addSelf();
+ this.connect(this.domNode, "onclick", "_handleClick");
+ }
+ },
+
+ _addSelf: function(){
+ // summary: Add this instance to the master LightBoxDialog
+ this._attachedDialog.addImage({
+ href: this.href,
+ title: this.title
+ },this.group||null);
+ },
+
+ _handleClick: function(/* Event */e){
+ // summary: Handle the click on the link
+ if(!this._allowPassthru){ e.preventDefault(); }
+ else{ return; }
+ this.show();
+ },
+
+ show: function(){
+ // summary: Show the Lightbox with this instance as the starting point
+ this._attachedDialog.show(this);
+ },
+
+ disable: function(){
+ // summary: Disables event clobbering and dialog, and follows natural link
+ this._allowPassthru = true;
+ },
+
+ enable: function(){
+ // summary: Enables the dialog (prevents default link)
+ this._allowPassthru = false;
+ }
+
+});
+
+dojo.declare("dojox.image._LightboxDialog",
+ dijit.Dialog,{
+ // summary:
+ // The "dialog" shared between any Lightbox instances on the page
+ //
+ // description:
+ //
+ // A widget that intercepts anchor links (typically around images)
+ // and displays a modal Dialog. this is the actual Dialog, which you can
+ // create and populate manually, though should use simple Lightbox's
+ // unless you need to direct access.
+ //
+ // There should only be one of these on a page, so all dojox.image.Lightbox's will us it
+ // (the first instance of a Lightbox to be show()'n will create me If i do not exist)
+ //
+ // title: String
+ // The current title, read from object passed to show()
+ title: "",
+
+ // FIXME: implement titleTemplate
+
+ // inGroup: Array
+ // Array of objects. this is populated by from the JSON object _groups, and
+ // should not be populate manually. it is a placeholder for the currently
+ // showing group of images in this master dialog
+ inGroup: null,
+
+ // imgUrl: String
+ // The src="" attribute of our imageNode (can be null at statup)
+ imgUrl: "",
+
+ // errorMessage: String
+ // The text to display when an unreachable image is linked
+ errorMessage: "Image not found.",
+
+ // adjust: Boolean
+ // If true, ensure the image always stays within the viewport
+ // more difficult than necessary to disable, but enabled by default
+ // seems sane in most use cases.
+ adjust: true,
+
+ // an object of arrays, each array (of objects) being a unique 'group'
+ _groups: { XnoGroupX: [] },
+
+ // errorImg: Url
+ // Path to the image used when a 404 is encountered
+ errorImg: dojo.moduleUrl("dojox.image","resources/images/warning.png"),
+
+ // privates:
+ _imageReady: false,
+ _blankImg: dojo.moduleUrl("dojo","resources/blank.gif"),
+ _clone: null, // the "untained" image
+ _wasStyled: null, // indicating taint on the imgNode
+
+ // animation holders:
+ _loadingAnim:null,
+ _showImageAnim: null,
+ _showNavAnim: null,
+ _animConnects: [],
+
+ templateString:"
\n\t
\n\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\n\t\t\t\t
${title}
\n\t\t\t
\n\t\t
\t\n\t\t\n\t
\n
\n",
+
+ startup: function(){
+ // summary: Add some extra event handlers, and startup our superclass.
+
+ this.inherited(arguments);
+ this._clone = dojo.clone(this.imgNode);
+ this.connect(document.documentElement,"onkeypress","_handleKey");
+ this.connect(window,"onresize","_position");
+ this.connect(this.nextNode, "onclick", "_nextImage");
+ this.connect(this.prevNode, "onclick", "_prevImage");
+ this.connect(this.closeNode, "onclick", "hide");
+ this._makeAnims();
+ this._vp = dijit.getViewport();
+
+ },
+
+ show: function(/* Object */groupData){
+ // summary: Show the Master Dialog. Starts the chain of events to show
+ // an image in the dialog, including showing the dialog if it is
+ // not already visible
+ //
+ // groupData: Object
+ // needs href and title attributes. the values for this image.
+
+ var _t = this; // size
+
+ // we only need to call dijit.Dialog.show() if we're not already open.
+ if(!_t.open){ _t.inherited(arguments); }
+
+ if(this._wasStyled){
+ // ugly fix for IE being stupid:
+ dojo._destroyElement(_t.imgNode);
+ _t.imgNode = dojo.clone(_t._clone);
+ dojo.place(_t.imgNode,_t.imageContainer,"first");
+ _t._makeAnims();
+ _t._wasStyled = false;
+ }
+
+ dojo.style(_t.imgNode,"opacity","0");
+ dojo.style(_t.titleNode,"opacity","0");
+
+ _t._imageReady = false;
+ _t.imgNode.src = groupData.href;
+
+ if((groupData.group && groupData !== "XnoGroupX") || _t.inGroup){
+ if(!_t.inGroup){
+ _t.inGroup = _t._groups[(groupData.group)];
+ // determine where we were or are in the show
+ dojo.forEach(_t.inGroup,function(g,i){
+ if(g.href == groupData.href){
+ _t._positionIndex = i;
+ }
+ },_t);
+ }
+ if(!_t._positionIndex){
+ _t._positionIndex=0;
+ _t.imgNode.src = _t.inGroup[_t._positionIndex].href;
+ }
+ // FIXME: implement titleTemplate
+ _t.groupCount.innerHTML = " (" +(_t._positionIndex+1) +" of "+_t.inGroup.length+")";
+ _t.prevNode.style.visibility = "visible";
+ _t.nextNode.style.visibility = "visible";
+ }else{
+ // single images don't have buttons, or counters:
+ _t.groupCount.innerHTML = "";
+ _t.prevNode.style.visibility = "hidden";
+ _t.nextNode.style.visibility = "hidden";
+ }
+ _t.textNode.innerHTML = groupData.title;
+
+ if(!_t._imageReady || _t.imgNode.complete === true){
+ // connect to the onload of the image
+ _t._imgConnect = dojo.connect(_t.imgNode, "onload", _t, function(){
+ _t._imageReady = true;
+ _t.resizeTo({
+ w: _t.imgNode.width,
+ h: _t.imgNode.height,
+ duration:_t.duration
+ });
+ // cleanup
+ dojo.disconnect(_t._imgConnect);
+ if(_t._imgError){ dojo.disconnect(_t._imgError); }
+ });
+
+ // listen for 404's:
+ _t._imgError = dojo.connect(_t.imgNode, "onerror", _t, function(){
+ dojo.disconnect(_t._imgError);
+ // trigger the above onload with a new src:
+ _t.imgNode.src = _t.errorImg;
+ _t._imageReady = true;
+ _t.textNode.innerHTML = _t.errorMessage;
+ });
+
+ // onload doesn't fire in IE if you connect before you set the src.
+ // hack to re-set the src after onload connection made:
+ if(dojo.isIE){ _t.imgNode.src = _t.imgNode.src; }
+
+ }else{
+ // do it quickly. kind of a hack, but image is ready now
+ _t.resizeTo({ w: _t.imgNode.width, h: _t.imgNode.height, duration: 1 });
+ }
+
+ },
+
+ _nextImage: function(){
+ // summary: Load next image in group
+ if(!this.inGroup){ return; }
+ if(this._positionIndex+1 this._vp.h || size.w + 50 > this._vp.w)){
+ size = this._scaleToFit(size);
+ }
+
+ var _sizeAnim = dojox.fx.sizeTo({
+ node: this.containerNode,
+ duration: size.duration||this.duration,
+ width: size.w,
+ height: size.h + 30
+ });
+ this.connect(_sizeAnim,"onEnd","_showImage");
+ _sizeAnim.play(15);
+ },
+
+ _showImage: function(){
+ // summary: Fade in the image, and fire showNav
+ this._showImageAnim.play(1);
+ },
+
+ _showNav: function(){
+ // summary: Fade in the footer, and setup our connections.
+ this._showNavAnim.play(1);
+ },
+
+ hide: function(){
+ // summary: Hide the Master Lightbox
+ dojo.fadeOut({node:this.titleNode, duration:200,
+ onEnd: dojo.hitch(this,function(){
+ // refs #5112 - if you _don't_ change the .src, safari will _never_ fire onload for this image
+ this.imgNode.src = this._blankImg;
+ })
+ }).play(5);
+ this.inherited(arguments);
+ this.inGroup = null;
+ this._positionIndex = null;
+ },
+
+ addImage: function(child, group){
+ // summary: Add an image to this Master Lightbox
+ //
+ // child: Object
+ // The image information to add.
+ // href: String - link to image (required)
+ // title: String - title to display
+ //
+ // group: String?
+ // attach to group of similar tag or null for individual image instance
+ var g = group;
+ if(!child.href){ return; }
+ if(g){
+ if(!this._groups[g]){
+ this._groups[g] = [];
+ }
+ this._groups[g].push(child);
+ }else{ this._groups["XnoGroupX"].push(child); }
+ },
+
+ _handleKey: function(/* Event */e){
+ // summary: Handle keyboard navigation internally
+ if(!this.open){ return; }
+
+ var dk = dojo.keys;
+ var key = (e.charCode == dk.SPACE ? dk.SPACE : e.keyCode);
+ switch(key){
+
+ case dk.ESCAPE: this.hide(); break;
+
+ case dk.DOWN_ARROW:
+ case dk.RIGHT_ARROW:
+ case 78: // key "n"
+ this._nextImage(); break;
+
+ case dk.UP_ARROW:
+ case dk.LEFT_ARROW:
+ case 80: // key "p"
+ this._prevImage(); break;
+ }
+ },
+
+ _scaleToFit: function(/* Object */size){
+ // summary: resize an image to fit within the bounds of the viewport
+ // size: Object
+ // The 'size' object passed around for this image
+ var ns = {};
+
+ // one of the dimensions is too big, go with the smaller viewport edge:
+ if(this._vp.h > this._vp.w){
+ // don't actually touch the edges:
+ ns.w = this._vp.w - 70;
+ ns.h = ns.w * (size.h / size.w);
+ }else{
+ // give a little room for the titlenode, too:
+ ns.h = this._vp.h - 80;
+ ns.w = ns.h * (size.w / size.h);
+ }
+
+ // trigger the nasty width="auto" workaround in show()
+ this._wasStyled = true;
+
+ // we actually have to style this image, it's too big
+ var s = this.imgNode.style;
+ s.height = ns.h + "px";
+ s.width = ns.w + "px";
+
+ ns.duration = size.duration;
+ return ns; // Object
+
+ },
+
+ _position: function(/* Event */e){
+ // summary: we want to know the viewport size any time it changes
+ this.inherited(arguments);
+ this._vp = dijit.getViewport();
+ },
+
+ _makeAnims: function(){
+ // summary: make and cleanup animation and animation connections
+
+ dojo.forEach(this._animConnects,dojo.disconnect);
+ this._animConnects = [];
+ this._showImageAnim = dojo.fadeIn({
+ node: this.imgNode,
+ duration: this.duration
+ });
+ this._animConnects.push(dojo.connect(this._showImageAnim, "onEnd", this, "_showNav"));
+ this._loadingAnim = dojo.fx.combine([
+ dojo.fadeOut({ node:this.imgNode, duration:175 }),
+ dojo.fadeOut({ node:this.titleNode, duration:175 })
+ ]);
+ this._animConnects.push(dojo.connect(this._loadingAnim, "onEnd", this, "_prepNodes"));
+ this._showNavAnim = dojo.fadeIn({ node: this.titleNode, duration:225 });
+ }
+});
+
+}
diff --git a/includes/js/dojox/image/Magnifier.js b/includes/js/dojox/image/Magnifier.js
new file mode 100644
index 0000000..b6a3923
--- /dev/null
+++ b/includes/js/dojox/image/Magnifier.js
@@ -0,0 +1,75 @@
+if(!dojo._hasResource["dojox.image.Magnifier"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.image.Magnifier"] = true;
+dojo.provide("dojox.image.Magnifier");
+
+dojo.require("dojox.gfx");
+dojo.require("dojox.image.MagnifierLite");
+
+dojo.declare("dojox.image.Magnifier",
+ [dojox.image.MagnifierLite],{
+ // summary: Adds magnification on a portion of an image element, using dojox.gfx
+ //
+ // description: An unobtrusive way to add an unstyled overlay
+ // above the srcNode image element. The overlay/glass is a
+ // scaled version of the src image (so larger images sized down
+ // are clearer).
+ //
+ // over-ride the _createGlass method to create your custom surface,
+ // being sure to create an img node on that surface.
+
+ _createGlass: function(){
+ // summary: create the glassNode, and an img on a dojox.gfx surface
+
+ // images are hard to make into workable templates, so just add outer overlay
+ // and skip using dijit._Templated
+ this.glassNode = dojo.doc.createElement('div');
+ this.surfaceNode = this.glassNode.appendChild(dojo.doc.createElement('div'));
+
+ dojo.addClass(this.glassNode,"glassNode");
+ dojo.body().appendChild(this.glassNode);
+
+ with(this.glassNode.style){
+ height = this.glassSize + "px";
+ width = this.glassSize + "px";
+ }
+
+ this.surface = dojox.gfx.createSurface(this.surfaceNode, this.glassSize, this.glassSize);
+ this.img = this.surface.createImage({
+ src:this.domNode.src,
+ width:this._zoomSize.w,
+ height:this._zoomSize.h
+ });
+
+ },
+
+ _placeGlass: function(e){
+ // summary: position the overlay centered under the cursor
+ var x = e.pageX - 2;
+ var y = e.pageY - 2 ;
+ var xMax = this.offset.x + this.offset.w + 2;
+ var yMax = this.offset.y + this.offset.h + 2;
+
+ // with svg, our mouseout connection to the image surface doesn't
+ // fire, so we'r have to manually calculate offsets
+ if(xxMax || y>yMax){
+ this._hideGlass();
+ }else{
+ this.inherited(arguments);
+ }
+ },
+
+ _setImage: function(e){
+ // summary: set the image's offset in the clipping window relative to the mouse position
+
+ var xOff = (e.pageX - this.offset.l) / this.offset.w;
+ var yOff = (e.pageY - this.offset.t) / this.offset.h;
+ var x = (this._zoomSize.w * xOff * -1)+(this.glassSize*xOff);
+ var y = (this._zoomSize.h * yOff * -1)+(this.glassSize*yOff);
+ // set the image offset
+ this.img.setShape({ x: x, y:y });
+
+ }
+
+});
+
+}
diff --git a/includes/js/dojox/image/MagnifierLite.js b/includes/js/dojox/image/MagnifierLite.js
new file mode 100644
index 0000000..2e37340
--- /dev/null
+++ b/includes/js/dojox/image/MagnifierLite.js
@@ -0,0 +1,126 @@
+if(!dojo._hasResource["dojox.image.MagnifierLite"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.image.MagnifierLite"] = true;
+dojo.provide("dojox.image.MagnifierLite");
+dojo.experimental("dojox.image.MagnifierLite");
+
+dojo.require("dijit._Widget");
+
+dojo.declare("dojox.image.MagnifierLite",
+ [dijit._Widget],{
+ // summary: Adds magnification on a portion of an image element
+ //
+ // description: An unobtrusive way to add an unstyled overlay
+ // above the srcNode image element. The overlay/glass is a
+ // scaled version of the src image (so larger images sized down
+ // are clearer).
+ //
+ // The logic behind requiring the src image to be large is
+ // "it's going to be downloaded, anyway" so this method avoids
+ // having to make thumbnails and 2 http requests among other things.
+ //
+ // glassSize: Int
+ // the width and height of the bounding box
+ glassSize: 125,
+
+ // scale: Decimal
+ // the multiplier of the Mangification.
+ scale: 6,
+
+ postCreate: function(){
+ this.inherited(arguments);
+
+ // images are hard to make into workable templates, so just add outer overlay
+ // and skip using dijit._Templated
+ this._adjustScale();
+ this._createGlass();
+
+ this.connect(this.domNode,"onmouseenter","_showGlass");
+ this.connect(this.glassNode,"onmousemove","_placeGlass");
+ this.connect(this.img,"onmouseout","_hideGlass");
+
+ // when position of domNode changes, _adjustScale needs to run.
+ // window.resize isn't it always, FIXME:
+ this.connect(window,"onresize","_adjustScale");
+
+ },
+
+ _createGlass: function(){
+ // summary: make img and glassNode elements as children of the body
+
+ this.glassNode = dojo.doc.createElement('div');
+ this.surfaceNode = this.glassNode.appendChild(dojo.doc.createElement('div'));
+ dojo.addClass(this.glassNode,"glassNode");
+ dojo.body().appendChild(this.glassNode);
+ with(this.glassNode.style){
+ height = this.glassSize + "px";
+ width = this.glassSize + "px";
+ }
+
+ this.img = dojo.doc.createElement('img');
+ this.glassNode.appendChild(this.img);
+ this.img.src = this.domNode.src;
+ // float the image around inside the .glassNode
+ with(this.img.style){
+ position = "relative";
+ top = 0; left = 0;
+ width = this._zoomSize.w+"px";
+ height = this._zoomSize.h+"px";
+ }
+
+ },
+
+ _adjustScale: function(){
+ // summary: update the calculations should this.scale change
+
+ this.offset = dojo.coords(this.domNode,true);
+ this._imageSize = { w: this.offset.w, h:this.offset.h };
+ this._zoomSize = {
+ w: this._imageSize.w * this.scale,
+ h: this._imageSize.h * this.scale
+ };
+ },
+
+ _showGlass: function(e){
+ // summary: show the overlay
+ this._placeGlass(e);
+ with(this.glassNode.style){
+ visibility = "visible";
+ display = "";
+ }
+
+ },
+
+ _hideGlass: function(e){
+ // summary: hide the overlay
+ this.glassNode.style.visibility = "hidden";
+ this.glassNode.style.display = "none";
+ },
+
+ _placeGlass: function(e){
+ // summary: position the overlay centered under the cursor
+
+ this._setImage(e);
+ var t = Math.floor(e.pageY - (this.glassSize/2));
+ var l = Math.floor(e.pageX - (this.glassSize/2));
+ dojo.style(this.glassNode,"top",t);
+ dojo.style(this.glassNode,"left",l);
+
+ },
+
+ _setImage: function(e){
+ // summary: set the image's offset in the clipping window relative to the mouse position
+
+ var xOff = (e.pageX - this.offset.l) / this.offset.w;
+ var yOff = (e.pageY - this.offset.t) / this.offset.h;
+ var x = (this._zoomSize.w * xOff * -1)+(this.glassSize*xOff);
+ var y = (this._zoomSize.h * yOff * -1)+(this.glassSize*yOff);
+ with(this.img.style){
+ top = y+"px";
+ left = x+"px";
+ }
+
+ }
+
+});
+
+}
diff --git a/includes/js/dojox/image/README b/includes/js/dojox/image/README
new file mode 100644
index 0000000..38e9c3d
--- /dev/null
+++ b/includes/js/dojox/image/README
@@ -0,0 +1,66 @@
+-------------------------------------------------------------------------------
+dojox.image
+-------------------------------------------------------------------------------
+Version 1.0
+Release date: 10/31/07
+-------------------------------------------------------------------------------
+Project state:
+prototype | experimental
+-------------------------------------------------------------------------------
+Credits
+ Peter Higgins (dante)
+ Shane O'Sullivan (shaneosullivan1@gmail.com)
+-------------------------------------------------------------------------------
+Project description
+
+ A class to provide a common API for images, and home for image
+ related Widgets.
+
+-------------------------------------------------------------------------------
+Dependencies:
+
+ LightBox: dojo core, dojox.fx and optionally dojox.data. uses
+ either tundra or soria theme, no standalone icons.
+
+ SlideShow: dojo core, dojo.fx, and dojo.data (optional
+ dojox.data store implementations apply)
+
+ ThumbNailPicker: dojo core, dojo.fx and dojo.data. Combined
+ with a SlideShow, creates a sample Gallery app.
+
+ Gallery: core, dojox.image.SlideShow, dojox.image.ThumbNailPicker
+
+ Magnifier: dojo core, dijit._Widget, dojox.gfx
+
+-------------------------------------------------------------------------------
+Documentation
+
+-------------------------------------------------------------------------------
+Installation instructions
+
+Grab the following from the Dojo SVN Repository:
+http://svn.dojotoolkit.org/dojo/dojox/trunk/image/*
+
+Install into the following directory structure:
+/dojox/image/
+
+...which should be at the same level as your Dojo checkout.
+-------------------------------------------------------------------------------
+Additional Notes
+
+ LightBox: currently works as individual items, and grouped items,
+ but usage of dojo.data is broken (atm). the API is subject to
+ change, and is marked accordingly.
+
+ Hoping to implement: Carossel, and Reflect using
+ a common API provided by dojox.image.Pane (?)
+
+ SlideShow: Shows an image, one by one, from a datastore. Acts
+ as standing ImagePane implementation,
+
+ Gallery: A combination Thumbnail view and SlideShow, using
+ a datastore, and providing navigation, and common API.
+
+ Magnifier: Unobtrusive way to attach a hovering window window
+ when moving the mouse over an image. The window shows a a zoomed
+ version of the original source. (experimental)
diff --git a/includes/js/dojox/image/SlideShow.js b/includes/js/dojox/image/SlideShow.js
new file mode 100644
index 0000000..4767cf1
--- /dev/null
+++ b/includes/js/dojox/image/SlideShow.js
@@ -0,0 +1,598 @@
+if(!dojo._hasResource["dojox.image.SlideShow"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.image.SlideShow"] = true;
+dojo.provide("dojox.image.SlideShow");
+//
+// dojox.image.SlideShow courtesy Shane O Sullivan, licensed under a Dojo CLA
+// For a sample usage, see http://www.skynet.ie/~sos/photos.php
+//
+// @author Copyright 2007 Shane O Sullivan (shaneosullivan1@gmail.com)
+//
+// TODO: more cleanups
+//
+dojo.require("dojo.string");
+dojo.require("dojo.fx");
+dojo.require("dijit._Widget");
+dojo.require("dijit._Templated");
+
+dojo.declare("dojox.image.SlideShow",
+ [dijit._Widget, dijit._Templated],
+ {
+ // summary: A Slideshow Widget
+
+ // imageHeight: Number
+ // The maximum height of an image
+ imageHeight: 375,
+
+ // imageWidth: Number
+ // The maximum width of an image.
+ imageWidth: 500,
+
+ // title: String
+ // the initial title of the SlideShow
+ title: "",
+
+ // titleTemplate: String
+ // a way to customize the wording in the title. supported parameters to be populated are:
+ // ${title} = the passed title of the image
+ // ${current} = the current index of the image
+ // ${total} = the total number of images in the SlideShow
+ //
+ // should add more?
+ titleTemplate: '${title} (${current} of ${total})',
+
+ // noLink: Boolean
+ // Prevents the slideshow from putting an anchor link around the displayed image
+ // enables if true, though still will not link in absence of a url to link to
+ noLink: false,
+
+ // loop: Boolean
+ // true/false - make the slideshow loop
+ loop: true,
+
+ // hasNav: Boolean
+ // toggle to enable/disable the visual navigation controls
+ hasNav: true,
+
+ // images: Array
+ // Contains the DOM nodes that individual images are stored in when loaded or loading.
+ images: [],
+
+ // pageSize: Number
+ // The number of images to request each time.
+ pageSize: 20,
+
+ // autoLoad: Boolean
+ // If true, then images are preloaded, before the user navigates to view them.
+ // If false, an image is not loaded until the user views it.
+ autoLoad: true,
+
+ // autoStart: Boolean
+ // If true, the SlideShow begins playing immediately
+ autoStart: false,
+
+ // fixedHeight: Boolean
+ // If true, the widget does not resize itself to fix the displayed image.
+ fixedHeight: false,
+
+ // imageStore: Object
+ // Implementation of the dojo.data.api.Read API, which provides data on the images
+ // to be displayed.
+ imageStore: null,
+
+ // linkAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // URL to link to from an image, if any.
+ linkAttr: "link",
+
+ // imageLargeAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // URL to the image.
+ imageLargeAttr: "imageUrl",
+
+ // titleAttr: String
+ // Defines the name of the attribute to request from the store to retrieve the
+ // title of the picture, if any.
+ titleAttr: "title",
+
+ // slideshowInterval: Number
+ // Time, in seconds, between image transitions during a slideshow.
+ slideshowInterval: 3,
+
+ templateString:"
\n\t
\n\t\t
\n\t\t\t
${title}
\n\t\t
\n\t\t
\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t
\n\t\t\t\t\n\t\t\n\t
\n
\n",
+
+ // _tempImgPath: URL
+ // URL to the image to display when an image is not yet fully loaded.
+ _tempImgPath: dojo.moduleUrl("dojo", "resources/blank.gif"),
+
+ // _imageCounter: Number
+ // A counter to keep track of which index image is to be loaded next
+ _imageCounter: 0,
+
+ // _tmpImage: DomNode
+ // The temporary image to show when a picture is loading.
+ _tmpImage: null,
+
+ // _request: Object
+ // Implementation of the dojo.data.api.Request API, which defines the query
+ // parameters for accessing the store.
+ _request: null,
+
+ postCreate: function(){
+ // summary: Initilizes the widget, sets up listeners and shows the first image
+ this.inherited(arguments);
+ var img = document.createElement("img");
+
+ // FIXME: should API be to normalize an image to fit in the specified height/width?
+ img.setAttribute("width", this.imageWidth);
+ img.setAttribute("height", this.imageHeight);
+
+ if(this.hasNav){
+ dojo.connect(this.outerNode, "onmouseover", function(evt){
+ try{_this._showNav();}
+ catch(e){} //TODO: remove try/catch
+ });
+ dojo.connect(this.outerNode, "onmouseout", function(evt){
+ try{_this._hideNav(evt);}
+ catch(e){} //TODO: remove try/catch
+ });
+ }
+
+ this.outerNode.style.width = this.imageWidth + "px";
+
+ img.setAttribute("src", this._tempImgPath);
+ var _this = this;
+
+ this.largeNode.appendChild(img);
+ this._tmpImage = this._currentImage = img;
+ this._fitSize(true);
+
+ this._loadImage(0, function(){
+ _this.showImage(0);
+ });
+ this._calcNavDimensions();
+ },
+
+ setDataStore: function(dataStore, request, /*optional*/paramNames){
+ // summary: Sets the data store and request objects to read data from.
+ // dataStore:
+ // An implementation of the dojo.data.api.Read API. This accesses the image
+ // data.
+ // request:
+ // An implementation of the dojo.data.api.Request API. This specifies the
+ // query and paging information to be used by the data store
+ // paramNames:
+ // An object defining the names of the item attributes to fetch from the
+ // data store. The three attributes allowed are 'linkAttr', 'imageLargeAttr' and 'titleAttr'
+ this.reset();
+ var _this = this;
+
+ this._request = {
+ query: {},
+ start: request.start || 0,
+ count: request.count || this.pageSize,
+ onBegin: function(count, request){
+ _this.maxPhotos = count;
+ }
+ };
+ if(request.query){ dojo.mixin(this._request.query, request.query); }
+ if(paramNames){
+ dojo.forEach(["imageLargeAttr", "linkAttr", "titleAttr"], function(attrName){
+ if(paramNames[attrName]){ this[attrName] = paramNames[attrName]; }
+ }, this);
+ }
+
+ var _complete = function(items){
+ _this.showImage(0);
+ _this._request.onComplete = null;
+ if(_this.autoStart){
+ _this.toggleSlideShow();
+ }
+ };
+
+ this.imageStore = dataStore;
+ this._request.onComplete = _complete;
+ this._request.start = 0;
+ this.imageStore.fetch(this._request);
+ },
+
+ reset: function(){
+ // summary: Resets the widget to its initial state
+ // description: Removes all previously loaded images, and clears all caches.
+ while(this.largeNode.firstChild){
+ this.largeNode.removeChild(this.largeNode.firstChild);
+ }
+ this.largeNode.appendChild(this._tmpImage);
+ while(this.hiddenNode.firstChild){
+ this.hiddenNode.removeChild(this.hiddenNode.firstChild);
+ }
+ dojo.forEach(this.images, function(img){
+ if(img && img.parentNode){ img.parentNode.removeChild(img); }
+ });
+ this.images = [];
+ this.isInitialized = false;
+ this._imageCounter = 0;
+ },
+
+ isImageLoaded: function(index){
+ // summary: Returns true if image at the specified index is loaded, false otherwise.
+ // index:
+ // The number index in the data store to check if it is loaded.
+ return this.images && this.images.length > index && this.images[index];
+ },
+
+ moveImageLoadingPointer: function(index){
+ // summary: If 'autoload' is true, this tells the widget to start loading
+ // images from the specified pointer.
+ // index:
+ // The number index in the data store to start loading images from.
+ this._imageCounter = index;
+ },
+
+ destroy: function(){
+ // summary: Cleans up the widget when it is being destroyed
+ if(this._slideId) { this._stop(); }
+ this.inherited(arguments);
+ },
+
+ showNextImage: function(inTimer, forceLoop){
+ // summary: Changes the image being displayed to the next image in the data store
+ // inTimer: Boolean
+ // If true, a slideshow is active, otherwise the slideshow is inactive.
+ if(inTimer && this._timerCancelled){return false;}
+
+ if(this.imageIndex + 1 >= this.maxPhotos){
+ if(inTimer && (this.loop || forceLoop)){ this.imageIndex = -1; }
+ else{
+ if(this._slideId){ this._stop(); }
+ return false;
+ }
+ }
+ var _this = this;
+ this.showImage(this.imageIndex + 1, function(){
+ if(inTimer){ _this._startTimer(); }
+ });
+ return true;
+ },
+
+ toggleSlideShow: function(){
+ // summary: Switches the slideshow mode on and off.
+ if(this._slideId){
+ this._stop();
+ }else{
+ dojo.toggleClass(this.domNode,"slideShowPaused");
+ this._timerCancelled = false;
+ var success = this.showNextImage(true, true);
+ if(!success){
+ this._stop();
+ }
+ }
+ },
+
+ getShowTopicName: function(){
+ // summary: Returns the topic id published to when an image is shown
+ // description:
+ // The information published is: index, title and url
+ return (this.widgetId || this.id) + "/imageShow";
+ },
+
+ getLoadTopicName: function(){
+ // summary: Returns the topic id published to when an image finishes loading.
+ // description:
+ // The information published is the index position of the image loaded.
+ return (this.widgetId ? this.widgetId : this.id) + "/imageLoad";
+ },
+
+ showImage: function(index, /* Function? */callback){
+ // summary: Shows the image at index 'index'.
+ // index: Number
+ // The position of the image in the data store to display
+ // callback: Function
+ // Optional callback function to call when the image has finished displaying.
+
+ if(!callback && this._slideId){ this.toggleSlideShow(); }
+ var _this = this;
+ var current = this.largeNode.getElementsByTagName("div");
+ this.imageIndex = index;
+
+ var showOrLoadIt = function() {
+ //If the image is already loaded, then show it.
+ if(_this.images[index]){
+ while(_this.largeNode.firstChild){
+ _this.largeNode.removeChild(_this.largeNode.firstChild);
+ }
+ _this.images[index].style.opacity = 0;
+ _this.largeNode.appendChild(_this.images[index]);
+ _this._currentImage = _this.images[index]._img;
+ _this._fitSize();
+
+ var onEnd = function(a,b,c) {
+ var img = _this.images[index].firstChild;
+ if(img.tagName.toLowerCase() != "img"){img = img.firstChild;}
+ title = img.getAttribute("title");
+
+ if(_this._navShowing){
+ _this._showNav(true);
+ }
+ dojo.publish(_this.getShowTopicName(), [{
+ index: index,
+ title: title,
+ url: img.getAttribute("src")
+ }]);
+ if(callback) { callback(a,b,c); }
+ _this._setTitle(title);
+ };
+
+ dojo.fadeIn({
+ node: _this.images[index],
+ duration: 300,
+ onEnd: onEnd
+ }).play();
+ }else{
+ //If the image is not loaded yet, load it first, then show it.
+ _this._loadImage(index, function(){
+ dojo.publish(_this.getLoadTopicName(), [index]);
+ _this.showImage(index, callback);
+ });
+ }
+ };
+
+ //If an image is currently showing, fade it out, then show
+ //the new image. Otherwise, just show the new image.
+ if(current && current.length > 0){
+ dojo.fadeOut({
+ node: current[0],
+ duration: 300,
+ onEnd: function(){
+ _this.hiddenNode.appendChild(current[0]);
+ showOrLoadIt();
+ }
+ }).play();
+ }else{
+ showOrLoadIt();
+ }
+ },
+
+ _fitSize: function(force){
+ // summary: Fits the widget size to the size of the image being shown,
+ // or centers the image, depending on the value of 'fixedHeight'
+ // force: Boolean
+ // If true, the widget is always resized, regardless of the value of 'fixedHeight'
+ if(!this.fixedHeight || force){
+ var height = (this._currentImage.height + (this.hasNav ? 20:0));
+ dojo.style(this.innerWrapper, "height", height + "px");
+ return;
+ }
+ dojo.style(this.largeNode, "paddingTop", this._getTopPadding() + "px");
+ },
+
+ _getTopPadding: function(){
+ if(!this.fixedHeight){return 0;}
+ // summary: Returns the padding to place at the top of the image to center it vertically.
+ return (this.imageHeight - this._currentImage.height)/2;
+ },
+
+ _loadNextImage: function(){
+ //summary: Load the next unloaded image.
+ if(!this.autoLoad){ return; }
+ while(this.images.length >= this._imageCounter && this.images[this._imageCounter]){
+ this._imageCounter++;
+ }
+ this._loadImage(this._imageCounter);
+ },
+
+ _loadImage: function(index, callbackFn){
+ // summary: Load image at specified index
+ // description:
+ // This function loads the image at position 'index' into the
+ // internal cache of images. This does not cause the image to be displayed.
+ // index:
+ // The position in the data store to load an image from.
+ // callbackFn:
+ // An optional function to execute when the image has finished loading.
+ if(this.images[index] || !this._request) { return; }
+
+ var pageStart = index - (index % this.pageSize);
+
+ this._request.start = pageStart;
+
+ this._request.onComplete = function(items){
+ var diff = index - pageStart;
+ if(items && items.length > diff){
+ loadIt(items[diff]);
+ }else{ /* Squelch - console.log("Got an empty set of items"); */ }
+ }
+
+ var _this = this;
+ var loadIt = function(item){
+ var url = _this.imageStore.getValue(item, _this.imageLargeAttr);
+ var img = document.createElement("img");
+ var div = document.createElement("div");
+ div._img = img;
+
+ var link = _this.imageStore.getValue(item,_this.linkAttr);
+ if(!link || _this.noLink){ div.appendChild(img);
+ }else{
+ var a = document.createElement("a");
+ a.setAttribute("href", link);
+ a.setAttribute("target","_blank");
+ div.appendChild(a);
+ a.appendChild(img);
+ }
+
+ div.setAttribute("id",_this.id + "_imageDiv" + index);
+ dojo.connect(img, "onload", function(){
+ _this._fitImage(img);
+ div.setAttribute("width",_this.imageWidth);
+ div.setAttribute("height",_this.imageHeight);
+
+ dojo.publish(_this.getLoadTopicName(), [index]);
+ _this._loadNextImage();
+ if(callbackFn){ callbackFn(); }
+ });
+ _this.hiddenNode.appendChild(div);
+
+ var titleDiv = document.createElement("div");
+ dojo.addClass(titleDiv, "slideShowTitle");
+ div.appendChild(titleDiv);
+
+ _this.images[index] = div;
+ img.setAttribute("src", url);
+
+ var title = _this.imageStore.getValue(item,_this.titleAttr);
+ if(title){ img.setAttribute("title",title); }
+ }
+ this.imageStore.fetch(this._request);
+ },
+
+ _stop: function(){
+ // summary: Stops a running slide show.
+ if(this._slideId){ clearTimeout(this._slideId); }
+ this._slideId = null;
+ this._timerCancelled = true;
+ dojo.removeClass(this.domNode,"slideShowPaused");
+ },
+
+ _prev: function(){
+ // summary: Show the previous image.
+ // FIXME: either pull code from showNext/prev, or call it here
+ if(this.imageIndex < 1){ return; }
+ this.showImage(this.imageIndex - 1);
+ },
+
+ _next: function(){
+ // summary: Show the next image
+ this.showNextImage();
+ },
+
+ _startTimer: function(){
+ // summary: Starts a timeout to show the next image when a slide show is active
+ var id = this.id;
+ this._slideId = setTimeout(function(){dijit.byId(id).showNextImage(true);}, this.slideshowInterval * 1000);
+ },
+
+ _calcNavDimensions: function() {
+ // summary:
+ // Calculates the dimensions of the navigation controls
+ dojo.style(this.navNode, "position", "absolute");
+
+ //Place the navigation controls far off screen
+ dojo.style(this.navNode, "top", "-10000px");
+
+ //Make the navigation controls visible
+ dojo._setOpacity(this.navNode, 99);
+
+ this.navPlay._size = dojo.marginBox(this.navPlay);
+ this.navPrev._size = dojo.marginBox(this.navPrev);
+ this.navNext._size = dojo.marginBox(this.navNext);
+
+ dojo._setOpacity(this.navNode, 0);
+ dojo.style(this.navNode, "position", "");
+ dojo.style(this.navNode, "top", "");
+ },
+
+ _setTitle: function(title){
+ // summary: Sets the title of the image to be displayed
+ // title: String
+ // The String title of the image
+ this.titleNode.innerHTML = dojo.string.substitute(this.titleTemplate,
+ { title: title, current: 1 + this.imageIndex, total: this.maxPhotos});
+ },
+
+ _fitImage: function(img) {
+ // summary: Ensures that the image width and height do not exceed the maximum.
+ // img: Node
+ // The image DOM node to optionally resize
+ var width = img.width;
+ var height = img.height;
+
+ if(width > this.imageWidth){
+ height = Math.floor(height * (this.imageWidth / width));
+ img.setAttribute("height", height + "px");
+ img.setAttribute("width", this.imageWidth + "px");
+ }
+ if(height > this.imageHeight){
+ width = Math.floor(width * (this.imageHeight / height));
+ img.setAttribute("height", this.imageHeight + "px");
+ img.setAttribute("width", width + "px");
+ }
+ },
+
+ _handleClick: function(/* Event */e){
+ // summary: Performs navigation on the images based on users mouse clicks
+ // e:
+ // An Event object
+ switch(e.target){
+ case this.navNext:this._next(); break;
+ case this.navPrev:this._prev(); break;
+ case this.navPlay:this.toggleSlideShow(); break;
+ }
+ },
+
+ _showNav: function(force){
+ // summary:
+ // Shows the navigation controls
+ // force: Boolean
+ // If true, the navigation controls are repositioned even if they are
+ // currently visible.
+ if(this._navShowing && !force){return;}
+ dojo.style(this.navNode, "marginTop", "0px");
+ dojo.style(this.navPlay, "marginLeft", "0px");
+ var wrapperSize = dojo.marginBox(this.outerNode);
+
+ var margin = this._currentImage.height - this.navPlay._size.h - 10 + this._getTopPadding();
+
+ if(margin > this._currentImage.height){margin += 10;}
+ dojo[this.imageIndex < 1 ? "addClass":"removeClass"](this.navPrev, "slideShowCtrlHide");
+ dojo[this.imageIndex + 1 >= this.maxPhotos ? "addClass":"removeClass"](this.navNext, "slideShowCtrlHide");
+
+ var _this = this;
+ if(this._navAnim) {
+ this._navAnim.stop();
+ }
+ if(this._navShowing){return;}
+ this._navAnim = dojo.fadeIn({node: this.navNode, duration: 300,
+ onEnd: function(){_this._navAnim=null;}});
+
+ this._navAnim.play();
+ this._navShowing = true;
+ },
+
+ _hideNav: function(/* Event */e){
+ // summary: Hides the navigation controls
+ // e: Event
+ // The DOM Event that triggered this function
+ if(!e || !this._overElement(this.outerNode, e)) {
+ var _this = this;
+ if(this._navAnim) {
+ this._navAnim.stop();
+ }
+ this._navAnim = dojo.fadeOut({node: this.navNode,duration:300,
+ onEnd: function(){_this._navAnim=null;}});
+ this._navAnim.play();
+ this._navShowing = false;
+ }
+ },
+
+ _overElement: function(/*DomNode*/element, /*Event*/e){
+ // summary:
+ // Returns whether the mouse is over the passed element.
+ // Element must be display:block (ie, not a )
+
+ //When the page is unloading, if this method runs it will throw an
+ //exception.
+ if(typeof(dojo)=="undefined"){return false;}
+ element = dojo.byId(element);
+ var m = {x: e.pageX, y: e.pageY};
+ var bb = dojo._getBorderBox(element);
+ var absl = dojo.coords(element, true);
+ var left = absl.x;
+
+ return (m.x >= left
+ && m.x <= (left + bb.w)
+ && m.y >= absl.y
+ && m.y <= (top + bb.h)
+ ); // boolean
+ }
+});
+
+}
diff --git a/includes/js/dojox/image/ThumbnailPicker.js b/includes/js/dojox/image/ThumbnailPicker.js
new file mode 100644
index 0000000..42f9862
--- /dev/null
+++ b/includes/js/dojox/image/ThumbnailPicker.js
@@ -0,0 +1,535 @@
+if(!dojo._hasResource["dojox.image.ThumbnailPicker"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.image.ThumbnailPicker"] = true;
+dojo.provide("dojox.image.ThumbnailPicker");
+dojo.experimental("dojox.image.ThumbnailPicker");
+//
+// dojox.image.ThumbnailPicker courtesy Shane O Sullivan, licensed under a Dojo CLA
+// @author Copyright 2007 Shane O Sullivan (shaneosullivan1@gmail.com)
+//
+// For a sample usage, see http://www.skynet.ie/~sos/photos.php
+//
+// document topics.
+
+dojo.require("dojo.fx");
+dojo.require("dijit._Widget");
+dojo.require("dijit._Templated");
+
+dojo.declare("dojox.image.ThumbnailPicker",
+ [dijit._Widget, dijit._Templated],
+ {
+ // summary: A scrolling Thumbnail Picker widget
+ //
+ // imageStore: Object
+ // A data store that implements the dojo.data Read API.
+ imageStore: null,
+
+ // request: Object
+ // A dojo.data Read API Request object.
+ request: null,
+
+ // size: Number
+ // Width or height in pixels, depending if horizontal or vertical.
+ size: 500, //FIXME: use CSS?
+
+ // thumbHeight: Number
+ // Default height of a thumbnail image
+ thumbHeight: 75, // FIXME: use CSS?
+
+ // thumbWidth: Number
+ // Default width of an image
+ thumbWidth: 100, // FIXME: use CSS?
+
+ // useLoadNotifier: Boolean
+ // Setting useLoadNotifier to true makes a colored DIV appear under each
+ // thumbnail image, which is used to display the loading status of each
+ // image in the data store.
+ useLoadNotifier: false,
+
+ // useHyperlink: boolean
+ // Setting useHyperlink to true causes a click on a thumbnail to open a link.
+ useHyperlink: false,
+
+ // hyperlinkTarget: String
+ // If hyperlinkTarget is set to "new", clicking on a thumb will open a new window
+ // If it is set to anything else, clicking a thumbnail will open the url in the
+ // current window.
+ hyperlinkTarget: "new",
+
+ // isClickable: Boolean
+ // When set to true, the cursor over a thumbnail changes.
+ isClickable: true,
+
+ // isScrollable: Boolean
+ // When true, uses smoothScroll to move between pages
+ isScrollable: true,
+
+ // isHorizontal: Boolean
+ // If true, the thumbnails are displayed horizontally. Otherwise they are displayed
+ // vertically
+ isHorizontal: true,
+
+ //autoLoad: Boolean
+ autoLoad: true,
+
+ // linkAttr: String
+ // The attribute name for accessing the url from the data store
+ linkAttr: "link",
+
+ // imageThumbAttr: String
+ // The attribute name for accessing the thumbnail image url from the data store
+ imageThumbAttr: "imageUrlThumb",
+
+ // imageLargeAttr: String
+ // The attribute name for accessing the large image url from the data store
+ imageLargeAttr: "imageUrl",
+
+ // pageSize: Number
+ // The number of images to request each time.
+ pageSize: 20,
+
+ // titleAttr: String
+ // The attribute name for accessing the title from the data store
+ titleAttr: "title",
+
+ templateString:"
\n\t
\n\t \n\t
\n\t
\n\t \n\t
\n\t
\n\t \n\t
\n
\n",
+ tempImgPath: dojo.moduleUrl("dojo", "resources/blank.gif"),
+
+ // thumbs: Array
+ // Stores the image nodes for the thumbnails.
+ _thumbs: [],
+
+ // _thumbIndex: Number
+ // The index of the first thumbnail shown
+ _thumbIndex: 0,
+
+ // _maxPhotos: Number
+ // The total number of photos in the image store
+ _maxPhotos: 0,
+
+ // _loadedImages: Object
+ // Stores the indices of images that have been marked as loaded using the
+ // markImageLoaded function.
+ _loadedImages: {},
+
+ postCreate: function(){
+ // summary: Initializes styles and listeners
+ this.widgetid = this.id;
+ this.inherited(arguments);
+ this.pageSize = Number(this.pageSize);
+
+ this._scrollerSize = this.size - (51 * 2);
+
+ var sizeProp = this._sizeProperty = this.isHorizontal ? "width" : "height";
+
+ // FIXME: do this via css? calculate the correct width for the widget
+ dojo.style(this.outerNode, "textAlign","center");
+ dojo.style(this.outerNode, sizeProp, this.size+"px");
+
+ dojo.style(this.thumbScroller, sizeProp, this._scrollerSize + "px");
+
+ //If useHyperlink is true, then listen for a click on a thumbnail, and
+ //open the link
+ if(this.useHyperlink){
+ dojo.subscribe(this.getClickTopicName(), this, function(packet){
+ var index = packet.index;
+ var url = this.imageStore.getValue(packet.data,this.linkAttr);
+
+ //If the data item doesn't contain a URL, do nothing
+ if(!url){return;}
+
+ if(this.hyperlinkTarget == "new"){
+ window.open(url);
+ }else{
+ window.location = url;
+ }
+ });
+ }
+
+ if(this.isScrollable) {
+ // FIXME: does this break builds or anything?
+ dojo.require("dojox.fx.scroll");
+ dojo.require("dojox.fx.easing");
+ }
+ if(this.isClickable){
+ dojo.addClass(this.thumbsNode, "thumbClickable");
+ }
+ this._totalSize = 0;
+ this.init();
+ },
+
+ init: function(){
+ // summary: Creates DOM nodes for thumbnail images and initializes their listeners
+ if(this.isInitialized) {return false;}
+
+ var classExt = this.isHorizontal ? "Horiz" : "Vert";
+
+ // FIXME: can we setup a listener around the whole element and determine based on e.target?
+ dojo.addClass(this.navPrev, "prev" + classExt);
+ dojo.addClass(this.navNext, "next" + classExt);
+ dojo.addClass(this.thumbsNode, "thumb"+classExt);
+ dojo.addClass(this.outerNode, "thumb"+classExt);
+
+ this.navNextImg.setAttribute("src", this.tempImgPath);
+ this.navPrevImg.setAttribute("src", this.tempImgPath);
+
+ this.connect(this.navPrev, "onclick", "_prev");
+ this.connect(this.navNext, "onclick", "_next");
+ this.isInitialized = true;
+
+ if(this.isHorizontal){
+ this._offsetAttr = "offsetLeft";
+ this._sizeAttr = "offsetWidth";
+ this._scrollAttr = "scrollLeft";
+ }else{
+ this._offsetAttr = "offsetTop";
+ this._sizeAttr = "offsetHeight";
+ this._scrollAttr = "scrollTop";
+ }
+
+ this._updateNavControls();
+ if(this.imageStore && this.request){this._loadNextPage();}
+ return true;
+ },
+
+ getClickTopicName: function(){
+ // summary: Returns the name of the dojo topic that can be
+ // subscribed to in order to receive notifications on
+ // which thumbnail was selected.
+ return (this.widgetId || this.id) + "/select"; // String
+ },
+
+ getShowTopicName: function(){
+ // summary: Returns the name of the dojo topic that can be
+ // subscribed to in order to receive notifications on
+ // which thumbnail is now visible
+ return (this.widgetId || this.id) + "/show"; // String
+ },
+
+ setDataStore: function(dataStore, request, /*optional*/paramNames){
+ // summary: Sets the data store and request objects to read data from.
+ // dataStore:
+ // An implementation of the dojo.data.api.Read API. This accesses the image
+ // data.
+ // request:
+ // An implementation of the dojo.data.api.Request API. This specifies the
+ // query and paging information to be used by the data store
+ // paramNames:
+ // An object defining the names of the item attributes to fetch from the
+ // data store. The four attributes allowed are 'linkAttr', 'imageLargeAttr',
+ // 'imageThumbAttr' and 'titleAttr'
+ this.reset();
+
+ this.request = {
+ query: {},
+ start: request.start || 0,
+ count: request.count || 10,
+ onBegin: dojo.hitch(this, function(total){
+ this._maxPhotos = total;
+ })
+ };
+
+ if(request.query){ dojo.mixin(this.request.query, request.query);}
+
+ if(paramNames){
+ dojo.forEach(["imageThumbAttr", "imageLargeAttr", "linkAttr", "titleAttr"], function(attrName){
+ if(paramNames[attrName]){ this[attrName] = paramNames[attrName]; }
+ }, this);
+ }
+
+ this.request.start = 0;
+ this.request.count = this.pageSize;
+ this.imageStore = dataStore;
+
+ if(!this.init()){this._loadNextPage();}
+ },
+
+ reset: function(){
+ // summary: Resets the widget back to its original state.
+ this._loadedImages = {};
+ dojo.forEach(this._thumbs, function(img){
+ if(img){
+ // dojo.event.browser.clean(img);
+ if(img.parentNode){
+ img.parentNode.removeChild(img);
+ }
+ }
+ });
+
+ this._thumbs = [];
+ this.isInitialized = false;
+ this._noImages = true;
+ },
+
+ isVisible: function(index) {
+ // summary: Returns true if the image at the specified index is currently visible. False otherwise.
+ var img = this._thumbs[index];
+ if(!img){return false;}
+ var pos = this.isHorizontal ? "offsetLeft" : "offsetTop";
+ var size = this.isHorizontal ? "offsetWidth" : "offsetHeight";
+ var scrollAttr = this.isHorizontal ? "scrollLeft" : "scrollTop";
+ var offset = img[pos] - this.thumbsNode[pos];
+ return (offset >= this.thumbScroller[scrollAttr]
+ && offset + img[size] <= this.thumbScroller[scrollAttr] + this._scrollerSize);
+ },
+
+ _next: function() {
+ // summary: Displays the next page of images
+ var pos = this.isHorizontal ? "offsetLeft" : "offsetTop";
+ var size = this.isHorizontal ? "offsetWidth" : "offsetHeight";
+ var baseOffset = this.thumbsNode[pos];
+ var firstThumb = this._thumbs[this._thumbIndex];
+ var origOffset = firstThumb[pos] - baseOffset;
+
+ var index = -1, img;
+
+ for(var i = this._thumbIndex + 1; i < this._thumbs.length; i++){
+ img = this._thumbs[i];
+ if(img[pos] - baseOffset + img[size] - origOffset > this._scrollerSize){
+ this._showThumbs(i);
+ return;
+ }
+ }
+ },
+
+ _prev: function(){
+ // summary: Displays the next page of images
+ if(this.thumbScroller[this.isHorizontal ? "scrollLeft" : "scrollTop"] == 0){return;}
+ var pos = this.isHorizontal ? "offsetLeft" : "offsetTop";
+ var size = this.isHorizontal ? "offsetWidth" : "offsetHeight";
+
+ var firstThumb = this._thumbs[this._thumbIndex];
+ var origOffset = firstThumb[pos] - this.thumbsNode[pos];
+
+ var index = -1, img;
+
+ for(var i = this._thumbIndex - 1; i > -1; i--) {
+ img = this._thumbs[i];
+ if(origOffset - img[pos] > this._scrollerSize){
+ this._showThumbs(i + 1);
+ return;
+ }
+ }
+ this._showThumbs(0);
+ },
+
+ _checkLoad: function(img, index){
+ dojo.publish(this.getShowTopicName(), [{index:index}]);
+ this._updateNavControls();
+ this._loadingImages = {};
+
+ this._thumbIndex = index;
+
+ //If we have not already requested the data from the store, do so.
+ if(this.thumbsNode.offsetWidth - img.offsetLeft < (this._scrollerSize * 2)){
+ this._loadNextPage();
+ }
+ },
+
+ _showThumbs: function(index){
+ // summary: Displays thumbnail images, starting at position 'index'
+ // index: Number
+ // The index of the first thumbnail
+
+//FIXME: When is this be called with an invalid index? Do we need this check at all?
+// if(typeof index != "number"){ index = this._thumbIndex; }
+ index = Math.min(Math.max(index, 0), this._maxPhotos);
+
+ if(index >= this._maxPhotos){ return; }
+
+ var img = this._thumbs[index];
+ if(!img){ return; }
+
+ var left = img.offsetLeft - this.thumbsNode.offsetLeft;
+ var top = img.offsetTop - this.thumbsNode.offsetTop;
+ var offset = this.isHorizontal ? left : top;
+
+ if( (offset >= this.thumbScroller[this._scrollAttr]) &&
+ (offset + img[this._sizeAttr] <= this.thumbScroller[this._scrollAttr] + this._scrollerSize)
+ ){
+ // FIXME: WTF is this checking for?
+ return;
+ }
+
+
+ if(this.isScrollable){
+ var target = this.isHorizontal ? {x: left, y: 0} : { x:0, y:top};
+ dojox.fx.smoothScroll({
+ target: target,
+ win: this.thumbScroller,
+ duration:300,
+ easing:dojox.fx.easing.easeOut,
+ onEnd: dojo.hitch(this, "_checkLoad", img, index)
+ }).play(10);
+ }else{
+ if(this.isHorizontal){
+ this.thumbScroller.scrollLeft = left;
+ }else{
+ this.thumbScroller.scrollTop = top;
+ }
+ this._checkLoad(img, index);
+ }
+ },
+
+ markImageLoaded: function(index){
+ // summary: Changes a visual cue to show the image is loaded
+ // description: If 'useLoadNotifier' is set to true, then a visual cue is
+ // given to state whether the image is loaded or not. Calling this function
+ // marks an image as loaded.
+ var thumbNotifier = dojo.byId("loadingDiv_"+this.widgetid+"_"+index);
+ if(thumbNotifier){this._setThumbClass(thumbNotifier, "thumbLoaded");}
+ this._loadedImages[index] = true;
+ },
+
+ _setThumbClass: function(thumb, className){
+ // summary: Adds a CSS class to a thumbnail, only if 'autoLoad' is true
+ // thumb: DomNode
+ // The thumbnail DOM node to set the class on
+ // className: String
+ // The CSS class to add to the DOM node.
+ if(!this.autoLoad){ return; }
+ dojo.addClass(thumb, className);
+ },
+
+ _loadNextPage: function(){
+ // summary: Loads the next page of thumbnail images
+ if(this._loadInProgress){return;}
+ this._loadInProgress = true;
+ var start = this.request.start + (this._noImages ? 0 : this.pageSize);
+
+ var pos = start;
+ while(pos < this._thumbs.length && this._thumbs[pos]){pos ++;}
+
+ //Define the function to call when the items have been
+ //returned from the data store.
+ var complete = function(items, request){
+ if(items && items.length){
+ var itemCounter = 0;
+ var loadNext = dojo.hitch(this, function(){
+ if(itemCounter >= items.length){
+ this._loadInProgress = false;
+ return;
+ }
+ var counter = itemCounter++;
+
+ this._loadImage(items[counter], pos + counter, loadNext);
+ });
+ loadNext();
+
+ //Show or hide the navigation arrows on the thumbnails,
+ //depending on whether or not the widget is at the start,
+ //end, or middle of the list of images.
+ this._updateNavControls();
+ }else{
+ this._loadInProgress = false;
+ }
+ };
+
+ //Define the function to call if the store reports an error.
+ var error = function(){
+ this._loadInProgress = false;
+ console.debug("Error getting items");
+ };
+
+ this.request.onComplete = dojo.hitch(this, complete);
+ this.request.onError = dojo.hitch(this, error);
+
+ //Increment the start parameter. This is the dojo.data API's
+ //version of paging.
+ this.request.start = start;
+ this._noImages = false;
+
+ //Execute the request for data.
+ this.imageStore.fetch(this.request);
+
+ },
+
+ _loadImage: function(data, index, callback){
+ var url = this.imageStore.getValue(data,this.imageThumbAttr);
+ var img = document.createElement("img");
+ var imgContainer = document.createElement("div");
+ imgContainer.setAttribute("id","img_" + this.widgetid+"_"+index);
+ imgContainer.appendChild(img);
+ img._index = index;
+ img._data = data;
+
+ this._thumbs[index] = imgContainer;
+ var loadingDiv;
+ if(this.useLoadNotifier){
+ loadingDiv = document.createElement("div");
+ loadingDiv.setAttribute("id","loadingDiv_" + this.widgetid+"_"+index);
+
+ //If this widget was previously told that the main image for this
+ //thumb has been loaded, make the loading indicator transparent.
+ this._setThumbClass(loadingDiv,
+ this._loadedImages[index] ? "thumbLoaded":"thumbNotifier");
+
+ imgContainer.appendChild(loadingDiv);
+ }
+ var size = dojo.marginBox(this.thumbsNode);
+ var defaultSize;
+ var sizeParam;
+ if(this.isHorizontal){
+ defaultSize = this.thumbWidth;
+ sizeParam = 'w';
+ } else{
+ defaultSize = this.thumbHeight;
+ sizeParam = 'h';
+ }
+ size = size[sizeParam];
+ var sl = this.thumbScroller.scrollLeft, st = this.thumbScroller.scrollTop;
+ dojo.style(this.thumbsNode, this._sizeProperty, (size + defaultSize + 20) + "px");
+ //Remember the scroll values, as changing the size can alter them
+ this.thumbScroller.scrollLeft = sl;
+ this.thumbScroller.scrollTop = st;
+ this.thumbsNode.appendChild(imgContainer);
+
+ dojo.connect(img, "onload", this, function(){
+ var realSize = dojo.marginBox(img)[sizeParam];
+ this._totalSize += (Number(realSize) + 4);
+ dojo.style(this.thumbsNode, this._sizeProperty, this._totalSize + "px");
+
+ if(this.useLoadNotifier){dojo.style(loadingDiv, "width", (img.width - 4) + "px"); }
+ callback();
+ return false;
+ });
+
+ dojo.connect(img, "onclick", this, function(evt){
+ dojo.publish(this.getClickTopicName(), [{
+ index: evt.target._index,
+ data: evt.target._data,
+ url: img.getAttribute("src"),
+ largeUrl: this.imageStore.getValue(data,this.imageLargeAttr),
+ title: this.imageStore.getValue(data,this.titleAttr),
+ link: this.imageStore.getValue(data,this.linkAttr)
+ }]);
+ return false;
+ });
+ dojo.addClass(img, "imageGalleryThumb");
+ img.setAttribute("src", url);
+ var title = this.imageStore.getValue(data, this.titleAttr);
+ if(title){ img.setAttribute("title",title); }
+ this._updateNavControls();
+
+ },
+
+ _updateNavControls: function(){
+ // summary: Updates the navigation controls to hide/show them when at
+ // the first or last images.
+ var cells = [];
+ var change = function(node, add){
+ var fn = add ? "addClass" : "removeClass";
+ dojo[fn](node,"enabled");
+ dojo[fn](node,"thumbClickable");
+ };
+
+ var pos = this.isHorizontal ? "scrollLeft" : "scrollTop";
+ var size = this.isHorizontal ? "offsetWidth" : "offsetHeight";
+ change(this.navPrev, (this.thumbScroller[pos] > 0));
+
+ var last = this._thumbs[this._thumbs.length - 1];
+ var addClass = (this.thumbScroller[pos] + this._scrollerSize < this.thumbsNode[size]);
+ change(this.navNext, addClass);
+ }
+});
+
+}
diff --git a/includes/js/dojox/image/resources/Gallery.html b/includes/js/dojox/image/resources/Gallery.html
new file mode 100644
index 0000000..571dc4f
--- /dev/null
+++ b/includes/js/dojox/image/resources/Gallery.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/includes/js/dojox/image/resources/Lightbox.html b/includes/js/dojox/image/resources/Lightbox.html
new file mode 100644
index 0000000..1eb292f
--- /dev/null
+++ b/includes/js/dojox/image/resources/Lightbox.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
${title}
+
+
+
+
+
\ No newline at end of file
diff --git a/includes/js/dojox/image/resources/Magnifier.css b/includes/js/dojox/image/resources/Magnifier.css
new file mode 100644
index 0000000..85eba72
--- /dev/null
+++ b/includes/js/dojox/image/resources/Magnifier.css
@@ -0,0 +1,5 @@
+.glassNode {
+ overflow:hidden;
+ position:absolute;
+ visibility:hidden;
+}
diff --git a/includes/js/dojox/image/resources/Magnifier.css.commented.css b/includes/js/dojox/image/resources/Magnifier.css.commented.css
new file mode 100644
index 0000000..85eba72
--- /dev/null
+++ b/includes/js/dojox/image/resources/Magnifier.css.commented.css
@@ -0,0 +1,5 @@
+.glassNode {
+ overflow:hidden;
+ position:absolute;
+ visibility:hidden;
+}
diff --git a/includes/js/dojox/image/resources/SlideShow.html b/includes/js/dojox/image/resources/SlideShow.html
new file mode 100644
index 0000000..fa4aca6
--- /dev/null
+++ b/includes/js/dojox/image/resources/SlideShow.html
@@ -0,0 +1,14 @@
+
+
+
+
${title}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/includes/js/dojox/image/resources/ThumbnailPicker.html b/includes/js/dojox/image/resources/ThumbnailPicker.html
new file mode 100644
index 0000000..561ce2d
--- /dev/null
+++ b/includes/js/dojox/image/resources/ThumbnailPicker.html
@@ -0,0 +1,11 @@
+
They are just images. It's entirely unobtrusive to add magnification to an image, and style it accordingly.
+
This widget is based on dojox.image.MagnifierLite, an image-only variant on this dojox.gfx
+ based Widget. The idea was/is to include addational surfaces in some kind of _Templated GFX widget, based on _Widget.
They are just images. It's entirely unobtrusive to add magnification to an image, and style it accordingly.
+
+
This is the base class for dojox.image.Magnifier, a dojox.gfx-based extension
+ this portion does not require the dojox.gfx package, but is limited to CSS-based styling.
+
+
+
+ Scale= 2.34, 5.67, and 8.90:
+
+
+
+
+
+
+
+
+ I Am Some inline text. lorem ipsum.
+
+
+
A Transparent .png: (url unavailable in release versions, need build-utils package, or svn)
+
+
+
+
+
+ This SlideShow should display five photos, and loop. It should also
+ open a URL when the image is clicked. The widget should also resize to
+ fit the image.
+
+
+
from dojox.data.FlickrRestStore
+ This SlideShow should display five photos, and not loop. It should also not
+ open a URL when the image is clicked. AutoLoading of images is also disabled.
+ The time between images in a SlideShow is 1 second. The widget should not resize to fit the image
+
+
+
+
diff --git a/includes/js/dojox/image/tests/test_ThumbnailPicker.html b/includes/js/dojox/image/tests/test_ThumbnailPicker.html
new file mode 100644
index 0000000..90cdf2e
--- /dev/null
+++ b/includes/js/dojox/image/tests/test_ThumbnailPicker.html
@@ -0,0 +1,134 @@
+
+
+
+
+ Testing the ThumbnailPicker
+
+
+
+
+
+
+
+
+
+
+
dojox.image.ThumbnailPicker
+
+
+ When you click on a thumbnail image, it's information is placed here
+
+
+
From FlickrRestStore:
+ This ThumbnailPicker should have 8 thumbnails, with each of them linking
+ to a URL when clicked on. The cursor should also change when over an image.
+
+
+
From ItemFileReadStore:
+ This ThumbnailPicker should have 5 thumbnails. Clicking on a thumbnail should NOT
+ open a URL, and the cursor should not change when over an image that is not an arrow.
+
+
+
+
+
From FlickrRestStore:
+ This ThumbnailPicker should have 6 thumbnails, with each of them linking
+ to a URL when clicked on. The cursor should also change when over an image.
+ Unlike the ThumbnailPicker above, when these links are clicked on, this page
+ changes, instead of a popup window.
+
+
+
+
From ItemFileReadStore, and vertical:
+ This ThumbnailPicker should have 5 thumbnails. Clicking on a thumbnail should NOT
+ open a URL, and the cursor should not change when over an image that is not an arrow.
+ The thumbnails should also be aligned vertically.
+
+
+
+
--
cgit v1.2.3-54-g00ecf