From: Andreas Gohr Date: Wed, 13 Jun 2007 14:42:06 +0000 (+0200) Subject: JavaScript updates (migration to JQuery + Interface) X-Git-Tag: 0.7.1~66 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=b74cc3599894356f86ada356d5e9dc81c18cfbe1;p=contagged JavaScript updates (migration to JQuery + Interface) darcs-hash:20070613144206-6e07b-4685df44fbd80a81b6303950ece69f8347acdd38.gz --- diff --git a/ajax.php b/ajax.php index 7310180..75a5822 100644 --- a/ajax.php +++ b/ajax.php @@ -2,15 +2,35 @@ require_once('init.php'); ldap_login(); -header('Content-Type: text/html; charset=utf-8'); +header('Content-Type: text/xml; charset=utf-8'); +/* +echo '<[!CDATA['; +print_r($_REQUEST); +echo ']]>'; +*/ + +$FIELD = preg_replace('/entry\[/','',$_REQUEST['field']); +$FIELD = preg_replace('/\W+/','',$FIELD); + +if($FIELD == 'marker'||$FIELD == 'markers'){ + ajax_taglookup($_REQUEST['value']); +}else{ + ajax_lookup($FIELD,$_REQUEST['value']); +} + +/* if(!empty($_REQUEST['taglookup'])){ ajax_taglookup($_REQUEST['taglookup']); +}elseif(!empty($_REQUEST['lookup']) && !empty($_REQUEST['s'])){ + ajax_lookup($_REQUEST['lookup'],$_REQUEST['s']); }elseif(!empty($_REQUEST['addnote'])){ ajax_addnote($_REQUEST['addnote'],$_REQUEST['note']); }elseif(!empty($_REQUEST['settags'])){ ajax_settags($_REQUEST['settags'],$_REQUEST['tags']); } +*/ + /** * Add a note to the existing notes @@ -69,10 +89,11 @@ function ajax_settags($dn,$tags){ function ajax_taglookup($tag){ global $conf; global $LDAP_CON; + global $FIELDS; if(!$FIELDS['_marker']) return; $search = ldap_filterescape($tag); - $filter = "(&(objectClass=inetOrgPerson)('.$FIELDS['_marker'].'=$search*))"; + $filter = "(&(objectClass=inetOrgPerson)(".$FIELDS['_marker']."=$search*))"; $result = ldap_queryabooks($filter,$FIELDS['_marker']); if(!count($result)) return; @@ -91,11 +112,52 @@ function ajax_taglookup($tag){ $tags = array_unique($tags); sort($tags,SORT_STRING); - print ''; + echo ''.NL; +} + +/** + * Do a simple lookup in any simple field + */ +function ajax_lookup($field,$search){ + global $conf; + global $LDAP_CON; + global $FIELDS; + + if(!$FIELDS[$field]) return; + $field = $FIELDS[$field]; + + $search = ldap_filterescape($search); + $filter = "(&(objectClass=inetOrgPerson)($field=$search*))"; + $result = ldap_queryabooks($filter,$field); + if(!count($result)) return; + + $items = array(); + foreach ($result as $entry){ + if(isset($entry[$field]) && !empty($entry[$field])){ + $items[] = $entry[$field][0]; + } + } + + $items = array_unique($items); + sort($items,SORT_STRING); + + echo ''.NL; + echo ''.NL; + foreach($items as $out){ + echo ''.NL; + echo ''.htmlspecialchars($out).''.NL; + echo ''.htmlspecialchars($out).''.NL; + echo ''.NL; + } + echo ''.NL; } ?> diff --git a/init.php b/init.php index ec981fa..657a1c6 100644 --- a/init.php +++ b/init.php @@ -6,6 +6,8 @@ require_once('template.php'); require_once('smarty/Smarty.class.php'); + define('NL',"\n"); + //init session session_name("ldapab"); session_start(); diff --git a/scripts/gui.js b/scripts/gui.js new file mode 100644 index 0000000..3ec99e0 --- /dev/null +++ b/scripts/gui.js @@ -0,0 +1,50 @@ + + + + + +/** + * Initialize everything when DOM is ready + */ +$(document).ready(function() { + + // autocompletion + $('#taglookup').Autocomplete({ + source: 'ajax.php', + delay: 300, + helperClass: 'autocompleter', + selectClass: 'autocompleterSelect', + inputWidth: true, + minchars: 1, + //multiple: true, + //multipleSeperator: ',' + }); + $('#tageditlookup').Autocomplete({ + source: 'ajax.php', + delay: 300, + helperClass: 'autocompleter', + selectClass: 'autocompleterSelect', + inputWidth: true, + minchars: 1, + multiple: true, + multipleSeperator: ',' + }); + // autocompletion + $('input.ac').Autocomplete({ + source: 'ajax.php', + delay: 300, + helperClass: 'autocompleter', + selectClass: 'autocompleterSelect', + inputWidth: true, + minchars: 1, + }); + + $.ImageBox.init({ + loaderSRC: 'pix/imagebox/loading.gif', + closeHTML: '' + }); + + // set focus + if($('#searchfield')) $('#searchfield').focus(); + if($('#firstfield')) $('#firstfield').focus(); +}); diff --git a/scripts/interface/accordion.js b/scripts/interface/accordion.js new file mode 100644 index 0000000..a9e18d5 --- /dev/null +++ b/scripts/interface/accordion.js @@ -0,0 +1,165 @@ +/** + * Interface Elements for jQuery + * Accordion + * + * http://interface.eyecon.ro + * + * Copyright (c) 2006 Stefan Petre + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + */ + +/** + * Create an accordion from a HTML structure + * + * @example $('#myAccordion').Accordion( + * { + * headerSelector : 'dt', + * panelSelector : 'dd', + * activeClass : 'myAccordionActive', + * hoverClass : 'myAccordionHover', + * panelHeight : 200, + * speed : 300 + * } + * ); + * @desc Converts definition list with id 'myAccordion' into an accordion width dt tags as headers and dd tags as panels + * + * @name Accordion + * @description Create an accordion from a HTML structure + * @param Hash hash A hash of parameters + * @option Integer panelHeight the pannels' height + * @option String headerSelector selector for header elements + * @option String panelSelector selector for panel elements + * @option String activeClass (optional) CSS Class for active header + * @option String hoverClass (optional) CSS Class for hovered header + * @option Function onShow (optional) callback called whenever an pannel gets active + * @option Function onHide (optional) callback called whenever an pannel gets incative + * @option Function onClick (optional) callback called just before an panel gets active + * @option Mixed speed (optional) animation speed, integer for miliseconds, string ['slow' | 'normal' | 'fast'] + * @option Integer crrentPanel (otional) the active panel on initialisation + * + * @type jQuery + * @cat Plugins/Interface + * @author Stefan Petre + */ +jQuery.iAccordion = { + build : function(options) + { + return this.each( + function() + { + if (!options.headerSelector || !options.panelSelector) + return; + var el = this; + el.accordionCfg = { + panelHeight : options.panelHeight||300, + headerSelector : options.headerSelector, + panelSelector : options.panelSelector, + activeClass : options.activeClass||'fakeAccordionClass', + hoverClass : options.hoverClass||'fakeAccordionClass', + onShow : options.onShow && typeof options.onShow == 'function' ? options.onShow : false, + onHide : options.onShow && typeof options.onHide == 'function' ? options.onHide : false, + onClick : options.onClick && typeof options.onClick == 'function' ? options.onClick : false, + headers : jQuery(options.headerSelector, this), + panels : jQuery(options.panelSelector, this), + speed : options.speed||400, + currentPanel : options.currentPanel||0 + }; + el.accordionCfg.panels + .hide() + .css('height', '1px') + .eq(0) + .css( + { + height: el.accordionCfg.panelHeight + 'px', + display: 'block' + } + ) + .end(); + + el.accordionCfg.headers + .each( + function(nr) + { + this.accordionPos = nr; + } + ) + .hover( + function() + { + jQuery(this).addClass(el.accordionCfg.hoverClass); + }, + function() + { + jQuery(this).removeClass(el.accordionCfg.hoverClass); + } + ) + .bind( + 'click', + function(e) + { + if (el.accordionCfg.currentPanel == this.accordionPos) + return; + el.accordionCfg.headers + .eq(el.accordionCfg.currentPanel) + .removeClass(el.accordionCfg.activeClass) + .end() + .eq(this.accordionPos) + .addClass(el.accordionCfg.activeClass) + .end(); + el.accordionCfg.panels + .eq(el.accordionCfg.currentPanel) + .animate( + {height:0}, + el.accordionCfg.speed, + function() + { + this.style.display = 'none'; + if (el.accordionCfg.onHide) { + el.accordionCfg.onHide.apply(el, [this]); + } + } + ) + .end() + .eq(this.accordionPos) + .show() + .animate ( + {height:el.accordionCfg.panelHeight}, + el.accordionCfg.speed, + function() + { + this.style.display = 'block'; + if (el.accordionCfg.onShow) { + el.accordionCfg.onShow.apply(el, [this]); + } + } + ) + .end(); + + if (el.accordionCfg.onClick) { + el.accordionCfg.onClick.apply( + el, + [ + this, + el.accordionCfg.panels.get(this.accordionPos), + el.accordionCfg.headers.get(el.accordionCfg.currentPanel), + el.accordionCfg.panels.get(el.accordionCfg.currentPanel) + ] + ); + } + el.accordionCfg.currentPanel = this.accordionPos; + } + ) + .eq(0) + .addClass(el.accordionCfg.activeClass) + .end(); + jQuery(this) + .css('height', jQuery(this).css('height')) + .css('overflow', 'hidden'); + } + ); + } +}; + +jQuery.fn.Accordion = jQuery.iAccordion.build; \ No newline at end of file diff --git a/scripts/interface/carousel.js b/scripts/interface/carousel.js new file mode 100644 index 0000000..7ed1c7f --- /dev/null +++ b/scripts/interface/carousel.js @@ -0,0 +1,257 @@ +/** + * Interface Elements for jQuery + * 3D Carousel + * + * http://interface.eyecon.ro + * + * Copyright (c) 2006 Stefan Petre + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + */ +/** + * Created a 3D Carousel from a list of images, with reflections and animated by mouse position + * + * @example window.onload = + * function() + * { + * $('#carousel').Carousel( + * { + * itemWidth: 110, + * itemHeight: 62, + * itemMinWidth: 50, + * items: 'a', + * reflections: .5, + * rotationSpeed: 1.8 + * } + * ); + * } + * HTML + * + * CSS + * #carousel + * { + * width: 700px; + * height: 150px; + * background-color: #111; + * position: absolute; + * top: 200px; + * left: 100px; + * } + * #carousel a + * { + * position: absolute; + * width: 110px; + * } + * + * @desc Creates a 3D carousel from all images inside div tag with id 'carousel' + * + * + * @name 3D Carousel + * @description Created a 3D Carousel from a list of images, with reflections and animated by mouse position + * @param Hash hash A hash of parameters + * @option String items items selection + * @option Integer itemWidth the max width for each item + * @option Integer itemHeight the max height for each item + * @option Integer itemMinWidth the minimum width for each item, the height is automaticaly calculated to keep proportions + * @option Float rotationSpeed the speed for rotation animation + * @option Float reflectionSize the reflection size a fraction from items' height + * + * @type jQuery + * @cat Plugins/Interface + * @author Stefan Petre + */ +jQuery.iCarousel = { + + build : function(options) + { + return this.each( + function() + { + var el = this; + var increment = 2*Math.PI/360; + var maxRotation = 2*Math.PI; + if(jQuery(el).css('position') != 'relative' && jQuery(el).css('position') != 'absolute') { + jQuery(el).css('position', 'relative'); + } + el.carouselCfg = { + items : jQuery(options.items, this), + itemWidth : options.itemWidth, + itemHeight : options.itemHeight, + itemMinWidth : options.itemMinWidth, + maxRotation : maxRotation, + size : jQuery.iUtil.getSize(this), + position : jQuery.iUtil.getPosition(this), + start : Math.PI/2, + rotationSpeed : options.rotationSpeed, + reflectionSize : options.reflections, + reflections : [], + protectRotation : false, + increment: 2*Math.PI/360 + }; + el.carouselCfg.radiusX = (el.carouselCfg.size.w - el.carouselCfg.itemWidth)/2; + el.carouselCfg.radiusY = (el.carouselCfg.size.h - el.carouselCfg.itemHeight - el.carouselCfg.itemHeight * el.carouselCfg.reflectionSize)/2; + el.carouselCfg.step = 2*Math.PI/el.carouselCfg.items.size(); + el.carouselCfg.paddingX = el.carouselCfg.size.w/2; + el.carouselCfg.paddingY = el.carouselCfg.size.h/2 - el.carouselCfg.itemHeight * el.carouselCfg.reflectionSize; + var reflexions = document.createElement('div'); + jQuery(reflexions) + .css( + { + position: 'absolute', + zIndex: 1, + top: 0, + left: 0 + } + ); + jQuery(el).append(reflexions); + el.carouselCfg.items + .each( + function(nr) + { + image = jQuery('img', this).get(0); + height = parseInt(el.carouselCfg.itemHeight*el.carouselCfg.reflectionSize); + if (jQuery.browser.msie) { + canvas = document.createElement('img'); + jQuery(canvas).css('position', 'absolute'); + canvas.src = image.src; + canvas.style.filter = 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity=60, style=1, finishOpacity=0, startx=0, starty=0, finishx=0)'; + + } else { + canvas = document.createElement('canvas'); + if (canvas.getContext) { + context = canvas.getContext("2d"); + canvas.style.position = 'absolute'; + canvas.style.height = height +'px'; + canvas.style.width = el.carouselCfg.itemWidth+'px'; + canvas.height = height; + canvas.width = el.carouselCfg.itemWidth; + context.save(); + + context.translate(0,height); + context.scale(1,-1); + + context.drawImage( + image, + 0, + 0, + el.carouselCfg.itemWidth, + height + ); + + context.restore(); + + context.globalCompositeOperation = "destination-out"; + var gradient = context.createLinearGradient( + 0, + 0, + 0, + height + ); + + gradient.addColorStop(1, "rgba(255, 255, 255, 1)"); + gradient.addColorStop(0, "rgba(255, 255, 255, 0.6)"); + + context.fillStyle = gradient; + if (navigator.appVersion.indexOf('WebKit') != -1) { + context.fill(); + } else { + context.fillRect( + 0, + 0, + el.carouselCfg.itemWidth, + height + ); + } + } + } + + el.carouselCfg.reflections[nr] = canvas; + jQuery(reflexions).append(canvas); + } + ) + .bind( + 'mouseover', + function(e) + { + el.carouselCfg.protectRotation = true; + el.carouselCfg.speed = el.carouselCfg.increment*0.1 * el.carouselCfg.speed / Math.abs(el.carouselCfg.speed); + return false; + } + ) + .bind( + 'mouseout', + function(e) + { + el.carouselCfg.protectRotation = false; + return false; + } + ); + jQuery.iCarousel.positionItems(el); + el.carouselCfg.speed = el.carouselCfg.increment*0.2; + el.carouselCfg.rotationTimer = window.setInterval( + function() + { + el.carouselCfg.start += el.carouselCfg.speed; + if (el.carouselCfg.start > maxRotation) + el.carouselCfg.start = 0; + jQuery.iCarousel.positionItems(el); + }, + 20 + ); + jQuery(el) + .bind( + 'mouseout', + function() + { + el.carouselCfg.speed = el.carouselCfg.increment*0.2 * el.carouselCfg.speed / Math.abs(el.carouselCfg.speed); + } + ) + .bind( + 'mousemove', + function(e) + { + if (el.carouselCfg.protectRotation == false) { + pointer = jQuery.iUtil.getPointer(e); + mousex = el.carouselCfg.size.w - pointer.x + el.carouselCfg.position.x; + el.carouselCfg.speed = el.carouselCfg.rotationSpeed * el.carouselCfg.increment * (el.carouselCfg.size.w/2 - mousex) / (el.carouselCfg.size.w/2); + } + } + ); + } + ); + }, + + positionItems : function(el) + { + el.carouselCfg.items.each( + function (nr) + { + angle = el.carouselCfg.start+nr*el.carouselCfg.step; + x = el.carouselCfg.radiusX*Math.cos(angle); + y = el.carouselCfg.radiusY*Math.sin(angle) ; + itemZIndex = parseInt(100*(el.carouselCfg.radiusY+y)/(2*el.carouselCfg.radiusY)); + parte = (el.carouselCfg.radiusY+y)/(2*el.carouselCfg.radiusY); + + width = parseInt((el.carouselCfg.itemWidth - el.carouselCfg.itemMinWidth) * parte + el.carouselCfg.itemMinWidth); + height = parseInt(width * el.carouselCfg.itemHeight / el.carouselCfg.itemWidth); + this.style.top = el.carouselCfg.paddingY + y - height/2 + "px"; + this.style.left = el.carouselCfg.paddingX + x - width/2 + "px"; + this.style.width = width + "px"; + this.style.height = height + "px"; + this.style.zIndex = itemZIndex; + el.carouselCfg.reflections[nr].style.top = parseInt(el.carouselCfg.paddingY + y + height - 1 - height/2) + "px"; + el.carouselCfg.reflections[nr].style.left = parseInt(el.carouselCfg.paddingX + x - width/2) + "px"; + el.carouselCfg.reflections[nr].style.width = width + "px"; + el.carouselCfg.reflections[nr].style.height = parseInt(height * el.carouselCfg.reflectionSize) + "px"; + } + ); + } +}; +jQuery.fn.Carousel = jQuery.iCarousel.build; \ No newline at end of file diff --git a/scripts/interface/easing.js b/scripts/interface/easing.js new file mode 100644 index 0000000..7b074cf --- /dev/null +++ b/scripts/interface/easing.js @@ -0,0 +1,124 @@ +/** + * Interface Elements for jQuery + * Easing formulas + * + * http://interface.eyecon.ro + * + * Copyright (c) 2006 Stefan Petre + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + */ + +/** + * Starting with jQuery 1.1 the fx function accepts easing formulas that can be used with .animation() and most of FX plugins from Interface. The object can be extended to accept new easing formulas + */ + + jQuery.extend({ + /** + * + * @param Integer p period step in animation + * @param Integer n current time + * @param Mixed firstNum begin value + * @param Mixed delta change in + * @param Integer duration duration + */ + easing : { + linear: function(p, n, firstNum, delta, duration) { + return ((-Math.cos(p*Math.PI)/2) + 0.5) * delta + firstNum; + }, + + easein: function(p, n, firstNum, delta, duration) { + return delta*(n/=duration)*n*n + firstNum; + }, + + easeout: function(p, n, firstNum, delta, duration) { + return -delta * ((n=n/duration-1)*n*n*n - 1) + firstNum; + }, + + easeboth: function(p, n, firstNum, delta, duration) { + if ((n/=duration/2) < 1) + return delta/2*n*n*n*n + firstNum; + return -delta/2 * ((n-=2)*n*n*n - 2) + firstNum; + }, + + bounceout: function(p, n, firstNum, delta, duration) { + if ((n/=duration) < (1/2.75)) { + return delta*(7.5625*n*n) + firstNum; + } else if (n < (2/2.75)) { + return delta*(7.5625*(n-=(1.5/2.75))*n + .75) + firstNum; + } else if (n < (2.5/2.75)) { + return delta*(7.5625*(n-=(2.25/2.75))*n + .9375) + firstNum; + } else { + return delta*(7.5625*(n-=(2.625/2.75))*n + .984375) + firstNum; + } + }, + + bouncein: function(p, n, firstNum, delta, duration) { + if (jQuery.easing.bounceout) + return delta - jQuery.easing.bounceout (p, duration - n, 0, delta, duration) + firstNum; + return firstNum + delta; + }, + + bounceboth: function(p, n, firstNum, delta, duration) { + if (jQuery.easing.bouncein && jQuery.easing.bounceout) + if (n < duration/2) + return jQuery.easing.bouncein(p, n*2, 0, delta, duration) * .5 + firstNum; + return jQuery.easing.bounceout(p, n*2-duration, 0, delta, duration) * .5 + delta*.5 + firstNum; + return firstNum + delta; + }, + + elasticin: function(p, n, firstNum, delta, duration) { + var a, s; + if (n == 0) + return firstNum; + if ((n/=duration)==1) + return firstNum+delta; + a = delta * 0.3; + p=duration*.3; + if (a < Math.abs(delta)) { + a=delta; + s=p/4; + } else { + s = p/(2*Math.PI) * Math.asin (delta/a); + } + return -(a*Math.pow(2,10*(n-=1)) * Math.sin( (n*duration-s)*(2*Math.PI)/p )) + firstNum; + }, + + elasticout:function(p, n, firstNum, delta, duration) { + var a, s; + if (n==0) + return firstNum; + if ((n/=duration/2)==2) + return firstNum + delta; + a = delta * 0.3; + p=duration*.3; + if (a < Math.abs(delta)){ + a = delta; + s=p/4; + } else { + s = p/(2*Math.PI) * Math.asin (delta/a); + } + return a*Math.pow(2,-10*n) * Math.sin( (n*duration-s)*(2*Math.PI)/p ) + delta + firstNum; + }, + + elasticboth: function(p, n, firstNum, delta, duration) { + var a, s; + if (n==0) + return firstNum; + if ((n/=duration/2)==2) + return firstNum + delta; + a = delta * 0.3; + p=duration*.3; + if (a < Math.abs(delta)){ + a = delta; + s=p/4; + } else { + s = p/(2*Math.PI) * Math.asin (delta/a); + } + if (n < 1) { + return -.5*(a*Math.pow(2,10*(n-=1)) * Math.sin( (n*duration-s)*(2*Math.PI)/p )) + firstNum; + } + return a*Math.pow(2,-10*(n-=1)) * Math.sin( (n*duration-s)*(2*Math.PI)/p )*.5 + delta + firstNum; + } + } +}); \ No newline at end of file diff --git a/scripts/interface/fisheye.js b/scripts/interface/fisheye.js new file mode 100644 index 0000000..28079b4 --- /dev/null +++ b/scripts/interface/fisheye.js @@ -0,0 +1,142 @@ +/** + * Interface Elements for jQuery + * Fisheye menu + * + * http://interface.eyecon.ro + * + * Copyright (c) 2006 Stefan Petre + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + */ + +/** + * Build a Fisheye menu from a list of links + * + * @name Fisheye + * @description Build a Fisheye menu from a list of links + * @param Hash hash A hash of parameters + * @option String items items selection + * @option String container container element + * @option Integer itemWidth the minimum width for each item + * @option Integer maxWidth the maximum width for each item + * @option String itemsText selection of element that contains the text for each item + * @option Integer proximity the distance from element that make item to interact + * @option String valign vertical alignment + * @option String halign horizontal alignment + * + * @type jQuery + * @cat Plugins/Interface + * @author Stefan Petre + */ +jQuery.iFisheye = { + + build : function(options) + { + + return this.each( + function() + { + var el = this; + el.fisheyeCfg = { + items : jQuery(options.items, this), + container: jQuery(options.container, this), + pos : jQuery.iUtil.getPosition(this), + itemWidth: options.itemWidth, + itemsText: options.itemsText, + proximity: options.proximity, + valign: options.valign, + halign: options.halign, + maxWidth : options.maxWidth + }; + jQuery.iFisheye.positionContainer(el, 0); + jQuery(window).bind( + 'resize', + function() + { + el.fisheyeCfg.pos = jQuery.iUtil.getPosition(el); + jQuery.iFisheye.positionContainer(el, 0); + jQuery.iFisheye.positionItems(el); + } + ); + jQuery.iFisheye.positionItems(el); + el.fisheyeCfg.items + .bind( + 'mouseover', + function() + { + jQuery(el.fisheyeCfg.itemsText, this).get(0).style.display = 'block'; + } + ) + .bind( + 'mouseout', + function() + { + jQuery(el.fisheyeCfg.itemsText, this).get(0).style.display = 'none'; + } + ); + jQuery(document).bind( + 'mousemove', + function(e) + { + var pointer = jQuery.iUtil.getPointer(e); + var toAdd = 0; + if (el.fisheyeCfg.halign && el.fisheyeCfg.halign == 'center') + var posx = pointer.x - el.fisheyeCfg.pos.x - (el.offsetWidth - el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size())/2 - el.fisheyeCfg.itemWidth/2; + else if (el.fisheyeCfg.halign && el.fisheyeCfg.halign == 'right') + var posx = pointer.x - el.fisheyeCfg.pos.x - el.offsetWidth + el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size(); + else + var posx = pointer.x - el.fisheyeCfg.pos.x; + var posy = Math.pow(pointer.y - el.fisheyeCfg.pos.y - el.offsetHeight/2,2); + el.fisheyeCfg.items.each( + function(nr) + { + distance = Math.sqrt( + Math.pow(posx - nr*el.fisheyeCfg.itemWidth, 2) + + posy + ); + distance -= el.fisheyeCfg.itemWidth/2; + + distance = distance < 0 ? 0 : distance; + distance = distance > el.fisheyeCfg.proximity ? el.fisheyeCfg.proximity : distance; + distance = el.fisheyeCfg.proximity - distance; + + extraWidth = el.fisheyeCfg.maxWidth * distance/el.fisheyeCfg.proximity; + + this.style.width = el.fisheyeCfg.itemWidth + extraWidth + 'px'; + this.style.left = el.fisheyeCfg.itemWidth * nr + toAdd + 'px'; + toAdd += extraWidth; + } + ); + jQuery.iFisheye.positionContainer(el, toAdd); + } + ); + } + ) + }, + + positionContainer : function(el, toAdd) + { + if (el.fisheyeCfg.halign) + if (el.fisheyeCfg.halign == 'center') + el.fisheyeCfg.container.get(0).style.left = (el.offsetWidth - el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size())/2 - toAdd/2 + 'px'; + else if (el.fisheyeCfg.halign == 'left') + el.fisheyeCfg.container.get(0).style.left = - toAdd/el.fisheyeCfg.items.size() + 'px'; + else if (el.fisheyeCfg.halign == 'right') + el.fisheyeCfg.container.get(0).style.left = (el.offsetWidth - el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size()) - toAdd/2 + 'px'; + el.fisheyeCfg.container.get(0).style.width = el.fisheyeCfg.itemWidth * el.fisheyeCfg.items.size() + toAdd + 'px'; + }, + + positionItems : function(el) + { + el.fisheyeCfg.items.each( + function(nr) + { + this.style.width = el.fisheyeCfg.itemWidth + 'px'; + this.style.left = el.fisheyeCfg.itemWidth * nr + 'px'; + } + ); + } +}; + +jQuery.fn.Fisheye = jQuery.iFisheye.build; \ No newline at end of file diff --git a/scripts/interface/iautocompleter.js b/scripts/interface/iautocompleter.js new file mode 100644 index 0000000..c7e34da --- /dev/null +++ b/scripts/interface/iautocompleter.js @@ -0,0 +1,537 @@ +/** + * Interface Elements for jQuery + * Autocompleter + * + * http://interface.eyecon.ro + * + * Copyright (c) 2006 Stefan Petre + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + */ + +/** + * Attach AJAX driven autocomplete/sugestion box to text input fields. + * + * + * + * @name Autocomplete + * @description Attach AJAX driven autocomplete/sugestion box to text input fields. + * @param Hash hash A hash of parameters + * @option String source the URL to request + * @option Integer delay (optional) the delayed time to start the AJAX request + * @option Boolean autofill (optional) when true the first sugested value fills the input + * @option String helperClass (optional) the CSS class applied to sugestion box + * @option String selectClass (optional) the CSS class applied to selected/hovered item + * @option Integer minchars (optional) the number of characters needed before starting AJAX request + * @option Hash fx (optional) {type:[slide|blind|fade]; duration: integer} the fx type to apply to sugestion box and duration for that fx + * @option Function onSelect (optional) A function to be executed whenever an item it is selected + * @option Function onShow (optional) A function to be executed whenever the suggection box is displayed + * @option Function onHide (optional) A function to be executed whenever the suggection box is hidden + * @option Function onHighlight (optional) A function to be executed whenever an item it is highlighted + * + * @type jQuery + * @cat Plugins/Interface + * @author Stefan Petre + */ +jQuery.iAuto = { + helper : null, + content : null, + iframe: null, + timer : null, + lastValue: null, + currentValue: null, + subject: null, + selectedItem : null, + items: null, + + empty : function() + { + jQuery.iAuto.content.empty(); + if (jQuery.iAuto.iframe) { + jQuery.iAuto.iframe.hide(); + } + }, + + clear : function() + { + jQuery.iAuto.items = null; + jQuery.iAuto.selectedItem = null; + jQuery.iAuto.lastValue = jQuery.iAuto.subject.value; + if(jQuery.iAuto.helper.css('display') == 'block') { + if (jQuery.iAuto.subject.autoCFG.fx) { + switch(jQuery.iAuto.subject.autoCFG.fx.type) { + case 'fade': + jQuery.iAuto.helper.fadeOut(jQuery.iAuto.subject.autoCFG.fx.duration, jQuery.iAuto.empty); + break; + case 'slide': + jQuery.iAuto.helper.SlideOutUp(jQuery.iAuto.subject.autoCFG.fx.duration, jQuery.iAuto.empty); + break; + case 'blind': + jQuery.iAuto.helper.BlindUp(jQuery.iAuto.subject.autoCFG.fx.duration, jQuery.iAuto.empty); + break; + } + } else { + jQuery.iAuto.helper.hide(); + } + if (jQuery.iAuto.subject.autoCFG.onHide) + jQuery.iAuto.subject.autoCFG.onHide.apply(jQuery.iAuto.subject, [jQuery.iAuto.helper, jQuery.iAuto.iframe]); + } else { + jQuery.iAuto.empty(); + } + window.clearTimeout(jQuery.iAuto.timer); + }, + + update : function () + { + var subject = jQuery.iAuto.subject; + var subjectValue = jQuery.iAuto.getFieldValues(subject); + //var selectionStart = jQuery.iAuto.getSelectionStart(subject); + if (subject && subjectValue.item != jQuery.iAuto.lastValue && subjectValue.item.length >= subject.autoCFG.minchars) { + jQuery.iAuto.lastValue = subjectValue.item; + jQuery.iAuto.currentValue = subjectValue.item; + + data = { + field: jQuery(subject).attr('name')||'field', + value: subjectValue.item + }; + + jQuery.ajax( + { + type: 'POST', + data: jQuery.param(data), + success: function(xml) + { + subject.autoCFG.lastSuggestion = jQuery('item',xml); + size = subject.autoCFG.lastSuggestion.size(); + if (size > 0) { + var toWrite = ''; + subject.autoCFG.lastSuggestion.each( + function(nr) + { + toWrite += '
  • ' + jQuery('text', this).text() + '
  • '; + } + ); + if (subject.autoCFG.autofill) { + var valueToAdd = jQuery('value', subject.autoCFG.lastSuggestion.get(0)).text(); + subject.value = subjectValue.pre + valueToAdd + subject.autoCFG.multipleSeparator + subjectValue.post; + jQuery.iAuto.selection( + subject, + subjectValue.item.length != valueToAdd.length ? (subjectValue.pre.length + subjectValue.item.length) : valueToAdd.length, + subjectValue.item.length != valueToAdd.length ? (subjectValue.pre.length + valueToAdd.length) : valueToAdd.length + ); + } + + if (size > 0) { + jQuery.iAuto.writeItems(subject, toWrite); + } else { + jQuery.iAuto.clear(); + } + } else { + jQuery.iAuto.clear(); + } + }, + url : subject.autoCFG.source + } + ); + } + }, + + writeItems : function(subject, toWrite) + { + jQuery.iAuto.content.html(toWrite); + jQuery.iAuto.items = jQuery('li', jQuery.iAuto.content.get(0)); + jQuery.iAuto.items + .mouseover(jQuery.iAuto.hoverItem) + .bind('click', jQuery.iAuto.clickItem); + var position = jQuery.iUtil.getPosition(subject); + var size = jQuery.iUtil.getSize(subject); + jQuery.iAuto.helper + .css('top', position.y + size.hb + 'px') + .css('left', position.x + 'px') + .addClass(subject.autoCFG.helperClass); + if (jQuery.iAuto.iframe) { + jQuery.iAuto.iframe + .css('display', 'block') + .css('top', position.y + size.hb + 'px') + .css('left', position.x + 'px') + .css('width', jQuery.iAuto.helper.css('width')) + .css('height', jQuery.iAuto.helper.css('height')); + } + jQuery.iAuto.selectedItem = 0; + jQuery.iAuto.items.get(0).className = subject.autoCFG.selectClass; + jQuery.iAuto.applyOn(subject,subject.autoCFG.lastSuggestion.get(0), 'onHighlight'); + + if (jQuery.iAuto.helper.css('display') == 'none') { + if (subject.autoCFG.inputWidth) { + var borders = jQuery.iUtil.getPadding(subject, true); + var paddings = jQuery.iUtil.getBorder(subject, true); + jQuery.iAuto.helper.css('width', subject.offsetWidth - (jQuery.boxModel ? (borders.l + borders.r + paddings.l + paddings.r) : 0 ) + 'px'); + } + if (subject.autoCFG.fx) { + switch(subject.autoCFG.fx.type) { + case 'fade': + jQuery.iAuto.helper.fadeIn(subject.autoCFG.fx.duration); + break; + case 'slide': + jQuery.iAuto.helper.SlideInUp(subject.autoCFG.fx.duration); + break; + case 'blind': + jQuery.iAuto.helper.BlindDown(subject.autoCFG.fx.duration); + break; + } + } else { + jQuery.iAuto.helper.show(); + } + + if (jQuery.iAuto.subject.autoCFG.onShow) + jQuery.iAuto.subject.autoCFG.onShow.apply(jQuery.iAuto.subject, [jQuery.iAuto.helper, jQuery.iAuto.iframe]); + } + }, + + checkCache : function() + { + var subject = this; + if (subject.autoCFG.lastSuggestion) { + + jQuery.iAuto.lastValue = subject.value; + jQuery.iAuto.currentValue = subject.value; + + var toWrite = ''; + subject.autoCFG.lastSuggestion.each( + function(nr) + { + value = jQuery('value', this).text().toLowerCase(); + inputValue = subject.value.toLowerCase(); + if (value.indexOf(inputValue) == 0) { + toWrite += '
  • ' + jQuery('text', this).text() + '
  • '; + } + } + ); + + if (toWrite != '') { + jQuery.iAuto.writeItems(subject, toWrite); + + this.autoCFG.inCache = true; + return; + } + } + subject.autoCFG.lastSuggestion = null; + this.autoCFG.inCache = false; + }, + + selection : function(field, start, end) + { + if (field.createTextRange) { + var selRange = field.createTextRange(); + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", - end + start); + selRange.select(); + } else if (field.setSelectionRange) { + field.setSelectionRange(start, end); + } else { + if (field.selectionStart) { + field.selectionStart = start; + field.selectionEnd = end; + } + } + field.focus(); + }, + + getSelectionStart : function(field) + { + if (field.selectionStart) + return field.selectionStart; + else if(field.createTextRange) { + var selRange = document.selection.createRange(); + var selRange2 = selRange.duplicate(); + return 0 - selRange2.moveStart('character', -100000); + //result.end = result.start + range.text.length; + /*var selRange = document.selection.createRange(); + var isCollapsed = selRange.compareEndPoints("StartToEnd", selRange) == 0; + if (!isCollapsed) + selRange.collapse(true); + var bookmark = selRange.getBookmark(); + return bookmark.charCodeAt(2) - 2;*/ + } + }, + + getFieldValues : function(field) + { + var fieldData = { + value: field.value, + pre: '', + post: '', + item: '' + }; + + if(field.autoCFG.multiple) { + var finishedPre = false; + var selectionStart = jQuery.iAuto.getSelectionStart(field)||0; + var chunks = fieldData.value.split(field.autoCFG.multipleSeparator); + for (var i=0; i= selectionStart + || + selectionStart == 0) + && + !finishedPre + ) { + if (fieldData.pre.length <= selectionStart) + fieldData.item = chunks[i]; + else + fieldData.post += chunks[i] + (chunks[i] != '' ? field.autoCFG.multipleSeparator : ''); + finishedPre = true; + } else if (finishedPre){ + fieldData.post += chunks[i] + (chunks[i] != '' ? field.autoCFG.multipleSeparator : ''); + } + if(!finishedPre) { + fieldData.pre += chunks[i] + (chunks.length > 1 ? field.autoCFG.multipleSeparator : ''); + } + } + } else { + fieldData.item = fieldData.value; + } + return fieldData; + }, + + autocomplete : function(e) + { + window.clearTimeout(jQuery.iAuto.timer); + var subject = jQuery.iAuto.getFieldValues(this); + + var pressedKey = e.charCode || e.keyCode || -1; + if (/13|27|35|36|38|40|9/.test(pressedKey) && jQuery.iAuto.items) { + if (window.event) { + window.event.cancelBubble = true; + window.event.returnValue = false; + } else { + e.preventDefault(); + e.stopPropagation(); + } + if (jQuery.iAuto.selectedItem != null) + jQuery.iAuto.items.get(jQuery.iAuto.selectedItem||0).className = ''; + else + jQuery.iAuto.selectedItem = -1; + switch(pressedKey) { + //enter + case 9: + case 13: + if (jQuery.iAuto.selectedItem == -1) + jQuery.iAuto.selectedItem = 0; + var selectedItem = jQuery.iAuto.items.get(jQuery.iAuto.selectedItem||0); + var valueToAdd = selectedItem.getAttribute('rel'); + this.value = subject.pre + valueToAdd + this.autoCFG.multipleSeparator + subject.post; + jQuery.iAuto.lastValue = subject.item; + jQuery.iAuto.selection( + this, + subject.pre.length + valueToAdd.length + this.autoCFG.multipleSeparator.length, + subject.pre.length + valueToAdd.length + this.autoCFG.multipleSeparator.length + ); + jQuery.iAuto.clear(); + if (this.autoCFG.onSelect) { + iteration = parseInt(selectedItem.getAttribute('dir'))||0; + jQuery.iAuto.applyOn(this,this.autoCFG.lastSuggestion.get(iteration), 'onSelect'); + } + if (this.scrollIntoView) + this.scrollIntoView(false); + return pressedKey != 13; + break; + //escape + case 27: + this.value = subject.pre + jQuery.iAuto.lastValue + this.autoCFG.multipleSeparator + subject.post; + this.autoCFG.lastSuggestion = null; + jQuery.iAuto.clear(); + if (this.scrollIntoView) + this.scrollIntoView(false); + return false; + break; + //end + case 35: + jQuery.iAuto.selectedItem = jQuery.iAuto.items.size() - 1; + break; + //home + case 36: + jQuery.iAuto.selectedItem = 0; + break; + //up + case 38: + jQuery.iAuto.selectedItem --; + if (jQuery.iAuto.selectedItem < 0) + jQuery.iAuto.selectedItem = jQuery.iAuto.items.size() - 1; + break; + case 40: + jQuery.iAuto.selectedItem ++; + if (jQuery.iAuto.selectedItem == jQuery.iAuto.items.size()) + jQuery.iAuto.selectedItem = 0; + break; + } + jQuery.iAuto.applyOn(this,this.autoCFG.lastSuggestion.get(jQuery.iAuto.selectedItem||0), 'onHighlight'); + jQuery.iAuto.items.get(jQuery.iAuto.selectedItem||0).className = this.autoCFG.selectClass; + if (jQuery.iAuto.items.get(jQuery.iAuto.selectedItem||0).scrollIntoView) + jQuery.iAuto.items.get(jQuery.iAuto.selectedItem||0).scrollIntoView(false); + if(this.autoCFG.autofill) { + var valToAdd = jQuery.iAuto.items.get(jQuery.iAuto.selectedItem||0).getAttribute('rel'); + this.value = subject.pre + valToAdd + this.autoCFG.multipleSeparator + subject.post; + if(jQuery.iAuto.lastValue.length != valToAdd.length) + jQuery.iAuto.selection( + this, + subject.pre.length + jQuery.iAuto.lastValue.length, + subject.pre.length + valToAdd.length + ); + } + return false; + } + jQuery.iAuto.checkCache.apply(this); + + if (this.autoCFG.inCache == false) { + if (subject.item != jQuery.iAuto.lastValue && subject.item.length >= this.autoCFG.minchars) + jQuery.iAuto.timer = window.setTimeout(jQuery.iAuto.update, this.autoCFG.delay); + if (jQuery.iAuto.items) { + jQuery.iAuto.clear(); + } + } + return true; + }, + + applyOn: function(field, item, type) + { + if (field.autoCFG[type]) { + var data = {}; + childs = item.getElementsByTagName('*'); + for(i=0; i