Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/webdocs/scripts/jspwiki-edit.js URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/webdocs/scripts/jspwiki-edit.js?rev=685201&r1=685200&r2=685201&view=diff ============================================================================== --- incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/webdocs/scripts/jspwiki-edit.js (original) +++ incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/webdocs/scripts/jspwiki-edit.js Tue Aug 12 08:47:28 2008 @@ -1,103 +1,40 @@ +/* + JSPWiki - a JSP-based WikiWiki clone. + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + /** - ** jspwiki edit support routines - ** Based on brushed template - ** Needs jspwiki-common.js and mootools.js + ** Javascript routines to support JSPWiki Editing + ** since v.2.6.0 + ** uses mootools v1.1 ** + ** Needs jspwiki-common.js and mootools.js ** EditTools object (main object) ** - find&replace functionality : with regexp support - ** - ** - included popup-pagelinks routine from Janne // + ** - included popup-pagelinks routines from Janne ** ** TextArea object ** Supports selections inside textarea, in ie and other browsers **/ - -var EditTools = +var WikiSnippets = { - onPageLoad: function(){ - - this.textarea = $('editorarea'); - if(!this.textarea || !this.textarea.visible) return; - - window.onbeforeunload = (function(){ - if(this.textarea.value != this.textarea.defaultValue) { - return "edit.areyousure".localize(); - }; - }).bind(this); - - /* make textarea more intelligent */ - this.wikisnippets = this.getWikiSnippets(); - this.wikismartpairs = this.getWikiSmartPairs(); - this.onPageLoadPostEditor(); - - /* activate editassist toolbar */ - var toolbar = $('toolbar'); - var fxToolbar = new Fx.Slide(toolbar,{ - onStart:function(){ - $('editassist').toggleClass('closed'); - } - }); - var e = $('editassist').addEvent('click', function(e){ - e = new Event(e); - fxToolbar.toggle(); - e.stop(); - }).getParent().show(); - - - //FIXME: stop-event not yet working properly on eg UNDO - $('tbREDO').addEvent('click', function(e) { EditTools.redoTextarea(); new Event(e).stop(); }); - $('tbUNDO').addEvent('click', function(e) { new Event(e).stop(); EditTools.undoTextarea(); }); - $('replace').addEvent('click', function(e) { EditTools.doReplace(); new Event(e).stop(); }) - .getParent().getParent().show(); - - toolbar.getElements('a.tool').each(function(el){ - el.addEvent('click', this.insertTextArea.pass(el,this)); - },this); - - /* add textarea resize drag bar */ - var hh=Wiki.prefs.get('EditorSize'); - if(hh) this.textarea.setStyle('height',hh); - var h = new Element('div',{'class':'textarea-resizer', 'title':'edit.resize'.localize()}) - .injectAfter(this.textarea); - this.textarea.makeResizable({ - handle:h, - modifiers: {x:false, y:'height'}, - onComplete: function(){ Wiki.prefs.set('EditorSize',this.value.now.y); } - }); - - }, - - onPageLoadPostEditor: function(){ - if(window.ie) return; - this.posteditor = new postEditor.create(this.textarea,'changenote'); - - /* patch posteditor DF Jul 07 */ - /* righ-arrow nok on FF, nop on Safari */ - this.posteditor.onKeyRight = Class.empty; - /* make posteditor changes undoable */ - this.posteditor.value = function(value) { - EditTools.storeTextarea(); - this.element.value = value.join(""); - }; - - ['smartpairs', 'tabcompletion'].each( function(el){ - $(el).setProperty('checked', Wiki.prefs.get(el) || false) - .addEvent('click',function(e) { - Wiki.prefs.set(el,this.checked); - EditTools.initPostEditor(); - }); - },this); - $('smartpairs').getParent().show(); - - this.initPostEditor(); - }, - initPostEditor: function(){ - if(! this.posteditor) return; - this.posteditor.changeSmartTypingPairs( $('smartpairs').checked ? this.wikismartpairs : {} ); - this.posteditor.changeSnippets( $('tabcompletion').checked ? this.wikisnippets : {} ); - }, - - getWikiSnippets: function(){ + getSnippets: function(){ return { "toc" : { snippet:["","[{TableOfContents }]", "\n"], @@ -128,19 +65,19 @@ tab:['some italic text',''] }, "h1" : { - snippet:["!!! ","Heading 1 title", "\n"], - tab:["Heading 1 title", ""] + snippet:["!!!","Heading 1 title\n", ""], + tab:["Heading 1 title\n", ""] }, "h2" : { - snippet:["!! ","Heading 2 title", "\n"], - tab:["Heading 2 title", ""] + snippet:["!!","Heading 2 title", ""], + tab:["Heading 2 title\n", ""] }, "h3" : { - snippet:["! ","Heading 3 title", "\n"], - tab:["Heading 3 title", ""] + snippet:["!","Heading 3 title", ""], + tab:["Heading 3 title\n", ""] }, "dl" : { - snippet:["\n",";term:definition text", "\n"], + snippet:[";","term:definition text", ""], tab:["term","definition text", ""] }, "mono" : { @@ -148,7 +85,7 @@ tab:["some monospaced text", ""] }, "hr" : { - snippet:['----\n','',''], + snippet:['','----','\n'], tab:[''] }, "sub" : { @@ -205,10 +142,10 @@ }; } } -} /* return */ + } /* return */ }, - getWikiSmartPairs: function(){ + getSmartPairs: function(){ return { '"' : '"', '(' : ')', @@ -217,280 +154,574 @@ '<' : '>', "'" : { scope:{ "{{{":"}}}" }, pair:"'" } } + } +} + +/* + * + */ +var EditTools = +{ + onPageLoad: function(){ + + Wiki.onPageLoad(); //Wiki.onpageload should always run first, but seems not guaranteed on ie so let's do this for sure + + this.textarea = $('editorarea'); + if(!this.textarea || !this.textarea.visible) return; + + /* Duplicate the textarea into a main and work area. + The workarea is used for actual editing. + The mainarea reflects at all times the whole document + */ + var m = this.mainarea = this.textarea; + this.textarea = m.clone() + .removeProperty('id') + .removeProperty('name') + .injectBefore( m.hide() ); + + //this.ta = new TextArea( this.textarea ); + this.ta = TextArea.initialize( this.textarea ); + + window.onbeforeunload = (function(){ + var ta = $('editorarea'); + if(ta.value != ta.defaultValue) return "edit.areyousure".localize(); + }).bind(this); + + //alert($('scroll').getValue()); + + this.wikisnippets = WikiSnippets.getSnippets(); + this.wikismartpairs = WikiSnippets.getSmartPairs(); + + this.onPageLoadSectionToc(); + this.onPageLoadResizeTextarea(); + this.onPageLoadToolbar(); + + this.onPageLoadPostEditor(); + this.onPageLoadPreview(); + + /* add textarea suggestion events */ + this.textarea + .addEvent('click',this.getSuggestions.bind(this)) + .addEvent('keyup',this.getSuggestions.bind(this)) + .focus(); }, - insertTextArea: function(el) { - var snippy = this.wikisnippets[el.getText()]; if(!snippy) return - var s = TextArea.getSelection(this.textarea), - t = snippy.snippet.join(''); - EditTools.storeTextarea(); + /* add textarea resize drag bar */ + onPageLoadResizeTextarea: function(){ + var hh=Wiki.prefs.get('EditorSize'); + if(hh) this.textarea.setStyle('height',hh); - if((el.rel=='break') && (!TextArea.isSelectionAtStartOfLine(this.textarea))) { - t = "\n" + t; - } - if(s) t = t.replace( snippy.tab[0], s) - TextArea.replaceSelection(this.textarea, t); - return false; /*don't propagate*/ - } , + var h = new Element('div',{ + 'class':'textarea-resizer', + 'title':'edit.resize'.localize() + }).injectAfter(this.textarea); - /* TOOLBAR: find&replace */ - doReplace: function( ){ - var findText = $('tbFIND').value, + this.textarea.makeResizable({ + handle:h, + modifiers: {x:false, y:'height'}, + onComplete: function(){ + Wiki.prefs.set('EditorSize',this.value.now.y); + } + }); + }, + + onPageLoadToolbar: function(){ + $('tools').addClass('collapsebox-closed'); + Collapsible.render('editform',''); + + $('tbREDO').addEvent('click', this.redo.bind(this) ); + $('tbUNDO').addEvent('click', this.undo.bind(this) ); + $('doreplace').addEvent('click', this.doReplace.bind(this) ); + $$('#tools a.tool').addEvent('click',this.toggleSnippet.bind(this) ); + + }, + + doReplace: function(e){ + new Event(e).stop(); + + var findText = $('tbFIND').value, + replaceText = $('tbREPLACE').value, isRegExp = $('tbREGEXP').checked, reGlobal = $('tbGLOBAL').checked ? 'g' : '', - replaceText = $('tbREPLACE').value, reMatchCase = $('tbMatchCASE').checked ? '' : 'i'; - if( findText == "") return; + if(findText == '') return; + + var sel = TextArea.getSelection(this.textarea), + data = (!sel || (sel=='')) ? this.textarea.value : sel; - var sel = TextArea.getSelection(this.textarea); - var data = ( !sel || (sel=="") ) ? this.textarea.value : sel; - if(!isRegExp){ /* escape all special re characters */ - var re = new RegExp( "([\.\*\\\?\+\[\^\$])", "gi"); - findText = findText.replace( re,"\\$1" ); + var re = new RegExp('([\.\*\\\?\+\[\^\$])','gi'); + findText = findText.replace(re,'\\$1'); } - var re = new RegExp(findText, reGlobal+reMatchCase+"m" ); //multiline + var re = new RegExp(findText, reGlobal+reMatchCase+'m'); //multiline if(!re.exec(data)){ - alert( "edit.findandreplace.nomatch".localize() ); - return true; - } - + Wiki.alert('edit.findandreplace.nomatch'.localize()); + return;// true; + } data = data.replace(re, replaceText); - this.storeTextarea(); + this.store(); if(!sel || (sel=="")){ this.textarea.value = data; } else { TextArea.replaceSelection( this.textarea, data ); } - if(this.textarea.onchange) this.textarea.onchange(); - } , + this.textarea.fireEvent('change'); + }, - /* TOOLBAR: cut/copy/paste clipboard functionality */ - CLIPBOARD : null, - clipboard : function( format ){ - var s = TextArea.getSelection(this.textarea); - if( !s || s == "") return; - - this.CLIPBOARD = s ; - $( 'tbPASTE' ).className = this.ToolbarMarker; - var ss = format.replace( /\$/, s); - if( s == ss ) return; //copy + onPageLoadPostEditor: function(){ + if(window.ie) return; + + $('toolextra').show(); + this.posteditor = new postEditor.create(this.textarea,'changenote'); + + /* patch posteditor DF Jul 07 */ + /* righ-arrow nok on FF, nop on Safari */ + this.posteditor.onKeyRight = Class.empty; + /* make posteditor changes undoable */ + this.posteditor.value = function(value) { + EditTools.store(); + this.element.value = value.join(''); + this.element.fireEvent('change'); + }; - this.storeTextarea(); //cut - TextArea.replaceSelection( this.textarea, ss ); - } , + /* next extra fix for latest Safari 3.1 cause tabs are not catched anymore in the onkeypress handler */ + /* TODO: this could be a great workaround for ie as well */ + if(window.webkit){ + this.textarea.addEvent('keydown',function(e){ + if(e.keyCode == 9) EditTools.posteditor.onKeyPress(e); + }); + }; + + ['smartpairs', 'tabcompletion'].each( function(el){ + $(el).setProperty('checked', Wiki.prefs.get(el) || false) + .addEvent('click',function(e) { + Wiki.prefs.set(el,this.checked); + EditTools.initPostEditor(); + }); + },this); + + this.initPostEditor(); + }, + + initPostEditor: function(){ + if(! this.posteditor) return; + this.posteditor.changeSmartTypingPairs( $('smartpairs').checked ? this.wikismartpairs : {} ); + this.posteditor.changeSnippets( $('tabcompletion').checked ? this.wikisnippets : {} ); + }, + + toggleSnippet: function(e) { + e = new Event(e).stop(); + + var el = e.target, + snippy = this.wikisnippets[el.getText()]; - paste : function() - { - if( !this.CLIPBOARD ) return; - this.storeTextarea(); - TextArea.replaceSelection( this.textarea, this.CLIPBOARD ); + if(!snippy) return; + + var s = TextArea.getSelection(this.textarea), + sn1 = snippy.snippet[0], + sn2 = snippy.snippet[2], + t = snippy.snippet.join(''); + + this.store(); + + if((el.rel=='break') && (!TextArea.isSelectionAtStartOfLine(this.textarea))) { + t = '\n' + t; + } + if(s) { + // toggle markup + if((s.indexOf(sn1) == 0) && (s.lastIndexOf(sn2) == (s.length - sn2.length))) { + t = s.substring(sn1.length, s.length-sn2.length); + } else { + t = t.replace( snippy.tab[0], s) + } + } + TextArea.replaceSelection(this.textarea, t); } , - /* UNDO functionality: use by all toolbar and find&replace functions */ - UNDOstack : [], - REDOstack : [], - UNDOdepth : 20, + // *** UNDO functionality *** + $undo: [], + $redo: [], + $maxundo: 20, + + $get: function() { + var ta = this.textarea, + sel = TextArea.getSelectionCoordinates(ta); + return { + main:this.mainarea.value, + value:ta.value, + cursor:sel, + scrollTop:ta.scrollTop, + scrollLeft:ta.scrollLeft + }; + }, + $put: function(o){ + var ta = this.textarea; + this.mainarea.value = o.main; + ta.value = o.value; + ta.scrollTop = o.scrollTop; + ta.scrollLeft = o.scrollLeft; + TextArea.setSelection(o.cursor.start,o.cursor.end); + ta.fireEvent('change'); + }, + store: function() { + this.$undo.push( this.$get() ); + this.$redo = []; + if(this.$undo.length > this.$maxundo) this.$undo.shift(); - storeTextarea : function() { - this.UNDOstack.push( this.textarea.value ); $('tbUNDO').disabled = ''; - this.REDOstack = []; $('tbREDO').disabled = 'true'; - if(this.UNDOstack.length > this.UNDOdepth) this.UNDOstack.shift(); }, - undoTextarea : function(){ - if(this.UNDOstack.length > 0){ + undo: function(e){ + new Event(e).stop(); + if(this.$undo.length > 0){ $('tbREDO').disabled = ''; - this.REDOstack.push(this.textarea.value); - this.textarea.value = this.UNDOstack.pop(); + this.$redo.push( this.$get() ); + this.$put( this.$undo.pop() ); + } else { + $('tbUNDO').disabled = 'true'; } - if(this.UNDOstack.length == 0) $('tbUNDO').disabled = 'true'; - if(!this.selector) return; - this.onSelectorLoad(); - this.onSelectorChanged(); - - this.textarea.focus(); }, - redoTextarea : function(){ - if(this.REDOstack.length > 0){ + redo: function(e){ + new Event(e).stop(); + if(this.$redo.length > 0){ + this.$undo.push( this.$get() ); + this.$put( this.$redo.pop() ); $('tbUNDO').disabled = ''; - this.UNDOstack.push(this.textarea.value); - this.textarea.value = this.REDOstack.pop(); + } else { + $('tbREDO').disabled = 'true'; } - if(this.REDOstack.length == 0) $('tbREDO').disabled = 'true'; - if(!this.selector) return; - this.onSelectorLoad(); - this.onSelectorChanged(); - this.textarea.focus(); }, - getSuggestionMenu: function(){ - var mID = 'findSuggestionMenu', - m = $(mID); - if( !m ) { - m = new Element('div',{'id':mID}).injectTop( $('favorites') ); + // *** end of UNDO functionality *** + + getSuggestions: function() { + var textarea = this.textarea, + sel = TextArea.getSelectionCoordinates(textarea), + val = textarea.value, + searchword = ''; + + var suggestID = 'findSuggestionMenu', + suggest = $(suggestID) || new Element('div',{ + 'id':suggestID + }).injectAfter($('favorites').getFirst()); + + /* find a partial jspwiki-link 'searchword' */ + /* look backwards for the start of a wiki-link bracket */ + for( i = sel.start-1; i >= 0; i-- ){ + if( val.charAt(i) == ']' ) break; + if( val.charAt(i) == '[' && i < val.length-1 ) { + searchword = val.substring(i+1,sel.start); + if(searchword.indexOf('|') != -1) searchword = searchword.split('|')[1]; + break; + } } - return m; - } -} + if(searchword =='') return suggest.hide(); + var searchlen = searchword.length; -/** TextArea support routines - **/ + if(sel.start == sel.end) { //when no selection, extend till next ] + var i = val.indexOf(']',sel.start); + if( i>0 ) sel.end = i + } + + Wiki.jsonrpc('search.getSuggestions', [searchword,30], function(result,exception){ + if(exception) { + alert(exception.message); + } else if(!result.list || (result.list.length == 0)) { + suggest.hide(); + } else { + var ul = new Element('ul').inject( suggest.empty().show() ); + result.list.each( function(rslt) { + new Element('li',{ + 'title':rslt, + 'events': { + 'click':function(ev){ + new Event(ev).stop(); + EditTools.store(); + TextArea.setSelection(sel.start,sel.end); + TextArea.replaceSelection(textarea, rslt.substr(searchlen)); + sel.end = sel.start + rslt.length - searchlen; + }, + 'mouseout': function(){ this.removeClass('hover') }, + 'mouseover':function(){ this.addClass('hover') } + } + }).setHTML(rslt.trunc(36) ).inject(ul); + }); /* each */ + } /* endif */ + }); + }, + + onPageLoadPreview : function(){ + if( $$('#sneakpreview','#autopreview').length != 2) return; + $('autopreview') + .setProperty('checked', Wiki.prefs.get('autopreview') || false) + .addEvent('click', function(){ + var ta = this.textarea, + isOn = $('autopreview').checked; + + $('sneakpreview').empty(); + ta.removeEvents('preview'); + Wiki.prefs.set('autopreview',isOn); + + if(isOn) ta.addEvent('preview', this.refreshPreview.bind(this)).fireEvent('preview'); + + }.bind(this)).fireEvent('click'); + }, + + refreshPreview: function(){ + var preview = $('sneakpreview'); + this.bgcolor = this.bgcolor || preview.getStyle('background-color'); + + var bgcolorfx = (this.bgcolor == 'transparent' ) ? '#fff' : this.bgcolor, + previewfx = preview.effect('background-color', { + duration:2000, + wait:false, + onComplete:function(){ preview.setStyle('background-color', this.bgcolor); } + }); + + //TODO: put a spinner in the preview result block + new Ajax( Wiki.TemplateUrl + "/AJAXPreview.jsp?page="+Wiki.PageName, { + postBody: 'wikimarkup=' + encodeURIComponent(this.textarea.value), + update: preview, + onComplete: function(){ + Wiki.renderPage(preview, Wiki.PageName); + previewfx.start('#ffff88',bgcolorfx); + } + }).request(); + }, + + onPageLoadSectionToc : function(){ + + if(Wiki.prefs.get('SectionEditing') != 'on') return; + + var tt = new Element('div',{'id':'toctoc'}).adopt( + new Element('label').setHTML('sectionediting.label'.localize()), + this.selector = new Element('ul') + ).injectTop($('favorites')) + + /* initialise the section selectors */ + this.onSelectorLoad(); + + var cursor = location.search.match(/[&?]section=(\d+)/); + cursor = (cursor && cursor[1]) ? 1+cursor[1].toInt() : 0; + if((cursor>0) && this.textarea.sop) cursor++; + + /* initialise the selected section */ + this.onChangeSelector(cursor); + + this.textarea.addEvent('change', this.onChangeTextarea.bind(this)); + }, + + /* + * UPDATE/RFEFRESH the section selector dropdown + * This function is called at startup, and everytime the section textarea changes + * Postcondition: the sectiontoc dropdown contains following entries + * 0. ( all ) + * 1. start-of-page (if applicable) + * 2. text==<<header 1...n>> , <<selector.offset stores start-offset in main textarea>> + */ + onSelectorLoad : function(){ + var mainarea = this.mainarea.value, + ta = this.textarea, + DELIM = "\u00a4"; + + /* mask all headers inside a {{{ ... }}} but keep length unchanged! */ + mainarea = mainarea.replace(/\{\{\{([\s\S]*?)\}\}\}/g, function(match){ + return match.replace( /^!/mg, ' ' ); + }); + + var tt = mainarea.replace( /^([!]{1,3})/mg, DELIM+"$1"+DELIM ).split(DELIM); + + this.newSelector(); + ta.sop = (tt.length>1) && (tt[0] != ''); //start of page section has no !!!header + if(ta.sop) this.addSelector("edit.startOfPage".localize(), 0, 0); + + var pos = tt.shift().length, + ttlen = tt.map(function(i){ return i.length }); + + for(var i=0; i<ttlen.length; i=i+2){ + var hlen = ttlen[i], //length of header markup !!!,!! or ! + indent = (hlen==2) ? 1 : (hlen==1) ? 2 : 0, + title = tt[i+1].match(/.*?$/m)[0]; //title is first line only + + this.addSelector(title, pos, indent); + pos += hlen + ttlen[i+1]; + }; + }, + + setSelector: function( cursor ){ + var els = this.selector.getChildren(); + + if(cursor <0 || cursor >= els.length) cursor = 0; + els.removeClass('cursor'); + els[cursor].addClass('cursor'); + }, + + newSelector: function(){ + this.selector.empty(); + this.selector.offsets = []; + this.addSelector("edit.allsections".localize(),-1,0); + }, + + addSelector: function(text,offset,indent){ + text = text.replace(/~([^~])/g, '$1'); /*remove wiki-markup escape chars ~ */ + this.selector.offsets.push(offset); + this.selector.adopt( + new Element('li').adopt( + new Element('a',{ + 'class':'action', + 'styles': { + 'padding-left':(indent+0.5)+'em' + }, + 'title':text, + 'events':{ + 'click':this.onChangeSelector.pass([this.selector.offsets.length-1],this) + } + }).setHTML(text.trunc(30)) + ) + ); + }, + + /* the USER clicks a new item from the section selector dropdown + * copy a part of the main textarea to the section textarea + */ + onChangeSelector: function(cursor){ + var se = this.selector.offsets, + ta = this.textarea, + ma = this.mainarea.value; + + this.setSelector(cursor); + ta.cursor = cursor; + ta.begin = (cursor==0) ? 0 : se[cursor]; + ta.end = ((cursor==0) || (cursor+1 >= se.length)) ? ma.length : se[cursor+1]; + ta.value = ma.substring(ta.begin,ta.end); + ta.focus(); + ta.fireEvent('preview'); + }, + + /* + * Changes in the section textarea: + * happens when + * (i) textarea is changed and deselected (click outside the textarea) + * (ii) user clicks a toolbar-button + * + * 1) copy section textarea at the right offset of the main textarea + * 2) refresh the sectiontoc menu + */ + onChangeTextarea : function(){ + var ta = this.textarea, ma = this.mainarea; + + var s = ta.value; + if( s.lastIndexOf("\n") + 1 != s.length ) ta.value += '\n'; + + s = ma.value; + ma.value = s.substring(0, ta.begin) + ta.value + s.substring(ta.end); + ta.end = ta.begin + ta.value.length; + this.onSelectorLoad(); //refresh selectortoc menu + ta.fireEvent('preview'); + } +} + +/* + * TextArea support routines + */ +//var TextArea = new Class({ var TextArea = { + initialize: function(el){ + this.textarea = $(el); + return this; + }, + getSelection: function(id){ var f = $(id); if(!f) return ''; - if(window.ie) return document.selection.createRange().text; - return f.getValue().substring(f.selectionStart, f.selectionEnd); + // IE fixme: this returns any selection, not only selected text in the textarea + //if(window.ie) return document.selection.createRange().text; + //return f.getValue().substring(f.selectionStart, f.selectionEnd); + + var cur = this.getSelectionCoordinates(id); + return f.getValue().substring(cur.start, cur.end); + }, + + setSelection: function(start, end){ + var ta = this.textarea; + if(window.ie){ + var r1 = ta.createTextRange(); + r1.collapse(true); + r1.moveStart('character',start); + r1.moveEnd('character',end-start); + r1.select(); + } else { + ta.selectionStart = start; + ta.selectionEnd = end; + } }, - /* replaces the selection with aValue, and returns with aValue selected */ + // getCursor(id) : returns start offset of cursor (integer) + getCursor: function(id) { + return this.getSelectionCoordinates(id).start; + }, + + // getSelectionCoordinates : returns {'start':x, 'end':y } coordinates of the selection + getSelectionCoordinates: function(id) { + var f = $(id); if(!f) return ''; + + if(window.ie){ + var r1 = document.selection.createRange(), + r2 = r1.duplicate(); // use as a 'dummy' + + r2.moveToElementText( f ); // select all text + r2.setEndPoint( 'EndToEnd', r1 ); // move 'dummy' end point to end point of original range + + return { + 'start': r2.text.length - r1.text.length, + 'end': r2.text.length + }; + + } + else if( f.selectionStart || f.selectionStart == '0') { + return {'start':f.selectionStart,'end':f.selectionEnd }; + } else { + return {'start':f.value.length,'end':f.value.length }; + } + }, + + // replaceSelection(id,newtext) replaces the selection with a newtext, an selects the replaced newtext replaceSelection: function(id, newText){ var f = $(id); if(!f) return; - var scrollTop = this.scrollTop; + var scrollTop = f.scrollTop; //cache top if(window.ie){ f.focus(); - var r = document.selection.createRange(); - r.text = newText; - r.moveStart('character',-newText.length); /***/ - r.select(); - f.range.select(); - } - else { - var start = f.selectionStart, end = f.selectionEnd; + var range = document.selection.createRange(); + range.text = newText; + range.collapse(true); + range.moveStart("character", -newText.length); + range.select(); + } else { + var start = f.selectionStart, + end = f.selectionEnd; f.value = f.value.substring(0, start) + newText + f.value.substring(end); - f.replaceSelectionRange(start + newText.length, start + newText.length); + f.selectionStart = start; + f.selectionEnd = start + newText.length; } f.focus(); f.scrollTop = scrollTop; - if(f.onchange) f.onchange(); + + f.fireEvent('change'); }, - /* check whether selection is preceeded by a \n (peek-ahead) */ + // isSelectionAtStartOfLine(id): returns boolean indicating whether cursor is at the start of newline isSelectionAtStartOfLine: function(id){ var f = $(id); if(!f) return false; - if(window.ie){ - f.focus(); - var r1 = document.selection.createRange(), - r2 = document.selection.createRange(); - r2.moveStart( "character", -1); - if(r2.text=="") r2.moveEnd( "character", 1); - if(r1.compareEndPoints("StartToStart", r2) == 0) return true; - if(r2.text.charAt(0).match( /[\n\r]/ )) return true; - } - else { - if(f.selectionStart == 0) return true; - if(f.value.charAt(f.selectionStart-1) == '\n') return true; - } - return false; - } -}; - -//************************* -// TODO -// copied from default -- to be incorporated in EditTools -var globalCursorPos; // global variabe to keep track of where the cursor was - -//sets the global variable to keep track of the cursor position -function setCursorPos(id) -{ - if(window.ie) return; - globalCursorPos = getCursorPos( $(id) ); -} - -function getCursorPos(textElement) -{ - //save off the current value to restore it later, - var sOldText = textElement.value; - - if(window.ie){ - var objRange = document.selection.createRange(), - sOldRange = objRange.text, - sWeirdString = '#%~'; //small string that will not normally be encountered - - //insert the weirdstring where the cursor is at - objRange.text = sOldRange + sWeirdString; - objRange.moveStart('character', (0 - sOldRange.length - sWeirdString.length)); - - //save off the new string with the weirdstring in it - var sNewText = textElement.value; - - //set the actual text value back to how it was - objRange.text = sOldRange; - - //look through the new string we saved off and find the location of - //the weirdstring that was inserted and return that value - for (i=0; i <= sNewText.length; i++) { - var sTemp = sNewText.substring(i, i + sWeirdString.length); - if (sTemp == sWeirdString) { - var cursorPos = (i - sOldRange.length); - return cursorPos; - } - } - } - // Mozilla and the rest - else if( textElement.selectionStart || textElement.selectionStart == '0') - { - return textElement.selectionStart; - } - else - { - return sOldText.length; + var i = this.getCursor(id); + return( (i<=0) || ( f.value.charAt( i-1 ).match( /[\n\r]/ ) ) ); } -} - -//this function inserts the input string into the textarea -//where the cursor was at -function insertString(stringToInsert) { - var firstPart = myForm.myTextArea.value.substring(0, globalCursorPos); - var secondPart = myForm.myTextArea.value.substring(globalCursorPos, - myForm.myTextArea.value.length); - myForm.myTextArea.value = firstPart + stringToInsert + secondPart; -} - -/** - ** JSON-RPC - ** POST is - ** {"id": 2, "method": "search.getSuggestions", "params": ["p", 10]} - ** Response is - ** {"result":{"list":["Pic\/ruby.jpg","Pic\/telenet-smile.gif","Pic\/spin-greyblocks.gif","Pic\/shadow_transparent2.png","Pic\/monkey-mam-child.jpg","Pic\/brushed-button.jpg","Pic\/resizecursorv.png","Pic\/UserKeychainIcon.tiff","PrototypeJavascriptLibrary","Pizza Margerita"],"javaClass":"java.util.ArrayList"},"id":2} - **/ -function getSuggestions(id) -{ - if(window.ie) return; - var textNode = $(id), - val = textNode.value, - searchword; - var pos = getCursorPos(textNode); - for( i = pos-1; i > 0; i-- ){ - if( val.charAt(i) == ']' ) break; - if( val.charAt(i) == '[' && i < val.length-1 ) { searchword = val.substring(i+1,pos); break; } - } - - if(searchword){ - jsonrpc.search.getSuggestions(callback, searchword, 10); - } else { - EditTools.getSuggestionMenu().hide(); - } -} -function callback(result, exception) -{ - if(exception) { alert(exception.message); return; } - - var menuNode = EditTools.getSuggestionMenu(), - html = []; - - result.list.each(function(el) { html.push('<li>'+el+'</li>'); }); - - menuNode.setHTML('<ul>',html.join(''),'</ul>').show(); -} +}; window.addEvent('load', EditTools.onPageLoad.bind(EditTools) ); //edit only \ No newline at end of file
Modified: incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/webdocs/scripts/jspwiki-prefs.js URL: http://svn.apache.org/viewvc/incubator/jspwiki/branches/JSPWIKI_2_9_STRIPES_BRANCH/src/webdocs/scripts/jspwiki-prefs.js?rev=685201&r1=685200&r2=685201&view=diff ============================================================================== Binary files - no diff available.
