diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/exe/ajax.php | 111 | ||||
-rw-r--r-- | lib/exe/js.php | 1 | ||||
-rw-r--r-- | lib/images/close.png | bin | 0 -> 820 bytes | |||
-rw-r--r-- | lib/scripts/linkwiz.js | 250 | ||||
-rw-r--r-- | lib/scripts/toolbar.js | 10 | ||||
-rw-r--r-- | lib/tpl/default/_linkwiz.css | 58 | ||||
-rw-r--r-- | lib/tpl/default/style.ini | 1 |
7 files changed, 430 insertions, 1 deletions
diff --git a/lib/exe/ajax.php b/lib/exe/ajax.php index 4a30b0349..53ff3882c 100644 --- a/lib/exe/ajax.php +++ b/lib/exe/ajax.php @@ -240,5 +240,114 @@ function ajax_index(){ } } +/** + * List matching namespaces and pages for the link wizard + */ +function ajax_linkwiz(){ + global $conf; + global $lang; + require_once(DOKU_INC.'inc/html.php'); + + $q = ltrim($_POST['q'],':'); + $id = noNS($q); + $ns = getNS($q); + + $ns = cleanID($ns); + $id = cleanID($id); + + $nsd = utf8_encodeFN(str_replace(':','/',$ns)); + $idd = utf8_encodeFN(str_replace(':','/',$id)); + + $data = array(); + if($q && !$ns){ + + // use index to lookup matching pages + require_once(DOKU_INC.'inc/fulltext.php'); + require_once(DOKU_INC.'inc/parserutils.php'); + $pages = array(); + $pages = ft_pageLookup($id,false); + + // result contains matches in pages and namespaces + // we now extract the matching namespaces to show + // them seperately + $dirs = array(); + $count = count($pages); + for($i=0; $i<$count; $i++){ + if(strpos(noNS($pages[$i]),$id) === false){ + // match was in the namespace + $dirs[getNS($pages[$i])] = 1; // assoc array avoids dupes + }else{ + // it is a matching page, add it to the result + $data[] = array( + 'id' => $pages[$i], + 'title' => p_get_first_heading($pages[$i],false), + 'type' => 'f', + ); + } + unset($pages[$i]); + } + foreach($dirs as $dir => $junk){ + $data[] = array( + 'id' => $dir, + 'type' => 'd', + ); + } + + }else{ + + require_once(DOKU_INC.'inc/search.php'); + $opts = array( + 'depth' => 1, + 'listfiles' => true, + 'listdirs' => true, + 'pagesonly' => true, + 'firsthead' => true, + ); + if($id) $opts['filematch'] = '^.*\/'.$id; + if($id) $opts['dirmatch'] = '^.*\/'.$id; + search($data,$conf['datadir'],'search_universal',$opts,$nsd); + + // add back to upper + if($ns){ + array_unshift($data,array( + 'id' => getNS($ns), + 'type' => 'u', + )); + } + } + + // fixme sort results in a useful way ? + + if(!count($data)){ + echo $lang['nothingfound']; + exit; + } + + // output the found data + $even = 1; + foreach($data as $item){ + $even *= -1; //zebra + + if(($item['type'] == 'd' || $item['type'] == 'u') && $item['id']) $item['id'] .= ':'; + $link = wl($item['id']); + + echo '<div class="'.(($even > 0)?'even':'odd').' type_'.$item['type'].'">'; + + + if($item['type'] == 'u'){ + $name = 'back to upper'; + }else{ + $name = htmlspecialchars($item['id']); + } + + echo '<a href="'.$link.'" title="'.htmlspecialchars($item['id']).'" class="wikilink1">'.$name.'</a>'; + + if($item['title']){ + echo '<span>'.htmlspecialchars($item['title']).'</span>'; + } + echo '</div>'; + } + +} + //Setup VIM: ex: et ts=2 enc=utf-8 : -?> diff --git a/lib/exe/js.php b/lib/exe/js.php index 96c7c6e77..9bf392e4c 100644 --- a/lib/exe/js.php +++ b/lib/exe/js.php @@ -55,6 +55,7 @@ function js_out(){ $files[] = DOKU_INC.'lib/scripts/textselection.js'; $files[] = DOKU_INC.'lib/scripts/toolbar.js'; $files[] = DOKU_INC.'lib/scripts/edit.js'; + $files[] = DOKU_INC.'lib/scripts/linkwiz.js'; } $files[] = DOKU_INC.'lib/scripts/media.js'; } diff --git a/lib/images/close.png b/lib/images/close.png Binary files differnew file mode 100644 index 000000000..06c1cf41f --- /dev/null +++ b/lib/images/close.png diff --git a/lib/scripts/linkwiz.js b/lib/scripts/linkwiz.js new file mode 100644 index 000000000..01deb2234 --- /dev/null +++ b/lib/scripts/linkwiz.js @@ -0,0 +1,250 @@ +/** + * The Link Wizard + * + * @author Andreas Gohr <gohr@cosmocode.de> + */ +linkwiz = { + wiz: null, + entry: null, + result: null, + timer: null, + sack: null, + textArea: null, + selected: -1, + + /** + * Initialize the linkwizard by creating the needed HTML + * and attaching the eventhandlers + */ + init: function(textArea){ + // prepare AJAX object + linkwiz.sack = new sack(DOKU_BASE + 'lib/exe/ajax.php'); + linkwiz.sack.AjaxFailedAlert = ''; + linkwiz.sack.encodeURIString = false; + + // create HTML Structure + linkwiz.wiz = document.createElement('div'); + linkwiz.wiz.id = 'link__wiz'; + linkwiz.wiz.className = 'picker'; + linkwiz.wiz.style.top = (findPosY(textArea)+20)+'px'; + linkwiz.wiz.style.left = (findPosX(textArea)+80)+'px'; + linkwiz.wiz.style.display = 'none'; + + linkwiz.wiz.innerHTML = + '<div id="link__wiz_header">'+ + '<img src="'+DOKU_BASE+'lib/images/close.png" width="16" height="16" align="right" alt="" id="link__wiz_close" />'+ + 'Link Wizard</div>'+ + '<div>Link: <input type="text" class="edit" id="link__wiz_entry" autocomplete="off" /></div>'+ + '<div id="link__wiz_result"></div>'; + textArea.form.parentNode.appendChild(linkwiz.wiz); + linkwiz.textArea = textArea; + linkwiz.result = $('link__wiz_result'); + linkwiz.entry = $('link__wiz_entry'); + + // attach event handlers + var obj; + obj = $('link__wiz_close'); + obj.onclick = linkwiz.hide; + + linkwiz.sack.elementObj = linkwiz.result; + addEvent(linkwiz.entry,'keyup',linkwiz.onEntry); + addEvent(linkwiz.result,'click',linkwiz.onResultClick); + drag.attach(linkwiz.wiz,$('link__wiz_header')); + }, + + /** + * handle all keyup events in the entry field + */ + onEntry: function(e){ + if(e.keyCode == 37 || e.keyCode == 39){ //left/right + return true; //ignore + } + if(e.keyCode == 38){ //Up + linkwiz.select(linkwiz.selected -1); + e.preventDefault(); + e.stopPropagation(); + return false; + } + if(e.keyCode == 40){ //Down + linkwiz.select(linkwiz.selected +1); + e.preventDefault(); + e.stopPropagation(); + return false; + } + if(e.keyCode == 13){ //Enter + if(linkwiz.selected > -1){ + var obj = linkwiz.getResult(linkwiz.selected); + if(obj){ + var a = obj.getElementsByTagName('A')[0]; + linkwiz.resultClick(a); + } + }else if(linkwiz.entry.value){ + linkwiz.insertLink(linkwiz.entry.value); + } + + e.preventDefault(); + e.stopPropagation(); + return false; + } + linkwiz.autocomplete(); + }, + + /** + * Get one of the result by index + * + * @param int result div to return + * @returns DOMObject or null + */ + getResult: function(num){ + var obj; + var childs = linkwiz.result.getElementsByTagName('DIV'); + obj = childs[num]; + if(obj){ + return obj; + }else{ + return null; + } + }, + + /** + * Select the given result + */ + select: function(num){ + if(num < 0){ + linkwiz.deselect(); + return; + } + + var obj = linkwiz.getResult(num); + if(obj){ + linkwiz.deselect(); + obj.className += ' selected'; + linkwiz.selected = num; + } + }, + + /** + * deselect a result if any is selected + */ + deselect: function(){ + if(linkwiz.selected > -1){ + var obj = linkwiz.getResult(linkwiz.selected); + if(obj){ + obj.className = obj.className.replace(/ ?selected/,''); + } + } + linkwiz.selected = -1; + }, + + /** + * Handle clicks in the result set an dispatch them to + * resultClick() + */ + onResultClick: function(e){ + if(e.target.tagName != 'A') return; + e.stopPropagation(); + e.preventDefault(); + linkwiz.resultClick(e.target); + return false; + }, + + /** + * Handles the "click" on a given result anchor + */ + resultClick: function(a){ + var id = a.title; + if(id == '' || id.substr(id.length-1) == ':'){ + linkwiz.entry.value = id; + linkwiz.autocomplete_exec(); + }else{ + linkwiz.entry.value = id; + if(a.nextSibling && a.nextSibling.tagName == 'SPAN'){ + linkwiz.insertLink(a.nextSibling.innerHTML); + }else{ + linkwiz.insertLink(''); + } + } + }, + + /** + * Insert the id currently in the entry box to the textarea, + * replacing the current selection or at the curso postion. + * When no selection is available the given title will be used + * as link title instead + */ + insertLink: function(title){ + if(!linkwiz.entry.value) return; + var sel = getSelection(linkwiz.textArea); + var stxt = sel.getText(); + if(!stxt) stxt=title; + + var link = '[['+linkwiz.entry.value; + if(stxt) link += '|'+stxt; + link += ']]'; + + var so = linkwiz.entry.value.length+3; + var eo = 2; + + pasteText(sel,link,{startofs: so, endofs: eo}); + linkwiz.hide(); + }, + + /** + * Start the page/namespace lookup timer + * + * Calls autocomplete_exec when the timer runs out + */ + autocomplete: function(){ + if(linkwiz.timer !== null){ + window.clearTimeout(linkwiz.timer); + linkwiz.timer = null; + } + + linkwiz.timer = window.setTimeout(linkwiz.autocomplete_exec,350); + }, + + /** + * Executes the AJAX call for the page/namespace lookup + */ + autocomplete_exec: function(){ + linkwiz.deselect(); + linkwiz.result.innerHTML = '<img src="'+DOKU_BASE+'lib/images/throbber.gif" alt="" width="16" height="16" />'; + linkwiz.sack.runAJAX('call=linkwiz&q='+encodeURI(linkwiz.entry.value)); + }, + + /** + * Clears the result area + */ + clear: function(){ + linkwiz.result.innerHTML = 'Search for a matching page name above, or browse through the pages on the right'; + linkwiz.entry.value = ''; + }, + + /** + * Show the linkwizard + */ + show: function(){ + linkwiz.wiz.style['display'] = ''; + linkwiz.entry.focus(); + linkwiz.autocomplete(); + }, + + /** + * Hide the link wizard + */ + hide: function(){ + linkwiz.wiz.style['display'] = 'none'; + }, + + /** + * Toggle the link wizard + */ + toggle: function(){ + if(linkwiz.wiz.style['display'] == 'none'){ + linkwiz.show(); + }else{ + linkwiz.hide(); + } + }, +}; + diff --git a/lib/scripts/toolbar.js b/lib/scripts/toolbar.js index 48a4a4a7e..3ad370ff5 100644 --- a/lib/scripts/toolbar.js +++ b/lib/scripts/toolbar.js @@ -145,6 +145,16 @@ function addBtnActionPicker(btn, props, edid) { return true; } +function addBtnActionLinkwiz(btn, props, edid) { + linkwiz.init($(edid)); + addEvent(btn,'click',function(){ + linkwiz.toggle(); + return false; + }); + return true; +} + + /** * Show/Hide a previosly created picker window * diff --git a/lib/tpl/default/_linkwiz.css b/lib/tpl/default/_linkwiz.css new file mode 100644 index 000000000..2a6a8997d --- /dev/null +++ b/lib/tpl/default/_linkwiz.css @@ -0,0 +1,58 @@ + +#link__wiz { + position: absolute; + display: block; + z-index: 99; + width: 300px; + height: 250px; + padding: 0; + margin: 0; + overflow: hidden; + border: 1px solid __border__; + background-color: __background_neu__; +} + +#link__wiz_header { + background-color: __background_alt__; + text-align: center; + height: 16px; + margin-bottom: 5px; +} + +#link__wiz_close { + cursor: pointer; + margin: 0; +} + +#link__wiz_result { + background-color: __background__; + width: 293px; + height: 193px; + overflow: auto; + border: 1px solid __border__; + margin: 3px auto; +} + +#link__wiz_result div.type_f { + padding: 3px 3px 3px 22px; + background: transparent url(../../images/page.png) 3px 3px no-repeat; +} + +#link__wiz_result div.type_d { + padding: 3px 3px 3px 22px; + background: transparent url(../../images/ns.png) 3px 3px no-repeat; +} + +#link__wiz_result div.even { + background-color: __background_neu__; +} + +#link__wiz_result div.selected { + background-color: __background_alt__; +} + +#link__wiz_result span { + display: block; + color: __text_neu__ +} + diff --git a/lib/tpl/default/style.ini b/lib/tpl/default/style.ini index 7631a34b7..dfd5500fa 100644 --- a/lib/tpl/default/style.ini +++ b/lib/tpl/default/style.ini @@ -12,6 +12,7 @@ style.css = screen media.css = screen _admin.css = screen +_linkwiz.css = screen rtl.css = rtl print.css = print |