| /** |
| ** Javascript routines to support the BrushedTemplate |
| ** Dirk Frederickx |
| ** Nov 06-Mar 07: aligned with MooTools ## |
| ** moo v1.1 selection needed: |
| ** Core, Class, Native, Element(ex. Dimensions), Window, |
| ** Effects(ex. Scroll), Drag(Base), Remote, Plugins(Hash.Cookie, Tips, Accordion) |
| ** |
| ** 100 Wiki object (page parms, UserPrefs and setting focus) ## |
| ** 110 WikiSlimbox : attachment viewer ## |
| ** 114 Reflection (adds reflection to images) ## |
| ** 120 QuickLinks object ## |
| ** 130 TabbedSection object |
| ** 132 Accordion object ## |
| ** 140 SearchBox object: remember 10 most recent search topics |
| ** 150 Colors, GraphBar object: e.g. used on the findpage |
| ** 160 URL |
| ** |
| ** 200 Collapsible list items |
| ** 220 RoundedCorners ffs |
| ** 230 Sortable (clever table-sort) ## |
| ** 240 Table-filter (excel like table filters ## |
| ** 250 Categories: turn wikipage link into AJAXed popup ## |
| ** 260 WikiTips ## |
| ** 270 WikiColumns ## |
| ** 280 ZebraTable: color odd/even row of a table ## |
| ** 290 HighlightWord: refactored |
| ** 295 Typography |
| ** 300 Prettify |
| **/ |
| |
| |
| /* extend mootools */ |
| String.extend({ |
| deCamelize: function(){ |
| return this.replace(/([a-z])([A-Z])/g,"$1 $2"); |
| } |
| }); |
| |
| |
| // get text of a dhtml node |
| function $getText(el) { |
| return el.innerText || el.textContent || ''; |
| } |
| Element.extend({ |
| /* wrapper = new Element('div').injectWrapper(node); */ |
| injectWrapper: function(el){ |
| while( el.firstChild ) this.appendChild( el.firstChild ); |
| el.appendChild( this ) ; |
| return this; |
| }, |
| visible: function() { |
| var el = this; |
| while($type(el)=='element'){ |
| if(el.getStyle('visibility') == 'hidden') return false; |
| if(el.getStyle('display') == 'none' ) return false; |
| el = el.getParent(); |
| } |
| return true; |
| }, |
| hide: function() { |
| this.style.display = 'none'; |
| return this; |
| }, |
| show: function() { |
| this.style.display = ''; |
| return this; |
| }, |
| toggle: function() { |
| this.visible() ? this.hide() : this.show(); |
| return this; |
| }, |
| scrollTo: function(x, y){ |
| this.scrollLeft = x; |
| this.scrollTop = y; |
| }, |
| /* dimensions.js */ |
| getPosition: function(overflown){ |
| overflown = overflown || []; |
| var el = this, left = 0, top = 0; |
| do { |
| left += el.offsetLeft || 0; |
| top += el.offsetTop || 0; |
| el = el.offsetParent; |
| } while (el); |
| overflown.each(function(element){ |
| left -= element.scrollLeft || 0; |
| top -= element.scrollTop || 0; |
| }); |
| return {'x': left, 'y': top}; |
| } |
| }); |
| |
| var Observer = new Class({ |
| initialize: function(el, fn, options){ |
| this.options = Object.extend({ |
| event: 'keyup', |
| delay: 300 |
| }, options || {}); |
| this.element = $(el); |
| this.callback = fn; |
| this.timeout = null; |
| this.listener = this.fired.bind(this); |
| this.value = this.element.getValue(); |
| this.element.setProperty('autocomplete','off').addEvent(this.options.event, this.listener); |
| }, |
| fired: function() { |
| if (this.value == this.element.value) return; |
| this.clear(); |
| this.value = this.element.value; |
| this.timeout = this.callback.delay(this.options.delay, null, [this.element]); |
| }, |
| clear: function() { |
| this.timeout = $clear(this.timeout); |
| }, |
| stop: function() { |
| this.element.removeEvent(this.options.event, this.listener); |
| this.clear(); |
| } |
| }); |
| /* Observable class: observe any form element for changes */ |
| Element.extend({ |
| observe: function(fn, options){ |
| return new Observer(this, fn, options); |
| } |
| }); |
| |
| |
| /* I18N Support |
| * LocalizedStrings takes form { "javascript.some.resource.key":"localised resource key {0}" } |
| * Examples: |
| * "javascript.moreInfo".localize(); |
| * "javascript.imageInfo".localize(2,4); => expects "Image {0} of {1}" |
| */ |
| String.extend({ |
| localize: function(){ |
| var s = LocalizedStrings["javascript."+this], args = arguments; |
| if(!s) return("???" + this + "???"); |
| return s.replace(/\{(\d)\}/g, function(m){ |
| return args[m.charAt(1)] || "???"+m.charAt(1)+"???"; |
| }); |
| } |
| }); |
| |
| /* FIXME parse number anywhere inside a string */ |
| Number.REparsefloat = new RegExp( "([+-]?\\d+(:?\\.\\d+)?(:?e[-+]?\\d+)?)", "i"); |
| |
| /** TABLE stuff **/ |
| function $T(el) { |
| var t = $(el); |
| return (t && t.tBodies[0]) ? $(t.tBodies[0]) : t; |
| }; |
| |
| /* FIXME */ |
| // find first ancestor element with tagName |
| function getAncestorByTagName( node, tagName ) { |
| if( !node) return null; |
| if( node.nodeType == 1 && (node.tagName.toLowerCase() == tagName.toLowerCase())){ |
| return node; |
| } else { |
| return getAncestorByTagName( node.parentNode, tagName ); |
| } |
| } |
| |
| |
| /** 100 Wiki functions **/ |
| var Wiki = { |
| |
| JSONid : 10000, |
| DELIM : '\u00A4', |
| init: function(props){ |
| Object.extend(Wiki,props || {}); |
| var h=location.host; |
| this.BasePath = this.BaseUrl.slice(this.BaseUrl.indexOf(h)+h.length,-1); |
| //this.ClientLanguage = navigator.language ? navigator.language : navigator.userLanguage; |
| //this.ClientTimezone = new Date().getTimezoneOffset()/60; |
| this.prefs=new Hash.Cookie('JSPWikiUserPrefs', {path:Wiki.BasePath, duration:20}); |
| }, |
| getUrl: function(pagename){ |
| return this.PageUrl.replace(/%23%24%25/, pagename); |
| }, |
| /* retrieve pagename from any wikipage url format */ |
| getPageName: function(url){ |
| var s = this.PageUrl.escapeRegExp().replace(/%23%24%25/, '(.+)'), |
| res = url.match(new RegExp(s)); |
| return (res ? res[1] : false); |
| }, |
| onPageLoad: function(){ |
| this.PermissionEdit = ($E('a.edit') !== undefined); //deduct permission level |
| this.url = null; |
| this.parseLocationHash.periodical(500); |
| |
| /* plain.jsp, login.jsp, prefs/profile, prefs/prefs, find */ |
| ['editorarea','j_username','loginname','assertedName','query2'].some(function(el){ |
| el = $(el); |
| if(el && el.visible()) { el.focus(); return true; } |
| return false; |
| }); |
| |
| if($('morebutton')) this.replaceMoreBox(); /* visual sugar */ |
| }, |
| savePrefs: function(){ |
| if($('prefSkin')) this.prefs.set('SkinName', $('prefSkin').getValue()); |
| if($('prefTimeZone')) this.prefs.set('TimeZone', $('prefTimeZone').getValue()); |
| if($('prefTimeFormat')) this.prefs.set('DateFormat', $('prefTimeFormat').getValue()); |
| if($('prefOrientation')) this.prefs.set('orientation', $('prefOrientation').getValue()); |
| if($('editor')) this.prefs.set('editor', $('editor').getValue()); |
| this.prefs.set('FontSize',this.PrefFontSize); |
| }, |
| |
| changeOrientation: function(){ |
| $('wikibody').className = $('prefOrientation').getValue(); |
| }, |
| replaceMoreBox: function(){ |
| var more = $('morebutton'), |
| popup = new Element('ul').inject(more), |
| hover = popup.effect('opacity', {wait:false}).set(0), |
| select = $('actionsMore'), |
| separator = ''; |
| |
| $A(select.options).each(function(o){ |
| if(o.value == "") return; |
| separator='separator'; |
| new Element('a',{'class':o.className,'href':o.value}) |
| .setHTML(o.text).inject(new Element('li').inject(popup)); |
| }); |
| $('moremenu').inject(new Element('li',{'class':separator}).inject(popup)); |
| |
| select.getParent().hide(); |
| more.show() |
| .addEvent('mouseout',(function(){ hover.start(0) }).bind(this)) |
| .addEvent('mouseover',(function(){ Wiki.locatemenu(more,popup); hover.start(0.9) }).bind(this)); |
| }, |
| |
| locatemenu: function(base,el){ |
| var win = {'x': window.getWidth(), 'y': window.getHeight()}, |
| scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()}, |
| corner = base.getPosition(), |
| offset = {'x': base.offsetWidth-el.offsetWidth, 'y': base.offsetHeight }, |
| popup = {'x': el.offsetWidth, 'y': el.offsetHeight}, |
| prop = {'x': 'left', 'y': 'top'}; |
| |
| for (var z in prop){ |
| var pos = corner[z] + offset[z]; /*top-left corner of base */ |
| if ((pos + popup[z] - scroll[z]) > win[z]) pos = win[z] - popup[z] + scroll[z]; |
| el.setStyle(prop[z], pos); |
| }; |
| }, |
| |
| parseLocationHash: function(){ |
| if(this.url && this.url == location.href ) return; |
| this.url = location.href; |
| var h = location.hash; |
| if( h=="" ) return; |
| h = h.replace(/^#/,''); |
| |
| var el = $(h); |
| |
| while( $type(el) == 'element' ){ |
| if( el.hasClass('hidetab') ){ |
| TabbedSection.clickTab.apply(el); |
| } else if( el.hasClass('tab') ){ |
| /* accordion -- need to find accordion object */ |
| } else if( el.hasClass('collapsebody') ){ |
| /* collapsible box */ |
| } else if(!el.visible() ){ |
| //alert('not visible'+el.id); |
| //fixme need to find the correct toggler |
| //el.show(); //eg collapsedBoxes: fixme |
| } |
| el = el.getParent(); |
| } |
| |
| location = location.href; /* now jump to the #hash */ |
| }, |
| |
| /* SubmitOnce: disable all buttons to avoid double submit */ |
| submitOnce: function(form){ |
| window.onbeforeunload = null; /* regular exit of this page -- see jspwiki-edit.js */ |
| (function(){ |
| $A(form.elements).each(function(e){ |
| if( (/submit|button/i).test(e.type)) e.disabled = true; |
| }); |
| }).delay(10); |
| return true; |
| }, |
| |
| submitUpload: function(form, progress){ |
| $('progressbar').setStyle('visibility','visible'); |
| this.progressbar = |
| Wiki.jsonrpc.periodical(1000, this, ["progressTracker.getProgress",[progress],function(result){ |
| if(!result.code) $('progressbar').getFirst().setStyle('width',result+'%').setHTML(result+'%'); |
| }]); |
| |
| return Wiki.submitOnce(form); |
| }, |
| |
| JSONid : 10000, |
| jsonrpc: function(method, params, fn) { |
| new Ajax( Wiki.JsonUrl, { |
| postBody: Json.toString({"id":Wiki.JSONid++, "method":method, "params":params}), |
| method: 'post', |
| onComplete: function(result){ |
| var r = Json.evaluate(result,true); |
| if(!r) return; |
| if(r.result) fn(r.result); |
| else if(r.error) fn(r.error); |
| } |
| }).request(); |
| } |
| } |
| |
| |
| /** 110 WikiSlimbox |
| ** Inspired http://www.digitalia.be/software/slimbox by Christophe Bleys |
| ** Dirk Frederickx, Mar 2007 |
| ** %%slimbox [...] %% |
| ** %%slimbox-img [some-image.jpg] %% |
| ** %%slimbox-ajax [some-page links] %% |
| **/ |
| var WikiSlimbox = { |
| |
| onPageLoad: function(){ |
| var i = 0, |
| lnk = new Element('a',{'class':'slimbox'}).setHTML('»'); |
| |
| $$('*[class^=slimbox]').each(function(slim){ |
| var group = 'lightbox'+ i++, |
| parm = slim.className.split('-')[1] || 'img ajax', |
| filter = []; |
| if(parm.test('img')) filter.extend(['img.inline', 'a.attachment']); |
| if(parm.test('ajax')) filter.extend(['a.wikipage', 'a.external']); |
| $ES(filter.join(','),slim).each(function(el){ |
| var href = el.src||el.href; |
| var rel = (el.className.test('inline|attachment')) ? 'img' : 'ajax'; |
| if((rel=='img') && !href.test('(.bmp|.gif|.png|.jpg|.jpeg)(\\?.*)?$','i')) return; |
| lnk.clone().setProperties({ |
| 'href':href, |
| 'rel':group+' '+rel, |
| 'title':el.alt||el.getText() |
| }).injectBefore(el); |
| if(el.src) el.replaceWith(new Element('a',{ |
| 'class':'attachment', |
| 'href':el.src |
| }).setHTML(el.alt||el.getText())); |
| }); |
| }); |
| if(i) Lightbox.init(); |
| //new Asset.javascript(Wiki.TemplateDir+'scripts/slimbox.js'); |
| } |
| } |
| |
| /* |
| Slimbox v1.31 - The ultimate lightweight Lightbox clone |
| by Christophe Beyls (http://www.digitalia.be) - MIT-style license. |
| Inspired by the original Lightbox v2 by Lokesh Dhakar. |
| |
| Updated by Dirk Frederickx to fit JSPWiki needs |
| - minimum size of image canvas DONE |
| - add maximum size of image w.r.t window size DONE |
| - CLOSE icon -> close x text iso icon DONE |
| - <<prev, next>> links added in visible part of screen DONE |
| - add size of picture to info window DONE |
| - spacebor, down arrow, enter : next image DONE |
| - up arrow : prev image DONE |
| - allow the same picture occuring several times DONE |
| - add support for external page links => slimbox_ex DONE |
| */ |
| var Lightbox = { |
| |
| init: function(options){ |
| this.options = $extend({ |
| resizeDuration: 400, |
| resizeTransition: false, /*Fx.Transitions.sineInOut,*/ |
| initialWidth: 250, |
| initialHeight: 250, |
| animateCaption: true, |
| errorMessage: "slimbox.error".localize() |
| }, options || {}); |
| |
| this.anchors=[]; |
| $each(document.links, function(el){ |
| if (el.rel && el.rel.test(/^lightbox/i)){ |
| el.onclick = this.click.pass(el, this); |
| this.anchors.push(el); |
| } |
| }, this); |
| this.eventKeyDown = this.keyboardListener.bindAsEventListener(this); |
| this.eventPosition = this.position.bind(this); |
| |
| /* Build float panel |
| <div id="lbOverlay"></div> |
| <div id="lbCenter"> |
| <div id="lbImage"> |
| <!-- img or iframe element is inserted here --> |
| </div> |
| </div> |
| <div id="lbBottomContainer"> |
| <div id="lbBottom"> |
| <div id="lbCaption"> |
| <div id="lbNumber"> |
| <a id="lbCloseLink"></a> |
| <div style="clear:both;"></div> |
| </div> |
| </div> |
| */ |
| this.overlay = new Element('div', {'id': 'lbOverlay'}).inject(document.body); |
| |
| this.center = new Element('div', {'id': 'lbCenter', 'styles': {'width': this.options.initialWidth, 'height': this.options.initialHeight, 'marginLeft': -(this.options.initialWidth/2), 'display': 'none'}}).inject(document.body); |
| new Element('a', {'id': 'lbCloseLink', 'href':'#', 'title':'slimbox.close.title'.localize()}).inject(this.center).onclick = this.overlay.onclick = this.close.bind(this); |
| this.image = new Element('div', {'id': 'lbImage'}).inject(this.center); |
| |
| this.bottomContainer = new Element('div', {'id': 'lbBottomContainer', 'styles': {'display': 'none'}}).inject(document.body); |
| this.bottom = new Element('div', {'id': 'lbBottom'}).inject(this.bottomContainer); |
| //new Element('a', {'id': 'lbCloseLink', 'href': '#', 'title':'slimbox.close.title'.localize()}).setHTML('slimbox.close'.localize()).inject(this.bottom).onclick = this.overlay.onclick = this.close.bind(this); |
| this.caption = new Element('div', {'id': 'lbCaption'}).inject(this.bottom); |
| |
| var info = new Element('div').inject(this.bottom); |
| this.prevLink = new Element('a', {'id': 'lbPrevLink', 'href': '#', 'styles': {'display': 'none'}}).setHTML("slimbox.previous".localize()).inject(info); |
| this.number = new Element('span', {'id': 'lbNumber'}).inject(info); |
| this.nextLink = this.prevLink.clone().setProperties({'id': 'lbNextLink' }).setHTML("slimbox.next".localize()).inject(info); |
| this.prevLink.onclick = this.previous.bind(this); |
| this.nextLink.onclick = this.next.bind(this); |
| |
| this.error = new Element('div').setProperty('id', 'lbError').setHTML(this.options.errorMessage); |
| new Element('div', {'styles': {'clear': 'both'}}).inject(this.bottom); |
| |
| var nextEffect = this.nextEffect.bind(this); |
| this.fx = { |
| overlay: this.overlay.effect('opacity', {duration: 500}).hide(), |
| resize: this.center.effects($extend({duration: this.options.resizeDuration, onComplete: nextEffect}, this.options.resizeTransition ? {transition: this.options.resizeTransition} : {})), |
| image: this.image.effect('opacity', {duration: 500, onComplete: nextEffect}), |
| bottom: this.bottom.effect('margin-top', {duration: 400, onComplete: nextEffect}) |
| }; |
| |
| this.fxs = new Fx.Elements([this.center, this.image], $extend({duration: this.options.resizeDuration, onComplete: nextEffect}, this.options.resizeTransition ? {transition: this.options.resizeTransition} : {})); |
| |
| this.preloadPrev = new Image(); |
| this.preloadNext = new Image(); |
| }, |
| |
| click: function(link){ |
| var rel = link.rel.split(' '); |
| if (rel[0].length == 8) return this.open([[url, title, rel[1]]], 0); |
| |
| var imageNum=0, images = []; |
| this.anchors.each(function(el){ |
| var elRel = el.rel.split(' '); |
| if (elRel[0]!=rel[0]) return; |
| if((el.href==link.href) && (el.title==link.title)) imageNum = images.length; |
| images.push([el.href, el.title, elRel[1]]); |
| }); |
| return this.open(images, imageNum); |
| }, |
| |
| open: function(images, imageNum){ |
| this.images = images; |
| this.position(); |
| this.setup(true); |
| this.top = window.getScrollTop() + (window.getHeight() / 15); |
| this.center.setStyles({top: this.top, display: ''}); |
| this.fx.overlay.start(0.7); |
| return this.changeImage(imageNum); |
| }, |
| |
| position: function(){ |
| this.overlay.setStyles({top: window.getScrollTop(), height: window.getHeight()}); |
| }, |
| |
| setup: function(open){ |
| var elements = $A(document.getElementsByTagName('object')); |
| elements.extend(document.getElementsByTagName(window.ie ? 'select' : 'embed')); |
| elements.each(function(el){ |
| if (open) el.lbBackupStyle = el.style.visibility; |
| el.style.visibility = open ? 'hidden' : el.lbBackupStyle; |
| }); |
| var fn = open ? 'addEvent' : 'removeEvent'; |
| window[fn]('scroll', this.eventPosition)[fn]('resize', this.eventPosition); |
| document[fn]('keydown', this.eventKeyDown); |
| this.step = 0; |
| }, |
| |
| keyboardListener: function(event){ |
| switch (event.keyCode){ |
| case 27: case 88: case 67: this.close(); break; |
| case 37: case 38: case 80: this.previous(); break; |
| case 13: case 32: case 39: case 40: case 78: this.next(); break; |
| default: return; |
| } |
| new Event(event).stop(); |
| }, |
| |
| previous: function(){ |
| return this.changeImage(this.activeImage-1); |
| }, |
| |
| next: function(){ |
| return this.changeImage(this.activeImage+1); |
| }, |
| |
| changeImage: function(imageNum){ |
| if (this.step || (imageNum < 0) || (imageNum >= this.images.length)) return false; |
| this.step = 1; |
| this.activeImage = imageNum; |
| |
| this.center.style.backgroundColor = ''; |
| this.bottomContainer.style.display = this.prevLink.style.display = this.nextLink.style.display = 'none'; |
| this.fx.image.hide(); |
| this.center.className = 'lbLoading'; |
| |
| this.preload = new Image(); |
| this.image.empty().setStyle('overflow','hidden'); |
| if( this.images[imageNum][2] == 'img' ){ |
| this.preload.onload = this.nextEffect.bind(this); |
| this.preload.src = this.images[imageNum][0]; |
| } else { |
| this.iframeId = "lbFrame_"+new Date().getTime(); // Safari would not update iframe content that has static id. |
| this.so = new Element('iframe').setProperties({ |
| id: this.iframeId, |
| // width: this.contentsWidth, |
| // height: this.contentsHeight, |
| frameBorder:0, |
| scrolling:'auto', |
| src:this.images[imageNum][0] |
| }).inject(this.image); |
| this.nextEffect(); //asynchronous loading? |
| |
| } |
| return false; |
| }, |
| |
| ajaxFailure: function (){ |
| this.ajaxFailed = true; |
| this.image.setHTML('').adopt(this.error.clone()); |
| this.nextEffect(); |
| }, |
| |
| nextEffect: function(){ |
| switch (this.step++){ |
| case 1: |
| this.center.className = ''; |
| this.caption.empty().adopt(new Element('a', { |
| 'href':this.images[this.activeImage][0], |
| 'title':"slimbox.directLink".localize() |
| }).setHTML(this.images[this.activeImage][1] || '')); |
| |
| var type = (this.images[this.activeImage][2]=='img') ? "slimbox.info" : "slimbox.remoteRequest"; |
| this.number.setHTML((this.images.length == 1) ? '' : type.localize(this.activeImage+1, this.images.length)); |
| this.image.style.backgroundImage = 'none'; |
| |
| var w = Math.max(this.options.initialWidth,this.preload.width), |
| h = Math.max(this.options.initialHeight,this.preload.height), |
| ww = Window.getWidth()-10, |
| wh = Window.getHeight()-120; |
| if(this.images[this.activeImage][2]!='img' &&!this.ajaxFailed){ w = 6000; h = 3000; } |
| if(w > ww) { h = Math.round(h * ww/w); w = ww; } |
| if(h > wh) { w = Math.round(w * wh/h); h = wh; } |
| |
| this.image.style.width = this.bottom.style.width = w+'px'; |
| this.image.style.height = /*this.prevLink.style.height = this.nextLink.style.height = */ h+'px'; |
| |
| if( this.images[this.activeImage][2]=='img') { |
| this.image.style.backgroundImage = 'url('+this.images[this.activeImage][0]+')'; |
| |
| if (this.activeImage) this.preloadPrev.src = this.images[this.activeImage-1][0]; |
| if (this.activeImage != (this.images.length - 1)) this.preloadNext.src = this.images[this.activeImage+1][0]; |
| |
| this.number.setHTML(this.number.innerHTML+' ['+this.preload.width+'×'+this.preload.height+']'); |
| } else { |
| this.so.style.width=w+'px'; |
| this.so.style.height=h+'px'; |
| } |
| |
| if (this.options.animateCaption) this.bottomContainer.setStyles({height: '0px', display: ''}); |
| |
| this.fxs.start({ |
| '0': { height: [this.image.offsetHeight], width: [this.image.offsetWidth], marginLeft: [-this.image.offsetWidth/2] }, |
| '1': { opacity: [1] } |
| }); |
| |
| break; |
| case 2: |
| //this.center.style.backgroundColor = '#000'; |
| this.image.setStyle('overflow','auto'); |
| this.bottomContainer.setStyles({ top: (this.top + this.center.clientHeight)+'px', marginLeft: this.center.style.marginLeft }); |
| if (this.options.animateCaption){ |
| this.fx.bottom.set(-this.bottom.offsetHeight); |
| this.bottomContainer.style.height = ''; |
| this.fx.bottom.start(0); |
| break; |
| } |
| this.bottomContainer.style.height = ''; |
| case 3: |
| if (this.activeImage) this.prevLink.style.display = ''; |
| if (this.activeImage != (this.images.length - 1)) this.nextLink.style.display = ''; |
| this.step = 0; |
| } |
| }, |
| |
| close: function(){ |
| if (this.step < 0) return; |
| this.step = -1; |
| if (this.preload){ |
| this.preload.onload = Class.empty; |
| this.preload = null; |
| } |
| for (var f in this.fx) this.fx[f].stop(); |
| this.center.style.display = this.bottomContainer.style.display = 'none'; |
| this.fx.overlay.chain(this.setup.pass(false, this)).start(0); |
| return false; |
| } |
| }; |
| |
| |
| /** 114 Reflection |
| ** Inspired by Reflection.js at http://cow.neondragon.net/stuff/reflection/ |
| ** Freely distributable under MIT-style license. |
| ** Adapted for JSPWiki/BrushedTemplate, D.Frederickx, Sep 06 |
| ** Use: |
| ** %%reflection-height-opacity [some-image.jpg] %% |
| **/ |
| var WikiReflection = { |
| |
| onPageLoad: function(){ |
| $$('*[class^=reflection]').each( function(w){ |
| var parms = w.className.split('-'); |
| $ES('img',w).each(function(img){ |
| Reflection.add(img, parms[1], parms[2]); |
| }); |
| }); |
| } |
| } |
| /* FIXME : add delayed loading of reflection library */ |
| var Reflection = { |
| |
| options: { height: 0.33, opacity: 0.5 }, |
| |
| add: function(img, height, opacity) { |
| //TODO Reflection.remove(image); --is this still needed? |
| height = (height ) ? height/100 : this.options.height; |
| opacity = (opacity) ? opacity/100: this.options.opacity; |
| |
| var div = new Element('div').injectAfter(img).adopt(img), |
| imgW = img.width, |
| imgH = img.height, |
| rH = Math.floor(imgH * height); //reflection height |
| |
| div.className = img.className.replace(/\breflection\b/, ""); |
| div.style.cssText = img.backupStyle = img.style.cssText; |
| //div.setStyles({'width':img.width, 'height':imgH +rH, "maxWidth": imgW }); |
| div.setStyles({'width':img.width, 'height':imgH +rH }); |
| img.style.cssText = 'vertical-align: bottom'; |
| //img.className = 'inline reflected'; //FIXME: is this still needed ?? |
| |
| if( window.ie ){ |
| new Element('img', {'src': img.src, 'styles': { |
| 'width': imgW, |
| 'marginBottom': "-" + (imgH - rH) + 'px', |
| 'filter': 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(opacity*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(height*100)+')' |
| }}).inject(div); |
| } else { |
| var r = new Element('canvas', {'width':imgW, 'height':rH, 'styles': {'width':imgW, 'height': rH}}).inject(div); |
| if( !r.getContext ) return; |
| |
| var ctx = r.getContext("2d"); |
| ctx.save(); |
| ctx.translate(0, imgH-1); |
| ctx.scale(1, -1); |
| ctx.drawImage(img, 0, 0, imgW, imgH); |
| ctx.restore(); |
| ctx.globalCompositeOperation = "destination-out"; |
| |
| var g = ctx.createLinearGradient(0, 0, 0, rH); |
| g.addColorStop( 0, "rgba(255, 255, 255, " + (1 - opacity) + ")" ); |
| g.addColorStop( 1, "rgba(255, 255, 255, 1.0)" ); |
| ctx.fillStyle = g; |
| ctx.rect( 0, 0, imgW, rH ); |
| ctx.fill(); |
| } |
| } |
| } |
| |
| /** 120 brushed quick links **/ |
| var QuickLinks = { |
| |
| onPageLoad: function(){ |
| if( $("previewcontent") || !Wiki.PrefShowQuickLinks ) return; |
| |
| var sections = $$('#pagecontent *[id^=section]'); |
| if(sections.length==0) return; |
| |
| var ql,qlPrev,qlEdit,qlNext; |
| function qql(clazz,title,text,href){ |
| var a = new Element('a',{'title':title.localize()}).setHTML(text); |
| if(href) a.setProperty('href',href); |
| ql.adopt(new Element('span',{'class':clazz}).adopt(a)); |
| return(a); |
| } |
| ql = new Element('div',{'class':'quicklinks'}); |
| qql('quick2Top','quick.top','«','#wikibody'); |
| qlPrev = qql('quick2Prev','quick.previous','‹'); |
| |
| if(Wiki.PermissioneEdit) qlEdit = qql('quick2Edit','quick.edit','•'); |
| |
| qlNext = qql('quick2Next','quick.next','›'); |
| qql('quick2Bottom','quick.bottom','»','#footer'); |
| |
| var last = sections.length-1; |
| sections.each(function(s,i){ |
| qlNext.setProperty('href',(i==last) ? '#footer' : '#'+sections[i+1].id); |
| qlPrev.setProperty('href',(i==0) ? '#wikibody' : '#'+sections[i-1].id); |
| if(qlEdit) qlEdit.setProperty('href','Edit.jsp?page='+Wiki.PageName+'§ion='+(i+1)); |
| s.adopt(ql.clone()); |
| }); |
| } |
| } |
| |
| /** Class: Tabbed Section (130) |
| Creates tabs, based on some css-class information |
| Use in jspwiki: %%tabbedSection %%tab-FirstTab .. %% %% |
| |
| Following markup: |
| <div class="tabbedSection"> |
| <div class="tab-FirstTab">..<div> |
| <div class="tab-SecondTab">..<div> |
| </div> |
| |
| is changed into |
| <div class="tabmenu"><span><a activetab>..</a></span>..</div> |
| <div class="tabbedSection tabs"> |
| <div class="tab-firstTab "> |
| <div class="tab-SecondTab hidetab"> |
| </div> |
| **/ |
| var TabbedSection = { |
| |
| onPageLoad: function(){ |
| |
| // charge existing tabmenu's with click handlers |
| $$('.tabmenu a').each(function(el){ |
| if(el.href) return; |
| var tab = $(el.id.substr(5)); //drop 'menu-' prefix |
| el.addEvent('click', this.clickTab.bind(tab) ); |
| },this); |
| |
| // convert tabbedSections into tabmenu's with click handlers |
| $$('.tabbedSection').each( function(tt){ |
| tt.addClass('tabs'); //css styling is on tabs |
| var tabmenu = new Element('div',{'class':'tabmenu'}).injectBefore(tt); |
| |
| tt.getChildren().each(function(tab,i) { |
| if( !tab.className.test('^tab-') ) return; |
| |
| if( !tab.id || (tab.id=="") ) tab.id = tab.className; |
| var title = tab.className.substr(4).deCamelize(); //drop 'tab-' prefix |
| |
| (i==0) ? tab.removeClass('hidetab') : tab.addClass('hidetab'); |
| |
| new Element('div',{'styles':{'clear':'both'}}).inject(tab); |
| |
| var menu = new Element('a', { |
| 'id':'menu-'+tab.id, |
| 'events':{ 'click': this.clickTab.bind(tab) } |
| }).appendText(title).inject(tabmenu); |
| if( i==0 ) menu.addClass('activetab'); |
| },this); |
| }, this); |
| }, |
| |
| clickTab: function(){ |
| var menu = $('menu-'+this.id); |
| this.getParent().getChildren().some( function(el){ |
| if(el.id){ |
| var m = $('menu-'+el.id); |
| if( m && m.hasClass('activetab') ) { |
| if( el.id != this.id ) { |
| m.removeClass('activetab'); |
| menu.addClass('activetab'); |
| el.addClass('hidetab'); |
| this.removeClass('hidetab'); //.show(); |
| } |
| return true; |
| } |
| } |
| return false; |
| },this); |
| } |
| |
| } |
| |
| /** 132 Accordion for Tabs, Accordeons, CollapseBoxes |
| ** |
| ** Following markup: |
| ** <div class="accordion"> |
| ** <div class="tab-FirstTab">...<div> |
| ** <div class="tab-SecondTab">...<div> |
| ** </div> |
| ** |
| ** is changed into |
| ** <div class="accordion"> |
| ** <div class="toggle active">First Tab</div> |
| ** <div class="tab-FirstTab tab active">...</div> |
| ** <div class="toggle">Second Tab</div> |
| ** <div class="tab-SecondTab">...</div> |
| ** </div> |
| **/ |
| var WikiAccordion = { |
| |
| onPageLoad: function(){ |
| $$('.accordion, .tabbedAccordion').each( function(tt){ |
| |
| var toggles=[], contents=[], togglemenu=false; |
| if(tt.hasClass('tabbedAccordion')) togglemenu = new Element('div',{'class':'togglemenu'}).injectBefore(tt); |
| |
| tt.getChildren().each(function(tab) { |
| if( !tab.className.test('^tab-') ) return; |
| |
| //FIXME use class to make tabs visible during printing |
| //(i==0) ? tab.removeClass('hidetab'): tab.addClass('hidetab'); |
| |
| var title = tab.className.substr(4).deCamelize(); |
| if(togglemenu) { |
| toggles.push(new Element('div',{'class':'toggle'}).inject(togglemenu).appendText(title)); |
| } else { |
| toggles.push(new Element('div',{'class':'toggle'}).injectBefore(tab).appendText(title)); |
| } |
| contents.push(tab.addClass('tab')); |
| }); |
| new Accordion(toggles, contents, { |
| alwaysHide: !togglemenu, |
| onComplete: function(){ |
| var el = $(this.elements[this.previous]); |
| if (el.offsetHeight > 0) el.setStyle('height', 'auto'); |
| }, |
| onActive: function(toggle,content){ |
| toggle.addClass('active'); content.addClass('active'); |
| }, |
| onBackground: function(toggle,content){ |
| content.setStyle('height', content['offsetHeight']); |
| toggle.removeClass('active'); content.removeClass('active'); |
| } |
| }); |
| }); |
| } |
| } |
| |
| |
| /* 140 SearchBox |
| * FIXME: remember 10 most recent search topics (cookie based) |
| * Extended with quick links for view, edit and clone (ref. idea of Ron Howard - Nov 05) |
| * Refactored for mootools, April 07 |
| */ |
| var SearchBox = { |
| |
| onPageLoad: function(){ |
| this.onPageLoadQuickSearch(); |
| this.onPageLoadFullSearch(); |
| }, |
| |
| onPageLoadQuickSearch : function(){ |
| var q = $('query'); if( !q ) return; |
| this.query = q; |
| q.observe(this.ajaxQuickSearch.bind(this) ); |
| |
| this.hover = $('searchboxMenu').setProperty('visibility','visible') |
| .effect('opacity', {wait:false}).set(0); |
| |
| $(q.form).addEvent('submit',this.submit.bind(this)) |
| //FIXME .addEvent('blur',function(){ this.hasfocus=false; this.hover.start(0) }.bind(this)) |
| //FIXME .addEvent('focus',function(){ this.hasfocus=true; this.hover.start(0.9) }.bind(this)) |
| .addEvent('mouseout',function(){ this.hover.start(0) }.bind(this)) |
| .addEvent('mouseover',function(){ Wiki.locatemenu(this.query, $('searchboxMenu') ); this.hover.start(0.9) }.bind(this)); |
| |
| /* use advanced search-input on safari - experimental */ |
| if(window.xwebkit){ |
| q.setProperties({type:"search",autosave:q.form.action,results:"9",placeholder:q.defaultValue}); |
| } else { |
| $('recentClear').addEvent('click', this.clear.bind(this)); |
| |
| this.recent = Wiki.prefs.get('RecentSearch'); if(!this.recent) return; |
| |
| var ul = new Element('ul',{'id':'recentItems'}).inject($('recentSearches').show()); |
| this.recent.each(function(el){ |
| new Element('a',{ |
| 'href':'#', |
| 'events': {'click':function(){ q.value = el; q.form.submit(); }} |
| }).setHTML(el).inject( new Element('li').inject(ul) ); |
| }); |
| } |
| }, |
| |
| onPageLoadFullSearch : function(){ |
| var q2 = $("query2"); if( !q2 ) return; |
| this.query2 = q2; |
| |
| var changescope = function(){ |
| var qq = this.query2.value.replace(/^(?:author:|name:|contents:|attachment:)/,''); |
| this.query2.value = $('scope').getValue() + qq; |
| this.runfullsearch(); |
| }.bind(this); |
| |
| q2.observe( this.runfullsearch.bind(this) ); |
| |
| $('scope').addEvent('change', changescope); |
| $('details').addEvent('click', this.runfullsearch.bind(this)); |
| }, |
| |
| runfullsearch : function(){ |
| var q2 = this.query2.value; |
| if( !q2 || (q2.trim()=='')) { |
| $('searchResult2').empty(); |
| return; |
| } |
| $('spin').show(); |
| |
| var scope = $('scope'), |
| match= q2.match(/^(?:author:|name:|contents:|attachment:)/) ||""; |
| $each(scope.options, function(option){ |
| if (option.value == match) option.selected = true; |
| }); |
| |
| new Ajax(Wiki.TemplateDir+'AJAXSearch.jsp', { |
| postBody: $('searchform2').toQueryString(), |
| update: 'searchResult2', |
| method: 'post', |
| onComplete: function() { $('spin').hide(); GraphBar.onPageLoad(); Wiki.prefs.set('PrevQuery', q2); } |
| }).request(); |
| }, |
| |
| submit: function(){ |
| var v = this.query.value; |
| if( v == this.query.defaultValue) this.query.value = ''; |
| if( !this.recent ) this.recent=[]; |
| if( !this.recent.test(v) ){ |
| if(this.recent.length > 9) this.recent.pop(); |
| this.recent.unshift(v); |
| Wiki.prefs.set('RecentSearch', this.recent); |
| } |
| }, |
| |
| clear: function(){ |
| this.recent = []; |
| Wiki.prefs.remove('RecentSearch'); |
| $('recentSearches','recentClear').hide(); |
| }, |
| |
| ajaxQuickSearch: function(){ |
| var qv = this.query.value ; |
| if( (qv==null) || (qv.trim()=="") || (qv==this.query.defaultValue) ) { |
| $('searchOutput').empty(); |
| return; |
| } |
| $('searchTarget').setHTML('('+qv+') :'); |
| $('searchSpin').show(); |
| |
| Wiki.jsonrpc('search.findPages', [qv,20], function(result){ |
| $('searchSpin').hide(); |
| if(!result.list) return; |
| var frag = new Element('ul'); |
| |
| result.list.each(function(el){ |
| new Element('li').adopt( |
| new Element('a',{'href':Wiki.getUrl(el.map.page) }).setHTML(el.map.page), |
| new Element('span',{'class':'small'}).setHTML(" ("+el.map.score+")") |
| ).inject(frag); |
| }); |
| $('searchOutput').empty().adopt(frag); |
| Wiki.locatemenu( $('query'), $('searchboxMenu') ); |
| }); |
| } , |
| |
| |
| /* navigate to url, after smart pagename handling */ |
| navigate: function(url, promptText, clone, search){ |
| var p = Wiki.PageName, s = this.query.value; |
| if(s == this.query.defaultValue) s = ''; |
| |
| if(s == ''){ |
| s = prompt(promptText, (clone) ? p+'sbox.clone.suffix'.localize() : p); |
| if( !s || (s == '') ) return false; |
| } |
| //if(!search) s = s.replace(/[^A-Za-z0-9._\/]/g, ''); //valid pagename FIXME |
| if( clone && (s != p) ) s += '&clone=' + p; |
| |
| if(s == '') return false; //dont exec the click |
| location.href = url.replace('__PAGEHERE__', s); |
| } |
| } |
| |
| |
| /** |
| ** 150 GraphBar Object: also used on the findpage |
| ** %%graphBars ... %% |
| ** convert numbers inside %%gBar ... %% tags to graphic horizontal bars |
| ** no img needed. |
| ** supported parameters: bar-color and bar-maxsize |
| ** e.g. %%graphBars-e0e0e0 ... %% use color #e0e0e0, default size 120 |
| ** e.g. %%graphBars-blue-red ... %% blend colors from blue to red |
| ** e.g. %%graphBars-red-40 ... %% use color red, maxsize 40 chars |
| ** e.g. %%graphBars-vertical ... %% vertical bars |
| ** e.g. %%graphBars-progress ... %% progress bars in 2 colors |
| ** e.g. %%graphBars-gauge ... %% gauge bars in gradient colors |
| **/ |
| |
| /* minimal variant of the Color class, inspired by mootools */ |
| var Color = new Class({ |
| |
| _HTMLColors: { |
| black :"000000", green :"008000", silver :"c0c0c0", lime :"00ff00", |
| gray :"808080", olive :"808000", white :"ffffff", yellow:"ffff00", |
| maroon :"800000", navy :"000080", red :"ff0000", blue :"0000ff", |
| purple :"800080", teal :"008080", fuchsia:"ff00ff", aqua :"00ffff" |
| }, |
| |
| initialize: function(color, type){ |
| type = type || (color.push ? 'rgb' : 'hex'); |
| if(this._HTMLColors[color]) color = this._HTMLColors[color]; |
| var rgb = (type=='rgb') ? color : color.toString().hexToRgb(true); |
| if(!rgb) return false; |
| rgb.hex = rgb.rgbToHex(); |
| return $extend(rgb, Color.prototype); |
| }, |
| |
| mix: function(){ |
| var colors = $A(arguments), |
| rgb = this.copy(), |
| alpha = (($type(colors[colors.length - 1]) == 'number') ? colors.pop() : 50)/100, |
| alphaI = 1-alpha; |
| |
| colors.each(function(color){ |
| color = new Color(color); |
| for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] * alphaI) + (color[i] * alpha)); |
| }); |
| return new Color(rgb, 'rgb'); |
| }, |
| |
| invert: function(){ |
| return new Color(this.map(function(value){ |
| return 255 - value; |
| })); |
| } |
| |
| }); |
| |
| var GraphBar = |
| { |
| onPageLoad : function(){ |
| $$('*[class^=graphBars]').each( function(g){ |
| var lbound = 20, //max - lowerbound size of bar |
| ubound = 320, //min - upperbound size of bar |
| vwidth = 20, //vertical bar width |
| color1 = null, // bar color |
| color2 = null, // 2nd bar color used depending on bar-type |
| isGauge = false, // gauge bar |
| isProgress = false, // progress bar |
| isHorizontal = true,// horizontal or vertical orientation |
| parms = g.className.substr(9).split('-'), |
| barName = parms.shift(); //first param is optional barName |
| |
| parms.each(function(p){ |
| p = p.toLowerCase(); |
| if(p == "vertical") { isHorizontal = false; } |
| else if(p == "progress") { isProgress = true; } |
| else if(p == "gauge") { isGauge = true; } |
| else if(p.indexOf("min") == 0) { lbound = p.substr(3).toInt(); } |
| else if(p.indexOf("max") == 0) { ubound = p.substr(3).toInt(); } |
| else if(p != "") { |
| p = new Color(p,'hex'); if(!p.hex) return; |
| if(!color1) color1 = p; |
| else if(!color2) color2 = p; |
| } |
| }); |
| if( !color2 && color1) color2 = (isGauge || isProgress) ? color1.invert() : color1; |
| |
| if( lbound > ubound ) { var m = ubound; ubound=lbound; ubound=m; } |
| var size = ubound-lbound; |
| |
| var bars = $ES('.gBar'+barName, g); //collect all gBar elements |
| if( (bars.length==0) && barName && (barName!="")){ // check table data |
| bars = this.getTableValues(g, barName); |
| } |
| if( !bars ) return; |
| |
| var barData = this.parseBarData( bars, lbound, size ), |
| border = (isHorizontal ? 'borderLeft' : 'borderBottom'); |
| |
| bars.each(function(b,j){ |
| var bar1 = $H().set(border+'Width',barData[j]), |
| bar2 = $H(), // 2nd bar only valid ico 'progress' |
| barEL = new Element('span',{'class':'graphBar'}), |
| pb = b.getParent(); // parent of gBar element |
| |
| if(isHorizontal){ |
| barEL.setHTML('x'); |
| if(isProgress){ |
| bar2.extend(bar1.obj); |
| bar1.set(border+'Width',ubound-barData[j]).set('marginLeft','-1ex'); |
| } |
| } else { // isVertical |
| if(pb.getTag()=='td') { pb = new Element('div').injectWrapper(pb); } |
| |
| pb.setStyles({'height':ubound+b.getStyle('lineHeight').toInt(), 'position':'relative'}); |
| b.setStyle('position', 'relative'); //needed for inserted spans ;-)) hehe |
| if( !isProgress ) { b.setStyle('top', (ubound-barData[j])); } |
| |
| bar1.extend({'position':'absolute', 'width':vwidth, 'bottom':'0'}); |
| if(isProgress){ |
| bar2.extend(bar1.obj).set(border+'Width', ubound); |
| } |
| } |
| if(isProgress){ |
| if(color1){ bar1.set('borderColor', color1.hex); } |
| if(color2){ |
| bar2.set('borderColor', color2.hex); |
| } else { |
| bar1.set('borderColor', 'transparent'); |
| } |
| } else if(color1){ |
| var percent = isGauge ? (barData[j]-lbound)/size : j/(bars.length-1); |
| bar1.set('borderColor', color1.mix(color2, 100 * percent).hex); |
| } |
| |
| if(bar2.length > 0){ barEL.clone().setStyles(bar2.obj).injectBefore(b); }; |
| if(bar1.length > 0){ barEL.setStyles(bar1.obj).injectBefore(b); }; |
| },this); |
| |
| },this); |
| }, |
| |
| // parse bar data types and scale according to lbound and size |
| parseBarData: function(nodes, lbound, size){ |
| var barData=[], |
| maxValue=Number.MIN_VALUE, |
| minValue=Number.MAX_VALUE, |
| num=date=true; |
| |
| nodes.each(function(n,i){ |
| var s = n.getText(); |
| barData.push(s); |
| if(num) num = !isNaN(parseFloat( s.match(Number.REparsefloat) ) ); |
| if(date) date = !isNaN(Date.parse(s)); |
| }); |
| barData = barData.map(function(b){ |
| if(date) { b = new Date(Date.parse(b) ).valueOf(); } |
| else if(num) { b = parseFloat( b.match(Number.REparsefloat) ); } |
| |
| maxValue = Math.max(maxValue, b); |
| minValue = Math.min(minValue, b); |
| return b; |
| }); |
| |
| if(maxValue==minValue) maxValue=minValue+1; /* avoid div by 0 */ |
| size = size/(maxValue-minValue); |
| return barData.map(function(b){ |
| return ( (size*(b-minValue)) + lbound).toInt(); |
| }); |
| }, |
| |
| /* Fetch set of gBar values from a table |
| * Check first-row to match field-name: return array with col values |
| * Check first-column to match field-name: return array with row values |
| * insert SPANs as place-holder of the missing gBars |
| */ |
| getTableValues: function(node, fieldName){ |
| var table = $E('table', node); if(!table) return false; |
| var tlen = table.rows.length; |
| |
| if( tlen > 1 ){ /* check for COLUMN based table */ |
| var r = table.rows[0]; |
| for( var h=0; h < r.cells.length; h++ ){ |
| if( $getText( r.cells[h] ).trim() == fieldName ){ |
| var result = []; |
| for( var i=1; i< tlen; i++) |
| result.push( new Element('span').injectWrapper(table.rows[i].cells[h]) ); |
| return result; |
| } |
| } |
| } |
| for( var h=0; h < tlen; h++ ){ /* check for ROW based table */ |
| var r = table.rows[h]; |
| if( $getText( r.cells[0] ).trim() == fieldName ){ |
| var result = []; |
| for( var i=1; i< r.cells.length; i++) |
| result.push( new Element('span').injectWrapper(r.cells[i]) ); |
| return result; |
| } |
| } |
| return false; |
| } |
| } |
| |
| /** 200 Collapsible list and boxes |
| ** See also David Lindquist <first name><at><last name><dot><net> |
| ** See: http://www.gazingus.org/html/DOM-Scripted_Lists_Revisited.html |
| ** |
| ** Add support for collabsable boxes, Nov 05, D.Frederickx |
| ** Refactored on mootools, including effects, May 07, D.Frederickx |
| **/ |
| var Collapsible = |
| { |
| pims : [], // all me cookies |
| |
| onPageLoad: function(){ |
| this.bullet = new Element('div',{'class':'collapseBullet'}).setHTML('•'); |
| this.initialise( "favorites", "JSPWikiCollapseFavorites" ); |
| this.initialise( "pagecontent", "JSPWikiCollapse" + Wiki.PageName ); |
| this.initialise( "previewcontent", "JSPWikiCollapse" + Wiki.PageName ); |
| this.initialise( "info" ); |
| }, |
| |
| initialise: function( page, cookie){ |
| page = $(page); if(!page) return; |
| |
| this.pims.push({ |
| 'name':cookie, |
| 'value':'', |
| 'initial': (cookie ? Cookie.get(cookie) : "") |
| }); |
| $ES('.collapse', page).each(function(el){ |
| if( $E('.collapseBullet',el) ) return; /* no nesting */ |
| this.collapseNode(el); |
| }, this); |
| $ES('.collapsebox,.collapsebox-closed', page).each(function(el){ |
| this.collapseBox(el); |
| }, this); |
| }, |
| |
| collapseBox: function(el){ |
| var title = el.getFirst(); if( !title ) return; |
| var body = new Element('div', {'class':'collapsebody'}), |
| bullet = this.bullet.clone(), |
| isclosed = el.hasClass('collapsebox-closed'); |
| |
| while(title.nextSibling) body.appendChild(title.nextSibling); // wrap other siblings |
| el.appendChild(body); |
| |
| if(isclosed) el.removeClass('collapsebox-closed').addClass('collapsebox'); |
| bullet.injectTop( title.addClass('collapsetitle') ); |
| this.newBullet(bullet, body, !isclosed, title ); |
| }, |
| |
| // Modifies the list such that sublists can be hidden/shown by clicking the listitem bullet |
| // The listitem bullet is a node inserted into the DOM tree as the first child of the |
| // listitem containing the sublist. |
| collapseNode: function(node){ |
| $ES('li',node).each(function(li){ |
| var ulol = $E('ul',li) || $E('ol',li); |
| |
| //dont insert bullet when LI is 'empty': no text or no non-ul/ol tags |
| var emptyLI = true; |
| for( var n = li.firstChild; n ; n = n.nextSibling ) { |
| if((n.nodeType == 3 ) && ( n.nodeValue.trim() == "" ) ) continue; //keep searching |
| if((n.nodeName == "UL") || (n.nodeName == "OL")) break; //seems like an empty li |
| emptyLI = false; |
| break; |
| } |
| if( emptyLI ) return; |
| |
| new Element('div',{'class':'collapsebody'}).injectWrapper(li); |
| var bullet = this.bullet.clone().injectTop(li); |
| if(ulol) this.newBullet(bullet, ulol, (ulol.getTag()=='ul')); |
| },this); |
| }, |
| |
| newBullet: function(bullet, body, isopen, clicktarget){ |
| var ck = this.pims.getLast(); //read cookie |
| isopen = this.parseCookie(isopen); |
| if(!clicktarget) clicktarget = bullet; |
| |
| var bodyfx = body.setStyle('overflow','hidden') |
| .effect('height', { |
| wait:false, |
| onStart:this.renderBullet.bind(bullet), |
| onComplete:function(){ if(bullet.hasClass('collapseOpen')) body.setStyle('height','auto'); } |
| }); |
| |
| bullet.className = (isopen ? 'collapseClose' : 'collapseOpen'); //ready for rendering |
| clicktarget.addEvent('click', this.clickBullet.bind(bullet, [ck, ck.value.length-1, bodyfx])) |
| .addEvent('mouseenter', function(){ clicktarget.addClass('collapseHover')} ) |
| .addEvent('mouseleave', function(){ clicktarget.removeClass('collapseHover')} ); |
| |
| bodyfx.fireEvent('onStart'); |
| if(!isopen) bodyfx.set(0); //.set( isopen ? body.scrollHeight : 0 ); |
| }, |
| |
| renderBullet: function(){ |
| if(this.hasClass('collapseClose')){ |
| this.setProperties({'title':'collapse'.localize(), 'class':'collapseOpen'}).setHTML('-'); /* » */ |
| } else { |
| this.setProperties({'title':'expand'.localize(), 'class':'collapseClose'}).setHTML('+'); /* « */ |
| } |
| }, |
| |
| clickBullet: function( ck, bulletidx, bodyfx){ |
| var collapse = this.hasClass('collapseOpen'), |
| bodyHeight = bodyfx.element.scrollHeight; |
| |
| if(collapse) bodyfx.start(bodyHeight, 0); else bodyfx.start(bodyHeight); |
| |
| ck.value = ck.value.substring(0,bulletidx) + (collapse ? 'c' : 'o') + ck.value.substring(bulletidx+1) ; |
| if(ck.name) Cookie.set(ck.name, ck.value, {path:Wiki.BasePath, duration:20}); |
| }, |
| |
| // parse initial cookie versus actual document |
| // returns true if collapse status is open |
| parseCookie: function( isopen ){ |
| var ck = this.pims.getLast(), |
| cursor = ck.value.length, |
| token = (isopen ? 'o' : 'c'); |
| |
| if(ck.initial && (ck.initial.length > cursor)){ |
| var cookieToken = ck.initial.charAt( cursor ); |
| |
| if( ( isopen && (cookieToken == 'c') ) |
| || ( !isopen && (cookieToken == 'o') ) ) token = cookieToken ; |
| |
| if(token != cookieToken) ck.initial = null; //mismatch with initial cookie |
| } |
| ck.value += token; //append and save currentcookie |
| |
| return(token == 'o'); |
| } |
| } |
| |
| |
| /** 220 RoundedCorners --experimental |
| ** based on Nifty corners by Allesandro Fulciniti |
| ** www.pro.html.it |
| ** Refactored for JSPWiki |
| ** |
| ** JSPWiki syntax: |
| ** |
| ** %%roundedCorners-<corners>-<color>-<borderColor> |
| ** %% |
| ** |
| ** roundedCorners-yyyy-ffc5ff-c0c0c0 |
| ** |
| ** corners: "yyyy" where first y: top-left, 2nd y: top-right, |
| ** 3rd y: bottom-left; 4th y: bottom-right |
| ** value can be: "y": Normal rounded corner (lowercase y) |
| ** "s": Small rounded corner (lowercase s) |
| ** "n": Normal square corner |
| ** |
| **/ |
| var RoundedCorners = |
| { |
| /** Definition of CORNER dimensions |
| ** Normal Normal+Border Small Small+Border |
| ** .....+++ .....BBB ..+++ ..BBB |
| ** ...+++++ ...BB+++ .++++ .B+++ |
| ** ..++++++ ..B+++++ +++++ B++++ |
| ** .+++++++ .B++++++ |
| ** .+++++++ .B++++++ |
| ** ++++++++ B+++++++ |
| ** |
| ** legend: . background, B border, + forground color |
| **/ |
| NormalTop : |
| [ { margin: "5px", height: "1px", borderSide: "0", borderTop: "1px" } |
| , { margin: "3px", height: "1px", borderSide: "2px" } |
| , { margin: "2px", height: "1px", borderSide: "1px" } |
| , { margin: "1px", height: "2px", borderSide: "1px" } |
| ] , |
| SmallTop : |
| [ { margin: "2px", height: "1px", borderSide: "0", borderTop: "1px" } |
| , { margin: "1px", height: "1px", borderSide: "1px" } |
| ] , |
| //NormalBottom: see onPageLoad() |
| //SmallBottom: see onPageLoad() |
| |
| /** |
| ** Usage: |
| ** RoundedCorners.register( "#header", ['yyyy', '00f000', '32cd32'] ); |
| **/ |
| registry: {}, |
| register: function( selector, parameters ) |
| { |
| this.registry[selector] = parameters; |
| return this; |
| }, |
| |
| onPageLoad: function() |
| { |
| /* make reverse copies for bottom definitions */ |
| this.NormalBottom = this.NormalTop.slice(0).reverse(); |
| this.SmallBottom = this.SmallTop.slice(0).reverse(); |
| |
| for( selector in this.registry ) // CHECK NEEDED |
| { |
| var n = $$(selector); |
| var parms = this.registry[selector]; |
| this.exec( n, parms[0], parms[1], parms[2], parms[3] ); |
| } |
| |
| $$('#pagecontent *[class^=roundedCorners]').each(function(el){ |
| var parms = el.className.split('-'); |
| if( parms.length < 2 ) return; |
| this.exec( [el], parms[1], parms[2], parms[3], parms[4] ); |
| },this); |
| }, |
| |
| exec: function( nodes, corners, color, borderColor, background ) |
| { |
| corners = ( corners ? corners+"nnnn": "yyyy" ); |
| color = new Color(color,'hex') || 'transparent'; |
| if(borderColor) borderColor = new Color(borderColor); |
| if(background) background = new Color(background); |
| |
| var c = corners.split(''); |
| /* [0]=top-left; [1]=top-right; [2]=bottom-left; [3]=bottom-right; */ |
| |
| var nodeTop = null; |
| var nodeBottom = null; |
| |
| if( c[0]+c[1] != "nn" ) //add top rounded corners |
| { |
| nodeTop = document.createElement("b") ; |
| nodeTop.className = "roundedCorners" ; |
| |
| if( (c[0] == "y") || (c[1] == "y") ) |
| { |
| this.addCorner( nodeTop, this.NormalTop, c[0], c[1], color, borderColor ); |
| } |
| else if( (c[0] == "s") || (c[1] == "s") ) |
| { |
| this.addCorner( nodeTop, this.SmallTop, c[0], c[1], color, borderColor ); |
| } |
| } |
| |
| if( c[2]+c[3] != "nn" ) //add bottom rounded corners |
| { |
| nodeBottom = document.createElement("b"); |
| nodeBottom.className = "roundedCorners"; |
| |
| if( (c[2] == "y") || (c[3] == "y") ) |
| { |
| this.addCorner( nodeBottom, this.NormalBottom, c[2], c[3], color, borderColor ); |
| } |
| else if( (c[2] == "s") || (c[3] == "s") ) |
| { |
| this.addCorner( nodeBottom, this.SmallBottom, c[2], c[3], color, borderColor ); |
| } |
| } |
| |
| if( (!nodeTop) && (!borderColor) && (!nodeBottom) ) return; |
| |
| for( var i=0; i<nodes.length; i++) |
| { |
| if( !nodes[i] ) continue; |
| this.addBody( nodes[i], color, borderColor ); |
| if( nodeTop ) nodes[i].insertBefore( nodeTop.cloneNode(true), nodes[i].firstChild ); |
| if( nodeBottom ) nodes[i].appendChild( nodeBottom.cloneNode(true) ); |
| } |
| }, |
| |
| addCorner: function( node, arr, left, right, color, borderColor ) |
| { |
| for( var i=0; i< arr.length; i++ ) |
| { |
| var n = document.createElement("div"); |
| n.style.height = arr[i].height; |
| n.style.overflow = "hidden"; |
| n.style.borderWidth = "0"; |
| n.style.backgroundColor = color.hex; |
| |
| if( borderColor ) |
| { |
| n.style.borderColor = borderColor.hex; |
| n.style.borderStyle = "solid"; |
| if(arr[i].borderTop) |
| { |
| n.style.borderTopWidth = arr[i].borderTop; |
| n.style.height = "0"; |
| } |
| } |
| |
| if( left != 'n' ) n.style.marginLeft = arr[i].margin; |
| if( right != 'n' ) n.style.marginRight = arr[i].margin; |
| if( borderColor ) |
| { |
| n.style.borderLeftWidth = ( left == 'n' ) ? "1px": arr[i].borderSide; |
| n.style.borderRightWidth = ( right == 'n' ) ? "1px": arr[i].borderSide; |
| } |
| node.appendChild( n ); |
| } |
| }, |
| |
| // move all children of the node inside a DIV and set color and bordercolor |
| addBody: function( node, color, borderColor) |
| { |
| if( node.passed ) return; |
| |
| var container = new Element('div').injectWrapper(node); |
| |
| container.style.padding = "0 4px"; |
| container.style.backgroundColor = color.hex; |
| if( borderColor ) |
| { |
| container.style.borderLeft = "1px solid " + borderColor.hex; |
| container.style.borderRight = "1px solid " + borderColor.hex; |
| } |
| |
| node.passed=true; |
| } |
| } |
| |
| |
| /** 230 Sortable -- Sort tables **/ |
| //TODO cache table ok, cache datatype for each column |
| var Sortable = |
| { |
| onPageLoad: function(){ |
| this.DefaultTitle = "sort.click".localize(); |
| this.AscendingTitle = "sort.ascending".localize(); |
| this.DescendingTitle = "sort.descending".localize(); |
| |
| $$('.sortable table').each(function(table){ |
| if( table.rows.length < 2 ) return; |
| |
| $A(table.rows[0].cells).each(function(th){ |
| th=$(th); |
| if( th.getTag() != 'th' ) return; |
| th.addEvent('click', function(){ Sortable.sort(th); }) |
| .addClass('sort') |
| .title=Sortable.DefaultTitle; |
| }); |
| },this); |
| }, |
| |
| sort: function(th){ |
| var table = getAncestorByTagName(th, "table" ), |
| filter = (table.filterStack), |
| rows = (table.sortCache || []), |
| colidx = 0, //target column to sort |
| body = $T(table); |
| th = $(th); |
| |
| //todo add spinner while sorting |
| //validate header row |
| $A(body.rows[0].cells).each(function(thi, i){ |
| if(thi.getTag() != 'th') return; |
| if(th == thi) { colidx=i; return; } |
| thi.removeClass('sortAscending').removeClass('sortDescending') |
| .addClass('sort').title = Sortable.DefaultTitle; |
| }); |
| |
| if(rows.length == 0){ //if data not yet cached |
| $A(body.rows).each(function(r,i){ |
| if((i==0) || ((i==1) && (filter))) return; |
| rows.push( r ); |
| }); |
| }; |
| var datatype = Sortable.guessDataType(rows,colidx); |
| |
| //do the actual sorting |
| if(th.hasClass('sort')){ |
| rows.sort( Sortable.createCompare(colidx, datatype) ) |
| } |
| else rows.reverse(); |
| |
| var fl=th.hasClass('sortDescending'); |
| th.removeClass('sort').removeClass('sortAscending').removeClass('sortDescending'); |
| th.addClass(fl ? 'sortAscending': 'sortDescending') |
| .title= fl ? Sortable.DescendingTitle: Sortable.AscendingTitle; |
| |
| var frag = document.createDocumentFragment(); |
| rows.each( function(r,i){ frag.appendChild(r); }); |
| body.appendChild(frag); |
| table.sortCache = rows; |
| if(table.zebra) table.zebra(); |
| }, |
| |
| guessDataType: function(rows, colidx){ |
| var num=date=ip4=euro=true; |
| rows.each(function(r,i){ |
| var v = $getText(r.cells[colidx]).clean().toLowerCase(); |
| if(num) num = !isNaN(parseFloat(v)); |
| if(date) date = !isNaN(Date.parse(v)); |
| if(ip4) ip4 = v.test("(?:\\d{1,3}\\.){3}\\d{1,3}"); |
| if(euro) euro = v.test("^[£$€][0-9.,]+"); |
| }); |
| return (euro) ? 'euro': (ip4) ? 'ip4': (date) ? 'date': (num) ? 'num': 'string'; |
| }, |
| |
| convert: function(val, datatype){ |
| switch(datatype){ |
| case "num" : return parseFloat( val.match( Number.REparsefloat ) ); |
| case "euro": return parseFloat( val.replace(/[^0-9.,]/g,'') ); |
| case "date": return new Date( Date.parse( val ) ); |
| case "ip4" : |
| var octet = val.split( "." ); |
| return parseInt(octet[0]) * 1000000000 + parseInt(octet[1]) * 1000000 + parseInt(octet[2]) * 1000 + parseInt(octet[3]); |
| default : return val.toString().toLowerCase(); |
| } |
| }, |
| |
| createCompare: function(i, datatype) { |
| return function(row1, row2) { |
| var val1 = Sortable.convert( $getText(row1.cells[i]), datatype ); |
| var val2 = Sortable.convert( $getText(row2.cells[i]), datatype ); |
| |
| if(val1<val2){ return -1 } else if(val1>val2){ return 1 } else return 0; |
| } |
| } |
| } |
| |
| /** 240 table-filters |
| ** inspired by http://www.codeproject.com/jscript/filter.asp |
| **/ |
| var TableFilter = |
| { |
| onPageLoad: function(){ |
| this.All = "filter.all".localize(); |
| this.FilterRow = 1; //row number of filter dropdowns |
| |
| $$('.table-filter table').each( function(table){ |
| if( table.rows.length < 2 ) return; |
| |
| /* |
| $A(table.rows[0].cells).each(function(e,i){ |
| var s = new Element('select',{ |
| 'events': { |
| 'click':function(event){ event.stop(); }.bindWithEvent(), |
| 'change':TableFilter.filter |
| } |
| }); |
| s.fcol = i; //store index |
| e.adopt(s); |
| },this); |
| */ |
| |
| var r = $(table.insertRow(TableFilter.FilterRow)).addClass('filterrow'); |
| for(var j=0; j < table.rows[0].cells.length; j++ ){ |
| var s = new Element('select',{ |
| 'events': { |
| 'change':TableFilter.filter |
| } |
| }); |
| s.fcol = j; //store index |
| |
| new Element('th').adopt(s).inject(r); |
| } |
| table.filterStack = []; |
| TableFilter.buildEmptyFilters(table); |
| }); |
| }, |
| |
| buildEmptyFilters: function(table){ |
| for(var i=0; i < table.rows[0].cells.length; i++){ |
| var ff = table.filterStack.some(function(f){ return f.fcol==i }); |
| if(!ff) TableFilter.buildFilter(table, i); |
| } |
| if(table.zebra) table.zebra(); |
| }, |
| |
| // this function initialises a column dropdown filter |
| buildFilter: function(table, col, selectedValue){ |
| // Get a reference to the dropdownbox. |
| var select = table.rows[TableFilter.FilterRow].cells[col].firstChild; |
| //var select = $(table.rows[0].cells[col]).getLast(); |
| if(!select) return; //empty dropdown |
| select.options.length = 0; |
| |
| var rows=[]; |
| $A(table.rows).each(function(r,i){ |
| if((i==0) || (i==TableFilter.FilterRow)) return; |
| if(r.style.display == 'none') return; |
| rows.push( r ); |
| }); |
| rows.sort(Sortable.createCompare(col, Sortable.guessDataType(rows,col))); |
| |
| //add only unique strings to the dropdownbox |
| select.options[0]= new Option(this.All, this.All); |
| var value; |
| rows.each(function(r,i){ |
| var v = $getText(r.cells[col]).clean().toLowerCase(); |
| if(v == value) return; |
| value = v; |
| if(v.length > 32) v = v.substr(0,32)+ "..."; |
| select.options[select.options.length] = new Option(v, value); |
| }); |
| (select.options.length <= 2) ? select.hide() : select.show(); |
| if(selectedValue != undefined) { |
| select.value = selectedValue; |
| } else { |
| select.options[0].selected = true; |
| } |
| }, |
| |
| filter: function(){ //onchange handler of filter dropdowns |
| var col = this.fcol, |
| value = this.value, |
| table = getAncestorByTagName(this, 'table'); |
| if( !table || table.style.display == 'none') return; |
| |
| // First check if the column is allready in the filter. |
| if(table.filterStack.every(function(f,i){ |
| if(f.fcol != col) return true; |
| if(value == TableFilter.All) table.filterStack.splice(i, 1); |
| else f.fValue = value; |
| return false; |
| }) ) table.filterStack.push( {fValue:value, fcol:col} ); |
| |
| $A(table.rows).each(function(r,i){ //show all |
| r.style.display=''; |
| }); |
| |
| table.filterStack.each(function(f){ //now filter the right rows |
| var v = f.fValue, c = f.fcol; |
| TableFilter.buildFilter(table, c, v); |
| |
| var j=0; |
| $A(table.rows).each(function(r,i){ |
| if((i==0) || (i==TableFilter.FilterRow)) return; |
| if(v != $getText(r.cells[c]).clean().toLowerCase()) r.style.display = 'none'; |
| }); |
| }); |
| TableFilter.buildEmptyFilters(table); //fill remaining dropdowns |
| } |
| } |
| |
| |
| /** 250 Categories: turn wikipage link into AJAXed popup **/ |
| var Categories = |
| { |
| onPageLoad: function (){ |
| this.jsp = Wiki.TemplateDir + '/AJAXCategories.jsp'; |
| |
| $$('.category a.wikipage').each(function(link){ |
| var page = Wiki.getPageName(link.href); if(!page) return; |
| var wrap = new Element('span').injectBefore(link).adopt(link), |
| popup = new Element('div',{'class':'categoryPopup'}).inject(wrap), |
| popfx = popup.effect('opacity',{wait:false}).set(0); |
| |
| link.addClass('categoryLink') |
| .setProperties({ href:'#', title: "category.title".localize(page) }) |
| .addEvent('click', function(e){ |
| new Event(e).stop(); //dont jump to top of page ;-) |
| new Ajax( Categories.jsp, { |
| postBody: '&page=' + page, |
| update: popup, |
| onComplete: function(){ |
| link.setProperty('title', '').removeEvent('click'); |
| wrap.addEvent('mouseover', function(e){ popfx.start(0.9); }) |
| .addEvent('mouseout', function(e){ popfx.start(0); }); |
| popup.setStyle('left', link.getPosition().x); |
| popfx.start(0.9); |
| } |
| }).request(); |
| }); |
| }); |
| } |
| } |
| |
| /** |
| ** 260 Wiki Tips: |
| **/ |
| var WikiTips = |
| { |
| onPageLoad: function() { |
| var tips = []; |
| $$('*[class^=tip]').each( function(t){ |
| var parms = t.className.split('-'); |
| if( parms.length<=0 || parms[0] != 'tip' ) return; |
| t.className = "tip"; |
| |
| var body = new Element('span').injectWrapper(t).hide(), |
| caption = (parms[1]) ? parms[1].deCamelize(): "tip.default.title".localize(); |
| |
| tips.push( |
| new Element('span',{ |
| 'class': 'tip-anchor', |
| 'title': caption + '::' + body.innerHTML |
| }).setHTML(caption).inject(t) |
| ); |
| }); |
| if( tips.length>0 ) new Tips( tips , {'className':'tip'} ); |
| } |
| } |
| |
| |
| /** |
| ** 270 Wiki Columns |
| ** Dirk Frederickx, Mar 07 |
| **/ |
| var WikiColumns = |
| { |
| onPageLoad: function() { |
| var tips = []; |
| $$('*[class^=columns]').each( function(t){ |
| var parms = t.className.split('-'); |
| t.className='columns'; |
| WikiColumns.buildColumns(t, parms[1] || 'auto'); |
| }); |
| }, |
| |
| buildColumns: function( el, width){ |
| var breaks = $ES('hr',el); |
| if(!breaks || breaks.length==0) return; |
| |
| var colCount = breaks.length+1; |
| width = (width=='auto') ? 98/colCount+'%' : width/colCount+'px'; |
| |
| var colDef = new Element('div',{'class':'col','styles':{'width':width}}), |
| col = colDef.clone().injectBefore(el.getFirst()), |
| n; |
| while(n = col.nextSibling){ |
| if(n.tagName && n.tagName.toLowerCase() == 'hr'){ |
| col = colDef.clone(); |
| $(n).replaceWith(col); |
| continue; |
| } |
| col.appendChild(n); |
| } |
| new Element('div',{'styles':{'clear':'both'}}).inject(el); |
| } |
| } |
| |
| /** 280 ZebraTable |
| ** Color odd/even rows of table differently |
| ** 1) odd rows get css class odd (ref. jspwiki.css ) |
| ** %%zebra-table ... %% |
| ** |
| ** 2) odd rows get css style='background=<color>' |
| ** %%zebra-<odd-color> ... %% |
| ** |
| ** 3) odd rows get odd-color, even rows get even-color |
| ** %%zebra-<odd-color>-<even-color> ... %% |
| ** |
| ** colors are specified in HEX (without #) format or html color names (red, lime, ...) |
| **/ |
| var ZebraTable = { |
| |
| onPageLoad: function(){ |
| $$('*[class^=zebra]').each(function(z){ |
| var parms = z.className.split('-'), |
| isDefault = parms[1].test('table'), |
| c1 = '', |
| c2 = ''; |
| if(parms[1]) c1= new Color(parms[1],'hex'); |
| if(parms[2]) c2= new Color(parms[2],'hex'); |
| $ES('table',z).each(function(t){ |
| t.zebra = this.zebrafy.pass([isDefault, c1,c2],t); |
| t.zebra(); |
| },this); |
| },this); |
| }, |
| zebrafy: function(isDefault, c1,c2){ |
| var j=0; |
| $A($T(this).rows).each(function(r,i){ |
| if(i==0 || (r.style.display=='none')) return; |
| if(isDefault) (j++ % 2 == 0) ? $(r).addClass('odd') : $(r).removeClass('odd'); |
| else $(r).setStyle('background-color', (j++ % 2 == 0) ? c1 : c2 ); |
| }); |
| } |
| } |
| |
| |
| /** Highlight Word |
| ** Inspired by http://www.kryogenix.org/code/browser/searchhi/ |
| ** Modified 21006 to fix query string parsing and add case insensitivity |
| ** Modified 20030227 by sgala@hisitech.com to skip words |
| ** with "-" and cut %2B (+) preceding pages |
| ** Refactored for JSPWiki -- now based on regexp, by D.Frederickx. Nov 2005 |
| **/ |
| var HighlightWord = |
| { |
| ReQuery: new RegExp( "(?:\\?|&)(?:q|query)=([^&]*)", "g" ), |
| |
| onPageLoad: function (){ |
| var q = Wiki.prefs.get('PrevQuery'); Wiki.prefs.set('PrevQuery', ''); |
| if( !q && this.ReQuery.test(document.referrer)) q = RegExp.$1; |
| if( !q ) return; |
| |
| var words = decodeURIComponent(q); |
| words = words.replace( /\+/g, " " ); |
| words = words.replace( /\s+-\S+/g, "" ); |
| words = words.replace( /([\(\[\{\\\^\$\|\)\?\*\.\+])/g, "\\$1" ); //escape metachars |
| words = words.trim().split(/\s+/).join("|"); |
| this.reMatch = new RegExp( "(" + words + ")" , "gi"); |
| |
| this.walkDomTree( $("pagecontent") ); |
| }, |
| |
| // recursive tree walk matching all text nodes |
| walkDomTree: function( node ) |
| { |
| if( !node ) return; /* bugfix */ |
| var nn = null; |
| for( var n = node.firstChild; n ; n = nn ) { |
| nn = n. nextSibling; /* prefetch nextSibling cause the tree will be modified */ |
| this.walkDomTree( n ); |
| } |
| // continue on text-nodes, not yet highlighted, with a word match |
| if( node.nodeType != 3 ) return; |
| if( node.parentNode.className == "searchword" ) return; |
| var s = node.innerText || node.textContent || ''; |
| if( !this.reMatch.test( s ) ) return; |
| var tmp = new Element('span').setHTML(s.replace(this.reMatch,"<span class='searchword'>$1</span>")); |
| |
| var f = document.createDocumentFragment(); |
| while( tmp.firstChild ) f.appendChild( tmp.firstChild ); |
| |
| node.parentNode.replaceChild( f, node ); |
| } |
| } |
| |
| |
| /* 300 Javascript Code Prettifier |
| * based on http://google-code-prettify.googlecode.com/svn/trunk/README.html |
| */ |
| var WikiPrettify = { |
| onPageLoad: function(){ |
| var els = $$('.prettify pre, .prettify code'); if(!els) return; |
| |
| //TODO: load assets .css and .js |
| els.addClass('prettyprint'); |
| prettyPrint(); |
| } |
| } |
| |
| |
| window.addEvent('load', function(){ |
| |
| Wiki.onPageLoad(); |
| WikiReflection.onPageLoad(); //before accordion cause impacts height! |
| WikiAccordion.onPageLoad(); |
| |
| TabbedSection.onPageLoad(); //after coordion or safari |
| QuickLinks.onPageLoad(); |
| |
| //console.profile(); |
| Collapsible.onPageLoad(); |
| //console.profileEnd(); |
| |
| SearchBox.onPageLoad(); |
| Sortable.onPageLoad(); |
| TableFilter.onPageLoad(); |
| RoundedCorners.onPageLoad(); |
| ZebraTable.onPageLoad(); |
| HighlightWord.onPageLoad(); |
| GraphBar.onPageLoad(); |
| Categories.onPageLoad(); |
| |
| WikiSlimbox.onPageLoad(); |
| WikiTips.onPageLoad(); |
| WikiColumns.onPageLoad(); |
| WikiPrettify.onPageLoad(); |
| }); |