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}