1/* 2* Checks if property is derived from prototype, applies method if it is not exists 3* 4* @param string property name 5* @return bool true if prototyped 6* @access public 7*/ 8if ('undefined' == typeof Object.hasOwnProperty) { 9 Object.prototype.hasOwnProperty = function (prop) { 10 return !(this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]); 11 } 12} 13/************************************************ 14******** DOM related stuff 15************************************************/ 16/* 17* Performs parent lookup by 18* - node object: actually it's "is child of" check 19* - tagname: getParent(el, 'li') == getParent(el, 'tagName', 'LI') 20* - any node attribute 21* 22* @param DOMnode source element 23* @param mixed DOMNode or string tagname or string attribute name 24* @param string optional attribute value 25* @return mixed DOMNode or null 26*/ 27function getParent (el, cp, vl) { 28 if (el == null) return null; 29 else if (el.nodeType == 1 && 30 ((!isUndefined(vl) && el[cp] == vl) || 31 ('string' == typeof cp && el.tagName.toLowerCase() == cp.toLowerCase()) || 32 el == cp)) return el; 33 else return getParent(el.parentNode, cp, vl); 34}; 35 36/* 37* Creates element all-at-once 38* 39* @param string tag name 40* @param hash tag element properties { 'class' : 'className', 41* 'style' : { 'property' : value, ... }, 42* 'event' : { 'eventType' : handler, ... }, 43* 'child' : [ child1, child2, ...], 44* 'param' : { 'property' : value, ... }, 45* @return DOMObject created element or false 46* @access public 47*/ 48document.createElementExt = function (tag,p) { 49 var L, i, k, el = document.createElement(tag); 50 if (!el) return false; 51 for (i in p) { 52 if (!p.hasOwnProperty(i)) continue; 53 switch (i) { 54 case "class" : el.setAttribute('className',p[i]); el.setAttribute('class',p[i]); break; 55 case "style" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; el.style[k] = p[i][k]; } break; 56 case "event" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; el.attachEvent(k,p[i][k]); } break; 57 case "child" : L = p[i].length; for (k = 0; k<L; k++) el.appendChild(p[i][k]); break; 58 case "param" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; try { el[k] = p[i][k] } catch(e) {} } break; 59 } 60 } 61 return el; 62}; 63 64/* 65* Plugin used to fetch from the server document preview 66* 67* @author Ilya Lebedev 68* @lastmodified 2006-09-03 69* @license LGPL 70* @title LivePreview 71*/ 72 73var LivePreview = new function() { 74 var self = this; 75 /* 76 * current anchor 77 * 78 * @type {HTMLAElement} 79 * @access private 80 */ 81 var curA = null; 82 var dotQuestion = document.createElementExt('div' 83 ,{'param' : {'id' : 'livePreview'} 84 ,'child' : [document.createElementExt('div' 85 ,{'class' : 'livePreviewIcon', 86 'child' : [document.createElementExt('span',{'child': [document.createTextNode('[?]')]})] 87 } 88 ) 89// ,document.createTextNode('1') 90 ] 91 } 92 ); 93 /* 94 * Storage for the loaded previews 95 * 96 * @type Object 97 * @access private 98 */ 99 var tooltips = {}; 100 /* 101 * return object's position 102 * 103 * @see javascripttoolbox.com/lib/objectposition/ 104 * @author Matt Kruse 105 * @param {HTMLElement} object to found position of 106 * @access private 107 */ 108 var getPos = function(o) { 109 var fixBrowserQuirks = true; 110 111 if (o==null) { 112 return null; 113 } 114 115 var left = 0; 116 var top = 0; 117 var width = 0; 118 var height = 0; 119 var parentNode = null; 120 var offsetParent = null; 121 122 123 offsetParent = o.offsetParent; 124 var originalObject = o; 125 var el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references 126 while (el.parentNode!=null) { 127 el = el.parentNode; 128 if (el.offsetParent==null) { 129 } 130 else { 131 var considerScroll = true; 132 /* 133 In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already 134 take its scroll position into account. If elements further up the chain are scrollable, their 135 scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value 136 which must be ignored. 137 */ 138 if (fixBrowserQuirks && window.opera) { 139 if (el==originalObject.parentNode || el.nodeName=="TR") { 140 considerScroll = false; 141 } 142 } 143 if (considerScroll) { 144 if (el.scrollTop && el.scrollTop>0) { 145 top -= el.scrollTop; 146 } 147 if (el.scrollLeft && el.scrollLeft>0) { 148 left -= el.scrollLeft; 149 } 150 } 151 } 152 // If this node is also the offsetParent, add on the offsets and reset to the new offsetParent 153 if (el == offsetParent) { 154 left += o.offsetLeft; 155 if (el.clientLeft && el.nodeName!="TABLE") { 156 left += el.clientLeft; 157 } 158 top += o.offsetTop; 159 if (el.clientTop && el.nodeName!="TABLE") { 160 top += el.clientTop; 161 } 162 o = el; 163 if (o.offsetParent==null) { 164 if (o.offsetLeft) { 165 left += o.offsetLeft; 166 } 167 if (o.offsetTop) { 168 top += o.offsetTop; 169 } 170 } 171 offsetParent = o.offsetParent; 172 } 173 } 174 175 176 if (originalObject.offsetWidth) { 177 width = originalObject.offsetWidth; 178 } 179 if (originalObject.offsetHeight) { 180 height = originalObject.offsetHeight; 181 } 182 183 return {'left':left, 'top':top, 'width':width, 'height':height 184 }; 185 }; 186 187 /* 188 * Update toolip contents 189 * 190 * @param {String} tooltip id 191 * @param {String} new content 192 * @access private 193 */ 194 var tooltipShow = function (id, content) { 195 domTT_update(tooltips[id], content); 196 197 }; 198 /* 199 * Retrieve object's position from the server 200 * 201 * @param {String} document URI 202 * @access private 203 */ 204 var tooltipFetch = function (href) { 205 if (!RemoteScript) { 206 tooltipShow(href,'RemoteScript plugin is not available'); 207 } else { 208 tooltipShow(href,'Please wait, loading...'); 209 }; 210 var req = new RemoteScript; 211 req.onreadystatechange = function() { 212 if (req.readyState == 4) { 213 if (req.responseJS) { 214 tooltipShow(href, req.responseJS); 215 } else { 216 tooltipShow(href, '<br />'+req.responseText); 217 } 218 } 219 }; 220 req.loader = 'script'; 221 req.cache = false; 222 req.open ("GET",['livepreview','getpreview']); 223 req.send ({'src' : href}); 224 }; 225 /* 226 * Tries to find the anchor to the local page 227 * 228 * @param {MouseEvent} mousemove event 229 * @access protected 230 */ 231 this.anchorCatcher = function (e) { 232 if (!dotQuestion.offsetParent) document.body.appendChild(dotQuestion); 233 var el = getParent(e.srcElement || e.target, 'a'); 234 /* 235 * get the controller 236 */ 237 var ctrl = getParent(e.srcElement || e.target, 'className', 'livePreviewIcon'); 238 /* 239 * if we are on the livepreview controller, show the tip 240 */ 241 if (ctrl && curA && (!tooltips[String(curA)] || !domTT_isActive(tooltips[String(curA)]))) { 242 var ts1 = 'undefined' == typeof tooltips[curA.href]; 243 var i = 'livePreviewTip'+Math.round(Math.random()*10000); 244 tooltips[String(curA)] = domTT_activate(curA, e, 'content', '...', 245 'type', 'velcro', 246 'delay', 1, 247 'width', 400, 248 'id', i, 249 'styleClass', 'livePreviewTooltip', 250 'maxWidth', document.body.offsetWidth*0.8); 251 if (ts1) { 252 tooltipFetch(String(curA)); 253 } 254 } 255 256 /* 257 * no need to update current target 258 */ 259 if (el == curA || (ctrl && curA)) return; 260 261 /* 262 * if something was before... 263 */ 264 if (ctrl != null 265 || (el != null // element exists 266 && el.className.indexOf('urlextern')<0 // is not an external link 267 && el.className.indexOf('toc')<0 // is not a toc item 268 && !String(el).match(/\.php$/) // is not a script 269 && String(el).indexOf(document.location.protocol+"//" 270 +document.location.host)==0 // host is the same as current 271 && (document.location.pathname == DOKU_BASE // site's root 272 || String(el).indexOf(document.location.protocol+"//" 273 +document.location.host+document.location.pathname)<0 // is not a cyclic url 274 ) 275 && !String(el).match(/[?&]do=/) // is not the action url 276 ) 277 ) { 278 var c = getPos(ctrl?curA:el); 279 dotQuestion.style.left = c.left+(ctrl?curA:el).offsetWidth+'px'; 280 dotQuestion.style.top = c.top+3+'px'; 281 dotQuestion.style.display = ''; 282 } else { 283 dotQuestion.style.display = 'none'; 284 } 285 if (el != curA && curA) domTT_deactivate(tooltips[curA.href]); 286 287 /* 288 * save current handler, if we are on the anchor 289 */ 290 if (!ctrl) curA = el; 291 } 292}; 293 294if (document.addEventListener) { 295 document.addEventListener('mousemove',LivePreview.anchorCatcher,false); 296} else if (document.attachEvent) { 297 document.attachEvent('onmousemove',LivePreview.anchorCatcher) 298}